@task-handoff/control-plane 0.0.22-alpha.2 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/cli.js +2 -2
  2. package/package.json +1 -1
  3. package/ui/assets/{CodeBlockNode-sy66MtHh.js → CodeBlockNode-DGBER8OB.js} +3 -3
  4. package/ui/assets/{Tooltip-sP5EJXsB.js → Tooltip-Bxgx8sXg.js} +1 -1
  5. package/ui/assets/{abnfDiagram-VRR7QNED-tsop6O-W.js → abnfDiagram-VRR7QNED-BUH8Jp7H.js} +1 -1
  6. package/ui/assets/{arc-BrEv8Jkg.js → arc-CEQHyqXA.js} +1 -1
  7. package/ui/assets/{architectureDiagram-ZJ3FMSHR-CCvsG25T.js → architectureDiagram-ZJ3FMSHR-LwC90CMl.js} +1 -1
  8. package/ui/assets/{blockDiagram-677ZJIJ3-m5_kX-It.js → blockDiagram-677ZJIJ3-DFLuEdYc.js} +1 -1
  9. package/ui/assets/{c4Diagram-LMCZKHZV-BkKkRphZ.js → c4Diagram-LMCZKHZV-8odKU3Nv.js} +1 -1
  10. package/ui/assets/channel-DIafcwoy.js +1 -0
  11. package/ui/assets/{chunk-2Q5K7J3B-DUcJJ421.js → chunk-2Q5K7J3B-ChSt3opS.js} +1 -1
  12. package/ui/assets/{chunk-32BRIVSS-lxRYBpdt.js → chunk-32BRIVSS-C_pA83pt.js} +1 -1
  13. package/ui/assets/{chunk-5VM5RSS4-DfFSUe6H.js → chunk-5VM5RSS4-CRS3dVeE.js} +1 -1
  14. package/ui/assets/{chunk-EX3LRPZG-Bi0N679U.js → chunk-EX3LRPZG-CrMoNf2b.js} +1 -1
  15. package/ui/assets/{chunk-JWPE2WC7-Dt3HhYlx.js → chunk-JWPE2WC7-DOJSGcbs.js} +1 -1
  16. package/ui/assets/{chunk-MOJQB5TN-CiBmnUBJ.js → chunk-MOJQB5TN-BMTH_JL2.js} +1 -1
  17. package/ui/assets/{chunk-RYQCIY6F-D__HouzF.js → chunk-RYQCIY6F-CdqOdqQH.js} +1 -1
  18. package/ui/assets/{chunk-V7JOEXUC-CVkq9a_J.js → chunk-V7JOEXUC-HULjbu7t.js} +1 -1
  19. package/ui/assets/{chunk-VR4S4FIN-DnPDhtb9.js → chunk-VR4S4FIN-DWOutlOe.js} +1 -1
  20. package/ui/assets/{chunk-XXDRQBXY-Cjyk7W6r.js → chunk-XXDRQBXY-9x0lCKTV.js} +1 -1
  21. package/ui/assets/classDiagram-OUVF2IWQ-D4IvnM-g.js +1 -0
  22. package/ui/assets/classDiagram-v2-EOCWNBFH-D4IvnM-g.js +1 -0
  23. package/ui/assets/{cose-bilkent-JH36ORCC-Ct-tK2Tj.js → cose-bilkent-JH36ORCC-KOcW0jfA.js} +1 -1
  24. package/ui/assets/{cynefin-VYW2F7L2-C6XeUiAz.js → cynefin-VYW2F7L2-DVCIxQdV.js} +1 -1
  25. package/ui/assets/{cynefinDiagram-TSTJHNR4-BA01MEyz.js → cynefinDiagram-TSTJHNR4-Oe8S7GX2.js} +1 -1
  26. package/ui/assets/{dagre-VKFMJZFB-BYK4h0kr.js → dagre-VKFMJZFB-rp9tCkmu.js} +1 -1
  27. package/ui/assets/{diagram-FQU43EPY-CNyLRamm.js → diagram-FQU43EPY-iK1h37Xr.js} +1 -1
  28. package/ui/assets/{diagram-G47NLZAW-CN44MJCA.js → diagram-G47NLZAW-Dsv4MA6X.js} +1 -1
  29. package/ui/assets/{diagram-NH7WQ7WH-BR4yShME.js → diagram-NH7WQ7WH-Cn6pFoeN.js} +1 -1
  30. package/ui/assets/{diagram-OA4YK3LP-hs5XMqzc.js → diagram-OA4YK3LP-D9dbgoOP.js} +1 -1
  31. package/ui/assets/{diagram-WEI45ONY-CJ8MnvBs.js → diagram-WEI45ONY-CijoVAod.js} +1 -1
  32. package/ui/assets/{ebnfDiagram-CCIWWBDH-M2iz0nDJ.js → ebnfDiagram-CCIWWBDH-CvD2sGsD.js} +1 -1
  33. package/ui/assets/{erDiagram-Q63AITRT-Czy5YXu9.js → erDiagram-Q63AITRT-2yXS54Rl.js} +1 -1
  34. package/ui/assets/{flowDiagram-23GEKE2U-XFFATweO.js → flowDiagram-23GEKE2U-BH7IKjo1.js} +1 -1
  35. package/ui/assets/{ganttDiagram-NO4QXBWP-CVhTb26O.js → ganttDiagram-NO4QXBWP-Bi7hNgGU.js} +1 -1
  36. package/ui/assets/{gitGraphDiagram-IHSO6WYX-DeG8mO3Q.js → gitGraphDiagram-IHSO6WYX-CEVlQyvA.js} +1 -1
  37. package/ui/assets/index-C2EY0F65.css +1 -0
  38. package/ui/assets/index-SHIO43wh.js +624 -0
  39. package/ui/assets/{index10-CiYKuefh.js → index10-CgyRHaqr.js} +2 -2
  40. package/ui/assets/{index11-BQkdO_Uj.js → index11-BDFdtphY.js} +5 -5
  41. package/ui/assets/{index5-C8oq4pA7.js → index5-DGG3wLHl.js} +1 -1
  42. package/ui/assets/index6-Cd4ABY0T.js +1 -0
  43. package/ui/assets/index7-BeVRhpik.js +1 -0
  44. package/ui/assets/{index8-BtTkd4cv.js → index8-BA2ssMkt.js} +1 -1
  45. package/ui/assets/{infoDiagram-FWYZ7A6U-XGrtaOFz.js → infoDiagram-FWYZ7A6U-CWJAqQVG.js} +1 -1
  46. package/ui/assets/{ishikawaDiagram-FXEZZL3T-D9AJLNzZ.js → ishikawaDiagram-FXEZZL3T-DYxzlzh5.js} +1 -1
  47. package/ui/assets/{journeyDiagram-5HDEW3XC-BhYvizwK.js → journeyDiagram-5HDEW3XC-DJXbKesY.js} +1 -1
  48. package/ui/assets/{kanban-definition-HUTT4EX6-JQPkCeBt.js → kanban-definition-HUTT4EX6-DzcRadIO.js} +1 -1
  49. package/ui/assets/{linear-C-a5AUor.js → linear-CnRc42Sf.js} +1 -1
  50. package/ui/assets/{mermaid.core-BrdCP57J.js → mermaid.core-Bg6aTZcF.js} +4 -4
  51. package/ui/assets/{mhchem-CMc19Z7G.js → mhchem-BTbI-4_i.js} +1 -1
  52. package/ui/assets/{mindmap-definition-LN4V7U3C-9ZPanJHA.js → mindmap-definition-LN4V7U3C-B86--mTv.js} +1 -1
  53. package/ui/assets/{pegDiagram-2B236MQR-C-WgEIR_.js → pegDiagram-2B236MQR-BZ4PFFrX.js} +1 -1
  54. package/ui/assets/{pieDiagram-ENE6RG2P-bSBQZzkg.js → pieDiagram-ENE6RG2P-DmFioZd4.js} +1 -1
  55. package/ui/assets/{quadrantDiagram-ABIIQ3AL--6_DuuLL.js → quadrantDiagram-ABIIQ3AL-o382-4Q4.js} +1 -1
  56. package/ui/assets/{railroadDiagram-RFXS5EU6-zysyZqE1.js → railroadDiagram-RFXS5EU6-BXFKVkbb.js} +1 -1
  57. package/ui/assets/{requirementDiagram-TGXJPOKE-b-3qg1ik.js → requirementDiagram-TGXJPOKE-CZ2NyhTj.js} +1 -1
  58. package/ui/assets/{sankeyDiagram-HTMAVEWB-hWcoh1Pf.js → sankeyDiagram-HTMAVEWB-9AA8dZEU.js} +1 -1
  59. package/ui/assets/{sequenceDiagram-DBY2YBRQ-DuK8ZJvd.js → sequenceDiagram-DBY2YBRQ-ChH9YqRO.js} +1 -1
  60. package/ui/assets/{sizeCapture-X5ZJPWSS-mjC4vDQN.js → sizeCapture-X5ZJPWSS-GYtaZzn0.js} +1 -1
  61. package/ui/assets/{stateDiagram-2N3HPSRC-PYfrl_DA.js → stateDiagram-2N3HPSRC-CPVnrTqk.js} +1 -1
  62. package/ui/assets/stateDiagram-v2-6OUMAXLB-hg2mTFb6.js +1 -0
  63. package/ui/assets/{swimlanes-5IMT3BWC-CMfZNZWj.js → swimlanes-5IMT3BWC-CAk8Fivu.js} +2 -2
  64. package/ui/assets/swimlanesDiagram-G3AALYLV-DDgF5QZ9.js +8 -0
  65. package/ui/assets/{timeline-definition-FHXFAJF6-BrDxW7hy.js → timeline-definition-FHXFAJF6-l_NjEbbE.js} +1 -1
  66. package/ui/assets/ui-vendor-CKnAvqX8.js +10 -0
  67. package/ui/assets/{vennDiagram-L72KCM5P-wvquMj8M.js → vennDiagram-L72KCM5P-BLSuEW0g.js} +1 -1
  68. package/ui/assets/{wardleyDiagram-EHGQE667-Ck7V5Dky.js → wardleyDiagram-EHGQE667-BTPNBHby.js} +1 -1
  69. package/ui/assets/{xychartDiagram-FW5EYKEG-BawQ1jwZ.js → xychartDiagram-FW5EYKEG-gjoxmXl0.js} +1 -1
  70. package/ui/index.html +3 -3
  71. package/ui/assets/channel-B9ELRYWT.js +0 -1
  72. package/ui/assets/classDiagram-OUVF2IWQ-DJzyfElc.js +0 -1
  73. package/ui/assets/classDiagram-v2-EOCWNBFH-DJzyfElc.js +0 -1
  74. package/ui/assets/index-BvFnfiFc.css +0 -1
  75. package/ui/assets/index-Dfhvmp8c.js +0 -622
  76. package/ui/assets/index6-C1BPGR_3.js +0 -1
  77. package/ui/assets/index7-DpvqXeKK.js +0 -1
  78. package/ui/assets/stateDiagram-v2-6OUMAXLB-D5pgKELE.js +0 -1
  79. package/ui/assets/swimlanesDiagram-G3AALYLV-Cnw4y44M.js +0 -8
  80. package/ui/assets/ui-vendor-DrR81E4h.js +0 -10
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"),g=require("node:stream"),h=require("telegramify-markdown"),m=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 C(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 x=20971520,T=512e3,E=41943040,N="ai-session.snapshot",O="ai-session.patch",_="ai-session.removed",R="ai-session.message-delta",P="ai-session.unread.updated",j=a.z.string().trim().min(1).max(80),D=a.z.enum(["app-session","ai-session"]),M=a.z.enum(["running","waiting","idle","failed"]),L=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(),q=a.z.enum(["thinking","tool","editing","approval","responding","unknown"]),$=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(),B=a.z.enum(["pending-init","running","interrupted","completed","errored","shutdown","not-found"]),U=a.z.enum(["started","interacted","interrupted"]),F=a.z.object({threadId:a.z.string().trim().min(1).max(240),path:a.z.string().trim().max(4096).optional(),status:B,activity:U.optional(),message:a.z.string().trim().max(1e3).optional(),updatedAt:a.z.string().datetime()}).strict(),H=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}),W=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(),G=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(),V=a.z.enum(["image","file"]),K=a.z.object({id:a.z.string().trim().min(1).max(120),kind:V,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)}),J=a.z.union([K.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?x:T;(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.`})}),K.extend({source:a.z.object({type:a.z.literal("runtime-path"),path:a.z.string().trim().min(1).max(4096)}).strict()}).strict()]),Y=K.extend({sourceType:a.z.enum(["inline","runtime-path"])}).strict(),Q=a.z.union([a.z.object({id:a.z.string().trim().min(1).max(120),kind:V.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:V,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()]),X=a.z.enum(["auto","queue","steer","immediate"]),Z=a.z.enum(["ask","auto-review","full-access"]),ee=a.z.enum(["review","rename","goal","compact"]),te=a.z.object({command:ee,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.`})}),ne=a.z.object({command:ee,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 ie=a.z.object({name:a.z.string().trim().min(1).max(240),path:a.z.string().trim().min(1).max(4096)}),se=a.z.discriminatedUnion("kind",[ie.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(),ie.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(),ie.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()]),re=a.z.array(se).max(20).default([]),oe=a.z.enum(["plugin","skill","file","directory","app"]),ae=a.z.object({kind:oe,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."})}),de=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(),ce=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(ae).max(1e3).default([]),diagnostics:a.z.array(de).max(20).default([])}).strict(),le=a.z.object({query:a.z.string().trim().max(240).default("")}).strict(),pe=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(ae.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(),ue=a.z.object({message:a.z.string().trim().min(1).max(2e4),mode:X.optional(),permissionMode:Z.optional()}),ge=ue.extend({attachments:a.z.array(J).max(6).default([]),references:re}).strict().superRefine((e,t)=>{e.attachments.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>E&&t.addIssue({code:a.z.ZodIssueCode.custom,path:["attachments"],message:"Inline attachments must be 41943040 bytes or less in total."})}),he=ue.extend({attachments:a.z.array(Q).max(6).default([]),references:re}).strict(),me=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(),ye=ge.extend({agent:j,cwd:me,cwdFolderId:a.z.string().trim().min(1).max(120).optional(),clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),fe=a.z.object({mode:a.z.enum(["current-folder","worktree"]),branch:a.z.string().trim().min(1).max(1024)}).strict(),Ie=he.extend({agent:j,cwdFolderId:a.z.string().trim().min(1).max(120).optional(),gitSelection:fe.optional(),clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),be=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(),ve=a.z.object({mode:a.z.enum(["current","managed-worktree"]).default("current")}).strict().default({mode:"current"}),we=a.z.object({clientRequestId:a.z.string().trim().min(1).max(160),throughTurnId:a.z.string().trim().min(1).max(240).optional(),workspace:ve.optional().default({mode:"current"})}).strict(),Se=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(),Ae=a.z.object({clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),ke=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:D}).strict(),ze=a.z.object({clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),Ce=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:D}).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 xe=a.z.object({decision:a.z.enum(["allow","deny","skip"])}).strict(),Te=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(),Ee=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 Ne=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(Y).max(6).default([]),references:re,permissionMode:Z.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(),Oe=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(Ne).max(100).default([])}).strict().default({revision:0,pendingCount:0,items:[]}),_e=a.z.enum(["control","realtime","adapter-snapshot","transcript-tail","transcript-scan","process-scan","app-session"]),Re=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(),Pe=a.z.object({id:a.z.string().trim().min(1).max(240),providerTurnId:a.z.string().trim().max(240).optional(),source:_e.optional(),userPrompt:a.z.string().trim().optional(),status:a.z.enum(["queued","running","waiting","completed","failed"]).default("running"),phase:q.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(Re).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(),je=Pe.pick({id:!0,providerTurnId:!0,userPrompt:!0,status:!0,phase:!0,summary:!0,lastMessage:!0,contextCompactions:!0,startedAt:!0,updatedAt:!0,completedAt:!0}).strict(),De=a.z.object({id:a.z.string().trim().min(1).max(120),agent:j,creationSource:D.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:G.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:W.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(Pe).max(50).optional(),status:M.default("running"),phase:q.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:$.optional(),toolCallsSinceLastMessage:a.z.number().int().min(0).default(0),subAgents:a.z.array(F).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:H,queue:Oe}).strict(),Me=a.z.object({session:De,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(),Le=a.z.object({id:a.z.string().trim().min(1).max(120),agent:a.z.enum(["codex","claude"]),creationSource:D,providerSessionId:a.z.string().trim().min(1).max(240),lineage:G.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(Le).max(50).default([])}).strict();const qe=a.z.object({items:a.z.array(Le).max(50).default([])}).strict(),$e=a.z.object({item:Le,turns:a.z.array(je).max(50).default([])}).strict(),Be=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:D}).strict(),Ue=De.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}),Fe=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(Ue).default([]),updatedAt:a.z.string().datetime()}).strict(),He=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:Fe}).strict(),We=Fe.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 Ge(e,t={}){const n=e.sessions.filter(e=>"idle"===e.status).length,i=e.sessions.filter(e=>"failed"===e.status).length;return We.parse({runningCount:e.runningCount,waitingCount:e.waitingCount,staleCount:e.staleCount,idleCount:n,problemCount:i,updatedAt:e.updatedAt,revision:t.revision})}const Ve=a.z.enum(["provider-event","app-session-created","app-session-updated","app-session-deleted","discovery-scan","control-action","heartbeat-sync","startup"]),Ke=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:Ve}).strict(),Je=a.z.object({meta:Ke,snapshot:Fe}).strict(),Ye=a.z.object({meta:Ke,upserted:a.z.array(Ue).default([]),removed:a.z.array(a.z.string().trim().min(1).max(120)).default([])}).strict(),Qe=a.z.object({meta:Ke,sessionIds:a.z.array(a.z.string().trim().min(1).max(120)).default([]),expiresAt:a.z.string().datetime()}).strict(),Xe=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(),Ze=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:Je}).strict(),a.z.object({type:a.z.literal(O),payload:Ye}).strict(),a.z.object({type:a.z.literal(_),payload:Qe}).strict()])).default([])}).strict(),et=a.z.object({source:_e,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(),tt=et.extend({type:a.z.literal("snapshot"),agent:a.z.string().trim().min(1).max(80),creationSource:D.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:G.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:W.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(Pe).max(50).optional(),status:M.optional(),phase:q.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:$.optional(),toolCallsSinceLastMessage:a.z.number().int().min(0).optional(),subAgents:a.z.array(F).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(),nt=et.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:M.optional(),phase:q.optional(),summary:a.z.string().trim().max(1e3).optional(),error:a.z.string().trim().max(4e3).optional(),currentTool:$.nullable().optional(),toolCallsSinceLastMessage:a.z.number().int().min(0).optional(),subAgents:a.z.array(F).max(50).optional(),contextCompaction:Re.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",[tt,nt]);const it=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(),st="app-session.snapshot",rt="app-session.patch",ot="app-session.removed",at=a.z.enum(["created","starting","running","stopping","stopped","exited","failed","closed","terminated","unknown"]),dt=a.z.enum(["tty","vnc","web"]);a.z.object({mode:dt,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 ct=new Set(["stopped","failed","exited","closed","terminated"]),lt=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(),pt=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:at.default("unknown"),bindings:a.z.array(lt).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()})),ut=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(pt).default([]),updatedAt:a.z.string().datetime()}).strict(),gt=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:ut}).strict();ut.pick({runningCount:!0,problemCount:!0,updatedAt:!0}).extend({revision:a.z.number().int().min(0).optional()});const ht=a.z.enum(["app-session-created","app-session-updated","app-session-deleted","app-session-recovered","control-action","heartbeat-sync","startup"]),mt=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:ht}).strict(),yt=a.z.object({meta:mt,snapshot:ut}).strict(),ft=a.z.object({meta:mt,session:pt}).strict(),It=a.z.object({meta:mt,sessionId:a.z.string().trim().min(1).max(160),tombstone:pt.optional(),expiresAt:a.z.string().datetime().optional()}).strict(),bt=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(st),payload:yt}).strict(),a.z.object({type:a.z.literal(rt),payload:ft}).strict(),a.z.object({type:a.z.literal(ot),payload:It}).strict()])).default([])}).strict();function vt(e,t=(new Date).toISOString()){const n=e.map(e=>St(e));return ut.parse({runningCount:n.filter(e=>"running"===e.status).length,problemCount:n.filter(e=>"failed"===e.status).length,sessions:n,updatedAt:t})}function wt(e,t=(new Date).toISOString()){return vt(e.filter(e=>kt("string"==typeof e.status?e.status:void 0)),t)}function St(e){const t=At("string"==typeof e.status?e.status:void 0),n="string"==typeof e.id?e.id:"",i=function(e){const t=Nt(e.workspace),n=Nt(e.tty),i=Nt(e.launch),s=Nt(e.ai),r=Nt(s.claude),o=Ot(t.cwd)||Ot(n.cwd)||Ot(r.cwd)||Ot(i.cwd);return o?{cwd:o}:void 0}(e),{workspace:s,...r}=e;return pt.parse({...r,status:t,bindings:Et([...(o=e.bindings,Array.isArray(o)?o.flatMap(e=>{const t=lt.safeParse(e);return t.success?[t.data]:[]}):[]),...n?[{type:"app-session",id:n}]:[],...xt(e)]),...i?{workspace:i}:{}});var o}function At(e){const t=(e||"unknown").trim().toLowerCase();return"ended"===t?"closed":"terminating"===t?"stopping":at.options.includes(t)?t:"unknown"}function kt(e){return!ct.has(At(e))}function zt(e){return"tty"===e.kind?"tty":"gui"===e.kind?"vnc":"web"===e.kind?"web":void 0}function Ct(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 xt(e){const t=Nt(e.ai),n=Nt(t.claude),i=Nt(t.appServer),s=[],r=Ot(n.short);r&&s.push({type:"adapter-key",adapter:"claude",agent:"claude",id:`short:${r}`,key:`short:${r}`});const o=Ot(n.providerSessionId);o&&s.push({type:"provider-session",agent:"claude",id:o});const a=Array.isArray(t.threadIds)?t.threadIds.filter(e=>"string"==typeof e&&Boolean(e.trim())):[],d=Ot(t.activeThreadId);for(const e of[...new Set([d,...a].filter(Boolean))])s.push({type:"provider-session",agent:"codex",id:e});const c=Ot(i.socketPath);return c&&s.push({type:"adapter-key",adapter:"codex-app-server",agent:"codex",id:`socket:${c}`,key:`socket:${c}`}),s}function Tt(e){const t="string"==typeof e.id?e.id:"",n=Nt(e.ai),i=Ot(Nt(n.claude).short);return[t?`app:${t}`:"",i?`claude-short:${i}`:""]}function Et(e){const t=new Map;for(const n of e)t.set(Ct(n),n);return[...t.values()]}function Nt(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Ot(e){return"string"==typeof e&&e.trim()?e.trim():""}function _t(e=(new Date).toISOString()){return ut.parse({runningCount:0,problemCount:0,sessions:[],updatedAt:e})}const Rt=a.z.string().trim().min(3).max(160).regex(/^[a-z][a-z0-9_-]*$/),Pt=a.z.string().datetime(),jt=a.z.string().regex(/^sha256:[A-Za-z0-9_-]{43}$/),Dt=a.z.string().min(32).max(4096),Mt=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 Lt(e){return Array.isArray(e)?`[${e.map(Lt).join(",")}]`:e&&"object"==typeof e?`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${Lt(t)}`).join(",")}}`:JSON.stringify(e)}const qt="2026-08-10",$t="2026-08-10",Bt="2026-08-10",Ut=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(Ut.AccountApi)});const Ft=a.z.string().email().max(320).transform(e=>e.trim().toLowerCase()),Ht=a.z.enum(["pending-verification","active","disabled","pending-deletion"]);a.z.strictObject({id:Rt,email:Ft,emailVerified:a.z.boolean(),hasPassword:a.z.boolean().optional(),totpEnabled:a.z.boolean().optional(),displayName:Mt.optional(),status:Ht,createdAt:Pt}),a.z.strictObject({id:Rt,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:Pt,lastSeenAt:Pt.optional(),expiresAt:Pt,revokedAt:Pt.optional()}),a.z.union([a.z.object({code:Dt,state:a.z.string().min(1).max(4096).optional(),redirectUri:a.z.string().url(),expiresAt:Pt}),a.z.object({authorizationUrl:a.z.string().url(),expiresAt:Pt})]),a.z.object({tokenType:a.z.literal("Bearer"),accessToken:Dt,accessExpiresAt:Pt,refreshCredential:Dt,accountId:Rt,deviceSessionId:Rt}),a.z.strictObject({enrollmentToken:Dt,secret:Dt,algorithm:a.z.literal("SHA1"),digits:a.z.literal(6),periodSeconds:a.z.literal(30),otpauthUri:a.z.string().url().startsWith("otpauth://totp/"),expiresAt:Pt});const Wt=a.z.strictObject({controlPlaneId:Rt,algorithm:a.z.literal("Ed25519"),publicKey:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/),fingerprint:jt});a.z.strictObject({protocolVersion:a.z.literal(qt),audience:a.z.literal(Ut.Binding),challengeId:Rt,challenge:Dt,serviceOrigin:a.z.string().url(),identity:Wt,nonce:a.z.string().min(16).max(256),initiatingAdminSessionId:Rt,issuedAt:Pt,expiresAt:Pt}),a.z.strictObject({code:a.z.enum(["CONTROL_PLANE_ALREADY_BOUND","REVISION_CONFLICT","REVOCATION_PENDING","IDENTITY_CLONE_CONFLICT"]),controlPlaneId:Rt,expectedRevision:a.z.number().int().nonnegative().optional(),actualRevision:a.z.number().int().nonnegative().optional(),retryable:a.z.boolean()});const Gt=a.z.strictObject({bindingId:Rt.optional(),controlPlaneId:Rt,displayName:Mt,publicKeyFingerprint:jt,bindingRevision:a.z.number().int().positive(),remoteAccess:a.z.enum(["enabled","disabled","revocation-pending"]),leaseExpiresAt:Pt.optional(),lastConnectedAt:Pt.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()}),Vt=a.z.enum(["interactive","stream","bulk"]),Kt=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(),Jt=a.z.strictObject({protocolVersion:a.z.literal($t),audience:a.z.literal(Ut.CoordinatorControl),connectionId:Rt,processInstanceId:Rt,controlPlaneId:Rt,publicKey:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/),publicKeyFingerprint:jt,bindingId:Rt.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:Pt,expiresAt:Pt}).superRefine((e,t)=>{Boolean(e.bindingId)!==Boolean(e.bindingRevision)&&t.addIssue({code:"custom",message:"binding id and revision must be supplied together"})});Jt.safeExtend({signature:Dt}),a.z.strictObject({connectionId:Rt,controlPlaneId:Rt,bindingRevision:a.z.number().int().positive(),epoch:a.z.number().int().nonnegative(),relayId:Rt,relayRegion:a.z.string().trim().min(1).max(80),issuedAt:Pt,expiresAt:Pt});const Yt=a.z.strictObject({protocolVersion:a.z.literal($t),audience:a.z.literal(Ut.ControlPlaneAccess),ticketId:Rt,accountId:Rt,deviceSessionId:Rt,controlPlaneId:Rt,bindingId:Rt,bindingRevision:a.z.number().int().positive(),targetPublicKeyFingerprint:jt,nonce:a.z.string().min(16).max(256),trafficClasses:a.z.array(Vt).min(1),issuedAt:Pt,expiresAt:Pt,signature:Dt});a.z.strictObject({audience:a.z.literal(Ut.ControlPlaneAccess),accountId:Rt,deviceSessionId:Rt,controlPlaneId:Rt,bindingId:Rt,bindingRevision:a.z.number().int().positive(),authenticatedAt:Pt,expiresAt:Pt,signature:Dt});const Qt=a.z.enum(["client","control-plane"]),Xt=a.z.strictObject({protocolVersion:a.z.literal(Bt),audience:a.z.enum([Ut.RelayClientAttach,Ut.RelayControlPlaneAttach]),allocationId:Rt,relayId:Rt,role:Qt,controlPlaneId:Rt,accountId:Rt,deviceSessionId:Rt,bindingId:Rt,ticketId:Rt,bindingRevision:a.z.number().int().positive(),trafficClass:Vt,nonce:a.z.string().min(16).max(256),issuedAt:Pt,expiresAt:Pt,signature:Dt}).superRefine((e,t)=>{const n="client"===e.role?Ut.RelayClientAttach:Ut.RelayControlPlaneAttach;e.audience!==n&&t.addIssue({code:"custom",path:["audience"],message:`audience must match ${e.role} role`})});a.z.object({allocationId:Rt,relayId:Rt,relayRegion:a.z.string().trim().min(1).max(80),relayUrl:a.z.string().url(),clientAttach:Xt,expiresAt:Pt}),a.z.strictObject({channelId:Rt,allocationId:Rt,controlPlaneId:Rt,bindingRevision:a.z.number().int().positive(),trafficClass:Vt,state:a.z.enum(["waiting-for-peer","handshaking","open","closing","closed"]),clientAttached:a.z.boolean(),controlPlaneAttached:a.z.boolean(),openedAt:Pt.optional(),leaseExpiresAt:Pt}),a.z.strictObject({protocolVersion:a.z.literal(Bt),channelId:Rt,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:Rt,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(Bt),audience:a.z.literal(Ut.RelayRevocation),revocationId:Rt,relayId:Rt.optional(),allocationId:Rt.optional(),accountId:Rt.optional(),deviceSessionId:Rt.optional(),bindingId:Rt.optional(),issuedAt:Pt,expiresAt:Pt,signature:Dt}).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(qt),items:a.z.array(Gt)})}),Object.keys(Gt.shape);const Zt=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 en(){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 tn=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()]),nn=a.z.union([tn,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()]),sn=a.z.object({promptTemplate:a.z.string().trim().min(1).max(2e4)}).strict(),rn=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(),on=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:nn,action:sn,policy:rn.default({maxConcurrentRuns:1,whenBusy:"skip"}),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict(),an=a.z.object({type:a.z.literal("ai-session"),aiSessionId:a.z.string().trim().min(1).max(160)}).strict(),dn=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:an,localName:a.z.string().trim().min(1).max(160).optional(),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict(),cn=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(),ln=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:an,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(on).default([]),deployments:a.z.array(dn).default([]),runtime:a.z.array(cn).default([]),recentRuns:a.z.array(ln).default([])}).strict();const pn=a.z.object({instanceId:a.z.string().trim().min(1).max(160),instanceName:a.z.string().trim().min(1).max(160),deployment:dn,runtime:cn.optional()}).strip(),un=ln.extend({instanceName:a.z.string().trim().min(1).max(160).optional()}).strip(),gn=a.z.object({configHash:a.z.string().trim().min(8).max(80),config:on,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(pn),recentRuns:a.z.array(un)}).strip(),hn=a.z.object({updatedAt:a.z.string().datetime(),triggers:a.z.array(gn)}).strip();function mn(e){const t=In({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),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=fn(t,7)^fn(t,18)^t>>>3,s=fn(n,17)^fn(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+(fn(d,6)^fn(d,11)^fn(d,25))+(d&c^~d&l)+yn[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+((fn(t,2)^fn(t,13)^fn(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:on.shape.name,description:on.shape.description,source:nn,action:sn,policy:rn.partial().optional()}).strict();const yn=[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 fn(e,t){return e>>>t|e<<32-t}function In(e){return Array.isArray(e)?e.map(In):e&&"object"==typeof e?Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,In(t)])):e}const bn="2026-08-01",vn=a.z.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Proxy protocol version must use YYYY-MM-DD format."),wn=a.z.string().trim().min(1).max(160).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Sn=a.z.string().datetime(),An=a.z.string().trim().min(32).max(4096),kn=wn,zn=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}}),Cn=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}}),xn=new Set(["accept","accept-language","authorization","content-type","if-match","if-none-match","range","x-request-id"]),Tn=new Set(["cache-control","content-disposition","content-language","content-length","content-range","content-type","etag","last-modified","x-request-id"]),En="x-task-handoff-proxy-protocol-version",Nn="x-task-handoff-proxy-source-control-plane-id",On="x-task-handoff-proxy-binding-key-id",_n="x-task-handoff-proxy-credential",Rn={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"},Pn=a.z.enum(Object.values(Rn)),jn=a.z.object({code:Pn,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(),Dn=a.z.enum(["active","consumed","revoked","expired"]),Mn=a.z.object({id:wn,targetNodeId:wn,tokenHash:a.z.string().trim().min(32).max(256),status:Dn,createdBy:wn,expiresAt:Sn,consumedByClaimId:wn.optional(),consumedAt:Sn.optional(),revokedAt:Sn.optional(),createdAt:Sn,updatedAt:Sn}).strict(),Ln=Mn.omit({tokenHash:!0}),qn=a.z.object({targetNodeId:wn,expiresInSeconds:a.z.number().int().min(60).max(3600).default(600)}).strict(),$n=a.z.object({invite:Ln,token:a.z.string().trim().min(24).max(512),proxyOrigin:zn,protocolVersion:vn}).strict(),Bn=a.z.enum(["active","revoked"]),Un=a.z.object({id:wn,claimId:wn,sourceControlPlaneId:wn,targetNodeId:wn,bindingKeyId:wn,credentialHash:a.z.string().trim().min(32).max(256),status:Bn,revision:a.z.number().int().positive(),lastError:jn.optional(),revokedAt:Sn.optional(),createdAt:Sn,updatedAt:Sn}).strict(),Fn=Un.omit({credentialHash:!0}),Hn=a.z.object({protocolVersion:vn,inviteToken:a.z.string().trim().min(24).max(512).optional(),claimId:wn,sourceControlPlaneId:wn,targetNodeId:wn.optional(),bindingKeyId:wn,credential:An}).strict(),Wn=a.z.object({sourceControlPlaneId:wn,bindingKeyId:wn,credential:An}).strict(),Gn=a.z.object({id:wn,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:Sn.optional(),capabilities:a.z.record(a.z.string(),a.z.unknown()).default({})}).strict(),Vn=a.z.object({protocolVersion:vn,binding:Fn,streamId:wn,revision:a.z.number().int().nonnegative(),observedAt:Sn,target:Gn}).strict(),Kn=a.z.object({type:a.z.literal("control-plane-proxy.event"),protocolVersion:vn,streamId:wn,bindingId:wn,sourceControlPlaneId:wn,targetNodeId:wn,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:Gn,event:a.z.object({type:a.z.string().trim().min(1).max(240),topic:a.z.string().trim().min(1).max(240),createdAt:Sn}).strict()}).strict(),Jn=a.z.object({type:a.z.literal("control-plane-proxy.events.ready"),protocolVersion:vn,streamId:wn,bindingId:wn,sourceControlPlaneId:wn,targetNodeId:wn,latestRevision:a.z.number().int().nonnegative(),earliestRetainedRevision:a.z.number().int().nonnegative()}).strict(),Yn=a.z.object({type:a.z.literal("control-plane-proxy.snapshot-required"),protocolVersion:vn,streamId:wn,bindingId:wn,sourceControlPlaneId:wn,targetNodeId:wn,sinceRevision:a.z.number().int().nonnegative(),latestRevision:a.z.number().int().nonnegative(),earliestRetainedRevision:a.z.number().int().nonnegative(),error:jn}).strict(),Qn=a.z.discriminatedUnion("type",[Kn,Jn,Yn]),Xn=a.z.object({protocolVersion:vn,binding:Fn,target:Vn.shape.target}).strict(),Zn=a.z.object({id:wn,claimId:wn,proxyOrigin:zn,requestedName:a.z.string().trim().min(1).max(160).optional(),sourceControlPlaneId:wn,targetNodeId:wn.optional(),bindingKeyId:wn,credential:An,status:a.z.enum(["pending","compensation-required"]),createdAt:Sn,updatedAt:Sn,expiresAt:Sn}).strict();Zn.omit({credential:!0});const ei=a.z.object({id:wn,nodeId:wn,proxyOrigin:zn,proxyBindingId:wn,targetNodeId:wn,sourceControlPlaneId:wn,bindingKeyId:wn,credential:An,createdAt:Sn,updatedAt:Sn}).strict(),ti="2026-08-01",ni=a.z.string(),ii=a.z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),si=a.z.string().datetime(),ri=a.z.record(a.z.string(),a.z.string()).default({}),oi=a.z.record(a.z.string(),a.z.string()).default({}),ai=a.z.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Protocol version must use YYYY-MM-DD format.");function di(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 ci=/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/,li=/^sha256:([a-fA-F0-9]{64})$/,pi=/^(?:localhost|[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?)(?::[1-9][0-9]{0,4})?$/,ui=/^[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*$/;function gi(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?li.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&&!ci.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]),g=u?p.slice(1):p;if(u&&!pi.test(p[0].toLowerCase()))throw new Error("Docker image registry host or port is invalid.");if(!g.length||g.some(e=>!ui.test(e)))throw new Error("Docker image repository names must be lowercase and use valid separators.");const h=p.map((e,t)=>u&&0===t?e.toLowerCase():e).join("/"),m=r?`sha256:${r[1].toLowerCase()}`:void 0;return`${h}${c?`:${c}`:""}${m?`@${m}`:""}`}function hi(e){const t=gi(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 mi=a.z.string().trim().min(1).max(512).transform((e,t)=>{try{return gi(e)}catch(e){return t.addIssue({code:"custom",message:e instanceof Error?e.message:String(e)}),a.z.NEVER}}),yi=a.z.string().trim().transform((e,t)=>{const n=li.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)}),fi=a.z.object({codexModelHash:ii.nullable().optional(),claudeModelHash:ii.nullable().optional()}).strict().default({}),Ii=a.z.object({imageId:ii,tag:a.z.string().trim().min(1).max(128).regex(ci).optional()}).strict(),bi=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("image"),imageSelection:Ii}).strict(),a.z.object({type:a.z.literal("template"),environmentTemplateId:ii}).strict()]),vi=a.z.enum(["creating","ready","failed","deleting"]),wi=a.z.enum(["linux","darwin","win32","freebsd","openbsd","aix","sunos","unknown"]),Si=a.z.enum(["x64","arm64","arm","ia32","ppc64","s390x","riscv64","unknown"]),Ai=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(),ki=a.z.object({templateId:ii,nodeId:ii,imageId:yi,name:a.z.string().trim().min(1).max(160),platform:wi,architecture:Si}).strict(),zi=a.z.enum(["data","agent-home","workspace"]),Ci=a.z.object({deleteVolumes:a.z.boolean()}).strict(),xi=a.z.object({role:zi,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(),Ti=a.z.object({instanceId:ii,containerDeleted:a.z.boolean(),completed:a.z.boolean(),deletedVolumes:a.z.array(xi),retainedVolumes:a.z.array(xi),volumeResults:a.z.array(xi)}).strict(),Ei={img_default:"market_taskhandoff_browser",img_codex:"market_taskhandoff_codex",img_ai:"market_taskhandoff_ai"};function Ni(e,t){if(e&&"object"==typeof e&&!Array.isArray(e)){const t=e;return{imageId:"string"==typeof t.imageId&&Ei[t.imageId]||t.imageId,..."string"==typeof t.tag?{tag:t.tag}:{}}}if("string"==typeof t)return{imageId:Ei[t]||t}}function Oi(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,{defaultImageId:n,...i}=t;return{...i,defaultImageSelection:Ni(t.defaultImageSelection,n)}}const _i=a.z.object({id:ii,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(),Ri=a.z.object({code:a.z.enum(["APP_CATALOG_INVALID"]),message:a.z.string().trim().min(1).max(500)}).strict(),Pi=a.z.object({items:a.z.array(_i).max(256),observedAt:si,issues:a.z.array(Ri).max(32).default([])}).strict(),ji=a.z.object({id:ii,name:a.z.string().trim().min(1).max(160),sourceInstanceId:ii,nodeId:ii,imageId:yi.optional(),internalTag:a.z.string().trim().min(1).max(512).optional(),platform:wi.optional(),architecture:Si.optional(),sizeBytes:a.z.number().int().nonnegative().optional(),status:vi,error:Ai.optional(),createdAt:si,updatedAt:si}).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."})}),Di=a.z.enum(["apt","dnf","brew","npm"]),Mi=a.z.enum(["user","passwordless-sudo","root"]),Li=a.z.object({platform:wi,arch:Si,installers:a.z.array(Di).max(8),privilege:Mi,installerAccess:a.z.object({npmGlobalWritable:a.z.boolean().optional()}).strict().optional()}).strict(),qi=a.z.enum(["installed","not-installed","broken","unsupported"]),$i=a.z.enum(["recipe","bundled","external","none"]),Bi=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(),Ui=a.z.object({id:ii,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:qi,managementSource:$i,version:a.z.string().trim().max(120).optional(),canInstall:a.z.boolean(),canUninstall:a.z.boolean(),installReason:Bi.optional(),uninstallReason:Bi.optional(),activeJobId:ii.optional()}).strict(),Fi=a.z.enum(["install","uninstall"]),Hi=a.z.enum(["queued","running","succeeded","failed","cancelled","interrupted"]),Wi=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"]}),Gi=a.z.object({executable:a.z.string().trim().min(1).max(4096),args:a.z.array(a.z.string().max(4096)).max(128)}).strict(),Vi=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(ii).max(64).optional()}).strict(),Ki=a.z.object({id:ii,requestId:ii.optional(),appId:ii,operation:Fi,state:Hi,phase:a.z.string().trim().min(1).max(120).optional(),progress:Wi.optional(),command:Gi.optional(),logTail:a.z.string().max(32768).optional(),logTruncated:a.z.boolean().optional(),error:Vi.optional(),requestedAt:si,startedAt:si.optional(),finishedAt:si.optional(),updatedAt:si}).strict(),Ji=a.z.object({streamId:ii,sequence:a.z.number().int().nonnegative(),capabilities:Li,apps:a.z.array(Ui).max(256),activeJobs:a.z.array(Ki).max(256),recentJobs:a.z.array(Ki).max(256),observedAt:si}).strict(),Yi=a.z.object({requestId:ii.optional()}).strict(),Qi=a.z.object({job:Ki}).strict();a.z.object({type:a.z.literal("app-management"),streamId:ii,sequence:a.z.number().int().nonnegative(),observedAt:si,job:Ki.optional(),snapshot:Ji.optional()}).strict().refine(e=>void 0!==e.job||void 0!==e.snapshot,{message:"An app management event requires a job or snapshot."});const Xi=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:ni.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(),Zi=a.z.object({data:a.z.object({ok:a.z.literal(!0),role:a.z.literal("control-plane"),protocolVersion:ni,build:Xi.extend({component:a.z.literal("control-plane"),packageVersion:a.z.string().trim().min(1).max(80)}).loose(),dataDir:a.z.string().min(1),serverTime:si}).loose()}).loose(),es=a.z.enum(["stable","beta","alpha"]),ts=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(),ns=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(),is=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:si.optional(),matchedAt:si.optional(),error:ns.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(ii).max(1024).default([]),stoppedInstanceIds:a.z.array(ii).max(1024).default([]),activeInstanceIds:a.z.array(ii).max(1024).default([])}).strict(),rs=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(ii).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(),os=a.z.object({channel:es.default("stable")}).strict(),as=a.z.object({source:a.z.literal("npm"),channel:es,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(ts).default([]),impact:ss,updateAvailable:a.z.boolean(),supported:a.z.boolean().default(!0),reason:a.z.string().trim().max(2048).optional(),checkedAt:si,preflightToken:a.z.string().trim().min(16).max(240).optional()}).strict(),ds=a.z.object({id:ii,nodeId:ii,source:a.z.literal("npm"),channel:es,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(ts).default([]),impact:ss,rollout:rs,status:a.z.enum(["queued","updating-node","restarting-node","converging-instances","succeeded","degraded","failed"]),error:ns.optional(),startedAt:si.optional(),completedAt:si.optional(),createdAt:si,updatedAt:si}).strict(),cs=a.z.object({channel:es,targetVersion:a.z.string().trim().min(1).max(240),preflightToken:a.z.string().trim().min(16).max(240)}).strict(),ls=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(),ps=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(),us=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:ii,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:ls.default({type:"branch",name:"main"}),auth:ps.default({type:"none"}),clone:us.default({submodules:!1,lfs:!1,subdirectory:""}),defaultImageSelection:Ii.optional(),labels:ri,createdAt:si,updatedAt:si}).strict();const gs=a.z.object({id:ii,nodeId:ii,name:a.z.string().trim().min(1).max(160),path:a.z.string().trim().min(1).max(4096),defaultImageSelection:Ii.optional(),labels:ri,createdAt:si,updatedAt:si}).strict(),hs=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("git-repository"),repositoryId:ii.optional(),url:a.z.string().trim().min(1).max(2048),provider:a.z.string().trim().max(80).optional(),ref:ls.default({type:"branch",name:"main"}),auth:ps.default({type:"none"}),clone:us.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:ls.default({type:"branch",name:"main"}),auth:ps.default({type:"none"}),clone:us.default({submodules:!1,lfs:!1,subdirectory:""})}).strict(),a.z.object({type:a.z.literal("local-folder"),localFolderId:ii.optional(),path:a.z.string().trim().min(1).max(4096),ownerNodeId:ii.optional()}).strict()]),ms=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(),ys=a.z.enum(["codex","claude"]),fs=a.z.object({id:ii,name:a.z.string().trim().min(1).max(160),source:hs,defaultImageSelection:Ii.optional(),defaultNodeId:ii.optional(),defaultRuntimeId:ii.optional(),workspacePolicy:ms,labels:ri,createdAt:si,updatedAt:si}).strict(),Is=a.z.object({id:ii,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:ys,enabled:a.z.boolean().default(!0),order:a.z.number().int().min(0).max(1e6).default(0),labels:ri,createdAt:si,updatedAt:si}).strict(),bs=Is.omit({key:!0}).extend({keyPreview:a.z.string().trim().min(1).max(160),keySet:a.z.boolean()}).strict(),vs=bs.extend({referenceCount:a.z.number().int().min(0)}).strict(),ws=a.z.object({instanceId:ii,codexModelHash:ii.optional(),claudeModelHash:ii.optional(),updatedAt:si}).strict(),Ss=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("control-plane"),name:Is.shape.name,enabled:Is.shape.enabled,order:Is.shape.order}).strict(),a.z.object({type:a.z.literal("node"),nodeId:ii,name:Is.shape.name,enabled:Is.shape.enabled,order:Is.shape.order,referenceCount:a.z.number().int().min(0)}).strict()]),As=a.z.object({id:ii,model:bs,locations:a.z.array(Ss).min(1),referenceCount:a.z.number().int().min(0).default(0)}).strict(),ks=a.z.object({nodeId:ii,code:a.z.string().trim().min(1).max(120),message:a.z.string().trim().min(1).max(2e3)}).strict(),zs=a.z.object({models:a.z.array(As),nodeDiagnostics:a.z.array(ks).default([]),updatedAt:si}).strict();function Cs(e){const t={app:ys.parse(e.app),endpoint:Is.shape.endpoint.parse(e.endpoint),key:Is.shape.key.parse(e.key),model:Is.shape.model.parse(e.model)};return`mdl_${i.createHash("sha256").update(JSON.stringify(t)).digest("hex")}`}Is.omit({id:!0,createdAt:!0,updatedAt:!0}).strict().partial().strict(),a.z.object({modelSelection:fi,codexModelHash:ii.optional(),claudeModelHash:ii.optional()}).strict();const xs=a.z.enum(["market","custom"]),Ts=a.z.enum(["active","deprecated","yanked"]),Es=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:yi.optional()}).strict()]),Ns={kind:"builtin",key:"default-image-cover"},Os=a.z.array(a.z.string().trim().min(1).max(80)).default([]),_s=a.z.array(a.z.string().trim().min(1).max(120)).default([]),Rs=a.z.record(a.z.string().trim().min(2).max(35),a.z.string().trim().min(1).max(4096)),Ps=a.z.object({os:a.z.string().trim().min(1).max(40),architecture:a.z.string().trim().min(1).max(40),digest:yi.optional(),downloadSizeBytes:a.z.number().int().positive().optional(),unpackedSizeBytes:a.z.number().int().positive().optional()}).strict(),js=a.z.object({name:a.z.string().trim().min(1).max(128).regex(ci),version:a.z.string().trim().min(1).max(160).optional(),reference:mi,manifestDigest:yi.optional(),publishedAt:si.optional(),platforms:a.z.array(Ps).default([]),status:Ts.default("active")}).strict(),Ds=a.z.object({id:ii,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:Rs.optional(),cover:Es.optional(),repository:a.z.string().trim().min(1).max(512),defaultTag:a.z.string().trim().min(1).max(128).regex(ci),tags:a.z.array(js).min(1),capabilities:Os,optionalApps:_s,defaultEnv:oi,labels:ri,status:Ts.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."})}),Ms=a.z.object({protocolVersion:ai,catalogId:ii,revision:a.z.string().trim().min(1).max(240),source:a.z.enum(["embedded","remote","cache"]),generatedAt:si,expiresAt:si.optional(),items:a.z.array(Ds)}).strict(),Ls=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:si,error:a.z.string().trim().max(4096).optional()}).strict(),qs=a.z.object({id:ii,origin:a.z.literal("custom"),name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().max(4096).optional(),localizedDescriptions:Rs.optional(),cover:Es.optional(),reference:mi,repository:a.z.string().trim().min(1).max(512),tag:a.z.string().trim().min(1).max(128).regex(ci).optional(),pullPolicy:a.z.literal("if-not-present").default("if-not-present"),capabilities:Os,optionalApps:_s,defaultEnv:oi,labels:ri,createdAt:si,updatedAt:si}).strict(),$s=a.z.object({name:a.z.string().trim().min(1).max(128).regex(ci),version:a.z.string().trim().min(1).max(160).optional(),reference:mi,manifestDigest:yi.optional(),status:Ts}).strict(),Bs=a.z.object({id:ii,origin:xs,name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().max(4096).optional(),localizedDescriptions:Rs.optional(),cover:Es,repository:a.z.string().trim().min(1).max(512),tag:a.z.string().trim().min(1).max(128).regex(ci).optional(),availableTags:a.z.array($s),reference:mi,digest:yi.optional(),downloadSizeBytes:a.z.number().int().positive().optional(),unpackedSizeBytes:a.z.number().int().positive().optional(),capabilities:Os,optionalApps:_s,defaultEnv:oi,labels:ri,readOnly:a.z.boolean(),lifecycleStatus:Ts.optional(),market:a.z.object({catalogId:ii,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(),Us=a.z.object({id:ii,origin:xs,name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().max(4096).optional(),localizedDescriptions:Rs.optional(),cover:Es.optional(),repository:a.z.string().trim().min(1).max(512),tag:a.z.string().trim().min(1).max(128).regex(ci).optional(),requestedReference:mi,resolvedDigest:yi.optional(),resolvedReference:mi.optional(),downloadSizeBytes:a.z.number().int().positive().optional(),pullPolicy:a.z.literal("if-not-present").default("if-not-present"),capabilities:Os,optionalApps:_s,defaultEnv:oi,labels:ri,market:a.z.object({catalogId:ii,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:si,updatedAt:si}).strict(),Fs=a.z.object({phase:a.z.enum(["checking-image","pulling-image","resolving-image","ready","failed"]),requestedReference:mi,generation:a.z.number().int().nonnegative().default(0),error:a.z.string().trim().max(4096).optional(),startedAt:si,updatedAt:si}).strict(),Hs="image.pull.terminal.output",Ws="image.pull.terminal.finished",Gs=a.z.object({instanceId:ii,generation:a.z.number().int().nonnegative(),requestedReference:mi,sequence:a.z.number().int().nonnegative(),observedAt:si}).strict(),Vs=Gs.extend({data:a.z.string().min(1).max(65536),replay:a.z.boolean().optional()}).strict(),Ks=Gs.extend({outcome:a.z.enum(["succeeded","failed"])}).strict(),Js=Gs.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 Ys(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=gi(a)}catch{if(!a.includes("@")&&a.lastIndexOf(":")<=a.lastIndexOf("/"))try{a=gi(`${a}:latest`),t?.({imageId:s,field:"reference:implicit-latest"})}catch{}}try{o=a?hi(a):void 0}catch{}return{id:n.id,origin:"custom",name:n.name,description:n.description,localizedDescriptions:n.localizedDescriptions,cover:Ar(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 Qs=a.z.discriminatedUnion("kind",[a.z.object({kind:a.z.literal("direct")}).strict(),a.z.object({kind:a.z.literal("control-plane-proxy"),proxyId:ii,proxyBindingId:ii,targetNodeId:ii}).strict()]),Xs=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:si.optional(),target:Gn.optional(),lastError:jn.optional(),updatedAt:si}).strict(),Zs=a.z.object({id:ii,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:Qs.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:ii.optional(),secret:a.z.string().trim().max(4096).optional(),pairedAt:si.optional(),pairing:a.z.object({status:a.z.enum(["pending","paired","expired"]).default("pending"),joinToken:a.z.string().trim().max(4096).optional(),expiresAt:si.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:Xs.optional(),appInventory:Pi.optional(),labels:ri,lastSeenAt:si.optional(),createdAt:si,updatedAt:si}).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."})}),er=a.z.object({id:ii,nodeId:ii,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:ri,createdAt:si,updatedAt:si}).strict(),tr=a.z.object({instanceId:ii,runtimeKind:a.z.literal("docker"),state:a.z.enum(["pending","available","stopped","unavailable"]),sampledAt:si,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(),nr=a.z.object({ok:a.z.boolean().optional(),role:a.z.string().optional(),nodeId:ii.optional(),platform:wi.optional(),arch:Si.optional(),protocolVersion:ni.optional(),build:Xi.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:si.optional()}).strip(),ir=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(),sr=a.z.object({nodeId:ii,joinToken:a.z.string().trim().min(1),expiresAt:si}).passthrough(),rr=a.z.object({nodeId:ii,keyId:ii,secret:a.z.string().regex(/^[A-Za-z0-9_-]{32,128}$/),pairedAt:si}).strict(),or=a.z.object({id:ii,keyId:ii,name:a.z.string().trim().min(1).max(160).optional(),pairedAt:si,updatedAt:si,current:a.z.boolean()}).passthrough(),ar=a.z.object({keyId:ii,revoked:a.z.literal(!0),revokedAt:si}).strict(),dr=a.z.object({id:ii,pairingKeyId:ii,url:a.z.string().trim().min(1).max(2048),name:a.z.string().trim().min(1).max(160).optional(),enabled:a.z.boolean(),createdAt:si,updatedAt:si,status:a.z.enum(["disabled","connecting","connected","reconnecting","failed"]),lastConnectedAt:si.optional(),lastDisconnectedAt:si.optional(),error:a.z.string().optional()}).passthrough(),cr=a.z.object({pairing:or,connection:a.z.object({id:ii,pairingKeyId:ii,url:a.z.string().trim().min(1).max(2048),name:a.z.string().trim().min(1).max(160).optional(),enabled:a.z.boolean(),createdAt:si,updatedAt:si}).passthrough(),tunnel:a.z.object({status:a.z.enum(["disabled","saved","connecting","connected","failed"]),error:a.z.string().trim().max(2048).optional()}).passthrough()}).passthrough(),lr=a.z.object({deleted:a.z.boolean().optional()}).passthrough(),pr=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(),ur=a.z.object({image:Bs,status:a.z.enum(["available","pull-required","unknown"]),localImage:pr.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(),gr=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(gr)}).passthrough()),hr=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(),mr=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(),yr=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"}),fr=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(),Ir=a.z.object({id:ii,name:a.z.string().trim().min(1).max(160),projectId:ii.optional(),source:hs,sourceSnapshot:a.z.record(a.z.string(),a.z.unknown()).default({}),modelSelection:fi,nodeId:ii,runtimeId:ii,imageSelection:Ii.optional(),environmentSource:bi.optional(),environmentTemplateOrigin:ki.optional(),imageSnapshot:Us.optional(),imageProvisioning:Fs.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:ni.optional(),instanceVersion:a.z.string().trim().max(80).optional(),build:Xi.optional(),runtimeVersion:is.optional(),ready:a.z.boolean().default(!1),capabilities:a.z.record(a.z.string(),a.z.unknown()).default({}),appInventory:Pi.optional(),config:a.z.object({autoImportAgentConfigs:a.z.boolean().default(!0),defaultCodexPermissionMode:Z.default("ask")}).strict().default({autoImportAgentConfigs:!0,defaultCodexPermissionMode:"ask"}),workspace:fr.default({status:"unknown"}),target:mr.default({strategy:"direct-port",status:"unknown"}),access:yr,apps:a.z.object({runningCount:a.z.number().int().min(0).default(0),problemCount:a.z.number().int().min(0).default(0),updatedAt:si.optional(),revision:a.z.number().int().min(0).optional()}).strict().default({runningCount:0,problemCount:0}),aiSessions:Fe.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:on,deployments:a.z.array(dn).default([]),runtime:a.z.array(cn).default([])}).strict()).default([]),recentRuns:a.z.array(ln).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:si.optional(),createdAt:si,updatedAt:si}).strict(),br="instance.lifecycle.snapshot",vr=a.z.object({instanceId:Ir.shape.id,revision:a.z.number().int().min(0),updatedAt:si,status:Ir.shape.status.unwrap(),health:Ir.shape.health.unwrap(),connectionStatus:Ir.shape.connectionStatus.unwrap(),accessStatus:a.z.enum(["reachable","endpoint-unreachable"]),imageProvisioning:Fs.optional(),workspace:fr,runtime:Ir.shape.runtime.unwrap(),runtimeVersion:is.optional(),ready:a.z.boolean(),lastHeartbeatAt:si.optional()}).strict();function wr(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=Sr(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=Sr(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 Sr(e,t){let n=e;for(const e of t){if(!n||"object"!=typeof n)return;n=n[e]}return n}function Ar(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:ii.optional(),projectId:ii.optional(),source:hs.optional(),nodeId:ii.optional(),runtimeId:ii.optional(),imageSelection:Ii.optional(),instanceVersion:a.z.string().trim().max(80).optional(),protocolVersion:ni,build:Xi.optional(),controlMode:a.z.enum(["standalone","controlled"]).default("controlled"),capabilities:a.z.record(a.z.string(),a.z.unknown()).default({}),appInventory:Pi.optional(),target:mr.default({strategy:"direct-port",status:"unknown"}),workspace:fr.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)=>{e.protocolVersion!==ti||e.appInventory||t.addIssue({code:"custom",path:["appInventory"],message:"Current protocol register payload requires appInventory."})}),a.z.object({status:Ir.shape.status.optional(),health:Ir.shape.health.optional(),protocolVersion:ni,build:Xi.optional(),capabilities:Ir.shape.capabilities.optional(),appInventory:Pi.optional(),apps:Ir.shape.apps.optional(),aiSessions:Ir.shape.aiSessions.optional(),triggers:Ir.shape.triggers.optional(),workspace:fr.optional(),target:mr.partial().optional(),processIncarnationId:a.z.string().trim().min(1).max(120).optional()}).strict().superRefine((e,t)=>{e.protocolVersion!==ti||e.appInventory||t.addIssue({code:"custom",path:["appInventory"],message:"Current protocol heartbeat payload requires appInventory."})});const kr=a.z.enum(["web","telegram","wechat","dingding","lark"]),zr=a.z.object({id:ii,channel:kr,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:si,updatedAt:si}).strict(),Cr=a.z.object({id:ii,channel:kr,bridgeId:ii.optional(),chatSessionId:a.z.string().trim().min(1).max(240),userId:a.z.string().trim().max(240).optional(),activeProjectId:ii.optional(),activeInstanceId:ii.optional(),activeAiSessionId:a.z.string().trim().min(1).max(120).optional(),lastUsedAt:si,createdAt:si,updatedAt:si}).strict(),xr=a.z.object({source:a.z.object({type:a.z.literal("chat-gateway").default("chat-gateway"),channel:kr,bridgeId:ii.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(J).max(6).default([])}).strict().superRefine((e,t)=>{e.attachments.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>E&&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:ii,aiSessionId:a.z.string().trim().min(1).max(120)}).strict().optional()}).strict(),Tr=a.z.object({id:ii,instanceId:ii,projectId:ii.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:si}).strict();function Er(e){return!1!==e.ready&&(!e.runtimeVersion||["matched","failed"].includes(e.runtimeVersion.phase))}const Nr=6048e5;function Or(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 _r(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 Rr(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 Pr=a.z.enum(["ai.sessions","app.sessions"]),jr=a.z.object({topic:Pr,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(),Dr=a.z.object({protocolVersion:a.z.literal(1),streams:a.z.array(jr)}).strict(),Mr=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(),Lr=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:Mr,protocolVersion:a.z.string().regex(/^\d{4}-\d{2}-\d{2}$/),issuedAt:a.z.string().datetime(),expiresAt:a.z.string().datetime()}).strict(),qr=a.z.object({data:a.z.object({payload:Lr,signature:a.z.string().regex(/^[A-Za-z0-9_-]{86}$/)}).strict()}).strict(),$r=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(),Br=a.z.object({username:a.z.string().trim().min(1).max(80),password:a.z.string().min(1).max(4096),device:$r}).strict(),Ur=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(),Fr=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:$r,user:Ur}).strict();a.z.object({data:a.z.object({sessionToken:a.z.string().trim().min(32),session:Fr}).strict()}).strict(),a.z.object({data:a.z.array(Fr)}).strict(),a.z.object({data:a.z.object({revoked:a.z.boolean()}).strict()}).strict();function Hr(e,t=448){n.mkdirSync(e,{recursive:!0,mode:t}),n.chmodSync(e,t)}function Wr(e,i,s={}){const r=s.directoryMode??448,o=s.fileMode??384;Hr(t.dirname(e),r),c.sync(e,`${JSON.stringify(i,null,2)}\n`,{encoding:"utf8",mode:o}),n.chmodSync(e,o)}function Gr(e,t){console.warn(JSON.stringify({message:e,...t}))}function Vr(e){return e&&"object"==typeof e&&"issues"in e?{issues:e.issues}:{error:e instanceof Error?e.message:String(e)}}function Kr(e,t){const i=t.logger||Gr;let s;try{s=JSON.parse(n.readFileSync(e,"utf8"))}catch(t){return void i("stored JSON could not be read",{filePath:e,...Vr(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 Jr(e){return`${e}_${i.randomUUID().replace(/-/g,"").slice(0,20)}`}function Yr(){return i.randomBytes(24).toString("base64url")}class Qr{directory;options;permissionsInitialized=!1;constructor(e,t={}){this.directory=e,this.options=t}init(){if(this.permissionsInitialized&&n.existsSync(this.directory))return;Hr(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=Kr(t.join(this.directory,e),this.options);return n?[n]:[]})}get(e){this.init();const t=this.filePath(e);return n.existsSync(t)?Kr(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 Wr(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 Xr{filePathValue;defaults;options;constructor(e,t,n={}){this.filePathValue=e,this.defaults=t,this.options=n}init(){Hr(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)?Kr(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 Wr(this.filePathValue,n,this.options),n}}const Zr=d.promisify(i.scrypt),eo="task_handoff_cp_session",to=a.z.enum(["disabled","password"]),no=a.z.string().trim().min(1).max(80).regex(/^[a-zA-Z0-9_.@-]+$/),io=a.z.string().min(8).max(4096),so=a.z.object({username:no,password:io}).strict(),ro=a.z.object({username:a.z.string().trim().min(1).max(80),password:a.z.string().min(1).max(4096)}).strict(),oo=a.z.object({currentPassword:a.z.string().min(1).max(4096),newPassword:io}).strict(),ao=a.z.object({username:no,password:io}).strict(),co=a.z.object({id:a.z.string().trim().min(1),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}),lo=co.extend({username:no,passwordHash:a.z.string().trim().min(1),role:a.z.enum(["viewer","operator","admin"]),lastLoginAt:a.z.string().datetime().optional()}).strict(),po=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:$r.optional()}).strict().refine(e=>"mobile"!==e.clientType||Boolean(e.device),{path:["device"],message:"Mobile sessions require device metadata."});function uo(){return(new Date).toISOString()}function go(e,t){return Number.isInteger(e)&&Number(e)>0?Number(e):t}class ho{options;sourceFailures=new Map;usernameFailures=new Map;concurrent=0;constructor(e={}){this.options=function(e={}){return{windowMs:go(e.windowMs,9e5),maxFailuresPerSource:go(e.maxFailuresPerSource,20),maxFailuresPerUsername:go(e.maxFailuresPerUsername,10),maxConcurrent:go(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 mo("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 mo("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 mo(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 yo(e){return i.createHash("sha256").update(e).digest("base64url")}async function fo(e){const t=i.randomBytes(16).toString("base64url");return`scrypt$${t}$${(await Zr(e,t,64)).toString("base64url")}`}async function Io(e,t){const[n,s,r]=t.split("$");if("scrypt"!==n||!s||!r)return!1;const o=await Zr(e,s,64),a=Buffer.from(r,"base64url");return a.length===o.length&&i.timingSafeEqual(a,o)}function bo(e){return{id:e.id,username:e.username,role:e.role,createdAt:e.createdAt,updatedAt:e.updatedAt,lastLoginAt:e.lastLoginAt}}function vo(e,t){return Fr.parse({id:e.id,expiresAt:e.expiresAt,createdAt:e.createdAt,lastSeenAt:e.lastSeenAt,device:e.device,user:bo(t)})}class wo{mode;users;sessions;loginRateLimiter;bootstrapAdminInProgress=!1;credentialUpdateInProgress=!1;constructor(e,t={}){this.mode=function(e={}){return to.parse(e.mode||process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"disabled")}(t),this.users=new Qr(e.authUsersDir,{schema:lo}),this.sessions=new Qr(e.authSessionsDir,{schema:po}),this.loginRateLimiter=new ho(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=so.parse(e);this.bootstrapAdminInProgress=!0;try{const e=uo();return bo(this.users.put({id:Jr("user"),username:t.username,passwordHash:await fo(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=ro.parse(e),i=await this.authenticate(n.username,n.password,t),s=this.createSession(i,"web");return{user:bo(i),sessionToken:s.token,expiresAt:s.record.expiresAt}}async loginMobile(e,t={}){const n=Br.parse(e),i=await this.authenticate(n.username,n.password,t),s=this.createSession(i,"mobile",n.device);return{sessionToken:s.token,session:vo(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=oo.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 Io(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 Io(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=uo(),t=this.users.put({...i.storedUser,passwordHash:await fo(s.newPassword),updatedAt:e});this.revokeUserSessions(t.id);const n=this.createSession(t,"web");return{user:bo(t),sessionToken:n.token,expiresAt:n.record.expiresAt}}finally{a&&this.loginRateLimiter.finish(),this.credentialUpdateInProgress=!1}}async replaceCredentials(e){const t=ao.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=uo(),s=this.users.put({...n[0],username:t.username,passwordHash:await fo(t.password),updatedAt:i});return this.revokeUserSessions(s.id),bo(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 Io(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=uo();return this.users.put({...n,lastLoginAt:r,updatedAt:r})}finally{this.loginRateLimiter.finish()}}createSession(e,t,n){const i=uo(),s=Yr(),r=this.sessions.put({id:Jr("mobile"===t?"msess":"sess"),userId:e.id,tokenHash:yo(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<=uo()||s.tokenHash!==yo(i))return;const r=this.users.get(s.userId);if(!r)return;const o=uo();return{session:this.sessions.put({...s,lastSeenAt:o,updatedAt:o}),user:bo(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>uo()).map(e=>vo(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 So(e,t){let n=xo(t);for(let t=0;t<100;t+=1){const t=e.safeParse(n);if(t.success)return t;const i=ko(t.error.issues);let s=!1;for(const e of i){const t=Co(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 Ao(e,t){const n=So(e,t);if(!n.success)throw n.error;return n.data}function ko(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)=>zo(t)<zo(e)?t:e);n.push(...ko(s,[...t,...i.path]))}return n}function zo(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(zo)):1)},0)}function Co(e,t){let n=e;for(const e of t){if(!n||"object"!=typeof n)return;n=n[e]}return n}function xo(e){return Array.isArray(e)?e.map(xo):e&&"object"==typeof e?Object.getPrototypeOf(e)!==Object.prototype&&null!==Object.getPrototypeOf(e)?e:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,xo(t)])):e}const To=a.z.enum(["import","export"]),Eo=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(),No=a.z.object({direction:To,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(),Oo=a.z.object({import:a.z.string().trim().min(1).max(1e3).default("."),export:a.z.string().trim().min(1).max(1e3).default(".")}).strict(),_o=a.z.object({programs:a.z.array(Eo),preferences:Oo}).strict(),Ro=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(),Po=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:To,items:a.z.array(Ro).max(100)}).strict(),jo=a.z.object({direction:To,workspaceFolder:a.z.string().trim().min(1).max(1e3),programs:a.z.array(Po).min(1).max(20)}).strict(),Do=a.z.string().trim().min(1).max(160).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Mo=a.z.string().datetime(),Lo=a.z.string().trim().min(1).max(255).refine(e=>!(/[\u0000-\u001f\u007f ~^:?*[\\]/.test(e)||e.includes("..")||e.endsWith(".")||e.endsWith("/")),"Invalid Git name."),qo=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."),$o=a.z.enum(["ai-session","app-session"]),Bo=a.z.enum(["available","session-not-found","session-inactive","cwd-missing","cwd-inaccessible","git-unavailable","not-worktree"]),Uo=a.z.enum(["branch","detached","unborn"]),Fo=a.z.enum(["review-changes","resolve-conflicts","publish-branch","push","pull","diverged","up-to-date"]),Ho=a.z.enum(["conflict","staged","unstaged","untracked"]),Wo=a.z.enum(["added","modified","deleted","renamed","copied","type-changed","unmerged","untracked"]),Go=a.z.object({state:Uo,oid:a.z.string().regex(/^[0-9a-f]{40,64}$/).optional(),branch:a.z.string().min(1).max(1024).optional()}).strict(),Vo=a.z.object({ref:a.z.string().min(1).max(2048),remote:Lo,branch:a.z.string().min(1).max(1024),ahead:a.z.number().int().nonnegative(),behind:a.z.number().int().nonnegative()}).strict(),Ko=a.z.object({id:Do,isCurrent:a.z.boolean(),isMain:a.z.boolean(),managed:a.z.boolean(),head:Go,dirty:a.z.boolean(),locked:a.z.boolean(),lockReason:a.z.string().max(1e3).optional(),prunable:a.z.boolean(),activeAiSessionIds:a.z.array(Do).max(256).default([]),activeAppSessionIds:a.z.array(Do).max(256).default([])}).strict(),Jo=a.z.enum(["main-worktree","external-worktree","outside-workspace-roots","dirty","locked","prunable","session-occupied","path-inaccessible"]),Yo=Ko.extend({canCreateAiSession:a.z.boolean(),canRemove:a.z.boolean(),createAiSessionBlockers:a.z.array(Jo).max(16).default([]),removeBlockers:a.z.array(Jo).max(16).default([])}).strict(),Qo=a.z.object({repositoryId:Do,repositoryContextId:Do,snapshotId:Do,items:a.z.array(Yo).max(1e4)}).strict(),Xo=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(),Zo=a.z.object({name:Lo,fetchUrl:a.z.string().max(4096).optional(),pushUrl:a.z.string().max(4096).optional()}).strict(),ea=a.z.object({availability:Bo,sessionKind:$o,sessionId:Do,observedAt:Mo,snapshotId:Do.optional(),repositoryId:Do.optional(),repositoryContextId:Do.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:Go.optional(),upstream:Vo.optional(),currentWorktree:Ko.optional(),changes:Xo.optional(),remotes:a.z.array(Zo).max(128).optional(),primaryAction:Fo.optional()}).strict(),ta=a.z.enum(["directory","file","symlink","submodule","nested-repository","special"]),na=a.z.object({executable:a.z.boolean(),gitMode:a.z.enum(["100644","100755","120000","160000"]).optional()}).strict(),ia=a.z.object({name:a.z.string().min(1).max(1024),path:qo,kind:ta,traversable:a.z.boolean(),editable:a.z.boolean(),size:a.z.number().int().nonnegative().optional(),mode:na.optional()}).strict();a.z.object({path:a.z.string().max(4096),entries:a.z.array(ia).max(1e4),snapshotId:Do}).strict();const sa=a.z.string().min(16).max(160).regex(/^[a-zA-Z0-9_.:-]+$/),ra=a.z.object({path:qo,content:a.z.string(),byteLength:a.z.number().int().nonnegative(),version:sa,mode:na}).strict(),oa=a.z.object({path:qo,oldPath:qo.optional(),scope:Ho,status:Wo,version:sa,binary:a.z.boolean().default(!1)}).strict(),aa=a.z.object({snapshotId:Do,summary:Xo,entries:a.z.array(oa).max(1e5)}).strict();a.z.object({file:ra.optional(),snapshotId:Do,context:ea,changes:aa}).strict();const da=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:qo,oldPath:qo.optional(),scope:Ho,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(da).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(da).max(6e3),startLineCount:a.z.number().int().nonnegative().max(3e3),hasMore:a.z.boolean()}).strict()).max(2e4),version:sa,snapshotId:Do}).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(Do).max(256).default([])}).strict(),la=a.z.object({snapshotId:Do,branches:a.z.array(ca).max(1e5)}).strict();a.z.object({snapshotId:Do,context:ea,branches:la}).strict(),a.z.object({ok:a.z.literal(!0),snapshotId:Do,context:ea,changes:aa.optional(),commitOid:a.z.string().regex(/^[0-9a-f]{40,64}$/).optional()}).strict();const pa=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:pa,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 ua=a.z.object({expectedSnapshotId:Do}).strict(),ga=a.z.object({path:qo,expectedVersion:sa}).strict();a.z.object({path:qo,content:a.z.string().max(4194304),expectedAbsent:a.z.literal(!0),expectedSnapshotId:Do}).strict(),a.z.object({path:qo,content:a.z.string().max(4194304),expectedVersion:sa,expectedSnapshotId:Do}).strict(),a.z.object({path:qo,destination:qo,expectedVersion:sa,expectedDestinationAbsent:a.z.literal(!0),expectedSnapshotId:Do}).strict(),a.z.object({path:qo,expectedVersion:sa,expectedSnapshotId:Do,confirm:a.z.literal(!0)}).strict(),ua.extend({paths:a.z.array(ga).min(1).max(1e3)}).strict(),ua.extend({paths:a.z.array(ga).min(1).max(1e3)}).strict(),ua.extend({paths:a.z.array(ga).min(1).max(1e3),confirm:a.z.literal(!0)}).strict(),ua.extend({paths:a.z.array(ga).min(1).max(1e3),confirm:a.z.literal(!0)}).strict(),ua.extend({message:a.z.string().trim().min(1).max(65536)}).strict();const ha=a.z.discriminatedUnion("mode",[a.z.object({mode:a.z.literal("new-branch"),branchName:Lo,startRef:a.z.string().trim().min(1).max(2048),expectedSnapshotId:Do}).strict(),a.z.object({mode:a.z.literal("existing-branch"),branchName:Lo,expectedSnapshotId:Do}).strict()]);ua.extend({worktreeId:Do,confirm:a.z.literal(!0)}).strict(),a.z.object({worktreeId:Do,worktrees:Qo}).strict(),a.z.object({removedWorktreeId:Do,branchRetained:a.z.boolean(),worktrees:Qo}).strict();const ma=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("current")}).strict(),a.z.object({type:a.z.literal("worktree"),repositoryContextId:Do,worktreeId:Do}).strict()]);a.z.object({agent:a.z.enum(["codex","claude"]),workspaceSelection:ma,message:a.z.string().trim().min(1).max(2e4),clientRequestId:Do,permissionMode:a.z.enum(["ask","auto-review","full-access"]).optional()}).strict(),a.z.object({agent:a.z.enum(["codex","claude"]),worktree:ha,message:a.z.string().trim().min(1).max(2e4),clientRequestId:Do,permissionMode:a.z.enum(["ask","auto-review","full-access"]).optional()}).strict(),a.z.object({aiSessionId:Do,providerSessionId:a.z.string().trim().min(1).max(240),worktreeId:Do,disposition:a.z.literal("started")}).strict();const ya=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(),fa=a.z.object({availability:Bo,currentBranch:a.z.string().min(1).max(1024).optional(),dirty:a.z.boolean().default(!1),branches:a.z.array(ya).max(1e5).default([])}).strict();a.z.object({cwd:me}).strict();const Ia=fe;ye.extend({gitSelection:Ia}).strict(),ua.extend({name:Lo}).strict(),ua.extend({branch:a.z.string().trim().min(1).max(2048)}).strict(),ua.extend({name:Lo,remoteTrackingRef:a.z.string().trim().min(1).max(2048)}).strict(),ua.extend({name:Lo,confirm:a.z.literal(!0)}).strict(),ua.extend({remote:Lo}).strict(),ua.extend({remote:Lo,sourceBranch:Lo,targetBranch:Lo,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"]}),ua.extend({remote:Lo,sourceBranch:Lo,targetBranch:Lo}).strict();class ba{options;resumeSnapshotRefreshFailures=0;lastResumeSnapshotRefreshFailure;constructor(e){this.options=e}async resolveApproval(e,t,n){return Ao(Me,await this.post(e,ka(t,"approval"),{decision:n}))}async listHistory(e){return Ao(qe,await this.get(e,"/ai-sessions/history"))}async historyDetail(e,t){return Ao($e,await this.get(e,`/ai-sessions/history/${encodeURIComponent(t)}`))}async resume(e,t){const n=Ao(Be,await this.post(e,ka(t,"resume"),{}));return await this.refreshAfterCommittedResume(e,t),n}async create(e,t){Ca(t.attachments||[]);const n=await this.options.requireInstance(e),i=va(n);if(t.gitSelection&&!i)throw wa();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 Ao(be,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(!va(n))throw wa();return Ao(fa,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=Ao(Se,await this.post(e,ka(t,"fork"),n));try{await this.options.refreshSnapshots()}catch(n){try{this.options.warn?.({instanceId:e,aiSessionId:t,providerSessionId:i.providerSessionId,code:Sa(n),message:Aa(n)},"AI session Fork committed but snapshot refresh failed")}catch{}}return i}async openApp(e,t,n){return Ao(ke,await this.post(e,ka(t,"open-app"),{clientRequestId:n}))}async close(e,t,n){return Ao(Ce,await this.post(e,ka(t,"close"),{clientRequestId:n}))}async refreshAfterCommittedResume(e,t){try{await this.options.refreshSnapshots()}catch(n){const i={instanceId:e,aiSessionId:t,code:Sa(n),message:Aa(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){Ca(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 Ao(Me,await this.options.request(a,ka(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 Ao(ce,await this.get(e,ka(t,"mentions")))}async searchMentionFiles(e,t,n){return Ao(pe,await this.post(e,ka(t,"mentions/files"),{query:n}))}async executeCommand(e,t,n){return Ao(ne,await this.post(e,ka(t,"commands"),n))}async queue(e,t){return Ao(Oe,await this.get(e,ka(t,"queue")))}async steerQueuedMessage(e,t,n){return Ao(Me,await this.post(e,za(t,n,"steer"),{}))}async retryQueuedMessage(e,t,n){return Ao(De,await this.post(e,za(t,n,"retry"),{}))}async removeQueuedMessage(e,t,n){const i=await this.options.requireInstance(e);return Ao(De,await this.options.request(i,za(t,n),{method:"DELETE"}))}async editQueuedMessage(e,t,n,i){const s=Ee.parse(i);return Ao(De,await this.patch(e,za(t,n),s))}async reorderQueuedMessages(e,t,n){const i=Te.parse(n);return Ao(De,await this.patch(e,ka(t,"queue/reorder"),i))}async interrupt(e,t){return Ao(Me,await this.post(e,ka(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 va(e){const t=e.capabilities?.features;return Boolean(t&&"object"==typeof t&&!Array.isArray(t)&&!0===t.aiSessionWorkspaceSelection)}function wa(){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 Sa(e){return e&&"object"==typeof e&&"code"in e&&"string"==typeof e.code?e.code:"AI_SESSION_SNAPSHOT_REFRESH_FAILED"}function Aa(e){return e instanceof Error?e.message:String(e)}function ka(e,t){return`/ai-sessions/${encodeURIComponent(e)}/${t}`}function za(e,t,n){return`${ka(e,"queue")}/${encodeURIComponent(t)}${n?`/${n}`:""}`}function Ca(e){if(e.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)<=E)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 xa(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 Ta{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=So(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 Ea{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",nr)}checkUpdate(e,t){return this.client.requestSchema(e,"/updates/check",as,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}applyUpdate(e,t){return this.client.requestSchema(e,"/updates/apply",ds,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}listUpdateJobs(e){return this.client.requestSchema(e,"/updates/jobs",a.z.array(ds))}getExternalListener(e){return this.client.requestSchema(e,"/settings/external-listener",ir)}updateExternalListener(e,t){return this.client.requestSchema(e,"/settings/external-listener",ir,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}createPairingInvite(e,t={}){return this.client.requestSchema(e,"/pairing/invites",sr,{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(or))}deleteControlPlanePairing(e,t){return this.client.requestSchema(e,`/control-plane-pairings/${encodeURIComponent(t)}`,lr,{method:"DELETE"})}listControlPlaneConnections(e){return this.client.requestSchema(e,"/control-plane-connections",a.z.array(dr))}deleteControlPlaneConnection(e,t){return this.client.requestSchema(e,`/control-plane-connections/${encodeURIComponent(t)}`,lr,{method:"DELETE"})}listDockerImages(e){return this.client.requestSchema(e,"/docker/images",a.z.array(pr))}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(gr))}listLocalFolders(e,t={}){return this.client.requestSchema(e,"/local-folders",a.z.array(gs),t)}createLocalFolder(e,t){return this.client.requestSchema(e,"/local-folders",gs,{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(er),t)}createRuntime(e,t){return this.client.requestSchema(e,"/runtimes",er,{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,er,{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,er,{method:"POST"})}deleteRuntime(e,t){return this.client.requestSchema(e,`/runtimes/${encodeURIComponent(t)}`,lr,{method:"DELETE"})}deleteLocalFolder(e,t){return this.client.requestSchema(e,`/local-folders/${encodeURIComponent(t)}`,lr,{method:"DELETE"})}listModels(e,t={}){return this.client.requestSchema(e,"/models",a.z.array(vs),t)}createModel(e,t){return this.client.requestSchema(e,"/models",vs,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}deployModel(e,t,n){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}/deploy`,vs,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}updateModel(e,t,n){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}`,vs,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteModel(e,t){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}`,lr,{method:"DELETE"})}assignInstanceModels(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/model-assignment`,a.z.object({assignment:ws,instance:Ir}).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(xa(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",Ir,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}updateInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}`,Ir,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/delete`,Ti,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}listEnvironmentTemplates(e,t={}){return this.client.requestSchema(e,"/environment-templates",a.z.array(ji),t)}getEnvironmentTemplate(e,t,n={}){return this.client.requestSchema(e,`/environment-templates/${encodeURIComponent(t)}`,ji,n)}createEnvironmentTemplate(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/environment-templates`,ji,{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:ji.shape.id}).strict(),{method:"DELETE"})}startInstance(e,t,n={}){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/start`,Ir,{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`,Ir,{method:"POST"})}stopInstance(e,t){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/stop`,Ir,{method:"POST"})}restartInstance(e,t,n={}){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/restart`,Ir,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}instanceResourceMetrics(e,t){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/metrics`,tr)}proxyRawInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/proxy/raw`,hr,{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:[xa(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,Ir.safeParse(function(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,n=new Set(Object.keys(Ir.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=e}else i.capabilities={};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=Ar(e,["id","name","kind","source","availability","diagnosticCode"]);return!t||"object"!=typeof t||Array.isArray(t)?t:{...t,capabilities:Ar(e.capabilities,["automation","supportsCwdSelection"])}}):t.items,issues:Array.isArray(t.issues)?t.issues.map(e=>Ar(e,["code","message"])):t.issues},i=Pi.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=hs.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=Ar(t,s);if("local-folder"!==n){const e=wr(ls,Ar(t.ref,["type","name","commit"])),n=wr(ps,Ar(t.auth,["type","secretId"])),i=wr(us,Ar(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=wr(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=wr(Xi,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=wr(Ue,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:si.safeParse(t.updatedAt).success?t.updatedAt:(new Date).toISOString()};return Object.keys(t).some(e=>!["runningCount","waitingCount","staleCount","sessions","updatedAt"].includes(e)),Fe.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=wr(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=Ar(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=Ar(e,i)}return n.action=Ar(t.action,["promptTemplate"]),n.policy=Ar(t.policy,["cooldownMs","maxConcurrentRuns","whenBusy"]),wr(on,n)}(i.config);return"string"==typeof i.configHash&&s?[{configHash:i.configHash,config:s,deployments:n(i.deployments,dn),runtime:n(i.runtime,cn)}]:[]}):[];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,ln)}}(t.triggers,"string"==typeof t.id&&t.id),i.apps=wr(Ir.shape.apps.unwrap(),Ar(t.apps,["runningCount","problemCount","updatedAt","revision"]),0,0,"string"==typeof t.id&&t.id)||{runningCount:0,problemCount:0},i.config=wr(Ir.shape.config.unwrap(),Ar(t.config,["autoImportAgentConfigs","defaultCodexPermissionMode"]),0,0,"string"==typeof t.id&&t.id)||{autoImportAgentConfigs:!0,defaultCodexPermissionMode:"ask"},i.modelSelection=wr(fi.unwrap(),Ar(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=Ys(n),{reference:s,...r}=i,o=n.requestedReference??s;let a;try{a="string"==typeof o?hi(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?Ar(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=Ar(t.imageSelection,["imageId","tag"]);i.imageSelection=r||(s?{imageId:s,tag:i.imageSnapshot?.tag}:void 0),i.imageProvisioning=wr(Fs,Ar(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(is.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(ns.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=si.safeParse(t.lastAttemptAt),l=si.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=wr(fr,t.workspace,0,0,"string"==typeof t.id&&t.id)||{status:"unknown"},i.environmentSource=wr(bi,t.environmentSource,0,0,"string"==typeof t.id&&t.id),i.environmentTemplateOrigin=wr(ki,t.environmentTemplateOrigin,0,0,"string"==typeof t.id&&t.id),i.runtime=wr(Ir.shape.runtime.unwrap(),t.runtime,0,0,"string"==typeof t.id&&t.id)||{labels:{}},i.target=wr(mr,Ar(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=wr(yr,Ar(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(Ir.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!==ti?(this.client.logger?.warn?.({nodeId:e.id,instanceId:n.data.id,expectedProtocolVersion:ti,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 Na(e){return e.readyState===(e.OPEN??1)}function Oa(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 _a(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 Ra(e,t,n){e.close(_a(t),Oa(n)||void 0)}function Pa(e,t,n,i){if(Na(e))for(const e of t.splice(0))if(i(e),!n(e))return}function ja(e,t,n={}){const i=n.pendingFrameLimit??256,s=n.maxFrameBytes??8388608,r=n.maxTotalBytes??1073741824,o=n.maxBufferedBytes??16777216;let a=!1,d=Na(t);const c=[],l=[];let p,u=0,g=0,h=0;const m=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=m(o);return h+=a,n.onFrame?.(i,a),!(a>s||h>r)||(Ra(e,1009,"WebSocket bridge traffic limit exceeded."),Ra(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 Ra(e,1013,"WebSocket bridge consumer is too slow."),Ra(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 Ra(e,1011,"WebSocket bridge send failed."),Ra(t,1011,"WebSocket bridge send failed."),!1}},b=(n,s,r)=>{if(s.length>=i)return Ra(e,1011,"WebSocket bridge pending frame limit exceeded."),void Ra(t,1011,"WebSocket bridge pending frame limit exceeded.");const a="upstream"===n?u:g;if((("upstream"===n?t:e).bufferedAmount??0)+a+r.bytes>o)return Ra(e,1013,"WebSocket bridge consumer is too slow."),void Ra(t,1013,"WebSocket bridge consumer is too slow.");s.push(r),"upstream"===n?u+=r.bytes:g+=r.bytes};return n.upstreamOpenTimeoutMs&&!d&&(p=setTimeout(()=>{d||a||(Ra(e,1011,"Upstream websocket did not open."),Ra(t))},n.upstreamOpenTimeoutMs)),e.on("open",()=>Pa(e,l,t=>I(e,t),e=>{g-=e.bytes})),t.on("open",()=>{f(),d=!0,n.onUpstreamOpen?.(),Pa(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:m(e)};Na(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:m(t)};Na(e)?I(e,i):b("client",l,i)}),t.on("close",(t,i)=>{f(),n.onUpstreamClose?.(t,i),(d||a||!n.onUpstreamCloseBeforeOpen?.())&&Ra(e,t,i)}),t.on("error",t=>{n.onUpstreamError?.(t),(d||a||!n.onUpstreamErrorBeforeOpen?.(t))&&Ra(e)}),e.on("close",(e,i)=>{f(),a=!0,n.onClientClose?.(e,i),Ra(t,e,i)}),e.on("error",e=>{f(),a=!0,n.onClientError?.(e),Ra(t,1011,"WebSocket bridge client failed.")}),{close:(n,i)=>{f(),Ra(t,n,i),Ra(e,n,i)}}}const Da="TASK_HANDOFF_NODE_AGENT_V1",Ma=6e4,La="/api/node-tunnel";function qa(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=$a(e.body||""),r=Ba(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 $a(e=""){return i.createHash("sha256").update(e).digest("hex")}function Ba(e,t){return i.createHmac("sha256",e).update(function(e){return[Da,e.keyId,e.method.toUpperCase(),e.pathWithQuery,e.timestamp,e.nonce,e.bodySha256].join("\n")}(t)).digest("hex")}function Ua(e){if(e.startsWith("ipc://"))return decodeURIComponent(e.slice(6))}function Fa(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 Ha(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 Wa(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function Ga(e,t){const n=AbortSignal.timeout(t);return e?AbortSignal.any([e,n]):n}async function Va(e,t,n,i={}){const s=Ua(t);return s?(Fa(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?g.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 Ka(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 Ja(e,t,n,i){const s=Ka(e),r=Ua(s),o=`/api/node-agent${t}`;if(r)return Fa(r),Ha(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 Ya(e,t,n){const i=new Headers(n),s=qa(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 Qa(e=fetch,t={}){const n=t.openWebSocket||Ja,i=Wa(t.requestTimeoutMs,3e4),s=Wa(t.streamHeaderTimeoutMs,3e4),r=Wa(t.websocketOpenTimeoutMs,1e4);return{request:async(t,n,s={})=>{const r=Ka(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=Ya(t,{method:o,pathWithQuery:`/api/node-agent${n}`,body:a||""},s.headers);return Va(e,r,n,{...s,body:a,headers:d,signal:Ga(s.signal,i)})},requestStream:async(t,n,i={})=>{const r=Ka(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=Ya(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 Va(e,r,n,{...i,body:a,headers:d,signal:l})}finally{clearTimeout(c)}}(0,s,c)},proxyWebSocket(e,t,i,s,o={}){const a=Ya(e,{method:"GET",pathWithQuery:`/api/node-agent${i}`},o);ja(t,n(e,i,s,a),{upstreamOpenTimeoutMs:r,onUpstreamError:()=>t.close(1011,"Instance websocket proxy failed."),onUpstreamErrorBeforeOpen:()=>!0})}}}class Xa{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 Za(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 ed(e,t){if("control-plane-proxy"!==e.connectionPath.kind)throw Za("Control-plane proxy transport requires a proxy connection path.","CONTROL_PLANE_PROXY_CONFIGURATION_INVALID",400);const n=t(e);if(!n)throw Za("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 Za("Control-plane proxy credential does not match the node connection identity.","CONTROL_PLANE_PROXY_CREDENTIAL_MISMATCH",409);return n}function td(e,t){const n=new Headers(t);n.set(En,bn),n.set(Nn,e.sourceControlPlaneId),n.set(On,e.bindingKeyId),n.set(_n,e.credential);const s=kn.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 nd(e){const t=Cn.safeParse(e);if(t.success)return t.data;const n=Za("Control-plane proxy route is invalid.",Rn.RouteInvalid,400);throw Object.assign(n,{issues:t.error.issues}),n}function id(e,t,n){return t?new l.WebSocket(e,t,{headers:n}):new l.WebSocket(e,{headers:n})}class sd{credentialForNode;fetchImpl;openWebSocket;constructor(e){this.credentialForNode=e.credentialForNode,this.fetchImpl=e.fetchImpl||fetch,this.openWebSocket=e.openWebSocket||id}async fetch(e,t,n={}){const i=ed(e,this.credentialForNode),s=function(e,t){const n=new URL(nd(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:td(i,n.headers)})}catch(e){if(function(e){return e instanceof Error&&("AbortError"===e.name||"ABORT_ERR"===e.code)}(e))throw e;throw Za(`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=ed(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",nd(t)),n}(r,n).toString(),i,td(r,s));ja(t,o,{onUpstreamError:()=>t.close(1011,"Control-plane proxy websocket failed."),onUpstreamErrorBeforeOpen:()=>!0})}}const rd=new Set(Object.keys(Zn.shape)),od=new Set(Object.keys(ei.shape));function ad(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 dd(e){const{credential:t,...n}=e;return n}class cd{pendingClaims;nodeCredentials;identity;constructor(e,t){this.pendingClaims=new Qr(e.pendingClaimsDir,{schema:Zn,sanitize:e=>function(e){return ad(e,rd,e=>t?.("unknown stored pending proxy claim fields were ignored",{fields:e}))}(e),logger:t,directoryMode:448,fileMode:384}),this.nodeCredentials=new Qr(e.nodeCredentialsDir,{schema:ei,sanitize:e=>function(e){return ad(e,od,e=>t?.("unknown stored proxy node credential fields were ignored",{fields:e}))}(e),logger:t,directoryMode:448,fileMode:384}),this.identity=new Xr(e.identityPath,()=>({controlPlaneId:Jr("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(dd)}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 ld=a.z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),pd=a.z.string().datetime(),ud=a.z.enum(["connecting","handshaking","healthy","reconnecting","suspect","offline"]),gd=a.z.enum(["start","stop","restart","retry-image"]);a.z.object({instanceId:ld,revision:a.z.number().int().nonnegative(),updatedAt:pd,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:pd.optional()}).strip();const hd=a.z.object({code:a.z.string().trim().min(1).max(120),message:a.z.string().trim().min(1).max(2048)}).strict(),md=a.z.object({id:ld,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:ud.optional(),lastSeenAt:pd.optional(),observedAt:pd,capabilities:a.z.array(a.z.string().trim().min(1).max(120)).max(256),error:hd.optional()}).strict();a.z.array(md);const yd=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(),fd=a.z.object({id:ld,name:a.z.string().trim().min(1).max(160),nodeId:ld,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(),config:a.z.object({defaultCodexPermissionMode:Z.default("ask")}).strict().default({defaultCodexPermissionMode:"ask"}),lastHeartbeatAt:pd.optional(),heartbeatAgeMs:a.z.number().int().nonnegative().optional(),observedAt:pd,runtime:a.z.object({id:ld,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:We,availableActions:a.z.array(gd).max(4).default([]),availableApps:a.z.array(yd).max(256).default([]),availableAgents:a.z.array(yd).max(256),error:hd.optional()}).strict();function Id(e){if(!e||"object"!=typeof e)return;const t=e,n=Xi.safeParse(t.build),i=wi.safeParse(t.platform),s=Si.safeParse(t.arch);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}:{},...n.success?{build:n.data}:{},..."string"==typeof t.serverTime?{serverTime:t.serverTime}:{}}}function bd(e){const{agent:t,...n}=e.capabilities,{secret:i,...s}=e.auth,r=s.pairing?{...s.pairing,joinToken:void 0}:void 0,o=Id(t);return{...e,auth:r?{...s,pairing:r}:s,capabilities:o?{...n,agent:o}:n}}function vd(e){return"local-folder"===e.type?{mode:"local-bind",path:"/workspace",readOnly:!1}:{mode:"git-clone",path:"/workspace",readOnly:!1}}function wd(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 Sd(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 Ad(){return(new Date).toISOString()}function kd(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 zd(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 Cd(e){return e instanceof Error?e.message:String(e)}function xd(e,t){const n=new Error(t);throw Object.assign(n,{statusCode:404,code:e}),n}a.z.array(fd);const Td=a.z.object({proxyOrigin:zn,inviteToken:a.z.string().trim().min(24).max(512),name:a.z.string().trim().min(1).max(160).optional()}).strict(),Ed=a.z.object({data:a.z.object({binding:Fn,closed:a.z.object({abortedRequests:a.z.number().int().nonnegative(),closedSockets:a.z.number().int().nonnegative()}).strict()}).strict()}).strict();class Nd{claimOperations=new Map;options;constructor(e){this.options=e}listPendingClaims(){return this.options.privateStore.publicPendingClaims()}async claimNode(e){const t=Td.parse(e),n=Ad(),i=Jr("proxy_claim"),s={id:i,claimId:i,proxyOrigin:t.proxyOrigin,...t.name?{requestedName:t.name}:{},sourceControlPlaneId:this.options.privateStore.controlPlaneId(),bindingKeyId:Jr("proxy_key"),credential:Yr(),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||xd("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===Rn.InviteInvalid||s===Rn.BindingRevoked)return{deleted:this.options.privateStore.completePendingClaimCompensation(e),compensationRequired:!1,remoteRevoke:s===Rn.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=Ao(Xn,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!==Rn.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,Rn.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:Rn.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=Ad();return this.options.nodes.put(Zs.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=Ad();return this.options.nodes.put(Zs.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===Rn.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=Ao(Xn,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:Ad()},d=r||Zs.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:Ad(),target:s.target,updatedAt:Ad()},labels:{},lastSeenAt:s.target.lastSeenAt,createdAt:Ad(),updatedAt:Ad()});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:bd(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:Rn.BindingIdentityConflict,statusCode:409,retryable:!1}),e}return i}putTargetState(e,t,n){const i=Ad();return this.options.nodes.put(Zs.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:bn,...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:td(e)})}async responsePayload(e){return e.json().catch(()=>{})}requireRevocationReceipt(e,t){const n=So(Ed,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:Rn.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:Rn.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:Ad()}}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 Od=a.z.object({id:fs.shape.id.optional(),name:fs.shape.name,source:hs,defaultImageSelection:fs.shape.defaultImageSelection,defaultNodeId:fs.shape.defaultNodeId,defaultRuntimeId:fs.shape.defaultRuntimeId,workspacePolicy:ms.optional(),labels:fs.shape.labels.optional()}).strict(),_d=Od.omit({id:!0}).partial().strict();function Rd(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"/"!==e&&"\\"!==e}const Pd=a.z.string().refine(Rd,"Mention trigger must be one printable non-alphanumeric character other than / or \\.");function jd(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"\\"!==e}const Dd=a.z.string().refine(jd,"Command trigger must be one printable non-alphanumeric character other than \\."),Md=a.z.object({publicBaseUrl:a.z.string().trim().max(2048).optional(),updateChannel:es.default("stable"),mentionTrigger:Pd.default("@"),commandTrigger:Dd.default("/"),diagnosticLogs:a.z.boolean().default(!1)}).strict().refine(e=>e.mentionTrigger!==e.commandTrigger,{path:["commandTrigger"],message:"Command and mention triggers must be different."}),Ld=a.z.object({publicBaseUrl:a.z.string().trim().max(2048).optional(),updateChannel:es.optional(),mentionTrigger:Pd.optional(),commandTrigger:Dd.optional(),diagnosticLogs:a.z.boolean().optional()}).strict(),qd=a.z.object({id:qs.shape.id.optional(),name:qs.shape.name,description:qs.shape.description,cover:qs.shape.cover,reference:qs.shape.reference,pullPolicy:qs.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:qs.shape.defaultEnv.optional(),labels:qs.shape.labels.optional()}).strict(),$d=qd.omit({id:!0}).partial().strict(),Bd=a.z.object({name:zr.shape.name.optional(),channel:zr.shape.channel.optional(),enabled:a.z.boolean().optional(),token:zr.shape.token,defaultChatId:zr.shape.defaultChatId,allowedUserIds:a.z.array(a.z.string().trim().min(1).max(240)).optional(),pollIntervalMs:zr.shape.pollIntervalMs.optional(),settings:zr.shape.settings.optional()}).strict(),Ud=Bd.extend({channel:zr.shape.channel,name:zr.shape.name.optional()}),Fd=on.extend({id:on.shape.configHash}),Hd=a.z.object({name:on.shape.name,description:on.shape.description,source:nn,action:sn,policy:rn.partial().optional()}).strict(),Wd=Hd,Gd=a.z.object({instanceIds:a.z.array(Ir.shape.id).min(1),target:an,enabled:a.z.boolean().optional()}).strict(),Vd=a.z.object({configHash:on.shape.configHash,enabled:a.z.boolean().optional()}).strict(),Kd=a.z.object({mode:a.z.enum(["local-static-key","paired-hmac","proxy-binding"]).default("local-static-key"),keyId:Zs.shape.id.optional(),secret:a.z.string().trim().max(4096).optional(),pairedAt:Zs.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:Zs.shape.createdAt.optional()}).strict().optional()}).strict(),Jd=a.z.object({autoImportAgentConfigs:a.z.boolean().optional(),defaultCodexPermissionMode:Z.optional()}).strict(),Yd=a.z.object({id:Ir.shape.id.optional(),name:Ir.shape.name.optional(),projectId:Ir.shape.projectId,source:hs.optional(),sourceSnapshot:a.z.record(a.z.string(),a.z.unknown()).optional(),nodeId:Ir.shape.nodeId.optional(),runtimeId:Ir.shape.runtimeId.optional(),environmentSource:bi.optional(),imageSelection:Ir.shape.imageSelection,config:Jd.optional(),modelSelection:Ir.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."})}),Qd=a.z.object({name:Ir.shape.name.optional(),config:Jd.optional(),modelSelection:Ir.shape.modelSelection.optional()}).strict(),Xd=a.z.object({name:Is.shape.name,endpoint:Is.shape.endpoint,key:Is.shape.key,model:Is.shape.model,app:Is.shape.app,enabled:Is.shape.enabled.optional(),order:Is.shape.order.optional(),labels:Is.shape.labels.optional()}).strict(),Zd=Xd.partial().strict(),ec=a.z.object({id:Zs.shape.id.optional(),name:Zs.shape.name,connectionMode:Zs.shape.connectionMode.optional(),connectionPath:Zs.shape.connectionPath.optional(),connectionEnabled:Zs.shape.connectionEnabled.optional(),auth:Kd.optional(),joinToken:a.z.string().trim().min(1).max(4096).optional(),endpoint:Zs.shape.endpoint,controlEndpoint:Zs.shape.controlEndpoint,containerEndpoint:Zs.shape.containerEndpoint,publicWebBase:Zs.shape.publicWebBase,status:a.z.enum(["unknown","online","offline","degraded"]).optional(),health:a.z.enum(["unknown","ok","degraded","failed"]).optional(),capabilities:Zs.shape.capabilities.optional(),labels:Zs.shape.labels.optional(),lastSeenAt:Zs.shape.lastSeenAt}).strict(),tc=a.z.object({name:Zs.shape.name.optional(),connectionMode:Zs.shape.connectionMode.unwrap().optional(),connectionPath:Zs.shape.connectionPath.unwrap().optional(),connectionEnabled:Zs.shape.connectionEnabled.unwrap().optional(),auth:Kd.optional(),endpoint:Zs.shape.endpoint,controlEndpoint:Zs.shape.controlEndpoint,containerEndpoint:Zs.shape.containerEndpoint,publicWebBase:Zs.shape.publicWebBase,status:Zs.shape.status.unwrap().optional(),health:Zs.shape.health.unwrap().optional(),capabilities:Zs.shape.capabilities.unwrap().optional(),labels:Zs.shape.labels.unwrap().optional(),lastSeenAt:Zs.shape.lastSeenAt}).strict(),nc=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(),ic=a.z.object({nodeName:a.z.string().trim().min(1).max(160).optional(),expiresInMs:a.z.number().int().positive().max(36e5).optional()}).strict(),sc=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 rc{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 Ua(e)?"local-ipc":"local-loopback"}(n),s=Zs.parse({id:"node_local_probe",name:"Local Node Probe",connectionMode:i,auth:{mode:"local-static-key",secret:t},labels:e,createdAt:Ad(),updatedAt:Ad()}),r=await this.inspect(n,s),o=Ad(),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(Zs.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:Id(r.data)},labels:{...a?.labels||{},...e},createdAt:a?.createdAt||o,updatedAt:o}))}async create(e){const t=ec.parse(e),n=Ad(),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 oc("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 oc("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 oc("Remote node connections require a paired node secret or join token.","NODE_AGENT_REMOTE_SECRET_REQUIRED");if(r&&!s.keyId)throw oc("Remote node connections require a paired key id.","NODE_AGENT_REMOTE_KEY_ID_REQUIRED");const e=t.id||a?.nodeId||Jr("node"),u=Zs.parse({id:e,name:t.name,connectionMode:i,auth:s,labels:t.labels||{},createdAt:n,updatedAt:n}),g="reverse-wss"===i&&(t.id||a?.nodeId)?void 0:await this.inspect(o||"",u),h=t.id||a?.nodeId||g?.nodeId||e;if(!h)throw oc("Node id is required.","NODE_ID_REQUIRED");if(a&&t.id&&t.id!==a.nodeId)throw oc(`Paired node id ${a.nodeId} does not match requested node id ${t.id}.`,"NODE_AGENT_ID_MISMATCH");if(t.id&&g?.nodeId&&g.nodeId!==t.id)throw oc(`Node agent id ${g.nodeId} does not match requested node id ${t.id}.`,"NODE_AGENT_ID_MISMATCH");if(a&&g?.nodeId&&g.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:m,...y}=t,f=Zs.parse({...y,id:h,connectionMode:i,auth:s,endpoint:o,controlEndpoint:o,status:t.status||(g?"online":"unknown"),health:t.health||(g?"ok":"unknown"),capabilities:{...t.capabilities||{},...g?{agent:Id(g.data)}:{}},labels:t.labels||{},createdAt:n,updatedAt:n});if(a&&(l=f,p=a.secret,pc(bd(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 uc(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),uc(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=Ad();return sc.parse({id:Jr("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?cc(t.nodeId,t.secret):void 0,keyId:t?cc(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?qa(t,{method:"GET",pathWithQuery:`/api/node-agent${n}`}):{},s=await Va(this.options.fetchImpl,e,n,{headers:i}),r=await s.json().catch(()=>({}));if(!s.ok)throw this.options.warn(lc({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(lc({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=So(Xi,r.data?.build);return r.data?.protocolVersion!==ti&&this.options.warn(lc({nodeId:o,nodeEndpoint:e,expectedProtocolVersion:ti,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(lc({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=So(rr,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:Ad(),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 Va(this.options.fetchImpl,e,i,{method:"DELETE",headers:qa(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:dc(a.error?.code,t.secret,"NODE_AGENT_PAIRING_REVOKE_FAILED"),retryable:408===o.status||429===o.status||o.status>=500});const d=So(ar,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:cc(t.nodeId,t.secret),keyId:cc(t.keyId,t.secret),originalErrorCode:ac(n,t.secret)},"node agent pairing revoked after node creation failed")}catch{}}catch(e){const i={nodeId:cc(t.nodeId,t.secret),keyId:cc(t.keyId,t.secret),originalErrorCode:ac(n,t.secret),compensationErrorCode:ac(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 oc(e,t){return Object.assign(new Error(e),{statusCode:400,code:t})}function ac(e,t){return dc(e&&"object"==typeof e&&"code"in e?e.code:void 0,t,"UNKNOWN_ERROR")}function dc(e,t,n){return"string"!=typeof e||!/^[A-Z][A-Z0-9_]{0,127}$/.test(e)||e.includes(t)?n:e}function cc(e,t){return e.includes(t)?"[redacted]":e}function lc(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 uc(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:ac(e,t)});return e&&"object"==typeof e&&"retryable"in e&&"boolean"==typeof e.retryable&&Object.assign(s,{retryable:e.retryable}),s}class gc{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 hc=a.z.object({joinToken:a.z.string().trim().min(1).max(4096),nodeId:Zs.shape.id,nodeName:Zs.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 mc{options;invites=new gc;constructor(e){this.options=e}createInvite(e={}){const t=ic.parse(e&&"object"==typeof e?e:{}),n=Yr(),i={id:Jr("node_join"),tokenHash:yc(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=hc.parse(e),n=yc(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=Ad();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(Zs.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 yc(e){return i.createHash("sha256").update(e).digest("hex")}class fc{options;constructor(e){this.options=e}list(){return this.listAll().map(Sd)}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:Sd(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 zs.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:Ad()})}create(e){const t=Xd.parse(e),n=Ad(),i=Cs(t),s=this.options.models.get(i),r=Is.parse({...t,id:i,enabled:t.enabled??!0,order:t.order??this.nextOrder(),labels:t.labels||{},createdAt:s?.createdAt||n,updatedAt:n});return Sd(this.options.models.put(r))}update(e,t){const n=Zd.parse(t),i=this.requireSecret(e),s=Is.parse({...i,...n,key:n.key?.trim()?n.key:i.key,createdAt:i.createdAt,updatedAt:Ad()}),r=Cs(s);return Sd(this.options.models.put(Is.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)||xd("MODEL_NOT_FOUND",`Model ${e} was not found.`);return t.forEach((e,t)=>{const i=n.get(e);this.options.models.put(Is.parse({...i,order:100*(t+1),updatedAt:Ad()}))}),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)}require(e,t=!1){const n=this.requireSecret(e);return t?n:Sd(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 Ic(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||xd("MODEL_NOT_FOUND",`Model ${i} was not found on control-plane or node ${e.id}.`),Ic(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||xd("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,Is.parse(t)}return Is.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}}function Ic(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 bc{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}vc(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:kd(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}vc(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:kd(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}vc(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 vc(e){if(Er(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 wc{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=wd(e.instance);return{...i,aiSessions:Ge(i.aiSessions),connectionStatus:n,heartbeatAgeMs:t,project:e.project,image:e.image,node:e.node?bd(e.node):void 0,runtime:e.runtime,protocolCompatible:!e.instance.protocolVersion||e.instance.protocolVersion===ti}}({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 Sc{options;constructor(e){this.options=e}async create(e){const t=Yd.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 kc("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 kc(`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 kc(`Environment template ${p.id} is ${p.status}.`,409,"ENVIRONMENT_TEMPLATE_NOT_READY");if(p&&p.nodeId!==r.id)throw kc(`Environment template ${p.id} belongs to node ${p.nodeId}.`,409,"ENVIRONMENT_TEMPLATE_NODE_MISMATCH");if(a&&!l&&!p)throw kc(`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}),g=await this.options.prepareModels(r,t.modelSelection||{}),h=l?function(e){const t=Ad();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,m=await this.options.gateway.createInstance(r,{id:t.id,name:t.name,runtimeId:i,...d?{environmentSource:d}:{},...l&&h?{image:h}:{},projectId:n?.id,source:u.value,sourceSnapshot:u.snapshot,config:t.config,modelSelection:{}});let y=m;try{y=(await this.options.gateway.assignInstanceModels(r,m.id,g)).instance}catch(e){throw await this.options.gateway.deleteInstance(r,m.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:Ac(e,"INSTANCE_START_FAILED")},y=await this.options.gateway.listInstances(r).then(e=>e.find(e=>e.id===y.id)||y).catch(()=>y)}return{...wd(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 kc("Instance source is required.",400,"INSTANCE_SOURCE_REQUIRED");if("local"===e.runtime.type&&"local-folder"!==t.type)throw kc("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 kc(`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 Ac(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 kc(e,t,n){return Object.assign(new Error(e),{statusCode:t,code:n})}class zc{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:Cc(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 hn.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=Hd.parse(e||{}),n=Ad(),i={maxConcurrentRuns:t.policy?.maxConcurrentRuns??1,whenBusy:t.policy?.whenBusy??"skip",cooldownMs:t.policy?.cooldownMs},s=mn({source:t.source,action:t.action,policy:i}),r=Fd.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=Wd.parse(t||{}),s=Ad(),r={maxConcurrentRuns:i.policy?.maxConcurrentRuns??1,whenBusy:i.policy?.whenBusy??"skip",cooldownMs:i.policy?.cooldownMs},o=mn({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=Fd.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?xc(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||xd("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),{configHash:e,deletedTemplate:t,results:i}}async applyTrigger(e,t){const n=this.requireTrigger(e),i=Gd.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=Vd.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:xc(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=xc(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||xd("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),t}}function Cc(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 xc(e,t){return`ai_${Buffer.from(e).toString("base64url")}_${t}`}class Tc{options;constructor(e){this.options=e}getSettings(){return Md.parse(this.options.settings.get())}updateSettings(e){const t=Ld.parse(e),n=Md.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=Od.parse(e),n=Ad(),i=hs.parse(t.source);return this.options.projects.put(fs.parse({...t,id:t.id||Jr("proj"),source:i,defaultImageSelection:t.defaultImageSelection||{imageId:"market_taskhandoff_browser"},defaultNodeId:t.defaultNodeId||this.options.defaultNodeId(),defaultRuntimeId:t.defaultRuntimeId||"runtime_local_docker",workspacePolicy:ms.parse(t.workspacePolicy||vd(i)),labels:t.labels||{},createdAt:n,updatedAt:n}))}updateProject(e,t){const n=_d.parse(t),i=this.requireProject(e),s=n.source?hs.parse(n.source):i.source;return this.options.projects.put(fs.parse({...i,...n,id:e,source:s,workspacePolicy:n.workspacePolicy?ms.parse(n.workspacePolicy):i.workspacePolicy,createdAt:i.createdAt,updatedAt:Ad()}))}deleteProject(e){return this.options.projects.delete(e)}requireProject(e){const t=this.getProject(e);return t||xd("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||xd("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=qd.parse(e),n=Ad(),i=hi(t.reference);return this.options.images.put(qs.parse({...t,id:t.id||Jr("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=$d.parse(t),i=this.requireImage(e),s=hi(n.reference||i.reference);return this.options.images.put(qs.parse({...i,...n,id:e,origin:"custom",reference:s.reference,repository:s.repository,tag:s.tag,createdAt:i.createdAt,updatedAt:Ad()}))}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||xd("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={...Oi(e)};return"defaultRuntimeId"in t||(t.defaultRuntimeId="runtime_local_docker"),fs.parse(t)}return fs.parse(e)}(e);return t!==e&&this.options.projects.put(t),t}customImageOption(e){return Bs.parse({id:e.id,origin:"custom",name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover||Ns,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 Bs.parse({id:e.id,origin:"market",name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover||Ns,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 Ec(e){const t=hi(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:Ns,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 Nc(){const e=(t=process.env.TASK_HANDOFF_BUILT_AT)&&!Number.isNaN(Date.parse(t))?new Date(t).toISOString():(new Date).toISOString();var t;return Ms.parse({protocolVersion:"2026-07-29",catalogId:"task_handoff_embedded",revision:process.env.TASK_HANDOFF_VERSION||"0.0.1",source:"embedded",generatedAt:e,items:[Ec({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"]}),Ec({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"]}),Ec({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"]}),Ec({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 Oc{async loadCatalog(){return Nc()}}class _c{snapshot;status;constructor(e=Nc()){this.snapshot=Ms.parse(e),this.status=Ls.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=Ms.safeParse(e);return t.success?(this.snapshot=t.data,this.status=Ls.parse({source:t.data.source,state:"ready",revision:t.data.revision,updatedAt:(new Date).toISOString()}),{accepted:!0,snapshot:t.data}):(this.status=Ls.parse({...this.status,state:"failed",updatedAt:(new Date).toISOString(),error:t.error.message}),{accepted:!1,error:t.error})}recordRefreshFailure(e){return this.status=Ls.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 Rc{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 Pc{requireInstance;listAppSessions;tokens=new Rc({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=zt(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:jc(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=>Mc(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 jc(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):Mc(Dc(n.vnc).noVncPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`:Mc(Dc(n.web).webPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`}function Dc(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Mc(e){return"string"==typeof e&&e.trim()?e.trim():void 0}const Lc={allow:"a",deny:"d",skip:"s"};function qc(e){return i.createHash("sha256").update(e).digest("base64url").slice(0,Math.ceil(16))}class $c{tokens=new Rc({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:${Lc[t]}:${qc(e)}`}}function Bc(e){const{token:t,...n}=e;return{...n,settings:Fc(e.settings),tokenSet:Boolean(e.token)}}function Uc(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 Fc(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 Hc{chatBridges;chatSessions;constructor(e){this.chatBridges=e.chatBridges,this.chatSessions=e.chatSessions}list(){return this.chatBridges.list().map(Bc)}require(e){const t=this.chatBridges.get(e);return t||xd("CHAT_BRIDGE_NOT_FOUND",`Chat bridge ${e} was not found.`),t}create(e){const t=Ud.parse(e),n=Ad(),i=zr.parse({...t,id:Jr(`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:Uc({},t.settings),createdAt:n,updatedAt:n});var s,r;return this.chatBridges.put(i),Bc(i)}update(e,t){const n=Bd.parse(t),i=this.require(e),s=Uc(i.settings,n.settings),r=zr.parse({...i,...n,id:e,channel:i.channel,name:n.name||i.name,settings:s,updatedAt:Ad()});return this.chatBridges.put(r),Bc(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 Wc{chatSessions;constructor(e){this.chatSessions=e.chatSessions}list(){return this.chatSessions.list()}require(e){const t=this.chatSessions.get(e);return t||xd("CHAT_SESSION_NOT_FOUND",`Chat session ${e} was not found.`),t}upsert(e){const t=Ad(),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=Cr.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 Gc(e){return{inline_keyboard:e.map(e=>e.map(e=>({text:e.text,...e.url?{url:e.url}:{callback_data:e.callbackData||""}})))}}function Vc(e,t=40){return Gc(e.slice(0,t).map(e=>[e]))}function Kc(e){return Buffer.from(e,"utf8").toString("base64url")}function Jc(e){const t=Qc(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=Qc(t),n=String(e.callback_data||""),s=String(e.text||"").trim();s&&n&&i.push({text:s,id:`th_cb_${Kc(n)}`})}return i.slice(0,40)}function Yc(e,t){const n=String(e||"").replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-3))}...`}function Qc(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Xc(e){return(e.aiSessions?.sessions||[]).filter(t=>function(e,t){const n=(e.apps?.sessions||[]).filter(sl);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[...St(e).bindings.map(Ct),...Tt(e)].filter(Boolean)}(e).some(e=>i.has(e))))}(e,t))}function Zc(e){return"waiting"===e.status?4:"failed"===e.status?3:"running"===e.status?2:"idle"===e.status?1:0}function el(e){return[e.cwd||"",e.agent||"",e.providerSessionId||e.id].join("\0")}function tl(e){const t=e.session.title||e.session.userPrompt||e.session.summary||e.session.lastMessage||"",n=t?` - ${Yc(t,18)}`:"";return`${e.instance.name} - ${e.session.agent} ${e.session.status}${n}`}function nl(e,t=(e,t)=>`task_handoff:approval:${e.id}:${t}`){return Vc(e.flatMap(e=>"approval"!==e.kind?[]:[{text:Yc(`Allow ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"allow")},{text:Yc(`Skip ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"skip")},{text:Yc(`Deny ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"deny")}]))}function il(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 sl(e){const t=e&&"object"==typeof e&&!Array.isArray(e)?e:{};return kt("string"==typeof t.status?t.status:void 0)}class rl{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?Vc(t.map(e=>({text:`${e.active?"✓ ":""}${tl(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:wd(t),aiSession:n,reply:`Interrupt sent to ${t.name} / ${e.activeAiSessionId}.`}}}function ol(e){return e.providerTurnId||e.turnId||""}function al(e){return kt(pl(e.status))}function dl(e,t){const n=pl(t.appId)||"App",i=pl(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 cl(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=ul(e);t&&!n.has(t.id)&&n.set(t.id,t)}return[...n.values()]}function ll(e,t,n,i){const s=pl(t.id)&&function(e,t){const n=zt(e);if(!n)return;return`/apps/access/${n}?token=${encodeURIComponent(t(n))}`}(t,i)||`/instances/${encodeURIComponent(e.id)}/`,r=function(e,t){const n=pl(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 pl(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function ul(e){if("string"==typeof e&&e.trim())return{id:e,label:gl(e)};const t=function(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}(e),n=pl(t.id).trim();return n?{id:n,label:pl(t.name).trim()||gl(n)}:void 0}function gl(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 hl{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?Vc(t.map(e=>{return{text:Yc(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=cl(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?Vc(i.map(e=>{return{text:Yc(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=cl(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(al).filter(e=>Boolean(pl(e.id))).map(e=>({instance:t,session:e,link:ll(t,e,this.deps.controlPlanePublicBaseUrl(),n=>this.deps.createAppAccessToken({instanceId:t.id,sessionId:pl(e.id)||"",mode:n}).token)})):[]}),s=i.filter(e=>e.link.url).map(e=>({text:Yc(`${e.instance.name} · ${dl(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?Vc(s):void 0};var r,o}}class ml{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:wd(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}: ${Cd(t)}`}}}failedSendResult(e,t,n,i){return{accepted:!1,routed:!1,binding:e,project:t||void 0,instance:wd(n),reply:i}}sentResult(e,t,n,i,s){return{accepted:!0,routed:!0,binding:e,project:t||void 0,instance:wd(n),aiSession:s,instanceId:n.id,aiSessionId:i,turnId:(r=s,r.turnId||r.providerTurnId||r.session.activeTurnId||""),providerTurnId:ol(s),reply:`Sent to ${t?.name||n.sourceSnapshot.name||"Source"} / ${n.name} / ${i}.`};var r}}class yl{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(il).join("\n"):"No pending routes.",replyMarkup:n.length?nl(n,(e,t)=>this.deps.pendingDecisionCallbackData(e.id,t)):void 0}}async handlePendingDecisionCommand(e,t,n){const i=zd(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=zd(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 fl{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 Il{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?Xc({...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=>Xc(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=Zc(t.session)-Zc(e.session);return n||(String(e.instance.name||"").localeCompare(String(t.instance.name||""))||e.instance.id.localeCompare(t.instance.id)||el(e.session).localeCompare(el(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||xd("PROJECT_NOT_FOUND",`Project ${e} was not found.`),t}async resolveInstance(e,t){const n=await this.findInstance(e,t);return n||xd("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 bl{deps;targets;sender;appCommands;pendingCommands;aiSessionCommands;targetCommands;constructor(e){this.deps=e,this.targets=new Il(e),this.sender=new ml(e,this.targets),this.appCommands=new hl(e,this.targets),this.pendingCommands=new yl(e),this.aiSessionCommands=new rl(e,this.targets),this.targetCommands=new fl(e,this.targets)}async handleChatGatewayMessage(e){const t=xr.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 vl=a.z.object({id:a.z.string().trim().min(1),preferences:Oo,createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict();function wl(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 Sl(){return Oo.parse({})}function Al(e){return/^[a-z]:[\\/]/i.test(e)||/^[\\/]{2}[^\\/]+[\\/]+[^\\/]+/.test(e)}function kl(e){return Al(e)?t.win32:t.posix}class zl{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??Nr,s=[];for(const r of n.readdirSync(e.trashRoot,{withFileTypes:!0})){const o=Or(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??Nr,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=Or(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}`);_r(e.trashRoot);const s=e.nowMs??Date.now();let r=0,o=`${s}-${e.entryName}`;for(;n.existsSync(Or(e.trashRoot,o));)r+=1,o=`${s}-${r}-${e.entryName}`;const a=Or(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)})}}_r(e)}now(){return this.options.now?.()??Date.now()}}const Cl="task-handoff.control-plane.local",xl="task-handoff.control-plane.builtin";function Tl(e){return"true"===e.labels[Cl]}function El(e){return"true"===e.labels[xl]}class Nl{projects;models;modelService;images;nodes;pendingPairingRevokes;chatSessions;chatBridges;triggers;nodeJoinService;configSyncPreferences;settings;paths;fetchImpl;dockerCommandRunner;logger;diagnosticLogsState;nodeConnectionRuntime;appAccessService;persistenceMaintenance;chatActionTokenService=new $c;nodeAgentTransportResolver;proxyPrivateStore;proxyLifecycle;nodeConnectionManager;nodeAgentGateway;controlledInstanceGateway;aiSessionActionService;controlledInstanceCreator;instanceBoardReader=new wc;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 zl(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 Xa({direct:Qa(this.fetchImpl),tunnel:n.nodeAgentTransport,proxy:new sd({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 Xr(e.settingsPath,()=>Md.parse({diagnosticLogs:s}),{...i(Md),sanitize:e=>function(e,t={}){if(!e||"object"!=typeof e||Array.isArray(e))return{};const n={...e};return"string"==typeof n.mentionTrigger&&Rd(n.mentionTrigger)||(n.mentionTrigger="@"),"string"==typeof n.commandTrigger&&jd(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 Ta({request:(e,t,n)=>this.nodeAgentFetch(e,t,n),logger:this.logger});this.nodeAgentGateway=new Ea(o),this.controlledInstanceGateway=new bc({requireNode:e=>this.requireNode(e),nodeAgentTransport:e=>this.nodeAgentTransportResolver.resolve(e)}),this.aiSessionActionService=new ba({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 Qr(e.projectsDir,{...i(fs),sanitize:Oi}),this.models=new Qr(e.modelsDir,i(Is)),this.modelService=new fc({models:this.models,gateway:this.nodeAgentGateway,listNodes:()=>this.listNodes(),requireNode:e=>this.requireNode(e)}),this.images=new Qr(e.imagesDir,{...i(qs),sanitize:e=>Ys(e,e=>this.logWarn(e,"legacy image profile field was migrated"))}),this.nodes=new Qr(e.nodesDir,{...i(Zs),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)?Ar(n.auth,["mode","keyId","secret","pairedAt","pairing"]):n.auth;s&&"object"==typeof s&&"pairing"in s&&(s.pairing=Ar(s.pairing,["status","joinToken","expiresAt"]));const r=n.connectionPath&&"object"==typeof n.connectionPath&&!Array.isArray(n.connectionPath)?"control-plane-proxy"===n.connectionPath.kind?Ar(n.connectionPath,["kind","proxyId","proxyBindingId","targetNodeId"]):Ar(n.connectionPath,["kind"]):{kind:"direct"},o=n.proxyState&&"object"==typeof n.proxyState&&!Array.isArray(n.proxyState)?Ar(n.proxyState,["reachability","bindingStatus","bindingRevision","streamId","revision","observedAt","target","lastError","updatedAt"]):n.proxyState;if(o&&"object"==typeof o){const e=o;e.target=Ar(e.target,["id","name","status","health","lastSeenAt","capabilities"]),e.lastError=Ar(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 Qr(e.pendingPairingRevokesDir,i(sc)),this.proxyLifecycle=new Nd({nodes:this.nodes,privateStore:this.proxyPrivateStore,fetchImpl:this.fetchImpl,requireNode:e=>this.requireNode(e),deleteNode:e=>this.deleteNode(e)}),this.nodeConnectionManager=new rc({nodes:this.nodes,pendingPairingRevokes:this.pendingPairingRevokes,fetchImpl:this.fetchImpl,localNodeLabel:Cl,builtinNodeLabel:xl,info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)}),this.chatSessions=new Qr(e.chatSessionsDir,i(Cr)),this.chatBridges=new Qr(e.chatBridgesDir,i(zr)),this.triggers=new Qr(e.triggersDir,i(Fd)),this.nodeJoinService=new mc({nodes:this.nodes}),this.configSyncPreferences=new Qr(t.join(e.dataDir,"config-sync-preferences"),{...i(vl),sanitize:wl}),this.marketCatalogService=new _c,this.catalogService=new Tc({projects:this.projects,images:this.images,market:this.marketCatalogService,settings:this.settings,defaultNodeId:()=>this.defaultNodeId()}),this.controlledInstanceCreator=new Sc({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 zc({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 Pc({requireInstance:async e=>this.requireControlledInstance(e,!0),listAppSessions:()=>this.listAppSessions()}),this.chatBridgeService=new Hc({chatBridges:this.chatBridges,chatSessions:this.chatSessions}),this.chatSessionService=new Wc({chatSessions:this.chatSessions}),this.chatSessionRuntime=new bl({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(Ei),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:Cd(e)}),void this.logWarn({legacyId:t,error:Cd(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=fs.parse(Oi(t));r.push({filePath:e,raw:t,migrated:i})}catch(t){return this.writeMarketMigrationState("failed",{code:"PROJECT_REFERENCE_VALIDATION_FAILED",filePath:e,error:Cd(t)}),void this.logWarn({filePath:e,error:Cd(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:ti,createdAt:Ad(),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:Ei[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:Ad(),...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(Tl)?.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)}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 Oc),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 ur.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=>ur.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=Zs.parse({...t,id:i,status:"online",health:"ok",capabilities:"object"==typeof e&&e?{...t.capabilities,agent:Id(e)}:t.capabilities,lastSeenAt:Ad(),updatedAt:Ad()});return i!==t.id&&this.nodes.delete(t.id),this.nodes.put(s),this.nodeConnectionRuntime?.observedReachable(s),{id:s.id,status:"online",checkedAt:Ad(),agent:e}}catch(e){const n=Zs.parse({...t,status:"offline",health:"failed",updatedAt:Ad()});return this.nodes.put(n),this.nodeConnectionRuntime?.observedFailure(n,Cd(e)),{id:t.id,status:"offline",checkedAt:Ad(),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(!El(t)||!Tl(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=nc.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=>bd(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=tc.parse(t),i=this.requireNode(e);this.proxyLifecycle.assertIdentityPatch(i,n);const s=Zs.parse({...i,...n,id:e,createdAt:i.createdAt,updatedAt:Ad()});return this.nodes.put(s)}deleteNode(e){if(El(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(wd)}async listControlledInstancesWithDiagnostics(){const e=await this.listNodeInstancesWithDiagnostics();return{items:e.items.map(wd),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=Qd.parse(t),i=await this.requireNodeInstance(e),s=this.requireNode(i.nodeId),{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 wd(a)}async deleteControlledInstance(e,t){const n=Ci.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),wd(await this.nodeAgentGateway.startInstance(n,e))}async stopControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return wd(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),wd(await this.nodeAgentGateway.restartInstance(n,e))}async retryControlledInstanceImageProvisioning(e){const t=await this.requireNodeInstance(e);return wd(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(!Er(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 Ao(He,await this.instanceRequest(e,"/ai-sessions/state"))}catch(t){return this.logWarn({instanceId:e.id,error:Cd(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(!Er(e)||!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=_t();return{streamId:`bootstrap:${e.id}:app.sessions`,revision:0,lastEventAt:t.updatedAt,snapshot:t}}try{return Ao(gt,await this.instanceRequest(e,"/apps/sessions/state"))}catch(t){this.logWarn({instanceId:e.id,error:Cd(t),errorCode:"APP_SESSION_LIVE_REFRESH_FAILED"},"control plane failed to refresh live app sessions");const n=_t();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 Ao(Ze,await this.instanceRequest(i,`/ai-sessions?${s}`))}async recoverAiSessionSnapshot(e){const t=await this.requireControlledInstance(e,!0);return Ao(He,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 Ao(bt,await this.instanceRequest(i,`/apps/sessions?${s}`))}async recoverAppSessionSnapshot(e){const t=await this.requireControlledInstance(e,!0);return Ao(gt,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=Ad(),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=Tr.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:wd(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)}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||vd(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 Ao(Ji,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 Ao(Qi,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 Ao(Qi,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(Eo).parse(await this.instanceRequest(t,"/config-sync/programs"));return _o.parse({programs:n,preferences:this.configSyncPreferences.get(e)?.preferences||Sl()})}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(gr).parse(await this.instanceRequest(n,"/config-sync/folders"+(i.size?`?${i}`:"")))}async syncInstanceConfigs(e,t){const n=No.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=Ao(jo,await this.instanceRequest(i,"/config-sync",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(r)})),a=Ad(),d=this.configSyncPreferences.get(e);return this.configSyncPreferences.put({id:e,preferences:{...d?.preferences||Sl(),[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,Cd(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{}xd("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||xd("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 kl(s=n).resolve(s);var s;if("local-folder"!==e.source.type)return;const r=function(e,t){if(Al(e)!==Al(t))return;const n=kl(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||vd(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||xd("NODE_NOT_FOUND",`Node ${e} was not found.`),t}requirePublicNode(e){return bd(this.projectNodeConnection(this.requireNode(e)))}async requireControlledInstance(e,t=!1){const n=await this.requireNodeInstance(e);return t?n:wd(n)}}function Ol(e){return h(String(e),"escape").replace(/\n+$/,"")}function _l(e){const[t,...n]=String(e).split("\n");return[`*${Ol(t)}*`,...n.map(Ol)].join("\n")}function Rl(e,t=4e3){const n=String(e),i=_l(n);if(i.length<=t)return i;const[s,...r]=n.split("\n"),o=r.join("\n"),a="...\n";let d=s;for(;_l(`${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=_l(`${d}\n${a}`);for(;c<=l;){const e=Math.floor((c+l)/2),n=_l(`${d}\n${a}${o.slice(-e)}`);n.length<=t?(u=n,p=e,c=e+1):l=e-1}const g=o.slice(-p),h=g.indexOf("\n");return h>=0&&h<200&&(u=_l(`${d}\n${a}${g.slice(h+1)}`)),u}function Pl(e){return String(e).replace(/\\([_*\[\]()~`>#+\-=|{}.!\\])/g,"$1")}async function jl(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:Ol;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 Ml(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 Dl(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 Ml(e,t,n,i,s){const r=s.parseMode||"MarkdownV2",o=s.rawMarkdownV2?String(n):Ol(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&&Ll(d.description))return;if(s.rawMarkdownV2&&"MarkdownV2"===r){const s=await e({...i,text:Pl(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&&Ll(r.description))return}const c=await e({...i,text:s.rawMarkdownV2?Pl(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||!Ll(l.description))throw new Error(l.description||d.description||`Telegram ${t} failed with HTTP ${c.status}`)}function Ll(e){return"string"==typeof e&&e.toLowerCase().includes("message is not modified")}function ql(e,t){if("string"==typeof e&&e.trim())return e.trim();Bl(`Chat action token is missing ${t}.`)}function $l(e){if("allow"===e||"deny"===e||"skip"===e)return e;Bl("Chat action token has an invalid decision.")}function Bl(e){const t=new Error(e);throw Object.assign(t,{statusCode:400,code:"CHAT_ACTION_TOKEN_INVALID"}),t}function Ul(e){return Buffer.from(e,"base64url").toString("utf8")}function Fl(e){return String(e||"").split(/\r?\n/,1)[0].replace(/^#+\s*/,"").trim().slice(0,20)||"消息通知"}function Hl(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,"string"==typeof t?t:JSON.stringify(t)]))}function Wl(e){return`dtv1.card//IM_GROUP.${e}`}function Gl(e){return`dtv1.card//IM_ROBOT.${e}`}function Vl(e,t){return dp(t.biz_conversation_id).trim()||dp(e.spaceId).replace(/^dtv1\.card\/\/(?:IM_GROUP|IM_SINGLE|IM_ROBOT)\./,"")}function Kl(e,t={}){const n=dp(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 Jl(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 Yl(e,t,n,i,s){const r=Vl(i,s);return{cardUpdateOptions:{updateCardDataByKey:!0,updatePrivateDataByKey:!1},cardData:{cardParamMap:Hl({type:"actions",title:"TaskHandoff",description:e,list:Jc(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 Ql(e,t,n){const i=[];return Xl(i,n),Xl(i,t),Xl(i,e),i.find(e=>Jl(e))||""}function Xl(e,t){for(const n of["actionIdList","actionIds"]){const i=t[n];Array.isArray(i)&&e.push(...i.map(e=>dp(e)).filter(Boolean))}for(const n of["actionId","action_id","id","actionValue"]){const i=dp(t[n]);i&&e.push(i)}}async function Zl(e,t,n,i){i?.("info",{target:"sessionWebhook",hasSessionWebhook:Boolean(t),textPreview:rp(n)},"dingding webhook send requested");const s=await e(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({msgtype:"markdown",markdown:{title:Fl(n),text:n}})}),r=await s.json().catch(()=>{});if(i?.(s.ok?"info":"warn",{target:"sessionWebhook",status:s.status,response:sp(r)},"dingding webhook send completed"),!s.ok)throw new Error(`DingDing webhook failed with HTTP ${s.status}`)}async function ep(e){const t=Jc(e.replyMarkup);if(!t.length&&!e.forceCard)return e.sessionWebhook&&await Zl(e.fetchImpl,e.sessionWebhook,e.text,e.runtime.onLog),e.sessionWebhook?{delivered:!0}:void 0;const n=e.bridge.settings||{},i=dp(n.robotCode),s=dp(n.cardTemplateId)||"13fc6717-12e4-43ed-8533-111a310d4995.schema",r=dp(n.cardCallbackRouteKey)||"task_handoff_message",o=e.senderId||e.runtime.senderIds.get(e.chatId)||dp(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 Zl(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=Hl({type:"actions",title:e.title||Fl(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:Gl(n),imRobotOpenSpaceModel:{supportForward:!1},imRobotOpenDeliverModel:{extension:{},robotCode:i,spaceType:"IM_ROBOT"}}:{openSpaceId:Wl(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:rp(e.text)},"dingding card send requested"),await tp(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 tp(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=dp(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:np(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:sp(d)},"dingding api response"),!a.ok)throw new Error(`DingDing API failed with HTTP ${a.status}`);const c=op(d),l=c.code??c.errcode,p=c.success;if(void 0!==l&&"0"!==String(l)||!1===p)throw new Error(dp(c.message||c.errmsg)||`DingDing API returned ${String(l||"failure")}`);const u=function(e){const t=op(op(e).result).deliverResults;if(!Array.isArray(t))return"";const n=t.find(e=>!1===op(e).success);if(!n)return"";const i=op(n),s=dp(i.spaceId),r=dp(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 np(e){const t=op(e),n=op(t.cardData),i=op(n.cardParamMap);return{openSpaceId:dp(t.openSpaceId),outTrackId:dp(t.outTrackId),userId:dp(t.userId),userIdType:t.userIdType,callbackType:dp(t.callbackType),callbackRouteKey:dp(t.callbackRouteKey),hasImGroupTarget:Boolean(t.imGroupOpenSpaceModel||t.imGroupOpenDeliverModel),hasImSingleTarget:Boolean(t.imSingleOpenSpaceModel||t.imSingleOpenDeliverModel),hasImRobotTarget:Boolean(t.imRobotOpenSpaceModel||t.imRobotOpenDeliverModel),imGroupOpenDeliverModel:ip(t.imGroupOpenDeliverModel),imSingleOpenDeliverModel:ip(t.imSingleOpenDeliverModel),imRobotOpenDeliverModel:ip(t.imRobotOpenDeliverModel),bizConversationId:dp(i.biz_conversation_id),bizConversationType:dp(i.biz_conversation_type),bizSenderId:dp(i.biz_sender_id),hasBizSessionWebhook:Boolean(dp(i.biz_session_webhook))}}function ip(e){const t=op(e);if(Object.keys(t).length)return{hasExtension:Boolean(t.extension),hasRobotCode:Boolean(dp(t.robotCode)),spaceType:dp(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 sp(e){const t=op(e),n=op(t.result);return{code:t.code??t.errcode,message:rp(t.message||t.errmsg,240),success:t.success,requestId:t.requestId,result:Object.keys(n).length?n:void 0}}function rp(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 op(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function ap(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:"string"==typeof e&&e.trim()?cp(e):{}}function dp(e){return"string"==typeof e?e:""}function cp(e){try{return op(JSON.parse(String(e||"{}")))}catch{return{}}}function lp(e){return JSON.stringify(Jc(e))}const pp="task_handoff_action_id";function up(e,t){const n=Jc(t);return{schema:"2.0",config:{summary:{content:mp(e)}},body:{elements:[{tag:"markdown",content:e},...n.map(e=>({tag:"button",text:{tag:"plain_text",content:e.text},type:yp(e.text),width:"fill",size:"medium",behaviors:[{type:"callback",value:{[pp]:e.id}}]}))]}}}function gp(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[pp]||t.action_id||t.actionId||t.id||e)}function hp(e){return JSON.stringify(Jc(e))}function mp(e){const t=e.replace(/\s+/g," ").trim();return t.length<=50?t:`${t.slice(0,47)}...`}function yp(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 fp(e){return e instanceof Error?e.message:String(e)}function Ip(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 bp(e){return Array.isArray(e?.actionRows)?e.actionRows:(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e])}function vp(e,t){const n=bp(e),i=bp(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 wp{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||Ip,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&&vp(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: ${fp(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&&vp(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&&vp(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: ${fp(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: ${fp(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 Sp=20971520;function Ap(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 kp(e,n,i="telegram-image",s){if(s&&s>Sp)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>Sp)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 m.mkdir(p,{recursive:!0});const u=l.replace(/[^.\w-]/g,"")||".jpg",g=t.join(p,`telegram-${Date.now()}-${Math.random().toString(16).slice(2)}${u}`),h=Buffer.from(await a.arrayBuffer());if(h.length>Sp)throw new Error(`image is too large: ${h.length} bytes`);return await m.writeFile(g,h),g}class zp{store;constructor(e){this.store=new wp({updateIntervalMs:e.updateIntervalMs,send:(t,n,i)=>e.send(e.requireBridge(n?.bridgeId||""),n?.chatId||"",Rl(t),{rawMarkdownV2:!0,replyMarkup:Op(i)}),edit:(t,n,i,s)=>e.edit(e.requireBridge(i?.bridgeId||""),i?.chatId||"",t,Rl(n),{rawMarkdownV2:!0,replyMarkup:Op(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 Cp(e){return(await async function(e,t,n,i){const s=[];for(const r of Ap(n))try{const n=await kp({getFileLink:n=>Dl(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:xp(e),size:r.length,source:{type:"inline",encoding:"base64",data:r.toString("base64")}}})}function xp(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 Tp(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function Ep(e){return e&&"object"==typeof e?e:{}}function Np(e){return"string"==typeof e?e:""}function Op(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return Gc(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function _p(e){const t=Array.isArray(e.item_list)?e.item_list:[];for(const e of t){const t=Rp(e);if(1!==t.type)continue;const n=Pp(Rp(t.text_item).text).trim();if(n)return n}return""}function Rp(e){return e&&"object"==typeof e?e:{}}function Pp(e){return"string"==typeof e?e:""}function jp(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 jl(e,t,n,i,{replyMarkup:s.replyMarkup,replyToMessageId:s.replyToMessageId,rawMarkdownV2:s.rawMarkdownV2,parseMode:s.parseMode});return{provider:"telegram",raw:r,messageId:Number(Ep(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)||dp(t.settings.sessionWebhook);if(r.replyMarkup&&n){const a=await ep({fetchImpl:e,bridge:t,runtime:n,chatId:i,text:s,replyMarkup:r.replyMarkup,sessionWebhook:o,senderId:r.senderId||n.senderIds.get(i)||dp(t.settings.senderId)});if(a?.delivered)return{provider:"dingding",interactionId:a.outTrackId}}if(o)return await Zl(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:up(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||Pp(t.settings.contextToken);if(o)return await async function(e,t,n,s,r){const o=Pp(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(Pp(d.errmsg)||`WeChat send failed with HTTP ${a.status}`)}(e,t,n,o,s),{provider:"wechat"}}}}(t,n):{bridge:n,send:async()=>{}}}class Dp{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=lp(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,lp(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=ep({fetchImpl:this.fetchImpl,bridge:e.bridge,runtime:t,chatId:e.chatId,text:e.text,replyMarkup:e.replyMarkup,sessionWebhook:t.chatWebhooks.get(e.chatId)||Mp(e.bridge.settings.sessionWebhook),senderId:t.senderIds.get(e.chatId)||Mp(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 tp(e.fetchImpl,e.bridge,e.runtime,"PUT","/v1.0/card/instances",{outTrackId:e.outTrackId,cardData:{cardParamMap:Hl({type:"actions",title:e.title,description:e.text,list:Jc(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 Mp(e){return"string"==typeof e?e:""}function Lp(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 qp{runtimes=new Map;connected=new Set;reconnectTimers=new Map;progress;options;createClient;constructor(e){this.options=e,this.createClient=e.createClient||Lp,this.progress=new Dp(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 $p{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=hp(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,hp(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:up(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,up(i,s)),this.isCurrent(e.bridge.id,o)&&(n.lastText=i,n.lastActionsFingerprint=r,n.lastUpdateAt=Date.now()))}}function Bp(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 Up{runtimes=new Map;connected=new Set;unsubscribe=new Map;reconnectTimers=new Map;options;createChannel;progress;constructor(e){this.options=e,this.createChannel=e.createChannel||Bp,this.progress=new $p(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:Fp(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 Fp(e){return"lark"===String(e||"").trim().toLowerCase()?I.Domain.Lark:I.Domain.Feishu}class Hp{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 Wp{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=Gp(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!==Gp(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:Gc([[{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 Gp(e,t,n){return[e,t,n||""].join(":")}class Vp{cancelTokens=new Map;queueActionTokens=new Map;options;constructor(e){this.options=e}cancelCallbackData(e,t){this.pruneExpired();const n=Jp([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=Kp(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=Kp(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=Kp(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=Kp(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=Qp(await this.options.queue(t.instanceId,t.sessionId)),i=(Array.isArray(n.items)?n.items:[]).map(Qp).filter(e=>"queued"===Xp(e.status)&&Xp(e.id));if(!i.length)return void await this.answer(e,"Queue is empty");const s=i.slice(0,5).map((e,n)=>[{text:Yp(Xp(e.message),n),callbackData:this.queueDeleteItemCallbackData(t.instanceId,t.sessionId,Xp(e.id))}]);await this.send(e,"Delete queued message",{replyMarkup:Gc(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:Zp(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=Zp(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=Jp([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 Kp(e,t){if(!e.startsWith(t))return;const n=e.slice(t.length);return n&&!n.includes(":")?n:void 0}function Jp(e){return i.createHash("sha256").update(e.join("\0")).digest("base64url").slice(0,16)}function Yp(e,t){const n=`${t+1}. `,i=Xp(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 Qp(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Xp(e){return"string"==typeof e?e.trim():""}function Zp(e){return e instanceof Error?e.message:String(e)}class eu{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=tu(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,nu(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,nu(t)),!1))}}function tu(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:Gc([[{text:"Allow",callbackData:t(e.id,"allow")},{text:"Skip",callbackData:t(e.id,"skip")},{text:"Deny",callbackData:t(e.id,"deny")}]])}}function nu(e){return e instanceof Error?e.message:String(e)}function iu(){return e=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(e||"").trim().toLowerCase());var e}class su{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||iu,this.aiSessionInstanceNamesCache=new Hp(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 Hp(1e3,()=>this.service.listPendingRoutes().catch(()=>[])),this.telegramMessageAggregator=new Wp({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,gu(t))}),this.telegramAiSessionCallbacks=new Vp({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 eu({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 zp({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 qp({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,gu(t)),clearError:e=>this.bridgeErrors.delete(e)}),this.larkBridges=new Up({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,gu(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:gu(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:mu(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: ${gu(e)}`})}const o=ru(r);if(!o)return;const a=au(r);if(await this.sendLarkRoutedAiSessionProgress(r,e,n.chatId,o,a))return;const d=jp({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===Iu(r).routed,replyPreview:mu(o)},"lark chat gateway reply sent")}async sendLarkRoutedAiSessionProgress(e,t,n,i,s){if(!0!==e.routed)return!1;const r=wu(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=xu(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:mu(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=gp(n.action.value),r=(e,i)=>t.channel.updateCard(n.messageId,up(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:up(e,i?.replyMarkup)})}))return;let o;try{o=await this.parseChatGatewayCallbackAction(s)}catch(e){if(hu(e,"CHAT_PENDING_ACTION_STALE"))return void await r(gu(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&&ou(a))return void await r(`${o.decision} sent`);const d=ru(a)||uu(a.message)||"Updated";await r(d,au(a))}async handleDingdingRobotMessage(e,t,n){const i=function(e){const t=cp(e),n=dp(t.conversationId),i=dp(op(t.text).content).trim();if(!n||!i)return;const s=dp(t.senderStaffId||t.senderId);return{chatId:n,userId:s||void 0,senderId:s||void 0,sessionWebhook:dp(t.sessionWebhook)||void 0,conversationType:Kl(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)||uu(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:mu(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 Zl(this.fetchImpl,d,`Failed to handle message: ${gu(e)}`,t.onLog);throw e}const l=ru(c);if(l){const n=au(c);if(await this.sendDingdingRoutedAiSessionProgress(c,e,t,s,l,{replyMarkup:n,sessionWebhook:d,senderId:o,sourcePrompt:r}))return;const i=jp({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===Iu(c).routed,hasReplyMarkup:Boolean(n),replyPreview:mu(l)},"dingding chat gateway reply sent");this.logWarn({bridgeId:e.id,chatId:s,senderId:o,hasReplyMarkup:Boolean(n),hasSessionWebhook:Boolean(d),hasRobotCode:Boolean(uu(e.settings.robotCode)),replyPreview:mu(l)},"dingding chat gateway reply skipped")}}async sendDingdingRoutedAiSessionProgress(e,t,n,i,s,r={}){if(!0!==e.routed)return!1;const o=wu(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=xu(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:mu(r.sourcePrompt,80),textPreview:mu(s)},"dingding ai session progress card started"),!0)}async handleDingdingCardCallback(e,t,n){const i=function(e){const t=cp(e),n=ap(t.cardActionData||t.content),i=ap(n.cardPrivateData||t.cardPrivateData||t.content),s=ap(i.params||n.params||t.params),r=dp(t.userId),o=dp(s.biz_sender_id);return{userId:r||void 0,chatId:Vl(t,s),senderId:r||void 0,deliverySenderId:o||void 0,sessionWebhook:dp(s.biz_session_webhook)||void 0,conversationType:Kl(s.biz_conversation_type||t.conversationType||t.conversation_type),callbackData:Jl(Ql(t,n,i)),body:t,params:s}}(n.data);if(!this.dingdingAllowed(e,i.userId))return Yl("not authorized",void 0,"unauthorized",i.body,i.params);const s=i.chatId||uu(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(hu(e,"CHAT_PENDING_ACTION_STALE"))return Yl(gu(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,...yu(i)},"dingding card callback action unsupported"),Yl("Unsupported action",void 0,"unsupported",i.body,i.params);this.logInfo({bridgeId:e.id,chatId:s,userId:i.userId,senderId:r,actionType:a.type,...yu(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&&ou(d)?Yl(`${a.decision} sent`,void 0,"approval_done",i.body,i.params):Yl(ru(d)||uu(d.message)||"updated",au(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)||uu(n.updatesBuf),s=await async function(e){const t=Pp((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(Pp(i.errmsg||i.msg)||`chat bridge API returned ${s}`);const r=[];for(const e of Array.isArray(i.msgs)?i.msgs:[]){const t=Rp(e);if(1!==t.message_type)continue;const n=Pp(t.from_user_id),i=_p(t);n&&i&&r.push({chatId:n,text:i,contextToken:Pp(t.context_token)})}return{cursor:Pp(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=ru(a);if(d){const t=jp({fetchImpl:this.fetchImpl,bridge:e});await t.send(s,d,{contextToken:r||uu(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 jp({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=Ep(t.callback_query);if(Object.keys(r).length>0){s.push({updateId:i,callbackQuery:r});continue}const o=Ep(t.message||t.edited_message);if(0===Object.keys(o).length)continue;const a=Ep(o.chat),d=Ep(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=Np(o.text??o.caption),u=Ap(o);(p||0!==u.length)&&s.push({updateId:i,chatId:c,userId:l,text:p,rawText:p,message:o,messageId:Tp(o),replyToMessageId:Tp(Ep(o.reply_to_message)),quoteText:Np(Ep(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=Iu(t.message),s=Iu(i.chat),r=void 0!==s.id?String(s.id):e.defaultChatId;this.bridgeErrors.set(e.id,gu(n)),r&&await this.sendTelegramMessage(e,r,`Action failed: ${gu(n)}`).catch(t=>{this.bridgeErrors.set(e.id,gu(t))})});continue}if(!this.telegramAllowed(e,n.userId))continue;const i=await Cp({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:gu(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:mu(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=ru(d),l=au(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(Iu(n).message_id)||void 0,routed:!0===Iu(d).routed,replyPreview:mu(c)},"telegram chat gateway reply sent"),await this.rememberTelegramProgressMessage(d,e,t,n,c)}}catch(n){this.bridgeErrors.set(e.id,gu(n)),await this.sendTelegramMessage(e,t,`Failed to handle message: ${gu(n)}`,{replyToMessageId:r.sourceMessageId}).catch(t=>{this.bridgeErrors.set(e.id,gu(t))})}}async handleTelegramCallback(e,t){const n=uu(t.data),i=Iu(t.from),s=Iu(t.message),r=Iu(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:uu(t.id),userId:a,messageId:cu(s)}))return;const d=n.match(/^task_handoff:cp_msg_end:([^:]+)$/);if(d)return void await this.telegramMessageAggregator.handleEndCallback(e,o,uu(t.id),d[1],a);let c;try{c=await this.parseChatGatewayCallbackAction(n)}catch(n){if(hu(n,"CHAT_PENDING_ACTION_STALE")){await this.answerTelegramCallback(e,uu(t.id),gu(n));const i=cu(s);return void(void 0!==i&&await this.deleteTelegramStandaloneApprovalMessage(e,o,i))}throw n}if(!c)return void await this.answerTelegramCallback(e,uu(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&&ou(l)){await this.answerTelegramCallback(e,uu(t.id),"");const n=cu(s);return void(void 0!==n&&await this.deleteTelegramStandaloneApprovalMessage(e,o,n))}await this.answerTelegramCallback(e,uu(t.id),uu(l.message)||"updated");const p=ru(l),u=au(l),g=s.message_id;p&&"number"==typeof g?await this.editTelegramMessage(e,o,g,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:gu(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(Lc).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&&qc(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:ql(t(i[1],"instance-app-menu").instanceId,"instanceId")}:{type:"instance-app-menu",instanceId:Ul(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:ql(e.instanceId,"instanceId"),appId:ql(e.appId,"appId")}}return{type:"launch-app",instanceId:Ul(s[1]),appId:Ul(s[2])}}const r=e.match(/^task_handoff:cp_p:([^:]+)$/);if(r){const e=t(r[1],"pending-decision");return{type:"pending-decision",routeId:ql(e.routeId,"routeId"),decision:$l(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 Ml(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 jl(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=wu(e),{instanceId:o,sessionId:a,turnId:d}=r,c=Number(Iu(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=xu(o,a,d,t.id,n),p=this.telegramProgress.remember(l,c,s,{bridgeId:t.id,chatId:n});this.telegramProgressMessageTargets.set(lu(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:mu(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(lu(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:gu(e)},"telegram queued progress message replacement cleanup failed")}))}telegramReplyAiSessionTarget(e,t,n){const i=this.telegramProgressMessageTargets.get(lu(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=pu(i,e,t);if(s){const i={...s,messageId:n};return this.telegramProgressMessageTargets.set(lu(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(lu(i.route.bridgeId,i.route.chatId,i.messageId||0))||pu(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(lu(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=_u(n.get(e)||e,r),a=Ou(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:fu(Pu(r))});continue}const d=Tu(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:fu(Pu(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=xu(e,r.id,d,s.bridgeId||"",s.chatSessionId),l=Eu(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:fu(Pu(r)),textPreview:mu(a)});continue}const p=ku({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)||zu(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:fu(Pu(r)),textPreview:mu(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:gu(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:mu(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:mu(t?.lastText),progressHasPending:Boolean(t?.pending),latestTurn:fu(Pu(r)),textPreview:mu(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:mu(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=_u(n.get(e)||e,o),c=Ou(o,d),l=Tu(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:xu(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=Eu(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 g=ku({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)||zu(e,o),session:o}),h=await this.updateChatAiSessionProgress(a,c,p,g).catch(e=>(this.bridgeErrors.set(a.bridgeId||"",e instanceof Error?e.message:String(e)),!1));this.logAiSessionDelivery({stage:h?"remembered-delivered":"remembered-not-delivered",key:p,instanceId:e,sessionId:o.id,bridgeId:s.route.bridgeId,chatId:s.route.chatId,textPreview:mu(c)}),h&&(this.telegramProgressMessageTargets.set(lu(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(lu(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(lu(i.route.bridgeId,i.route.chatId,i.messageId))||pu(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||Pu(t)?.id===e.owner.turnId||Pu(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:du({actionRows:i})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:mu(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:du({actionRows:i})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:mu(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:mu(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:mu(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 ru(e){return"object"==typeof e&&e&&"reply"in e?String(e.reply||""):""}function ou(e){return"object"==typeof e&&null!==e&&!0===e.accepted}function au(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 du(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return Gc(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function cu(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function lu(e,t,n){return[e,t,String(n)].join(":")}function pu(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 uu(e){return"string"==typeof e?e:""}function gu(e){return e instanceof Error?e.message:String(e)}function hu(e,t){return Boolean(e&&"object"==typeof e&&"code"in e&&e.code===t)}function mu(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 yu(e){const t=bu(e.body.cardActionData||e.body.content),n=bu(t.cardPrivateData||e.body.cardPrivateData||e.body.content);return{outTrackId:uu(e.body.outTrackId),spaceId:uu(e.body.spaceId),conversationType:e.conversationType,hasCallbackData:Boolean(e.callbackData),callbackDataPreview:mu(e.callbackData,120),actionIds:[...vu(n.actionIdList),...vu(t.actionIdList),uu(n.actionId),uu(t.actionId),uu(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 fu(e){if(e)return{id:e.id,providerTurnId:e.providerTurnId,source:e.source,status:e.status,phase:e.phase,revision:e.revision,userPrompt:mu(e.userPrompt,80),hasResponse:Boolean(e.lastMessage?.trim()||e.summary?.trim()),responsePreview:mu(e.lastMessage||e.summary,80),updatedAt:e.updatedAt,observedAt:e.observedAt}}function Iu(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function bu(e){if(e&&"object"==typeof e&&!Array.isArray(e))return e;if("string"==typeof e&&e.trim())try{return Iu(JSON.parse(e))}catch{return{}}return{}}function vu(e){return Array.isArray(e)?e.map(e=>uu(e)).filter(Boolean):[]}function wu(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?Tu(n):""),sources:{resultTurnId:e.turnId,resultProviderTurnId:e.providerTurnId,actionTurnId:t?.turnId,actionProviderTurnId:t?.providerTurnId,sessionActiveTurnId:n?.activeTurnId,latestTurnId:n?Pu(n)?.id:void 0}}}const Su=5,Au=48;function ku(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,Su);return[...d.map((e,t)=>[{text:Cu(e.message,t),callbackData:n(e.id)}]),d.length?[{text:"Delete Queue",callbackData:i()},{text:"Cancel",callbackData:t}]:[{text:"Cancel",callbackData:t}]]}function zu(e,t){if("approval"===t.phase)return{id:`${e}:ai:${t.id}`,kind:"approval"}}function Cu(e,t){const n=`${t+1}. `,i=e.replace(/\s+/g," ").trim()||"Queued message",s=Math.max(8,Au-n.length),r=Array.from(i);return`${n}${r.length>s?`${r.slice(0,Math.max(1,s-3)).join("")}...`:i}`}function xu(e,t,...n){return[e,t,...n].join(":")}function Tu(e){const t=Pu(e);return t?.id?t.id:uu(e.activeTurnId)}function Eu(e,t=""){const n=Pu(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),Nu(e)].join("\0")}function Nu(e){return(e.queue?.items||[]).map(e=>[e.id,e.status,e.message].join(":")).join("|")}function Ou(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&&!Ru(n,e)?i:""].filter(Boolean).join("\n\n")}(e,Pu(e));return n?`${t}\n${n}`:""}function _u(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 Ru(e,t){if("waiting"!==t.status||"approval"!==t.phase)return!1;const n=t.currentTool?.inputPreview?.trim();return Boolean(n&&e.includes(n))}function Pu(e){return(e.turns||[]).filter(e=>e.id||e.userPrompt?.trim()||e.lastMessage?.trim()||e.summary?.trim()).at(-1)}class ju{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&&Du(t.topics,s,e)&&Mu(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||Rr(e),createdAt:(new Date).toISOString(),payload:t,scope:n.scope}}}function Du(e,t,n){return!e||e.has("*")||e.has(t)||e.has(n)}function Mu(e,t){return!e||!t?.instanceId||e.has(t.instanceId)}const Lu={"image/bmp":".bmp","image/gif":".gif","image/jpeg":".jpg","image/png":".png","image/webp":".webp"},qu=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 $u(){return t.join(y.tmpdir(),"task-handoff-ai-session-attachments")}class Bu{items=new Map;ttlMs;constructor(e=864e5){this.ttlMs=e,this.pruneOrphanFiles()}upload(e){this.pruneExpired();const s=qu.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=Lu[o]||"";if("image"===s.kind&&!a)throw new Error(`Unsupported image type: ${o}`);const d="image"===s.kind?r.buffer.length>x:r.buffer.length>=T;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=$u();n.mkdirSync(u,{recursive:!0});const g=function(e){return t.basename(e).replace(/[^\w.\- ()\u4e00-\u9fff]/g,"_").slice(0,160)||"attachment"}(s.name),h=t.join(u,`${c}-${g.endsWith(a)?g:`${g}${a}`}`);n.writeFileSync(h,r.buffer);const m={id:c,instanceId:s.instanceId,sessionId:s.sessionId,kind:s.kind,name:g,mime:o,size:r.buffer.length,source:{type:"inline",encoding:"base64",data:r.buffer.toString("base64")},path:h,createdAt:l.toISOString(),expiresAt:p.toISOString()};return this.items.set(c,m),this.publicAttachment(m)}resolveRefs(e,t,n){this.pruneExpired();const i=a.z.array(Q).max(6).default([]).parse(e),s=i.map(e=>"runtime-path"===e.source.type?J.parse(e):this.requireAttachment(e,t,n));if(s.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>E)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 J.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=$u();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 Uu={controlPlaneAuthBoundary:"public"},Fu={controlPlaneAuthBoundary:"public-ui"},Hu={controlPlaneAuthBoundary:"proxy-binding"},Wu={controlPlaneAuthBoundary:"node-tunnel"};class Gu{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 Vu(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function Ku(e){return e.unref?.(),e}class Ju{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=Vu(e.connectTimeoutMs,1e4),this.handshakeTimeoutMs=Vu(e.handshakeTimeoutMs,1e4),this.heartbeatIntervalMs=Vu(e.heartbeatIntervalMs,25e3),this.heartbeatTimeoutMs=Vu(e.heartbeatTimeoutMs,1e4),this.stableThresholdMs=Vu(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=Ku(this.setTimeoutFn(()=>this.timeout("connect"),this.connectTimeoutMs))}opened(){this.stopped||(this.clearTimer("connectTimer"),this.setPhase("handshaking"),this.handshakeTimer=Ku(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=Ku(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=Ku(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 Yu{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 Qu={[N]:Je,[O]:Ye,[_]:Qe,[R]:Xe,[st]:yt,[rt]:ft,[ot]:It},Xu=new Set(Object.keys(Qu));class Zu{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=So(Dr,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=eg(t.event),s="string"==typeof i?.type?i.type:"";if(!s)return!0;const r="payload"in i?i.payload:{},o=eg(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=So(tr,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===br){const t=So(vr,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===Hs||s===Ws){const t=So(s===Hs?Vs:Ks,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(Xu.has(s)){const t=function(e,t){const n=Qu[e];if(!n)return;const i=So(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]=ng(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=tg(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=tg(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 eg(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:void 0}function tg(e,t){return JSON.stringify([e,t])}function ng(e){const t=JSON.parse(e);return Array.isArray(t)&&2===t.length?[String(t[0]),String(t[1])]:["",""]}const ig=a.z.object({nodeId:a.z.string().trim().min(1).max(120)}).strict();function sg(){return`req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}const rg=new Map;function og(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)>Ma)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()-Ma;for(const[e,t]of rg)t<=r&&rg.delete(e);const o=`${e.id}:${n.keyId}:${n.nonce}`;if(!n.nonce||rg.has(o))throw Object.assign(new Error("Reverse tunnel nonce is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_NONCE_INVALID"});const a=$a("");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||`${La}?nodeId=${encodeURIComponent(e.id)}`,c=Ba(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"});rg.set(o,Date.now()+Ma)}function ag(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 dg{sockets=new Map;eventRouter;httpStreamHeaderTimeoutMs;requestTimeoutMs;auxiliaryAttachTimeoutMs;connectionRuntime;connectionOptions;constructor(e,t={}){this.eventRouter=new Zu({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 Ju({...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=sg(),r=di(n.body),o={type:"control-plane.request",requestId:s,route:t,init:{method:n.method||"GET",headers:ag(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=sg(),r=di(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:ag(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 g.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(g.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=sg(),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=_a(e),s=Oa(t);n.upstream&&Ra(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 ja(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),Ra(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 cg{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=Ua(t),i=n?void 0:new URL(t),s=qa(e,{method:"GET",pathWithQuery:i?`${i.pathname}${i.search}`:"/api/node-agent/events"}),r=n?Ha(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 Gu;this.retries.set(e.id,{timer:a,url:t});const d=new Ju({...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 Gu};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(Ua(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 lg(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 pg 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 ug(e){return t.join(e,"owner.json")}function gg(e){return t.join(e,"initializing.json")}function hg(e){return t.join(e,"recovering.json")}function mg(e){return Number.isInteger(e)&&Number(e)>0}function yg(e,t=process.platform){if(mg(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 fg=function(e){try{const t=JSON.parse(n.readFileSync(ug(e),"utf8"));if(mg(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(!(mg(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 Ig(e){if(!mg(e))return!1;try{return process.kill(Number(e),0),!0}catch(e){return"EPERM"===e.code}}function bg(e){if(!e||!Ig(e.pid))return!1;if(!e.startIdentity)return!0;const t=yg(e.pid);return void 0===t||t===e.startIdentity}function vg(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=Sg(e);if(r?.token!==i.token)throw kg(s),new Error(`Process lock initialization was superseded: ${e}`);n.renameSync(s,ug(e)),kg(gg(e))}function wg(e,s,r){const o=fg(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"}),fg(e)?.token!==s.token)return!1;n.renameSync(d,ug(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{kg(d)}}function Sg(e){try{return JSON.parse(n.readFileSync(gg(e),"utf8"))}catch{return}}function Ag(e){const t=Sg(e);return mg(t?.pid)&&bg({pid:t.pid,startIdentity:t.startIdentity})}function kg(e){try{n.unlinkSync(e)}catch(e){if("ENOENT"!==e.code)throw e}}function zg(){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,20)}function Cg(e){try{const t=Sg(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 xg(e,s){try{return n.writeFileSync(hg(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=hg(e),r=Tg(s),o=Date.parse(r?.startedAt||"");if(Ig(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=Tg(a);if(d?.token===r?.token)return kg(a),!0;try{n.linkSync(a,s)}catch(e){if("EEXIST"!==e.code)throw e}finally{kg(a)}return!1}(e)&&xg(e,s);if("ENOENT"===r.code)return!1;throw r}}function Tg(e){try{return JSON.parse(n.readFileSync(e,"utf8"))}catch{return}}function Eg(e,t){return Tg(hg(e))?.token===t}function Ng(){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 Og(e,s={}){return function(e,s={}){n.mkdirSync(t.dirname(e),{recursive:!0});const r=yg(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(gg(e),`${JSON.stringify({token:o.token,pid:o.pid,startIdentity:o.startIdentity,startedAt:(new Date).toISOString()})}\n`,{encoding:"utf8",mode:384,flag:"wx"}),vg(e,o),{lockPath:e,owner:o,updateDetails:t=>wg(e,o,t),release(){const t=fg(e);t?.token===o.token&&n.rmSync(e,{recursive:!0,force:!0})}}}catch(r){if("EEXIST"!==r.code)throw r;const o=fg(e);if(bg(o))throw new pg(e,o,s.error);if(!o&&(Ag(e)||Cg(e)<(s.incompleteLockStaleMs??2e3))){if(t+1<5){zg();continue}throw new pg(e,void 0,s.error)}const a=i.randomUUID();if(!xg(e,a)){if(t+1<5){zg();continue}throw new pg(e,fg(e),s.error)}const d=fg(e);if(bg(d))throw kg(hg(e)),new pg(e,d,s.error);if(o?.token&&d?.token!==o.token){kg(hg(e));continue}if(!Eg(e,a))continue;n.rmSync(e,{recursive:!0,force:!0})}const a=fg(e);throw new pg(e,a,s.error)}(e,{...s,component:"control-plane",error:{label:"Control plane",code:"CONTROL_PLANE_ALREADY_RUNNING"}})}function _g(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:Rg(e,t))}(t,n):"admin"===e.role||("viewer"===e.role?"read"===t:"operator"===e.role&&Rg(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 Rg(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 Pg=a.z.string().trim().min(1),jg=a.z.object({id:Pg}).strict(),Dg=a.z.object({id:Pg,keyId:Pg}).strict(),Mg=a.z.object({id:Pg,connectionId:Pg}).strict(),Lg=a.z.object({id:Pg,runtimeId:Pg}).strict(),qg=a.z.object({id:Pg,folderId:Pg}).strict(),$g=a.z.object({id:Pg,sessionId:Pg}).strict(),Bg=a.z.object({id:Pg,sessionId:Pg,queueId:Pg}).strict(),Ug=a.z.object({configHash:Pg}).strict(),Fg=a.z.object({id:Pg,configHash:Pg}).strict(),Hg=a.z.object({id:Pg,sessionId:Pg,configHash:Pg}).strict(),Wg=a.z.object({path:a.z.string().optional(),depth:a.z.coerce.number().int().min(0).max(32).optional()}).strict();async function Gg(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 Vg=a.z.object({ids:a.z.array(a.z.string().trim().min(1).max(120)).default([])}).strict(),Kg=a.z.object({nodeId:a.z.string().trim().min(1).max(120),modelId:a.z.string().trim().min(1).max(120).optional()}).strict(),Jg=a.z.object({source:a.z.object({channel:kr,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 Yg(e){const t=Jg.parse(e);if(!t.action)throw new Error("Chat gateway action is required.");return{source:t.source,action:t.action}}const Qg=a.z.object({path:a.z.string().trim().max(1e3).optional(),depth:a.z.coerce.number().int().min(0).max(2).optional()}).strict(),Xg=a.z.object({id:a.z.string().trim().min(1),appId:a.z.string().trim().min(1)}).strict(),Zg=a.z.object({id:a.z.string().trim().min(1),jobId:a.z.string().trim().min(1)}).strict(),eh=a.z.object({projection:a.z.literal("directory").optional(),instanceId:a.z.string().trim().min(1).max(120).optional()}).strict();const th=a.z.object({id:a.z.string().trim().min(1).max(120)}).strict(),nh=a.z.object({nodeId:a.z.string().trim().min(1).max(120),templateId:a.z.string().trim().min(1).max(120)}).strict(),ih=a.z.object({force:a.z.enum(["true","false"]).optional()}).strict(),sh=a.z.object({projection:a.z.literal("directory").optional()}).strict();const rh=a.z.object({cwdFolderId:a.z.string().trim().min(1).max(120)}).strict(),oh=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:{}}),ah=a.z.object({title:a.z.string().trim().min(1).max(120)}).strict(),dh=a.z.object({token:a.z.string().trim().min(1).max(512)}).strict(),ch=a.z.object({}).strict();function lh(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(jg.parse(e.params).id)})),e.patch("/api/projects/:id",async e=>{const i=t.updateProject(jg.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=jg.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)=>Gg(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/reorder",async e=>{const i=Vg.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(jg.parse(e.params).id)})),e.patch("/api/models/:id",async e=>{const i=await t.updateModel(jg.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=jg.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}=Kg.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.patch("/api/nodes/:nodeId/models/:modelId",async e=>{const{nodeId:i,modelId:s}=Kg.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}=Kg.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(jg.parse(e.params).id)})),e.patch("/api/images/:id",async e=>{const i=t.updateImage(jg.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=jg.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"===sh.parse(e.query).projection?t.listNodes().map(e=>function(e){const t=e.proxyState?.lastError;return md.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(jg.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(jg.parse(e.params).id)})),e.get("/api/nodes/:id/settings/external-listener",async e=>({data:await t.getLocalNodeExternalListener(jg.parse(e.params).id)})),e.patch("/api/nodes/:id/settings/external-listener",async e=>{const i=jg.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=jg.parse(e.params).id,s=await t.checkNodeUpdate(i,os.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=jg.parse(e.params).id,r=await t.applyNodeUpdate(s,cs.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=jg.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=jg.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=jg.parse(e.params);return{data:await t.listNodeControlPlanePairings(n.id)}}),e.delete("/api/nodes/:id/control-plane-pairings/:keyId",async e=>{const i=Dg.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=jg.parse(e.params);return{data:await t.listNodeControlPlaneConnections(n.id)}}),e.delete("/api/nodes/:id/control-plane-connections/:connectionId",async e=>{const i=Mg.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:Uu},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(jg.parse(e.params).id)})),e.post("/api/nodes/:id/runtimes",async(e,i)=>{const s=jg.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=Lg.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=Lg.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=Lg.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(jg.parse(e.params).id)})),e.get("/api/nodes/:id/image-options",async e=>({data:await t.listNodeImageAvailability(jg.parse(e.params).id)})),e.get("/api/nodes/:id/local-folders",async(e,n)=>Gg(e,n,async n=>({data:await t.listNodeLocalFolders(jg.parse(e.params).id,n)}))),e.get("/api/nodes/:id/folders/tree",async e=>{const n=jg.parse(e.params),i=Wg.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=jg.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=qg.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(jg.parse(e.params).id)})),e.patch("/api/nodes/:id",async e=>{const r=t.updateNode(jg.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=jg.parse(e.params).id,r=ih.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)=>Gg(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 Yu(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(La,{websocket:!0,config:Wu},(e,t)=>{try{const i=ig.parse(t.query),s=n.requireNode(i.nodeId);og(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(`${La}/streams/:streamId`,{websocket:!0,config:Wu},(e,t)=>{try{const i=ig.parse(t.query),s=n.requireNode(i.nodeId);og(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(`${La}/channels/:channelId`,{websocket:!0,config:Wu},(e,t)=>{try{const i=ig.parse(t.query),s=n.requireNode(i.nodeId);og(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(`${La}/http-streams/:streamId`,{websocket:!0,config:Wu},(e,t)=>{try{const i=ig.parse(t.query),s=n.requireNode(i.nodeId);og(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(jg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/metrics",async e=>({data:await t.instanceResourceMetrics(jg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/apps/management",async e=>({data:await t.instanceAppManagement(jg.parse(e.params).id)})),e.post("/api/controlled-instances/:id/apps/:appId/install",async e=>{const n=Xg.parse(e.params),i=Yi.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=Xg.parse(e.params),i=Yi.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=Zg.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(jg.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=jg.parse(e.params).id,s=await t.deleteControlledInstance(i,Ci.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(jg.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(jg.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(jg.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(jg.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(jg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/config-sync/folders",async e=>({data:await t.listInstanceConfigSyncFolders(jg.parse(e.params).id,Qg.parse(e.query))})),e.post("/api/controlled-instances/:id/config-sync",async e=>{const i=jg.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)=>Gg(e,n,async n=>{const i=eh.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===ti,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 fd.parse({id:e.id,name:e.name,nodeId:e.nodeId,status:e.status,health:e.health,connectionStatus:e.connectionStatus,ready:e.ready,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(th.parse(e.params).id)})),e.get("/api/nodes/:nodeId/environment-templates/:templateId",async e=>{const n=nh.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=th.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=nh.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=jg.parse(e.params),s=oh.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=$g.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=$g.parse(e.params),s=ah.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=$g.parse(e.params);ch.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=$g.parse(e.params),i=dh.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=jg.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=jg.parse(e.params);return{data:await t.listAiSessionHistory(n.id)}}),e.get("/api/controlled-instances/:id/ai-sessions/history/:sessionId",async e=>{const n=$g.parse(e.params);return{data:await t.getAiSessionHistoryDetail(n.id,n.sessionId)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/resume",async e=>{const i=$g.parse(e.params);ch.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=jg.parse(e.params),i=rh.parse(e.query||{});return{data:await t.inspectAiSessionWorkspace(n.id,i.cwdFolderId)}}),e.post("/api/controlled-instances/:id/ai-sessions",async e=>{const i=jg.parse(e.params),s=Ie.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=$g.parse(e.params),s=Ae.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=$g.parse(e.params),s=we.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=$g.parse(e.params),s=ze.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=$g.parse(e.params),s=he.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=$g.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=$g.parse(e.params),i=le.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=$g.parse(e.params),s=te.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=$g.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=Bg.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=Bg.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=Bg.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=Bg.parse(e.params),i=Ee.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=$g.parse(e.params),i=Te.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=$g.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=$g.parse(e.params),s=xe.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=$g.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(P,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=Ug.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=Ug.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=Ug.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=jg.parse(e.params);return{data:await t.listInstanceTriggers(n.id)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/triggers",async e=>{const i=$g.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=Hg.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=Fg.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(jg.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=jg.parse(i.params).id,r=t.requireChatBridge(s),o=Bd.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=jg.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=jg.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=jg.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(xr.parse(e.body))})),e.post("/api/chat-gateway/actions",async e=>({data:await t.handleChatGatewayAction(Yg(e.body))})),e.get("/api/pending-routes",async()=>({data:await t.listPendingRoutes()}))}({app:t,service:n,chatGateway:d})}const ph=new Set(["connection","content-length","keep-alive","proxy-authenticate","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),uh=new Set(["authorization"]),gh=new Set(["content-encoding"]);function hh(e){return Object.fromEntries(Object.entries(e).flatMap(([e,t])=>{const n=e.toLowerCase();if(ph.has(n)||uh.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()!==eo).join("; ")}(i);return s?[[e,s]]:[]}))}function mh(e){return Object.fromEntries(Object.entries(hh(e)).filter(([e])=>{const t=e.toLowerCase();return"host"!==t&&"cookie"!==t&&"authorization"!==t&&(!t.startsWith("sec-websocket-")||"sec-websocket-origin"===t)}))}function yh(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 fh(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 Ih(e,t,n){for(const[n,i]of Object.entries(t.headers)){const t=n.toLowerCase();ph.has(t)||gh.has(t)||e.header(n,i)}if(!t.body)return e.code(t.status).send();const i=g.Readable.fromWeb(t.body);return e.raw.once("close",()=>i.destroy()),e.code(t.status).send(n?i.pipe(n):i)}function bh(e){return`/instances/${encodeURIComponent(e)}`}function vh(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 g.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()}})}(bh(n)):void 0;return Ih(e,t,s)}function wh(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 Sh(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 Ah(e){return new URL(e,"http://control-plane.local").searchParams.get("token")||""}function kh(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 zh{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){const t=So(Xe,e.payload);return!!t.success||(this.logger?.warn?.({eventType:e.type,issues:t.error.issues,errorCode:"AI_SESSION_MESSAGE_DELTA_INVALID"},"ai-session.aggregator.message-delta.invalid"),!1)}const t=e.type===N?Je:e.type===O?Ye:e.type===_?Qe:void 0;if(!t)return!1;const n=So(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 Ze.parse({streamId:i,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:s,syncRequired:!0,events:[]});if(e.sinceRevision===n)return Ze.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 Ze.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:He.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=Fe.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:He.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 Ch=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 xh{records;bySession=new Map;listener;constructor(e,t={}){this.records=new Qr(e.aiSessionUnreadDir,{schema:Ch}),this.listener=t.onChanged}init(){this.records.init(),this.bySession.clear();for(const e of this.records.list())this.bySession.set(Eh(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(Eh(e,t.id))?.unread||!1}))}}markRead(e,t,n){const i=this.bySession.get(Eh(e,t));return i&&i.sessionUpdatedAt===n&&i.unread?Th(this.store({...i,unread:!1,updatedAt:(new Date).toISOString()},!1)):i?Th(i):void 0}removeInstance(e){for(const t of[...this.bySession.values()])t.instanceId===e&&this.deleteRecord(t)}reconcileSession(e,t){const n=Eh(e,t.id),i=this.bySession.get(n),s=(new Date).toISOString();if(!i)return void this.store({id:Nh(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(Eh(n.instanceId,n.sessionId),n),t&&this.listener?.(Th(n)),n}deleteRecord(e){this.records.delete(e.id),this.bySession.delete(Eh(e.instanceId,e.sessionId))}}function Th(e){return L.parse({instanceId:e.instanceId,sessionId:e.sessionId,unread:e.unread,sessionUpdatedAt:e.sessionUpdatedAt,updatedAt:e.updatedAt})}function Eh(e,t){return`${e}\0${t}`}function Nh(e,t){return`ais_unread_${i.createHash("sha256").update(Eh(e,t)).digest("hex").slice(0,32)}`}class Oh{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===st?yt:e.type===rt?ft:e.type===ot?It:void 0;if(!t)return!1;const n=So(t,e.payload);return n.success?e.type===st?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:st,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,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 bt.parse({streamId:i,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:s,syncRequired:!0,events:[]});if(e.sinceRevision===n)return bt.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 bt.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===st&&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===st)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:wt(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===rt){const e=i.findIndex(e=>e.id===t.payload.session.id);kt(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=vt(i,n.generatedAt);return{kind:"applied",projection:gt.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:wt(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:st,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:st,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 _h(e){return e.raw[0].replace(/\\\$\{/g,"${")}class Rh{states=new Map;events;constructor(e){this.events=e}handle(e){if(e.type===br){const t=So(vr,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===Hs){const t=So(Vs,e.payload);return void(t.success&&this.applyOutput(t.data))}if(e.type===Ws){const t=So(Ks,e.payload);t.success&&this.applyFinished(t.data)}}snapshots(){return[...this.states.values()].filter(e=>e.progress).map(e=>Js.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 Mh,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=jh(s);e.set(i,{...a,status:o,...d||{}})}}(n.layers,n.terminal.text()),n.progress=Ph(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=Ph(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 Mh,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=Ph(e),this.events.publish("image.pull.progress",e.progress,{topic:"instances",scope:{instanceId:e.identity.instanceId}}),t&&(e.progress=Ph(e)))}}function Ph(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 Js.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 jh(e){const t=e.match(/([\d.]+)\s*([kmgt]?i?b)\s*\/\s*([\d.]+)\s*([kmgt]?i?b)/i);if(t)return{current:Dh(t[1],t[2]),total:Dh(t[3],t[4])}}function Dh(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 Mh{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 Lh=a.z.object({revision:a.z.number().int().nonnegative(),invites:a.z.array(Mn),bindings:a.z.array(Un)}).strict(),qh={invite:new Set(Object.keys(Mn.shape)),binding:new Set(Object.keys(Un.shape))};function $h(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 Bh(e,t,n){if(!t||"object"!=typeof t||Array.isArray(t))return t;const i=t,s=qh[e],r=Object.keys(i).filter(e=>!s.has(e));r.length>0&&n?.({kind:e,fields:r});const o=$h(i,s);return"binding"===e&&o.lastError&&(o.lastError=$h(o.lastError,Object.keys(jn.shape))),o}function Uh(e){const{tokenHash:t,...n}=e;return Ln.parse(n)}function Fh(e){const{credentialHash:t,...n}=e;return Fn.parse(n)}class Hh{authority;constructor(e,t){this.authority=new Xr(e,()=>({revision:0,invites:[],bindings:[]}),{schema:Lh,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=>Bh("invite",e,t)):n.invites,bindings:Array.isArray(n.bindings)?n.bindings.map(e=>Bh("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 Wh 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 Gh=e=>i.createHash("sha256").update(e).digest("base64url"),Vh=()=>i.randomBytes(32).toString("base64url");function Kh(e,t){const n=Gh(t),s=Buffer.from(e),r=Buffer.from(n);return s.length===r.length&&i.timingSafeEqual(s,r)}function Jh(e,t,n,i=!1,s={}){throw new Wh(e,t,n,i,s)}class Yh{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??Vh}init(){this.store.init(),this.expireInvites()}createInvite(e,t){const n=this.resolveProxyOrigin();n||Jh(Rn.Unavailable,"Configure an externally reachable HTTPS control-plane proxy origin before creating an invite.",409,!1);const i=qn.parse(e);this.requireManageableTarget(i.targetNodeId);const s=this.createTokenValue(),r=this.nowIso(),o={id:Jr("proxy_invite"),targetNodeId:i.targetNodeId,tokenHash:Gh(s),status:"active",createdBy:t,expiresAt:new Date(this.now().getTime()+1e3*i.expiresInSeconds).toISOString(),createdAt:r,updatedAt:r},a=$n.parse({invite:Uh(o),token:s,proxyOrigin:n,protocolVersion:bn});return this.store.transaction(e=>e.invites.push(o)),a}resolveProxyOrigin(){const e=this.configuredProxyOrigin??this.proxyOriginProvider?.();if(!e)return;const t=zn.safeParse(e);return t.success?t.data:void 0}listInvites(){return this.expireInvites(),this.store.listInvites().map(Uh)}revokeInvite(e){const t=this.requireInvite(e);if("consumed"===t.status&&Jh(Rn.InviteConsumed,"A consumed proxy invite cannot be revoked independently of its binding.",409,!1,{inviteId:e}),"revoked"===t.status||"expired"===t.status)return Uh(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}),Uh(i)}claimInvite(e){const t=Hn.parse(e);this.requireCurrentProtocol(t.protocolVersion),this.expireInvites();const n=Gh(t.credential);return this.store.transaction(e=>{const i=e.bindings.find(e=>e.claimId===t.claimId);if(!t.inviteToken)return i||Jh(Rn.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)&&Jh(Rn.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:t.claimId}),"revoked"===i.status&&Jh(Rn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:i.id}),this.claimResult(i,this.requireKnownTarget(i.targetNodeId));const s=e.invites.find(e=>Kh(e.tokenHash,t.inviteToken));s||Jh(Rn.InviteInvalid,"Proxy invite is invalid.",401),t.targetNodeId&&t.targetNodeId!==s.targetNodeId&&Jh(Rn.TargetMismatch,"Proxy invite is bound to a different target.",409,!1,{inviteId:s.id,targetNodeId:t.targetNodeId});const r=(o=s.id,`proxy_binding_${Gh(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&&Jh(Rn.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&&Jh(Rn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:c.id}),"consumed"===s.status&&s.consumedByClaimId===t.claimId||Jh(Rn.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(Fh)}authenticateBinding(e,t){const n=Wn.parse(t),i=this.store.getBinding(e);return i||Jh(Rn.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),"active"!==i.status&&Jh(Rn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:e}),i.sourceControlPlaneId===n.sourceControlPlaneId&&i.bindingKeyId===n.bindingKeyId&&Kh(i.credentialHash,n.credential)||Jh(Rn.AuthenticationFailed,"Proxy binding authentication failed.",401,!1,{bindingId:e}),Fh(i)}revokeBinding(e){const t=this.requireBinding(e);if("revoked"===t.status)return Fh(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}),Fh(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}),Fh(e))),invites:t.invites.filter(t=>t.targetNodeId===e&&"active"===t.status).map(e=>(Object.assign(e,{status:"revoked",revokedAt:n,updatedAt:n}),Uh(e)))}})}nowIso(){return this.now().toISOString()}requireCurrentProtocol(e){e!==bn&&Jh(Rn.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:e,supportedVersion:bn})}requireKnownTarget(e){const t=this.targets.get(e);return t||Jh(Rn.TargetUnavailable,"Proxy target no longer exists.",404,!1,{targetNodeId:e}),t}requireManageableTarget(e){const t=this.requireKnownTarget(e);return t.manageable&&"online"===t.status||Jh(Rn.TargetUnavailable,"Proxy target is not currently manageable.",503,!0,{targetNodeId:e}),t}requireInvite(e){const t=this.store.getInvite(e);return t||Jh(Rn.InviteInvalid,"Proxy invite is unknown.",404,!1,{inviteId:e}),t}requireBinding(e){const t=this.store.getBinding(e);return t||Jh(Rn.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),t}requireClaimableInvite(e){"active"!==e.status&&Jh({expired:Rn.InviteExpired,consumed:Rn.InviteConsumed,revoked:Rn.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||Jh(Rn.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:i.claimId})}claimResult(e,t){const{manageable:n,...i}=t;return Xn.parse({protocolVersion:bn,binding:Fh(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 Qh extends Error{statusCode=429;code=Rn.ResourceLimit;retryable=!0;details;constructor(e,t){super(e),this.name="NodeProxyRuntimeError",this.details=t}}class Xh{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:Rn.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+=Zh(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=Zh(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:Rn.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 Qh(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 Zh(e){return Buffer.isBuffer(e)||e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:Buffer.byteLength("string"==typeof e?e:String(e),"utf8")}class em{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:tm(t)}}subscribe(e,t,n,i=()=>{}){const{bindingId:s,sourceControlPlaneId:r,targetNodeId:o}=e,a=this.stream(o),d=tm(a);if(t>a.revision||t<d-1)return n(Yn.parse({type:"control-plane-proxy.snapshot-required",protocolVersion:bn,streamId:a.streamId,bindingId:s,sourceControlPlaneId:r,targetNodeId:o,sinceRevision:t,latestRevision:a.revision,earliestRetainedRevision:d,error:{code:Rn.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(Jn.parse({type:"control-plane-proxy.events.ready",protocolVersion:bn,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(nm(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:tm(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=Kn.safeParse({type:"control-plane-proxy.event",protocolVersion:bn,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=im(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=nm(d,e.bindingId,e.sourceControlPlaneId),n=im(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 tm(e){return e.history[0]?.event.revision??e.revision+1}function nm(e,t,n){return Kn.parse({...e,bindingId:t,sourceControlPlaneId:n})}function im(e){try{return Buffer.byteLength(JSON.stringify(e),"utf8")}catch{return}}function sm(e,t){const n=new WeakSet;let i=t,s=0;const r=e=>{if(i-=Buffer.byteLength(e,"utf8"),i<0)throw rm("Proxy target projection byte limit exceeded.",{resource:"target-projection-bytes",limit:t})},o=(e,t)=>{if(s+=1,s>16384||t>24)throw rm("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 rm("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 rm(e,t,n=!0){return Object.assign(new Error(e),{code:"CONTROL_PLANE_PROXY_RESOURCE_LIMIT",statusCode:429,retryable:n,...t?{details:t}:{}})}function om(e){const{manageable:t,...n}=e;return n}const am=a.z.object({bindingId:a.z.string().trim().min(1).max(160)}).passthrough(),dm=a.z.object({route:Cn}).strict(),cm=a.z.object({sinceRevision:a.z.coerce.number().int().nonnegative()}).strict(),lm=new Set(["connection","cookie","host","keep-alive","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),pm=524288;function um(e,t,n){const i=bm(n.headers,En);if(i!==bn)throw Im(Rn.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:i,supportedVersion:bn});const s=bm(n.headers,Nn),r=bm(n.headers,On),o=bm(n.headers,_n);if(!s||!r||!o)throw Im(Rn.AuthenticationFailed,"Proxy binding authentication headers are incomplete.",401);return e.authenticateBinding(t,{sourceControlPlaneId:s,bindingKeyId:r,credential:o})}function gm(e,t,n){const i=um(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 Im(Rn.BindingIdentityConflict,"Proxy binding changed while the request was being established.",409,!0,{bindingId:t.id,expectedRevision:t.revision,actualRevision:i.revision})}function hm(e,t){if(t.id!==e.targetNodeId)throw Im(Rn.TargetMismatch,"Proxy target resolver returned another node.",409,!1,{bindingId:e.id,targetNodeId:e.targetNodeId})}function mm(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 Im(Rn.HeaderInvalid,"Caller-supplied node transport authentication headers are forbidden.",400,!1,{header:e})}const t=Object.fromEntries([...xn].flatMap(t=>{if(lm.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=kn.safeParse(t["x-request-id"]);if(!e.success)throw Im(Rn.HeaderInvalid,"Proxy request correlation id is invalid.",400,!1,{header:"x-request-id"});t["x-request-id"]=e.data}return t}function ym(e,t,n){const i=fm(t),s=vm(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 fm(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)||Rn.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 Im(e,t,n,i=!1,s){return Object.assign(new Error(t),{code:e,statusCode:n,retryable:i,...s?{details:s}:{}})}function bm(e,t){const n=e[t];return Array.isArray(n)?n.join(","):"string"==typeof n?n:""}function vm(e){if(!e)return;const t=kn.safeParse(bm(e,"x-request-id"));return t.success?t.data:void 0}function wm(e){let t="";for(const n of e){if(Buffer.byteLength(t+n)>123)break;t+=n}return t}const Sm=e=>jn.parse({code:Rn.Unavailable,message:e,retryable:!0});class Am{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:td(n)});if(!this.current(e,t))return;const s=await i.json().catch(()=>{});if(!i.ok){const n=So(jn,s?.error),r=n.success?n.data:Sm(`Proxy snapshot failed with HTTP ${i.status}.`);return r.code===Rn.BindingRevoked?void this.onStateChanged(this.service.markProxyBindingRevoked(e,r)):void this.fail(e,t,r,r.retryable)}const r=Ao(Vn,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:Rn.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:km(n)},"control-plane proxy state bootstrap failed"),this.fail(e,t,Sm("Trusted control-plane proxy is unavailable."),!0)}else this.fail(e,t,Sm("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),td(n));s.socket=r;let o=!1;const a=n=>{o||(o=!0,this.fail(e,t,Sm(n),!0))};r.on("message",s=>{if(this.current(e,t))try{const r=Ao(Qn,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:km(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:Rn.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 km(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 zm=a.z.object({id:a.z.string().trim().min(1).max(160)}).strict(),Cm=a.z.object({}).strict(),xm=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 Tm(){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 Em(e){return`sha256:${i.createHash("sha256").update(Buffer.from(e,"base64url")).digest("base64url")}`}function Nm(e){return Array.isArray(e)?`[${e.map(Nm).join(",")}]`:e&&"object"==typeof e?`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${Nm(t)}`).join(",")}}`:JSON.stringify(e)}class Om{identity;controlPlaneId;constructor(e,t,n){this.controlPlaneId=t,this.identity=new Xr(e,Tm,{schema:xm,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=Lr.parse({version:1,kind:"control-plane",controlPlaneId:this.controlPlaneId(),publicKey:{algorithm:"Ed25519",encoding:"base64url",value:n.publicKey,fingerprint:Em(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(Lr.parse(a)))),this.privateKey()).toString("base64url");var a;return qr.parse({data:{payload:r,signature:o}})}publicIdentity(){const e=this.identity.get();return{controlPlaneId:this.controlPlaneId(),algorithm:e.algorithm,publicKey:e.publicKey,fingerprint:Em(e.publicKey)}}signCloudBindingChallenge(e){return i.sign(null,Buffer.from(`task-handoff:cloud-binding-challenge:v1\n${Nm(e)}`),this.privateKey()).toString("base64url")}signCloudOutboundRegistration(e){return i.sign(null,Buffer.from((t=e,`task-handoff:outbound-control-registration:v1\n${Lt(Jt.parse(t))}`)),this.privateKey()).toString("base64url");var t}acceptCloudAccessHandshake(e,t){return function(e){const t=Yt.parse(e.ticket),n=Zt.parse(e.clientHello);if(t.ticketId!==n.ticketId||t.deviceSessionId!==n.deviceSessionId||t.targetPublicKeyFingerprint!==e.controlPlaneFingerprint)throw en();const s=i.generateKeyPairSync("x25519"),r=function(e){const t=e.export({format:"jwk"}).x;if(!t)throw en();return t}(s.publicKey),o=function(e,t,n){return i.createHash("sha256").update(Lt({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 _m{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 Rm(e,n){const i=t.extname(e);return`${i?e.slice(0,-i.length):e}.${n}${i}`}const Pm=1048576,jm=52428800;function Dm(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:e}function Mm(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 Lm(e,i,s){const r=n.statSync(e),o=Math.min(r.size,Pm,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 qm=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 $m{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 Xr(e.statePath,()=>({version:1,serviceOrigin:this.serviceOrigin,status:"unbound",remoteAccessEnabled:!0,updatedAt:new Date(this.clock()).toISOString(),connectionEpoch:0}),{schema:qm,directoryMode:448,fileMode:384})}init(){if(this.state.init(),this.state.get().serviceOrigin!==this.serviceOrigin)throw Um("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 Um("active"===e.status?"CONTROL_PLANE_ALREADY_BOUND":"BINDING_STATE_CONFLICT","Existing cloud binding must be resolved first.");this.prune();const t=Jr("binding_challenge"),n=i.randomBytes(32).toString("base64url"),s=this.challengePayload(t);return this.challenges.set(t,{digest:Bm(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=Bm(s),o.length!==a.length||!i.timingSafeEqual(o,a)))throw Um("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 Um("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 Um("CONTROL_PLANE_ALREADY_BOUND","Control Plane is already bound to another account.")}if("pending-claim"!==t.status)throw Um("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 Bm(e){return i.createHash("sha256").update(e).digest()}function Um(e,t){return Object.assign(new Error(t),{code:e,statusCode:e.includes("CONFLICT")||e.includes("BOUND")?409:400})}class Fm{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 Hm{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 Wm{connection;processInstanceId=`control_plane_process_${i.randomUUID().replaceAll("-","_")}`;backoff;options;constructor(e){this.options=e,this.backoff=e.backoff??new Hm}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 Gm{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 Vm{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 Km{options;constructor(e){this.options=e}async connect(e){const t=e.allocation,n=Xt.parse(t.attach),i=Yt.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(Xm("RELAY_SOCKET_CLOSED")))})}(s),s.send(JSON.stringify({type:"attach",capability:n})),async function(e,t,n,i,s){const r=await Ym(e,e=>"frame"===e?.type&&"handshake"===e.frame?.kind);if(r.frame.channelId!==t||0!==r.frame.sequence)throw Xm("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 Jm(e,t,a.sessionKey,c,s);return l.start(),{close:(e="normal")=>l.close(e)}}(s,(await Ym(s,e=>"attached"===e?.type)).channelId,i,this.options.identity,this.options.bridge)}}class Jm{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 Xm("RELAY_FRAME_SEQUENCE_INVALID");const i=w.secretbox.open(Buffer.from(n.ciphertext,"base64url"),Qm(1,this.receiveCounter++),this.key);if(!i)throw Xm("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 Xm("RELAY_ENVELOPE_UNSUPPORTED")}send(e){if(this.socket.readyState!==l.OPEN||this.socket.bufferedAmount>2097152)throw Xm("RELAY_BACKPRESSURE_LIMIT");const t=w.secretbox(Buffer.from(JSON.stringify(e)),Qm(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 Ym(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(Xm("RELAY_SOCKET_CLOSED"))},o=()=>{e.off("message",s),e.off("close",r)};e.on("message",s),e.once("close",r)})}function Qm(e,t){const n=new Uint8Array(24);return n[0]=e,new DataView(n.buffer).setBigUint64(16,BigInt(t),!1),n}function Xm(e){return Object.assign(new Error("Cloud Relay session is invalid."),{code:e,retryable:!0})}class Zm{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(ty("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(ty("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 ty("CLOUD_CONTROL_CONNECTION_UNAVAILABLE");return this.current.request(e,t)}}class ey{lifecycle;dataConnections;connector;control;events;timer;running=!1;connecting;options;constructor(e){this.options=e,this.connector=new Zm({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 Km({identity:e.identity,bridge:e.relayBridge,webSocket:e.webSocket}):{async connect(){throw ty("CLOUD_RELAY_CONNECTOR_UNAVAILABLE")}});this.dataConnections=new Gm({verifyAllocation:e.verifyAllocation??(t=>function(e,t){const n=e,i=Xt.parse(n?.attach),s=Yt.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 Xm("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 Xm("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 Fm({state:e.state,connections:{stop:e=>this.control.stop(e)},dataConnections:this.dataConnections}),this.control=new Wm({state:e.state,connector:this.connector,onEvent:async e=>{await this.events.apply(e)}}),this.lifecycle=new Vm({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 ty("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 ty("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 ty(e){return Object.assign(new Error("Cloud background connection is unavailable."),{code:e,retryable:!0})}const ny="x-task-handoff-cloud-internal-actor",iy=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(),sy=a.z.object({error:iy}).strict(),ry="https://cloud.thandoff.com";function oy(e,t={}){const n=new URL(e||ry).origin;if(n===ry)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 ay(e){const t=process.env[e]?.trim();return t||void 0}const dy=function(e,t=process.env,n=e){let i;return()=>{const s=t.TASK_HANDOFF_VERSION?.trim();return s||(i||=C(e,t,n),i)}}("@task-handoff/control-plane");function cy(){return{component:"control-plane",packageName:"@task-handoff/control-plane",packageVersion:dy(),protocolVersion:ti,buildId:ay("TASK_HANDOFF_BUILD_ID"),builtAt:ay("TASK_HANDOFF_BUILT_AT"),gitCommit:ay("TASK_HANDOFF_GIT_COMMIT"),imageRef:ay("TASK_HANDOFF_IMAGE_REF"),imageDigest:ay("TASK_HANDOFF_IMAGE_DIGEST")}}const ly={".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 py(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 uy(e,i,s){const r=py(i,s);return r?(e.header("cache-control","no-store"),e.type(ly[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 hy(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[eo],clientType:"web"}}async function my(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 yy=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 fy(e,t){const n=t.split("?")[0]||"/";if(!n.startsWith("/api/"))return;if(yy.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 Iy(e={}){const d=lg(e.dataDir),c=s({logger:e.logger??!0}),l=new ju,p=e.cloudConnectivityEnabled??"0"!==process.env.TASK_HANDOFF_CLOUD_CONNECTIVITY_ENABLED;let u=(h=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(h||"").trim().toLowerCase()));var h;const m=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(Rm(e,t),{force:!0});for(let i=t-1;i>=1;i-=1){const t=Rm(e,i);n.existsSync(t)&&n.renameSync(t,Rm(e,i+1))}}}(e,r),r>0?t.size>s?(n.writeFileSync(Rm(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,Rm(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:Dm(a)},(e,t)=>Dm(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 _m;f.onChange(e=>l.publish("node.connection.updated",e,{topic:"node.state",scope:{nodeId:e.nodeId}}));const I=new Nl(d,{...e.service,logger:m,nodeConnectionRuntime:f}),b=new wo(d,e.auth),v=new Om(d.identitySigningPath,()=>I.proxyPrivateStore.controlPlaneId(),(e,t)=>c.log.warn(t,e)),w=new $m({statePath:d.cloudConnectivityPath,identity:v,serviceOrigin:oy(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 ey({state:w,identity:v,relayBridge:{async request(e,t){const n=String(t?.method||"GET").toUpperCase(),s=String(t?.path||""),r=fy(n,s);if(!s.startsWith("/api/")||!r||yy.has(s.split("?")[0]))throw Object.assign(new Error("Cloud access route is not available."),{code:"CLOUD_ROUTE_FORBIDDEN",statusCode:403});_g(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",ny].includes(e.toLowerCase())).map(([e,t])=>[e,String(t)])),i=await c.inject({method:n,url:s,headers:{...e,[ny]: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(_g(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=it.parse(t);n(Kt.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,C=e.publishCloudBindingChallenge??(e=>k.publishBindingChallenge(e)),x=new Rh(l),T=new xh(d,{onChanged:e=>queueMicrotask(()=>l.publish(P,e,{topic:"ai.sessions",scope:{instanceId:e.instanceId,sessionId:e.sessionId}}))});T.init();const E=new zh({bootstrap:()=>I.bootstrapAiSessionsFromInstances(),logger:m,recoverDelta:(e,t,n)=>I.recoverAiSessionDelta(e,t,n),recoverSnapshot:e=>I.recoverAiSessionSnapshot(e),onRecoveredEvent:e=>l.publish(e.type,e.payload)});E.onSnapshot(e=>T.reconcile(e.instanceId,e.aiSessions));const N=new Oh({bootstrap:()=>I.bootstrapAppSessionsFromInstances(),logger:m,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=>E.list(e)),l.on(e=>{if(x.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),E.removeInstance(t),T.removeInstance(t))}});const O=new Bu;c.addHook("onClose",async()=>{O.dispose()});const _=new dg(l,{connectionRuntime:f,validateInstanceScope:(e,t)=>I.nodeOwnsInstance(e,t),onStreamsHello:(e,t)=>{for(const n of t.streams)"ai.sessions"===n.topic&&E.advertiseStream(e,n),"app.sessions"===n.topic&&N.advertiseStream(e,n)},onSessionEvent:e=>e.type.startsWith("app-session.")?N.handleEvent(e):E.handleEvent(e)}),R=e.proxyOrigin||process.env.TASK_HANDOFF_CONTROL_PLANE_PROXY_ORIGIN,j=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:sm(e.capabilities||{},262144),manageable:!1!==e.connectionEnabled&&(n||"online"===i)}}(t,_.connected(t.id)):void 0},D=new Yh(new Hh(d.proxyAuthorityPath,(e,t)=>c.log.warn(t,e)),{get:j},{proxyOrigin:R,proxyOriginProvider:()=>I.getSettings().publicBaseUrl}),M=new Xh,L=new em(l,{projectTarget:e=>{const t=j(e);return t?om(t):void 0}}),q=new Am(I,{fetchImpl:e.service?.fetchImpl,logger:m,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 su(I,e.service?.fetchImpl,{aiSessions:E,logger:m,diagnosticLogsEnabled:()=>u});H.startEnabled();const W=new cg(I,_,{safetyIntervalMs:Number(process.env.TASK_HANDOFF_EVENT_CONNECTION_SAFETY_INTERVAL_MS)||void 0,logger:m,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(()=>{})),x.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(sy.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[ny],o="string"==typeof r?S.get(r):void 0;if(o){S.delete(r);const t=fy(e.method,i);if(!t)throw Object.assign(new Error("Cloud access route is not authorized."),{code:"CLOUD_ROUTE_FORBIDDEN",statusCode:403});return void _g(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 my(b,hy(e)),n=fy(e.method,i);return void(n&&_g(t||{type:"system",reason:"auth-disabled"},n.action,n.resource))}const d=await my(b,hy(e));if(!d)return t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to access the Control Plane."}});const c=fy(e.method,i);c&&_g(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:Uu},async(e,n)=>{const i=e.params["*"];return uy(n,G,t.join("assets",i||""))}),c.get("/favicon.ico",{config:Uu},async(e,t)=>py(G,"favicon.ico")?uy(t,G,"favicon.ico"):t.code(204).send())),c.get("/api/health",{config:Uu},async()=>Zi.parse({data:{ok:!0,role:"control-plane",protocolVersion:ti,build:cy(),dataDir:d.dataDir,serverTime:(new Date).toISOString()}})),c.get("/api/control-plane/identity",{config:Uu},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});_g(await my(b,hy(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 C(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:E.diagnostics(),aiSessionActions:I.aiSessionActionDiagnostics(),appSessions:N.diagnostics(),nodeConnections:{...W.diagnostics(),runtime:f.diagnostics()}}})),c.get("/install-node-agent.sh",{config:Uu},async(e,t)=>(t.header("cache-control","no-store"),t.type("text/x-shellscript; charset=utf-8"),_h`#!/bin/sh
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.enum(["connecting","handshaking","healthy","reconnecting","suspect","offline"]),_d=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 Rd=a.z.object({code:a.z.string().trim().min(1).max(120),message:a.z.string().trim().min(1).max(2048)}).strict(),Pd=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:Od.optional(),lastSeenAt:Nd.optional(),observedAt:Nd,capabilities:a.z.array(a.z.string().trim().min(1).max(120)).max(256),error:Rd.optional()}).strict();a.z.array(Pd);const jd=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(),Dd=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(),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(_d).max(4).default([]),availableApps:a.z.array(jd).max(256).default([]),availableAgents:a.z.array(jd).max(256),error:Rd.optional()}).strict();function Md(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 Ld(e){const{agent:t,...n}=e.capabilities,{secret:i,...s}=e.auth,r=s.pairing?{...s.pairing,joinToken:void 0}:void 0,o=Md(t);return{...e,auth:r?{...s,pairing:r}:s,capabilities:o?{...n,agent:o}:n}}function qd(e){return"local-folder"===e.type?{mode:"local-bind",path:"/workspace",readOnly:!1}:{mode:"git-clone",path:"/workspace",readOnly:!1}}function $d(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 Bd(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 Ud(){return(new Date).toISOString()}function Fd(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 Hd(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 Wd(e){return e instanceof Error?e.message:String(e)}function Gd(e,t){const n=new Error(t);throw Object.assign(n,{statusCode:404,code:e}),n}a.z.array(Dd);const Vd=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(),Kd=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 Jd{claimOperations=new Map;options;constructor(e){this.options=e}listPendingClaims(){return this.options.privateStore.publicPendingClaims()}async claimNode(e){const t=Vd.parse(e),n=Ud(),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||Gd("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=Ud();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=Ud();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:Ud()},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:Ud(),target:s.target,updatedAt:Ud()},labels:{},lastSeenAt:s.target.lastSeenAt,createdAt:Ud(),updatedAt:Ud()});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:Ld(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=Ud();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(Kd,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:Ud()}}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 Yd=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(),Qd=Yd.omit({id:!0}).partial().strict();function Xd(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"/"!==e&&"\\"!==e}const Zd=a.z.string().refine(Xd,"Mention trigger must be one printable non-alphanumeric character other than / or \\.");function ec(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"\\"!==e}const tc=a.z.string().refine(ec,"Command trigger must be one printable non-alphanumeric character other than \\."),nc=a.z.object({publicBaseUrl:a.z.string().trim().max(2048).optional(),updateChannel:Is.default("stable"),mentionTrigger:Zd.default("@"),commandTrigger:tc.default("/"),diagnosticLogs:a.z.boolean().default(!1)}).strict().refine(e=>e.mentionTrigger!==e.commandTrigger,{path:["commandTrigger"],message:"Command and mention triggers must be different."}),ic=a.z.object({publicBaseUrl:a.z.string().trim().max(2048).optional(),updateChannel:Is.optional(),mentionTrigger:Zd.optional(),commandTrigger:tc.optional(),diagnosticLogs:a.z.boolean().optional()}).strict(),sc=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(),rc=sc.omit({id:!0}).partial().strict(),oc=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(),ac=oc.extend({channel:Hr.shape.channel,name:Hr.shape.name.optional()}),dc=fn.extend({id:fn.shape.configHash}),cc=a.z.object({name:fn.shape.name,description:fn.shape.description,source:gn,action:hn,policy:yn.partial().optional()}).strict(),lc=cc,pc=a.z.object({instanceIds:a.z.array(Mr.shape.id).min(1),target:In,enabled:a.z.boolean().optional()}).strict(),uc=a.z.object({configHash:fn.shape.configHash,enabled:a.z.boolean().optional()}).strict(),mc=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(),gc=a.z.object({autoImportAgentConfigs:a.z.boolean().optional(),defaultCodexPermissionMode:de.optional(),aiSessionHistoryLimit:a.z.number().int().min(1).max(Ve).optional()}).strict(),hc=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:gc.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."})}),yc=a.z.object({name:Mr.shape.name.optional(),config:gc.optional(),modelSelection:Mr.shape.modelSelection.optional()}).strict(),fc=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(),Ic=fc.partial().strict(),bc=a.z.object({endpoint:Ds.shape.endpoint,key:Ds.shape.key.optional(),existingModelId:Ds.shape.id.optional()}).strict(),vc=bc.extend({model:Ds.shape.model,app:Ds.shape.app}).strict(),wc=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:mc.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(),Sc=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:mc.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(),Ac=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(),kc=a.z.object({nodeName:a.z.string().trim().min(1).max(160).optional(),expiresInMs:a.z.number().int().positive().max(36e5).optional()}).strict(),zc=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 Tc{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:Ud(),updatedAt:Ud()}),r=await this.inspect(n,s),o=Ud(),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:Md(r.data)},labels:{...a?.labels||{},...e},createdAt:a?.createdAt||o,updatedAt:o}))}async create(e){const t=wc.parse(e),n=Ud(),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 Ec("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 Ec("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 Ec("Remote node connections require a paired node secret or join token.","NODE_AGENT_REMOTE_SECRET_REQUIRED");if(r&&!s.keyId)throw Ec("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 Ec("Node id is required.","NODE_ID_REQUIRED");if(a&&t.id&&t.id!==a.nodeId)throw Ec(`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 Ec(`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:Md(m.data)}:{}},labels:t.labels||{},createdAt:n,updatedAt:n});if(a&&(l=f,p=a.secret,_c(Ld(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 Rc(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),Rc(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=Ud();return zc.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?Nc(t.nodeId,t.secret):void 0,keyId:t?Nc(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(Oc({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(Oc({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(Oc({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(Oc({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:Ud(),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:xc(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:Nc(t.nodeId,t.secret),keyId:Nc(t.keyId,t.secret),originalErrorCode:Cc(n,t.secret)},"node agent pairing revoked after node creation failed")}catch{}}catch(e){const i={nodeId:Nc(t.nodeId,t.secret),keyId:Nc(t.keyId,t.secret),originalErrorCode:Cc(n,t.secret),compensationErrorCode:Cc(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 Ec(e,t){return Object.assign(new Error(e),{statusCode:400,code:t})}function Cc(e,t){return xc(e&&"object"==typeof e&&"code"in e?e.code:void 0,t,"UNKNOWN_ERROR")}function xc(e,t,n){return"string"!=typeof e||!/^[A-Z][A-Z0-9_]{0,127}$/.test(e)||e.includes(t)?n:e}function Nc(e,t){return e.includes(t)?"[redacted]":e}function Oc(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 _c(e,t){return"string"==typeof e?e.includes(t):Array.isArray(e)?e.some(e=>_c(e,t)):!(!e||"object"!=typeof e)&&Object.entries(e).some(([e,n])=>e.includes(t)||_c(n,t))}function Rc(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:Cc(e,t)});return e&&"object"==typeof e&&"retryable"in e&&"boolean"==typeof e.retryable&&Object.assign(s,{retryable:e.retryable}),s}class Pc{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 jc=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 Dc{options;invites=new Pc;constructor(e){this.options=e}createInvite(e={}){const t=kc.parse(e&&"object"==typeof e?e:{}),n=yo(),i={id:ho("node_join"),tokenHash:Mc(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=jc.parse(e),n=Mc(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=Ud();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 Mc(e){return i.createHash("sha256").update(e).digest("hex")}function Lc(e,t){const n=qc(e);return n.pathname=`${n.pathname.replace(/\/+$/,"")}/${t.replace(/^\/+/,"")}`,n.search="",n.hash="",n.toString()}function qc(e){let t;try{t=new URL(e.trim())}catch{throw Fc("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 Fc("MODEL_ENDPOINT_INVALID","The model endpoint must be an HTTP or HTTPS URL without embedded credentials.",400);return t}async function $c(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 Fc(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 Bc(e,t){const n=await e.text();if(n.length>1e6)throw Fc(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 Fc(t,"The model endpoint returned invalid JSON.",502)}}function Uc(e,t){return Fc(e,401===t||403===t?"The model endpoint rejected the API key.":"The model endpoint rejected the request.",502,t)}function Fc(e,t,n,i){return Object.assign(new Error(t),{code:e,statusCode:n,...i?{details:{upstreamStatus:i}}:{}})}function Hc(e,t){e.includes(t)||e.push(t)}function Wc(e){const t=new Set;return e.filter(e=>!t.has(e.id)&&(t.add(e.id),!0))}class Gc{options;constructor(e){this.options=e}list(){return this.listAll().map(Bd)}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:Bd(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:Ud()})}create(e){const t=fc.parse(e),n=Ud(),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 Bd(this.options.models.put(r))}update(e,t){const n=Ic.parse(t),i=this.requireSecret(e),s=Ds.parse({...i,...n,key:n.key?.trim()?n.key:i.key,createdAt:i.createdAt,updatedAt:Ud()}),r=Hs(s);return Bd(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)||Gd("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:Ud()}))}),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=bc.parse(e);return async function(e,t){const n=function(e){const t=qc(e),n=[],i=t.pathname.split("/").filter(Boolean).at(-1)||"";return Hc(n,Lc(t.toString(),/^v\d+$/.test(i)?"models":"v1/models")),Hc(n,new URL("/v1/models",t.origin).toString()),Hc(n,new URL("/models",t.origin).toString()),n}(t.endpoint),i=Date.now();let s;for(const r of n){const n=await $c(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 Uc("MODEL_DISCOVERY_FAILED",n.status);const o=await Bc(n,"MODEL_DISCOVERY_RESPONSE_INVALID"),a=Array.isArray(o.data)?o.data:void 0;if(!a)throw Fc("MODEL_DISCOVERY_RESPONSE_INVALID","The model endpoint returned an invalid model list.",502);return{models:Wc(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 Fc("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=vc.parse(e);return async function(e,t){const n=Date.now(),i="codex"===t.app?await $c(e,Lc(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 $c(e,function(e){const t=qc(e),n=t.pathname.split("/").filter(Boolean).at(-1)||"";return Lc(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 Uc("MODEL_TEST_FAILED",i.status);if((await Bc(i,"MODEL_TEST_RESPONSE_INVALID")).error)throw Fc("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 Vc(n),this.options.gateway.discoverModels(n,t)}testOnNode(e,t){const n=this.options.requireNode(e);return Vc(n),this.options.gateway.testModel(n,t)}require(e,t=!1){const n=this.requireSecret(e);return t?n:Bd(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 Kc(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||Gd("MODEL_NOT_FOUND",`Model ${i} was not found on control-plane or node ${e.id}.`),Kc(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||Gd("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 Vc(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 Kc(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 Jc{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}Yc(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:Fd(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}Yc(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:Fd(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}Yc(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 Yc(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 Qc{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=$d(e.instance);return{...i,aiSessions:nt(i.aiSessions),connectionStatus:n,heartbeatAgeMs:t,project:e.project,image:e.image,node:e.node?Ld(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 Xc{options;constructor(e){this.options=e}async create(e){const t=hc.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 el("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 el(`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 el(`Environment template ${p.id} is ${p.status}.`,409,"ENVIRONMENT_TEMPLATE_NOT_READY");if(p&&p.nodeId!==r.id)throw el(`Environment template ${p.id} belongs to node ${p.nodeId}.`,409,"ENVIRONMENT_TEMPLATE_NODE_MISMATCH");if(a&&!l&&!p)throw el(`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=Ud();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:Zc(e,"INSTANCE_START_FAILED")},y=await this.options.gateway.listInstances(r).then(e=>e.find(e=>e.id===y.id)||y).catch(()=>y)}return{...$d(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 el("Instance source is required.",400,"INSTANCE_SOURCE_REQUIRED");if("local"===e.runtime.type&&"local-folder"!==t.type)throw el("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 el(`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 Zc(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 el(e,t,n){return Object.assign(new Error(e),{statusCode:t,code:n})}class tl{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:nl(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=cc.parse(e||{}),n=Ud(),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=dc.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=lc.parse(t||{}),s=Ud(),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=dc.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?il(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||Gd("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),{configHash:e,deletedTemplate:t,results:i}}async applyTrigger(e,t){const n=this.requireTrigger(e),i=pc.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=uc.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:il(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=il(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||Gd("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),t}}function nl(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 il(e,t){return`ai_${Buffer.from(e).toString("base64url")}_${t}`}class sl{options;constructor(e){this.options=e}getSettings(){return nc.parse(this.options.settings.get())}updateSettings(e){const t=ic.parse(e),n=nc.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=Yd.parse(e),n=Ud(),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||qd(i)),labels:t.labels||{},createdAt:n,updatedAt:n}))}updateProject(e,t){const n=Qd.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:Ud()}))}deleteProject(e){return this.options.projects.delete(e)}requireProject(e){const t=this.getProject(e);return t||Gd("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||Gd("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=sc.parse(e),n=Ud(),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=rc.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:Ud()}))}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||Gd("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 rl(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 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 tr.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 al{async loadCatalog(){return ol()}}class dl{snapshot;status;constructor(e=ol()){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 cl{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 ll{requireInstance;listAppSessions;tokens=new cl({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:pl(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=>ml(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 pl(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):ml(ul(n.vnc).noVncPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`:ml(ul(n.web).webPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`}function ul(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function ml(e){return"string"==typeof e&&e.trim()?e.trim():void 0}const gl={allow:"a",deny:"d",skip:"s"};function hl(e){return i.createHash("sha256").update(e).digest("base64url").slice(0,Math.ceil(16))}class yl{tokens=new cl({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:${gl[t]}:${hl(e)}`}}function fl(e){const{token:t,...n}=e;return{...n,settings:bl(e.settings),tokenSet:Boolean(e.token)}}function Il(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 bl(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 vl{chatBridges;chatSessions;constructor(e){this.chatBridges=e.chatBridges,this.chatSessions=e.chatSessions}list(){return this.chatBridges.list().map(fl)}require(e){const t=this.chatBridges.get(e);return t||Gd("CHAT_BRIDGE_NOT_FOUND",`Chat bridge ${e} was not found.`),t}create(e){const t=ac.parse(e),n=Ud(),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:Il({},t.settings),createdAt:n,updatedAt:n});var s,r;return this.chatBridges.put(i),fl(i)}update(e,t){const n=oc.parse(t),i=this.require(e),s=Il(i.settings,n.settings),r=Hr.parse({...i,...n,id:e,channel:i.channel,name:n.name||i.name,settings:s,updatedAt:Ud()});return this.chatBridges.put(r),fl(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 wl{chatSessions;constructor(e){this.chatSessions=e.chatSessions}list(){return this.chatSessions.list()}require(e){const t=this.chatSessions.get(e);return t||Gd("CHAT_SESSION_NOT_FOUND",`Chat session ${e} was not found.`),t}upsert(e){const t=Ud(),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 Sl(e){return{inline_keyboard:e.map(e=>e.map(e=>({text:e.text,...e.url?{url:e.url}:{callback_data:e.callbackData||""}})))}}function Al(e,t=40){return Sl(e.slice(0,t).map(e=>[e]))}function kl(e){return Buffer.from(e,"utf8").toString("base64url")}function zl(e){const t=El(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=El(t),n=String(e.callback_data||""),s=String(e.text||"").trim();s&&n&&i.push({text:s,id:`th_cb_${kl(n)}`})}return i.slice(0,40)}function Tl(e,t){const n=String(e||"").replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-3))}...`}function El(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Cl(e){return(e.aiSessions?.sessions||[]).filter(t=>function(e,t){const n=(e.apps?.sessions||[]).filter(Pl);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 xl(e){return"waiting"===e.status?4:"failed"===e.status?3:"running"===e.status?2:"idle"===e.status?1:0}function Nl(e){return[e.cwd||"",e.agent||"",e.providerSessionId||e.id].join("\0")}function Ol(e){const t=e.session.title||e.session.userPrompt||e.session.summary||e.session.lastMessage||"",n=t?` - ${Tl(t,18)}`:"";return`${e.instance.name} - ${e.session.agent} ${e.session.status}${n}`}function _l(e,t=(e,t)=>`task_handoff:approval:${e.id}:${t}`){return Al(e.flatMap(e=>"approval"!==e.kind?[]:[{text:Tl(`Allow ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"allow")},{text:Tl(`Skip ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"skip")},{text:Tl(`Deny ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"deny")}]))}function Rl(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 Pl(e){const t=e&&"object"==typeof e&&!Array.isArray(e)?e:{};return jt("string"==typeof t.status?t.status:void 0)}class jl{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?Al(t.map(e=>({text:`${e.active?"✓ ":""}${Ol(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:$d(t),aiSession:n,reply:`Interrupt sent to ${t.name} / ${e.activeAiSessionId}.`}}}function Dl(e){return e.providerTurnId||e.turnId||""}function Ml(e){return jt(Bl(e.status))}function Ll(e,t){const n=Bl(t.appId)||"App",i=Bl(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 ql(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=Ul(e);t&&!n.has(t.id)&&n.set(t.id,t)}return[...n.values()]}function $l(e,t,n,i){const s=Bl(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=Bl(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 Bl(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function Ul(e){if("string"==typeof e&&e.trim())return{id:e,label:Fl(e)};const t=function(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}(e),n=Bl(t.id).trim();return n?{id:n,label:Bl(t.name).trim()||Fl(n)}:void 0}function Fl(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 Hl{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?Al(t.map(e=>{return{text:Tl(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=ql(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?Al(i.map(e=>{return{text:Tl(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=ql(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(Ml).filter(e=>Boolean(Bl(e.id))).map(e=>({instance:t,session:e,link:$l(t,e,this.deps.controlPlanePublicBaseUrl(),n=>this.deps.createAppAccessToken({instanceId:t.id,sessionId:Bl(e.id)||"",mode:n}).token)})):[]}),s=i.filter(e=>e.link.url).map(e=>({text:Tl(`${e.instance.name} · ${Ll(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?Al(s):void 0};var r,o}}class Wl{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:$d(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}: ${Wd(t)}`}}}failedSendResult(e,t,n,i){return{accepted:!1,routed:!1,binding:e,project:t||void 0,instance:$d(n),reply:i}}sentResult(e,t,n,i,s){return{accepted:!0,routed:!0,binding:e,project:t||void 0,instance:$d(n),aiSession:s,instanceId:n.id,aiSessionId:i,turnId:(r=s,r.turnId||r.providerTurnId||r.session.activeTurnId||""),providerTurnId:Dl(s),reply:`Sent to ${t?.name||n.sourceSnapshot.name||"Source"} / ${n.name} / ${i}.`};var r}}class Gl{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(Rl).join("\n"):"No pending routes.",replyMarkup:n.length?_l(n,(e,t)=>this.deps.pendingDecisionCallbackData(e.id,t)):void 0}}async handlePendingDecisionCommand(e,t,n){const i=Hd(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=Hd(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 Vl{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 Kl{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?Cl({...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=>Cl(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=xl(t.session)-xl(e.session);return n||(String(e.instance.name||"").localeCompare(String(t.instance.name||""))||e.instance.id.localeCompare(t.instance.id)||Nl(e.session).localeCompare(Nl(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||Gd("PROJECT_NOT_FOUND",`Project ${e} was not found.`),t}async resolveInstance(e,t){const n=await this.findInstance(e,t);return n||Gd("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 Jl{deps;targets;sender;appCommands;pendingCommands;aiSessionCommands;targetCommands;constructor(e){this.deps=e,this.targets=new Kl(e),this.sender=new Wl(e,this.targets),this.appCommands=new Hl(e,this.targets),this.pendingCommands=new Gl(e),this.aiSessionCommands=new jl(e,this.targets),this.targetCommands=new Vl(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 Yl=a.z.object({id:a.z.string().trim().min(1),preferences:Yo,createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict();function Ql(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 Xl(){return Yo.parse({})}function Zl(e){return/^[a-z]:[\\/]/i.test(e)||/^[\\/]{2}[^\\/]+[\\/]+[^\\/]+/.test(e)}function ep(e){return Zl(e)?t.win32:t.posix}class tp{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 np="task-handoff.control-plane.local",ip="task-handoff.control-plane.builtin";function sp(e){return"true"===e.labels[np]}function rp(e){return"true"===e.labels[ip]}class op{projects;models;modelService;images;nodes;pendingPairingRevokes;chatSessions;chatBridges;triggers;nodeJoinService;configSyncPreferences;settings;paths;fetchImpl;dockerCommandRunner;logger;diagnosticLogsState;nodeConnectionRuntime;appAccessService;persistenceMaintenance;chatActionTokenService=new yl;nodeAgentTransportResolver;proxyPrivateStore;proxyLifecycle;nodeConnectionManager;nodeAgentGateway;controlledInstanceGateway;aiSessionActionService;controlledInstanceCreator;instanceBoardReader=new Qc;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 tp(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,()=>nc.parse({diagnosticLogs:s}),{...i(nc),sanitize:e=>function(e,t={}){if(!e||"object"!=typeof e||Array.isArray(e))return{};const n={...e};return"string"==typeof n.mentionTrigger&&Xd(n.mentionTrigger)||(n.mentionTrigger="@"),"string"==typeof n.commandTrigger&&ec(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 Jc({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 Gc({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(zc)),this.proxyLifecycle=new Jd({nodes:this.nodes,privateStore:this.proxyPrivateStore,fetchImpl:this.fetchImpl,requireNode:e=>this.requireNode(e),deleteNode:e=>this.deleteNode(e)}),this.nodeConnectionManager=new Tc({nodes:this.nodes,pendingPairingRevokes:this.pendingPairingRevokes,fetchImpl:this.fetchImpl,localNodeLabel:np,builtinNodeLabel:ip,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(dc)),this.nodeJoinService=new Dc({nodes:this.nodes}),this.configSyncPreferences=new fo(t.join(e.dataDir,"config-sync-preferences"),{...i(Yl),sanitize:Ql}),this.marketCatalogService=new dl,this.catalogService=new sl({projects:this.projects,images:this.images,market:this.marketCatalogService,settings:this.settings,defaultNodeId:()=>this.defaultNodeId()}),this.controlledInstanceCreator=new Xc({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 tl({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 ll({requireInstance:async e=>this.requireControlledInstance(e,!0),listAppSessions:()=>this.listAppSessions()}),this.chatBridgeService=new vl({chatBridges:this.chatBridges,chatSessions:this.chatSessions}),this.chatSessionService=new wl({chatSessions:this.chatSessions}),this.chatSessionRuntime=new Jl({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:Wd(e)}),void this.logWarn({legacyId:t,error:Wd(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:Wd(t)}),void this.logWarn({filePath:e,error:Wd(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:Ud(),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:Ud(),...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(sp)?.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 al),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:Md(e)}:t.capabilities,lastSeenAt:Ud(),updatedAt:Ud()});return i!==t.id&&this.nodes.delete(t.id),this.nodes.put(s),this.nodeConnectionRuntime?.observedReachable(s),{id:s.id,status:"online",checkedAt:Ud(),agent:e}}catch(e){const n=fr.parse({...t,status:"offline",health:"failed",updatedAt:Ud()});return this.nodes.put(n),this.nodeConnectionRuntime?.observedFailure(n,Wd(e)),{id:t.id,status:"offline",checkedAt:Ud(),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)||!sp(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=Ac.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=>Ld(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=Sc.parse(t),i=this.requireNode(e);this.proxyLifecycle.assertIdentityPatch(i,n);const s=fr.parse({...i,...n,id:e,createdAt:i.createdAt,updatedAt:Ud()});return this.nodes.put(s)}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.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($d)}async listControlledInstancesWithDiagnostics(){const e=await this.listNodeInstancesWithDiagnostics();return{items:e.items.map($d),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=yc.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 $d(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),$d(await this.nodeAgentGateway.startInstance(n,e))}async stopControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return $d(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),$d(await this.nodeAgentGateway.restartInstance(n,e))}async retryControlledInstanceImageProvisioning(e){const t=await this.requireNodeInstance(e);return $d(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:Wd(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:Wd(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=Ud(),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:$d(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||qd(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||Xl()})}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=Ud(),d=this.configSyncPreferences.get(e);return this.configSyncPreferences.put({id:e,preferences:{...d?.preferences||Xl(),[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,Wd(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{}Gd("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||Gd("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 ep(s=n).resolve(s);var s;if("local-folder"!==e.source.type)return;const r=function(e,t){if(Zl(e)!==Zl(t))return;const n=ep(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||qd(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||Gd("NODE_NOT_FOUND",`Node ${e} was not found.`),t}requirePublicNode(e){return Ld(this.projectNodeConnection(this.requireNode(e)))}async requireControlledInstance(e,t=!1){const n=await this.requireNodeInstance(e);return t?n:$d(n)}}function ap(e){return g(String(e),"escape").replace(/\n+$/,"")}function dp(e){const[t,...n]=String(e).split("\n");return[`*${ap(t)}*`,...n.map(ap)].join("\n")}function cp(e,t=4e3){const n=String(e),i=dp(n);if(i.length<=t)return i;const[s,...r]=n.split("\n"),o=r.join("\n"),a="...\n";let d=s;for(;dp(`${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=dp(`${d}\n${a}`);for(;c<=l;){const e=Math.floor((c+l)/2),n=dp(`${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=dp(`${d}\n${a}${m.slice(g+1)}`)),u}function lp(e){return String(e).replace(/\\([_*\[\]()~`>#+\-=|{}.!\\])/g,"$1")}async function pp(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:ap;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 mp(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 up(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 mp(e,t,n,i,s){const r=s.parseMode||"MarkdownV2",o=s.rawMarkdownV2?String(n):ap(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&&gp(d.description))return;if(s.rawMarkdownV2&&"MarkdownV2"===r){const s=await e({...i,text:lp(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&&gp(r.description))return}const c=await e({...i,text:s.rawMarkdownV2?lp(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||!gp(l.description))throw new Error(l.description||d.description||`Telegram ${t} failed with HTTP ${c.status}`)}function gp(e){return"string"==typeof e&&e.toLowerCase().includes("message is not modified")}function hp(e,t){if("string"==typeof e&&e.trim())return e.trim();fp(`Chat action token is missing ${t}.`)}function yp(e){if("allow"===e||"deny"===e||"skip"===e)return e;fp("Chat action token has an invalid decision.")}function fp(e){const t=new Error(e);throw Object.assign(t,{statusCode:400,code:"CHAT_ACTION_TOKEN_INVALID"}),t}function Ip(e){return Buffer.from(e,"base64url").toString("utf8")}function bp(e){return String(e||"").split(/\r?\n/,1)[0].replace(/^#+\s*/,"").trim().slice(0,20)||"消息通知"}function vp(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,"string"==typeof t?t:JSON.stringify(t)]))}function wp(e){return`dtv1.card//IM_GROUP.${e}`}function Sp(e){return`dtv1.card//IM_ROBOT.${e}`}function Ap(e,t){return Lp(t.biz_conversation_id).trim()||Lp(e.spaceId).replace(/^dtv1\.card\/\/(?:IM_GROUP|IM_SINGLE|IM_ROBOT)\./,"")}function kp(e,t={}){const n=Lp(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 zp(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 Tp(e,t,n,i,s){const r=Ap(i,s);return{cardUpdateOptions:{updateCardDataByKey:!0,updatePrivateDataByKey:!1},cardData:{cardParamMap:vp({type:"actions",title:"TaskHandoff",description:e,list:zl(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 Ep(e,t,n){const i=[];return Cp(i,n),Cp(i,t),Cp(i,e),i.find(e=>zp(e))||""}function Cp(e,t){for(const n of["actionIdList","actionIds"]){const i=t[n];Array.isArray(i)&&e.push(...i.map(e=>Lp(e)).filter(Boolean))}for(const n of["actionId","action_id","id","actionValue"]){const i=Lp(t[n]);i&&e.push(i)}}async function xp(e,t,n,i){i?.("info",{target:"sessionWebhook",hasSessionWebhook:Boolean(t),textPreview:jp(n)},"dingding webhook send requested");const s=await e(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({msgtype:"markdown",markdown:{title:bp(n),text:n}})}),r=await s.json().catch(()=>{});if(i?.(s.ok?"info":"warn",{target:"sessionWebhook",status:s.status,response:Pp(r)},"dingding webhook send completed"),!s.ok)throw new Error(`DingDing webhook failed with HTTP ${s.status}`)}async function Np(e){const t=zl(e.replyMarkup);if(!t.length&&!e.forceCard)return e.sessionWebhook&&await xp(e.fetchImpl,e.sessionWebhook,e.text,e.runtime.onLog),e.sessionWebhook?{delivered:!0}:void 0;const n=e.bridge.settings||{},i=Lp(n.robotCode),s=Lp(n.cardTemplateId)||"13fc6717-12e4-43ed-8533-111a310d4995.schema",r=Lp(n.cardCallbackRouteKey)||"task_handoff_message",o=e.senderId||e.runtime.senderIds.get(e.chatId)||Lp(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 xp(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=vp({type:"actions",title:e.title||bp(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:Sp(n),imRobotOpenSpaceModel:{supportForward:!1},imRobotOpenDeliverModel:{extension:{},robotCode:i,spaceType:"IM_ROBOT"}}:{openSpaceId:wp(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:jp(e.text)},"dingding card send requested"),await Op(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 Op(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=Lp(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:_p(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:Pp(d)},"dingding api response"),!a.ok)throw new Error(`DingDing API failed with HTTP ${a.status}`);const c=Dp(d),l=c.code??c.errcode,p=c.success;if(void 0!==l&&"0"!==String(l)||!1===p)throw new Error(Lp(c.message||c.errmsg)||`DingDing API returned ${String(l||"failure")}`);const u=function(e){const t=Dp(Dp(e).result).deliverResults;if(!Array.isArray(t))return"";const n=t.find(e=>!1===Dp(e).success);if(!n)return"";const i=Dp(n),s=Lp(i.spaceId),r=Lp(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 _p(e){const t=Dp(e),n=Dp(t.cardData),i=Dp(n.cardParamMap);return{openSpaceId:Lp(t.openSpaceId),outTrackId:Lp(t.outTrackId),userId:Lp(t.userId),userIdType:t.userIdType,callbackType:Lp(t.callbackType),callbackRouteKey:Lp(t.callbackRouteKey),hasImGroupTarget:Boolean(t.imGroupOpenSpaceModel||t.imGroupOpenDeliverModel),hasImSingleTarget:Boolean(t.imSingleOpenSpaceModel||t.imSingleOpenDeliverModel),hasImRobotTarget:Boolean(t.imRobotOpenSpaceModel||t.imRobotOpenDeliverModel),imGroupOpenDeliverModel:Rp(t.imGroupOpenDeliverModel),imSingleOpenDeliverModel:Rp(t.imSingleOpenDeliverModel),imRobotOpenDeliverModel:Rp(t.imRobotOpenDeliverModel),bizConversationId:Lp(i.biz_conversation_id),bizConversationType:Lp(i.biz_conversation_type),bizSenderId:Lp(i.biz_sender_id),hasBizSessionWebhook:Boolean(Lp(i.biz_session_webhook))}}function Rp(e){const t=Dp(e);if(Object.keys(t).length)return{hasExtension:Boolean(t.extension),hasRobotCode:Boolean(Lp(t.robotCode)),spaceType:Lp(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 Pp(e){const t=Dp(e),n=Dp(t.result);return{code:t.code??t.errcode,message:jp(t.message||t.errmsg,240),success:t.success,requestId:t.requestId,result:Object.keys(n).length?n:void 0}}function jp(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 Dp(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Mp(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:"string"==typeof e&&e.trim()?qp(e):{}}function Lp(e){return"string"==typeof e?e:""}function qp(e){try{return Dp(JSON.parse(String(e||"{}")))}catch{return{}}}function $p(e){return JSON.stringify(zl(e))}const Bp="task_handoff_action_id";function Up(e,t){const n=zl(t);return{schema:"2.0",config:{summary:{content:Wp(e)}},body:{elements:[{tag:"markdown",content:e},...n.map(e=>({tag:"button",text:{tag:"plain_text",content:e.text},type:Gp(e.text),width:"fill",size:"medium",behaviors:[{type:"callback",value:{[Bp]:e.id}}]}))]}}}function Fp(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[Bp]||t.action_id||t.actionId||t.id||e)}function Hp(e){return JSON.stringify(zl(e))}function Wp(e){const t=e.replace(/\s+/g," ").trim();return t.length<=50?t:`${t.slice(0,47)}...`}function Gp(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 Vp(e){return e instanceof Error?e.message:String(e)}function Kp(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 Jp(e){return Array.isArray(e?.actionRows)?e.actionRows:(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e])}function Yp(e,t){const n=Jp(e),i=Jp(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 Qp{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||Kp,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&&Yp(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: ${Vp(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&&Yp(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&&Yp(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: ${Vp(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: ${Vp(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 Xp=20971520;function Zp(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 eu(e,n,i="telegram-image",s){if(s&&s>Xp)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>Xp)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>Xp)throw new Error(`image is too large: ${g.length} bytes`);return await h.writeFile(m,g),m}class tu{store;constructor(e){this.store=new Qp({updateIntervalMs:e.updateIntervalMs,send:(t,n,i)=>e.send(e.requireBridge(n?.bridgeId||""),n?.chatId||"",cp(t),{rawMarkdownV2:!0,replyMarkup:au(i)}),edit:(t,n,i,s)=>e.edit(e.requireBridge(i?.bridgeId||""),i?.chatId||"",t,cp(n),{rawMarkdownV2:!0,replyMarkup:au(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 nu(e){return(await async function(e,t,n,i){const s=[];for(const r of Zp(n))try{const n=await eu({getFileLink:n=>up(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:iu(e),size:r.length,source:{type:"inline",encoding:"base64",data:r.toString("base64")}}})}function iu(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 su(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 au(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return Sl(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function du(e){const t=Array.isArray(e.item_list)?e.item_list:[];for(const e of t){const t=cu(e);if(1!==t.type)continue;const n=lu(cu(t.text_item).text).trim();if(n)return n}return""}function cu(e){return e&&"object"==typeof e?e:{}}function lu(e){return"string"==typeof e?e:""}function pu(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 pp(e,t,n,i,{replyMarkup:s.replyMarkup,replyToMessageId:s.replyToMessageId,rawMarkdownV2:s.rawMarkdownV2,parseMode:s.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(i,s,r={})=>{const o=r.sessionWebhook||n?.chatWebhooks.get(i)||Lp(t.settings.sessionWebhook);if(r.replyMarkup&&n){const a=await Np({fetchImpl:e,bridge:t,runtime:n,chatId:i,text:s,replyMarkup:r.replyMarkup,sessionWebhook:o,senderId:r.senderId||n.senderIds.get(i)||Lp(t.settings.senderId)});if(a?.delivered)return{provider:"dingding",interactionId:a.outTrackId}}if(o)return await xp(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:Up(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||lu(t.settings.contextToken);if(o)return await async function(e,t,n,s,r){const o=lu(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(lu(d.errmsg)||`WeChat send failed with HTTP ${a.status}`)}(e,t,n,o,s),{provider:"wechat"}}}}(t,n):{bridge:n,send:async()=>{}}}class uu{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=$p(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,$p(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=Np({fetchImpl:this.fetchImpl,bridge:e.bridge,runtime:t,chatId:e.chatId,text:e.text,replyMarkup:e.replyMarkup,sessionWebhook:t.chatWebhooks.get(e.chatId)||mu(e.bridge.settings.sessionWebhook),senderId:t.senderIds.get(e.chatId)||mu(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 Op(e.fetchImpl,e.bridge,e.runtime,"PUT","/v1.0/card/instances",{outTrackId:e.outTrackId,cardData:{cardParamMap:vp({type:"actions",title:e.title,description:e.text,list:zl(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 mu(e){return"string"==typeof e?e:""}function gu(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 hu{runtimes=new Map;connected=new Set;reconnectTimers=new Map;progress;options;createClient;constructor(e){this.options=e,this.createClient=e.createClient||gu,this.progress=new uu(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 yu{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=Hp(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,Hp(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:Up(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,Up(i,s)),this.isCurrent(e.bridge.id,o)&&(n.lastText=i,n.lastActionsFingerprint=r,n.lastUpdateAt=Date.now()))}}function fu(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 Iu{runtimes=new Map;connected=new Set;unsubscribe=new Map;reconnectTimers=new Map;options;createChannel;progress;constructor(e){this.options=e,this.createChannel=e.createChannel||fu,this.progress=new yu(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:bu(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 bu(e){return"lark"===String(e||"").trim().toLowerCase()?I.Domain.Lark:I.Domain.Feishu}class vu{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 wu{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=Su(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!==Su(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:Sl([[{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 Su(e,t,n){return[e,t,n||""].join(":")}class Au{cancelTokens=new Map;queueActionTokens=new Map;options;constructor(e){this.options=e}cancelCallbackData(e,t){this.pruneExpired();const n=zu([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=ku(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=ku(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=ku(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=ku(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=Eu(await this.options.queue(t.instanceId,t.sessionId)),i=(Array.isArray(n.items)?n.items:[]).map(Eu).filter(e=>"queued"===Cu(e.status)&&Cu(e.id));if(!i.length)return void await this.answer(e,"Queue is empty");const s=i.slice(0,5).map((e,n)=>[{text:Tu(Cu(e.message),n),callbackData:this.queueDeleteItemCallbackData(t.instanceId,t.sessionId,Cu(e.id))}]);await this.send(e,"Delete queued message",{replyMarkup:Sl(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:xu(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=xu(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=zu([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 ku(e,t){if(!e.startsWith(t))return;const n=e.slice(t.length);return n&&!n.includes(":")?n:void 0}function zu(e){return i.createHash("sha256").update(e.join("\0")).digest("base64url").slice(0,16)}function Tu(e,t){const n=`${t+1}. `,i=Cu(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 Eu(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Cu(e){return"string"==typeof e?e.trim():""}function xu(e){return e instanceof Error?e.message:String(e)}class Nu{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=Ou(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,_u(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,_u(t)),!1))}}function Ou(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:Sl([[{text:"Allow",callbackData:t(e.id,"allow")},{text:"Skip",callbackData:t(e.id,"skip")},{text:"Deny",callbackData:t(e.id,"deny")}]])}}function _u(e){return e instanceof Error?e.message:String(e)}function Ru(){return e=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(e||"").trim().toLowerCase());var e}class Pu{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||Ru,this.aiSessionInstanceNamesCache=new vu(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 vu(1e3,()=>this.service.listPendingRoutes().catch(()=>[])),this.telegramMessageAggregator=new wu({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,Fu(t))}),this.telegramAiSessionCallbacks=new Au({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 Nu({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 tu({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 hu({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,Fu(t)),clearError:e=>this.bridgeErrors.delete(e)}),this.larkBridges=new Iu({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,Fu(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:Fu(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:Wu(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: ${Fu(e)}`})}const o=ju(r);if(!o)return;const a=Mu(r);if(await this.sendLarkRoutedAiSessionProgress(r,e,n.chatId,o,a))return;const d=pu({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===Ku(r).routed,replyPreview:Wu(o)},"lark chat gateway reply sent")}async sendLarkRoutedAiSessionProgress(e,t,n,i,s){if(!0!==e.routed)return!1;const r=Qu(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=im(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:Wu(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=Fp(n.action.value),r=(e,i)=>t.channel.updateCard(n.messageId,Up(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:Up(e,i?.replyMarkup)})}))return;let o;try{o=await this.parseChatGatewayCallbackAction(s)}catch(e){if(Hu(e,"CHAT_PENDING_ACTION_STALE"))return void await r(Fu(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&&Du(a))return void await r(`${o.decision} sent`);const d=ju(a)||Uu(a.message)||"Updated";await r(d,Mu(a))}async handleDingdingRobotMessage(e,t,n){const i=function(e){const t=qp(e),n=Lp(t.conversationId),i=Lp(Dp(t.text).content).trim();if(!n||!i)return;const s=Lp(t.senderStaffId||t.senderId);return{chatId:n,userId:s||void 0,senderId:s||void 0,sessionWebhook:Lp(t.sessionWebhook)||void 0,conversationType:kp(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)||Uu(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:Wu(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 xp(this.fetchImpl,d,`Failed to handle message: ${Fu(e)}`,t.onLog);throw e}const l=ju(c);if(l){const n=Mu(c);if(await this.sendDingdingRoutedAiSessionProgress(c,e,t,s,l,{replyMarkup:n,sessionWebhook:d,senderId:o,sourcePrompt:r}))return;const i=pu({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===Ku(c).routed,hasReplyMarkup:Boolean(n),replyPreview:Wu(l)},"dingding chat gateway reply sent");this.logWarn({bridgeId:e.id,chatId:s,senderId:o,hasReplyMarkup:Boolean(n),hasSessionWebhook:Boolean(d),hasRobotCode:Boolean(Uu(e.settings.robotCode)),replyPreview:Wu(l)},"dingding chat gateway reply skipped")}}async sendDingdingRoutedAiSessionProgress(e,t,n,i,s,r={}){if(!0!==e.routed)return!1;const o=Qu(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=im(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:Wu(r.sourcePrompt,80),textPreview:Wu(s)},"dingding ai session progress card started"),!0)}async handleDingdingCardCallback(e,t,n){const i=function(e){const t=qp(e),n=Mp(t.cardActionData||t.content),i=Mp(n.cardPrivateData||t.cardPrivateData||t.content),s=Mp(i.params||n.params||t.params),r=Lp(t.userId),o=Lp(s.biz_sender_id);return{userId:r||void 0,chatId:Ap(t,s),senderId:r||void 0,deliverySenderId:o||void 0,sessionWebhook:Lp(s.biz_session_webhook)||void 0,conversationType:kp(s.biz_conversation_type||t.conversationType||t.conversation_type),callbackData:zp(Ep(t,n,i)),body:t,params:s}}(n.data);if(!this.dingdingAllowed(e,i.userId))return Tp("not authorized",void 0,"unauthorized",i.body,i.params);const s=i.chatId||Uu(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(Hu(e,"CHAT_PENDING_ACTION_STALE"))return Tp(Fu(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,...Gu(i)},"dingding card callback action unsupported"),Tp("Unsupported action",void 0,"unsupported",i.body,i.params);this.logInfo({bridgeId:e.id,chatId:s,userId:i.userId,senderId:r,actionType:a.type,...Gu(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&&Du(d)?Tp(`${a.decision} sent`,void 0,"approval_done",i.body,i.params):Tp(ju(d)||Uu(d.message)||"updated",Mu(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)||Uu(n.updatesBuf),s=await async function(e){const t=lu((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(lu(i.errmsg||i.msg)||`chat bridge API returned ${s}`);const r=[];for(const e of Array.isArray(i.msgs)?i.msgs:[]){const t=cu(e);if(1!==t.message_type)continue;const n=lu(t.from_user_id),i=du(t);n&&i&&r.push({chatId:n,text:i,contextToken:lu(t.context_token)})}return{cursor:lu(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=ju(a);if(d){const t=pu({fetchImpl:this.fetchImpl,bridge:e});await t.send(s,d,{contextToken:r||Uu(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 pu({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=ru(t.callback_query);if(Object.keys(r).length>0){s.push({updateId:i,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=Zp(o);(p||0!==u.length)&&s.push({updateId:i,chatId:c,userId:l,text:p,rawText:p,message:o,messageId:su(o),replyToMessageId:su(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: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=Ku(t.message),s=Ku(i.chat),r=void 0!==s.id?String(s.id):e.defaultChatId;this.bridgeErrors.set(e.id,Fu(n)),r&&await this.sendTelegramMessage(e,r,`Action failed: ${Fu(n)}`).catch(t=>{this.bridgeErrors.set(e.id,Fu(t))})});continue}if(!this.telegramAllowed(e,n.userId))continue;const i=await nu({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:Fu(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:Wu(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=ju(d),l=Mu(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(Ku(n).message_id)||void 0,routed:!0===Ku(d).routed,replyPreview:Wu(c)},"telegram chat gateway reply sent"),await this.rememberTelegramProgressMessage(d,e,t,n,c)}}catch(n){this.bridgeErrors.set(e.id,Fu(n)),await this.sendTelegramMessage(e,t,`Failed to handle message: ${Fu(n)}`,{replyToMessageId:r.sourceMessageId}).catch(t=>{this.bridgeErrors.set(e.id,Fu(t))})}}async handleTelegramCallback(e,t){const n=Uu(t.data),i=Ku(t.from),s=Ku(t.message),r=Ku(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:Uu(t.id),userId:a,messageId:qu(s)}))return;const d=n.match(/^task_handoff:cp_msg_end:([^:]+)$/);if(d)return void await this.telegramMessageAggregator.handleEndCallback(e,o,Uu(t.id),d[1],a);let c;try{c=await this.parseChatGatewayCallbackAction(n)}catch(n){if(Hu(n,"CHAT_PENDING_ACTION_STALE")){await this.answerTelegramCallback(e,Uu(t.id),Fu(n));const i=qu(s);return void(void 0!==i&&await this.deleteTelegramStandaloneApprovalMessage(e,o,i))}throw n}if(!c)return void await this.answerTelegramCallback(e,Uu(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&&Du(l)){await this.answerTelegramCallback(e,Uu(t.id),"");const n=qu(s);return void(void 0!==n&&await this.deleteTelegramStandaloneApprovalMessage(e,o,n))}await this.answerTelegramCallback(e,Uu(t.id),Uu(l.message)||"updated");const p=ju(l),u=Mu(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:Fu(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(gl).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&&hl(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:hp(t(i[1],"instance-app-menu").instanceId,"instanceId")}:{type:"instance-app-menu",instanceId:Ip(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:hp(e.instanceId,"instanceId"),appId:hp(e.appId,"appId")}}return{type:"launch-app",instanceId:Ip(s[1]),appId:Ip(s[2])}}const r=e.match(/^task_handoff:cp_p:([^:]+)$/);if(r){const e=t(r[1],"pending-decision");return{type:"pending-decision",routeId:hp(e.routeId,"routeId"),decision:yp(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 mp(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 pp(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=Qu(e),{instanceId:o,sessionId:a,turnId:d}=r,c=Number(Ku(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=im(o,a,d,t.id,n),p=this.telegramProgress.remember(l,c,s,{bridgeId:t.id,chatId:n});this.telegramProgressMessageTargets.set($u(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:Wu(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($u(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:Fu(e)},"telegram queued progress message replacement cleanup failed")}))}telegramReplyAiSessionTarget(e,t,n){const i=this.telegramProgressMessageTargets.get($u(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=Bu(i,e,t);if(s){const i={...s,messageId:n};return this.telegramProgressMessageTargets.set($u(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($u(i.route.bridgeId,i.route.chatId,i.messageId||0))||Bu(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($u(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=dm(n.get(e)||e,r),a=am(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:Vu(lm(r))});continue}const d=sm(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:Vu(lm(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=im(e,r.id,d,s.bridgeId||"",s.chatSessionId),l=rm(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:Vu(lm(r)),textPreview:Wu(a)});continue}const p=em({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)||tm(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:Vu(lm(r)),textPreview:Wu(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:Fu(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:Wu(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:Wu(t?.lastText),progressHasPending:Boolean(t?.pending),latestTurn:Vu(lm(r)),textPreview:Wu(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:Wu(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=dm(n.get(e)||e,o),c=am(o,d),l=sm(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:im(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=rm(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=em({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)||tm(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:Wu(c)}),g&&(this.telegramProgressMessageTargets.set($u(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($u(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($u(i.route.bridgeId,i.route.chatId,i.messageId))||Bu(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||lm(t)?.id===e.owner.turnId||lm(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:Lu({actionRows:i})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:Wu(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:Lu({actionRows:i})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:Wu(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:Wu(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:Wu(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 ju(e){return"object"==typeof e&&e&&"reply"in e?String(e.reply||""):""}function Du(e){return"object"==typeof e&&null!==e&&!0===e.accepted}function Mu(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 Lu(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return Sl(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function qu(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function $u(e,t,n){return[e,t,String(n)].join(":")}function Bu(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 Uu(e){return"string"==typeof e?e:""}function Fu(e){return e instanceof Error?e.message:String(e)}function Hu(e,t){return Boolean(e&&"object"==typeof e&&"code"in e&&e.code===t)}function Wu(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 Gu(e){const t=Ju(e.body.cardActionData||e.body.content),n=Ju(t.cardPrivateData||e.body.cardPrivateData||e.body.content);return{outTrackId:Uu(e.body.outTrackId),spaceId:Uu(e.body.spaceId),conversationType:e.conversationType,hasCallbackData:Boolean(e.callbackData),callbackDataPreview:Wu(e.callbackData,120),actionIds:[...Yu(n.actionIdList),...Yu(t.actionIdList),Uu(n.actionId),Uu(t.actionId),Uu(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 Vu(e){if(e)return{id:e.id,providerTurnId:e.providerTurnId,source:e.source,status:e.status,phase:e.phase,revision:e.revision,userPrompt:Wu(e.userPrompt,80),hasResponse:Boolean(e.lastMessage?.trim()||e.summary?.trim()),responsePreview:Wu(e.lastMessage||e.summary,80),updatedAt:e.updatedAt,observedAt:e.observedAt}}function Ku(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Ju(e){if(e&&"object"==typeof e&&!Array.isArray(e))return e;if("string"==typeof e&&e.trim())try{return Ku(JSON.parse(e))}catch{return{}}return{}}function Yu(e){return Array.isArray(e)?e.map(e=>Uu(e)).filter(Boolean):[]}function Qu(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?sm(n):""),sources:{resultTurnId:e.turnId,resultProviderTurnId:e.providerTurnId,actionTurnId:t?.turnId,actionProviderTurnId:t?.providerTurnId,sessionActiveTurnId:n?.activeTurnId,latestTurnId:n?lm(n)?.id:void 0}}}const Xu=5,Zu=48;function em(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,Xu);return[...d.map((e,t)=>[{text:nm(e.message,t),callbackData:n(e.id)}]),d.length?[{text:"Delete Queue",callbackData:i()},{text:"Cancel",callbackData:t}]:[{text:"Cancel",callbackData:t}]]}function tm(e,t){if("approval"===t.phase)return{id:`${e}:ai:${t.id}`,kind:"approval"}}function nm(e,t){const n=`${t+1}. `,i=e.replace(/\s+/g," ").trim()||"Queued message",s=Math.max(8,Zu-n.length),r=Array.from(i);return`${n}${r.length>s?`${r.slice(0,Math.max(1,s-3)).join("")}...`:i}`}function im(e,t,...n){return[e,t,...n].join(":")}function sm(e){const t=lm(e);return t?.id?t.id:Uu(e.activeTurnId)}function rm(e,t=""){const n=lm(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),om(e)].join("\0")}function om(e){return(e.queue?.items||[]).map(e=>[e.id,e.status,e.message].join(":")).join("|")}function am(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&&!cm(n,e)?i:""].filter(Boolean).join("\n\n")}(e,lm(e));return n?`${t}\n${n}`:""}function dm(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 cm(e,t){if("waiting"!==t.status||"approval"!==t.phase)return!1;const n=t.currentTool?.inputPreview?.trim();return Boolean(n&&e.includes(n))}function lm(e){return(e.turns||[]).filter(e=>e.id||e.userPrompt?.trim()||e.lastMessage?.trim()||e.summary?.trim()).at(-1)}class pm{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&&um(t.topics,s,e)&&mm(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 um(e,t,n){return!e||e.has("*")||e.has(t)||e.has(n)}function mm(e,t){return!e||!t?.instanceId||e.has(t.instanceId)}const gm={"image/bmp":".bmp","image/gif":".gif","image/jpeg":".jpg","image/png":".png","image/webp":".webp"},hm=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 ym(){return t.join(y.tmpdir(),"task-handoff-ai-session-attachments")}class fm{items=new Map;ttlMs;constructor(e=864e5){this.ttlMs=e,this.pruneOrphanFiles()}upload(e){this.pruneExpired();const s=hm.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=gm[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=ym();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=ym();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 Im={controlPlaneAuthBoundary:"public"},bm={controlPlaneAuthBoundary:"public-ui"},vm={controlPlaneAuthBoundary:"proxy-binding"},wm={controlPlaneAuthBoundary:"node-tunnel"};class Sm{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 Am(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function km(e){return e.unref?.(),e}class zm{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=Am(e.connectTimeoutMs,1e4),this.handshakeTimeoutMs=Am(e.handshakeTimeoutMs,1e4),this.heartbeatIntervalMs=Am(e.heartbeatIntervalMs,25e3),this.heartbeatTimeoutMs=Am(e.heartbeatTimeoutMs,1e4),this.stableThresholdMs=Am(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=km(this.setTimeoutFn(()=>this.timeout("connect"),this.connectTimeoutMs))}opened(){this.stopped||(this.clearTimer("connectTimer"),this.setPhase("handshaking"),this.handshakeTimer=km(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=km(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=km(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 Tm{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 Em={[N]:rt,[O]:ot,[_]:at,[R]:dt,[P]:ct,[ht]:Et,[yt]:Ct,[ft]:xt},Cm=new Set(Object.keys(Em));class xm{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=Nm(t.event),s="string"==typeof i?.type?i.type:"";if(!s)return!0;const r="payload"in i?i.payload:{},o=Nm(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(Cm.has(s)){const t=function(e,t){const n=Em[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]=_m(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=Om(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=Om(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 Nm(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:void 0}function Om(e,t){return JSON.stringify([e,t])}function _m(e){const t=JSON.parse(e);return Array.isArray(t)&&2===t.length?[String(t[0]),String(t[1])]:["",""]}const Rm=a.z.object({nodeId:a.z.string().trim().min(1).max(120)}).strict();function Pm(){return`req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}const jm=new Map;function Dm(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 jm)t<=r&&jm.delete(e);const o=`${e.id}:${n.keyId}:${n.nonce}`;if(!n.nonce||jm.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"});jm.set(o,Date.now()+nd)}function Mm(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 Lm{sockets=new Map;eventRouter;httpStreamHeaderTimeoutMs;requestTimeoutMs;auxiliaryAttachTimeoutMs;connectionRuntime;connectionOptions;constructor(e,t={}){this.eventRouter=new xm({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 zm({...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=Pm(),r=Ti(n.body),o={type:"control-plane.request",requestId:s,route:t,init:{method:n.method||"GET",headers:Mm(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=Pm(),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:Mm(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=Pm(),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 qm{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 Sm;this.retries.set(e.id,{timer:a,url:t});const d=new zm({...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 Sm};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 $m(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 Bm 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 Um(e){return t.join(e,"owner.json")}function Fm(e){return t.join(e,"initializing.json")}function Hm(e){return t.join(e,"recovering.json")}function Wm(e){return Number.isInteger(e)&&Number(e)>0}function Gm(e,t=process.platform){if(Wm(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 Vm=function(e){try{const t=JSON.parse(n.readFileSync(Um(e),"utf8"));if(Wm(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(!(Wm(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 Km(e){if(!Wm(e))return!1;try{return process.kill(Number(e),0),!0}catch(e){return"EPERM"===e.code}}function Jm(e){if(!e||!Km(e.pid))return!1;if(!e.startIdentity)return!0;const t=Gm(e.pid);return void 0===t||t===e.startIdentity}function Ym(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=Xm(e);if(r?.token!==i.token)throw eg(s),new Error(`Process lock initialization was superseded: ${e}`);n.renameSync(s,Um(e)),eg(Fm(e))}function Qm(e,s,r){const o=Vm(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"}),Vm(e)?.token!==s.token)return!1;n.renameSync(d,Um(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{eg(d)}}function Xm(e){try{return JSON.parse(n.readFileSync(Fm(e),"utf8"))}catch{return}}function Zm(e){const t=Xm(e);return Wm(t?.pid)&&Jm({pid:t.pid,startIdentity:t.startIdentity})}function eg(e){try{n.unlinkSync(e)}catch(e){if("ENOENT"!==e.code)throw e}}function tg(){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,20)}function ng(e){try{const t=Xm(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 ig(e,s){try{return n.writeFileSync(Hm(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=Hm(e),r=sg(s),o=Date.parse(r?.startedAt||"");if(Km(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=sg(a);if(d?.token===r?.token)return eg(a),!0;try{n.linkSync(a,s)}catch(e){if("EEXIST"!==e.code)throw e}finally{eg(a)}return!1}(e)&&ig(e,s);if("ENOENT"===r.code)return!1;throw r}}function sg(e){try{return JSON.parse(n.readFileSync(e,"utf8"))}catch{return}}function rg(e,t){return sg(Hm(e))?.token===t}function og(){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 ag(e,s={}){return function(e,s={}){n.mkdirSync(t.dirname(e),{recursive:!0});const r=Gm(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(Fm(e),`${JSON.stringify({token:o.token,pid:o.pid,startIdentity:o.startIdentity,startedAt:(new Date).toISOString()})}\n`,{encoding:"utf8",mode:384,flag:"wx"}),Ym(e,o),{lockPath:e,owner:o,updateDetails:t=>Qm(e,o,t),release(){const t=Vm(e);t?.token===o.token&&n.rmSync(e,{recursive:!0,force:!0})}}}catch(r){if("EEXIST"!==r.code)throw r;const o=Vm(e);if(Jm(o))throw new Bm(e,o,s.error);if(!o&&(Zm(e)||ng(e)<(s.incompleteLockStaleMs??2e3))){if(t+1<5){tg();continue}throw new Bm(e,void 0,s.error)}const a=i.randomUUID();if(!ig(e,a)){if(t+1<5){tg();continue}throw new Bm(e,Vm(e),s.error)}const d=Vm(e);if(Jm(d))throw eg(Hm(e)),new Bm(e,d,s.error);if(o?.token&&d?.token!==o.token){eg(Hm(e));continue}if(!rg(e,a))continue;n.rmSync(e,{recursive:!0,force:!0})}const a=Vm(e);throw new Bm(e,a,s.error)}(e,{...s,component:"control-plane",error:{label:"Control plane",code:"CONTROL_PLANE_ALREADY_RUNNING"}})}function dg(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:cg(e,t))}(t,n):"admin"===e.role||("viewer"===e.role?"read"===t:"operator"===e.role&&cg(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 cg(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 lg=a.z.string().trim().min(1),pg=a.z.object({id:lg}).strict(),ug=a.z.object({id:lg,keyId:lg}).strict(),mg=a.z.object({id:lg,connectionId:lg}).strict(),gg=a.z.object({id:lg,runtimeId:lg}).strict(),hg=a.z.object({id:lg,folderId:lg}).strict(),yg=a.z.object({id:lg,sessionId:lg}).strict(),fg=a.z.object({id:lg,sessionId:lg,turnId:lg}).strict(),Ig=a.z.object({id:lg,sessionId:lg,queueId:lg}).strict(),bg=a.z.object({configHash:lg}).strict(),vg=a.z.object({id:lg,configHash:lg}).strict(),wg=a.z.object({id:lg,sessionId:lg,configHash:lg}).strict(),Sg=a.z.object({path:a.z.string().optional(),depth:a.z.coerce.number().int().min(0).max(32).optional()}).strict();async function Ag(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 kg=a.z.object({ids:a.z.array(a.z.string().trim().min(1).max(120)).default([])}).strict(),zg=a.z.object({nodeId:a.z.string().trim().min(1).max(120),modelId:a.z.string().trim().min(1).max(120).optional()}).strict(),Tg=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 Eg(e){const t=Tg.parse(e);if(!t.action)throw new Error("Chat gateway action is required.");return{source:t.source,action:t.action}}const Cg=a.z.object({path:a.z.string().trim().max(1e3).optional(),depth:a.z.coerce.number().int().min(0).max(2).optional()}).strict(),xg=a.z.object({id:a.z.string().trim().min(1),appId:a.z.string().trim().min(1)}).strict(),Ng=a.z.object({id:a.z.string().trim().min(1),jobId:a.z.string().trim().min(1)}).strict(),Og=a.z.object({projection:a.z.literal("directory").optional(),instanceId:a.z.string().trim().min(1).max(120).optional()}).strict();const _g=a.z.object({id:a.z.string().trim().min(1).max(120)}).strict(),Rg=a.z.object({nodeId:a.z.string().trim().min(1).max(120),templateId:a.z.string().trim().min(1).max(120)}).strict(),Pg=a.z.object({force:a.z.enum(["true","false"]).optional()}).strict(),jg=a.z.object({projection:a.z.literal("directory").optional()}).strict();const Dg=a.z.object({cwdFolderId:a.z.string().trim().min(1).max(120)}).strict(),Mg=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:{}}),Lg=a.z.object({title:a.z.string().trim().min(1).max(120)}).strict(),qg=a.z.object({token:a.z.string().trim().min(1).max(512)}).strict(),$g=a.z.object({}).strict();function Bg(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(pg.parse(e.params).id)})),e.patch("/api/projects/:id",async e=>{const i=t.updateProject(pg.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=pg.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)=>Ag(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=kg.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(pg.parse(e.params).id)})),e.patch("/api/models/:id",async e=>{const i=await t.updateModel(pg.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=pg.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}=zg.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}=zg.parse(e.params);return{data:await t.discoverNodeModels(n,e.body)}}),e.post("/api/nodes/:nodeId/models/test",async e=>{const{nodeId:n}=zg.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}=zg.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}=zg.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(pg.parse(e.params).id)})),e.patch("/api/images/:id",async e=>{const i=t.updateImage(pg.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=pg.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"===jg.parse(e.query).projection?t.listNodes().map(e=>function(e){const t=e.proxyState?.lastError;return Pd.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(pg.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(pg.parse(e.params).id)})),e.get("/api/nodes/:id/settings/external-listener",async e=>({data:await t.getLocalNodeExternalListener(pg.parse(e.params).id)})),e.patch("/api/nodes/:id/settings/external-listener",async e=>{const i=pg.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=pg.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=pg.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=pg.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=pg.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=pg.parse(e.params);return{data:await t.listNodeControlPlanePairings(n.id)}}),e.delete("/api/nodes/:id/control-plane-pairings/:keyId",async e=>{const i=ug.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=pg.parse(e.params);return{data:await t.listNodeControlPlaneConnections(n.id)}}),e.delete("/api/nodes/:id/control-plane-connections/:connectionId",async e=>{const i=mg.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:Im},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(pg.parse(e.params).id)})),e.post("/api/nodes/:id/runtimes",async(e,i)=>{const s=pg.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=gg.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=gg.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=gg.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(pg.parse(e.params).id)})),e.get("/api/nodes/:id/image-options",async e=>({data:await t.listNodeImageAvailability(pg.parse(e.params).id)})),e.get("/api/nodes/:id/local-folders",async(e,n)=>Ag(e,n,async n=>({data:await t.listNodeLocalFolders(pg.parse(e.params).id,n)}))),e.get("/api/nodes/:id/folders/tree",async e=>{const n=pg.parse(e.params),i=Sg.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=pg.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=hg.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(pg.parse(e.params).id)})),e.patch("/api/nodes/:id",async e=>{const r=t.updateNode(pg.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=pg.parse(e.params).id,r=Pg.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)=>Ag(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 Tm(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:wm},(e,t)=>{try{const i=Rm.parse(t.query),s=n.requireNode(i.nodeId);Dm(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:wm},(e,t)=>{try{const i=Rm.parse(t.query),s=n.requireNode(i.nodeId);Dm(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:wm},(e,t)=>{try{const i=Rm.parse(t.query),s=n.requireNode(i.nodeId);Dm(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:wm},(e,t)=>{try{const i=Rm.parse(t.query),s=n.requireNode(i.nodeId);Dm(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(pg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/metrics",async e=>({data:await t.instanceResourceMetrics(pg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/apps/management",async e=>({data:await t.instanceAppManagement(pg.parse(e.params).id)})),e.post("/api/controlled-instances/:id/apps/:appId/install",async e=>{const n=xg.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=xg.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=Ng.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(pg.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=pg.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(pg.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(pg.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(pg.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(pg.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(pg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/config-sync/folders",async e=>({data:await t.listInstanceConfigSyncFolders(pg.parse(e.params).id,Cg.parse(e.query))})),e.post("/api/controlled-instances/:id/config-sync",async e=>{const i=pg.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)=>Ag(e,n,async n=>{const i=Og.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 Dd.parse({id:e.id,name:e.name,nodeId:e.nodeId,status:e.status,health:e.health,connectionStatus:e.connectionStatus,ready:e.ready,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(_g.parse(e.params).id)})),e.get("/api/nodes/:nodeId/environment-templates/:templateId",async e=>{const n=Rg.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=_g.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=Rg.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=pg.parse(e.params),s=Mg.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=yg.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=yg.parse(e.params),s=Lg.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=yg.parse(e.params);$g.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=yg.parse(e.params),i=qg.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=pg.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=pg.parse(e.params);return{data:await t.listAiSessionHistory(n.id)}}),e.get("/api/controlled-instances/:id/ai-sessions/history/:sessionId",async e=>{const n=yg.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=yg.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=fg.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=yg.parse(e.params);$g.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=pg.parse(e.params),i=Dg.parse(e.query||{});return{data:await t.inspectAiSessionWorkspace(n.id,i.cwdFolderId)}}),e.post("/api/controlled-instances/:id/ai-sessions",async e=>{const i=pg.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=yg.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=yg.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=yg.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=yg.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=yg.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=yg.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=yg.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=yg.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=Ig.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=Ig.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=Ig.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=Ig.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=yg.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=yg.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=yg.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=yg.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=bg.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=bg.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=bg.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=pg.parse(e.params);return{data:await t.listInstanceTriggers(n.id)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/triggers",async e=>{const i=yg.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=wg.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=vg.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(pg.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=pg.parse(i.params).id,r=t.requireChatBridge(s),o=oc.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=pg.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=pg.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=pg.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(Eg(e.body))})),e.get("/api/pending-routes",async()=>({data:await t.listPendingRoutes()}))}({app:t,service:n,chatGateway:d})}const Ug=new Set(["connection","content-length","keep-alive","proxy-authenticate","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),Fg=new Set(["authorization"]),Hg=new Set(["content-encoding"]);function Wg(e){return Object.fromEntries(Object.entries(e).flatMap(([e,t])=>{const n=e.toLowerCase();if(Ug.has(n)||Fg.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 Gg(e){return Object.fromEntries(Object.entries(Wg(e)).filter(([e])=>{const t=e.toLowerCase();return"host"!==t&&"cookie"!==t&&"authorization"!==t&&(!t.startsWith("sec-websocket-")||"sec-websocket-origin"===t)}))}function Vg(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 Kg(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 Jg(e,t,n){for(const[n,i]of Object.entries(t.headers)){const t=n.toLowerCase();Ug.has(t)||Hg.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 Yg(e){return`/instances/${encodeURIComponent(e)}`}function Qg(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()}})}(Yg(n)):void 0;return Jg(e,t,s)}function Xg(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 Zg(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 eh(e){return new URL(e,"http://control-plane.local").searchParams.get("token")||""}function th(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 nh{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 ih=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 sh{records;bySession=new Map;listener;constructor(e,t={}){this.records=new fo(e.aiSessionUnreadDir,{schema:ih}),this.listener=t.onChanged}init(){this.records.init(),this.bySession.clear();for(const e of this.records.list())this.bySession.set(oh(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(oh(e,t.id))?.unread||!1}))}}markRead(e,t,n){const i=this.bySession.get(oh(e,t));return i&&i.sessionUpdatedAt===n&&i.unread?rh(this.store({...i,unread:!1,updatedAt:(new Date).toISOString()},!1)):i?rh(i):void 0}removeInstance(e){for(const t of[...this.bySession.values()])t.instanceId===e&&this.deleteRecord(t)}reconcileSession(e,t){const n=oh(e,t.id),i=this.bySession.get(n),s=(new Date).toISOString();if(!i)return void this.store({id:ah(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(oh(n.instanceId,n.sessionId),n),t&&this.listener?.(rh(n)),n}deleteRecord(e){this.records.delete(e.id),this.bySession.delete(oh(e.instanceId,e.sessionId))}}function rh(e){return q.parse({instanceId:e.instanceId,sessionId:e.sessionId,unread:e.unread,sessionUpdatedAt:e.sessionUpdatedAt,updatedAt:e.updatedAt})}function oh(e,t){return`${e}\0${t}`}function ah(e,t){return`ais_unread_${i.createHash("sha256").update(oh(e,t)).digest("hex").slice(0,32)}`}class dh{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 ch(e){return e.raw[0].replace(/\\\$\{/g,"${")}class lh{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 gh,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=uh(s);e.set(i,{...a,status:o,...d||{}})}}(n.layers,n.terminal.text()),n.progress=ph(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=ph(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 gh,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=ph(e),this.events.publish("image.pull.progress",e.progress,{topic:"instances",scope:{instanceId:e.identity.instanceId}}),t&&(e.progress=ph(e)))}}function ph(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 uh(e){const t=e.match(/([\d.]+)\s*([kmgt]?i?b)\s*\/\s*([\d.]+)\s*([kmgt]?i?b)/i);if(t)return{current:mh(t[1],t[2]),total:mh(t[3],t[4])}}function mh(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 gh{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 hh=a.z.object({revision:a.z.number().int().nonnegative(),invites:a.z.array(Kn),bindings:a.z.array(Zn)}).strict(),yh={invite:new Set(Object.keys(Kn.shape)),binding:new Set(Object.keys(Zn.shape))};function fh(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 Ih(e,t,n){if(!t||"object"!=typeof t||Array.isArray(t))return t;const i=t,s=yh[e],r=Object.keys(i).filter(e=>!s.has(e));r.length>0&&n?.({kind:e,fields:r});const o=fh(i,s);return"binding"===e&&o.lastError&&(o.lastError=fh(o.lastError,Object.keys(Gn.shape))),o}function bh(e){const{tokenHash:t,...n}=e;return Jn.parse(n)}function vh(e){const{credentialHash:t,...n}=e;return ei.parse(n)}class wh{authority;constructor(e,t){this.authority=new Io(e,()=>({revision:0,invites:[],bindings:[]}),{schema:hh,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=>Ih("invite",e,t)):n.invites,bindings:Array.isArray(n.bindings)?n.bindings.map(e=>Ih("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 Sh 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 Ah=e=>i.createHash("sha256").update(e).digest("base64url"),kh=()=>i.randomBytes(32).toString("base64url");function zh(e,t){const n=Ah(t),s=Buffer.from(e),r=Buffer.from(n);return s.length===r.length&&i.timingSafeEqual(s,r)}function Th(e,t,n,i=!1,s={}){throw new Sh(e,t,n,i,s)}class Eh{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??kh}init(){this.store.init(),this.expireInvites()}createInvite(e,t){const n=this.resolveProxyOrigin();n||Th(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:Ah(s),status:"active",createdBy:t,expiresAt:new Date(this.now().getTime()+1e3*i.expiresInSeconds).toISOString(),createdAt:r,updatedAt:r},a=Qn.parse({invite:bh(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(bh)}revokeInvite(e){const t=this.requireInvite(e);if("consumed"===t.status&&Th(Hn.InviteConsumed,"A consumed proxy invite cannot be revoked independently of its binding.",409,!1,{inviteId:e}),"revoked"===t.status||"expired"===t.status)return bh(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}),bh(i)}claimInvite(e){const t=ti.parse(e);this.requireCurrentProtocol(t.protocolVersion),this.expireInvites();const n=Ah(t.credential);return this.store.transaction(e=>{const i=e.bindings.find(e=>e.claimId===t.claimId);if(!t.inviteToken)return i||Th(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)&&Th(Hn.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:t.claimId}),"revoked"===i.status&&Th(Hn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:i.id}),this.claimResult(i,this.requireKnownTarget(i.targetNodeId));const s=e.invites.find(e=>zh(e.tokenHash,t.inviteToken));s||Th(Hn.InviteInvalid,"Proxy invite is invalid.",401),t.targetNodeId&&t.targetNodeId!==s.targetNodeId&&Th(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_${Ah(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&&Th(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&&Th(Hn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:c.id}),"consumed"===s.status&&s.consumedByClaimId===t.claimId||Th(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(vh)}authenticateBinding(e,t){const n=ni.parse(t),i=this.store.getBinding(e);return i||Th(Hn.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),"active"!==i.status&&Th(Hn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:e}),i.sourceControlPlaneId===n.sourceControlPlaneId&&i.bindingKeyId===n.bindingKeyId&&zh(i.credentialHash,n.credential)||Th(Hn.AuthenticationFailed,"Proxy binding authentication failed.",401,!1,{bindingId:e}),vh(i)}revokeBinding(e){const t=this.requireBinding(e);if("revoked"===t.status)return vh(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}),vh(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}),vh(e))),invites:t.invites.filter(t=>t.targetNodeId===e&&"active"===t.status).map(e=>(Object.assign(e,{status:"revoked",revokedAt:n,updatedAt:n}),bh(e)))}})}nowIso(){return this.now().toISOString()}requireCurrentProtocol(e){e!==Nn&&Th(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||Th(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||Th(Hn.TargetUnavailable,"Proxy target is not currently manageable.",503,!0,{targetNodeId:e}),t}requireInvite(e){const t=this.store.getInvite(e);return t||Th(Hn.InviteInvalid,"Proxy invite is unknown.",404,!1,{inviteId:e}),t}requireBinding(e){const t=this.store.getBinding(e);return t||Th(Hn.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),t}requireClaimableInvite(e){"active"!==e.status&&Th({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||Th(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:vh(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 Ch extends Error{statusCode=429;code=Hn.ResourceLimit;retryable=!0;details;constructor(e,t){super(e),this.name="NodeProxyRuntimeError",this.details=t}}class xh{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+=Nh(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=Nh(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 Ch(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 Nh(e){return Buffer.isBuffer(e)||e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:Buffer.byteLength("string"==typeof e?e:String(e),"utf8")}class Oh{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:_h(t)}}subscribe(e,t,n,i=()=>{}){const{bindingId:s,sourceControlPlaneId:r,targetNodeId:o}=e,a=this.stream(o),d=_h(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(Rh(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:_h(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=Ph(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=Rh(d,e.bindingId,e.sourceControlPlaneId),n=Ph(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 _h(e){return e.history[0]?.event.revision??e.revision+1}function Rh(e,t,n){return ri.parse({...e,bindingId:t,sourceControlPlaneId:n})}function Ph(e){try{return Buffer.byteLength(JSON.stringify(e),"utf8")}catch{return}}function jh(e,t){const n=new WeakSet;let i=t,s=0;const r=e=>{if(i-=Buffer.byteLength(e,"utf8"),i<0)throw Dh("Proxy target projection byte limit exceeded.",{resource:"target-projection-bytes",limit:t})},o=(e,t)=>{if(s+=1,s>16384||t>24)throw Dh("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 Dh("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 Dh(e,t,n=!0){return Object.assign(new Error(e),{code:"CONTROL_PLANE_PROXY_RESOURCE_LIMIT",statusCode:429,retryable:n,...t?{details:t}:{}})}function Mh(e){const{manageable:t,...n}=e;return n}const Lh=a.z.object({bindingId:a.z.string().trim().min(1).max(160)}).passthrough(),qh=a.z.object({route:Mn}).strict(),$h=a.z.object({sinceRevision:a.z.coerce.number().int().nonnegative()}).strict(),Bh=new Set(["connection","cookie","host","keep-alive","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),Uh=524288;function Fh(e,t,n){const i=Yh(n.headers,$n);if(i!==Nn)throw Jh(Hn.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:i,supportedVersion:Nn});const s=Yh(n.headers,Bn),r=Yh(n.headers,Un),o=Yh(n.headers,Fn);if(!s||!r||!o)throw Jh(Hn.AuthenticationFailed,"Proxy binding authentication headers are incomplete.",401);return e.authenticateBinding(t,{sourceControlPlaneId:s,bindingKeyId:r,credential:o})}function Hh(e,t,n){const i=Fh(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 Jh(Hn.BindingIdentityConflict,"Proxy binding changed while the request was being established.",409,!0,{bindingId:t.id,expectedRevision:t.revision,actualRevision:i.revision})}function Wh(e,t){if(t.id!==e.targetNodeId)throw Jh(Hn.TargetMismatch,"Proxy target resolver returned another node.",409,!1,{bindingId:e.id,targetNodeId:e.targetNodeId})}function Gh(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 Jh(Hn.HeaderInvalid,"Caller-supplied node transport authentication headers are forbidden.",400,!1,{header:e})}const t=Object.fromEntries([...Ln].flatMap(t=>{if(Bh.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 Jh(Hn.HeaderInvalid,"Proxy request correlation id is invalid.",400,!1,{header:"x-request-id"});t["x-request-id"]=e.data}return t}function Vh(e,t,n){const i=Kh(t),s=Qh(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 Kh(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 Jh(e,t,n,i=!1,s){return Object.assign(new Error(t),{code:e,statusCode:n,retryable:i,...s?{details:s}:{}})}function Yh(e,t){const n=e[t];return Array.isArray(n)?n.join(","):"string"==typeof n?n:""}function Qh(e){if(!e)return;const t=jn.safeParse(Yh(e,"x-request-id"));return t.success?t.data:void 0}function Xh(e){let t="";for(const n of e){if(Buffer.byteLength(t+n)>123)break;t+=n}return t}const Zh=e=>Gn.parse({code:Hn.Unavailable,message:e,retryable:!0});class ey{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:Zh(`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:ty(n)},"control-plane proxy state bootstrap failed"),this.fail(e,t,Zh("Trusted control-plane proxy is unavailable."),!0)}else this.fail(e,t,Zh("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,Zh(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:ty(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 ty(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 ny=a.z.object({id:a.z.string().trim().min(1).max(160)}).strict(),iy=a.z.object({}).strict(),sy=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 ry(){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 oy(e){return`sha256:${i.createHash("sha256").update(Buffer.from(e,"base64url")).digest("base64url")}`}function ay(e){return Array.isArray(e)?`[${e.map(ay).join(",")}]`:e&&"object"==typeof e?`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${ay(t)}`).join(",")}}`:JSON.stringify(e)}class dy{identity;controlPlaneId;constructor(e,t,n){this.controlPlaneId=t,this.identity=new Io(e,ry,{schema:sy,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:oy(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:oy(e.publicKey)}}signCloudBindingChallenge(e){return i.sign(null,Buffer.from(`task-handoff:cloud-binding-challenge:v1\n${ay(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 cy{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 ly(e,n){const i=t.extname(e);return`${i?e.slice(0,-i.length):e}.${n}${i}`}const py=1048576,uy=52428800;function my(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:e}function gy(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 hy(e,i,s){const r=n.statSync(e),o=Math.min(r.size,py,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 yy=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 fy{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:yy,directoryMode:448,fileMode:384})}init(){if(this.state.init(),this.state.get().serviceOrigin!==this.serviceOrigin)throw by("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 by("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:Iy(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=Iy(s),o.length!==a.length||!i.timingSafeEqual(o,a)))throw by("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 by("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 by("CONTROL_PLANE_ALREADY_BOUND","Control Plane is already bound to another account.")}if("pending-claim"!==t.status)throw by("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 Iy(e){return i.createHash("sha256").update(e).digest()}function by(e,t){return Object.assign(new Error(t),{code:e,statusCode:e.includes("CONFLICT")||e.includes("BOUND")?409:400})}class vy{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 wy{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 Sy{connection;processInstanceId=`control_plane_process_${i.randomUUID().replaceAll("-","_")}`;backoff;options;constructor(e){this.options=e,this.backoff=e.backoff??new wy}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 Ay{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 ky{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 zy{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(xy("RELAY_SOCKET_CLOSED")))})}(s),s.send(JSON.stringify({type:"attach",capability:n})),async function(e,t,n,i,s){const r=await Ey(e,e=>"frame"===e?.type&&"handshake"===e.frame?.kind);if(r.frame.channelId!==t||0!==r.frame.sequence)throw xy("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 Ty(e,t,a.sessionKey,c,s);return l.start(),{close:(e="normal")=>l.close(e)}}(s,(await Ey(s,e=>"attached"===e?.type)).channelId,i,this.options.identity,this.options.bridge)}}class Ty{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 xy("RELAY_FRAME_SEQUENCE_INVALID");const i=w.secretbox.open(Buffer.from(n.ciphertext,"base64url"),Cy(1,this.receiveCounter++),this.key);if(!i)throw xy("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 xy("RELAY_ENVELOPE_UNSUPPORTED")}send(e){if(this.socket.readyState!==l.OPEN||this.socket.bufferedAmount>2097152)throw xy("RELAY_BACKPRESSURE_LIMIT");const t=w.secretbox(Buffer.from(JSON.stringify(e)),Cy(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 Ey(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(xy("RELAY_SOCKET_CLOSED"))},o=()=>{e.off("message",s),e.off("close",r)};e.on("message",s),e.once("close",r)})}function Cy(e,t){const n=new Uint8Array(24);return n[0]=e,new DataView(n.buffer).setBigUint64(16,BigInt(t),!1),n}function xy(e){return Object.assign(new Error("Cloud Relay session is invalid."),{code:e,retryable:!0})}class Ny{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(_y("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(_y("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 _y("CLOUD_CONTROL_CONNECTION_UNAVAILABLE");return this.current.request(e,t)}}class Oy{lifecycle;dataConnections;connector;control;events;timer;running=!1;connecting;options;constructor(e){this.options=e,this.connector=new Ny({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 zy({identity:e.identity,bridge:e.relayBridge,webSocket:e.webSocket}):{async connect(){throw _y("CLOUD_RELAY_CONNECTOR_UNAVAILABLE")}});this.dataConnections=new Ay({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 xy("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 xy("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 vy({state:e.state,connections:{stop:e=>this.control.stop(e)},dataConnections:this.dataConnections}),this.control=new Sy({state:e.state,connector:this.connector,onEvent:async e=>{await this.events.apply(e)}}),this.lifecycle=new ky({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 _y("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 _y("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 _y(e){return Object.assign(new Error("Cloud background connection is unavailable."),{code:e,retryable:!0})}const Ry="x-task-handoff-cloud-internal-actor",Py=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(),jy=a.z.object({error:Py}).strict(),Dy="https://cloud.thandoff.com";function My(e,t={}){const n=new URL(e||Dy).origin;if(n===Dy)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 Ly(e){const t=process.env[e]?.trim();return t||void 0}const qy=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 $y(){return{component:"control-plane",packageName:"@task-handoff/control-plane",packageVersion:qy(),protocolVersion:ui,buildId:Ly("TASK_HANDOFF_BUILD_ID"),builtAt:Ly("TASK_HANDOFF_BUILT_AT"),gitCommit:Ly("TASK_HANDOFF_GIT_COMMIT"),imageRef:Ly("TASK_HANDOFF_IMAGE_REF"),imageDigest:Ly("TASK_HANDOFF_IMAGE_DIGEST")}}const By={".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 Uy(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 Fy(e,i,s){const r=Uy(i,s);return r?(e.header("cache-control","no-store"),e.type(By[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 Hy(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 Wy(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 Gy(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 Vy=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 Ky(e,t){const n=t.split("?")[0]||"/";if(!n.startsWith("/api/"))return;if(Vy.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 Jy(e={}){const d=$m(e.dataDir),c=s({logger:e.logger??!0}),l=new pm,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(ly(e,t),{force:!0});for(let i=t-1;i>=1;i-=1){const t=ly(e,i);n.existsSync(t)&&n.renameSync(t,ly(e,i+1))}}}(e,r),r>0?t.size>s?(n.writeFileSync(ly(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,ly(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:my(a)},(e,t)=>my(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 cy;f.onChange(e=>l.publish("node.connection.updated",e,{topic:"node.state",scope:{nodeId:e.nodeId}}));const I=new op(d,{...e.service,logger:h,nodeConnectionRuntime:f}),b=new $o(d,e.auth),v=new dy(d.identitySigningPath,()=>I.proxyPrivateStore.controlPlaneId(),(e,t)=>c.log.warn(t,e)),w=new fy({statePath:d.cloudConnectivityPath,identity:v,serviceOrigin:My(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 Oy({state:w,identity:v,relayBridge:{async request(e,t){const n=String(t?.method||"GET").toUpperCase(),s=String(t?.path||""),r=Ky(n,s);if(!s.startsWith("/api/")||!r||Vy.has(s.split("?")[0]))throw Object.assign(new Error("Cloud access route is not available."),{code:"CLOUD_ROUTE_FORBIDDEN",statusCode:403});dg(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",Ry].includes(e.toLowerCase())).map(([e,t])=>[e,String(t)])),i=await c.inject({method:n,url:s,headers:{...e,[Ry]: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(dg(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 lh(l),C=new sh(d,{onChanged:e=>queueMicrotask(()=>l.publish(j,e,{topic:"ai.sessions",scope:{instanceId:e.instanceId,sessionId:e.sessionId}}))});C.init();const x=new nh({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 dh({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 fm;c.addHook("onClose",async()=>{O.dispose()});const _=new Lm(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:jh(e.capabilities||{},262144),manageable:!1!==e.connectionEnabled&&(n||"online"===i)}}(t,_.connected(t.id)):void 0},D=new Eh(new wh(d.proxyAuthorityPath,(e,t)=>c.log.warn(t,e)),{get:P},{proxyOrigin:R,proxyOriginProvider:()=>I.getSettings().publicBaseUrl}),M=new xh,L=new Oh(l,{projectTarget:e=>{const t=P(e);return t?Mh(t):void 0}}),q=new ey(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 Pu(I,e.service?.fetchImpl,{aiSessions:x,logger:h,diagnosticLogsEnabled:()=>u});H.startEnabled();const W=new qm(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=Hy(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(jy.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[Ry],o="string"==typeof r?S.get(r):void 0;if(o){S.delete(r);const t=Ky(e.method,i);if(!t)throw Object.assign(new Error("Cloud access route is not authorized."),{code:"CLOUD_ROUTE_FORBIDDEN",statusCode:403});return void dg(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 Gy(b,Wy(e)),n=Ky(e.method,i);return void(n&&dg(t||{type:"system",reason:"auth-disabled"},n.action,n.resource))}const d=await Gy(b,Wy(e));if(!d)return t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to access the Control Plane."}});const c=Ky(e.method,i);c&&dg(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:Im},async(e,n)=>{const i=e.params["*"];return Fy(n,G,t.join("assets",i||""))}),c.get("/favicon.ico",{config:Im},async(e,t)=>Uy(G,"favicon.ico")?Fy(t,G,"favicon.ico"):t.code(204).send())),c.get("/api/health",{config:Im},async()=>fs.parse({data:{ok:!0,role:"control-plane",protocolVersion:ui,build:$y(),dataDir:d.dataDir,serverTime:(new Date).toISOString()}})),c.get("/api/control-plane/identity",{config:Im},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});dg(await Gy(b,Wy(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:Im},async(e,t)=>(t.header("cache-control","no-store"),t.type("text/x-shellscript; charset=utf-8"),ch`#!/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([E.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 x.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:Uu},async e=>{const t=hy(e);return{data:await b.currentSession(t.token,t.clientType)}}),c.post("/api/auth/bootstrap-admin",{config:Uu},async(e,t)=>{const n=await b.bootstrapAdmin(e.body);return t.code(201).send({data:n})}),c.post("/api/auth/login",{config:Uu},async(e,t)=>{const n=await b.login(e.body,{sourceId:e.ip});return t.setCookie(eo,n.sessionToken,{path:"/",httpOnly:!0,sameSite:"lax",expires:new Date(n.expiresAt)}),{data:{user:n.user}}}),c.post("/api/auth/mobile/login",{config:Uu},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[eo],e.body,{sourceId:e.ip});return t.setCookie(eo,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=hy(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(hy(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(hy(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:Uu},async(e,t)=>{const n=b.logout(e.cookies[eo]);return t.clearCookie(eo,{path:"/"}),{data:n}}),c.get("/api/control-plane/status",async()=>({data:{protocolVersion:ti,build:cy(),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 Mm(e.root)){if(c>=jm)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=Lm(s,t.join(i,o),jm-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:Pm,totalBytes:jm},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)}})}}),lh({app:c,service:I,events:l,appSessionAggregator:N,aiSessionAggregator:E,aiSessionUnread:T,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 Xh,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:Hu,bodyLimit:o.maxRequestBodyBytes,logLevel:"silent",async onRequest(e,t){try{const i=am.parse(e.params).bindingId,s=um(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 Im(Rn.RouteInvalid,"Proxy route is invalid.",400);const i=Cn.safeParse(n[1]);if(!i.success)throw Im(Rn.RouteInvalid,i.error.issues[0]?.message||"Proxy route is invalid.",400);return i.data}(e),c=mm(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 ym(t,n,e)}},async onError(e,t){d(e,t);const n=vm(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 Im(Rn.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 Im(Rn.TargetMismatch,"Proxy request attempts to select a target outside its binding.",409,!1,{bindingId:e.id,targetNodeId:e.targetNodeId})}(o,c,e.body);const h=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(h?.byteLength??0);try{const{node:s,transport:r}=await i(o.targetNodeId);return gm(n,o,e),hm(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([...Tn].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=g.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,...h?{body:h}:{},signal:p.controller.signal}),p,u,e,l["x-request-id"])}catch(n){throw d(e,t),n}}catch(n){return d(e,t),ym(t,n,e)}var s}),t.get("/api/node-proxy/bindings/:bindingId/websocket",{websocket:!0,logLevel:"silent",config:Hu},async(e,t)=>{let s;try{const r=am.parse(t.params).bindingId,a=um(n,r,t),d=dm.parse(t.query).route,{node:c,transport:l}=await i(a.targetNodeId);gm(n,a,t),hm(a,c),s=o.openWebSocket(a.id,e),l.proxyWebSocket(c,s,d,function(e){const t=bm(e,"sec-websocket-protocol").split(",").map(e=>e.trim()).filter(Boolean);return t.length?t:void 0}(t.headers),mm(t.headers))}catch(t){const n=fm(t);s?.close(1008,n.message),s||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,wm(n.message))}}),t.get("/api/node-proxy/bindings/:bindingId/snapshot",{config:Hu},async(e,t)=>{try{const t=am.parse(e.params).bindingId,a=um(n,t,e),{node:d}=await i(a.targetNodeId);gm(n,a,e),hm(a,d);const c=s(a.targetNodeId);if(!c)throw Im(Rn.TargetUnavailable,"Proxy target no longer exists.",404,!1,{targetNodeId:a.targetNodeId});const l=r.cursor(a.targetNodeId),p=Vn.parse({protocolVersion:bn,binding:a,streamId:l.streamId,revision:l.revision,observedAt:(new Date).toISOString(),target:om(c)});if(o=p,Buffer.byteLength(JSON.stringify(o),"utf8")>pm)throw Im(Rn.ResourceLimit,"Proxy target snapshot byte limit exceeded.",429,!0,{bindingId:a.id,resource:"snapshot-bytes",limit:pm});return{data:p}}catch(n){return ym(t,n,e)}var o}),t.get("/api/node-proxy/bindings/:bindingId/events",{websocket:!0,logLevel:"silent",config:Hu},async(e,t)=>{let s,a,d;try{const c=am.parse(t.params).bindingId,l=um(n,c,t),p=cm.parse(t.query),{node:u}=await i(l.targetNodeId);gm(n,l,t),hm(l,u),s=o.openWebSocket(l.id,e,()=>a?.()),s.on("message",()=>s?.close(1008,"Proxy event streams do not accept client messages."));const g=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=g.close,d=o.registerBindingCleanup(l.id,a);const h=()=>{a?.(),d?.()};s.on("close",h),s.on("error",h),"snapshot-required"===g.kind?(a(),s.close(1008,"Proxy target snapshot is required.")):1!==s.readyState&&a()}catch(t){a?.(),d?.();const n=fm(t);s?.close(1008,n.message),s||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,wm(n.message))}}),t.delete("/api/node-proxy/bindings/:bindingId",{config:Hu},async(t,i)=>{try{const i=am.parse(t.params).bindingId;um(n,i,t);const s=n.revokeBinding(i),r=o.closeBinding(i);return e.onBindingRevoked?.(s),{data:{binding:s,closed:r}}}catch(e){return ym(i,e,t)}})}({app:c,authority:D,resolveTarget:e=>{const t=I.requireNode(e);return{node:t,transport:I.resolveNodeAgentTransport(t)}},projectTarget:j,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(zm.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=zm.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:Uu},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=zm.parse(e.params).id;Cm.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(zm.parse(e.params).id)}))}({app:c,service:I,proxy:D,runtime:M,events:l,actorId:async e=>{const t=await my(b,hy(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"])Sh(e,t);Sh(e,/^multipart\/form-data(?:;.*)?$/i)}(e),e.get("/api/app-access/session",{config:Uu},async e=>{const n=Ah(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?kh(n,s.access.sessionId,s.session):void 0}}}),e.get("/apps/access/tty/ws",{websocket:!0,config:Uu},async(e,n)=>{try{const i=await t.appAccessProxyTarget(Ah(n.url),"tty");await t.proxyInstanceWebSocket(i.instance.id,e,i.path,yh(n.headers),mh(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||Ah(n.url),"vnc",i["*"]||"");await t.proxyInstanceWebSocket(s.instance.id,e,s.path,yh(n.headers),mh(n.headers))}catch{e.close(1011,"VNC access link is invalid or expired.")}};e.route({method:"GET",url:"/apps/access/vnc/proxy/*",config:Uu,wsHandler:n,handler:async(e,n)=>{const i=e.params,s=await t.appAccessProxyTarget(Ah(e.url),"vnc",i["*"]||"");return vh(n,await fh(t,n,s.instance.id,s.path,{method:e.method,headers:hh(e.headers)}),s.instance.id,s.path)}}),e.route({method:"GET",url:"/apps/access/vnc/:token/proxy/*",config:Uu,wsHandler:n,handler:async(e,n)=>{const i=e.params,s=await t.appAccessProxyTarget(i.token,"vnc",i["*"]||"");return vh(n,await fh(t,n,s.instance.id,s.path,{method:e.method,headers:hh(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(`${bh(i.id)}/`):vh(n,await fh(t,n,i.id,"/",{method:e.method,headers:hh(e.headers),body:wh(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}`,yh(n.headers),mh(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 vh(n,await fh(t,n,i.id,o,{method:e.method,headers:hh(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 Ih(n,await fh(t,n,i.id,`/${s}${o}`,{method:e.method,headers:hh(e.headers),body:wh(e.body)}))}})}({app:c,service:I}),c.get("*",{config:Fu},async(e,t)=>n.existsSync(G)?uy(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 by(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 vy(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",by,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",vy,process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"password").action(async e=>{await async function(e){const t=lg(e.dataDir),n=Og(Ng(),{dataDir:t.dataDir,host:e.host,port:e.port});try{const t=await Iy(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=lg(e),s=Og(n.lockPath||Ng(),{dataDir:i.dataDir});try{const e=new wo(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
+ `)),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:Im},async e=>{const t=Wy(e);return{data:await b.currentSession(t.token,t.clientType)}}),c.post("/api/auth/bootstrap-admin",{config:Im},async(e,t)=>{const n=await b.bootstrapAdmin(e.body);return t.code(201).send({data:n})}),c.post("/api/auth/login",{config:Im},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:Im},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=Wy(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(Wy(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(Wy(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:Im},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:$y(),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 gy(e.root)){if(c>=uy)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=hy(s,t.join(i,o),uy-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:py,totalBytes:uy},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)}})}}),Bg({app:c,service:I,events:l,appSessionAggregator:N,aiSessionAggregator:x,aiSessionUnread:C,chatGateway:H,aiSessionAttachments:O,nodeAgentTunnel:_,nodeEventSubscriber:W,errorPayload:Hy}),function(e){const{app:t,authority:n,resolveTarget:i,projectTarget:s,eventHub:r}=e,o=e.runtime??new xh,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:vm,bodyLimit:o.maxRequestBodyBytes,logLevel:"silent",async onRequest(e,t){try{const i=Lh.parse(e.params).bindingId,s=Fh(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 Jh(Hn.RouteInvalid,"Proxy route is invalid.",400);const i=Mn.safeParse(n[1]);if(!i.success)throw Jh(Hn.RouteInvalid,i.error.issues[0]?.message||"Proxy route is invalid.",400);return i.data}(e),c=Gh(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 Vh(t,n,e)}},async onError(e,t){d(e,t);const n=Qh(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 Jh(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 Jh(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 Hh(n,o,e),Wh(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),Vh(t,n,e)}var s}),t.get("/api/node-proxy/bindings/:bindingId/websocket",{websocket:!0,logLevel:"silent",config:vm},async(e,t)=>{let s;try{const r=Lh.parse(t.params).bindingId,a=Fh(n,r,t),d=qh.parse(t.query).route,{node:c,transport:l}=await i(a.targetNodeId);Hh(n,a,t),Wh(a,c),s=o.openWebSocket(a.id,e),l.proxyWebSocket(c,s,d,function(e){const t=Yh(e,"sec-websocket-protocol").split(",").map(e=>e.trim()).filter(Boolean);return t.length?t:void 0}(t.headers),Gh(t.headers))}catch(t){const n=Kh(t);s?.close(1008,n.message),s||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,Xh(n.message))}}),t.get("/api/node-proxy/bindings/:bindingId/snapshot",{config:vm},async(e,t)=>{try{const t=Lh.parse(e.params).bindingId,a=Fh(n,t,e),{node:d}=await i(a.targetNodeId);Hh(n,a,e),Wh(a,d);const c=s(a.targetNodeId);if(!c)throw Jh(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:Mh(c)});if(o=p,Buffer.byteLength(JSON.stringify(o),"utf8")>Uh)throw Jh(Hn.ResourceLimit,"Proxy target snapshot byte limit exceeded.",429,!0,{bindingId:a.id,resource:"snapshot-bytes",limit:Uh});return{data:p}}catch(n){return Vh(t,n,e)}var o}),t.get("/api/node-proxy/bindings/:bindingId/events",{websocket:!0,logLevel:"silent",config:vm},async(e,t)=>{let s,a,d;try{const c=Lh.parse(t.params).bindingId,l=Fh(n,c,t),p=$h.parse(t.query),{node:u}=await i(l.targetNodeId);Hh(n,l,t),Wh(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=Kh(t);s?.close(1008,n.message),s||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,Xh(n.message))}}),t.delete("/api/node-proxy/bindings/:bindingId",{config:vm},async(t,i)=>{try{const i=Lh.parse(t.params).bindingId;Fh(n,i,t);const s=n.revokeBinding(i),r=o.closeBinding(i);return e.onBindingRevoked?.(s),{data:{binding:s,closed:r}}}catch(e){return Vh(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(ny.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=ny.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:Im},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=ny.parse(e.params).id;iy.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(ny.parse(e.params).id)}))}({app:c,service:I,proxy:D,runtime:M,events:l,actorId:async e=>{const t=await Gy(b,Wy(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"])Zg(e,t);Zg(e,/^multipart\/form-data(?:;.*)?$/i)}(e),e.get("/api/app-access/session",{config:Im},async e=>{const n=eh(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?th(n,s.access.sessionId,s.session):void 0}}}),e.get("/apps/access/tty/ws",{websocket:!0,config:Im},async(e,n)=>{try{const i=await t.appAccessProxyTarget(eh(n.url),"tty");await t.proxyInstanceWebSocket(i.instance.id,e,i.path,Vg(n.headers),Gg(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||eh(n.url),"vnc",i["*"]||"");await t.proxyInstanceWebSocket(s.instance.id,e,s.path,Vg(n.headers),Gg(n.headers))}catch{e.close(1011,"VNC access link is invalid or expired.")}};e.route({method:"GET",url:"/apps/access/vnc/proxy/*",config:Im,wsHandler:n,handler:async(e,n)=>{const i=e.params,s=await t.appAccessProxyTarget(eh(e.url),"vnc",i["*"]||"");return Qg(n,await Kg(t,n,s.instance.id,s.path,{method:e.method,headers:Wg(e.headers)}),s.instance.id,s.path)}}),e.route({method:"GET",url:"/apps/access/vnc/:token/proxy/*",config:Im,wsHandler:n,handler:async(e,n)=>{const i=e.params,s=await t.appAccessProxyTarget(i.token,"vnc",i["*"]||"");return Qg(n,await Kg(t,n,s.instance.id,s.path,{method:e.method,headers:Wg(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(`${Yg(i.id)}/`):Qg(n,await Kg(t,n,i.id,"/",{method:e.method,headers:Wg(e.headers),body:Xg(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}`,Vg(n.headers),Gg(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 Qg(n,await Kg(t,n,i.id,o,{method:e.method,headers:Wg(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 Jg(n,await Kg(t,n,i.id,`/${s}${o}`,{method:e.method,headers:Wg(e.headers),body:Xg(e.body)}))}})}({app:c,service:I}),c.get("*",{config:bm},async(e,t)=>n.existsSync(G)?Fy(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 Yy(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 Qy(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",Yy,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",Qy,process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"password").action(async e=>{await async function(e){const t=$m(e.dataDir),n=ag(og(),{dataDir:t.dataDir,host:e.host,port:e.port});try{const t=await Jy(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=$m(e),s=ag(n.lockPath||og(),{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});