@task-handoff/control-plane 0.0.19 → 0.0.21

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 (75) hide show
  1. package/dist/cli.js +2 -2
  2. package/package.json +2 -1
  3. package/ui/assets/{CodeBlockNode-BzvFZHHG.js → CodeBlockNode-CQ8M9c4W.js} +1 -1
  4. package/ui/assets/{Tooltip-Bd-es-ax.js → Tooltip-DfSjy5Pe.js} +1 -1
  5. package/ui/assets/{abnfDiagram-VRR7QNED-DGZ5AdDK.js → abnfDiagram-VRR7QNED-CvtgJEbk.js} +1 -1
  6. package/ui/assets/{arc-hQkKxuYc.js → arc-CfuzLNAK.js} +1 -1
  7. package/ui/assets/{architectureDiagram-ZJ3FMSHR-B8NwN41E.js → architectureDiagram-ZJ3FMSHR-DaSFYN_I.js} +1 -1
  8. package/ui/assets/{blockDiagram-677ZJIJ3-lLLs_v0V.js → blockDiagram-677ZJIJ3-C7NUTxX3.js} +1 -1
  9. package/ui/assets/{c4Diagram-LMCZKHZV-f0HmfgjP.js → c4Diagram-LMCZKHZV-Q7Xvg99u.js} +1 -1
  10. package/ui/assets/channel-C082KI0n.js +1 -0
  11. package/ui/assets/{chunk-2Q5K7J3B-C6FsraZR.js → chunk-2Q5K7J3B-B2ls0tY7.js} +1 -1
  12. package/ui/assets/{chunk-32BRIVSS-D4K9Slii.js → chunk-32BRIVSS-D2lf3CfN.js} +1 -1
  13. package/ui/assets/{chunk-5VM5RSS4-nliC9-qR.js → chunk-5VM5RSS4-BKGWvotD.js} +1 -1
  14. package/ui/assets/{chunk-EX3LRPZG-CPwTEuJv.js → chunk-EX3LRPZG-D8Tifow1.js} +1 -1
  15. package/ui/assets/{chunk-JWPE2WC7-BgAeCVrd.js → chunk-JWPE2WC7-CyA4VtdQ.js} +1 -1
  16. package/ui/assets/{chunk-MOJQB5TN-BGNJepqS.js → chunk-MOJQB5TN-uTeMfbhC.js} +1 -1
  17. package/ui/assets/{chunk-RYQCIY6F-DHUkS6kO.js → chunk-RYQCIY6F-BLVMjOPS.js} +1 -1
  18. package/ui/assets/{chunk-V7JOEXUC-7m73T5Zr.js → chunk-V7JOEXUC-CTbXBENv.js} +1 -1
  19. package/ui/assets/{chunk-VR4S4FIN-BS9xb9TE.js → chunk-VR4S4FIN-DZ3Nal8q.js} +1 -1
  20. package/ui/assets/{chunk-XXDRQBXY-Dohzy83e.js → chunk-XXDRQBXY-DGUfwrj6.js} +1 -1
  21. package/ui/assets/classDiagram-OUVF2IWQ-HNZJ6wP2.js +1 -0
  22. package/ui/assets/classDiagram-v2-EOCWNBFH-HNZJ6wP2.js +1 -0
  23. package/ui/assets/{cose-bilkent-JH36ORCC-Bw3IacvP.js → cose-bilkent-JH36ORCC-CLPQshqp.js} +1 -1
  24. package/ui/assets/{cynefin-VYW2F7L2-D5ysMeMO.js → cynefin-VYW2F7L2-yTwt550L.js} +1 -1
  25. package/ui/assets/{cynefinDiagram-TSTJHNR4-liB33tEn.js → cynefinDiagram-TSTJHNR4-APV611dc.js} +1 -1
  26. package/ui/assets/{dagre-VKFMJZFB-BziNSFEL.js → dagre-VKFMJZFB-CoqVEyP0.js} +1 -1
  27. package/ui/assets/{diagram-FQU43EPY-CvJmpS69.js → diagram-FQU43EPY-DwH_phDJ.js} +1 -1
  28. package/ui/assets/{diagram-G47NLZAW-DY1NCuIg.js → diagram-G47NLZAW-CI8OTDpt.js} +1 -1
  29. package/ui/assets/{diagram-NH7WQ7WH-DzsZN3GS.js → diagram-NH7WQ7WH-B47sPsv9.js} +1 -1
  30. package/ui/assets/{diagram-OA4YK3LP-Dm5jcWQ3.js → diagram-OA4YK3LP-CrVPeWuP.js} +1 -1
  31. package/ui/assets/{diagram-WEI45ONY-D84JOUyX.js → diagram-WEI45ONY-DOnQLasl.js} +1 -1
  32. package/ui/assets/{ebnfDiagram-CCIWWBDH-Bj9I0w_p.js → ebnfDiagram-CCIWWBDH-CkTcGGLA.js} +1 -1
  33. package/ui/assets/{erDiagram-Q63AITRT-BWLxnGk7.js → erDiagram-Q63AITRT-weuu-HFp.js} +1 -1
  34. package/ui/assets/{flowDiagram-23GEKE2U-BD1kYhHy.js → flowDiagram-23GEKE2U-Fl7R0sPi.js} +1 -1
  35. package/ui/assets/{ganttDiagram-NO4QXBWP-D-Kprz-a.js → ganttDiagram-NO4QXBWP-B_2mouLc.js} +1 -1
  36. package/ui/assets/{gitGraphDiagram-IHSO6WYX-Bw8_OKBI.js → gitGraphDiagram-IHSO6WYX-CELXNr6e.js} +1 -1
  37. package/ui/assets/index-CWdPJLZb.js +622 -0
  38. package/ui/assets/{index-BUyznhhp.css → index-D4G2CbCj.css} +1 -1
  39. package/ui/assets/{index10-Csh6UPiW.js → index10-DgG0qZbY.js} +1 -1
  40. package/ui/assets/{index11-B8ZooVhN.js → index11-B-Jv9dsS.js} +1 -1
  41. package/ui/assets/{index5-2efTOyCD.js → index5-Dvc8IQR2.js} +1 -1
  42. package/ui/assets/{index6-DcUWe2JV.js → index6-CTo0NJF4.js} +1 -1
  43. package/ui/assets/{index7-CPyjslmp.js → index7-CC5lzwLM.js} +1 -1
  44. package/ui/assets/{index8-yAEzlw4y.js → index8-CBHgOMpS.js} +1 -1
  45. package/ui/assets/{infoDiagram-FWYZ7A6U--08cljnJ.js → infoDiagram-FWYZ7A6U-Clhfrm2T.js} +1 -1
  46. package/ui/assets/{ishikawaDiagram-FXEZZL3T-CN0sUnE6.js → ishikawaDiagram-FXEZZL3T-813_e3vz.js} +1 -1
  47. package/ui/assets/{journeyDiagram-5HDEW3XC-KpK7rPIm.js → journeyDiagram-5HDEW3XC-DMwbabaI.js} +1 -1
  48. package/ui/assets/{kanban-definition-HUTT4EX6-DpEdcwro.js → kanban-definition-HUTT4EX6-h8oQXgGV.js} +1 -1
  49. package/ui/assets/{linear-aDyfLopz.js → linear-6LakjIbS.js} +1 -1
  50. package/ui/assets/{mermaid.core-Ca4GmIRT.js → mermaid.core-CGiShzv5.js} +4 -4
  51. package/ui/assets/{mhchem-BsyImv3K.js → mhchem-DOuKChBK.js} +1 -1
  52. package/ui/assets/{mindmap-definition-LN4V7U3C-dNiapg8y.js → mindmap-definition-LN4V7U3C-BJ0HOeAz.js} +1 -1
  53. package/ui/assets/{pegDiagram-2B236MQR-Cir3dhJd.js → pegDiagram-2B236MQR-Ct0wOB8B.js} +1 -1
  54. package/ui/assets/{pieDiagram-ENE6RG2P-DkQtyClj.js → pieDiagram-ENE6RG2P-Dce9wMCR.js} +1 -1
  55. package/ui/assets/{quadrantDiagram-ABIIQ3AL-CINalc1f.js → quadrantDiagram-ABIIQ3AL-BWoxWpIl.js} +1 -1
  56. package/ui/assets/{railroadDiagram-RFXS5EU6-D3ue40pV.js → railroadDiagram-RFXS5EU6-DlIleNuN.js} +1 -1
  57. package/ui/assets/{requirementDiagram-TGXJPOKE-0hf14q-a.js → requirementDiagram-TGXJPOKE-CyH3eFb4.js} +1 -1
  58. package/ui/assets/{sankeyDiagram-HTMAVEWB-_o29fixX.js → sankeyDiagram-HTMAVEWB-DPsNfgex.js} +1 -1
  59. package/ui/assets/{sequenceDiagram-DBY2YBRQ-B1c6gyNV.js → sequenceDiagram-DBY2YBRQ-CPOI8Xit.js} +1 -1
  60. package/ui/assets/{sizeCapture-X5ZJPWSS-CEBNbyv_.js → sizeCapture-X5ZJPWSS-Cdq6JXEl.js} +1 -1
  61. package/ui/assets/{stateDiagram-2N3HPSRC-YheukJqB.js → stateDiagram-2N3HPSRC-VfQnM2vS.js} +1 -1
  62. package/ui/assets/stateDiagram-v2-6OUMAXLB-Uq3ml9vd.js +1 -0
  63. package/ui/assets/{swimlanes-5IMT3BWC-D9KmXC-4.js → swimlanes-5IMT3BWC-CR5xg60T.js} +2 -2
  64. package/ui/assets/swimlanesDiagram-G3AALYLV-BJJAMdVU.js +8 -0
  65. package/ui/assets/{timeline-definition-FHXFAJF6-DLw22g9p.js → timeline-definition-FHXFAJF6-3Tr5N1Ac.js} +1 -1
  66. package/ui/assets/{vennDiagram-L72KCM5P-CPD3aOTM.js → vennDiagram-L72KCM5P-BM5rN-7j.js} +1 -1
  67. package/ui/assets/{wardleyDiagram-EHGQE667-XJMcnT17.js → wardleyDiagram-EHGQE667-D0QM8mRt.js} +1 -1
  68. package/ui/assets/{xychartDiagram-FW5EYKEG-aY72b-VS.js → xychartDiagram-FW5EYKEG-BbX_u2x9.js} +1 -1
  69. package/ui/index.html +2 -2
  70. package/ui/assets/channel-C6tYtcdb.js +0 -1
  71. package/ui/assets/classDiagram-OUVF2IWQ-BRwz8mXG.js +0 -1
  72. package/ui/assets/classDiagram-v2-EOCWNBFH-BRwz8mXG.js +0 -1
  73. package/ui/assets/index-xW8dWI4s.js +0 -620
  74. package/ui/assets/stateDiagram-v2-6OUMAXLB-BjWLtCiZ.js +0 -1
  75. package/ui/assets/swimlanesDiagram-G3AALYLV-DV2RCqrI.js +0 -8
package/dist/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var e=require("commander"),t=require("node:path"),n=require("node:fs"),s=require("fastify"),i=require("@fastify/cookie"),r=require("@fastify/websocket"),o=require("zod"),a=require("node:crypto"),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");function v(e){var t=Object.create(null);return e&&Object.keys(e).forEach(function(n){if("default"!==n){var s=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,s.get?s:{enumerable:!0,get:function(){return e[n]}})}}),t.default=e,Object.freeze(t)}var w=v(require("tar"));function S(e,t){try{const s=JSON.parse(n.readFileSync(e,"utf8"));if(t&&s.name!==t)return;return"string"==typeof s.version&&s.version.trim()?s.version.trim():void 0}catch{return}}function A(e){if(e)try{return t.dirname(n.realpathSync(e))}catch{return}}function k(e,n=process.env,s=e){const i=n.TASK_HANDOFF_VERSION?.trim();if(i)return i;const r=s.split("/").at(-1),o=process.argv[1]?t.resolve(process.argv[1]):void 0,a=o?t.dirname(o):void 0,d=[A(o),a,process.cwd()].filter(e=>Boolean(e));for(const n of new Set(d)){let s=n;for(;;){const n=S(t.join(s,"package.json"),e);if(n)return n;const i=t.dirname(s);if(i===s)break;s=i}}let c;for(const e of new Set(d)){let n=e;for(;;){if(r){const e=S(t.join(n,"packages",r,"package.json"),s);if(e)return e}c||=S(t.join(n,"package.json"));const e=t.dirname(n);if(e===n)break;n=e}}return c||"unknown"}const z=20971520,T=512e3,C=41943040,x="ai-session.snapshot",E="ai-session.patch",N="ai-session.removed",_="ai-session.message-delta",P="ai-session.unread.updated",R=o.z.string().trim().min(1).max(80),O=o.z.enum(["app-session","ai-session"]),j=o.z.enum(["running","waiting","idle","failed"]),M=o.z.object({instanceId:o.z.string().trim().min(1).max(160),sessionId:o.z.string().trim().min(1).max(120),unread:o.z.boolean(),sessionUpdatedAt:o.z.string().datetime(),updatedAt:o.z.string().datetime()}).strict(),D=o.z.enum(["thinking","tool","editing","approval","responding","unknown"]),q=o.z.object({id:o.z.string().trim().min(1).max(240).optional(),kind:o.z.string().trim().min(1).max(80).optional(),name:o.z.string().trim().min(1).max(120),inputPreview:o.z.string().trim().max(500).optional(),startedAt:o.z.string().datetime().optional()}).strict(),L=o.z.enum(["pending-init","running","interrupted","completed","errored","shutdown","not-found"]),$=o.z.enum(["started","interacted","interrupted"]),B=o.z.object({threadId:o.z.string().trim().min(1).max(240),path:o.z.string().trim().max(4096).optional(),status:L,activity:$.optional(),message:o.z.string().trim().max(1e3).optional(),updatedAt:o.z.string().datetime()}).strict(),U=o.z.object({toolCalls:o.z.number().int().min(0).default(0),edits:o.z.number().int().min(0).default(0),approvals:o.z.number().int().min(0).default(0)}).strict().default({toolCalls:0,edits:0,approvals:0}),F=o.z.object({send:o.z.boolean().optional(),interrupt:o.z.boolean().optional(),approval:o.z.boolean().optional(),openApp:o.z.boolean().optional(),close:o.z.boolean().optional()}).strict(),H=o.z.enum(["image","file"]),W=o.z.object({id:o.z.string().trim().min(1).max(120),kind:H,name:o.z.string().trim().min(1).max(240),mime:o.z.string().trim().min(1).max(120),size:o.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER)}),G=o.z.union([W.extend({source:o.z.object({type:o.z.literal("inline"),encoding:o.z.literal("base64"),data:o.z.string().min(1).max(31457280)}).strict()}).strict().superRefine((e,t)=>{const n="image"===e.kind?z:T;(e.size<=0||("file"===e.kind?e.size>=n:e.size>n))&&t.addIssue({code:o.z.ZodIssueCode.custom,path:["size"],message:`Inline ${e.kind} must be between 1 byte and ${n} bytes.`})}),W.extend({source:o.z.object({type:o.z.literal("runtime-path"),path:o.z.string().trim().min(1).max(4096)}).strict()}).strict()]),V=W.extend({sourceType:o.z.enum(["inline","runtime-path"])}).strict(),K=o.z.union([o.z.object({id:o.z.string().trim().min(1).max(120),kind:H.optional(),source:o.z.object({type:o.z.literal("upload-ref")}).strict().default({type:"upload-ref"})}).strict(),o.z.object({id:o.z.string().trim().min(1).max(120),kind:H,name:o.z.string().trim().min(1).max(240),mime:o.z.string().trim().min(1).max(120),size:o.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),source:o.z.object({type:o.z.literal("runtime-path"),path:o.z.string().trim().min(1).max(4096)}).strict()}).strict()]),J=o.z.enum(["auto","queue","steer","immediate"]),Q=o.z.enum(["ask","auto-review","full-access"]),Y=o.z.enum(["review","rename","goal","compact"]),X=o.z.object({command:Y,argument:o.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.`})}),Z=o.z.object({command:Y,value:o.z.string().max(4e3).optional(),turnId:o.z.string().trim().min(1).max(240).optional()}).strict();o.z.enum(["skill","app","plugin"]);const ee=o.z.object({name:o.z.string().trim().min(1).max(240),path:o.z.string().trim().min(1).max(4096)}),te=o.z.discriminatedUnion("kind",[ee.extend({kind:o.z.literal("skill"),path:o.z.string().trim().min(1).max(4096).refine(e=>e.startsWith("/"),"Skill paths must be absolute.")}).strict(),ee.extend({kind:o.z.literal("app"),path:o.z.string().trim().min(7).max(4096).regex(/^app:\/\/[^\s/]+$/,"App paths must use app://<id>.")}).strict(),ee.extend({kind:o.z.literal("plugin"),path:o.z.string().trim().min(10).max(4096).regex(/^plugin:\/\/[^\s/]+$/,"Plugin paths must use plugin://<id>.")}).strict()]),ne=o.z.array(te).max(20).default([]),se=o.z.enum(["plugin","skill","file","directory","app"]),ie=o.z.object({kind:se,name:o.z.string().trim().min(1).max(240),description:o.z.string().trim().max(1e3).optional(),path:o.z.string().trim().min(1).max(4096),icon:o.z.string().trim().max(4096).optional()}).strict().superRefine((e,t)=>{"skill"!==e.kind||e.path.startsWith("/")||t.addIssue({code:"custom",path:["path"],message:"Skill paths must be absolute."}),"app"!==e.kind||/^app:\/\/[^\s/]+$/.test(e.path)||t.addIssue({code:"custom",path:["path"],message:"App paths must use app://<id>."}),"plugin"!==e.kind||/^plugin:\/\/[^\s/]+$/.test(e.path)||t.addIssue({code:"custom",path:["path"],message:"Plugin paths must use plugin://<id>."}),"file"!==e.kind&&"directory"!==e.kind||!e.path.startsWith("/")&&!e.path.split(/[\\/]+/).includes("..")||t.addIssue({code:"custom",path:["path"],message:"File and directory paths must be relative to the session cwd."})}),re=o.z.object({category:o.z.enum(["skills","plugins","apps","files"]),code:o.z.string().trim().min(1).max(160),message:o.z.string().trim().min(1).max(2e3)}).strict(),oe=o.z.object({sessionId:o.z.string().trim().min(1).max(120),providerSessionId:o.z.string().trim().min(1).max(240),cwd:o.z.string().trim().min(1).max(4096),candidates:o.z.array(ie).max(1e3).default([]),diagnostics:o.z.array(re).max(20).default([])}).strict(),ae=o.z.object({query:o.z.string().trim().max(240).default("")}).strict(),de=o.z.object({sessionId:o.z.string().trim().min(1).max(120),cwd:o.z.string().trim().min(1).max(4096),query:o.z.string().trim().max(240),requestId:o.z.string().trim().min(1).max(160),candidates:o.z.array(ie.refine(e=>"file"===e.kind||"directory"===e.kind,"File search only returns files and directories.")).max(200).default([]),complete:o.z.boolean().default(!1)}).strict(),ce=o.z.object({message:o.z.string().trim().min(1).max(2e4),mode:J.optional(),permissionMode:Q.optional()}),le=ce.extend({attachments:o.z.array(G).max(6).default([]),references:ne}).strict().superRefine((e,t)=>{e.attachments.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>C&&t.addIssue({code:o.z.ZodIssueCode.custom,path:["attachments"],message:"Inline attachments must be 41943040 bytes or less in total."})}),pe=ce.extend({attachments:o.z.array(K).max(6).default([]),references:ne}).strict(),ue=o.z.object({type:o.z.literal("runtime-path"),path:o.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();le.extend({agent:R,cwd:ue,clientRequestId:o.z.string().trim().min(1).max(160)}).strict();const ge=pe.extend({agent:R,cwdFolderId:o.z.string().trim().min(1).max(120).optional(),clientRequestId:o.z.string().trim().min(1).max(160)}).strict(),he=o.z.object({disposition:o.z.enum(["created","already-created"]),aiSessionId:o.z.string().trim().min(1).max(120),providerSessionId:o.z.string().trim().min(1).max(240),creationSource:o.z.literal("ai-session")}).strict(),me=o.z.object({clientRequestId:o.z.string().trim().min(1).max(160)}).strict(),ye=o.z.object({disposition:o.z.enum(["opened","already-open"]),aiSessionId:o.z.string().trim().min(1).max(120),providerSessionId:o.z.string().trim().min(1).max(240),appSessionId:o.z.string().trim().min(1).max(120),creationSource:O}).strict(),fe=o.z.object({clientRequestId:o.z.string().trim().min(1).max(160)}).strict(),Ie=o.z.object({disposition:o.z.enum(["closed","already-closed"]),aiSessionId:o.z.string().trim().min(1).max(120),providerSessionId:o.z.string().trim().min(1).max(240),creationSource:O}).strict();o.z.object({code:o.z.enum(["invalid-request","not-found","unsupported","provider-unavailable","materialization-failed","open-app-failed","close-failed","conflict"]),message:o.z.string().trim().min(1).max(4e3),retryable:o.z.boolean().default(!1),aiSessionId:o.z.string().trim().min(1).max(120).optional(),providerSessionId:o.z.string().trim().min(1).max(240).optional()}).strict();const be=o.z.object({decision:o.z.enum(["allow","deny","skip"])}).strict(),ve=o.z.object({expectedRevision:o.z.number().int().min(0),queueIds:o.z.array(o.z.string().trim().min(1).max(120)).max(100)}).strict(),we=o.z.object({expectedRevision:o.z.number().int().min(0),message:o.z.string().trim().min(1).max(2e4)}).strict();o.z.object({code:o.z.string().trim().min(1).max(160),message:o.z.string(),instanceId:o.z.string().trim().min(1).max(160).optional(),nodeId:o.z.string().trim().min(1).max(160).optional(),route:o.z.string().trim().min(1).max(4096).optional()}).strict();const Se=o.z.object({id:o.z.string().trim().min(1).max(120),message:o.z.string().trim().min(1).max(2e4),attachments:o.z.array(V).max(6).default([]),references:ne,permissionMode:Q.optional(),status:o.z.enum(["queued","sending","failed"]).default("queued"),createdAt:o.z.string().datetime(),updatedAt:o.z.string().datetime(),error:o.z.string().trim().max(4e3).optional()}).strict(),Ae=o.z.object({revision:o.z.number().int().min(0).default(0),pendingCount:o.z.number().int().min(0).default(0),items:o.z.array(Se).max(100).default([])}).strict().default({revision:0,pendingCount:0,items:[]}),ke=o.z.enum(["control","realtime","adapter-snapshot","transcript-tail","transcript-scan","process-scan","app-session"]),ze=o.z.object({id:o.z.string().trim().min(1).max(240),status:o.z.enum(["running","completed"]),startedAt:o.z.string().datetime().optional(),completedAt:o.z.string().datetime().optional()}).strict(),Te=o.z.object({id:o.z.string().trim().min(1).max(240),providerTurnId:o.z.string().trim().max(240).optional(),source:ke.optional(),userPrompt:o.z.string().trim().optional(),status:o.z.enum(["queued","running","waiting","completed","failed"]).default("running"),phase:D.optional(),summary:o.z.string().trim().max(1e3).optional(),lastMessage:o.z.string().trim().optional(),lastMessageItemId:o.z.string().trim().max(240).optional(),contextCompactions:o.z.array(ze).max(20).optional(),revision:o.z.number().int().min(0).default(0),sourcePriority:o.z.number().int().min(0).max(100).optional(),snapshotVersion:o.z.number().int().min(0).optional(),observedAt:o.z.string().datetime().optional(),startedAt:o.z.string().datetime().optional(),updatedAt:o.z.string().datetime().optional(),completedAt:o.z.string().datetime().optional()}).strict(),Ce=Te.pick({id:!0,providerTurnId:!0,userPrompt:!0,status:!0,phase:!0,summary:!0,lastMessage:!0,contextCompactions:!0,startedAt:!0,updatedAt:!0,completedAt:!0}).strict(),xe=o.z.object({id:o.z.string().trim().min(1).max(120),agent:R,creationSource:O.default("app-session"),appSessionId:o.z.string().trim().max(120).optional(),appId:o.z.string().trim().max(120).optional(),providerSessionId:o.z.string().trim().max(240).optional(),providerMeta:o.z.record(o.z.string(),o.z.unknown()).optional(),appBindingKeys:o.z.array(o.z.string().trim().min(1).max(240)).max(20).optional(),actions:F.optional(),activeTurnId:o.z.string().trim().max(240).optional(),title:o.z.string().trim().max(240).optional(),cwd:o.z.string().trim().max(4096).optional(),userPrompt:o.z.string().trim().optional(),turns:o.z.array(Te).max(50).optional(),status:j.default("running"),phase:D.default("unknown"),summary:o.z.string().trim().max(1e3).optional(),lastMessage:o.z.string().trim().optional(),lastMessageItemId:o.z.string().trim().max(240).optional(),currentTool:q.optional(),toolCallsSinceLastMessage:o.z.number().int().min(0).default(0),subAgents:o.z.array(B).max(50).default([]),transcriptPath:o.z.string().trim().max(4096).optional(),transcriptSize:o.z.number().int().min(0).optional(),startedAt:o.z.string().datetime(),updatedAt:o.z.string().datetime(),completedAt:o.z.string().datetime().optional(),error:o.z.string().trim().max(4e3).optional(),counters:U,queue:Ae}).strict(),Ee=o.z.object({session:xe,provider:o.z.string().trim().min(1).max(80),action:o.z.enum(["send","queue","steer","interrupt","approval"]),decision:o.z.enum(["allow","deny","skip"]).optional(),turnId:o.z.string().trim().min(1).max(240).optional(),providerTurnId:o.z.string().trim().min(1).max(240).optional(),queueId:o.z.string().trim().min(1).max(120).optional()}).strict(),Ne=o.z.object({id:o.z.string().trim().min(1).max(120),agent:o.z.enum(["codex","claude"]),creationSource:O,providerSessionId:o.z.string().trim().min(1).max(240),title:o.z.string().trim().max(240).optional(),userPrompt:o.z.string().trim().optional(),lastMessage:o.z.string().trim().optional(),cwd:o.z.string().trim().min(1).max(4096),lastActiveAt:o.z.string().datetime(),archivedAt:o.z.string().datetime()}).strict();o.z.object({schemaVersion:o.z.literal(1).default(1),items:o.z.array(Ne).max(50).default([])}).strict();const _e=o.z.object({items:o.z.array(Ne).max(50).default([])}).strict(),Pe=o.z.object({item:Ne,turns:o.z.array(Ce).max(50).default([])}).strict(),Re=o.z.object({disposition:o.z.enum(["resumed","already-open"]),aiSessionId:o.z.string().trim().min(1).max(120),providerSessionId:o.z.string().trim().min(1).max(240),appSessionId:o.z.string().trim().min(1).max(120).optional(),creationSource:O}).strict(),Oe=xe.pick({id:!0,agent:!0,creationSource:!0,appSessionId:!0,appId:!0,providerSessionId:!0,providerMeta:!0,appBindingKeys:!0,actions:!0,activeTurnId:!0,title:!0,cwd:!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}),je=o.z.object({runningCount:o.z.number().int().min(0).default(0),waitingCount:o.z.number().int().min(0).default(0),staleCount:o.z.number().int().min(0).default(0),sessions:o.z.array(Oe).default([]),updatedAt:o.z.string().datetime()}).strict(),Me=o.z.object({streamId:o.z.string().trim().min(1).max(240),revision:o.z.number().int().min(0),lastEventAt:o.z.string().datetime(),snapshot:je}).strict(),De=je.pick({runningCount:!0,waitingCount:!0,staleCount:!0,updatedAt:!0}).extend({idleCount:o.z.number().int().min(0).default(0),problemCount:o.z.number().int().min(0).default(0),revision:o.z.number().int().min(0).optional()});function qe(e,t={}){const n=e.sessions.filter(e=>"idle"===e.status).length,s=e.sessions.filter(e=>"failed"===e.status).length;return De.parse({runningCount:e.runningCount,waitingCount:e.waitingCount,staleCount:e.staleCount,idleCount:n,problemCount:s,updatedAt:e.updatedAt,revision:t.revision})}const Le=o.z.enum(["provider-event","app-session-created","app-session-updated","app-session-deleted","discovery-scan","control-action","heartbeat-sync","startup"]),$e=o.z.object({streamId:o.z.string().trim().min(1).max(240),instanceId:o.z.string().trim().min(1).max(160),nodeId:o.z.string().trim().min(1).max(160).optional(),revision:o.z.number().int().min(0),previousRevision:o.z.number().int().min(0).optional(),traceId:o.z.string().trim().min(1).max(160),generatedAt:o.z.string().datetime(),reason:Le}).strict(),Be=o.z.object({meta:$e,snapshot:je}).strict(),Ue=o.z.object({meta:$e,upserted:o.z.array(Oe).default([]),removed:o.z.array(o.z.string().trim().min(1).max(120)).default([])}).strict(),Fe=o.z.object({meta:$e,sessionIds:o.z.array(o.z.string().trim().min(1).max(120)).default([]),expiresAt:o.z.string().datetime()}).strict(),He=o.z.object({instanceId:o.z.string().trim().min(1).max(160),nodeId:o.z.string().trim().min(1).max(160).optional(),sessionId:o.z.string().trim().min(1).max(120),providerSessionId:o.z.string().trim().min(1).max(240),turnId:o.z.string().trim().min(1).max(240),itemId:o.z.string().trim().min(1).max(240),delta:o.z.string().min(1),generatedAt:o.z.string().datetime()}).strict(),We=o.z.object({streamId:o.z.string().trim().min(1).max(240),instanceId:o.z.string().trim().min(1).max(160),sinceRevision:o.z.number().int().min(0),latestRevision:o.z.number().int().min(0),earliestRetainedRevision:o.z.number().int().min(0),syncRequired:o.z.boolean().default(!1),events:o.z.array(o.z.discriminatedUnion("type",[o.z.object({type:o.z.literal(x),payload:Be}).strict(),o.z.object({type:o.z.literal(E),payload:Ue}).strict(),o.z.object({type:o.z.literal(N),payload:Fe}).strict()])).default([])}).strict(),Ge=o.z.object({source:ke,sourcePriority:o.z.number().int().min(0).max(100).optional(),observedAt:o.z.string().datetime().optional(),snapshotVersion:o.z.number().int().min(0).optional()}).strict(),Ve=Ge.extend({type:o.z.literal("snapshot"),agent:o.z.string().trim().min(1).max(80),creationSource:O.optional(),appSessionId:o.z.string().trim().max(120).optional(),appId:o.z.string().trim().max(120).optional(),providerSessionId:o.z.string().trim().max(240).optional(),providerMeta:o.z.record(o.z.string(),o.z.unknown()).optional(),appBindingKeys:o.z.array(o.z.string().trim().min(1).max(240)).max(20).optional(),actions:F.optional(),title:o.z.string().trim().max(240).optional(),cwd:o.z.string().trim().max(4096).optional(),activeTurnId:o.z.string().trim().max(240).optional(),userPrompt:o.z.string().trim().optional(),turns:o.z.array(Te).max(50).optional(),status:j.optional(),phase:D.optional(),summary:o.z.string().trim().max(1e3).optional(),lastMessage:o.z.string().trim().optional(),lastMessageItemId:o.z.string().trim().max(240).optional(),currentTool:q.optional(),toolCallsSinceLastMessage:o.z.number().int().min(0).optional(),subAgents:o.z.array(B).max(50).optional(),transcriptPath:o.z.string().trim().max(4096).optional(),transcriptSize:o.z.number().int().min(0).optional(),replaceActivity:o.z.boolean().optional()}).strict(),Ke=Ge.extend({type:o.z.literal("event"),sessionId:o.z.string().trim().min(1).max(120),kind:o.z.enum(["lifecycle","send-ack","turn-started","user-message","assistant-message","approval-requested","turn-completed","tool-activity","sub-agent-activity","context-compaction"]),activeTurnId:o.z.string().trim().max(240).optional(),providerTurnId:o.z.string().trim().max(240).optional(),userPrompt:o.z.string().trim().optional(),text:o.z.string().optional(),itemId:o.z.string().trim().max(240).optional(),status:j.optional(),phase:D.optional(),summary:o.z.string().trim().max(1e3).optional(),error:o.z.string().trim().max(4e3).optional(),currentTool:q.nullable().optional(),toolCallsSinceLastMessage:o.z.number().int().min(0).optional(),subAgents:o.z.array(B).max(50).optional(),contextCompaction:ze.optional(),counters:o.z.object({toolCalls:o.z.number().int().min(0).optional(),edits:o.z.number().int().min(0).optional(),approvals:o.z.number().int().min(0).optional()}).strict().optional()}).strict().superRefine((e,t)=>{if("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"})});o.z.discriminatedUnion("type",[Ve,Ke]);const Je=o.z.union([o.z.object({type:o.z.literal("schedule"),scheduleKind:o.z.literal("interval").default("interval"),intervalMs:o.z.number().int().min(1e3)}).strict(),o.z.object({type:o.z.literal("schedule"),scheduleKind:o.z.literal("daily"),timeOfDay:o.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/),timezone:o.z.string().trim().min(1).max(120)}).strict(),o.z.object({type:o.z.literal("schedule"),scheduleKind:o.z.literal("weekly"),weekdays:o.z.array(o.z.number().int().min(0).max(6)).min(1).max(7),timeOfDay:o.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/),timezone:o.z.string().trim().min(1).max(120)}).strict()]),Qe=o.z.union([Je,o.z.object({type:o.z.literal("file-change"),roots:o.z.array(o.z.string().trim().min(1).max(4096)).min(1).max(50),globs:o.z.array(o.z.string().trim().min(1).max(500)).min(1).max(100),ignore:o.z.array(o.z.string().trim().min(1).max(500)).max(100).optional(),debounceMs:o.z.number().int().min(100).max(6e4).default(1500)}).strict(),o.z.object({type:o.z.literal("ai-session"),agent:o.z.string().trim().min(1).max(80).optional(),statuses:o.z.array(o.z.enum(["running","waiting","idle","failed"])).max(20).optional(),phases:o.z.array(o.z.enum(["thinking","tool","editing","approval","responding","unknown"])).max(20).optional()}).strict()]),Ye=o.z.object({promptTemplate:o.z.string().trim().min(1).max(2e4)}).strict(),Xe=o.z.object({cooldownMs:o.z.number().int().min(0).max(864e5).optional(),maxConcurrentRuns:o.z.number().int().min(1).max(20).default(1),whenBusy:o.z.enum(["skip","queue"]).default("skip")}).strict(),Ze=o.z.object({configHash:o.z.string().trim().min(8).max(80),name:o.z.string().trim().min(1).max(160),description:o.z.string().trim().max(1e3).optional(),source:Qe,action:Ye,policy:Xe.default({maxConcurrentRuns:1,whenBusy:"skip"}),createdAt:o.z.string().datetime(),updatedAt:o.z.string().datetime()}).strict(),et=o.z.object({type:o.z.literal("ai-session"),aiSessionId:o.z.string().trim().min(1).max(160)}).strict(),tt=o.z.object({configHash:o.z.string().trim().min(8).max(80),deploymentId:o.z.string().trim().min(1).max(240).optional(),instanceId:o.z.string().trim().min(1).max(160),origin:o.z.enum(["control-plane","controlled-instance"]).default("controlled-instance"),enabled:o.z.boolean().default(!0),target:et,localName:o.z.string().trim().min(1).max(160).optional(),createdAt:o.z.string().datetime(),updatedAt:o.z.string().datetime()}).strict(),nt=o.z.object({configHash:o.z.string().trim().min(8).max(80),deploymentId:o.z.string().trim().min(1).max(240).optional(),instanceId:o.z.string().trim().min(1).max(160),status:o.z.enum(["idle","running","disabled","error"]).default("idle"),lastTriggeredAt:o.z.string().datetime().optional(),lastCompletedAt:o.z.string().datetime().optional(),lastSkippedAt:o.z.string().datetime().optional(),lastError:o.z.string().trim().max(4e3).optional(),runCount:o.z.number().int().min(0).default(0),skippedCount:o.z.number().int().min(0).default(0)}).strict(),st=o.z.object({id:o.z.string().trim().min(1).max(160),configHash:o.z.string().trim().min(8).max(80),deploymentId:o.z.string().trim().min(1).max(240).optional(),instanceId:o.z.string().trim().min(1).max(160),eventType:o.z.enum(["manual","schedule","file-change","ai-session"]),status:o.z.enum(["started","completed","failed","skipped"]),target:et,promptPreview:o.z.string().trim().max(500),eventSummary:o.z.string().trim().max(1e3).optional(),error:o.z.string().trim().max(4e3).optional(),startedAt:o.z.string().datetime(),completedAt:o.z.string().datetime().optional()}).strict();o.z.object({schemaVersion:o.z.literal(1).default(1),configs:o.z.array(Ze).default([]),deployments:o.z.array(tt).default([]),runtime:o.z.array(nt).default([]),recentRuns:o.z.array(st).default([])}).strict();const it=o.z.object({instanceId:o.z.string().trim().min(1).max(160),instanceName:o.z.string().trim().min(1).max(160),deployment:tt,runtime:nt.optional()}).strip(),rt=st.extend({instanceName:o.z.string().trim().min(1).max(160).optional()}).strip(),ot=o.z.object({configHash:o.z.string().trim().min(8).max(80),config:Ze,deploymentCount:o.z.number().int().min(0),enabledCount:o.z.number().int().min(0),runningCount:o.z.number().int().min(0),errorCount:o.z.number().int().min(0),ownedByControlPlane:o.z.boolean(),controlPlaneDeploymentCount:o.z.number().int().min(0),deployments:o.z.array(it),recentRuns:o.z.array(rt)}).strip(),at=o.z.object({updatedAt:o.z.string().datetime(),triggers:o.z.array(ot)}).strip();function dt(e){const t=pt({source:e.source,action:e.action,policy:Xe.parse(e.policy||{})});return`trg_${function(e){const t=(new TextEncoder).encode(e),n=64*Math.ceil((t.length+9)/64),s=new Uint8Array(n);s.set(t),s[t.length]=128;const i=new DataView(s.buffer),r=8*t.length;i.setUint32(n-8,Math.floor(r/4294967296)),i.setUint32(n-4,r>>>0);const o=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),a=new Uint32Array(64);for(let e=0;e<n;e+=64){for(let t=0;t<16;t+=1)a[t]=i.getUint32(e+4*t);for(let e=16;e<64;e+=1){const t=a[e-15],n=a[e-2],s=lt(t,7)^lt(t,18)^t>>>3,i=lt(n,17)^lt(n,19)^n>>>10;a[e]=a[e-16]+s+a[e-7]+i>>>0}let[t,n,s,r,d,c,l,p]=o;for(let e=0;e<64;e+=1){const i=p+(lt(d,6)^lt(d,11)^lt(d,25))+(d&c^~d&l)+ct[e]+a[e]>>>0,o=t&n^t&s^n&s;p=l,l=c,c=d,d=r+i>>>0,r=s,s=n,n=t,t=i+((lt(t,2)^lt(t,13)^lt(t,22))+o>>>0)>>>0}o[0]=o[0]+t>>>0,o[1]=o[1]+n>>>0,o[2]=o[2]+s>>>0,o[3]=o[3]+r>>>0,o[4]=o[4]+d>>>0,o[5]=o[5]+c>>>0,o[6]=o[6]+l>>>0,o[7]=o[7]+p>>>0}return[...o].map(e=>e.toString(16).padStart(8,"0")).join("")}(JSON.stringify(t)).slice(0,24)}`}o.z.object({name:Ze.shape.name,description:Ze.shape.description,source:Qe,action:Ye,policy:Xe.partial().optional()}).strict();const ct=[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 lt(e,t){return e>>>t|e<<32-t}function pt(e){return Array.isArray(e)?e.map(pt):e&&"object"==typeof e?Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,pt(t)])):e}const ut="2026-08-01",gt=o.z.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Proxy protocol version must use YYYY-MM-DD format."),ht=o.z.string().trim().min(1).max(160).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),mt=o.z.string().datetime(),yt=o.z.string().trim().min(32).max(4096),ft=ht,It=o.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)}),o.z.NEVER}}),bt=o.z.string().trim().min(1).max(4096).transform((e,t)=>{try{return function(e){const t=e.trim();if(!t.startsWith("/")||t.startsWith("//")||t.includes("\\")||/%25/i.test(t))throw new Error("Proxy route must be a single-encoded node-agent relative route.");const n=t.split("?",1)[0];let s,i;try{s=n.split("/").map(e=>decodeURIComponent(e))}catch{throw new Error("Proxy route contains invalid percent encoding.")}if(s.some(e=>".."===e||"."===e))throw new Error("Proxy route cannot traverse outside the node-agent API.");try{i=new URL(t,"https://node-agent.invalid")}catch{throw new Error("Proxy route is invalid.")}if("https://node-agent.invalid"!==i.origin||i.username||i.password)throw new Error("Proxy route cannot select an absolute upstream URL.");return`${i.pathname}${i.search}`}(e)}catch(e){return t.addIssue({code:"custom",message:e instanceof Error?e.message:String(e)}),o.z.NEVER}}),vt=new Set(["accept","accept-language","authorization","content-type","if-match","if-none-match","range","x-request-id"]),wt=new Set(["cache-control","content-disposition","content-language","content-length","content-range","content-type","etag","last-modified","x-request-id"]),St="x-task-handoff-proxy-protocol-version",At="x-task-handoff-proxy-source-control-plane-id",kt="x-task-handoff-proxy-binding-key-id",zt="x-task-handoff-proxy-credential",Tt={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"},Ct=o.z.enum(Object.values(Tt)),xt=o.z.object({code:Ct,message:o.z.string().trim().min(1).max(2048),retryable:o.z.boolean(),details:o.z.record(o.z.string(),o.z.unknown()).optional()}).strict(),Et=o.z.enum(["active","consumed","revoked","expired"]),Nt=o.z.object({id:ht,targetNodeId:ht,tokenHash:o.z.string().trim().min(32).max(256),status:Et,createdBy:ht,expiresAt:mt,consumedByClaimId:ht.optional(),consumedAt:mt.optional(),revokedAt:mt.optional(),createdAt:mt,updatedAt:mt}).strict(),_t=Nt.omit({tokenHash:!0}),Pt=o.z.object({targetNodeId:ht,expiresInSeconds:o.z.number().int().min(60).max(3600).default(600)}).strict(),Rt=o.z.object({invite:_t,token:o.z.string().trim().min(24).max(512),proxyOrigin:It,protocolVersion:gt}).strict(),Ot=o.z.enum(["active","revoked"]),jt=o.z.object({id:ht,claimId:ht,sourceControlPlaneId:ht,targetNodeId:ht,bindingKeyId:ht,credentialHash:o.z.string().trim().min(32).max(256),status:Ot,revision:o.z.number().int().positive(),lastError:xt.optional(),revokedAt:mt.optional(),createdAt:mt,updatedAt:mt}).strict(),Mt=jt.omit({credentialHash:!0}),Dt=o.z.object({protocolVersion:gt,inviteToken:o.z.string().trim().min(24).max(512).optional(),claimId:ht,sourceControlPlaneId:ht,targetNodeId:ht.optional(),bindingKeyId:ht,credential:yt}).strict(),qt=o.z.object({sourceControlPlaneId:ht,bindingKeyId:ht,credential:yt}).strict(),Lt=o.z.object({id:ht,name:o.z.string().trim().min(1).max(160),status:o.z.enum(["unknown","online","offline","degraded"]),health:o.z.enum(["unknown","ok","degraded","failed"]),lastSeenAt:mt.optional(),capabilities:o.z.record(o.z.string(),o.z.unknown()).default({})}).strict(),$t=o.z.object({protocolVersion:gt,binding:Mt,streamId:ht,revision:o.z.number().int().nonnegative(),observedAt:mt,target:Lt}).strict(),Bt=o.z.object({type:o.z.literal("control-plane-proxy.event"),protocolVersion:gt,streamId:ht,bindingId:ht,sourceControlPlaneId:ht,targetNodeId:ht,revision:o.z.number().int().positive(),source:o.z.object({id:o.z.string().trim().min(1).max(512),seq:o.z.number().int().nonnegative()}).strict(),target:Lt,event:o.z.object({type:o.z.string().trim().min(1).max(240),topic:o.z.string().trim().min(1).max(240),createdAt:mt}).strict()}).strict(),Ut=o.z.object({type:o.z.literal("control-plane-proxy.events.ready"),protocolVersion:gt,streamId:ht,bindingId:ht,sourceControlPlaneId:ht,targetNodeId:ht,latestRevision:o.z.number().int().nonnegative(),earliestRetainedRevision:o.z.number().int().nonnegative()}).strict(),Ft=o.z.object({type:o.z.literal("control-plane-proxy.snapshot-required"),protocolVersion:gt,streamId:ht,bindingId:ht,sourceControlPlaneId:ht,targetNodeId:ht,sinceRevision:o.z.number().int().nonnegative(),latestRevision:o.z.number().int().nonnegative(),earliestRetainedRevision:o.z.number().int().nonnegative(),error:xt}).strict(),Ht=o.z.discriminatedUnion("type",[Bt,Ut,Ft]),Wt=o.z.object({protocolVersion:gt,binding:Mt,target:$t.shape.target}).strict(),Gt=o.z.object({id:ht,claimId:ht,proxyOrigin:It,requestedName:o.z.string().trim().min(1).max(160).optional(),sourceControlPlaneId:ht,targetNodeId:ht.optional(),bindingKeyId:ht,credential:yt,status:o.z.enum(["pending","compensation-required"]),createdAt:mt,updatedAt:mt,expiresAt:mt}).strict();Gt.omit({credential:!0});const Vt=o.z.object({id:ht,nodeId:ht,proxyOrigin:It,proxyBindingId:ht,targetNodeId:ht,sourceControlPlaneId:ht,bindingKeyId:ht,credential:yt,createdAt:mt,updatedAt:mt}).strict(),Kt="2026-08-01",Jt=o.z.string(),Qt=o.z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Yt=o.z.string().datetime(),Xt=o.z.record(o.z.string(),o.z.string()).default({}),Zt=o.z.record(o.z.string(),o.z.string()).default({}),en=o.z.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Protocol version must use YYYY-MM-DD format.");function tn(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.")}}o.z.object({encoding:o.z.enum(["utf8","base64"]),data:o.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 nn=/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/,sn=/^sha256:([a-fA-F0-9]{64})$/,rn=/^(?:localhost|[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?)(?::[1-9][0-9]{0,4})?$/,on=/^[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*$/;function an(e){const t=e.trim();if(!t||t.length>512||t.includes("://")||/\s/.test(t))throw new Error("Docker image reference must not contain a URL scheme or whitespace.");const n=t.indexOf("@");if(-1!==n&&n!==t.lastIndexOf("@"))throw new Error("Docker image reference contains more than one digest separator.");const s=-1===n?void 0:t.slice(n+1),i=-1===n?t:t.slice(0,n),r=s?sn.exec(s):void 0;if(s&&!r)throw new Error("Docker image digest must use sha256 followed by 64 hexadecimal characters.");const o=i.lastIndexOf("/"),a=i.lastIndexOf(":"),d=a>o,c=d?i.slice(a+1):void 0,l=d?i.slice(0,a):i;if(c&&!nn.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&&!rn.test(p[0].toLowerCase()))throw new Error("Docker image registry host or port is invalid.");if(!g.length||g.some(e=>!on.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 dn(e){const t=an(e),n=t.indexOf("@"),s=-1===n?void 0:t.slice(n+1),i=-1===n?t:t.slice(0,n),r=i.lastIndexOf("/"),o=i.lastIndexOf(":"),a=o>r;return{reference:t,repository:a?i.slice(0,o):i,tag:a?i.slice(o+1):void 0,digest:s}}const cn=o.z.string().trim().min(1).max(512).transform((e,t)=>{try{return an(e)}catch(e){return t.addIssue({code:"custom",message:e instanceof Error?e.message:String(e)}),o.z.NEVER}}),ln=o.z.string().trim().transform((e,t)=>{const n=sn.exec(e);return n?`sha256:${n[1].toLowerCase()}`:(t.addIssue({code:"custom",message:"Docker image digest must use sha256 followed by 64 hexadecimal characters."}),o.z.NEVER)}),pn=o.z.object({codexModelHash:Qt.nullable().optional(),claudeModelHash:Qt.nullable().optional()}).strict().default({}),un=o.z.object({imageId:Qt,tag:o.z.string().trim().min(1).max(128).regex(nn).optional()}).strict(),gn=o.z.discriminatedUnion("type",[o.z.object({type:o.z.literal("image"),imageSelection:un}).strict(),o.z.object({type:o.z.literal("template"),environmentTemplateId:Qt}).strict()]),hn=o.z.enum(["creating","ready","failed","deleting"]),mn=o.z.enum(["linux","darwin","win32","freebsd","openbsd","aix","sunos","unknown"]),yn=o.z.enum(["x64","arm64","arm","ia32","ppc64","s390x","riscv64","unknown"]),fn=o.z.object({code:o.z.string().trim().min(1).max(120),message:o.z.string().trim().min(1).max(2048),phase:o.z.enum(["validate","commit","inspect","security-check","persist","delete","recovery"]).optional()}).strict(),In=o.z.object({templateId:Qt,nodeId:Qt,imageId:ln,name:o.z.string().trim().min(1).max(160),platform:mn,architecture:yn}).strict(),bn=o.z.enum(["data","agent-home","workspace"]),vn=o.z.object({deleteVolumes:o.z.boolean()}).strict(),wn=o.z.object({role:bn,name:o.z.string().trim().min(1).max(255),mountPath:o.z.string().trim().startsWith("/").max(4096),status:o.z.enum(["deleted","retained","missing","failed"]),error:o.z.object({code:o.z.string().trim().min(1).max(120),message:o.z.string().trim().min(1).max(2048)}).strict().optional()}).strict(),Sn=o.z.object({instanceId:Qt,containerDeleted:o.z.boolean(),completed:o.z.boolean(),deletedVolumes:o.z.array(wn),retainedVolumes:o.z.array(wn),volumeResults:o.z.array(wn)}).strict(),An={img_default:"market_taskhandoff_browser",img_codex:"market_taskhandoff_codex",img_ai:"market_taskhandoff_ai"};function kn(e,t){if(e&&"object"==typeof e&&!Array.isArray(e)){const t=e;return{imageId:"string"==typeof t.imageId&&An[t.imageId]||t.imageId,..."string"==typeof t.tag?{tag:t.tag}:{}}}if("string"==typeof t)return{imageId:An[t]||t}}function zn(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,{defaultImageId:n,...s}=t;return{...s,defaultImageSelection:kn(t.defaultImageSelection,n)}}const Tn=o.z.object({id:Qt,name:o.z.string().trim().min(1).max(120),kind:o.z.enum(["tty","gui","web"]),source:o.z.enum(["builtin","custom"]),availability:o.z.enum(["available","missing-dependency"]),capabilities:o.z.object({automation:o.z.enum(["cdp"]).optional(),supportsCwdSelection:o.z.boolean().default(!1)}).strict().default({supportsCwdSelection:!1}),diagnosticCode:o.z.enum(["APP_EXECUTABLE_NOT_FOUND"]).optional()}).strict(),Cn=o.z.object({code:o.z.enum(["APP_CATALOG_INVALID"]),message:o.z.string().trim().min(1).max(500)}).strict(),xn=o.z.object({items:o.z.array(Tn).max(256),observedAt:Yt,issues:o.z.array(Cn).max(32).default([])}).strict(),En=o.z.object({id:Qt,name:o.z.string().trim().min(1).max(160),sourceInstanceId:Qt,nodeId:Qt,imageId:ln.optional(),internalTag:o.z.string().trim().min(1).max(512).optional(),platform:mn.optional(),architecture:yn.optional(),sizeBytes:o.z.number().int().nonnegative().optional(),status:hn,error:fn.optional(),createdAt:Yt,updatedAt:Yt}).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."})}),Nn=o.z.enum(["apt","dnf","brew","npm"]),_n=o.z.enum(["user","passwordless-sudo","root"]),Pn=o.z.object({platform:mn,arch:yn,installers:o.z.array(Nn).max(8),privilege:_n,installerAccess:o.z.object({npmGlobalWritable:o.z.boolean().optional()}).strict().optional()}).strict(),Rn=o.z.enum(["installed","not-installed","broken","unsupported"]),On=o.z.enum(["recipe","bundled","external","none"]),jn=o.z.object({code:o.z.enum(["BUNDLED","EXTERNALLY_MANAGED","ALREADY_INSTALLED","NOT_INSTALLED","UNSUPPORTED_PLATFORM","INSTALLER_UNAVAILABLE","INSTALLER_NOT_WRITABLE","INSUFFICIENT_PRIVILEGE","OPERATION_IN_PROGRESS"]),message:o.z.string().trim().min(1).max(500)}).strict(),Mn=o.z.object({id:Qt,name:o.z.string().trim().min(1).max(120),kind:o.z.enum(["tty","gui","web"]),description:o.z.string().trim().max(500).optional(),state:Rn,managementSource:On,version:o.z.string().trim().max(120).optional(),canInstall:o.z.boolean(),canUninstall:o.z.boolean(),installReason:jn.optional(),uninstallReason:jn.optional(),activeJobId:Qt.optional()}).strict(),Dn=o.z.enum(["install","uninstall"]),qn=o.z.enum(["queued","running","succeeded","failed","cancelled","interrupted"]),Ln=o.z.object({current:o.z.number().finite().nonnegative().optional(),total:o.z.number().finite().positive().optional(),unit:o.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"]}),$n=o.z.object({executable:o.z.string().trim().min(1).max(4096),args:o.z.array(o.z.string().max(4096)).max(128)}).strict(),Bn=o.z.object({code:o.z.string().trim().min(1).max(120).regex(/^[a-z0-9][a-z0-9._-]*$/),message:o.z.string().trim().min(1).max(4096),retryable:o.z.boolean(),sessionIds:o.z.array(Qt).max(64).optional()}).strict(),Un=o.z.object({id:Qt,requestId:Qt.optional(),appId:Qt,operation:Dn,state:qn,phase:o.z.string().trim().min(1).max(120).optional(),progress:Ln.optional(),command:$n.optional(),logTail:o.z.string().max(32768).optional(),logTruncated:o.z.boolean().optional(),error:Bn.optional(),requestedAt:Yt,startedAt:Yt.optional(),finishedAt:Yt.optional(),updatedAt:Yt}).strict(),Fn=o.z.object({streamId:Qt,sequence:o.z.number().int().nonnegative(),capabilities:Pn,apps:o.z.array(Mn).max(256),activeJobs:o.z.array(Un).max(256),recentJobs:o.z.array(Un).max(256),observedAt:Yt}).strict(),Hn=o.z.object({requestId:Qt.optional()}).strict(),Wn=o.z.object({job:Un}).strict();o.z.object({type:o.z.literal("app-management"),streamId:Qt,sequence:o.z.number().int().nonnegative(),observedAt:Yt,job:Un.optional(),snapshot:Fn.optional()}).strict().refine(e=>void 0!==e.job||void 0!==e.snapshot,{message:"An app management event requires a job or snapshot."});const Gn=o.z.object({component:o.z.enum(["control-plane","node-agent","controlled-instance"]),packageName:o.z.string().trim().max(160).optional(),packageVersion:o.z.string().trim().max(80).optional(),protocolVersion:Jt.optional(),buildId:o.z.string().trim().max(160).optional(),builtAt:o.z.string().trim().max(120).optional(),gitCommit:o.z.string().trim().max(120).optional(),imageRef:o.z.string().trim().max(512).optional(),imageDigest:o.z.string().trim().max(240).optional()}).strict(),Vn=o.z.enum(["stable","beta","alpha"]),Kn=o.z.object({packageName:o.z.literal("@task-handoff/controlled-instance"),version:o.z.string().trim().min(1).max(80),platform:o.z.string().trim().min(1).max(40),arch:o.z.string().trim().min(1).max(40),formatVersion:o.z.number().int().positive(),launcherAbi:o.z.number().int().positive(),entrypoint:o.z.string().trim().min(1).max(512),sha256:o.z.string().regex(/^[a-f0-9]{64}$/)}).strict(),Jn=o.z.object({code:o.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:o.z.string().trim().min(1).max(4096),expectedVersion:o.z.string().trim().min(1).max(80).optional(),actualVersion:o.z.string().trim().min(1).max(80).optional(),retryable:o.z.boolean().default(!1)}).strict(),Qn=o.z.object({desiredVersion:o.z.string().trim().min(1).max(80),actualVersion:o.z.string().trim().min(1).max(80).optional(),phase:o.z.enum(["pending","draining","installing","restarting","verifying","matched","failed"]),attempt:o.z.number().int().nonnegative().default(0),lastAttemptAt:Yt.optional(),matchedAt:Yt.optional(),error:Jn.optional()}).strict(),Yn=o.z.object({runningInstanceCount:o.z.number().int().nonnegative(),stoppedInstanceCount:o.z.number().int().nonnegative(),activeInstanceCount:o.z.number().int().nonnegative(),restartInstanceCount:o.z.number().int().nonnegative(),runningInstanceIds:o.z.array(Qt).max(1024).default([]),stoppedInstanceIds:o.z.array(Qt).max(1024).default([]),activeInstanceIds:o.z.array(Qt).max(1024).default([])}).strict(),Xn=o.z.object({phase:o.z.enum(["queued","updating-node","restarting-node","converging-instances","succeeded","degraded","failed"]),desiredVersion:o.z.string().trim().min(1).max(80),nodeVersion:o.z.string().trim().min(1).max(80).optional(),expectedInstanceIds:o.z.array(Qt).max(1024).default([]),expectedInstanceCount:o.z.number().int().nonnegative(),matchedInstanceCount:o.z.number().int().nonnegative(),pendingInstanceCount:o.z.number().int().nonnegative(),failedInstanceCount:o.z.number().int().nonnegative(),deferredInstanceCount:o.z.number().int().nonnegative().default(0)}).strict(),Zn=o.z.object({channel:Vn.default("stable")}).strict(),es=o.z.object({source:o.z.literal("npm"),channel:Vn,currentVersion:o.z.string().trim().max(240).optional(),availableVersion:o.z.string().trim().min(1).max(240),artifactRef:o.z.string().trim().min(1).max(512).optional(),runtimeArtifacts:o.z.array(Kn).default([]),impact:Yn,updateAvailable:o.z.boolean(),supported:o.z.boolean().default(!0),reason:o.z.string().trim().max(2048).optional(),checkedAt:Yt,preflightToken:o.z.string().trim().min(16).max(240).optional()}).strict(),ts=o.z.object({id:Qt,nodeId:Qt,source:o.z.literal("npm"),channel:Vn,fromVersion:o.z.string().trim().max(240).optional(),toVersion:o.z.string().trim().min(1).max(240),artifactRef:o.z.string().trim().min(1).max(512).optional(),runtimeArtifacts:o.z.array(Kn).default([]),impact:Yn,rollout:Xn,status:o.z.enum(["queued","updating-node","restarting-node","converging-instances","succeeded","degraded","failed"]),error:Jn.optional(),startedAt:Yt.optional(),completedAt:Yt.optional(),createdAt:Yt,updatedAt:Yt}).strict(),ns=o.z.object({channel:Vn,targetVersion:o.z.string().trim().min(1).max(240),preflightToken:o.z.string().trim().min(16).max(240)}).strict(),ss=o.z.object({type:o.z.enum(["branch","tag","commit"]),name:o.z.string().trim().min(1).max(240).optional(),commit:o.z.string().trim().max(80).optional()}).strict(),is=o.z.object({type:o.z.enum(["none","ssh-key","https-token"]).default("none"),secretId:o.z.string().trim().min(1).max(120).optional()}).strict(),rs=o.z.object({depth:o.z.number().int().positive().max(1e5).optional(),submodules:o.z.boolean().default(!1),lfs:o.z.boolean().default(!1),subdirectory:o.z.string().trim().max(240).default("")}).strict();o.z.object({id:Qt,name:o.z.string().trim().min(1).max(160),url:o.z.string().trim().min(1).max(2048),provider:o.z.string().trim().max(80).optional(),ref:ss.default({type:"branch",name:"main"}),auth:is.default({type:"none"}),clone:rs.default({submodules:!1,lfs:!1,subdirectory:""}),defaultImageSelection:un.optional(),labels:Xt,createdAt:Yt,updatedAt:Yt}).strict();const os=o.z.object({id:Qt,nodeId:Qt,name:o.z.string().trim().min(1).max(160),path:o.z.string().trim().min(1).max(4096),defaultImageSelection:un.optional(),labels:Xt,createdAt:Yt,updatedAt:Yt}).strict(),as=o.z.discriminatedUnion("type",[o.z.object({type:o.z.literal("git-repository"),repositoryId:Qt.optional(),url:o.z.string().trim().min(1).max(2048),provider:o.z.string().trim().max(80).optional(),ref:ss.default({type:"branch",name:"main"}),auth:is.default({type:"none"}),clone:rs.default({submodules:!1,lfs:!1,subdirectory:""})}).strict(),o.z.object({type:o.z.literal("git-template"),url:o.z.string().trim().min(1).max(2048),templateId:o.z.string().trim().min(1).max(120).optional(),ref:ss.default({type:"branch",name:"main"}),auth:is.default({type:"none"}),clone:rs.default({submodules:!1,lfs:!1,subdirectory:""})}).strict(),o.z.object({type:o.z.literal("local-folder"),localFolderId:Qt.optional(),path:o.z.string().trim().min(1).max(4096),ownerNodeId:Qt.optional()}).strict()]),ds=o.z.object({mode:o.z.enum(["local-bind","git-clone","empty-volume","persistent-volume"]),path:o.z.string().trim().min(1).max(4096).default("/workspace"),volumeName:o.z.string().trim().max(240).optional(),readOnly:o.z.boolean().default(!1)}).strict(),cs=o.z.enum(["codex","claude"]),ls=o.z.object({id:Qt,name:o.z.string().trim().min(1).max(160),source:as,defaultImageSelection:un.optional(),defaultNodeId:Qt.optional(),defaultRuntimeId:Qt.optional(),workspacePolicy:ds,labels:Xt,createdAt:Yt,updatedAt:Yt}).strict(),ps=o.z.object({id:Qt,name:o.z.string().trim().min(1).max(160),endpoint:o.z.string().trim().min(1).max(2048),key:o.z.string().trim().min(1).max(4096),model:o.z.string().trim().min(1).max(240),app:cs,enabled:o.z.boolean().default(!0),order:o.z.number().int().min(0).max(1e6).default(0),labels:Xt,createdAt:Yt,updatedAt:Yt}).strict(),us=ps.omit({key:!0}).extend({keyPreview:o.z.string().trim().min(1).max(160),keySet:o.z.boolean()}).strict(),gs=us.extend({referenceCount:o.z.number().int().min(0)}).strict(),hs=o.z.object({instanceId:Qt,codexModelHash:Qt.optional(),claudeModelHash:Qt.optional(),updatedAt:Yt}).strict(),ms=o.z.discriminatedUnion("type",[o.z.object({type:o.z.literal("control-plane"),name:ps.shape.name,enabled:ps.shape.enabled,order:ps.shape.order}).strict(),o.z.object({type:o.z.literal("node"),nodeId:Qt,name:ps.shape.name,enabled:ps.shape.enabled,order:ps.shape.order,referenceCount:o.z.number().int().min(0)}).strict()]),ys=o.z.object({id:Qt,model:us,locations:o.z.array(ms).min(1),referenceCount:o.z.number().int().min(0).default(0)}).strict(),fs=o.z.object({nodeId:Qt,code:o.z.string().trim().min(1).max(120),message:o.z.string().trim().min(1).max(2e3)}).strict(),Is=o.z.object({models:o.z.array(ys),nodeDiagnostics:o.z.array(fs).default([]),updatedAt:Yt}).strict();function bs(e){const t={app:cs.parse(e.app),endpoint:ps.shape.endpoint.parse(e.endpoint),key:ps.shape.key.parse(e.key),model:ps.shape.model.parse(e.model)};return`mdl_${a.createHash("sha256").update(JSON.stringify(t)).digest("hex")}`}ps.omit({id:!0,createdAt:!0,updatedAt:!0}).strict().partial().strict(),o.z.object({modelSelection:pn,codexModelHash:Qt.optional(),claudeModelHash:Qt.optional()}).strict();const vs=o.z.enum(["market","custom"]),ws=o.z.enum(["active","deprecated","yanked"]),Ss=o.z.discriminatedUnion("kind",[o.z.object({kind:o.z.literal("builtin"),key:o.z.string().trim().min(1).max(120)}).strict(),o.z.object({kind:o.z.literal("remote"),url:o.z.string().trim().url().max(2048),mediaType:o.z.enum(["image/png","image/jpeg","image/webp"]).optional(),digest:ln.optional()}).strict()]),As={kind:"builtin",key:"default-image-cover"},ks=o.z.array(o.z.string().trim().min(1).max(80)).default([]),zs=o.z.array(o.z.string().trim().min(1).max(120)).default([]),Ts=o.z.record(o.z.string().trim().min(2).max(35),o.z.string().trim().min(1).max(4096)),Cs=o.z.object({os:o.z.string().trim().min(1).max(40),architecture:o.z.string().trim().min(1).max(40),digest:ln.optional(),downloadSizeBytes:o.z.number().int().positive().optional(),unpackedSizeBytes:o.z.number().int().positive().optional()}).strict(),xs=o.z.object({name:o.z.string().trim().min(1).max(128).regex(nn),version:o.z.string().trim().min(1).max(160).optional(),reference:cn,manifestDigest:ln.optional(),publishedAt:Yt.optional(),platforms:o.z.array(Cs).default([]),status:ws.default("active")}).strict(),Es=o.z.object({id:Qt,publisher:o.z.string().trim().min(1).max(160),slug:o.z.string().trim().min(1).max(160),name:o.z.string().trim().min(1).max(160),description:o.z.string().trim().min(1).max(4096),localizedDescriptions:Ts.optional(),cover:Ss.optional(),repository:o.z.string().trim().min(1).max(512),defaultTag:o.z.string().trim().min(1).max(128).regex(nn),tags:o.z.array(xs).min(1),capabilities:ks,optionalApps:zs,defaultEnv:Zt,labels:Xt,status:ws.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."})}),Ns=o.z.object({protocolVersion:en,catalogId:Qt,revision:o.z.string().trim().min(1).max(240),source:o.z.enum(["embedded","remote","cache"]),generatedAt:Yt,expiresAt:Yt.optional(),items:o.z.array(Es)}).strict(),_s=o.z.object({source:o.z.enum(["embedded","remote","cache"]),state:o.z.enum(["ready","refreshing","stale","failed"]),revision:o.z.string().trim().min(1).max(240),updatedAt:Yt,error:o.z.string().trim().max(4096).optional()}).strict(),Ps=o.z.object({id:Qt,origin:o.z.literal("custom"),name:o.z.string().trim().min(1).max(160),description:o.z.string().trim().max(4096).optional(),localizedDescriptions:Ts.optional(),cover:Ss.optional(),reference:cn,repository:o.z.string().trim().min(1).max(512),tag:o.z.string().trim().min(1).max(128).regex(nn).optional(),pullPolicy:o.z.literal("if-not-present").default("if-not-present"),capabilities:ks,optionalApps:zs,defaultEnv:Zt,labels:Xt,createdAt:Yt,updatedAt:Yt}).strict(),Rs=o.z.object({name:o.z.string().trim().min(1).max(128).regex(nn),version:o.z.string().trim().min(1).max(160).optional(),reference:cn,manifestDigest:ln.optional(),status:ws}).strict(),Os=o.z.object({id:Qt,origin:vs,name:o.z.string().trim().min(1).max(160),description:o.z.string().trim().max(4096).optional(),localizedDescriptions:Ts.optional(),cover:Ss,repository:o.z.string().trim().min(1).max(512),tag:o.z.string().trim().min(1).max(128).regex(nn).optional(),availableTags:o.z.array(Rs),reference:cn,digest:ln.optional(),downloadSizeBytes:o.z.number().int().positive().optional(),unpackedSizeBytes:o.z.number().int().positive().optional(),capabilities:ks,optionalApps:zs,defaultEnv:Zt,labels:Xt,readOnly:o.z.boolean(),lifecycleStatus:ws.optional(),market:o.z.object({catalogId:Qt,catalogRevision:o.z.string().trim().min(1).max(240),publisher:o.z.string().trim().min(1).max(160),version:o.z.string().trim().min(1).max(160).optional()}).strict().optional()}).strict(),js=o.z.object({id:Qt,origin:vs,name:o.z.string().trim().min(1).max(160),description:o.z.string().trim().max(4096).optional(),localizedDescriptions:Ts.optional(),cover:Ss.optional(),repository:o.z.string().trim().min(1).max(512),tag:o.z.string().trim().min(1).max(128).regex(nn).optional(),requestedReference:cn,resolvedDigest:ln.optional(),resolvedReference:cn.optional(),downloadSizeBytes:o.z.number().int().positive().optional(),pullPolicy:o.z.literal("if-not-present").default("if-not-present"),capabilities:ks,optionalApps:zs,defaultEnv:Zt,labels:Xt,market:o.z.object({catalogId:Qt,catalogRevision:o.z.string().trim().min(1).max(240),publisher:o.z.string().trim().min(1).max(160),version:o.z.string().trim().min(1).max(160).optional()}).strict().optional(),createdAt:Yt,updatedAt:Yt}).strict(),Ms=o.z.object({phase:o.z.enum(["checking-image","pulling-image","resolving-image","ready","failed"]),requestedReference:cn,generation:o.z.number().int().nonnegative().default(0),error:o.z.string().trim().max(4096).optional(),startedAt:Yt,updatedAt:Yt}).strict(),Ds="image.pull.terminal.output",qs="image.pull.terminal.finished",Ls=o.z.object({instanceId:Qt,generation:o.z.number().int().nonnegative(),requestedReference:cn,sequence:o.z.number().int().nonnegative(),observedAt:Yt}).strict(),$s=Ls.extend({data:o.z.string().min(1).max(65536),replay:o.z.boolean().optional()}).strict(),Bs=Ls.extend({outcome:o.z.enum(["succeeded","failed"])}).strict(),Us=Ls.extend({status:o.z.enum(["connecting","pulling","extracting","complete","failed"]),layers:o.z.object({total:o.z.number().int().nonnegative(),completed:o.z.number().int().nonnegative(),downloaded:o.z.number().int().nonnegative(),downloading:o.z.number().int().nonnegative(),extracting:o.z.number().int().nonnegative()}).strict(),bytes:o.z.object({current:o.z.number().finite().nonnegative(),total:o.z.number().finite().positive()}).strict().optional(),percent:o.z.number().finite().min(0).max(100).optional(),message:o.z.string().trim().min(1).max(500),terminalTail:o.z.string().max(262144).optional(),terminalTruncated:o.z.boolean().optional()}).strict();function Fs(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,s=new Set(["id","origin","name","description","localizedDescriptions","cover","reference","repository","tag","image","registry","pullPolicy","capabilities","optionalApps","defaultEnv","labels","createdAt","updatedAt"]);for(const e of Object.keys(n))s.has(e)||t?.({imageId:"string"==typeof n.id?n.id:void 0,field:e});const i="string"==typeof n.id?n.id:void 0,r="string"==typeof n.image?n.image:void 0;void 0!==r&&t?.({imageId:i,field:"image"}),Object.prototype.hasOwnProperty.call(n,"registry")&&t?.({imageId:i,field:"registry"});let o,a="string"==typeof n.reference?n.reference:r;if(a)try{a=an(a)}catch{if(!a.includes("@")&&a.lastIndexOf(":")<=a.lastIndexOf("/"))try{a=an(`${a}:latest`),t?.({imageId:i,field:"reference:implicit-latest"})}catch{}}try{o=a?dn(a):void 0}catch{}return{id:n.id,origin:"custom",name:n.name,description:n.description,localizedDescriptions:n.localizedDescriptions,cover:yi(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 Hs=o.z.discriminatedUnion("kind",[o.z.object({kind:o.z.literal("direct")}).strict(),o.z.object({kind:o.z.literal("control-plane-proxy"),proxyId:Qt,proxyBindingId:Qt,targetNodeId:Qt}).strict()]),Ws=o.z.object({reachability:o.z.enum(["unknown","reachable","unreachable"]),bindingStatus:o.z.enum(["unknown","active","revoked"]),bindingRevision:o.z.number().int().positive().optional(),streamId:o.z.string().trim().min(1).max(160).optional(),revision:o.z.number().int().nonnegative().optional(),observedAt:Yt.optional(),target:Lt.optional(),lastError:xt.optional(),updatedAt:Yt}).strict(),Gs=o.z.object({id:Qt,name:o.z.string().trim().min(1).max(160),connectionMode:o.z.enum(["local-ipc","local-loopback","direct-http","reverse-wss","control-plane-proxy"]).default("direct-http"),connectionPath:Hs.default({kind:"direct"}),connectionEnabled:o.z.boolean().default(!0),auth:o.z.object({mode:o.z.enum(["local-static-key","paired-hmac","proxy-binding"]).default("local-static-key"),keyId:Qt.optional(),secret:o.z.string().trim().max(4096).optional(),pairedAt:Yt.optional(),pairing:o.z.object({status:o.z.enum(["pending","paired","expired"]).default("pending"),joinToken:o.z.string().trim().max(4096).optional(),expiresAt:Yt.optional()}).strict().optional()}).strict().default({mode:"local-static-key"}),endpoint:o.z.string().trim().max(2048).optional(),controlEndpoint:o.z.string().trim().max(2048).optional(),containerEndpoint:o.z.string().trim().max(2048).optional(),publicWebBase:o.z.string().trim().max(2048).optional(),status:o.z.enum(["unknown","online","offline","degraded"]).default("unknown"),health:o.z.enum(["unknown","ok","degraded","failed"]).default("unknown"),capabilities:o.z.record(o.z.string(),o.z.unknown()).default({}),proxyState:Ws.optional(),appInventory:xn.optional(),labels:Xt,lastSeenAt:Yt.optional(),createdAt:Yt,updatedAt:Yt}).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."})}),Vs=o.z.object({id:Qt,nodeId:Qt,name:o.z.string().trim().min(1).max(160),type:o.z.enum(["docker","kubernetes","local"]),status:o.z.enum(["unknown","online","offline","degraded"]).default("unknown"),accessStrategy:o.z.enum(["node-proxy","direct-port","kubernetes-ingress","kubernetes-port-forward"]).default("node-proxy"),capabilities:o.z.record(o.z.string(),o.z.unknown()).default({}),labels:Xt,createdAt:Yt,updatedAt:Yt}).strict(),Ks=o.z.object({instanceId:Qt,runtimeKind:o.z.literal("docker"),state:o.z.enum(["pending","available","stopped","unavailable"]),sampledAt:Yt,cpu:o.z.object({usagePercent:o.z.number().nonnegative()}).strict().optional(),memory:o.z.object({usageBytes:o.z.number().nonnegative(),limitBytes:o.z.number().nonnegative().optional(),usagePercent:o.z.number().nonnegative().optional()}).strict().optional(),network:o.z.object({rxBytes:o.z.number().nonnegative(),txBytes:o.z.number().nonnegative()}).strict().optional(),blockIo:o.z.object({readBytes:o.z.number().nonnegative(),writeBytes:o.z.number().nonnegative()}).strict().optional(),pids:o.z.number().int().nonnegative().optional(),error:o.z.string().trim().max(2048).optional()}).strict(),Js=o.z.object({ok:o.z.boolean().optional(),role:o.z.string().optional(),nodeId:Qt.optional(),platform:mn.optional(),arch:yn.optional(),protocolVersion:Jt.optional(),build:Gn.strip().optional(),process:o.z.object({pid:o.z.number().int().positive(),startIdentity:o.z.string().trim().min(1).optional()}).strip().optional(),listener:o.z.object({host:o.z.string().trim().min(1),port:o.z.number().int().min(1).max(65535)}).strip().optional(),instanceProxy:o.z.object({requests:o.z.number().int().nonnegative(),active:o.z.number().int().nonnegative(),completed:o.z.number().int().nonnegative(),aborted:o.z.number().int().nonnegative(),limitRejected:o.z.number().int().nonnegative(),responseBytes:o.z.number().nonnegative(),totalDurationMs:o.z.number().nonnegative(),maxResponseBytes:o.z.number().int().nonnegative()}).partial().strip().optional(),serverTime:Yt.optional()}).strip(),Qs=o.z.object({bindScope:o.z.enum(["loopback","all-ipv4"]),port:o.z.number().int().min(1).max(65535)}).strict().extend({host:o.z.enum(["127.0.0.1","0.0.0.0"]),status:o.z.enum(["listening","error"]),source:o.z.enum(["bootstrap","persisted"]),error:o.z.string().trim().max(2048).optional()}).strict(),Ys=o.z.object({nodeId:Qt,joinToken:o.z.string().trim().min(1),expiresAt:Yt}).passthrough(),Xs=o.z.object({nodeId:Qt,keyId:Qt,secret:o.z.string().regex(/^[A-Za-z0-9_-]{32,128}$/),pairedAt:Yt}).strict(),Zs=o.z.object({id:Qt,keyId:Qt,name:o.z.string().trim().min(1).max(160).optional(),pairedAt:Yt,updatedAt:Yt,current:o.z.boolean()}).passthrough(),ei=o.z.object({keyId:Qt,revoked:o.z.literal(!0),revokedAt:Yt}).strict(),ti=o.z.object({id:Qt,pairingKeyId:Qt,url:o.z.string().trim().min(1).max(2048),name:o.z.string().trim().min(1).max(160).optional(),enabled:o.z.boolean(),createdAt:Yt,updatedAt:Yt,status:o.z.enum(["disabled","connecting","connected","reconnecting","failed"]),lastConnectedAt:Yt.optional(),lastDisconnectedAt:Yt.optional(),error:o.z.string().optional()}).passthrough(),ni=o.z.object({pairing:Zs,connection:o.z.object({id:Qt,pairingKeyId:Qt,url:o.z.string().trim().min(1).max(2048),name:o.z.string().trim().min(1).max(160).optional(),enabled:o.z.boolean(),createdAt:Yt,updatedAt:Yt}).passthrough(),tunnel:o.z.object({status:o.z.enum(["disabled","saved","connecting","connected","failed"]),error:o.z.string().trim().max(2048).optional()}).passthrough()}).passthrough(),si=o.z.object({deleted:o.z.boolean().optional()}).passthrough(),ii=o.z.object({repository:o.z.string().trim().optional(),tag:o.z.string().trim().optional(),id:o.z.string().trim(),createdSince:o.z.string().trim().optional(),size:o.z.string().trim().optional(),sizeBytes:o.z.number().int().nonnegative().optional(),reference:o.z.string().trim().min(1),repoDigests:o.z.array(o.z.string().trim().min(1).max(512)).default([])}).passthrough(),ri=o.z.object({image:Os,status:o.z.enum(["available","pull-required","unknown"]),localImage:ii.optional(),localSizeBytes:o.z.number().int().nonnegative().optional(),downloadSizeBytes:o.z.number().int().positive().optional(),unpackedSizeBytes:o.z.number().int().positive().optional(),error:o.z.string().trim().max(2048).optional()}).strict(),oi=o.z.lazy(()=>o.z.object({name:o.z.string().trim().min(1),path:o.z.string().trim().min(1).max(4096),children:o.z.array(oi)}).passthrough()),ai=o.z.object({status:o.z.number().int().min(100).max(599).optional(),headers:o.z.record(o.z.string(),o.z.string()).optional(),bodyBase64:o.z.string().optional()}).passthrough(),di=o.z.object({strategy:o.z.enum(["node-proxy","direct-port","kubernetes-ingress","kubernetes-port-forward"]).default("node-proxy"),web:o.z.string().trim().max(2048).optional(),api:o.z.string().trim().max(2048).optional(),vnc:o.z.string().trim().max(2048).optional(),tty:o.z.string().trim().max(2048).optional(),logs:o.z.string().trim().max(2048).optional(),status:o.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown")}).strict(),ci=o.z.object({strategy:o.z.enum(["control-plane-proxy","direct-port","node-proxy","kubernetes-ingress","kubernetes-port-forward"]).default("control-plane-proxy"),web:o.z.string().trim().max(2048).optional(),api:o.z.string().trim().max(2048).optional(),ws:o.z.string().trim().max(2048).optional(),status:o.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown")}).strict().default({strategy:"control-plane-proxy",status:"unknown"}),li=o.z.object({mode:o.z.enum(["local-bind","git-clone","empty-volume","persistent-volume"]).optional(),status:o.z.enum(["unknown","pending","ready","failed"]).default("unknown"),path:o.z.string().trim().max(4096).optional(),resolvedCommit:o.z.string().trim().max(120).optional(),error:o.z.string().trim().max(2048).optional()}).passthrough(),pi=o.z.object({id:Qt,name:o.z.string().trim().min(1).max(160),projectId:Qt.optional(),source:as,sourceSnapshot:o.z.record(o.z.string(),o.z.unknown()).default({}),modelSelection:pn,nodeId:Qt,runtimeId:Qt,imageSelection:un.optional(),environmentSource:gn.optional(),environmentTemplateOrigin:In.optional(),imageSnapshot:js.optional(),imageProvisioning:Ms.optional(),stateRevision:o.z.number().int().min(0).default(0),processIncarnationId:o.z.string().trim().min(1).max(120).optional(),status:o.z.enum(["created","provisioning","starting","registering","registered","running","stopping","stopped","deleting","failed","unhealthy"]).default("created"),health:o.z.enum(["unknown","ok","degraded","failed"]).default("unknown"),connectionStatus:o.z.enum(["unknown","online","offline","endpoint-unreachable"]).default("unknown"),agentStatus:o.z.enum(["unknown","online","offline"]).default("unknown"),targetStatus:o.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown"),uiAccessStatus:o.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown"),controlMode:o.z.enum(["standalone","controlled"]).default("controlled"),protocolVersion:Jt.optional(),instanceVersion:o.z.string().trim().max(80).optional(),build:Gn.optional(),runtimeVersion:Qn.optional(),ready:o.z.boolean().default(!1),capabilities:o.z.record(o.z.string(),o.z.unknown()).default({}),appInventory:xn.optional(),config:o.z.object({autoImportAgentConfigs:o.z.boolean().default(!0),defaultCodexPermissionMode:Q.default("ask")}).strict().default({autoImportAgentConfigs:!0,defaultCodexPermissionMode:"ask"}),workspace:li.default({status:"unknown"}),target:di.default({strategy:"direct-port",status:"unknown"}),access:ci,apps:o.z.object({runningCount:o.z.number().int().min(0).default(0),problemCount:o.z.number().int().min(0).default(0),updatedAt:Yt.optional(),revision:o.z.number().int().min(0).optional()}).strict().default({runningCount:0,problemCount:0}),aiSessions:je.default(()=>({runningCount:0,waitingCount:0,staleCount:0,sessions:[],updatedAt:(new Date).toISOString()})),triggers:o.z.object({enabledCount:o.z.number().int().min(0).default(0),runningCount:o.z.number().int().min(0).default(0),errorCount:o.z.number().int().min(0).default(0),configs:o.z.array(o.z.object({configHash:o.z.string().trim().min(1),config:Ze,deployments:o.z.array(tt).default([]),runtime:o.z.array(nt).default([])}).strict()).default([]),recentRuns:o.z.array(st).default([])}).strict().optional(),runtime:o.z.object({kind:o.z.string().trim().max(80).optional(),containerName:o.z.string().trim().max(240).optional(),containerId:o.z.string().trim().max(240).optional(),workspacePath:o.z.string().trim().max(4096).optional(),pid:o.z.number().int().positive().optional(),port:o.z.number().int().positive().max(65535).optional(),labels:o.z.record(o.z.string(),o.z.string()).default({})}).strict().default({labels:{}}),registrationToken:o.z.string().trim().min(1).max(240).optional(),lastHeartbeatAt:Yt.optional(),createdAt:Yt,updatedAt:Yt}).strict(),ui="instance.lifecycle.snapshot",gi=o.z.object({instanceId:pi.shape.id,revision:o.z.number().int().min(0),updatedAt:Yt,status:pi.shape.status.unwrap(),health:pi.shape.health.unwrap(),connectionStatus:pi.shape.connectionStatus.unwrap(),accessStatus:o.z.enum(["reachable","endpoint-unreachable"]),imageProvisioning:Ms.optional(),workspace:li,runtime:pi.shape.runtime.unwrap(),runtimeVersion:Qn.optional(),ready:o.z.boolean(),lastHeartbeatAt:Yt.optional()}).strict();function hi(e,t,n,s,i){if(!t||"object"!=typeof t||Array.isArray(t))return;let r=structuredClone(t);for(let t=0;t<20;t+=1){const t=e.safeParse(r);if(t.success)return t.data;let n=!1;for(const e of t.error.issues){if("unrecognized_keys"!==e.code)continue;const t=mi(r,e.path);if(t&&"object"==typeof t&&!Array.isArray(t))for(const s of e.keys)Object.prototype.hasOwnProperty.call(t,s)&&(delete t[s],n=!0)}if(!n){const n=structuredClone(r);let s=!1;for(const e of t.error.issues){if(!e.path.length||"string"!=typeof e.path.at(-1))continue;const t=mi(n,e.path.slice(0,-1)),i=e.path.at(-1);t&&"object"==typeof t&&!Array.isArray(t)&&Object.prototype.hasOwnProperty.call(t,i)&&(delete t[i],s=!0)}if(s){const t=e.safeParse(n);if(t.success)return t.data}break}}}function mi(e,t){let n=e;for(const e of t){if(!n||"object"!=typeof n)return;n=n[e]}return n}function yi(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]]))}o.z.object({instanceId:Qt.optional(),projectId:Qt.optional(),source:as.optional(),nodeId:Qt.optional(),runtimeId:Qt.optional(),imageSelection:un.optional(),instanceVersion:o.z.string().trim().max(80).optional(),protocolVersion:Jt,build:Gn.optional(),controlMode:o.z.enum(["standalone","controlled"]).default("controlled"),capabilities:o.z.record(o.z.string(),o.z.unknown()).default({}),appInventory:xn.optional(),target:di.default({strategy:"direct-port",status:"unknown"}),workspace:li.default({status:"unknown"}),registrationToken:o.z.string().trim().max(240).optional(),processIncarnationId:o.z.string().trim().min(1).max(120).optional()}).strict().superRefine((e,t)=>{e.protocolVersion!==Kt||e.appInventory||t.addIssue({code:"custom",path:["appInventory"],message:"Current protocol register payload requires appInventory."})}),o.z.object({status:pi.shape.status.optional(),health:pi.shape.health.optional(),protocolVersion:Jt,build:Gn.optional(),capabilities:pi.shape.capabilities.optional(),appInventory:xn.optional(),apps:pi.shape.apps.optional(),aiSessions:pi.shape.aiSessions.optional(),triggers:pi.shape.triggers.optional(),workspace:li.optional(),target:di.partial().optional(),processIncarnationId:o.z.string().trim().min(1).max(120).optional()}).strict().superRefine((e,t)=>{e.protocolVersion!==Kt||e.appInventory||t.addIssue({code:"custom",path:["appInventory"],message:"Current protocol heartbeat payload requires appInventory."})});const fi=o.z.enum(["web","telegram","wechat","dingding","lark"]),Ii=o.z.object({id:Qt,channel:fi,name:o.z.string().trim().min(1).max(160),enabled:o.z.boolean().default(!1),token:o.z.string().trim().max(4096).optional(),defaultChatId:o.z.string().trim().max(240).optional(),allowedUserIds:o.z.array(o.z.string().trim().min(1).max(240)).default([]),pollIntervalMs:o.z.number().int().positive().max(6e4).default(3e3),settings:o.z.record(o.z.string(),o.z.unknown()).default({}),createdAt:Yt,updatedAt:Yt}).strict(),bi=o.z.object({id:Qt,channel:fi,bridgeId:Qt.optional(),chatSessionId:o.z.string().trim().min(1).max(240),userId:o.z.string().trim().max(240).optional(),activeProjectId:Qt.optional(),activeInstanceId:Qt.optional(),activeAiSessionId:o.z.string().trim().min(1).max(120).optional(),lastUsedAt:Yt,createdAt:Yt,updatedAt:Yt}).strict(),vi=o.z.object({source:o.z.object({type:o.z.literal("chat-gateway").default("chat-gateway"),channel:fi,bridgeId:Qt.optional(),chatSessionId:o.z.string().trim().min(1).max(240),userId:o.z.string().trim().max(240).optional()}).strict(),message:o.z.object({text:o.z.string().trim().max(2e4).default(""),attachments:o.z.array(G).max(6).default([])}).strict().superRefine((e,t)=>{e.attachments.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>C&&t.addIssue({code:o.z.ZodIssueCode.custom,path:["attachments"],message:"Inline attachments must be 41943040 bytes or less in total."})}),target:o.z.object({instanceId:Qt,aiSessionId:o.z.string().trim().min(1).max(120)}).strict().optional()}).strict(),wi=o.z.object({id:Qt,instanceId:Qt,projectId:Qt.optional(),aiSessionId:o.z.string().trim().min(1).max(120),providerSessionId:o.z.string().trim().max(240).optional(),result:o.z.string().default(""),timeoutMs:o.z.number().positive().optional(),source:o.z.string().trim().max(120).optional(),kind:o.z.enum(["task","approval"]).default("task"),status:o.z.enum(["pending","unreachable"]).default("pending"),error:o.z.string().trim().max(2048).optional(),lastSeenAt:Yt}).strict();function Si(e){return!1!==e.ready&&(!e.runtimeVersion||["matched","failed"].includes(e.runtimeVersion.phase))}const Ai=6048e5;function ki(e,n){const s=t.resolve(e),i=t.resolve(s,n);if(t.dirname(i)!==s||t.basename(i)!==n)throw new Error(`Retention entry is not a direct child of its managed root: ${n}`);return i}function zi(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 Ti(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 Ci=o.z.enum(["ai.sessions","app.sessions"]),xi=o.z.object({topic:Ci,instanceId:o.z.string().trim().min(1).max(160),streamId:o.z.string().trim().min(1).max(240),latestRevision:o.z.number().int().min(0),earliestRetainedRevision:o.z.number().int().min(0)}).strict(),Ei=o.z.object({protocolVersion:o.z.literal(1),streams:o.z.array(xi)}).strict(),Ni=o.z.object({authentication:o.z.enum(["required","disabled"]),aiSessions:o.z.boolean(),nodes:o.z.boolean(),instanceBoard:o.z.boolean(),triggers:o.z.boolean().optional()}).strict(),_i=o.z.object({version:o.z.literal(1),kind:o.z.literal("control-plane"),controlPlaneId:o.z.string().trim().min(1).max(160),publicKey:o.z.object({algorithm:o.z.literal("Ed25519"),encoding:o.z.literal("base64url"),value:o.z.string().regex(/^[A-Za-z0-9_-]{43}$/),fingerprint:o.z.string().regex(/^sha256:[A-Za-z0-9_-]{43}$/)}).strict(),capabilities:Ni,protocolVersion:o.z.string().regex(/^\d{4}-\d{2}-\d{2}$/),issuedAt:o.z.string().datetime(),expiresAt:o.z.string().datetime()}).strict(),Pi=o.z.object({data:o.z.object({payload:_i,signature:o.z.string().regex(/^[A-Za-z0-9_-]{86}$/)}).strict()}).strict(),Ri=o.z.object({id:o.z.string().trim().min(8).max(160),name:o.z.string().trim().min(1).max(160),platform:o.z.enum(["ios","android"]),appVersion:o.z.string().trim().min(1).max(80).optional()}).strict(),Oi=o.z.object({username:o.z.string().trim().min(1).max(80),password:o.z.string().min(1).max(4096),device:Ri}).strict(),ji=o.z.object({id:o.z.string().trim().min(1),username:o.z.string().trim().min(1).max(80),role:o.z.enum(["viewer","operator","admin"]),createdAt:o.z.string().datetime(),updatedAt:o.z.string().datetime(),lastLoginAt:o.z.string().datetime().optional()}).strict(),Mi=o.z.object({id:o.z.string().trim().min(1),expiresAt:o.z.string().datetime(),createdAt:o.z.string().datetime(),lastSeenAt:o.z.string().datetime().optional(),device:Ri,user:ji}).strict();o.z.object({data:o.z.object({sessionToken:o.z.string().trim().min(32),session:Mi}).strict()}).strict(),o.z.object({data:o.z.array(Mi)}).strict(),o.z.object({data:o.z.object({revoked:o.z.boolean()}).strict()}).strict();function Di(e,t=448){n.mkdirSync(e,{recursive:!0,mode:t}),n.chmodSync(e,t)}function qi(e,s,i={}){const r=i.directoryMode??448,o=i.fileMode??384;Di(t.dirname(e),r),c.sync(e,`${JSON.stringify(s,null,2)}\n`,{encoding:"utf8",mode:o}),n.chmodSync(e,o)}function Li(e,t){console.warn(JSON.stringify({message:e,...t}))}function $i(e){return e&&"object"==typeof e&&"issues"in e?{issues:e.issues}:{error:e instanceof Error?e.message:String(e)}}function Bi(e,t){const s=t.logger||Li;let i;try{i=JSON.parse(n.readFileSync(e,"utf8"))}catch(t){return void s("stored JSON could not be read",{filePath:e,...$i(t)})}if(!t.schema)return i;const r=t.sanitize?t.sanitize(i):i,o=t.schema.safeParse(r);if(o.success)return o.data;const a="strip"in t.schema&&"function"==typeof t.schema.strip?t.schema.strip().safeParse(r):void 0;if(a?.success)return s("unknown stored fields were ignored",{filePath:e,issues:o.error.issues}),a.data;s("stored record failed validation and was isolated",{filePath:e,issues:o.error.issues})}function Ui(e){return`${e}_${a.randomUUID().replace(/-/g,"").slice(0,20)}`}function Fi(){return a.randomBytes(24).toString("base64url")}class Hi{directory;options;permissionsInitialized=!1;constructor(e,t={}){this.directory=e,this.options=t}init(){if(this.permissionsInitialized&&n.existsSync(this.directory))return;Di(this.directory,this.options.directoryMode??448);const e=this.options.fileMode??384;for(const s of n.readdirSync(this.directory).filter(e=>e.endsWith(".json")))n.chmodSync(t.join(this.directory,s),e);this.permissionsInitialized=!0}filePath(e){return t.join(this.directory,`${e}.json`)}list(){return this.init(),n.readdirSync(this.directory).filter(e=>e.endsWith(".json")).sort().flatMap(e=>{const n=Bi(t.join(this.directory,e),this.options);return n?[n]:[]})}get(e){this.init();const t=this.filePath(e);return n.existsSync(t)?Bi(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 qi(this.filePath(n.id),n,this.options),n}patch(e,t){const n=this.get(e);if(!n)return;const s={...n,...t,id:n.id,createdAt:n.createdAt,updatedAt:(new Date).toISOString()};return this.put(s)}delete(e){const t=this.filePath(e);return!!n.existsSync(t)&&(n.unlinkSync(t),!0)}}class Wi{filePathValue;defaults;options;constructor(e,t,n={}){this.filePathValue=e,this.defaults=t,this.options=n}init(){Di(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)?Bi(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 qi(this.filePathValue,n,this.options),n}}const Gi=d.promisify(a.scrypt),Vi="task_handoff_cp_session",Ki=o.z.enum(["disabled","password"]),Ji=o.z.string().trim().min(1).max(80).regex(/^[a-zA-Z0-9_.@-]+$/),Qi=o.z.string().min(8).max(4096),Yi=o.z.object({username:Ji,password:Qi}).strict(),Xi=o.z.object({username:o.z.string().trim().min(1).max(80),password:o.z.string().min(1).max(4096)}).strict(),Zi=o.z.object({currentPassword:o.z.string().min(1).max(4096),newPassword:Qi}).strict(),er=o.z.object({username:Ji,password:Qi}).strict(),tr=o.z.object({id:o.z.string().trim().min(1),createdAt:o.z.string().datetime(),updatedAt:o.z.string().datetime()}),nr=tr.extend({username:Ji,passwordHash:o.z.string().trim().min(1),role:o.z.enum(["viewer","operator","admin"]),lastLoginAt:o.z.string().datetime().optional()}).strict(),sr=tr.extend({userId:o.z.string().trim().min(1),tokenHash:o.z.string().trim().min(1),expiresAt:o.z.string().datetime(),lastSeenAt:o.z.string().datetime().optional(),clientType:o.z.enum(["web","mobile"]).default("web"),device:Ri.optional()}).strict().refine(e=>"mobile"!==e.clientType||Boolean(e.device),{path:["device"],message:"Mobile sessions require device metadata."});function ir(){return(new Date).toISOString()}function rr(e,t){return Number.isInteger(e)&&Number(e)>0?Number(e):t}class or{options;sourceFailures=new Map;usernameFailures=new Map;concurrent=0;constructor(e={}){this.options=function(e={}){return{windowMs:rr(e.windowMs,9e5),maxFailuresPerSource:rr(e.maxFailuresPerSource,20),maxFailuresPerUsername:rr(e.maxFailuresPerUsername,10),maxConcurrent:rr(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 ar("Too many password verifications are already in progress.",1e3);this.concurrent+=1}finish(){this.concurrent=Math.max(0,this.concurrent-1)}recordFailure(e,t){const n=Date.now();this.record(this.sourceFailures,e,n),this.record(this.usernameFailures,t,n),this.sourceFailures.size+this.usernameFailures.size>1e4&&(this.pruneAll(n),this.trimOldest(this.sourceFailures,5e3),this.trimOldest(this.usernameFailures,5e3))}assertBucketAvailable(e,t,n,s){const i=this.currentFailures(e,t,s);if(!(i.length<n))throw ar("Too many failed sign-in attempts. Try again later.",i[0]+this.options.windowMs-s)}record(e,t,n){const s=this.currentFailures(e,t,n);s.push(n),e.set(t,s)}currentFailures(e,t,n){const s=n-this.options.windowMs,i=(e.get(t)||[]).filter(e=>e>s);return i.length?e.set(t,i):e.delete(t),i}pruneAll(e){for(const[t]of this.sourceFailures)this.currentFailures(this.sourceFailures,t,e);for(const[t]of this.usernameFailures)this.currentFailures(this.usernameFailures,t,e)}trimOldest(e,t){for(;e.size>t;){const t=e.keys().next().value;if(void 0===t)return;e.delete(t)}}}function ar(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 dr(e){return a.createHash("sha256").update(e).digest("base64url")}async function cr(e){const t=a.randomBytes(16).toString("base64url");return`scrypt$${t}$${(await Gi(e,t,64)).toString("base64url")}`}async function lr(e,t){const[n,s,i]=t.split("$");if("scrypt"!==n||!s||!i)return!1;const r=await Gi(e,s,64),o=Buffer.from(i,"base64url");return o.length===r.length&&a.timingSafeEqual(o,r)}function pr(e){return{id:e.id,username:e.username,role:e.role,createdAt:e.createdAt,updatedAt:e.updatedAt,lastLoginAt:e.lastLoginAt}}function ur(e,t){return Mi.parse({id:e.id,expiresAt:e.expiresAt,createdAt:e.createdAt,lastSeenAt:e.lastSeenAt,device:e.device,user:pr(t)})}class gr{mode;users;sessions;loginRateLimiter;bootstrapAdminInProgress=!1;credentialUpdateInProgress=!1;constructor(e,t={}){this.mode=function(e={}){return Ki.parse(e.mode||process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"disabled")}(t),this.users=new Hi(e.authUsersDir,{schema:nr}),this.sessions=new Hi(e.authSessionsDir,{schema:sr}),this.loginRateLimiter=new or(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=Yi.parse(e);this.bootstrapAdminInProgress=!0;try{const e=ir();return pr(this.users.put({id:Ui("user"),username:t.username,passwordHash:await cr(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=Xi.parse(e),s=await this.authenticate(n.username,n.password,t),i=this.createSession(s,"web");return{user:pr(s),sessionToken:i.token,expiresAt:i.record.expiresAt}}async loginMobile(e,t={}){const n=Oi.parse(e),s=await this.authenticate(n.username,n.password,t),i=this.createSession(s,"mobile",n.device);return{sessionToken:i.token,session:ur(i.record,s)}}async changePassword(e,t,n={}){const s=this.resolveSessionToken(e,"web");if(!s){const e=new Error("Sign in to change the password.");throw Object.assign(e,{statusCode:401,code:"CONTROL_PLANE_AUTH_REQUIRED"}),e}const i=Zi.parse(t);if(this.credentialUpdateInProgress){const e=new Error("Control Plane credentials are already being updated.");throw Object.assign(e,{statusCode:409,code:"AUTH_CREDENTIAL_UPDATE_IN_PROGRESS"}),e}this.credentialUpdateInProgress=!0;const r=String(n.sourceId||"unknown").trim()||"unknown",o=s.storedUser.username.toLocaleLowerCase("en-US");let a=!1;try{if(this.loginRateLimiter.begin(r,o),a=!0,!await lr(i.currentPassword,s.storedUser.passwordHash)){this.loginRateLimiter.recordFailure(r,o);const e=new Error("The current password is incorrect.");throw Object.assign(e,{statusCode:400,code:"AUTH_CURRENT_PASSWORD_INVALID"}),e}if(await lr(i.newPassword,s.storedUser.passwordHash)){const e=new Error("The new password must be different from the current password.");throw Object.assign(e,{statusCode:400,code:"AUTH_PASSWORD_UNCHANGED"}),e}const e=ir(),t=this.users.put({...s.storedUser,passwordHash:await cr(i.newPassword),updatedAt:e});this.revokeUserSessions(t.id);const n=this.createSession(t,"web");return{user:pr(t),sessionToken:n.token,expiresAt:n.record.expiresAt}}finally{a&&this.loginRateLimiter.finish(),this.credentialUpdateInProgress=!1}}async replaceCredentials(e){const t=er.parse(e),n=this.users.list();if(0===n.length){const e=new Error("Control Plane administrator has not been initialized.");throw Object.assign(e,{statusCode:409,code:"AUTH_ACCOUNT_NOT_INITIALIZED"}),e}if(1!==n.length){const e=new Error("The account to update is ambiguous.");throw Object.assign(e,{statusCode:409,code:"AUTH_ACCOUNT_AMBIGUOUS"}),e}const s=ir(),i=this.users.put({...n[0],username:t.username,passwordHash:await cr(t.password),updatedAt:s});return this.revokeUserSessions(i.id),pr(i)}async authenticate(e,t,n){if(!this.enabled()){const e=new Error("Control Plane authentication is disabled.");throw Object.assign(e,{statusCode:400,code:"AUTH_DISABLED"}),e}const s=String(n.sourceId||"unknown").trim()||"unknown",i=e.toLocaleLowerCase("en-US");this.loginRateLimiter.begin(s,i);try{const n=this.users.list().find(t=>t.username===e);if(!n||!await lr(t,n.passwordHash)){this.loginRateLimiter.recordFailure(s,i);const e=new Error("Invalid username or password.");throw Object.assign(e,{statusCode:401,code:"AUTH_LOGIN_FAILED"}),e}const r=ir();return this.users.put({...n,lastLoginAt:r,updatedAt:r})}finally{this.loginRateLimiter.finish()}}createSession(e,t,n){const s=ir(),i=Fi(),r=this.sessions.put({id:Ui("mobile"===t?"msess":"sess"),userId:e.id,tokenHash:dr(i),expiresAt:new Date(Date.now()+12096e5).toISOString(),createdAt:s,updatedAt:s,lastSeenAt:s,clientType:t,...n?{device:n}:{}});return{record:r,token:`${r.id}.${i}`}}revokeUserSessions(e){for(const t of this.sessions.list())t.userId===e&&this.sessions.delete(t.id)}async userForSessionToken(e){const t=this.resolveSessionToken(e,"web");return t?.user}async userForMobileSessionToken(e){const t=this.resolveSessionToken(e,"mobile");return t?.user}resolveSessionToken(e,t){if(!this.enabled()||!e)return;const[n,s]=e.split(".");if(!n||!s)return;const i=this.sessions.get(n);if(!i||t&&i.clientType!==t||i.expiresAt<=ir()||i.tokenHash!==dr(s))return;const r=this.users.get(i.userId);if(!r)return;const o=ir();return{session:this.sessions.put({...i,lastSeenAt:o,updatedAt:o}),user:pr(r),storedUser:r}}async currentSession(e,t="web"){const n=this.state(),s="mobile"===t?await this.userForMobileSessionToken(e):await this.userForSessionToken(e);return{...n,authenticated:!this.enabled()||Boolean(s),user:s}}logout(e){const t=e?.split(".")[0];return t&&this.sessions.delete(t),{ok:!0}}mobileSessions(e){const t=this.resolveSessionToken(e);if(t)return this.sessions.list().filter(e=>"mobile"===e.clientType&&e.userId===t.storedUser.id&&e.expiresAt>ir()).map(e=>ur(e,t.storedUser))}revokeMobileSession(e,t){const n=this.resolveSessionToken(e);if(!n)return;const s=this.sessions.get(t);return!(!s||"mobile"!==s.clientType||s.userId!==n.storedUser.id)&&this.sessions.delete(s.id)}}function hr(e,t){let n=br(t);for(let t=0;t<100;t+=1){const t=e.safeParse(n);if(t.success)return t;const s=yr(t.error.issues);let i=!1;for(const e of s){const t=Ir(n,e.path);if(t&&"object"==typeof t&&!Array.isArray(t))for(const n of e.keys)Object.prototype.hasOwnProperty.call(t,n)&&(delete t[n],i=!0)}if(!i)return t}return e.safeParse(n)}function mr(e,t){const n=hr(e,t);if(!n.success)throw n.error;return n.data}function yr(e,t=[]){const n=[];for(const s of e){if("unrecognized_keys"===s.code){n.push({code:"unrecognized_keys",keys:s.keys,path:[...t,...s.path]});continue}if("invalid_union"!==s.code||!Array.isArray(s.errors))continue;const e=s.errors.filter(e=>Array.isArray(e));if(!e.length)continue;const i=e.reduce((e,t)=>fr(t)<fr(e)?t:e);n.push(...yr(i,[...t,...s.path]))}return n}function fr(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(fr)):1)},0)}function Ir(e,t){let n=e;for(const e of t){if(!n||"object"!=typeof n)return;n=n[e]}return n}function br(e){return Array.isArray(e)?e.map(br):e&&"object"==typeof e?Object.getPrototypeOf(e)!==Object.prototype&&null!==Object.getPrototypeOf(e)?e:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,br(t)])):e}const vr=o.z.enum(["import","export"]),wr=o.z.object({id:o.z.string().trim().min(1).max(120),label:o.z.string().trim().min(1).max(120),directoryName:o.z.string().trim().min(1).max(120)}).strict(),Sr=o.z.object({direction:vr,programIds:o.z.array(o.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:o.z.string().trim().min(1).max(1e3)}).strict(),Ar=o.z.object({import:o.z.string().trim().min(1).max(1e3).default("."),export:o.z.string().trim().min(1).max(1e3).default(".")}).strict(),kr=o.z.object({programs:o.z.array(wr),preferences:Ar}).strict(),zr=o.z.object({id:o.z.string().trim().min(1).max(120),type:o.z.enum(["file","dir"]),projectPath:o.z.string().trim().min(1).max(1e3),containerPath:o.z.string().trim().min(1).max(1e3),source:o.z.string().trim().min(1).max(4096),target:o.z.string().trim().min(1).max(4096),status:o.z.enum(["copied","skipped_missing_source","failed"]),error:o.z.string().trim().max(4096).optional()}).strict(),Tr=o.z.object({preset:o.z.object({id:o.z.string().trim().min(1).max(120),label:o.z.string().trim().min(1).max(120),projectRoot:o.z.string().trim().min(1).max(1e3)}).strict(),direction:vr,items:o.z.array(zr).max(100)}).strict(),Cr=o.z.object({direction:vr,workspaceFolder:o.z.string().trim().min(1).max(1e3),programs:o.z.array(Tr).min(1).max(20)}).strict(),xr="app-session.snapshot",Er="app-session.patch",Nr="app-session.removed",_r=o.z.enum(["created","starting","running","stopping","stopped","exited","failed","closed","terminated","unknown"]),Pr=o.z.enum(["tty","vnc","web"]);o.z.object({mode:Pr,url:o.z.string().trim().min(1).max(4096),token:o.z.string().trim().min(1).max(512),expiresAt:o.z.string().datetime()}).strict(),o.z.object({revoked:o.z.boolean()}).strict();const Rr=new Set(["stopped","failed","exited","closed","terminated"]),Or=o.z.object({type:o.z.enum(["app-session","provider-session","adapter-key"]),id:o.z.string().trim().min(1).max(240),agent:o.z.string().trim().min(1).max(80).optional(),adapter:o.z.string().trim().min(1).max(80).optional(),key:o.z.string().trim().min(1).max(240).optional()}).strict(),jr=o.z.record(o.z.string(),o.z.unknown()).and(o.z.object({id:o.z.string().trim().min(1).max(160),appId:o.z.string().trim().min(1).max(160).optional(),title:o.z.string().trim().max(240).optional(),kind:o.z.string().trim().max(80).optional(),status:_r.default("unknown"),bindings:o.z.array(Or).max(40).default([]),workspace:o.z.object({cwd:o.z.string().trim().max(4096).optional()}).strict().optional(),createdAt:o.z.string().datetime().optional(),updatedAt:o.z.string().datetime().optional()})),Mr=o.z.object({runningCount:o.z.number().int().min(0).default(0),problemCount:o.z.number().int().min(0).default(0),sessions:o.z.array(jr).default([]),updatedAt:o.z.string().datetime()}).strict(),Dr=o.z.object({streamId:o.z.string().trim().min(1).max(240),revision:o.z.number().int().min(0),lastEventAt:o.z.string().datetime(),snapshot:Mr}).strict();Mr.pick({runningCount:!0,problemCount:!0,updatedAt:!0}).extend({revision:o.z.number().int().min(0).optional()});const qr=o.z.enum(["app-session-created","app-session-updated","app-session-deleted","app-session-recovered","control-action","heartbeat-sync","startup"]),Lr=o.z.object({streamId:o.z.string().trim().min(1).max(240),instanceId:o.z.string().trim().min(1).max(160),nodeId:o.z.string().trim().min(1).max(160).optional(),revision:o.z.number().int().min(0),previousRevision:o.z.number().int().min(0).optional(),traceId:o.z.string().trim().min(1).max(160),generatedAt:o.z.string().datetime(),reason:qr}).strict(),$r=o.z.object({meta:Lr,snapshot:Mr}).strict(),Br=o.z.object({meta:Lr,session:jr}).strict(),Ur=o.z.object({meta:Lr,sessionId:o.z.string().trim().min(1).max(160),tombstone:jr.optional(),expiresAt:o.z.string().datetime().optional()}).strict(),Fr=o.z.object({streamId:o.z.string().trim().min(1).max(240),instanceId:o.z.string().trim().min(1).max(160),sinceRevision:o.z.number().int().min(0),latestRevision:o.z.number().int().min(0),earliestRetainedRevision:o.z.number().int().min(0),syncRequired:o.z.boolean().default(!1),events:o.z.array(o.z.discriminatedUnion("type",[o.z.object({type:o.z.literal(xr),payload:$r}).strict(),o.z.object({type:o.z.literal(Er),payload:Br}).strict(),o.z.object({type:o.z.literal(Nr),payload:Ur}).strict()])).default([])}).strict();function Hr(e,t=(new Date).toISOString()){const n=e.map(e=>Gr(e));return Mr.parse({runningCount:n.filter(e=>"running"===e.status).length,problemCount:n.filter(e=>"failed"===e.status).length,sessions:n,updatedAt:t})}function Wr(e,t=(new Date).toISOString()){return Hr(e.filter(e=>Kr("string"==typeof e.status?e.status:void 0)),t)}function Gr(e){const t=Vr("string"==typeof e.status?e.status:void 0),n="string"==typeof e.id?e.id:"",s=function(e){const t=eo(e.workspace),n=eo(e.tty),s=eo(e.launch),i=eo(e.ai),r=eo(i.claude),o=to(t.cwd)||to(n.cwd)||to(r.cwd)||to(s.cwd);return o?{cwd:o}:void 0}(e),{workspace:i,...r}=e;return jr.parse({...r,status:t,bindings:Zr([...(o=e.bindings,Array.isArray(o)?o.flatMap(e=>{const t=Or.safeParse(e);return t.success?[t.data]:[]}):[]),...n?[{type:"app-session",id:n}]:[],...Yr(e)]),...s?{workspace:s}:{}});var o}function Vr(e){const t=(e||"unknown").trim().toLowerCase();return"ended"===t?"closed":"terminating"===t?"stopping":_r.options.includes(t)?t:"unknown"}function Kr(e){return!Rr.has(Vr(e))}function Jr(e){return"tty"===e.kind?"tty":"gui"===e.kind?"vnc":"web"===e.kind?"web":void 0}function Qr(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 Yr(e){const t=eo(e.ai),n=eo(t.claude),s=eo(t.appServer),i=[],r=to(n.short);r&&i.push({type:"adapter-key",adapter:"claude",agent:"claude",id:`short:${r}`,key:`short:${r}`});const o=to(n.providerSessionId);o&&i.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=to(t.activeThreadId);for(const e of[...new Set([d,...a].filter(Boolean))])i.push({type:"provider-session",agent:"codex",id:e});const c=to(s.socketPath);return c&&i.push({type:"adapter-key",adapter:"codex-app-server",agent:"codex",id:`socket:${c}`,key:`socket:${c}`}),i}function Xr(e){const t="string"==typeof e.id?e.id:"",n=eo(e.ai),s=to(eo(n.claude).short);return[t?`app:${t}`:"",s?`claude-short:${s}`:""]}function Zr(e){const t=new Map;for(const n of e)t.set(Qr(n),n);return[...t.values()]}function eo(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function to(e){return"string"==typeof e&&e.trim()?e.trim():""}function no(e=(new Date).toISOString()){return Mr.parse({runningCount:0,problemCount:0,sessions:[],updatedAt:e})}class so{options;resumeSnapshotRefreshFailures=0;lastResumeSnapshotRefreshFailure;constructor(e){this.options=e}async resolveApproval(e,t,n){return mr(Ee,await this.post(e,oo(t,"approval"),{decision:n}))}async listHistory(e){return mr(_e,await this.get(e,"/ai-sessions/history"))}async historyDetail(e,t){return mr(Pe,await this.get(e,`/ai-sessions/history/${encodeURIComponent(t)}`))}async resume(e,t){const n=mr(Re,await this.post(e,oo(t,"resume"),{}));return await this.refreshAfterCommittedResume(e,t),n}async create(e,t){co(t.attachments||[]);const n=await this.options.requireInstance(e),s=t.permissionMode||("codex"===t.agent?n.config.defaultCodexPermissionMode:void 0);return mr(he,await this.options.request(n,"/ai-sessions",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...t,...s?{permissionMode:s}:{}})}))}async openApp(e,t,n){return mr(ye,await this.post(e,oo(t,"open-app"),{clientRequestId:n}))}async close(e,t,n){return mr(Ie,await this.post(e,oo(t,"close"),{clientRequestId:n}))}async refreshAfterCommittedResume(e,t){try{await this.options.refreshSnapshots()}catch(n){const s={instanceId:e,aiSessionId:t,code:io(n),message:ro(n),occurredAt:(new Date).toISOString()};this.resumeSnapshotRefreshFailures+=1,this.lastResumeSnapshotRefreshFailure=s;try{this.options.warn?.(s,"AI session resumed but snapshot refresh failed")}catch{}}}diagnostics(){return{resumeSnapshotRefreshFailures:this.resumeSnapshotRefreshFailures,lastResumeSnapshotRefreshFailure:this.lastResumeSnapshotRefreshFailure}}async sendMessage(e,t,n,s,i=[],r=[],o){co(i);const a=await this.options.requireInstance(e);i.some(e=>"runtime-path"===e.source.type)&&function(e,t){if(!e.some(e=>"runtime-path"===e.source.type)||"local"===t)return;const n=new Error("Runtime path attachments are currently available only for Local Runtime instances.");throw Object.assign(n,{statusCode:400,code:"AI_SESSION_RUNTIME_PATH_UNSUPPORTED"}),n}(i,(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 mr(Ee,await this.options.request(a,oo(t,"messages"),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({message:n,...s?{mode:s}:{},...i.length?{attachments:i}:{},...r.length?{references:r}:{},...c?{permissionMode:c}:{}})}))}async mentionCatalog(e,t){return mr(oe,await this.get(e,oo(t,"mentions")))}async searchMentionFiles(e,t,n){return mr(de,await this.post(e,oo(t,"mentions/files"),{query:n}))}async executeCommand(e,t,n){return mr(Z,await this.post(e,oo(t,"commands"),n))}async queue(e,t){return mr(Ae,await this.get(e,oo(t,"queue")))}async steerQueuedMessage(e,t,n){return mr(Ee,await this.post(e,ao(t,n,"steer"),{}))}async retryQueuedMessage(e,t,n){return mr(xe,await this.post(e,ao(t,n,"retry"),{}))}async removeQueuedMessage(e,t,n){const s=await this.options.requireInstance(e);return mr(xe,await this.options.request(s,ao(t,n),{method:"DELETE"}))}async editQueuedMessage(e,t,n,s){const i=we.parse(s);return mr(xe,await this.patch(e,ao(t,n),i))}async reorderQueuedMessages(e,t,n){const s=ve.parse(n);return mr(xe,await this.patch(e,oo(t,"queue/reorder"),s))}async interrupt(e,t){return mr(Ee,await this.post(e,oo(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 io(e){return e&&"object"==typeof e&&"code"in e&&"string"==typeof e.code?e.code:"AI_SESSION_SNAPSHOT_REFRESH_FAILED"}function ro(e){return e instanceof Error?e.message:String(e)}function oo(e,t){return`/ai-sessions/${encodeURIComponent(e)}/${t}`}function ao(e,t,n){return`${oo(e,"queue")}/${encodeURIComponent(t)}${n?`/${n}`:""}`}function co(e){if(e.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)<=C)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 lo(e,t,n,s){const i=s&&"object"==typeof s?s:{};return{nodeId:e.id,route:"string"==typeof i.route?i.route:t,method:n,code:"string"==typeof i.code?i.code:"NODE_AGENT_REQUEST_FAILED",message:s instanceof Error?s.message:String(s),statusCode:"number"==typeof i.statusCode?i.statusCode:void 0,issues:Array.isArray(i.issues)?i.issues:void 0}}class po{requestImpl;logger;constructor(e){this.requestImpl=e.request,this.logger=e.logger}async request(e,t,n={}){const s=n.method||"GET";let i,r;try{i=await this.requestImpl(e,t,n)}catch(n){throw this.logger?.warn?.({nodeId:e.id,route:t,method:s,error:n instanceof Error?n.message:String(n),errorCode:"NODE_AGENT_TRANSPORT_FAILED"},"node agent transport failed"),n}try{r=await i.json()}catch(n){this.logger?.warn?.({nodeId:e.id,route:t,method:s,statusCode:i.status,error:n instanceof Error?n.message:String(n),errorCode:"NODE_AGENT_RESPONSE_INVALID_JSON"},"node agent response was not valid json");const r=new Error(`Node agent ${e.id} returned invalid JSON for ${t}.`);throw Object.assign(r,{statusCode:502,code:"NODE_AGENT_RESPONSE_INVALID_JSON",nodeId:e.id,route:t}),r}if(!i.ok){const n=new Error(r.error?.message||`Node agent request failed with HTTP ${i.status}`);throw Object.assign(n,{statusCode:i.status,code:r.error?.code||"NODE_AGENT_REQUEST_FAILED",nodeId:e.id,route:t}),this.logger?.warn?.({nodeId:e.id,route:t,method:s,statusCode:i.status,errorCode:r.error?.code||"NODE_AGENT_REQUEST_FAILED",error:n.message},"node agent request failed"),n}return this.logger?.info?.({nodeId:e.id,route:t,method:s,statusCode:i.status},"node agent request ok"),r.data??r}async requestSchema(e,t,n,s={}){return this.parse(e,t,n,await this.request(e,t,s),s.method||"GET")}parse(e,t,n,s,i="GET"){const r=hr(n,s);if(r.success)return r.data;this.logger?.warn?.({nodeId:e.id,route:t,method:i,errorCode:"NODE_AGENT_PROTOCOL_INVALID",issues:r.error.issues},"node agent protocol response did not match schema");const o=new Error(`Node agent ${e.id} returned invalid protocol data for ${t}.`);throw Object.assign(o,{statusCode:502,code:"NODE_AGENT_PROTOCOL_INVALID",nodeId:e.id,route:t,issues:r.error.issues}),o}}class uo{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",Js)}checkUpdate(e,t){return this.client.requestSchema(e,"/updates/check",es,{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",o.z.array(ts))}getExternalListener(e){return this.client.requestSchema(e,"/settings/external-listener",Qs)}updateExternalListener(e,t){return this.client.requestSchema(e,"/settings/external-listener",Qs,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}createPairingInvite(e,t={}){return this.client.requestSchema(e,"/pairing/invites",Ys,{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",ni,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}listControlPlanePairings(e){return this.client.requestSchema(e,"/control-plane-pairings",o.z.array(Zs))}deleteControlPlanePairing(e,t){return this.client.requestSchema(e,`/control-plane-pairings/${encodeURIComponent(t)}`,si,{method:"DELETE"})}listControlPlaneConnections(e){return this.client.requestSchema(e,"/control-plane-connections",o.z.array(ti))}deleteControlPlaneConnection(e,t){return this.client.requestSchema(e,`/control-plane-connections/${encodeURIComponent(t)}`,si,{method:"DELETE"})}listDockerImages(e){return this.client.requestSchema(e,"/docker/images",o.z.array(ii))}listFolderTree(e,t={}){const n=new URLSearchParams;t.path&&n.set("path",t.path),void 0!==t.depth&&n.set("depth",String(t.depth));const s=n.toString();return this.client.requestSchema(e,"/folders/tree"+(s?`?${s}`:""),o.z.array(oi))}listLocalFolders(e,t={}){return this.client.requestSchema(e,"/local-folders",o.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",o.z.array(Vs),t)}createRuntime(e,t){return this.client.requestSchema(e,"/runtimes",Vs,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}updateRuntime(e,t,n){const s=`/runtimes/${encodeURIComponent(t)}`;return this.client.requestSchema(e,s,Vs,{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,Vs,{method:"POST"})}deleteRuntime(e,t){return this.client.requestSchema(e,`/runtimes/${encodeURIComponent(t)}`,si,{method:"DELETE"})}deleteLocalFolder(e,t){return this.client.requestSchema(e,`/local-folders/${encodeURIComponent(t)}`,si,{method:"DELETE"})}listModels(e,t={}){return this.client.requestSchema(e,"/models",o.z.array(gs),t)}createModel(e,t){return this.client.requestSchema(e,"/models",gs,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}deployModel(e,t,n){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}/deploy`,gs,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}updateModel(e,t,n){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}`,gs,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteModel(e,t){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}`,si,{method:"DELETE"})}assignInstanceModels(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/model-assignment`,o.z.object({assignment:hs,instance:pi}).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,s)=>{if("fulfilled"===n.status)t.items.push(...n.value.models.map(e=>({nodeId:n.value.node.id,model:e})));else{const i=e[s];i&&t.nodeErrors.push(lo(i,"/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",o.z.array(o.z.unknown()),t).then(t=>t.reduce((t,n)=>{const s=this.normalizeInstance(e,n);return s.instance&&t.items.push(s.instance),s.error&&t.nodeErrors.push(s.error),t},{items:[],nodeErrors:[]}))}createInstance(e,t){return this.client.requestSchema(e,"/instances",pi,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}updateInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}`,pi,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/delete`,Sn,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}listEnvironmentTemplates(e,t={}){return this.client.requestSchema(e,"/environment-templates",o.z.array(En),t)}getEnvironmentTemplate(e,t,n={}){return this.client.requestSchema(e,`/environment-templates/${encodeURIComponent(t)}`,En,n)}createEnvironmentTemplate(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/environment-templates`,En,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteEnvironmentTemplate(e,t){return this.client.requestSchema(e,`/environment-templates/${encodeURIComponent(t)}`,o.z.object({deleted:o.z.boolean(),templateId:En.shape.id}).strict(),{method:"DELETE"})}startInstance(e,t,n={}){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/start`,pi,{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`,pi,{method:"POST"})}stopInstance(e,t){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/stop`,pi,{method:"POST"})}restartInstance(e,t,n={}){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/restart`,pi,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}instanceResourceMetrics(e,t){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/metrics`,Ks)}proxyRawInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/proxy/raw`,ai,{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,s,i){const r=new Set(e.map(e=>e.id));for(const e of s.keys())r.has(e)||s.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=>i(e,t));return s.set(e.id,{connectionKey:r,items:[...o.items]}),o}catch(n){const i=s.get(e.id);return{items:i?.connectionKey===r?[...i.items]:[],nodeErrors:[lo(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,s="reverse-wss"!==e.connectionMode&&"control-plane-proxy"!==e.connectionMode;if(!n||"healthy"===n||s)return;const i=new Error(`Node agent ${e.id} is ${n}; serving its latest fleet snapshot.`);throw Object.assign(i,{code:"NODE_AGENT_CONNECTION_PENDING",nodeId:e.id,route:t}),i}async withFleetDeadline(e,t,n,s){const i=new AbortController,r=Object.assign(new Error(`Node agent ${e.id} did not return ${t} before the fleet aggregation deadline.`),{code:"NODE_AGENT_FLEET_TIMEOUT",nodeId:e.id,route:t}),o=new Promise((e,t)=>{const n=()=>t(i.signal.reason||r);i.signal.aborted?n():i.signal.addEventListener("abort",n,{once:!0})}),a=()=>i.abort(n.signal?.reason);n.signal?.aborted?a():n.signal?.addEventListener("abort",a,{once:!0});const d=setTimeout(()=>i.abort(r),this.fleetRequestTimeoutMs);d.unref?.();try{return await Promise.race([s({...n,signal:i.signal}),o])}finally{clearTimeout(d),n.signal?.removeEventListener("abort",a)}}normalizeInstance(e,t){const n=(s=t,pi.safeParse(function(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,n=new Set(Object.keys(pi.shape)),s={};for(const[e,i]of Object.entries(t))n.has(e)&&(s[e]=i);if(t.capabilities&&"object"==typeof t.capabilities&&!Array.isArray(t.capabilities)){const e={...t.capabilities};Object.prototype.hasOwnProperty.call(e,"apps")&&delete e.apps,s.capabilities=e}else s.capabilities={};s.appInventory=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e;Object.keys(t).some(e=>!["observedAt","items","issues"].includes(e));const n={observedAt:t.observedAt,items:Array.isArray(t.items)?t.items.map(e=>{e&&"object"==typeof e&&!Array.isArray(e)&&Object.keys(e).some(e=>!["id","name","kind","source","availability","capabilities","diagnosticCode"].includes(e));const t=yi(e,["id","name","kind","source","availability","diagnosticCode"]);return!t||"object"!=typeof t||Array.isArray(t)?t:{...t,capabilities:yi(e.capabilities,["automation","supportsCwdSelection"])}}):t.items,issues:Array.isArray(t.issues)?t.issues.map(e=>yi(e,["code","message"])):t.issues},s=xn.safeParse(n);return s.success?s.data:void 0}(t.appInventory,"string"==typeof t.id&&t.id),s.source=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,n=t.type,s=as.options.find(e=>e.shape.type.value===n);if(!s)return e;const i="local-folder"===n?["type","localFolderId","path","ownerNodeId"]:"git-template"===n?["type","url","templateId","ref","auth","clone"]:["type","repositoryId","url","provider","ref","auth","clone"],r=yi(t,i);if("local-folder"!==n){const e=hi(ss,yi(t.ref,["type","name","commit"])),n=hi(is,yi(t.auth,["type","secretId"])),s=hi(rs,yi(t.clone,["depth","submodules","lfs","subdirectory"]));e?r.ref=e:delete r.ref,n?r.auth=n:delete r.auth,s?r.clone=s:delete r.clone}const o=hi(s,r);return o?(Object.keys(t).some(e=>!i.includes(e)),o):r}(t.source,"string"==typeof t.id&&t.id),s.sourceSnapshot=t.sourceSnapshot&&"object"==typeof t.sourceSnapshot&&!Array.isArray(t.sourceSnapshot)?t.sourceSnapshot:{},s.build=hi(Gn,t.build,0,0,"string"==typeof t.id&&t.id),s.aiSessions=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n=Array.isArray(t.sessions)?t.sessions.flatMap((e,t)=>{const n=hi(Oe,e);return n?[n]:[]}):[],s={runningCount:"number"==typeof t.runningCount&&Number.isInteger(t.runningCount)&&t.runningCount>=0?t.runningCount:0,waitingCount:"number"==typeof t.waitingCount&&Number.isInteger(t.waitingCount)&&t.waitingCount>=0?t.waitingCount:0,staleCount:"number"==typeof t.staleCount&&Number.isInteger(t.staleCount)&&t.staleCount>=0?t.staleCount:0,sessions:n,updatedAt:Yt.safeParse(t.updatedAt).success?t.updatedAt:(new Date).toISOString()};return Object.keys(t).some(e=>!["runningCount","waitingCount","staleCount","sessions","updatedAt"].includes(e)),je.parse(s)}(t.aiSessions,"string"==typeof t.id&&t.id),s.triggers=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e;Object.keys(t).some(e=>!["enabledCount","runningCount","errorCount","configs","recentRuns"].includes(e));const n=(e,t,n)=>Array.isArray(e)?e.flatMap((e,n)=>{const s=hi(t,e);return s?[s]:[]}):[],s=Array.isArray(t.configs)?t.configs.flatMap((e,t)=>{if(!e||"object"!=typeof e||Array.isArray(e))return[];const s=e;Object.keys(s).some(e=>!["configHash","config","deployments","runtime"].includes(e));const i=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n=yi(t,["configHash","name","description","createdAt","updatedAt"]);if(t.source&&"object"==typeof t.source&&!Array.isArray(t.source)){const e=t.source,s="schedule"===e.type?"interval"===e.scheduleKind?["type","scheduleKind","intervalMs"]:"daily"===e.scheduleKind?["type","scheduleKind","timeOfDay","timezone"]:["type","scheduleKind","weekdays","timeOfDay","timezone"]:"file-change"===e.type?["type","roots","globs","ignore","debounceMs"]:["type","agent","statuses","phases"];n.source=yi(e,s)}return n.action=yi(t.action,["promptTemplate"]),n.policy=yi(t.policy,["cooldownMs","maxConcurrentRuns","whenBusy"]),hi(Ze,n)}(s.config);return"string"==typeof s.configHash&&i?[{configHash:s.configHash,config:i,deployments:n(s.deployments,tt),runtime:n(s.runtime,nt)}]:[]}):[];return{enabledCount:"number"==typeof t.enabledCount&&Number.isInteger(t.enabledCount)&&t.enabledCount>=0?t.enabledCount:0,runningCount:"number"==typeof t.runningCount&&Number.isInteger(t.runningCount)&&t.runningCount>=0?t.runningCount:0,errorCount:"number"==typeof t.errorCount&&Number.isInteger(t.errorCount)&&t.errorCount>=0?t.errorCount:0,configs:s,recentRuns:n(t.recentRuns,st)}}(t.triggers,"string"==typeof t.id&&t.id),s.apps=hi(pi.shape.apps.unwrap(),yi(t.apps,["runningCount","problemCount","updatedAt","revision"]),0,0,"string"==typeof t.id&&t.id)||{runningCount:0,problemCount:0},s.config=hi(pi.shape.config.unwrap(),yi(t.config,["autoImportAgentConfigs","defaultCodexPermissionMode"]),0,0,"string"==typeof t.id&&t.id)||{autoImportAgentConfigs:!0,defaultCodexPermissionMode:"ask"},s.modelSelection=hi(pn.unwrap(),yi(t.modelSelection,["codexModelHash","claudeModelHash"]),0,0,"string"==typeof t.id&&t.id)||{},s.imageSnapshot=function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,s=Fs(n),{reference:i,...r}=s,o=n.requestedReference??i;let a;try{a="string"==typeof o?dn(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?yi(n.market,["catalogId","catalogRevision","publisher","version"])??{catalogId:"task_handoff_embedded",catalogRevision:"legacy",publisher:"task-handoff"}:void 0}}(t.imageSnapshot,t.imageId,"string"==typeof t.id&&t.id);const i="string"==typeof t.imageId?{img_default:"market_taskhandoff_browser",img_codex:"market_taskhandoff_codex",img_ai:"market_taskhandoff_ai"}[t.imageId]||t.imageId:void 0,r=yi(t.imageSelection,["imageId","tag"]);s.imageSelection=r||(i?{imageId:i,tag:s.imageSnapshot?.tag}:void 0),s.imageProvisioning=hi(Ms,yi(t.imageProvisioning,["phase","requestedReference","generation","error","startedAt","updatedAt"]),0,0,"string"==typeof t.id&&t.id),s.runtimeVersion=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n=e=>{if("string"!=typeof e)return;const t=e.trim();return t&&t.length<=80?t:void 0},s=n(t.desiredVersion);if(!s)return;const i=new Set(Qn.shape.phase.options),r="string"==typeof t.phase?t.phase:"pending",o=i.has(r)?r:{idle:"pending",queued:"pending",checking:"pending",downloading:"installing",updating:"installing",completed:"matched",succeeded:"matched",ready:"matched",error:"failed"}[r]||"pending";let a;if(t.error&&"object"==typeof t.error&&!Array.isArray(t.error)){const e=t.error,s="string"==typeof e.message?e.message.trim().slice(0,4096):"";if(s){const t=new Set(Jn.shape.code.options),i="string"==typeof e.code&&t.has(e.code)?e.code:"INSTANCE_RUNTIME_INSTALL_FAILED";e.code;const r=n(e.expectedVersion),o=n(e.actualVersion);a={code:i,message:s,...r?{expectedVersion:r}:{},...o?{actualVersion:o}:{},retryable:!0===e.retryable}}}"string"==typeof t.error&&t.error.trim()&&(a={code:"INSTANCE_RUNTIME_INSTALL_FAILED",message:t.error.trim().slice(0,4096),expectedVersion:s,...n(t.actualVersion)?{actualVersion:n(t.actualVersion)}:{},retryable:!1});const d=n(t.actualVersion),c=Yt.safeParse(t.lastAttemptAt),l=Yt.safeParse(t.matchedAt);return void 0!==t.lastAttemptAt&&c.success,void 0!==t.matchedAt&&l.success,{desiredVersion:s,...d?{actualVersion:d}:{},phase:o,attempt:"number"==typeof t.attempt&&Number.isInteger(t.attempt)&&t.attempt>=0?t.attempt:0,...c.success?{lastAttemptAt:c.data}:{},...l.success?{matchedAt:l.data}:{},...a?{error:a}:{}}}(t.runtimeVersion,"string"==typeof t.id&&t.id),s.workspace=hi(li,t.workspace,0,0,"string"==typeof t.id&&t.id)||{status:"unknown"},s.environmentSource=hi(gn,t.environmentSource,0,0,"string"==typeof t.id&&t.id),s.environmentTemplateOrigin=hi(In,t.environmentTemplateOrigin,0,0,"string"==typeof t.id&&t.id),s.runtime=hi(pi.shape.runtime.unwrap(),t.runtime,0,0,"string"==typeof t.id&&t.id)||{labels:{}},s.target=hi(di,yi(t.target??t.endpoints,["strategy","web","api","vnc","tty","logs","status"]),0,0,"string"==typeof t.id&&t.id)||{strategy:"direct-port",status:"unknown"},s.access=hi(ci,yi(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(pi.shape))Object.prototype.hasOwnProperty.call(s,e)&&!t.safeParse(s[e]).success&&t.safeParse(void 0).success&&delete s[e];return s}(s)));var s;if(n.success)return n.data.protocolVersion&&n.data.protocolVersion!==Kt?(this.client.logger?.warn?.({nodeId:e.id,instanceId:n.data.id,expectedProtocolVersion:Kt,actualProtocolVersion:n.data.protocolVersion,errorCode:"PROTOCOL_VERSION_MISMATCH"},"node instance protocol version mismatch"),{instance:n.data}):{instance:n.data};const i=t&&"object"==typeof t?t:{},r="string"==typeof i.id?i.id:void 0;return this.client.logger?.warn?.({nodeId:e.id,instanceId:r,errorCode:"NODE_INSTANCE_PAYLOAD_INVALID",issues:n.error.issues.map(e=>({path:e.path.join("."),message:e.message}))},"node instance payload invalid"),{error:{nodeId:e.id,route:"/instances",method:"GET",code:"NODE_INSTANCE_PAYLOAD_INVALID",message:r?`Node instance ${r} payload is invalid.`:"Node instance payload is invalid.",statusCode:502,issues:n.error.issues}}}}function go(e){return e.readyState===(e.OPEN??1)}function ho(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 mo(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 yo(e,t,n){e.close(mo(t),ho(n)||void 0)}function fo(e,t,n,s){if(go(e))for(const e of t.splice(0))if(s(e),!n(e))return}function Io(e,t,n={}){const s=n.pendingFrameLimit??256,i=n.maxFrameBytes??8388608,r=n.maxTotalBytes??1073741824,o=n.maxBufferedBytes??16777216;let a=!1,d=go(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=(s,o)=>{const a=m(o);return h+=a,n.onFrame?.(s,a),!(a>i||h>r)||(yo(e,1009,"WebSocket bridge traffic limit exceeded."),yo(t,1009,"WebSocket bridge traffic limit exceeded."),!1)},f=()=>{p&&(clearTimeout(p),p=void 0)},I=(n,s)=>{const i=s.bytes;if((n.bufferedAmount??0)+i>o)return yo(e,1013,"WebSocket bridge consumer is too slow."),yo(t,1013,"WebSocket bridge consumer is too slow."),!1;try{return function(e,t){e.send(t.data,{binary:t.isBinary})}(n,s),!0}catch{return yo(e,1011,"WebSocket bridge send failed."),yo(t,1011,"WebSocket bridge send failed."),!1}},b=(n,i,r)=>{if(i.length>=s)return yo(e,1011,"WebSocket bridge pending frame limit exceeded."),void yo(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 yo(e,1013,"WebSocket bridge consumer is too slow."),void yo(t,1013,"WebSocket bridge consumer is too slow.");i.push(r),"upstream"===n?u+=r.bytes:g+=r.bytes};return n.upstreamOpenTimeoutMs&&!d&&(p=setTimeout(()=>{d||a||(yo(e,1011,"Upstream websocket did not open."),yo(t))},n.upstreamOpenTimeoutMs)),e.on("open",()=>fo(e,l,t=>I(e,t),e=>{g-=e.bytes})),t.on("open",()=>{f(),d=!0,n.onUpstreamOpen?.(),fo(t,c,e=>I(t,e),e=>{u-=e.bytes})}),e.on("message",(e,n=!1)=>{if(!y("client-to-upstream",e))return;const s={data:e,isBinary:Boolean(n),bytes:m(e)};go(t)?I(t,s):b("upstream",c,s)}),t.on("message",(t,n=!1)=>{if(!y("upstream-to-client",t))return;const s={data:t,isBinary:Boolean(n),bytes:m(t)};go(e)?I(e,s):b("client",l,s)}),t.on("close",(t,s)=>{f(),n.onUpstreamClose?.(t,s),(d||a||!n.onUpstreamCloseBeforeOpen?.())&&yo(e,t,s)}),t.on("error",t=>{n.onUpstreamError?.(t),(d||a||!n.onUpstreamErrorBeforeOpen?.(t))&&yo(e)}),e.on("close",(e,s)=>{f(),a=!0,n.onClientClose?.(e,s),yo(t,e,s)}),e.on("error",e=>{f(),a=!0,n.onClientError?.(e),yo(t,1011,"WebSocket bridge client failed.")}),{close:(n,s)=>{f(),yo(t,n,s),yo(e,n,s)}}}const bo="TASK_HANDOFF_NODE_AGENT_V1",vo=6e4,wo="/api/node-tunnel";function So(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||a.randomBytes(18).toString("base64url"),s=Ao(e.body||""),i=ko(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":i}}({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 Ao(e=""){return a.createHash("sha256").update(e).digest("hex")}function ko(e,t){return a.createHmac("sha256",e).update(function(e){return[bo,e.keyId,e.method.toUpperCase(),e.pathWithQuery,e.timestamp,e.nonce,e.bodySha256].join("\n")}(t)).digest("hex")}function zo(e){if(e.startsWith("ipc://"))return decodeURIComponent(e.slice(6))}function To(e,t=process.platform){if(!function(e,t=process.platform){if("win32"===t)return e.startsWith("\\\\.\\pipe\\");const s=n.statSync(e),i=process.getuid?.();return void 0===i||s.uid===i}(e,t)){const e=new Error("Local node agent IPC socket is not owned by the current user.");throw Object.assign(e,{statusCode:403,code:"NODE_AGENT_IPC_OWNER_INVALID"}),e}}function Co(e,t,n,s={}){const i=`/api/node-agent${t}`,r={createConnection:()=>u.connect(e),headers:{host:"task-handoff-node-agent.local",...s}};return n&&(Array.isArray(n)?n.length>0:n.trim().length>0)?new l.WebSocket(`ws://task-handoff-node-agent.local${i}`,n,r):new l.WebSocket(`ws://task-handoff-node-agent.local${i}`,r)}function xo(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function Eo(e,t){const n=AbortSignal.timeout(t);return e?AbortSignal.any([e,n]):n}async function No(e,t,n,s={}){const i=zo(t);return i?(To(i),async function(e,t,n={}){const s=n.method||"GET",i="string"==typeof n.body||n.body instanceof Buffer?n.body:void 0===n.body||null===n.body?void 0:String(n.body),r=new Headers(n.headers||{});return void 0===i||r.has("content-length")||r.set("content-length",String(Buffer.byteLength(i))),new Promise((o,a)=>{const d=p.request({socketPath:e,method:s,path:`/api/node-agent${t}`,headers:Object.fromEntries(r.entries())},e=>{const t=e.statusCode||500;o(new Response("HEAD"!==s&&204!==t&&205!==t&&304!==t?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!==i&&d.write(i),d.end()})}(i,n,s)):e(`${t.replace(/\/$/,"")}/api/node-agent${n}`,s)}function _o(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 Po(e,t,n,s){const i=_o(e),r=zo(i),o=`/api/node-agent${t}`;if(r)return To(r),Co(r,t,n,s);const a=new URL(o,i.replace(/\/$/,""));return a.protocol="https:"===a.protocol?"wss:":"ws:",n?new l.WebSocket(a.toString(),n,{headers:s}):new l.WebSocket(a.toString(),{headers:s})}function Ro(e,t,n){const s=new Headers(n),i=So(e,t);for(const[e,t]of Object.entries(i))"authorization"===e&&s.has(e)||s.set(e,t);return Object.fromEntries(s.entries())}function Oo(e=fetch,t={}){const n=t.openWebSocket||Po,s=xo(t.requestTimeoutMs,3e4),i=xo(t.streamHeaderTimeoutMs,3e4),r=xo(t.websocketOpenTimeoutMs,1e4);return{request:async(t,n,i={})=>{const r=_o(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=Ro(t,{method:o,pathWithQuery:`/api/node-agent${n}`,body:a||""},i.headers);return No(e,r,n,{...i,body:a,headers:d,signal:Eo(i.signal,s)})},requestStream:async(t,n,s={})=>{const r=_o(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=Ro(t,{method:o,pathWithQuery:`/api/node-agent${n}`,body:a||""},s.headers),c=new AbortController,l=s.signal?AbortSignal.any([s.signal,c.signal]):c.signal;return async function(t,i,o){const c=setTimeout(()=>o.abort(Object.assign(new Error("Node agent response header timed out."),{code:"NODE_AGENT_RESPONSE_HEADER_TIMEOUT"})),i);c.unref?.();try{return await No(e,r,n,{...s,body:a,headers:d,signal:l})}finally{clearTimeout(c)}}(0,i,c)},proxyWebSocket(e,t,s,i,o={}){const a=Ro(e,{method:"GET",pathWithQuery:`/api/node-agent${s}`},o);Io(t,n(e,s,i,a),{upstreamOpenTimeoutMs:r,onUpstreamError:()=>t.close(1011,"Instance websocket proxy failed."),onUpstreamErrorBeforeOpen:()=>!0})}}}class jo{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 Mo(e,t,n,s){const i=new Error(e,void 0===s?void 0:{cause:s});return Object.assign(i,{code:t,statusCode:n,retryable:n>=500}),i}function Do(e,t){if("control-plane-proxy"!==e.connectionPath.kind)throw Mo("Control-plane proxy transport requires a proxy connection path.","CONTROL_PLANE_PROXY_CONFIGURATION_INVALID",400);const n=t(e);if(!n)throw Mo("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 Mo("Control-plane proxy credential does not match the node connection identity.","CONTROL_PLANE_PROXY_CREDENTIAL_MISMATCH",409);return n}function qo(e,t){const n=new Headers(t);n.set(St,ut),n.set(At,e.sourceControlPlaneId),n.set(kt,e.bindingKeyId),n.set(zt,e.credential);const s=ft.safeParse(n.get("x-request-id"));return n.set("x-request-id",s.success?s.data:`proxy_request_${a.randomUUID().replace(/-/g,"")}`),Object.fromEntries(n.entries())}function Lo(e){const t=bt.safeParse(e);if(t.success)return t.data;const n=Mo("Control-plane proxy route is invalid.",Tt.RouteInvalid,400);throw Object.assign(n,{issues:t.error.issues}),n}function $o(e,t,n){return t?new l.WebSocket(e,t,{headers:n}):new l.WebSocket(e,{headers:n})}class Bo{credentialForNode;fetchImpl;openWebSocket;constructor(e){this.credentialForNode=e.credentialForNode,this.fetchImpl=e.fetchImpl||fetch,this.openWebSocket=e.openWebSocket||$o}async fetch(e,t,n={}){const s=Do(e,this.credentialForNode),i=function(e,t){const n=new URL(Lo(t),"https://node-agent.invalid"),s=new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/http${n.pathname}`,e.proxyOrigin);return s.search=n.search,s}(s,t);try{return await this.fetchImpl(i,{...n,headers:qo(s,n.headers)})}catch(e){if(function(e){return e instanceof Error&&("AbortError"===e.name||"ABORT_ERR"===e.code)}(e))throw e;throw Mo(`Trusted control-plane proxy ${s.proxyOrigin} is unavailable.`,"CONTROL_PLANE_PROXY_UNAVAILABLE",503,e)}}request(e,t,n={}){return this.fetch(e,t,n)}requestStream(e,t,n={}){return this.fetch(e,t,n)}proxyWebSocket(e,t,n,s,i={}){const r=Do(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",Lo(t)),n}(r,n).toString(),s,qo(r,i));Io(t,o,{onUpstreamError:()=>t.close(1011,"Control-plane proxy websocket failed."),onUpstreamErrorBeforeOpen:()=>!0})}}const Uo=new Set(Object.keys(Gt.shape)),Fo=new Set(Object.keys(Vt.shape));function Ho(e,t,n){if(!e||"object"!=typeof e||Array.isArray(e))return e;const s=e,i=Object.keys(s).filter(e=>!t.has(e));return i.length&&n?.(i),Object.fromEntries([...t].filter(e=>e in s).map(e=>[e,s[e]]))}function Wo(e){const{credential:t,...n}=e;return n}class Go{pendingClaims;nodeCredentials;identity;constructor(e,t){this.pendingClaims=new Hi(e.pendingClaimsDir,{schema:Gt,sanitize:e=>function(e){return Ho(e,Uo,e=>t?.("unknown stored pending proxy claim fields were ignored",{fields:e}))}(e),logger:t,directoryMode:448,fileMode:384}),this.nodeCredentials=new Hi(e.nodeCredentialsDir,{schema:Vt,sanitize:e=>function(e){return Ho(e,Fo,e=>t?.("unknown stored proxy node credential fields were ignored",{fields:e}))}(e),logger:t,directoryMode:448,fileMode:384}),this.identity=new Wi(e.identityPath,()=>({controlPlaneId:Ui("control_plane")}),{schema:o.z.object({controlPlaneId:o.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(Wo)}nodeCredential(e){return this.nodeCredentials.list().find(t=>t.nodeId===e)}putNodeCredential(e){const t=this.nodeCredential(e.nodeId);if(t&&(t.proxyOrigin!==e.proxyOrigin||t.proxyBindingId!==e.proxyBindingId||t.targetNodeId!==e.targetNodeId||t.sourceControlPlaneId!==e.sourceControlPlaneId||t.bindingKeyId!==e.bindingKeyId||t.credential!==e.credential)){const e=new Error("Proxy node credential conflicts with the existing node identity.");throw Object.assign(e,{code:"CONTROL_PLANE_PROXY_NODE_IDENTITY_CONFLICT",statusCode:409}),e}return t||this.nodeCredentials.put(e)}deleteNodeCredential(e){const t=this.nodeCredential(e);return!!t&&this.nodeCredentials.delete(t.id)}gcNodeCredentials(e){const t=[];for(const n of this.nodeCredentials.list())e(n)||(this.nodeCredentials.delete(n.id),t.push(n.id));return t}promotePendingClaim(e,t){const n=this.pendingClaimByClaimId(e);if(!n)return;if(n.proxyOrigin!==t.proxyOrigin||n.sourceControlPlaneId!==t.sourceControlPlaneId||void 0!==n.targetNodeId&&n.targetNodeId!==t.targetNodeId||n.bindingKeyId!==t.bindingKeyId||n.credential!==t.credential){const e=new Error("Proxy node credential does not match the pending claim identity.");throw Object.assign(e,{code:"CONTROL_PLANE_PROXY_BINDING_IDENTITY_CONFLICT",statusCode:409}),e}const s=this.putNodeCredential(t);return this.pendingClaims.delete(n.id),s}markCompensationRequired(e){const t=this.pendingClaimByClaimId(e);if(t)return this.pendingClaims.patch(t.id,{status:"compensation-required"})}cancelPendingClaim(e,t){const n=this.pendingClaimByClaimId(e);return n?t?(this.pendingClaims.patch(n.id,{status:"compensation-required"}),{deleted:!1,compensationRequired:!0}):{deleted:this.pendingClaims.delete(n.id),compensationRequired:!1}:{deleted:!1,compensationRequired:!1}}completePendingClaimCompensation(e){const t=this.pendingClaimByClaimId(e);return!(!t||"compensation-required"!==t.status)&&this.pendingClaims.delete(t.id)}gcPendingClaims(e=Date.now()){const t=[];for(const n of this.pendingClaims.list()){if("compensation-required"===n.status)continue;const s=Date.parse(n.expiresAt);!Number.isFinite(s)||s>e||(this.pendingClaims.delete(n.id),t.push(n.id))}return t}}const Vo=o.z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Ko=o.z.string().datetime(),Jo=o.z.enum(["connecting","handshaking","healthy","reconnecting","suspect","offline"]),Qo=o.z.enum(["start","stop","restart","retry-image"]);o.z.object({instanceId:Vo,revision:o.z.number().int().nonnegative(),updatedAt:Ko,status:o.z.enum(["created","provisioning","starting","registering","registered","running","stopping","stopped","deleting","failed","unhealthy"]),health:o.z.enum(["unknown","ok","degraded","failed"]),connectionStatus:o.z.enum(["unknown","online","offline","endpoint-unreachable"]),ready:o.z.boolean(),lastHeartbeatAt:Ko.optional()}).strip();const Yo=o.z.object({code:o.z.string().trim().min(1).max(120),message:o.z.string().trim().min(1).max(2048)}).strict(),Xo=o.z.object({id:Vo,name:o.z.string().trim().min(1).max(160),status:o.z.enum(["unknown","online","offline","degraded"]),health:o.z.enum(["unknown","ok","degraded","failed"]),connectionMode:o.z.enum(["local-ipc","local-loopback","direct-http","reverse-wss","control-plane-proxy"]),connectionPhase:Jo.optional(),lastSeenAt:Ko.optional(),observedAt:Ko,capabilities:o.z.array(o.z.string().trim().min(1).max(120)).max(256),error:Yo.optional()}).strict();o.z.array(Xo);const Zo=o.z.object({id:o.z.string().trim().min(1).max(120),name:o.z.string().trim().min(1).max(120),kind:o.z.enum(["tty","gui","web"]),supportsCwdSelection:o.z.boolean()}).strict(),ea=o.z.object({id:Vo,name:o.z.string().trim().min(1).max(160),nodeId:Vo,status:o.z.enum(["created","provisioning","starting","registering","registered","running","stopping","stopped","deleting","failed","unhealthy"]),health:o.z.enum(["unknown","ok","degraded","failed"]),connectionStatus:o.z.enum(["unknown","online","offline","endpoint-unreachable"]),ready:o.z.boolean(),config:o.z.object({defaultCodexPermissionMode:Q.default("ask")}).strict().default({defaultCodexPermissionMode:"ask"}),lastHeartbeatAt:Ko.optional(),heartbeatAgeMs:o.z.number().int().nonnegative().optional(),observedAt:Ko,runtime:o.z.object({id:Vo,name:o.z.string().trim().min(1).max(160).optional(),type:o.z.enum(["docker","kubernetes","local"]).optional()}).strict(),workspace:o.z.object({status:o.z.enum(["unknown","pending","ready","failed"]),path:o.z.string().trim().max(4096).optional()}).strict(),protocol:o.z.object({version:o.z.string().optional(),compatible:o.z.boolean(),warning:o.z.string().trim().min(1).max(500).optional()}).strict(),aiSessions:De,availableActions:o.z.array(Qo).max(4).default([]),availableApps:o.z.array(Zo).max(256).default([]),availableAgents:o.z.array(Zo).max(256),error:Yo.optional()}).strict();function ta(e){if(!e||"object"!=typeof e)return;const t=e,n=Gn.safeParse(t.build),s=mn.safeParse(t.platform),i=yn.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}:{},...s.success?{platform:s.data}:{},...i.success?{arch:i.data}:{},...n.success?{build:n.data}:{},..."string"==typeof t.serverTime?{serverTime:t.serverTime}:{}}}function na(e){const{agent:t,...n}=e.capabilities,{secret:s,...i}=e.auth,r=i.pairing?{...i.pairing,joinToken:void 0}:void 0,o=ta(t);return{...e,auth:r?{...i,pairing:r}:i,capabilities:o?{...n,agent:o}:n}}function sa(e){const t=e.runtimeVersion?.error,n=e.imageProvisioning?.error,s=e.workspace.error,i=t?{code:t.code,message:"Instance runtime convergence failed. Use the desktop Control Plane for diagnostics."}:n?{code:"IMAGE_PROVISIONING_FAILED",message:"Instance image provisioning failed. Use the desktop Control Plane for diagnostics."}:s?{code:"WORKSPACE_FAILED",message:"Instance workspace preparation failed. Use the desktop Control Plane for diagnostics."}:void 0,r=e.node?.capabilities.agent,o=r&&"object"==typeof r&&!Array.isArray(r)?r:void 0,a="string"==typeof o?.protocolVersion?o.protocolVersion:void 0,d=!a||a===Kt,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 ea.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:i})}function ia(e){return"local-folder"===e.type?{mode:"local-bind",path:"/workspace",readOnly:!1}:{mode:"git-clone",path:"/workspace",readOnly:!1}}function ra(e){return function(e){const{registrationToken:t,target:n,agentStatus:s,targetStatus:i,uiAccessStatus:r,...o}=e;return o}(function(e){const t=`/instances/${encodeURIComponent(e.id)}`,n={strategy:"control-plane-proxy",web:`${t}/`,api:`${t}/api`,ws:`${t}/api`,status:"online"===e.connectionStatus||"online"===e.agentStatus?"reachable":"endpoint-unreachable"};return{...e,access:n}}(e))}function oa(e){const{key:t,...n}=e;return{...n,keyPreview:(s=e.key,s.length<=8?"set":`${s.slice(0,4)}...${s.slice(-4)}`),keySet:!0};var s}function aa(){return(new Date).toISOString()}function da(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 ca(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 la(e){return e instanceof Error?e.message:String(e)}function pa(e,t){const n=new Error(t);throw Object.assign(n,{statusCode:404,code:e}),n}o.z.array(ea);const ua=o.z.object({proxyOrigin:It,inviteToken:o.z.string().trim().min(24).max(512),name:o.z.string().trim().min(1).max(160).optional()}).strict(),ga=o.z.object({data:o.z.object({binding:Mt,closed:o.z.object({abortedRequests:o.z.number().int().nonnegative(),closedSockets:o.z.number().int().nonnegative()}).strict()}).strict()}).strict();class ha{claimOperations=new Map;options;constructor(e){this.options=e}listPendingClaims(){return this.options.privateStore.publicPendingClaims()}async claimNode(e){const t=ua.parse(e),n=aa(),s=Ui("proxy_claim"),i={id:s,claimId:s,proxyOrigin:t.proxyOrigin,...t.name?{requestedName:t.name}:{},sourceControlPlaneId:this.options.privateStore.controlPlaneId(),bindingKeyId:Ui("proxy_key"),credential:Fi(),status:"pending",createdAt:n,updatedAt:n,expiresAt:new Date(Date.now()+864e5).toISOString()};return this.options.privateStore.putPendingClaim(i),this.withClaimLock(i.claimId,()=>this.completeClaim(i,t.inviteToken))}async resumeClaim(e){return this.withClaimLock(e,async()=>{const t=this.options.privateStore.pendingClaimByClaimId(e);return t||pa("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 s=await this.responsePayload(n);if(!n.ok){const i=s?.error?.code;if(i===Tt.InviteInvalid||i===Tt.BindingRevoked)return{deleted:this.options.privateStore.completePendingClaimCompensation(e),compensationRequired:!1,remoteRevoke:i===Tt.BindingRevoked?"already-revoked":"not-created"};throw this.compensationError(t,s?.error?.message||`Proxy claim recovery failed with HTTP ${n.status}.`,void 0,n.status,i,s?.error?.retryable)}const i=mr(Wt,s?.data);this.requireClaimResultIdentity(t,i);const r=this.compensationCredential(t,i);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!==Tt.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,Tt.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),s=n.proxyState;if(!s?.streamId||s.streamId!==t.streamId||void 0===s.revision||t.revision!==s.revision+1){const e=new Error("Proxy target event does not continue the authoritative snapshot cursor.");throw Object.assign(e,{code:Tt.SnapshotRequired,statusCode:409,retryable:!0}),e}return this.putTargetState(n,t.target,{...s,reachability:"reachable",bindingStatus:"revoked"===s.bindingStatus?"revoked":"active",revision:t.revision,observedAt:t.event.createdAt})}markUnavailable(e,t){const n=this.requireProxyNodeIdentity(e),s=aa();return this.options.nodes.put(Gs.parse({...n,status:"degraded",health:"degraded",proxyState:{...n.proxyState,reachability:"unreachable",bindingStatus:n.proxyState?.bindingStatus??"unknown",lastError:t,updatedAt:s},updatedAt:s}))}markBindingRevoked(e,t){const n=this.requireProxyNodeIdentity(e),s=aa();return this.options.nodes.put(Gs.parse({...n,status:"degraded",health:"degraded",proxyState:{...n.proxyState,reachability:"reachable",bindingStatus:"revoked",lastError:t,updatedAt:s},updatedAt:s}))}assertIdentityPatch(e,t){const n=t.connectionMode??e.connectionMode,s=t.connectionPath??e.connectionPath,i=t.auth??e.auth,r="control-plane-proxy"===e.connectionMode||"control-plane-proxy"===e.connectionPath.kind||"proxy-binding"===e.auth.mode,o="control-plane-proxy"===n||"control-plane-proxy"===s.kind||"proxy-binding"===i.mode,a=n!==e.connectionMode||JSON.stringify(s)!==JSON.stringify(e.connectionPath)||JSON.stringify(i)!==JSON.stringify(e.auth);if((r||o)&&a){const e=new Error("Proxy node connection identity can only be changed through the control-plane proxy lifecycle API.");throw Object.assign(e,{statusCode:409,code:"CONTROL_PLANE_PROXY_IDENTITY_IMMUTABLE",retryable:!1}),e}}async deleteNode(e,t=!1){if("control-plane-proxy"!==e.connectionMode)return{deleted:this.options.deleteNode(e.id),revoke:{mode:"not-proxied",orphanRisk:!1}};const n=this.options.privateStore.nodeCredential(e.id);if(!n){if(!t){const e=new Error("Proxy node credential is missing; remote binding cannot be revoked.");throw Object.assign(e,{statusCode:409,code:"CONTROL_PLANE_PROXY_CREDENTIAL_REQUIRED",retryable:!1,details:{forceDeleteAllowed:!0,forceDeleteReason:"credential-missing"}}),e}return this.forceDeleteNode(e.id)}let s;try{s=await this.revokeBinding(n)}catch(n){if(t)return this.forceDeleteNode(e.id);const s=new Error("Trusted control-plane proxy is unavailable; the binding was not revoked.",{cause:n});throw Object.assign(s,{statusCode:503,code:"CONTROL_PLANE_PROXY_REVOKE_UNAVAILABLE",retryable:!0,details:{forceDeleteAllowed:!0,forceDeleteReason:"proxy-unavailable"}}),s}const i=await this.responsePayload(s);if(!s.ok){if(i?.error?.code===Tt.BindingRevoked){const t=i.error.details?.bindingId;if(t===n.proxyBindingId)return this.finishRevokedNodeDelete(e.id)}const t=new Error(i?.error?.message||`Proxy binding revoke failed with HTTP ${s.status}.`);throw Object.assign(t,{statusCode:s.status,code:i?.error?.code||"CONTROL_PLANE_PROXY_REVOKE_FAILED",retryable:i?.error?.retryable??s.status>=500,details:{...(r=i?.error?.details,r&&"object"==typeof r&&!Array.isArray(r)?r:{}),forceDeleteAllowed:!1}}),t}var r;try{this.requireRevocationReceipt(i,n)}catch(e){if(e&&"object"==typeof e){const t=e;t.details={...t.details||{},forceDeleteAllowed:!1}}throw e}return this.finishRevokedNodeDelete(e.id)}async completeClaim(e,t){let n;this.options.privateStore.markCompensationRequired(e.claimId);try{n=await this.requestClaim(e,t)}catch(t){const n=new Error(`Trusted control-plane proxy ${e.proxyOrigin} is unavailable.`,{cause:t});throw Object.assign(n,{statusCode:503,code:"CONTROL_PLANE_PROXY_UNAVAILABLE",retryable:!0,claimId:e.claimId}),n}const s=await this.responsePayload(n);if(!n.ok){const t=s?.error?.retryable??n.status>=500;t||this.options.privateStore.completePendingClaimCompensation(e.claimId);const i=new Error(s?.error?.message||`Proxy claim failed with HTTP ${n.status}.`);throw Object.assign(i,{statusCode:n.status,code:s?.error?.code||"CONTROL_PLANE_PROXY_CLAIM_FAILED",retryable:t,details:s?.error?.details,claimId:e.claimId}),i}const i=mr(Wt,s?.data);this.requireClaimResultIdentity(e,i);const r=this.options.nodes.get(i.target.id),o="control-plane-proxy"===r?.connectionMode&&"control-plane-proxy"===r.connectionPath.kind&&r.connectionPath.proxyBindingId===i.binding.id&&r.connectionPath.targetNodeId===i.target.id;if(r&&!o){this.options.privateStore.markCompensationRequired(e.claimId);const t=new Error(`Node ${i.target.id} already exists with another connection identity.`);throw Object.assign(t,{statusCode:409,code:"CONTROL_PLANE_PROXY_NODE_IDENTITY_CONFLICT",claimId:e.claimId}),t}const a={id:`proxy_credential_${i.target.id}`,nodeId:i.target.id,proxyOrigin:e.proxyOrigin,proxyBindingId:i.binding.id,targetNodeId:i.target.id,sourceControlPlaneId:e.sourceControlPlaneId,bindingKeyId:e.bindingKeyId,credential:e.credential,createdAt:e.createdAt,updatedAt:aa()},d=r||Gs.parse({id:i.target.id,name:e.requestedName||i.target.name,connectionMode:"control-plane-proxy",connectionPath:{kind:"control-plane-proxy",proxyId:new URL(e.proxyOrigin).host,proxyBindingId:i.binding.id,targetNodeId:i.target.id},connectionEnabled:!0,auth:{mode:"proxy-binding"},status:i.target.status,health:i.target.health,capabilities:i.target.capabilities,proxyState:{reachability:"reachable",bindingStatus:i.binding.status,bindingRevision:i.binding.revision,observedAt:aa(),target:i.target,updatedAt:aa()},labels:{},lastSeenAt:i.target.lastSeenAt,createdAt:aa(),updatedAt:aa()});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:na(d),binding:i.binding}}requireProxyNodeIdentity(e,t,n){const s=this.options.requireNode(e);if("control-plane-proxy"!==s.connectionMode||"control-plane-proxy"!==s.connectionPath.kind||void 0!==t&&s.connectionPath.proxyBindingId!==t||void 0!==n&&s.connectionPath.targetNodeId!==n){const e=new Error("Proxy state identity does not match the node connection path.");throw Object.assign(e,{code:Tt.BindingIdentityConflict,statusCode:409,retryable:!1}),e}return s}putTargetState(e,t,n){const s=aa();return this.options.nodes.put(Gs.parse({...e,name:t.name,status:t.status,health:t.health,capabilities:t.capabilities,lastSeenAt:t.lastSeenAt,proxyState:{...n,target:t,updatedAt:s},updatedAt:s}))}requestClaim(e,t){return this.options.fetchImpl(new URL("/api/node-proxy/claims",e.proxyOrigin),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({protocolVersion:ut,...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:qo(e)})}async responsePayload(e){return e.json().catch(()=>{})}requireRevocationReceipt(e,t){const n=hr(ga,e),s=n.success?n.data.data.binding:void 0;if(!s||s.id!==t.proxyBindingId||s.sourceControlPlaneId!==t.sourceControlPlaneId||s.targetNodeId!==t.targetNodeId||s.bindingKeyId!==t.bindingKeyId||"revoked"!==s.status){const e=new Error("Proxy binding revocation receipt does not match the local binding identity.");throw Object.assign(e,{statusCode:502,code:Tt.TransportFailed,retryable:!0,details:{bindingId:t.proxyBindingId}}),e}return s}requireClaimResultIdentity(e,t){if(t.binding.claimId!==e.claimId||t.binding.sourceControlPlaneId!==e.sourceControlPlaneId||t.binding.bindingKeyId!==e.bindingKeyId||t.binding.targetNodeId!==t.target.id||void 0!==e.targetNodeId&&t.binding.targetNodeId!==e.targetNodeId){const t=new Error("Proxy claim response does not match the persisted pending identity.");throw Object.assign(t,{statusCode:409,code:Tt.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:aa()}}compensationError(e,t,n,s=503,i="CONTROL_PLANE_PROXY_COMPENSATION_REQUIRED",r=!0){const o=new Error(t,void 0===n?void 0:{cause:n});return Object.assign(o,{statusCode:s,code:i,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 ma=o.z.object({id:ls.shape.id.optional(),name:ls.shape.name,source:as,defaultImageSelection:ls.shape.defaultImageSelection,defaultNodeId:ls.shape.defaultNodeId,defaultRuntimeId:ls.shape.defaultRuntimeId,workspacePolicy:ds.optional(),labels:ls.shape.labels.optional()}).strict(),ya=ma.omit({id:!0}).partial().strict();function fa(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"/"!==e&&"\\"!==e}const Ia=o.z.string().refine(fa,"Mention trigger must be one printable non-alphanumeric character other than / or \\.");function ba(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"\\"!==e}const va=o.z.string().refine(ba,"Command trigger must be one printable non-alphanumeric character other than \\."),wa=o.z.object({publicBaseUrl:o.z.string().trim().max(2048).optional(),updateChannel:Vn.default("stable"),mentionTrigger:Ia.default("@"),commandTrigger:va.default("/"),diagnosticLogs:o.z.boolean().default(!1)}).strict().refine(e=>e.mentionTrigger!==e.commandTrigger,{path:["commandTrigger"],message:"Command and mention triggers must be different."}),Sa=o.z.object({publicBaseUrl:o.z.string().trim().max(2048).optional(),updateChannel:Vn.optional(),mentionTrigger:Ia.optional(),commandTrigger:va.optional(),diagnosticLogs:o.z.boolean().optional()}).strict(),Aa=o.z.object({id:Ps.shape.id.optional(),name:Ps.shape.name,description:Ps.shape.description,cover:Ps.shape.cover,reference:Ps.shape.reference,pullPolicy:Ps.shape.pullPolicy.optional(),capabilities:o.z.array(o.z.string().trim().min(1).max(80)).optional(),optionalApps:o.z.array(o.z.string().trim().min(1).max(120)).optional(),defaultEnv:Ps.shape.defaultEnv.optional(),labels:Ps.shape.labels.optional()}).strict(),ka=Aa.omit({id:!0}).partial().strict(),za=o.z.object({name:Ii.shape.name.optional(),channel:Ii.shape.channel.optional(),enabled:o.z.boolean().optional(),token:Ii.shape.token,defaultChatId:Ii.shape.defaultChatId,allowedUserIds:o.z.array(o.z.string().trim().min(1).max(240)).optional(),pollIntervalMs:Ii.shape.pollIntervalMs.optional(),settings:Ii.shape.settings.optional()}).strict(),Ta=za.extend({channel:Ii.shape.channel,name:Ii.shape.name.optional()}),Ca=Ze.extend({id:Ze.shape.configHash}),xa=o.z.object({name:Ze.shape.name,description:Ze.shape.description,source:Qe,action:Ye,policy:Xe.partial().optional()}).strict(),Ea=xa,Na=o.z.object({instanceIds:o.z.array(pi.shape.id).min(1),target:et,enabled:o.z.boolean().optional()}).strict(),_a=o.z.object({configHash:Ze.shape.configHash,enabled:o.z.boolean().optional()}).strict(),Pa=o.z.object({mode:o.z.enum(["local-static-key","paired-hmac","proxy-binding"]).default("local-static-key"),keyId:Gs.shape.id.optional(),secret:o.z.string().trim().max(4096).optional(),pairedAt:Gs.shape.createdAt.optional(),pairing:o.z.object({status:o.z.enum(["pending","paired","expired"]).default("pending"),joinToken:o.z.string().trim().max(4096).optional(),expiresAt:Gs.shape.createdAt.optional()}).strict().optional()}).strict(),Ra=o.z.object({autoImportAgentConfigs:o.z.boolean().optional(),defaultCodexPermissionMode:Q.optional()}).strict(),Oa=o.z.object({id:pi.shape.id.optional(),name:pi.shape.name.optional(),projectId:pi.shape.projectId,source:as.optional(),sourceSnapshot:o.z.record(o.z.string(),o.z.unknown()).optional(),nodeId:pi.shape.nodeId.optional(),runtimeId:pi.shape.runtimeId.optional(),environmentSource:gn.optional(),imageSelection:pi.shape.imageSelection,config:Ra.optional(),modelSelection:pi.shape.modelSelection.optional(),start:o.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."})}),ja=o.z.object({name:pi.shape.name.optional(),config:Ra.optional(),modelSelection:pi.shape.modelSelection.optional()}).strict(),Ma=o.z.object({name:ps.shape.name,endpoint:ps.shape.endpoint,key:ps.shape.key,model:ps.shape.model,app:ps.shape.app,enabled:ps.shape.enabled.optional(),order:ps.shape.order.optional(),labels:ps.shape.labels.optional()}).strict(),Da=Ma.partial().strict(),qa=o.z.object({id:Gs.shape.id.optional(),name:Gs.shape.name,connectionMode:Gs.shape.connectionMode.optional(),connectionPath:Gs.shape.connectionPath.optional(),connectionEnabled:Gs.shape.connectionEnabled.optional(),auth:Pa.optional(),joinToken:o.z.string().trim().min(1).max(4096).optional(),endpoint:Gs.shape.endpoint,controlEndpoint:Gs.shape.controlEndpoint,containerEndpoint:Gs.shape.containerEndpoint,publicWebBase:Gs.shape.publicWebBase,status:o.z.enum(["unknown","online","offline","degraded"]).optional(),health:o.z.enum(["unknown","ok","degraded","failed"]).optional(),capabilities:Gs.shape.capabilities.optional(),labels:Gs.shape.labels.optional(),lastSeenAt:Gs.shape.lastSeenAt}).strict(),La=o.z.object({name:Gs.shape.name.optional(),connectionMode:Gs.shape.connectionMode.unwrap().optional(),connectionPath:Gs.shape.connectionPath.unwrap().optional(),connectionEnabled:Gs.shape.connectionEnabled.unwrap().optional(),auth:Pa.optional(),endpoint:Gs.shape.endpoint,controlEndpoint:Gs.shape.controlEndpoint,containerEndpoint:Gs.shape.containerEndpoint,publicWebBase:Gs.shape.publicWebBase,status:Gs.shape.status.unwrap().optional(),health:Gs.shape.health.unwrap().optional(),capabilities:Gs.shape.capabilities.unwrap().optional(),labels:Gs.shape.labels.unwrap().optional(),lastSeenAt:Gs.shape.lastSeenAt}).strict(),$a=o.z.object({controlPlaneUrl:o.z.string().trim().url().max(2048),joinToken:o.z.string().trim().min(1).max(4096),controlPlaneName:o.z.string().trim().min(1).max(160).optional(),activate:o.z.boolean().optional()}).strict(),Ba=o.z.object({nodeName:o.z.string().trim().min(1).max(160).optional(),expiresInMs:o.z.number().int().positive().max(36e5).optional()}).strict(),Ua=o.z.object({id:o.z.string().min(1),endpoint:o.z.string().min(1),nodeId:o.z.string().min(1),keyId:o.z.string().min(1),secret:o.z.string().min(1),pairedAt:o.z.string().min(1),createdAt:o.z.string().min(1),updatedAt:o.z.string().min(1)}).strict();class Fa{options;activePendingPairingRevokes=new Set;constructor(e){this.options=e}async syncLocal(){const e={[this.options.localNodeLabel]:"true",[this.options.builtinNodeLabel]:"true"},t=process.env.TASK_HANDOFF_NODE_AGENT_TOKEN?.trim()||void 0,n=process.env.TASK_HANDOFF_NODE_AGENT_CONTROL_ENDPOINT||process.env.TASK_HANDOFF_NODE_AGENT_ENDPOINT||"http://127.0.0.1:8091",s=function(e){return zo(e)?"local-ipc":"local-loopback"}(n),i=Gs.parse({id:"node_local_probe",name:"Local Node Probe",connectionMode:s,auth:{mode:"local-static-key",secret:t},labels:e,createdAt:aa(),updatedAt:aa()}),r=await this.inspect(n,i),o=aa(),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(Gs.parse({...a||{},id:r.nodeId,name:a?.name||"Local Node",connectionMode:s,auth:{mode:"local-static-key",secret:t},endpoint:n,controlEndpoint:n,containerEndpoint:process.env.TASK_HANDOFF_NODE_AGENT_CONTAINER_URL,publicWebBase:process.env.TASK_HANDOFF_INSTANCE_PUBLIC_WEB_BASE,status:"online",health:"ok",capabilities:{...a?.capabilities||{},agent:ta(r.data)},labels:{...a?.labels||{},...e},createdAt:a?.createdAt||o,updatedAt:o}))}async create(e){const t=qa.parse(e),n=aa(),s=t.connectionMode||"direct-http";let i="auth"in(e&&"object"==typeof e&&!Array.isArray(e)?e:{})?t.auth:{mode:"local-ipc"===s||"local-loopback"===s?"local-static-key":"paired-hmac"};const r="direct-http"===s||"reverse-wss"===s;if(r&&"paired-hmac"!==i.mode)throw Ha("Remote node connections require paired-HMAC authentication.","NODE_AGENT_REMOTE_REQUIRES_PAIRED_HMAC");const o=t.controlEndpoint||t.endpoint;if(!o&&"reverse-wss"!==s)throw Ha("Node agent direct HTTP mode requires an endpoint.","NODE_AGENT_ENDPOINT_REQUIRED");const a=t.joinToken&&o?await this.completePairing(o,t.joinToken):void 0;let d,c=!1;try{if(d=a&&o?this.pendingPairingRevoke(o,a):void 0,d&&(this.activePendingPairingRevokes.add(d.id),this.options.pendingPairingRevokes?.put(d)),a){if(a.invalidResponse||a.unsafePublicIdentifiers)throw Object.assign(new Error("Node agent pairing response reflected secret material in a public identifier."),{statusCode:502,code:"NODE_AGENT_PAIRING_RESPONSE_INVALID"});i={mode:"paired-hmac",keyId:a.keyId,secret:a.secret,pairedAt:a.pairedAt,pairing:{status:"paired"}}}if(r&&!i.secret)throw Ha("Remote node connections require a paired node secret or join token.","NODE_AGENT_REMOTE_SECRET_REQUIRED");if(r&&!i.keyId)throw Ha("Remote node connections require a paired key id.","NODE_AGENT_REMOTE_KEY_ID_REQUIRED");const e=t.id||a?.nodeId||Ui("node"),u=Gs.parse({id:e,name:t.name,connectionMode:s,auth:i,labels:t.labels||{},createdAt:n,updatedAt:n}),g="reverse-wss"===s&&(t.id||a?.nodeId)?void 0:await this.inspect(o||"",u),h=t.id||a?.nodeId||g?.nodeId||e;if(!h)throw Ha("Node id is required.","NODE_ID_REQUIRED");if(a&&t.id&&t.id!==a.nodeId)throw Ha(`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 Ha(`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=Gs.parse({...y,id:h,connectionMode:s,auth:i,endpoint:o,controlEndpoint:o,status:t.status||(g?"online":"unknown"),health:t.health||(g?"ok":"unknown"),capabilities:{...t.capabilities||{},...g?{agent:ta(g.data)}:{}},labels:t.labels||{},createdAt:n,updatedAt:n});if(a&&(l=f,p=a.secret,Ja(na(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 Qa(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),Qa(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=aa();return Ua.parse({id:Ui("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?Va(t.nodeId,t.secret):void 0,keyId:t?Va(t.keyId,t.secret):void 0,errorCode:"NODE_AGENT_PAIRING_OUTBOX_CLEANUP_FAILED"},"node agent pairing outbox cleanup failed; recovery will retry")}catch{}}}async inspect(e,t){const n="/health",s=t?So(t,{method:"GET",pathWithQuery:`/api/node-agent${n}`}):{},i=await No(this.options.fetchImpl,e,n,{headers:s}),r=await i.json().catch(()=>({}));if(!i.ok)throw this.options.warn(Ka({nodeEndpoint:e,statusCode:i.status,errorCode:"NODE_AGENT_HEALTH_FAILED"},t?.auth.secret),"node agent health check failed"),Object.assign(new Error(r.error?.message||`Node agent health check failed with HTTP ${i.status}`),{statusCode:i.status,code:"NODE_AGENT_HEALTH_FAILED"});const o="string"==typeof r.data?.nodeId&&r.data.nodeId.trim()?r.data.nodeId.trim():void 0;if(!o)throw this.options.warn(Ka({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=hr(Gn,r.data?.build);return r.data?.protocolVersion!==Kt&&this.options.warn(Ka({nodeId:o,nodeEndpoint:e,expectedProtocolVersion:Kt,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(Ka({nodeId:o,nodeEndpoint:e,protocolVersion:r.data.protocolVersion,build:a.success?a.data:void 0},t?.auth.secret),"node agent health check ok"),{nodeId:o,data:r.data||{}}}async completePairing(e,t){const n=await this.options.fetchImpl(`${e.replace(/\/$/,"")}/api/node-agent/pairing/complete`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({joinToken:t,controlPlaneName:"Control Plane"})}),s=await n.json().catch(()=>({}));if(!n.ok)throw Object.assign(new Error(s.error?.message||`Node agent pairing failed with status ${n.status}.`),{statusCode:n.status,code:"NODE_AGENT_PAIRING_FAILED"});const i=s.data;if("string"!=typeof i?.nodeId||!i.nodeId.trim()||"string"!=typeof i?.keyId||!i.keyId.trim()||"string"!=typeof i?.secret||!i.secret.trim())throw Object.assign(new Error("Node agent pairing response did not include nodeId, keyId, and secret."),{statusCode:502,code:"NODE_AGENT_PAIRING_RESPONSE_INVALID"});const r=hr(Xs,i),o=i.nodeId.trim(),a=i.keyId.trim(),d=i.secret.trim();return{nodeId:o,keyId:a,secret:d,pairedAt:r.success?r.data.pairedAt:aa(),invalidResponse:!r.success,unsafePublicIdentifiers:o.includes(d)||a.includes(d)}}async compensatePairing(e,t,n){const s="/pairing/current",i=`/api/node-agent${s}`,r={id:t.nodeId,connectionMode:"direct-http",auth:{mode:"paired-hmac",keyId:t.keyId,secret:t.secret}};try{const o=await No(this.options.fetchImpl,e,s,{method:"DELETE",headers:So(r,{method:"DELETE",pathWithQuery:i}),signal:AbortSignal.timeout(1e4)}),a=await o.json().catch(()=>({}));if(!o.ok)throw Object.assign(new Error(`Node agent pairing revoke failed with HTTP ${o.status}.`),{statusCode:o.status,code:Ga(a.error?.code,t.secret,"NODE_AGENT_PAIRING_REVOKE_FAILED"),retryable:408===o.status||429===o.status||o.status>=500});const d=hr(ei,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:Va(t.nodeId,t.secret),keyId:Va(t.keyId,t.secret),originalErrorCode:Wa(n,t.secret)},"node agent pairing revoked after node creation failed")}catch{}}catch(e){const s={nodeId:Va(t.nodeId,t.secret),keyId:Va(t.keyId,t.secret),originalErrorCode:Wa(n,t.secret),compensationErrorCode:Wa(e,t.secret)};try{this.options.warn(s,"node agent pairing compensation failed")}catch{}throw Object.assign(new Error("Node creation failed after pairing, and the remote pairing could not be revoked."),{statusCode:502,code:"NODE_AGENT_PAIRING_COMPENSATION_FAILED",retryable:(o=e,!o||"object"!=typeof o||!("retryable"in o)||"boolean"!=typeof o.retryable||o.retryable),details:s})}var o}}function Ha(e,t){return Object.assign(new Error(e),{statusCode:400,code:t})}function Wa(e,t){return Ga(e&&"object"==typeof e&&"code"in e?e.code:void 0,t,"UNKNOWN_ERROR")}function Ga(e,t,n){return"string"!=typeof e||!/^[A-Z][A-Z0-9_]{0,127}$/.test(e)||e.includes(t)?n:e}function Va(e,t){return e.includes(t)?"[redacted]":e}function Ka(e,t){if(!t)return e;const n=e=>"string"==typeof e?e.includes(t)?"[redacted]":e:Array.isArray(e)?e.map(n):e&&"object"==typeof e?Object.fromEntries(Object.entries(e).map(([e,s])=>[e.includes(t)?"[redacted-key]":e,n(s)])):e;return n(e)}function Ja(e,t){return"string"==typeof e?e.includes(t):Array.isArray(e)?e.some(e=>Ja(e,t)):!(!e||"object"!=typeof e)&&Object.entries(e).some(([e,n])=>e.includes(t)||Ja(n,t))}function Qa(e,t){const n=e instanceof Error&&!e.message.includes(t)?e.message:"Node creation failed after pairing.",s=e&&"object"==typeof e&&"statusCode"in e&&"number"==typeof e.statusCode?e.statusCode:502,i=Object.assign(new Error(n),{statusCode:s,code:Wa(e,t)});return e&&"object"==typeof e&&"retryable"in e&&"boolean"==typeof e.retryable&&Object.assign(i,{retryable:e.retryable}),i}class Ya{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 Xa=o.z.object({joinToken:o.z.string().trim().min(1).max(4096),nodeId:Gs.shape.id,nodeName:Gs.shape.name.optional(),keyId:o.z.string().trim().min(1).max(160),secret:o.z.string().trim().min(1).max(4096),pairedAt:o.z.string().datetime().optional()}).strict();class Za{options;invites=new Ya;constructor(e){this.options=e}createInvite(e={}){const t=Ba.parse(e&&"object"==typeof e?e:{}),n=Fi(),s={id:Ui("node_join"),tokenHash:ed(n),expiresAt:new Date(Date.now()+(t.expiresInMs||6e5)).toISOString(),...t.nodeName?{nodeName:t.nodeName}:{}};return this.invites.put(s.tokenHash,s),{id:s.id,joinToken:n,expiresAt:s.expiresAt}}complete(e){const t=Xa.parse(e),n=ed(t.joinToken),s=this.invites.take(n);if(!s)throw Object.assign(new Error("Node join token is invalid or expired."),{statusCode:401,code:"NODE_JOIN_TOKEN_INVALID"});const i=aa();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(Gs.parse({id:t.nodeId,name:t.nodeName||s.nodeName||t.nodeId,connectionMode:"reverse-wss",auth:{mode:"paired-hmac",keyId:t.keyId,secret:t.secret,pairedAt:t.pairedAt||i,pairing:{status:"paired"}},status:"unknown",health:"unknown",capabilities:{},labels:{},createdAt:i,updatedAt:i}))}}function ed(e){return a.createHash("sha256").update(e).digest("hex")}class td{options;constructor(e){this.options=e}list(){return this.listAll().map(oa)}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:oa(e),locations:[{type:"control-plane",name:e.name,enabled:e.enabled,order:e.order}],referenceCount:0});for(const{nodeId:e,model:s}of t.items){const{referenceCount:t,...i}=s,r=n.get(s.id);r?(r.locations.push({type:"node",nodeId:e,name:s.name,enabled:s.enabled,order:s.order,referenceCount:s.referenceCount}),r.referenceCount+=s.referenceCount):n.set(s.id,{id:s.id,model:i,locations:[{type:"node",nodeId:e,name:s.name,enabled:s.enabled,order:s.order,referenceCount:s.referenceCount}],referenceCount:s.referenceCount})}return Is.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:aa()})}create(e){const t=Ma.parse(e),n=aa(),s=bs(t),i=this.options.models.get(s),r=ps.parse({...t,id:s,enabled:t.enabled??!0,order:t.order??this.nextOrder(),labels:t.labels||{},createdAt:i?.createdAt||n,updatedAt:n});return oa(this.options.models.put(r))}update(e,t){const n=Da.parse(t),s=this.requireSecret(e),i=ps.parse({...s,...n,key:n.key?.trim()?n.key:s.key,createdAt:s.createdAt,updatedAt:aa()}),r=bs(i);return oa(this.options.models.put(ps.parse({...i,id:r})))}delete(e){return this.requireSecret(e),this.options.models.delete(e)}reorder(e){const t=[...new Set(e)],n=new Map(this.options.models.list().map(e=>[e.id,e]));for(const e of t)n.has(e)||pa("MODEL_NOT_FOUND",`Model ${e} was not found.`);return t.forEach((e,t)=>{const s=n.get(e);this.options.models.put(ps.parse({...s,order:100*(t+1),updatedAt:aa()}))}),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:oa(n)}async prepareAssignment(e,t){const n=await this.options.gateway.listModels(e),s={...null===t.codexModelHash?{codexModelHash:null}:t.codexModelHash?.trim()?{codexModelHash:t.codexModelHash.trim()}:{},...null===t.claudeModelHash?{claudeModelHash:null}:t.claudeModelHash?.trim()?{claudeModelHash:t.claudeModelHash.trim()}:{}},i=async(t,s)=>{if(null===s)return;const i=s?this.listAll().find(e=>e.id===s):this.listAll().find(e=>e.enabled&&e.app===t);if(i)return nd(i,t),await this.options.gateway.deployModel(e,i.id,i),i.id;if(!s)return;const r=n.find(e=>e.id===s);return r||pa("MODEL_NOT_FOUND",`Model ${s} was not found on control-plane or node ${e.id}.`),nd(r,t),r.id};return{modelSelection:s,codexModelHash:await i("codex",s.codexModelHash),claudeModelHash:await i("claude",s.claudeModelHash)}}async ensureInstanceAssignment(e){const t=this.options.requireNode(e.nodeId),n=await this.prepareAssignment(t,e.modelSelection);return this.options.gateway.assignInstanceModels(t,e.id,n)}listAll(){return this.options.models.list().map(e=>this.normalize(e)).sort((e,t)=>e.order-t.order||e.createdAt.localeCompare(t.createdAt)||e.id.localeCompare(t.id))}requireSecret(e){const t=this.options.models.get(e);return t||pa("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,ps.parse(t)}return ps.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 nd(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 sd{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}id(e);const s=this.requireNode(e.nodeId),i=await this.nodeAgentTransport(s).request(s,`/instances/${encodeURIComponent(e.id)}/proxy`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({path:`/api/${t.replace(/^\/+/,"")}`,method:n.method||"GET",headers:da(n.headers),body:(r=n.body,"string"==typeof r?r:null==r?void 0:String(r))})});var r;const o=await i.json().catch(()=>({}));if(!i.ok){const n=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n="string"==typeof t.code&&t.code.trim()?t.code:void 0,s="string"==typeof t.message&&t.message?t.message:void 0,i=t.details&&"object"==typeof t.details&&!Array.isArray(t.details)?t.details:void 0;return n||s?{code:n,message:s,details:i}:void 0}(o.error),s=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 ${i.status}`,r=new Error(s);throw Object.assign(r,{statusCode:i.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}id(e);const s=this.requireNode(e.nodeId),i=await this.nodeAgentTransport(s).requestStream(s,`/instances/${encodeURIComponent(e.id)}/proxy/stream`,{method:"POST",headers:{"content-type":"application/json"},signal:n.signal,body:JSON.stringify({path:t,method:n.method||"GET",headers:da(n.headers),...(r=n.body,null==r?{}:"string"==typeof r?{body:r}:Buffer.isBuffer(r)?{bodyBase64:r.toString("base64")}:r instanceof Uint8Array?{bodyBase64:Buffer.from(r).toString("base64")}:{body:String(r)})})});var r;return{status:i.status||502,headers:Object.fromEntries(i.headers.entries()),body:i.body}}proxyWebSocket(e,t,n,s,i={}){if(!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=new Error(`Instance ${e.name} web endpoint is not reachable.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_WEB_UNREACHABLE"}),t}id(e);const r=this.requireNode(e.nodeId),o=n.startsWith("/")?n.slice(1):n;this.nodeAgentTransport(r).proxyWebSocket(r,t,`/instances/${encodeURIComponent(e.id)}/proxy/ws/${o}`,s,i)}async reportHeartbeat(e,t){if(!e.registrationToken)return;const n=this.requireNode(e.nodeId),s=`/instances/${encodeURIComponent(e.id)}/heartbeat`,i={method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.registrationToken}`},body:JSON.stringify(t)},r=await this.nodeAgentTransport(n).request(n,s,i),o=await r.json().catch(()=>({}));if(!r.ok){const e=new Error(o.error?.message||`Instance heartbeat sync failed with HTTP ${r.status}`);throw Object.assign(e,{statusCode:r.status,code:"INSTANCE_HEARTBEAT_SYNC_FAILED"}),e}}}function id(e){if(Si(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 rd{read(e){const t=new Map(e.projects.map(e=>[e.id,e])),n=new Map(e.images.map(e=>[e.id,e])),s=new Map(e.nodes.map(e=>[e.id,e])),i=new Map(e.runtimes.map(e=>[`${e.nodeId}:${e.id}`,e])),r=Date.now();return{items:e.instances.map(e=>function(e){const t=e.instance.lastHeartbeatAt?e.currentTime-Date.parse(e.instance.lastHeartbeatAt):void 0,n=void 0!==t&&t>3e4?"offline":e.instance.connectionStatus,s=ra(e.instance);return{...s,aiSessions:qe(s.aiSessions),connectionStatus:n,heartbeatAgeMs:t,project:e.project,image:e.image,node:e.node?na(e.node):void 0,runtime:e.runtime,protocolCompatible:!e.instance.protocolVersion||e.instance.protocolVersion===Kt}}({instance:e,currentTime:r,project:e.projectId?t.get(e.projectId):void 0,image:e.imageSnapshot||(e.imageSelection?n.get(e.imageSelection.imageId):void 0),node:s.get(e.nodeId),runtime:i.get(`${e.nodeId}:${e.runtimeId}`)})),nodeErrors:e.nodeErrors||[]}}}class od{options;constructor(e){this.options=e}async create(e){const t=Oa.parse(e),n=t.projectId?this.options.requireProject(t.projectId):void 0,s=t.runtimeId||n?.defaultRuntimeId||"runtime_local_docker",i=t.nodeId||n?.defaultNodeId||this.options.defaultNodeId();if(!i)throw dd("At least one node connection is required before creating an instance.",400,"NODE_REQUIRED");const r=this.options.requireNode(i),o=await this.options.requireRuntime(r.id,s),a=o.capabilities.requiresImage??"local"!==o.type,d=t.environmentSource||(t.imageSelection?{type:"image",imageSelection:t.imageSelection}:void 0)||(a&&n?.defaultImageSelection?{type:"image",imageSelection:n.defaultImageSelection}:void 0);if("template"===d?.type&&"docker"!==o.type)throw dd(`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 dd(`Environment template ${p.id} is ${p.status}.`,409,"ENVIRONMENT_TEMPLATE_NOT_READY");if(p&&p.nodeId!==r.id)throw dd(`Environment template ${p.id} belongs to node ${p.nodeId}.`,409,"ENVIRONMENT_TEMPLATE_NODE_MISMATCH");if(a&&!l&&!p)throw dd(`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=aa();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:s,...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:ad(e,"INSTANCE_START_FAILED")},y=await this.options.gateway.listInstances(r).then(e=>e.find(e=>e.id===y.id)||y).catch(()=>y)}return{...ra(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 dd("Instance source is required.",400,"INSTANCE_SOURCE_REQUIRED");if("local"===e.runtime.type&&"local-folder"!==t.type)throw dd("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 dd(`Local folder ${t.path} belongs to node ${t.ownerNodeId}, not ${e.node.id}.`,400,"LOCAL_FOLDER_REQUIRES_OWNER_NODE");const s=t.localFolderId?await this.options.requireLocalFolder(e.node,t.localFolderId):await this.options.gateway.createLocalFolder(e.node,{name:"string"==typeof n.name?n.name:"Local folder",path:t.path,defaultImageSelection:e.imageOption?{imageId:e.imageOption.id,tag:e.imageOption.tag}:void 0});return t={...t,localFolderId:s.id,ownerNodeId:s.nodeId,path:s.path},n=s,{value:t,snapshot:n}}}function ad(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 dd(e,t,n){return Object.assign(new Error(e),{statusCode:t,code:n})}class cd{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:ld(e),deploymentCount:0,enabledCount:0,runningCount:0,errorCount:0,ownedByControlPlane:!0,controlPlaneDeploymentCount:0,deployments:[],recentRuns:[]});for(const n of e){const e=n.triggers;for(const s of e?.configs||[]){const i=t.get(s.configHash)||{configHash:s.configHash,config:s.config,deploymentCount:0,enabledCount:0,runningCount:0,errorCount:0,ownedByControlPlane:!1,controlPlaneDeploymentCount:0,deployments:[],recentRuns:[]},r=(s.deployments||[]).map(e=>({instanceId:n.id,instanceName:n.name,deployment:e,runtime:(s.runtime||[]).find(t=>t.deploymentId?t.deploymentId===e.deploymentId:t.configHash===e.configHash)}));i.deploymentCount+=r.length,i.enabledCount+=r.filter(e=>Boolean(e.deployment.enabled)).length,i.controlPlaneDeploymentCount+=r.filter(e=>"control-plane"===e.deployment.origin).length,i.runningCount+=(s.runtime||[]).filter(e=>"running"===e.status).length,i.errorCount+=(s.runtime||[]).filter(e=>"error"===e.status).length,i.deployments.push(...r),i.recentRuns.push(...(e.recentRuns||[]).filter(e=>e.configHash===s.configHash).map(e=>({...e,instanceId:n.id,instanceName:n.name}))),t.set(s.configHash,i)}}return at.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=xa.parse(e||{}),n=aa(),s={maxConcurrentRuns:t.policy?.maxConcurrentRuns??1,whenBusy:t.policy?.whenBusy??"skip",cooldownMs:t.policy?.cooldownMs},i=dt({source:t.source,action:t.action,policy:s}),r=Ca.parse({id:i,configHash:i,name:t.name,description:t.description,source:t.source,action:t.action,policy:s,createdAt:n,updatedAt:n});return this.triggers.put(r)}async updateTrigger(e,t){const n=this.requireTrigger(e),s=Ea.parse(t||{}),i=aa(),r={maxConcurrentRuns:s.policy?.maxConcurrentRuns??1,whenBusy:s.policy?.whenBusy??"skip",cooldownMs:s.policy?.cooldownMs},o=dt({source:s.source,action:s.action,policy:r});if(o!==e&&this.triggers.get(o)){const e=new Error(`Trigger ${o} already exists.`);throw Object.assign(e,{statusCode:409,code:"TRIGGER_ALREADY_EXISTS"}),e}const a=Ca.parse({id:o,configHash:o,name:s.name,description:s.description,source:s.source,action:s.action,policy:r,createdAt:n.createdAt,updatedAt:i}),d=await this.listInstances(),c=[];for(const t of d){const n=t.triggers?.configs?.find(t=>t.configHash===e),s=(n?.deployments||[]).filter(e=>"control-plane"===e.origin);if(o!==e)for(const n of s){const s="ai-session"===n.target.type?pd(n.target.aiSessionId,o):n.deploymentId,i=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:s,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:s,data:i})}else s.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(),s=[];for(const t of n){const n=t.triggers?.configs?.find(t=>t.configHash===e);if(!n)continue;const i=(n.deployments||[]).filter(e=>"control-plane"===e.origin);if(!i.length)continue;const r=n.deployments.every(e=>"control-plane"===e.origin);for(const n of i)try{const i=n.deploymentId?`/triggers/${encodeURIComponent(e)}/deployments/${encodeURIComponent(n.deploymentId)}`:r?`/triggers/${encodeURIComponent(e)}`:void 0;if(!i){s.push({instanceId:t.id,configHash:e,deploymentId:n.deploymentId,deleted:!1,skipped:"missing-deployment-id"});continue}const o=await this.instanceRequest(t,i,{method:"DELETE"});if(s.push({instanceId:t.id,configHash:e,deploymentId:n.deploymentId,deleted:!0,data:o}),!n.deploymentId)break}catch(i){s.push({instanceId:t.id,configHash:e,deploymentId:n.deploymentId,deleted:!1,error:i instanceof Error?i.message:String(i)})}}return t||s.length||pa("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),{configHash:e,deletedTemplate:t,results:s}}async applyTrigger(e,t){const n=this.requireTrigger(e),s=Na.parse(t||{}),i=[];for(const e of s.instanceIds){const t=await this.requireInstance(e);i.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:s.enabled??!0,target:s.target}})})})}return{configHash:e,results:i}}async listInstanceTriggers(e){const t=await this.requireInstance(e);return this.instanceRequest(t,"/triggers")}async bindAiSessionTrigger(e,t,n){const s=_a.parse(n||{}),i=this.requireTrigger(s.configHash),r=await this.requireInstance(e);return this.instanceRequest(r,"/triggers",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:i.name,description:i.description,source:i.source,action:i.action,policy:i.policy,deployment:{deploymentId:pd(t,s.configHash),origin:"control-plane",enabled:s.enabled??!0,target:{type:"ai-session",aiSessionId:t}}})})}async unbindAiSessionTrigger(e,t,n){const s=await this.requireInstance(e),i=pd(t,n);return this.instanceRequest(s,`/triggers/${encodeURIComponent(n)}/deployments/${encodeURIComponent(i)}`,{method:"DELETE"})}async runInstanceTrigger(e,t,n={}){const s=await this.requireInstance(e);return this.instanceRequest(s,`/triggers/${encodeURIComponent(t)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n||{})})}requireTrigger(e){const t=this.triggers.get(e);return t||pa("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),t}}function ld(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 pd(e,t){return`ai_${Buffer.from(e).toString("base64url")}_${t}`}class ud{options;constructor(e){this.options=e}getSettings(){return wa.parse(this.options.settings.get())}updateSettings(e){const t=Sa.parse(e),n=wa.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=ma.parse(e),n=aa(),s=as.parse(t.source);return this.options.projects.put(ls.parse({...t,id:t.id||Ui("proj"),source:s,defaultImageSelection:t.defaultImageSelection||{imageId:"market_taskhandoff_browser"},defaultNodeId:t.defaultNodeId||this.options.defaultNodeId(),defaultRuntimeId:t.defaultRuntimeId||"runtime_local_docker",workspacePolicy:ds.parse(t.workspacePolicy||ia(s)),labels:t.labels||{},createdAt:n,updatedAt:n}))}updateProject(e,t){const n=ya.parse(t),s=this.requireProject(e),i=n.source?as.parse(n.source):s.source;return this.options.projects.put(ls.parse({...s,...n,id:e,source:i,workspacePolicy:n.workspacePolicy?ds.parse(n.workspacePolicy):s.workspacePolicy,createdAt:s.createdAt,updatedAt:aa()}))}deleteProject(e){return this.options.projects.delete(e)}requireProject(e){const t=this.getProject(e);return t||pa("PROJECT_NOT_FOUND",`Project ${e} was not found.`),t}listImages(){return this.options.images.list()}getMarketCatalog(){return{catalog:this.options.market.getCatalog(),status:this.options.market.getStatus()}}listImageOptions(e){return[...this.options.market.getCatalog().items.map(t=>this.marketImageOption(t,void 0,e,!0)),...this.listImages().map(e=>this.customImageOption(e))]}resolveImageSelection(e,t){const n=this.options.market.getCatalog().items.find(t=>t.id===e.imageId);if(n)return this.marketImageOption(n,e.tag,t);const s=this.options.images.get(e.imageId);if(s||pa("IMAGE_NOT_FOUND",`Image ${e.imageId} was not found.`),e.tag&&e.tag!==s.tag)throw Object.assign(new Error(`Custom image ${s.id} cannot override its stored tag.`),{statusCode:400,code:"CUSTOM_IMAGE_TAG_OVERRIDE"});return this.customImageOption(s)}createImage(e){const t=Aa.parse(e),n=aa(),s=dn(t.reference);return this.options.images.put(Ps.parse({...t,id:t.id||Ui("img"),origin:"custom",reference:s.reference,repository:s.repository,tag:s.tag,pullPolicy:t.pullPolicy||"if-not-present",capabilities:t.capabilities||[],optionalApps:t.optionalApps||[],defaultEnv:t.defaultEnv||{},labels:t.labels||{},createdAt:n,updatedAt:n}))}updateImage(e,t){const n=ka.parse(t),s=this.requireImage(e),i=dn(n.reference||s.reference);return this.options.images.put(Ps.parse({...s,...n,id:e,origin:"custom",reference:i.reference,repository:i.repository,tag:i.tag,createdAt:s.createdAt,updatedAt:aa()}))}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||pa("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={...zn(e)};return"defaultRuntimeId"in t||(t.defaultRuntimeId="runtime_local_docker"),ls.parse(t)}return ls.parse(e)}(e);return t!==e&&this.options.projects.put(t),t}customImageOption(e){return Os.parse({id:e.id,origin:"custom",name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover||As,repository:e.repository,tag:e.tag,availableTags:e.tag?[{name:e.tag,reference:e.reference,status:"active"}]:[],reference:e.reference,capabilities:e.capabilities,optionalApps:e.optionalApps,defaultEnv:e.defaultEnv,labels:e.labels,readOnly:!1})}marketImageOption(e,t,n,s=!1){if("yanked"===e.status&&!s)throw Object.assign(new Error(`Market image ${e.id} is no longer selectable.`),{statusCode:409,code:"MARKET_IMAGE_YANKED"});const i=t||e.defaultTag,r=e.tags.find(e=>e.name===i);if(!r)throw Object.assign(new Error(`Market image ${e.id} does not provide tag ${i}.`),{statusCode:400,code:"MARKET_IMAGE_TAG_NOT_FOUND"});if("yanked"===r.status&&!s)throw Object.assign(new Error(`Market image tag ${e.id}:${i} is no longer selectable.`),{statusCode:409,code:"MARKET_IMAGE_TAG_YANKED"});const o=r.platforms.find(e=>!(n?.os&&e.os!==n.os||n?.architecture&&e.architecture!==n.architecture)),a=this.options.market.getCatalog();return Os.parse({id:e.id,origin:"market",name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover||As,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 gd(e){const t=dn(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:As,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 hd(){const e=(t=process.env.TASK_HANDOFF_BUILT_AT)&&!Number.isNaN(Date.parse(t))?new Date(t).toISOString():(new Date).toISOString();var t;return Ns.parse({protocolVersion:"2026-07-29",catalogId:"task_handoff_embedded",revision:process.env.TASK_HANDOFF_VERSION||"0.0.1",source:"embedded",generatedAt:e,items:[gd({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"]}),gd({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"]}),gd({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 md{async loadCatalog(){return hd()}}class yd{snapshot;status;constructor(e=hd()){this.snapshot=Ns.parse(e),this.status=_s.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=Ns.safeParse(e);return t.success?(this.snapshot=t.data,this.status=_s.parse({source:t.data.source,state:"ready",revision:t.data.revision,updatedAt:(new Date).toISOString()}),{accepted:!0,snapshot:t.data}):(this.status=_s.parse({...this.status,state:"failed",updatedAt:(new Date).toISOString(),error:t.error.message}),{accepted:!1,error:t.error})}recordRefreshFailure(e){return this.status=_s.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 fd{records=new Map;options;constructor(e){this.options=e}create(e){const t=a.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 Id{requireInstance;listAppSessions;tokens=new fd({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=Jr(t);if("vnc"!==n){const e=new Error("This app session does not expose a VNC view.");throw Object.assign(e,{statusCode:409,code:"APP_SESSION_ACCESS_UNAVAILABLE"}),e}if("running"!==t.status){const e=new Error("The app session is not running.");throw Object.assign(e,{statusCode:409,code:"APP_SESSION_NOT_RUNNING"}),e}return this.createToken({...e,mode:n})}resolveToken(e,t){return this.tokens.resolve(e,e=>!t||e.mode===t)}revokeToken(e,t){this.tokens.revoke(e,e=>e.instanceId===t.instanceId&&e.sessionId===t.sessionId)}async proxyTarget(e,t,n=""){const s=this.resolveToken(e,t),i=await this.requireInstance(s.instanceId),r=await this.requireSession(s.instanceId,s.sessionId);return{access:s,instance:i,session:r,path:bd(t,s.sessionId,r,n)}}async requireSession(e,t){const n=await this.listAppSessions(),s=n.instances.find(t=>t.instanceId===e)?.appSessions.sessions.find(e=>wd(e.id)===t);if(s)return s;const i=new Error("App session was not found.");throw Object.assign(i,{statusCode:404,code:"APP_SESSION_NOT_FOUND"}),i}}function bd(e,t,n,s=""){return"tty"===e?`/api/apps/sessions/${encodeURIComponent(t)}/tty`:"vnc"===e?s?function(e,t){const n=`/${t.replace(/^\/+/,"")}`,s=n.split("?",1)[0]||"/",i=encodeURIComponent(e);if(!["/api/novnc/",`/api/apps/sessions/${i}/web/`,`/api/apps/sessions/${i}/vnc`,`/api/apps/sessions/${i}/novnc/`].some(e=>s===e.replace(/\/$/,"")||s.startsWith(e))){const e=new Error("App access token cannot be used for this path.");throw Object.assign(e,{statusCode:403,code:"APP_ACCESS_PATH_FORBIDDEN"}),e}return n}(t,s):wd(vd(n.vnc).noVncPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`:wd(vd(n.web).webPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`}function vd(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function wd(e){return"string"==typeof e&&e.trim()?e.trim():void 0}const Sd={allow:"a",deny:"d",skip:"s"};function Ad(e){return a.createHash("sha256").update(e).digest("base64url").slice(0,Math.ceil(16))}class kd{tokens=new fd({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:${Sd[t]}:${Ad(e)}`}}function zd(e){const{token:t,...n}=e;return{...n,settings:Cd(e.settings),tokenSet:Boolean(e.token)}}function Td(e,t){if(!t)return e;const n={...e};for(const[e,s]of Object.entries(t))void 0!==s&&""!==s&&(n[e]=s);return n}function Cd(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 xd{chatBridges;chatSessions;constructor(e){this.chatBridges=e.chatBridges,this.chatSessions=e.chatSessions}list(){return this.chatBridges.list().map(zd)}require(e){const t=this.chatBridges.get(e);return t||pa("CHAT_BRIDGE_NOT_FOUND",`Chat bridge ${e} was not found.`),t}create(e){const t=Ta.parse(e),n=aa(),s=Ii.parse({...t,id:Ui(`chat_${t.channel}`),name:t.name||(i=t.channel,r=this.chatBridges.list().filter(e=>e.channel===t.channel).length+1,`${"telegram"===i?"Telegram":"wechat"===i?"WeChat":"dingding"===i?"DingDing":"lark"===i?"Lark":"Web"} ${r}`),enabled:t.enabled??!1,allowedUserIds:t.allowedUserIds||[],pollIntervalMs:t.pollIntervalMs||3e3,settings:Td({},t.settings),createdAt:n,updatedAt:n});var i,r;return this.chatBridges.put(s),zd(s)}update(e,t){const n=za.parse(t),s=this.require(e),i=Td(s.settings,n.settings),r=Ii.parse({...s,...n,id:e,channel:s.channel,name:n.name||s.name,settings:i,updatedAt:aa()});return this.chatBridges.put(r),zd(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 Ed{chatSessions;constructor(e){this.chatSessions=e.chatSessions}list(){return this.chatSessions.list()}require(e){const t=this.chatSessions.get(e);return t||pa("CHAT_SESSION_NOT_FOUND",`Chat session ${e} was not found.`),t}upsert(e){const t=aa(),n=(s=e.channel,i=e.chatSessionId,`${e.bridgeId||s}:${i.replace(/[^a-zA-Z0-9_.:-]/g,"_")}`);var s,i;const r=this.chatSessions.get(n),o=bi.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 Nd(e){return{inline_keyboard:e.map(e=>e.map(e=>({text:e.text,...e.url?{url:e.url}:{callback_data:e.callbackData||""}})))}}function _d(e,t=40){return Nd(e.slice(0,t).map(e=>[e]))}function Pd(e){return Buffer.from(e,"utf8").toString("base64url")}function Rd(e){const t=jd(e).inline_keyboard,n=Array.isArray(t)?t:[],s=[];for(const e of n)if(Array.isArray(e))for(const t of e){const e=jd(t),n=String(e.callback_data||""),i=String(e.text||"").trim();i&&n&&s.push({text:i,id:`th_cb_${Pd(n)}`})}return s.slice(0,40)}function Od(e,t){const n=String(e||"").replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-3))}...`}function jd(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Md(e){return(e.aiSessions?.sessions||[]).filter(t=>function(e,t){const n=(e.apps?.sessions||[]).filter(Ud);if(t.appSessionId&&n.some(e=>e.id===t.appSessionId))return!0;const s=new Set(t.appBindingKeys||[]);return Boolean(s.size&&n.some(e=>function(e){return[...Gr(e).bindings.map(Qr),...Xr(e)].filter(Boolean)}(e).some(e=>s.has(e))))}(e,t))}function Dd(e){return"waiting"===e.status?4:"failed"===e.status?3:"running"===e.status?2:"idle"===e.status?1:0}function qd(e){return[e.cwd||"",e.agent||"",e.providerSessionId||e.id].join("\0")}function Ld(e){const t=e.session.title||e.session.userPrompt||e.session.summary||e.session.lastMessage||"",n=t?` - ${Od(t,18)}`:"";return`${e.instance.name} - ${e.session.agent} ${e.session.status}${n}`}function $d(e,t=(e,t)=>`task_handoff:approval:${e.id}:${t}`){return _d(e.flatMap(e=>"approval"!==e.kind?[]:[{text:Od(`Allow ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"allow")},{text:Od(`Skip ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"skip")},{text:Od(`Deny ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"deny")}]))}function Bd(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 Ud(e){const t=e&&"object"==typeof e&&!Array.isArray(e)?e:{};return Kr("string"==typeof t.status?t.status:void 0)}class Fd{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async handleAiSessionsCommand(e){const t=await this.targets.aiSessionChoices(e),n=t.find(e=>e.active),s=t.map(e=>function(e){const t=e.session.userPrompt||e.session.summary||e.session.lastMessage||"",n=e.active?"* ":"",s=e.session.phase&&"unknown"!==e.session.phase?`/${e.session.phase}`:"";return`${n}${e.index+1}. ${e.projectName} / ${e.instance.name} - ${e.session.agent} - ${e.session.status}${s} - ${e.session.id}${t?` - ${t}`:""}`}(e));return{accepted:!0,routed:!1,binding:e,instances:t.map(e=>e.instance),reply:t.length?["Select AI session",`Current ${n?`${n.projectName} / ${n.instance.name} / ${n.session.id}`:await this.targets.renderChatTarget(e)}, total ${t.length}`,"",...s].join("\n"):"No AI sessions found.",replyMarkup:t.length?_d(t.map(e=>({text:`${e.active?"✓ ":""}${Ld(e)}`,callbackData:`task_handoff:cp_session:${e.index}`}))):void 0}}async handleAiSessionCommand(e,t){const n=String(t[0]||"").trim();if(!n)return this.handleAiSessionsCommand(e);const s=await this.targets.findAiSession(n);if(!s)return{accepted:!1,routed:!1,binding:e,reply:`AI session ${n} was not found. Try /sessions.`};const i=s.instance.projectId?this.deps.getProject(s.instance.projectId):void 0;return{accepted:!0,routed:!1,binding:this.deps.upsertChatSession({...e,activeProjectId:i?.id||e.activeProjectId,activeInstanceId:s.instance.id,activeAiSessionId:s.session.id}),instance:s.instance,aiSession:s.session,reply:`Active AI session: ${s.instance.name} / ${s.session.agent} ${s.session.id}`}}async handleAiSessionIndexAction(e,t){const n=(await this.targets.aiSessionChoices(e)).find(e=>e.index===t);if(!n)return{accepted:!1,routed:!1,binding:e,reply:"AI session was not found. Use /session to refresh the list.",replyMarkup:void 0};const s=this.deps.upsertChatSession({...e,activeProjectId:n.projectId||e.activeProjectId,activeInstanceId:n.instance.id,activeAiSessionId:n.session.id}),i=await this.handleAiSessionsCommand(s);return{...i,accepted:!0,binding:s,instance:n.instance,aiSession:n.session,message:`selected ${n.session.id}`,reply:[`Current chat is bound to AI session ${n.session.id}`,"",i.reply].join("\n")}}async handleAiSessionInterruptCommand(e){if(!e.activeInstanceId||!e.activeAiSessionId)return{accepted:!1,routed:!1,binding:e,reply:"No active AI session is selected. Use /sessions and /session <id> first."};const t=await this.deps.requireControlledInstance(e.activeInstanceId,!0),n=await this.deps.interruptAiSession(t.id,e.activeAiSessionId);return{accepted:!0,routed:!0,binding:e,instance:ra(t),aiSession:n,reply:`Interrupt sent to ${t.name} / ${e.activeAiSessionId}.`}}}function Hd(e){return e.providerTurnId||e.turnId||""}function Wd(e){return Kr(Jd(e.status))}function Gd(e,t){const n=Jd(t.appId)||"App",s=Jd(t.title).trim();if(s&&s!==n)return s;const i=function(e,t){for(const n of e.appInventory?.items||[])if(n.id===t)return n.name;return""}(e,n);return i||n}function Vd(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=Qd(e);t&&!n.has(t.id)&&n.set(t.id,t)}return[...n.values()]}function Kd(e,t,n,s){const i=Jd(t.id)&&function(e,t){const n=Jr(e);if(!n)return;return`/apps/access/${n}?token=${encodeURIComponent(t(n))}`}(t,s)||`/instances/${encodeURIComponent(e.id)}/`,r=function(e,t){const n=Jd(t);if(n&&new RegExp("^https?://","i").test(n))return new URL(e,n.endsWith("/")?n:n+"/").toString()}(i,n);return{text:r||i,url:r}}function Jd(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function Qd(e){if("string"==typeof e&&e.trim())return{id:e,label:Yd(e)};const t=function(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}(e),n=Jd(t.id).trim();return n?{id:n,label:Jd(t.name).trim()||Yd(n)}:void 0}function Yd(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 Xd{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?_d(t.map(e=>{return{text:Od(e.name||e.id,56),callbackData:(t=this.deps.createChatActionToken({type:"instance-app-menu",instanceId:e.id}).token,`task_handoff:cp_i:${t}`)};var t})):void 0};var n}async handleInstanceAppMenuAction(e,t){const n=(await this.targets.instancesForBinding(e)).find(e=>e.id===t);if(!n)return{accepted:!1,routed:!1,binding:e,reply:"Instance not found."};const s=Vd(n);return{accepted:!0,routed:!1,binding:e,instance:n,message:`Select an app for ${n.name}.`,reply:s.length?`New app for ${n.name}`:`No launchable apps for ${n.name}.`,replyMarkup:s.length?_d(s.map(e=>{return{text:Od(e.label,56),callbackData:(t=this.deps.createChatActionToken({type:"launch-app",instanceId:n.id,appId:e.id}).token,`task_handoff:cp_a:${t}`)};var t})):void 0}}async handleLaunchAppAction(e,t,n){const s=(await this.targets.instancesForBinding(e)).find(e=>e.id===t);if(!s)return{accepted:!1,routed:!1,binding:e,reply:"Instance not found."};const i=Vd(s).find(e=>e.id===n);return i?{accepted:!0,routed:!1,binding:e,instance:s,session:await this.deps.launchAppSession(s.id,i.id),message:`${i.label} launched`,reply:`Launched ${i.label} on ${s.name}.`}:{accepted:!1,routed:!1,binding:e,reply:`App ${n} is not launchable for ${s.name}.`}}async handleAppsCommand(e){const t=await this.deps.boardAsync(),n=new Map(t.map(e=>[e.id,e])),s=(await this.deps.listAppSessions()).instances.flatMap(e=>{const t=n.get(e.instanceId);return t?e.appSessions.sessions.filter(Wd).filter(e=>Boolean(Jd(e.id))).map(e=>({instance:t,session:e,link:Kd(t,e,this.deps.controlPlanePublicBaseUrl(),n=>this.deps.createAppAccessToken({instanceId:t.id,sessionId:Jd(e.id)||"",mode:n}).token)})):[]}),i=s.filter(e=>e.link.url).map(e=>({text:Od(`${e.instance.name} · ${Gd(e.instance,e.session)}`,56),url:e.link.url}));return{accepted:!0,routed:!1,binding:e,instances:t,reply:(r=s.length,o=i.length,0===r?"No app sessions found.":0===o?`App sessions: ${r}. Set the control plane public URL in Settings > Appearance to open them from chat.`:`App sessions: ${r}. Tap a button to open.`),replyMarkup:i.length?_d(i):void 0};var r,o}}class Zd{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async forwardChatMessage(e,t){const n=t.target?.instanceId||e.activeInstanceId||"",s=t.target?.aiSessionId||e.activeAiSessionId,i=await this.deps.requireControlledInstance(n,!0),r=i.projectId?this.deps.requireProject(i.projectId):void 0;if("online"!==i.connectionStatus){const e=new Error(`Instance ${i.name} is not reachable.`);throw Object.assign(e,{statusCode:409,code:"CHAT_TARGET_UNREACHABLE"}),e}if(s){const n=await this.trySendAiSessionMessage(e,i.id,s,t.message.text,t.message.attachments,!t.target);return n.ok?this.sentResult(e,r,i,s,n.aiSession):this.failedSendResult(n.binding,r,i,n.reply)}const o=await this.targets.defaultAiSessionIdForInstance(i.id);if(o){const n=this.deps.upsertChatSession({...e,activeAiSessionId:o}),s=await this.trySendAiSessionMessage(n,i.id,o,t.message.text,t.message.attachments);return s.ok?this.sentResult(n,r,i,o,s.aiSession):this.failedSendResult(s.binding,r,i,s.reply)}return{accepted:!1,routed:!1,binding:e,project:r||void 0,instance:ra(i),reply:`No active AI session is selected for ${i.name}. Use /sessions and /session <id> first.`}}async trySendAiSessionMessage(e,t,n,s,i=[],r=!0){try{return{ok:!0,binding:e,aiSession:await this.deps.sendAiSessionMessage(t,n,s||"请查看附件。",void 0,i)}}catch(t){return function(e){return"AI_SESSION_NOT_FOUND"===(e&&"object"==typeof e?e:{}).code}(t)?{ok:!1,binding:r?this.deps.upsertChatSession({...e,activeAiSessionId:void 0}):e,reply:`The selected AI session ${n} no longer exists. Use /session to choose an active AI session.`}:{ok:!1,binding:e,reply:`Failed to send to AI session ${n}: ${la(t)}`}}}failedSendResult(e,t,n,s){return{accepted:!1,routed:!1,binding:e,project:t||void 0,instance:ra(n),reply:s}}sentResult(e,t,n,s,i){return{accepted:!0,routed:!0,binding:e,project:t||void 0,instance:ra(n),aiSession:i,instanceId:n.id,aiSessionId:s,turnId:(r=i,r.turnId||r.providerTurnId||r.session.activeTurnId||""),providerTurnId:Hd(i),reply:`Sent to ${t?.name||n.sourceSnapshot.name||"Source"} / ${n.name} / ${s}.`};var r}}class ec{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(Bd).join("\n"):"No pending routes.",replyMarkup:n.length?$d(n,(e,t)=>this.deps.pendingDecisionCallbackData(e.id,t)):void 0}}async handlePendingDecisionCommand(e,t,n){const s=ca(t[0]);return s?s.aiSessionId?{accepted:!0,routed:!0,binding:e,pending:s,aiSession:await this.deps.resolveAiSessionApproval(s.instanceId,s.aiSessionId,n),reply:`${n} sent for ${s.instanceId}:${s.aiSessionId}.`}:{accepted:!1,routed:!1,binding:e,pending:s,reply:"Only AI session pending routes are supported here."}:{accepted:!1,routed:!1,binding:e,reply:`Usage: /${"allow"===n?"approve":n} <instance-id:pending-id>`}}async handlePendingReplyCommand(e,t){const n=ca(t[0]),s=t.slice(1).join(" ").trim();return n&&s?n.aiSessionId?{accepted:!0,routed:!0,binding:e,pending:n,aiSession:await this.deps.sendAiSessionMessage(n.instanceId,n.aiSessionId,s),reply:`Reply sent for ${n.instanceId}:${n.aiSessionId}.`}:{accepted:!1,routed:!1,binding:e,pending:n,reply:"Only AI session pending routes are supported here."}:{accepted:!1,routed:!1,binding:e,reply:"Usage: /reply <instance-id:pending-id> <message>"}}}class tc{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async handleUseCommand(e,t){if(0===t.length)return{accepted:!0,routed:!1,binding:e,instances:await this.targets.instancesForBinding(e),reply:await this.targets.renderUseHelp(e)};if(t.length>=2){const n=this.targets.resolveProject(t[0]),s=await this.targets.resolveInstance(t[1],n.id),i=this.deps.upsertChatSession({...e,activeProjectId:n.id,activeInstanceId:s.id,activeAiSessionId:await this.targets.defaultAiSessionIdForInstance(s.id)});return{accepted:!0,routed:!1,binding:i,reply:await this.targets.renderTargetSelected(i)}}const n=t[0],s=await this.targets.findInstance(n);if(s){const t=s.projectId?this.deps.requireProject(s.projectId):void 0,n=this.deps.upsertChatSession({...e,activeProjectId:t?.id,activeInstanceId:s.id,activeAiSessionId:await this.targets.defaultAiSessionIdForInstance(s.id)});return{accepted:!0,routed:!1,binding:n,reply:await this.targets.renderTargetSelected(n)}}const i=this.targets.resolveProject(n),r=(await this.deps.boardAsync()).filter(e=>e.projectId===i.id),o=r.filter(e=>"running"===e.status&&"online"===e.connectionStatus);if(1===o.length){const t=this.deps.upsertChatSession({...e,activeProjectId:i.id,activeInstanceId:o[0].id,activeAiSessionId:await this.targets.defaultAiSessionIdForInstance(o[0].id)});return{accepted:!0,routed:!1,binding:t,reply:await this.targets.renderTargetSelected(t)}}return{accepted:!0,routed:!1,binding:this.deps.upsertChatSession({...e,activeProjectId:i.id,activeInstanceId:void 0,activeAiSessionId:void 0}),instances:r,reply:`${i.name} selected. Choose an instance with /use ${i.id} <instance-id-or-name>.\n${this.targets.renderInstanceLines(r)}`}}async handleProjectCommand(e,t){if(0===t.length)return{accepted:!1,routed:!1,binding:e,reply:"Usage: /project <project-id-or-name>"};const n=this.targets.resolveProject(t[0]),s=e.activeInstanceId?await this.deps.requireControlledInstance(e.activeInstanceId).catch(()=>{}):void 0,i=this.deps.upsertChatSession({...e,activeProjectId:n.id,activeInstanceId:s?.projectId===n.id?s.id:void 0,activeAiSessionId:s?.projectId===n.id?e.activeAiSessionId:void 0});return{accepted:!0,routed:!1,binding:i,reply:`Active project: ${n.name}${i.activeInstanceId?"":". Choose an instance with /use."}`}}}class nc{deps;constructor(e){this.deps=e}async instancesForBinding(e){const t=await this.deps.boardAsync();return e.activeProjectId?t.filter(t=>t.projectId===e.activeProjectId):t}async fullInstancesForBinding(e){const t=await this.deps.listNodeInstances();return e.activeProjectId?t.filter(t=>t.projectId===e.activeProjectId):t}async renderUseHelp(e){return`Active target: ${await this.renderChatTarget(e)}\nUse /instances to list targets, then /use <instance-id-or-name>. Use /sessions to choose an AI session when there is more than one.`}async renderChatStatus(e){const t=e.activeInstanceId?(await this.deps.boardAsync()).find(t=>t.id===e.activeInstanceId):void 0;return t?`Active target: ${await this.renderChatTarget(e)}\nStatus: ${t.status}, connection: ${t.connectionStatus}`:`Active target: ${await this.renderChatTarget(e)}`}async renderChatHelp(e){return["TaskHandoff chat commands:","/help - show this help","/status or /target - show the active project, instance, and AI session","/instances - list controlled instances","/apps - list app sessions","/use <instance-id-or-name> - choose an active instance","/use <project-id-or-name> <instance-id-or-name> - choose a project and instance","/project <project-id-or-name> - narrow instance selection to a project","/sessions - list all AI sessions","/session <ai-session-id> - choose an active AI session","/pending - list waiting approvals","/approve <instance-id:pending-id>, /deny <...>, /skip <...> - answer approvals","/reply <instance-id:pending-id> <message> - reply to a waiting session","/cancel - interrupt the active AI session","","Send normal text after selecting a target; if there is only one AI session, it is selected automatically.",`Current target: ${await this.renderChatTarget(e)}`].join("\n")}renderInstanceLines(e){return e.map(e=>`${e.name} (${e.id}) - ${e.status}/${e.connectionStatus}`).join("\n")}async renderChatTarget(e){const t=e.activeProjectId?this.deps.getProject(e.activeProjectId):void 0,n=e.activeInstanceId?await this.deps.requireControlledInstance(e.activeInstanceId).catch(()=>{}):void 0,s=e.activeAiSessionId||"none";return`${t?.name||e.activeProjectId||"none"} / ${n?.name||e.activeInstanceId||"none"} / ${s}`}async renderTargetSelected(e){const t=await this.renderChatTarget(e);return e.activeAiSessionId?`Active target: ${t}`:`Active target: ${t}\nNo AI session selected yet. Use /sessions and /session <id>, or send a message once exactly one session is available.`}async defaultAiSessionIdForInstance(e){const t=await this.aiSessionSnapshotForInstance(e),n=(await this.deps.boardAsync()).find(t=>t.id===e),s=(await this.deps.listAppSessions()).instances.find(t=>t.instanceId===e),i=n?{...n,apps:{...n.apps,sessions:s?.appSessions.sessions||[]}}:void 0,r=t&&n?Md({...i,aiSessions:t}):t?.sessions||[];return 1===r.length?r[0].id:void 0}async aiSessionChoices(e){return(await this.boardInstancesForBinding({},{refresh:!0})).flatMap(t=>Md(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=Dd(t.session)-Dd(e.session);return n||(String(e.instance.name||"").localeCompare(String(t.instance.name||""))||e.instance.id.localeCompare(t.instance.id)||qd(e.session).localeCompare(qd(t.session)))}).map((e,t)=>({...e,index:t}))}async boardInstancesForBinding(e,t={}){const n=await this.deps.boardAsync(),s=await this.deps.listAiSessions(t),i=await this.deps.listAppSessions(t),r=new Map(s.instances.map(e=>[e.instanceId,e.aiSessions])),o=new Map(i.instances.map(e=>[e.instanceId,e.appSessions])),a=n.map(e=>{return{...e,apps:{...e.apps,sessions:o.get(e.id)?.sessions||[]},aiSessions:r.get(e.id)||(t=e.aiSessions.updatedAt,{runningCount:0,waitingCount:0,staleCount:0,sessions:[],updatedAt:t})};var t});return e.activeProjectId?a.filter(t=>t.projectId===e.activeProjectId):a}async findAiSession(e){const t=await this.boardInstancesForBinding({},{refresh:!0});for(const n of t){const t=(n.aiSessions?.sessions||[]).find(t=>t.id===e||t.providerSessionId===e);if(t)return{instance:n,session:t}}}async aiSessionSnapshotForInstance(e){const t=await this.deps.listAiSessions();return t.instances.find(t=>t.instanceId===e)?.aiSessions}resolveProject(e){const t=this.deps.getProject(e)||this.deps.listProjects().find(t=>t.name===e);return t||pa("PROJECT_NOT_FOUND",`Project ${e} was not found.`),t}async resolveInstance(e,t){const n=await this.findInstance(e,t);return n||pa("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 sc{deps;targets;sender;appCommands;pendingCommands;aiSessionCommands;targetCommands;constructor(e){this.deps=e,this.targets=new nc(e),this.sender=new Zd(e,this.targets),this.appCommands=new Xd(e,this.targets),this.pendingCommands=new ec(e),this.aiSessionCommands=new Fd(e,this.targets),this.targetCommands=new tc(e,this.targets)}async handleChatGatewayMessage(e){const t=vi.parse(e),n=this.deps.upsertChatSession({channel:t.source.channel,bridgeId:t.source.bridgeId,chatSessionId:t.source.chatSessionId,userId:t.source.userId}),s=t.message.text.trim();return s.startsWith("/")?this.handleChatCommand(n,s):s||t.message.attachments.length?n.activeInstanceId?this.sender.forwardChatMessage(n,t):{accepted:!1,routed:!1,binding:n,reply:await this.targets.renderUseHelp(n)}:{accepted:!1,routed:!1,binding:n,reply:""}}async handleChatGatewayAction(e){const t=this.deps.upsertChatSession({channel:e.source.channel,bridgeId:e.source.bridgeId,chatSessionId:e.source.chatSessionId,userId:e.source.userId});return"ai-session"===e.action.type?this.aiSessionCommands.handleAiSessionIndexAction(t,e.action.index):"instance-app-menu"===e.action.type?this.appCommands.handleInstanceAppMenuAction(t,e.action.instanceId):"launch-app"===e.action.type?this.appCommands.handleLaunchAppAction(t,e.action.instanceId,e.action.appId):"pending-decision"===e.action.type?this.pendingCommands.handlePendingDecisionCommand(t,[e.action.routeId],e.action.decision):{accepted:!1,routed:!1,binding:t,reply:"Unknown action."}}async handleChatCommand(e,t){const[n="",...s]=t.split(/\s+/),i=n.replace(/@[\w_]+$/,"");switch(i.toLowerCase()){case"/help":case"/start":return{accepted:!0,routed:!1,binding:e,reply:await this.targets.renderChatHelp(e)};case"/sessions":return this.aiSessionCommands.handleAiSessionsCommand(e);case"/session":return this.aiSessionCommands.handleAiSessionCommand(e,s);case"/cancel":case"/interrupt":return this.aiSessionCommands.handleAiSessionInterruptCommand(e);case"/pending":return this.pendingCommands.handlePendingCommand(e);case"/approve":return this.pendingCommands.handlePendingDecisionCommand(e,s,"allow");case"/deny":return this.pendingCommands.handlePendingDecisionCommand(e,s,"deny");case"/skip":return this.pendingCommands.handlePendingDecisionCommand(e,s,"skip");case"/reply":return this.pendingCommands.handlePendingReplyCommand(e,s);case"/instances":return this.appCommands.handleInstancesCommand(e);case"/apps":return this.appCommands.handleAppsCommand(e);case"/use":return this.targetCommands.handleUseCommand(e,s);case"/project":return this.targetCommands.handleProjectCommand(e,s);case"/status":case"/target":return{accepted:!0,routed:!1,binding:e,instance:e.activeInstanceId?(await this.deps.boardAsync()).find(t=>t.id===e.activeInstanceId):void 0,reply:await this.targets.renderChatStatus(e)};default:return{accepted:!1,routed:!1,binding:e,reply:`Unknown command: ${i||n}. Try /help.`}}}}const ic=o.z.object({id:o.z.string().trim().min(1),preferences:Ar,createdAt:o.z.string().datetime(),updatedAt:o.z.string().datetime()}).strict();function rc(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 oc(){return Ar.parse({})}function ac(e){return/^[a-z]:[\\/]/i.test(e)||/^[\\/]{2}[^\\/]+[\\/]+[^\\/]+/.test(e)}function dc(e){return ac(e)?t.win32:t.posix}class cc{retiredRoot;legacyControlledInstancesDir;legacyNodeRuntimesDir;legacyNodeJoinInvitesDir;paths;options;constructor(e,n={}){this.paths=e,this.options=n,this.retiredRoot=t.join(e.dataDir,"retired-persistence"),this.legacyControlledInstancesDir=t.join(e.dataDir,"controlled-instances"),this.legacyNodeRuntimesDir=t.join(e.dataDir,"node-runtimes"),this.legacyNodeJoinInvitesDir=t.join(e.dataDir,"node-join-invites")}run(){return this.removePersistedInvites(),this.retireLegacyProjection("controlled-instances",this.legacyControlledInstancesDir,!0),this.retireLegacyProjection("node-runtimes",this.legacyNodeRuntimesDir,!1),function(e){if(!n.existsSync(e.trashRoot))return[];const t=e.nowMs??Date.now(),s=e.retentionMs??Ai,i=[];for(const r of n.readdirSync(e.trashRoot,{withFileTypes:!0})){const o=ki(e.trashRoot,r.name);try{const e=Number(r.name.split("-",1)[0]);if(!Number.isFinite(e)||e+s>t)continue;const a=n.lstatSync(o);a.isSymbolicLink()?n.unlinkSync(o):a.isDirectory()?n.rmSync(o,{recursive:!0,force:!0}):n.unlinkSync(o),i.push(o)}catch(t){e.logger?.("retired persistence entry cleanup failed",{path:o,error:t instanceof Error?t.message:String(t)})}}return i}({trashRoot:this.retiredRoot,retentionMs:this.options.retentionMs??Ai,nowMs:this.now(),logger:this.options.logger})}removePersistedInvites(){n.existsSync(this.legacyNodeJoinInvitesDir)&&n.rmSync(this.legacyNodeJoinInvitesDir,{recursive:!0,force:!0})}retireLegacyProjection(e,s,i){if(!n.existsSync(s))return;const r=n.lstatSync(s);if(!r.isDirectory()||r.isSymbolicLink())return n.rmSync(s,{force:!0}),void this.options.logger?.("invalid legacy persistence path was removed",{store:e});n.readdirSync(s).length?(i&&this.redactLegacyInstanceCredentials(s),function(e){const t=ki(e.sourceRoot,e.entryName);if(!n.existsSync(t))return;const s=n.lstatSync(t);if(!s.isDirectory()||s.isSymbolicLink())throw new Error(`Retention source must be a real directory: ${t}`);zi(e.trashRoot);const i=e.nowMs??Date.now();let r=0,o=`${i}-${e.entryName}`;for(;n.existsSync(ki(e.trashRoot,o));)r+=1,o=`${i}-${r}-${e.entryName}`;const a=ki(e.trashRoot,o);n.renameSync(t,a)}({sourceRoot:this.paths.dataDir,entryName:t.basename(s),trashRoot:this.retiredRoot,nowMs:this.now()}),this.options.logger?.("legacy control-plane persistence was retired",{store:e})):n.rmdirSync(s)}redactLegacyInstanceCredentials(e){for(const s of n.readdirSync(e,{withFileTypes:!0})){if(!s.isFile()||s.isSymbolicLink())continue;const i=t.join(e,s.name);try{const e=JSON.parse(n.readFileSync(i,"utf8"));delete e.registrationToken,c.sync(i,`${JSON.stringify(e,null,2)}\n`,{encoding:"utf8",mode:384}),n.chmodSync(i,384)}catch(e){n.rmSync(i,{force:!0}),this.options.logger?.("unreadable legacy instance record was removed",{filePath:i,error:e instanceof Error?e.message:String(e)})}}zi(e)}now(){return this.options.now?.()??Date.now()}}const lc="task-handoff.control-plane.local",pc="task-handoff.control-plane.builtin";function uc(e){return"true"===e.labels[lc]}function gc(e){return"true"===e.labels[pc]}class hc{projects;models;modelService;images;nodes;pendingPairingRevokes;chatSessions;chatBridges;triggers;nodeJoinService;configSyncPreferences;settings;paths;fetchImpl;dockerCommandRunner;logger;diagnosticLogsState;nodeConnectionRuntime;appAccessService;persistenceMaintenance;chatActionTokenService=new kd;nodeAgentTransportResolver;proxyPrivateStore;proxyLifecycle;nodeConnectionManager;nodeAgentGateway;controlledInstanceGateway;aiSessionActionService;controlledInstanceCreator;instanceBoardReader=new rd;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 cc(e,{logger:(e,t)=>this.logWarn(t,e)});const s=e=>({schema:e,logger:(e,t)=>this.logWarn(t,e)});this.proxyPrivateStore=new Go(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 jo({direct:Oo(this.fetchImpl),tunnel:n.nodeAgentTransport,proxy:new Bo({credentialForNode:e=>this.proxyPrivateStore.nodeCredential(e.id),fetchImpl:this.fetchImpl})});const i=(r=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(r||"").trim().toLowerCase()));var r;this.diagnosticLogsState=i,this.settings=new Wi(e.settingsPath,()=>wa.parse({diagnosticLogs:i}),{...s(wa),sanitize:e=>function(e,t={}){if(!e||"object"!=typeof e||Array.isArray(e))return{};const n={...e};return"string"==typeof n.mentionTrigger&&fa(n.mentionTrigger)||(n.mentionTrigger="@"),"string"==typeof n.commandTrigger&&ba(n.commandTrigger)&&n.commandTrigger!==n.mentionTrigger||(n.commandTrigger="/"),"boolean"!=typeof n.diagnosticLogs&&(n.diagnosticLogs=t.diagnosticLogs??!1),n}(e,{diagnosticLogs:i})}),this.logger=n.logger?{info:(e,t)=>{this.diagnosticLogsEnabled()&&n.logger?.info?.(e,t)},warn:(e,t)=>{this.diagnosticLogsEnabled()&&n.logger?.warn?.(e,t)},error:(e,t)=>{this.diagnosticLogsEnabled()&&n.logger?.error?.(e,t)}}:void 0;const o=new po({request:(e,t,n)=>this.nodeAgentFetch(e,t,n),logger:this.logger});this.nodeAgentGateway=new uo(o),this.controlledInstanceGateway=new sd({requireNode:e=>this.requireNode(e),nodeAgentTransport:e=>this.nodeAgentTransportResolver.resolve(e)}),this.aiSessionActionService=new so({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 Hi(e.projectsDir,{...s(ls),sanitize:zn}),this.models=new Hi(e.modelsDir,s(ps)),this.modelService=new td({models:this.models,gateway:this.nodeAgentGateway,listNodes:()=>this.listNodes(),requireNode:e=>this.requireNode(e)}),this.images=new Hi(e.imagesDir,{...s(Ps),sanitize:e=>Fs(e,e=>this.logWarn(e,"legacy image profile field was migrated"))}),this.nodes=new Hi(e.nodesDir,{...s(Gs),sanitize:e=>function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,s=new Set(["id","name","connectionMode","connectionPath","connectionEnabled","auth","endpoint","controlEndpoint","containerEndpoint","publicWebBase","status","health","capabilities","proxyState","appInventory","labels","lastSeenAt","createdAt","updatedAt"]);for(const e of Object.keys(n))s.has(e)||t?.({field:e});const i=n.auth&&"object"==typeof n.auth&&!Array.isArray(n.auth)?yi(n.auth,["mode","keyId","secret","pairedAt","pairing"]):n.auth;i&&"object"==typeof i&&"pairing"in i&&(i.pairing=yi(i.pairing,["status","joinToken","expiresAt"]));const r=n.connectionPath&&"object"==typeof n.connectionPath&&!Array.isArray(n.connectionPath)?"control-plane-proxy"===n.connectionPath.kind?yi(n.connectionPath,["kind","proxyId","proxyBindingId","targetNodeId"]):yi(n.connectionPath,["kind"]):{kind:"direct"},o=n.proxyState&&"object"==typeof n.proxyState&&!Array.isArray(n.proxyState)?yi(n.proxyState,["reachability","bindingStatus","bindingRevision","streamId","revision","observedAt","target","lastError","updatedAt"]):n.proxyState;if(o&&"object"==typeof o){const e=o;e.target=yi(e.target,["id","name","status","health","lastSeenAt","capabilities"]),e.lastError=yi(e.lastError,["code","message","retryable","details"])}return{...Object.fromEntries(Object.entries(n).filter(([e])=>s.has(e))),auth:i,connectionPath:r,proxyState:o}}(e,e=>this.logWarn(e,"unknown stored node field was ignored"))}),this.pendingPairingRevokes=new Hi(e.pendingPairingRevokesDir,s(Ua)),this.proxyLifecycle=new ha({nodes:this.nodes,privateStore:this.proxyPrivateStore,fetchImpl:this.fetchImpl,requireNode:e=>this.requireNode(e),deleteNode:e=>this.deleteNode(e)}),this.nodeConnectionManager=new Fa({nodes:this.nodes,pendingPairingRevokes:this.pendingPairingRevokes,fetchImpl:this.fetchImpl,localNodeLabel:lc,builtinNodeLabel:pc,info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)}),this.chatSessions=new Hi(e.chatSessionsDir,s(bi)),this.chatBridges=new Hi(e.chatBridgesDir,s(Ii)),this.triggers=new Hi(e.triggersDir,s(Ca)),this.nodeJoinService=new Za({nodes:this.nodes}),this.configSyncPreferences=new Hi(t.join(e.dataDir,"config-sync-preferences"),{...s(ic),sanitize:rc}),this.marketCatalogService=new yd,this.catalogService=new ud({projects:this.projects,images:this.images,market:this.marketCatalogService,settings:this.settings,defaultNodeId:()=>this.defaultNodeId()}),this.controlledInstanceCreator=new od({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 cd({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 Id({requireInstance:async e=>this.requireControlledInstance(e,!0),listAppSessions:()=>this.listAppSessions()}),this.chatBridgeService=new xd({chatBridges:this.chatBridges,chatSessions:this.chatSessions}),this.chatSessionService=new Ed({chatSessions:this.chatSessions}),this.chatSessionRuntime=new sc({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,s,i)=>this.sendAiSessionMessage(e,t,n,s,i),interruptAiSession:(e,t)=>this.interruptAiSession(e,t),launchAppSession:(e,t,n)=>this.launchAppSession(e,t,n)})}logInfo(e,t){this.logger?.info?.(e,t)}logWarn(e,t){this.logger?.warn?.(e,t)}logError(e,t){this.logger?.error?.(e,t)}setNodeAgentTransport(e){this.nodeAgentTransportResolver.setTunnel(e)}resolveNodeAgentTransport(e){return this.nodeAgentTransportResolver.resolve(e)}setAiSessionSnapshotProvider(e){this.aiSessionSnapshotProvider=e}async listAiSessions(e={}){return this.aiSessionSnapshotProvider?this.aiSessionSnapshotProvider(e):this.bootstrapAiSessionsFromInstances()}setAppSessionSnapshotProvider(e){this.appSessionSnapshotProvider=e}async listAppSessions(e={}){return this.appSessionSnapshotProvider?this.appSessionSnapshotProvider(e):this.bootstrapAppSessionsFromInstances()}init(){this.runPersistenceMaintenance(),this.projects.init(),this.models.init(),this.images.init(),this.nodes.init(),this.pendingPairingRevokes.init(),this.chatSessions.init(),this.chatBridges.init(),this.triggers.init(),this.proxyPrivateStore.init(),this.proxyPrivateStore.gcNodeCredentials(e=>{const t=this.nodes.get(e.nodeId);return"control-plane-proxy"===t?.connectionMode&&"control-plane-proxy"===t.connectionPath.kind&&t.connectionPath.proxyBindingId===e.proxyBindingId&&t.connectionPath.targetNodeId===e.targetNodeId}),this.settings.init();const e=this.settings.put(this.settings.get());this.diagnosticLogsState=e.diagnosticLogs,this.migrateLegacyImageCatalog(),this.seedDefaults()}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(An),s=[];for(const t of e){const e=this.images.filePath(t);if(n.existsSync(e))try{s.push({id:t,filePath:e,record:JSON.parse(n.readFileSync(e,"utf8"))})}catch(e){return this.writeMarketMigrationState("failed",{code:"LEGACY_IMAGE_BACKUP_READ_FAILED",legacyId:t,error:la(e)}),void this.logWarn({legacyId:t,error:la(e)},"legacy embedded image migration was not applied")}}if(!s.length)return;const i=n.readdirSync(this.paths.projectsDir).filter(e=>e.endsWith(".json")).sort().map(e=>t.join(this.paths.projectsDir,e)),r=[];for(const e of i)try{const t=JSON.parse(n.readFileSync(e,"utf8")),s=ls.parse(zn(t));r.push({filePath:e,raw:t,migrated:s})}catch(t){return this.writeMarketMigrationState("failed",{code:"PROJECT_REFERENCE_VALIDATION_FAILED",filePath:e,error:la(t)}),void this.logWarn({filePath:e,error:la(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:Kt,createdAt:aa(),images:s.map(({id:e,record:t})=>({id:e,record:t})),projects:r.map(({filePath:e,raw:n})=>({file:t.basename(e),record:n}))},null,2)}\n`,{encoding:"utf8"});for(const{migrated:e}of r)this.projects.put(e);for(const{id:e}of s)this.images.delete(e),this.logWarn({legacyId:e,marketId:An[e]},"embedded image profile migrated to Market");this.writeMarketMigrationState("complete",{code:"LEGACY_IMAGE_MIGRATION_COMPLETE",migratedImageIds:s.map(({id:e})=>e),backupPath:this.paths.marketMigrationBackupPath})}}writeMarketMigrationState(e,t){n.mkdirSync(this.paths.marketDir,{recursive:!0}),c.sync(this.paths.marketStatePath,`${JSON.stringify({status:e,updatedAt:aa(),...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(uc)?.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 md),this.getMarketCatalog()}listImageOptions(){return this.catalogService.listImageOptions()}createImage(e){return this.catalogService.createImage(e)}async listNodeDockerImages(e){const t=this.requireNode(e);return this.nodeAgentGateway.listDockerImages(t)}async listNodeImageAvailability(e){const t=this.requireNode(e),n=t.capabilities.agent&&"object"==typeof t.capabilities.agent?t.capabilities.agent:{},s={os:"string"==typeof n.platform?n.platform:void 0,architecture:"string"==typeof n.arch?"x64"===n.arch?"amd64":n.arch:void 0},i=this.catalogService.listImageOptions(s);try{const e=await this.nodeAgentGateway.listDockerImages(t);return i.map(t=>{const n=e.find(e=>e.reference===t.reference||!!t.digest&&e.repoDigests.some(e=>e.endsWith(`@${t.digest}`))||e.repoDigests.includes(t.reference));return ri.parse({image:t,status:n?"available":"pull-required",localImage:n,localSizeBytes:n?.sizeBytes,downloadSizeBytes:n?void 0:t.downloadSizeBytes,unpackedSizeBytes:n?void 0:t.unpackedSizeBytes})})}catch(e){const t=e instanceof Error?e.message:String(e);return i.map(e=>ri.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:{},s="string"==typeof n.nodeId&&n.nodeId.trim()?n.nodeId.trim():t.id,i=Gs.parse({...t,id:s,status:"online",health:"ok",capabilities:"object"==typeof e&&e?{...t.capabilities,agent:ta(e)}:t.capabilities,lastSeenAt:aa(),updatedAt:aa()});return s!==t.id&&this.nodes.delete(t.id),this.nodes.put(i),this.nodeConnectionRuntime?.observedReachable(i),{id:i.id,status:"online",checkedAt:aa(),agent:e}}catch(e){const n=Gs.parse({...t,status:"offline",health:"failed",updatedAt:aa()});return this.nodes.put(n),this.nodeConnectionRuntime?.observedFailure(n,la(e)),{id:t.id,status:"offline",checkedAt:aa(),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(!gc(t)||!uc(t)){const e=new Error("Node agent TCP listener settings are available only for the built-in local node.");throw Object.assign(e,{statusCode:403,code:"LOCAL_NODE_LISTENER_ONLY"}),e}return t}createNodeJoinInvite(e={}){return this.nodeJoinService.createInvite(e)}completeNodeJoin(e){return this.nodeJoinService.complete(e)}async connectNodeToControlPlane(e,t){const n=this.requireNode(e),s=$a.parse(t);return this.nodeAgentGateway.createControlPlaneConnection(n,s)}async listNodeControlPlanePairings(e){const t=this.requireNode(e);return this.nodeAgentGateway.listControlPlanePairings(t)}async deleteNodeControlPlanePairing(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteControlPlanePairing(n,t)}async listNodeControlPlaneConnections(e){const t=this.requireNode(e);return this.nodeAgentGateway.listControlPlaneConnections(t)}async deleteNodeControlPlaneConnection(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteControlPlaneConnection(n,t)}updateImage(e,t){return this.catalogService.updateImage(e,t)}async deleteImage(e){this.catalogService.requireImage(e);const t=this.listProjects().find(t=>t.defaultImageSelection?.imageId===e);if(t)throw Object.assign(new Error(`Image ${e} is the default for project ${t.name}.`),{statusCode:409,code:"IMAGE_IN_USE"});const n=(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 s=(await this.listNodeInstances()).find(t=>t.imageSelection?.imageId===e);if(s)throw Object.assign(new Error(`Image ${e} is used by instance ${s.name}.`),{statusCode:409,code:"IMAGE_IN_USE"});return this.catalogService.deleteImage(e)}listNodes(){return this.nodes.list()}listPublicNodes(){return this.listNodes().map(e=>na(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=La.parse(t),s=this.requireNode(e);this.proxyLifecycle.assertIdentityPatch(s,n);const i=Gs.parse({...s,...n,id:e,createdAt:s.createdAt,updatedAt:aa()});return this.nodes.put(i)}deleteNode(e){if(gc(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 s=this.requireNode(e);return this.nodeAgentGateway.updateRuntime(s,t,n)}async deleteNodeRuntime(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteRuntime(n,t)}async checkNodeRuntime(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.checkRuntime(n,t)}async listControlledInstances(){return(await this.listNodeInstances()).map(ra)}async listControlledInstancesWithDiagnostics(){const e=await this.listNodeInstancesWithDiagnostics();return{items:e.items.map(ra),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=ja.parse(t),s=await this.requireNodeInstance(e),i=this.requireNode(s.nodeId),{modelSelection:r,...o}=n;let a=Object.keys(o).length?await this.nodeAgentGateway.updateInstance(i,e,o):s;if(r){const t=await this.modelService.prepareAssignment(i,r);a=(await this.nodeAgentGateway.assignInstanceModels(i,e,t)).instance}return ra(a)}async deleteControlledInstance(e,t){const n=vn.parse(t),s=await this.requireNodeInstance(e),i=this.requireNode(s.nodeId),r=await this.nodeAgentGateway.deleteInstance(i,e,n);return r.completed&&this.configSyncPreferences.delete(e),r}listEnvironmentTemplates(e){return this.nodeAgentGateway.listEnvironmentTemplates(this.requireNode(e))}getEnvironmentTemplate(e,t){return this.nodeAgentGateway.getEnvironmentTemplate(this.requireNode(e),t)}async createEnvironmentTemplate(e,t){const n=await this.requireNodeInstance(e);return this.nodeAgentGateway.createEnvironmentTemplate(this.requireNode(n.nodeId),e,t)}deleteEnvironmentTemplate(e,t){return this.nodeAgentGateway.deleteEnvironmentTemplate(this.requireNode(e),t)}async startControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return await this.modelService.ensureInstanceAssignment(t),ra(await this.nodeAgentGateway.startInstance(n,e))}async stopControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return ra(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),ra(await this.nodeAgentGateway.restartInstance(n,e))}async retryControlledInstanceImageProvisioning(e){const t=await this.requireNodeInstance(e);return ra(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(!Si(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 mr(Me,await this.instanceRequest(e,"/ai-sessions/state"))}catch(t){return this.logWarn({instanceId:e.id,error:la(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(!Si(e)||!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=no();return{streamId:`bootstrap:${e.id}:app.sessions`,revision:0,lastEventAt:t.updatedAt,snapshot:t}}try{return mr(Dr,await this.instanceRequest(e,"/apps/sessions/state"))}catch(t){this.logWarn({instanceId:e.id,error:la(t),errorCode:"APP_SESSION_LIVE_REFRESH_FAILED"},"control plane failed to refresh live app sessions");const n=no();return{streamId:`bootstrap:${e.id}:app.sessions`,revision:0,lastEventAt:n.updatedAt,snapshot:n}}}));return{updatedAt:(new Date).toISOString(),instances:e.map((e,n)=>({instanceId:e.id,streamId:t[n].streamId,appSessions:t[n].snapshot,revision:t[n].revision,lastEventAt:t[n].lastEventAt}))}}async recoverAiSessionDelta(e,t,n){const s=await this.requireControlledInstance(e,!0),i=new URLSearchParams({streamId:t,sinceRevision:String(n)});return mr(We,await this.instanceRequest(s,`/ai-sessions?${i}`))}async recoverAiSessionSnapshot(e){const t=await this.requireControlledInstance(e,!0);return mr(Me,await this.instanceRequest(t,"/ai-sessions/state"))}async recoverAppSessionDelta(e,t,n){const s=await this.requireControlledInstance(e,!0),i=new URLSearchParams({streamId:t,sinceRevision:String(n)});return mr(Fr,await this.instanceRequest(s,`/apps/sessions?${i}`))}async recoverAppSessionSnapshot(e){const t=await this.requireControlledInstance(e,!0);return mr(Dr,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=aa(),t=[],n=await this.listAiSessions(),s=new Map(n.instances.map(e=>[e.instanceId,e.aiSessions])),i=await this.nodeAgentGateway.listFleetInstances(this.listNodes());for(const n of i.items){if("online"!==n.connectionStatus&&"online"!==n.agentStatus||!n.target.web)continue;const i=n.projectId?this.catalogService.getProject(n.projectId):void 0;for(const r of s.get(n.id)?.sessions||[]){if("waiting"!==r.status)continue;const s=wi.parse({id:`${n.id}:ai:${r.id}`,instanceId:n.id,projectId:n.projectId,aiSessionId:r.id,providerSessionId:r.providerSessionId,result:r.summary||r.currentTool?.inputPreview||r.lastMessage||`${r.agent} is waiting for approval`,source:r.agent,kind:"approval",status:"pending",lastSeenAt:e});t.push({...s,project:i,instance:ra(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:s,...i}=t,r={type:"runtime-path",path:t.cwdFolderId?await this.runtimeCwdForFolderId(n,t.cwdFolderId):n.runtime.workspacePath||n.workspace.path||ia(n.source).path||"/workspace"};return this.aiSessionActionService.create(e,{...i,cwd:r})}openAiSessionApp(e,t,n){return this.aiSessionActionService.openApp(e,t,n)}closeAiSession(e,t,n){return this.aiSessionActionService.close(e,t,n)}aiSessionActionDiagnostics(){return this.aiSessionActionService.diagnostics()}async launchAppSession(e,t="terminal-tty",n={}){const s=await this.requireControlledInstance(e,!0);if("online"!==s.connectionStatus&&"online"!==s.agentStatus){const e=new Error(`Instance ${s.name} is still starting. Wait for it to connect before launching apps.`);throw Object.assign(e,{statusCode:409,code:"INSTANCE_NOT_CONNECTED"}),e}const i=await this.resolveAppLaunchOptions(s,n),r=await this.instanceRequest(s,"/apps/sessions",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({appId:t,...i})});return await this.listAppSessions({refresh:!0}),r}async stopAppSession(e,t){const n=await this.requireControlledInstance(e,!0),s=await this.instanceRequest(n,`/apps/sessions/${encodeURIComponent(t)}/stop`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});return await this.listAppSessions({refresh:!0}),s}async instanceAppManagement(e){const t=await this.requireControlledInstance(e,!0);try{return function(e){try{return mr(Fn,e)}catch(e){if(e instanceof o.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 o.z.ZodError||404===t.statusCode){const e=new Error("This controlled instance does not support managed app operations.");throw Object.assign(e,{statusCode:409,code:"INSTANCE_APP_MANAGEMENT_UNSUPPORTED"}),e}throw e}}async requestInstanceAppOperation(e,t,n,s={}){const i=await this.requireControlledInstance(e,!0);return mr(Wn,await this.instanceRequest(i,`/apps/${encodeURIComponent(t)}/${n}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)}))}async instanceAppManagementJob(e,t){const n=await this.requireControlledInstance(e,!0);return mr(Wn,await this.instanceRequest(n,`/apps/jobs/${encodeURIComponent(t)}`))}async renameAppSession(e,t,n){const s=await this.requireControlledInstance(e,!0),i=await this.instanceRequest(s,`/apps/sessions/${encodeURIComponent(t)}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({title:n})});return await this.listAppSessions({refresh:!0}),i}sendAiSessionMessage(e,t,n,s,i=[],r=[],o){return this.aiSessionActionService.sendMessage(e,t,n,s,i,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,s){return this.aiSessionActionService.editQueuedMessage(e,t,n,s)}reorderAiSessionQueuedMessages(e,t,n){return this.aiSessionActionService.reorderQueuedMessages(e,t,n)}interruptAiSession(e,t){return this.aiSessionActionService.interrupt(e,t)}async proxyInstanceHttp(e,t,n={}){const s=await this.requireControlledInstance(e,!0);return this.controlledInstanceGateway.proxyHttp(s,t,n)}async proxyInstanceWebSocket(e,t,n,s,i={}){const r=await this.requireControlledInstance(e,!0);this.controlledInstanceGateway.proxyWebSocket(r,t,n,s,i)}async instanceConfigSyncState(e){const t=await this.requireControlledInstance(e,!0),n=o.z.array(wr).parse(await this.instanceRequest(t,"/config-sync/programs"));return kr.parse({programs:n,preferences:this.configSyncPreferences.get(e)?.preferences||oc()})}async listInstanceConfigSyncFolders(e,t={}){const n=await this.requireControlledInstance(e,!0),s=new URLSearchParams;return t.path&&s.set("path",t.path),void 0!==t.depth&&s.set("depth",String(t.depth)),o.z.array(oi).parse(await this.instanceRequest(n,"/config-sync/folders"+(s.size?`?${s}`:"")))}async syncInstanceConfigs(e,t){const n=Sr.parse(t),s=await this.requireControlledInstance(e,!0);if("export"===n.direction&&"local-folder"!==s.source.type){const e=new Error("Exporting instance config is only available for local folder projects.");throw Object.assign(e,{statusCode:400,code:"CONFIG_SYNC_EXPORT_REQUIRES_LOCAL_PROJECT"}),e}const i=function(e){const t=function(e){const t=[];for(const n of e.split("/"))if(n&&"."!==n)if(".."===n){if(!t.length)return"..";t.pop()}else t.push(n);return t.join("/")||"."}(e.trim().replace(/\\/g,"/")||".");if(t.startsWith("/")||".."===t||t.startsWith("../")){const e=new Error("Config sync folder must stay inside the instance workspace.");throw Object.assign(e,{statusCode:400,code:"CONFIG_SYNC_FOLDER_INVALID"}),e}return t||"."}(n.workspaceFolder),r={...n,workspaceFolder:i},o=mr(Cr,await this.instanceRequest(s,"/config-sync",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(r)})),a=aa(),d=this.configSyncPreferences.get(e);return this.configSyncPreferences.put({id:e,preferences:{...d?.preferences||oc(),[n.direction]:i},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 s="reverse-wss"!==e.connectionMode&&"control-plane-proxy"!==e.connectionMode;try{const i=await this.nodeAgentTransportResolver.resolve(e).request(e,t,n);return s&&this.nodeConnectionRuntime?.observedReachable(e),i}catch(t){throw!s||n.signal?.aborted||function(e){return e instanceof Error&&("AbortError"===e.name||"ABORT_ERR"===e.code)}(t)||this.nodeConnectionRuntime?.observedFailure(e,la(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{}pa("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||pa("NODE_RUNTIME_NOT_FOUND",`Runtime ${t} was not found on node ${e}.`),n}async requireNodeLocalFolder(e,t){return this.nodeAgentGateway.requireLocalFolder(e,t)}async resolveAppLaunchOptions(e,t){const n="string"==typeof t.cwdFolderId?t.cwdFolderId.trim():"",s={...t};return delete s.cwdFolderId,n?{...s,cwd:await this.runtimeCwdForFolderId(e,n)}:s}async runtimeCwdForFolderId(e,t){const n=this.requireNode(e.nodeId),s=await this.requireNodeLocalFolder(n,t);if(s.nodeId!==e.nodeId){const t=new Error(`Local folder ${s.id} belongs to node ${s.nodeId}, not ${e.nodeId}.`);throw Object.assign(t,{statusCode:400,code:"LOCAL_FOLDER_REQUIRES_INSTANCE_NODE"}),t}const i=await this.requireNodeRuntimeOnNode(e.nodeId,e.runtimeId);return this.appLaunchCwdForFolder(e,s,i)}appLaunchCwdForFolder(e,n,s){const i=function(e,n,s){if("local"===s.type)return dc(i=n).resolve(i);var i;if("local-folder"!==e.source.type)return;const r=function(e,t){if(ac(e)!==ac(t))return;const n=dc(e),s=n.resolve(e),i=n.resolve(t),r=n.relative(s,i);return r?".."===r||r.startsWith(`..${n.sep}`)||n.isAbsolute(r)?void 0:r.split(n.sep).filter(Boolean):[]}(e.source.path,n);if(!r)return;const o=e.runtime.workspacePath||e.workspace.path||ia(e.source).path||"/workspace";return r.length?t.posix.join(o,...r):o}(e,n.path,s);if(i)return i;if("local-folder"!==e.source.type){const e=new Error("App cwd folder selection is only supported for local-folder instances.");throw Object.assign(e,{statusCode:400,code:"APP_CWD_REQUIRES_LOCAL_FOLDER_SOURCE"}),e}const r=new Error(`Local folder ${n.path} is outside the instance workspace ${e.source.path}.`);throw Object.assign(r,{statusCode:400,code:"APP_CWD_OUTSIDE_WORKSPACE"}),r}requireProject(e){return this.catalogService.requireProject(e)}requireModel(e,t=!1){return this.modelService.require(e,t)}requireImage(e){return this.catalogService.requireImage(e)}requireNode(e){const t=this.nodes.get(e);return t||pa("NODE_NOT_FOUND",`Node ${e} was not found.`),t}requirePublicNode(e){return na(this.projectNodeConnection(this.requireNode(e)))}async requireControlledInstance(e,t=!1){const n=await this.requireNodeInstance(e);return t?n:ra(n)}}function mc(e){return h(String(e),"escape").replace(/\n+$/,"")}function yc(e){const[t,...n]=String(e).split("\n");return[`*${mc(t)}*`,...n.map(mc)].join("\n")}function fc(e,t=4e3){const n=String(e),s=yc(n);if(s.length<=t)return s;const[i,...r]=n.split("\n"),o=r.join("\n"),a="...\n";let d=i;for(;yc(`${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=yc(`${d}\n${a}`);for(;c<=l;){const e=Math.floor((c+l)/2),n=yc(`${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=yc(`${d}\n${a}${g.slice(h+1)}`)),u}function Ic(e){return String(e).replace(/\\([_*\[\]()~`>#+\-=|{}.!\\])/g,"$1")}async function bc(e,t,n,s,i={}){if(!t.token)return;const r=n=>e(`https://api.telegram.org/bot${t.token}/sendMessage`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)}),o=function(e,t={}){const n=String(e),s=t.rawMarkdownV2?e=>e:mc;if(s(n).length<=4e3)return[n];const i=[];let r=n;for(;r;){let e=1,t=r.length,n=1;for(;e<=t;){const i=Math.floor((e+t)/2);s(r.slice(0,i)).length<=4e3?(n=i,e=i+1):t=i-1}if(n<r.length){const e=r.slice(0,n),t=Math.max(e.lastIndexOf("\n"),e.lastIndexOf(" "));t>=Math.floor(.6*n)&&(n=t+1)}i.push(r.slice(0,n).trimEnd()),r=r.slice(n).trimStart()}return i.filter(Boolean)}(s,i);let a;for(const[e,t]of o.entries())a=await wc(r,"sendMessage",t,{chat_id:n,...0===e&&i.replyToMessageId?{reply_to_message_id:i.replyToMessageId,allow_sending_without_reply:!0}:{},...e===o.length-1&&i.replyMarkup?{reply_markup:i.replyMarkup}:{}},i);return a}async function vc(e,t,n){if(!t.token||!n)throw new Error("Telegram file id is required.");const s=await e(`https://api.telegram.org/bot${t.token}/getFile`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({file_id:n})}),i=await s.json().catch(()=>({}));if(!s.ok||!1===i.ok||!i.result?.file_path)throw new Error(i.description||`Telegram getFile failed with HTTP ${s.status}`);return`https://api.telegram.org/file/bot${t.token}/${i.result.file_path}`}async function wc(e,t,n,s,i){const r=i.parseMode||"MarkdownV2",o=i.rawMarkdownV2?String(n):mc(n),a=await e({...s,text:o,disable_web_page_preview:!0,parse_mode:r}),d=await a.json().catch(()=>({}));if(a.ok&&!1!==d.ok)return d.result;if("editMessageText"===t&&Sc(d.description))return;if(i.rawMarkdownV2&&"MarkdownV2"===r){const i=await e({...s,text:Ic(n),disable_web_page_preview:!0,parse_mode:"Markdown"}),r=await i.json().catch(()=>({}));if(i.ok&&!1!==r.ok)return r.result;if("editMessageText"===t&&Sc(r.description))return}const c=await e({...s,text:i.rawMarkdownV2?Ic(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||!Sc(l.description))throw new Error(l.description||d.description||`Telegram ${t} failed with HTTP ${c.status}`)}function Sc(e){return"string"==typeof e&&e.toLowerCase().includes("message is not modified")}function Ac(e,t){if("string"==typeof e&&e.trim())return e.trim();zc(`Chat action token is missing ${t}.`)}function kc(e){if("allow"===e||"deny"===e||"skip"===e)return e;zc("Chat action token has an invalid decision.")}function zc(e){const t=new Error(e);throw Object.assign(t,{statusCode:400,code:"CHAT_ACTION_TOKEN_INVALID"}),t}function Tc(e){return Buffer.from(e,"base64url").toString("utf8")}function Cc(e){return String(e||"").split(/\r?\n/,1)[0].replace(/^#+\s*/,"").trim().slice(0,20)||"消息通知"}function xc(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,"string"==typeof t?t:JSON.stringify(t)]))}function Ec(e){return`dtv1.card//IM_GROUP.${e}`}function Nc(e){return`dtv1.card//IM_ROBOT.${e}`}function _c(e,t){return Gc(t.biz_conversation_id).trim()||Gc(e.spaceId).replace(/^dtv1\.card\/\/(?:IM_GROUP|IM_SINGLE|IM_ROBOT)\./,"")}function Pc(e,t={}){const n=Gc(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 Rc(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 Oc(e,t,n,s,i){const r=_c(s,i);return{cardUpdateOptions:{updateCardDataByKey:!0,updatePrivateDataByKey:!1},cardData:{cardParamMap:xc({type:"actions",title:"TaskHandoff",description:e,list:Rd(t),biz_out_track_id:s.outTrackId||i.biz_out_track_id||"",biz_conversation_id:r,biz_sender_id:i.biz_sender_id||s.userId||"",biz_session_webhook:i.biz_session_webhook||"",biz_conversation_type:i.biz_conversation_type||"",biz_step:n,error_msg:""})}}}function jc(e,t,n){const s=[];return Mc(s,n),Mc(s,t),Mc(s,e),s.find(e=>Rc(e))||""}function Mc(e,t){for(const n of["actionIdList","actionIds"]){const s=t[n];Array.isArray(s)&&e.push(...s.map(e=>Gc(e)).filter(Boolean))}for(const n of["actionId","action_id","id","actionValue"]){const s=Gc(t[n]);s&&e.push(s)}}async function Dc(e,t,n,s){s?.("info",{target:"sessionWebhook",hasSessionWebhook:Boolean(t),textPreview:Fc(n)},"dingding webhook send requested");const i=await e(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({msgtype:"markdown",markdown:{title:Cc(n),text:n}})}),r=await i.json().catch(()=>{});if(s?.(i.ok?"info":"warn",{target:"sessionWebhook",status:i.status,response:Uc(r)},"dingding webhook send completed"),!i.ok)throw new Error(`DingDing webhook failed with HTTP ${i.status}`)}async function qc(e){const t=Rd(e.replyMarkup);if(!t.length&&!e.forceCard)return e.sessionWebhook&&await Dc(e.fetchImpl,e.sessionWebhook,e.text,e.runtime.onLog),e.sessionWebhook?{delivered:!0}:void 0;const n=e.bridge.settings||{},s=Gc(n.robotCode),i=Gc(n.cardTemplateId)||"13fc6717-12e4-43ed-8533-111a310d4995.schema",r=Gc(n.cardCallbackRouteKey)||"task_handoff_message",o=e.senderId||e.runtime.senderIds.get(e.chatId)||Gc(n.senderId),a=(d=e.runtime,c=e.chatId,d.conversationTypes?.get(c)||"IM_GROUP");var d,c;if(!s||!i||!o){if(e.sessionWebhook&&!e.forceCard)return await Dc(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=xc({type:"actions",title:e.title||Cc(e.text),description:e.text,list:t,biz_out_track_id:l,biz_step:e.step||"task_handoff_actions",biz_conversation_id:e.chatId,biz_sender_id:o,biz_session_webhook:e.sessionWebhook||e.runtime.chatWebhooks.get(e.chatId)||"",biz_conversation_type:a,error_msg:""}),u=function(e,t,n,s){return"IM_SINGLE"===e?{openSpaceId:(i=t,`dtv1.card//IM_SINGLE.${i}`),imSingleOpenSpaceModel:{},imSingleOpenDeliverModel:{extension:{}}}:"IM_ROBOT"===e?{openSpaceId:Nc(n),imRobotOpenSpaceModel:{supportForward:!1},imRobotOpenDeliverModel:{extension:{},robotCode:s,spaceType:"IM_ROBOT"}}:{openSpaceId:Ec(t),imGroupOpenSpaceModel:{supportForward:!1},imGroupOpenDeliverModel:{extension:{},robotCode:s}};var i}(a,e.chatId,o,s);return e.runtime.onLog?.("info",{target:"card",chatId:e.chatId,senderId:o,conversationType:a,openSpaceId:u.openSpaceId,hasSessionWebhook:Boolean(e.sessionWebhook||e.runtime.chatWebhooks.get(e.chatId)),hasReplyMarkup:Boolean(e.replyMarkup),actionCount:t.length,textPreview:Fc(e.text)},"dingding card send requested"),await Lc(e.fetchImpl,e.bridge,e.runtime,"POST","/v1.0/card/instances/createAndDeliver",{userId:o,cardTemplateId:i,outTrackId:l,callbackType:"STREAM",callbackRouteKey:r,cardData:{cardParamMap:p},userIdType:Number(n.cardUserIdType||1),...u}),{delivered:!0,outTrackId:l}}async function Lc(e,t,n,s,i,r){const o=await async function(e,t,n){if(n.accessToken&&n.accessToken.expiresAt>Date.now()+6e4)return n.accessToken.value;const s=Gc(t.settings.clientSecret);if(!t.token||!s)throw new Error("DingDing client id/secret is not configured.");const i=await e("https://api.dingtalk.com/v1.0/oauth2/accessToken",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({appKey:t.token,appSecret:s})}),r=await i.json().catch(()=>({}));if(!i.ok||!r.accessToken)throw new Error(`DingDing access token failed with HTTP ${i.status}`);const o=Number(r.expireIn||7200);return n.accessToken={value:r.accessToken,expiresAt:Date.now()+1e3*Math.max(60,o-120)},n.accessToken.value}(e,t,n);n.onLog?.("info",{method:s,path:i,body:$c(r)},"dingding api request");const a=await e(`https://api.dingtalk.com${i}`,{method:s,headers:{"content-type":"application/json","x-acs-dingtalk-access-token":o},body:JSON.stringify(r)}),d=await a.json().catch(()=>{});if(n.onLog?.(a.ok?"info":"warn",{method:s,path:i,status:a.status,response:Uc(d)},"dingding api response"),!a.ok)throw new Error(`DingDing API failed with HTTP ${a.status}`);const c=Hc(d),l=c.code??c.errcode,p=c.success;if(void 0!==l&&"0"!==String(l)||!1===p)throw new Error(Gc(c.message||c.errmsg)||`DingDing API returned ${String(l||"failure")}`);const u=function(e){const t=Hc(Hc(e).result).deliverResults;if(!Array.isArray(t))return"";const n=t.find(e=>!1===Hc(e).success);if(!n)return"";const s=Hc(n),i=Gc(s.spaceId),r=Gc(s.errorMsg||s.message||s.errmsg)||"delivery failed";return i?`DingDing card delivery failed for ${i}: ${r}`:`DingDing card delivery failed: ${r}`}(d);if(u)throw new Error(u);return a}function $c(e){const t=Hc(e),n=Hc(t.cardData),s=Hc(n.cardParamMap);return{openSpaceId:Gc(t.openSpaceId),outTrackId:Gc(t.outTrackId),userId:Gc(t.userId),userIdType:t.userIdType,callbackType:Gc(t.callbackType),callbackRouteKey:Gc(t.callbackRouteKey),hasImGroupTarget:Boolean(t.imGroupOpenSpaceModel||t.imGroupOpenDeliverModel),hasImSingleTarget:Boolean(t.imSingleOpenSpaceModel||t.imSingleOpenDeliverModel),hasImRobotTarget:Boolean(t.imRobotOpenSpaceModel||t.imRobotOpenDeliverModel),imGroupOpenDeliverModel:Bc(t.imGroupOpenDeliverModel),imSingleOpenDeliverModel:Bc(t.imSingleOpenDeliverModel),imRobotOpenDeliverModel:Bc(t.imRobotOpenDeliverModel),bizConversationId:Gc(s.biz_conversation_id),bizConversationType:Gc(s.biz_conversation_type),bizSenderId:Gc(s.biz_sender_id),hasBizSessionWebhook:Boolean(Gc(s.biz_session_webhook))}}function Bc(e){const t=Hc(e);if(Object.keys(t).length)return{hasExtension:Boolean(t.extension),hasRobotCode:Boolean(Gc(t.robotCode)),spaceType:Gc(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 Uc(e){const t=Hc(e),n=Hc(t.result);return{code:t.code??t.errcode,message:Fc(t.message||t.errmsg,240),success:t.success,requestId:t.requestId,result:Object.keys(n).length?n:void 0}}function Fc(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 Hc(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Wc(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:"string"==typeof e&&e.trim()?Vc(e):{}}function Gc(e){return"string"==typeof e?e:""}function Vc(e){try{return Hc(JSON.parse(String(e||"{}")))}catch{return{}}}function Kc(e){return JSON.stringify(Rd(e))}const Jc="task_handoff_action_id";function Qc(e,t){const n=Rd(t);return{schema:"2.0",config:{summary:{content:Zc(e)}},body:{elements:[{tag:"markdown",content:e},...n.map(e=>({tag:"button",text:{tag:"plain_text",content:e.text},type:el(e.text),width:"fill",size:"medium",behaviors:[{type:"callback",value:{[Jc]:e.id}}]}))]}}}function Yc(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[Jc]||t.action_id||t.actionId||t.id||e)}function Xc(e){return JSON.stringify(Rd(e))}function Zc(e){const t=e.replace(/\s+/g," ").trim();return t.length<=50?t:`${t.slice(0,47)}...`}function el(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 tl(e){return e instanceof Error?e.message:String(e)}function nl(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 sl(e){return Array.isArray(e?.actionRows)?e.actionRows:(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e])}function il(e,t){const n=sl(e),s=sl(t);return n.length===s.length&&n.every((e,t)=>{const n=s[t];return e.length===n.length&&e.every((e,t)=>{const s=n[t];return e.text===s?.text&&e.callbackData===s.callbackData})})}class rl{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||nl,this.retryAfterMs=e.retryAfterMs,this.isMessageTooLong=e.isMessageTooLong,this.onLog=e.onLog}remember(e,t,n,s,i,r){const o=this.entries.get(e);return o&&(clearTimeout(o.timer),o.timer=void 0,o.pendingText=void 0),this.entries.set(e,{lastText:n,lastUpdateAt:Date.now(),messageId:t,route:s,options:i,lastOptions:i,renderOptions:r}),o}rekey(e,t){if(e===t)return this.entries.has(e);const n=this.entries.get(e);if(!n||this.entries.has(t))return!1;if(clearTimeout(n.timer),n.timer=void 0,this.entries.delete(e),this.entries.set(t,n),n.pendingText){const e=n.rateLimitedUntil?Math.max(0,n.rateLimitedUntil-Date.now()):Math.max(0,this.updateIntervalMs-(Date.now()-n.lastUpdateAt));this.scheduleFlush(t,e)}return!0}scheduleFlush(e,t){const n=this.entries.get(e);n&&!n.timer&&(n.timer=setTimeout(()=>{n.timer=void 0;const t=n.pendingText;n.pendingText=void 0,t&&this.applyUpdate(e,t,n.route,n.options)},t))}markRateLimited(e,t,n,s){const i=this.entries.get(e);i&&(i.rateLimitedUntil=Date.now()+n,i.pendingText=t,i.route=s||i.route,this.scheduleFlush(e,n))}async applyUpdate(e,t,n,s){let i=this.entries.get(e);const r=i,o=n||i?.route,a=s||i?.options;try{if(i&&(i.route=o,i.options=a),i?.pending&&await i.pending,i=this.entries.get(e),r&&i!==r)return!1;if(i?.messageId){if(i.lastText===t&&il(i.lastOptions,a))return!0;const n=Date.now()-(i.lastUpdateAt||0);return n<this.updateIntervalMs?(i.pendingText=t,i.route=o||i.route,i.options=a||i.options,this.scheduleFlush(e,this.updateIntervalMs-n),!0):(await this.edit(i.messageId,t,o||i.route,a),i.lastText=t,i.lastOptions=a,i.lastUpdateAt=Date.now(),i.rateLimitedUntil=void 0,!0)}const n={lastText:t,lastUpdateAt:Date.now(),route:o,options:a,lastOptions:a};return n.pending=this.send(t,o,a).then(e=>{const t=this.messageIdFromResult(e);t&&(n.messageId=t)}).finally(()=>{n.pending=void 0}),this.entries.set(e,n),await n.pending,this.entries.get(e)===n&&(n.rateLimitedUntil=void 0,Boolean(n.messageId))}catch(n){const s=this.retryAfterMs?.(n);return s&&this.markRateLimited(e,t,s,o),this.onLog?.(`Telegram progress update skipped: ${tl(n)}`),!1}}update(e,t,n,s){const i=String(t||"").trim();if(!i)return;const r=this.entries.get(e);if(r&&(r.route=n||r.route,r.options=s||r.options),r?.lastText===i&&il(r.lastOptions,s||r.options)&&!r.pending&&!r.pendingText)return;const o=Date.now();if(r?.rateLimitedUntil){if(r.rateLimitedUntil>o)return r.pendingText=i,void this.scheduleFlush(e,r.rateLimitedUntil-o);r.rateLimitedUntil=void 0}if(r?.pending&&!r.messageId)return r.pendingText=i,void this.scheduleFlush(e,this.updateIntervalMs);if(!r||!r.messageId)return void this.applyUpdate(e,i,n,s);const a=Date.now()-(r.lastUpdateAt||0);if(a>=this.updateIntervalMs)return clearTimeout(r.timer),r.timer=void 0,r.pendingText=void 0,void this.applyUpdate(e,i,n||r.route,s||r.options);r.pendingText=i,this.scheduleFlush(e,this.updateIntervalMs-a)}async finish(e,t,n,s,i){const r=this.entries.get(e);if(!r)return!1;try{if(clearTimeout(r.timer),r.timer=void 0,r.pendingText=void 0,r.pending&&await r.pending,this.entries.delete(e),!r.messageId)return!1;const o=s||r.options;return r.lastText===t&&il(r.lastOptions,o)||await this.edit(r.messageId,t,n||r.route,o,i||r.renderOptions),!0}catch(t){return this.entries.delete(e),this.isMessageTooLong?.(t)?this.onLog?.("Telegram progress finish too long; sending result as multiple messages"):this.onLog?.(`Telegram progress finish skipped: ${tl(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: ${tl(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 ol=20971520;function al(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 dl(e,n,s="telegram-image",i){if(i&&i>ol)throw new Error(`image is too large: ${i} bytes`);const r=await e.getFileLink(n),o=String(r),a=await(e.fetchFile||fetch)(o);if(!a.ok)throw new Error(`download failed with HTTP ${a.status}`);const d=Number(a.headers.get("content-length")||0);if(d>ol)throw new Error(`image is too large: ${d} bytes`);const c=t.extname(s)||".jpg";let l=c;try{l=t.extname(new URL(o).pathname)||c}catch{l=c}const p=t.join(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>ol)throw new Error(`image is too large: ${h.length} bytes`);return await m.writeFile(g,h),g}class cl{store;constructor(e){this.store=new rl({updateIntervalMs:e.updateIntervalMs,send:(t,n,s)=>e.send(e.requireBridge(n?.bridgeId||""),n?.chatId||"",fc(t),{rawMarkdownV2:!0,replyMarkup:ml(s)}),edit:(t,n,s,i)=>e.edit(e.requireBridge(s?.bridgeId||""),s?.chatId||"",t,fc(n),{rawMarkdownV2:!0,replyMarkup:ml(i)}),delete:(t,n)=>e.deleteMessage(e.requireBridge(n?.bridgeId||""),n?.chatId||"",t),onLog:e.onLog})}get entries(){return this.store.entries}remember(e,t,n,s){return this.store.remember(e,t,n,s)}rekey(e,t){return this.store.rekey(e,t)}delete(e){return this.store.delete(e)}async applyUpdate(e){return this.store.applyUpdate(e.key,e.text,{bridgeId:e.bridge.id,chatId:e.chatId},{actionRows:e.actionRows})}}async function ll(e){return(await async function(e,t,n,s){const i=[];for(const r of al(n))try{const n=await dl({getFileLink:n=>vc(e,t,n),fetchFile:e},r.fileId,r.fileName,r.fileSize);i.push(n)}catch(e){s?.({fileId:r.fileId,fileName:r.fileName,error:e})}return i}(e.fetchImpl,e.bridge,e.message,e.onImageDownloadError)).map((e,s)=>{const i=n.readFileSync(e);return{id:`tg_${a.randomUUID().replace(/-/g,"").slice(0,24)}`,kind:"image",name:t.basename(e)||`telegram-image-${s+1}`,mime:pl(e),size:i.length,source:{type:"inline",encoding:"base64",data:i.toString("base64")}}})}function pl(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 ul(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function gl(e){return e&&"object"==typeof e?e:{}}function hl(e){return"string"==typeof e?e:""}function ml(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return Nd(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function yl(e){const t=Array.isArray(e.item_list)?e.item_list:[];for(const e of t){const t=fl(e);if(1!==t.type)continue;const n=Il(fl(t.text_item).text).trim();if(n)return n}return""}function fl(e){return e&&"object"==typeof e?e:{}}function Il(e){return"string"==typeof e?e:""}function bl(e){const{fetchImpl:t,bridge:n,dingdingRuntime:s,larkRuntime:i}=e;return"telegram"===n.channel?function(e,t){return{bridge:t,send:async(n,s,i={})=>{const r=await bc(e,t,n,s,{replyMarkup:i.replyMarkup,replyToMessageId:i.replyToMessageId,rawMarkdownV2:i.rawMarkdownV2,parseMode:i.parseMode});return{provider:"telegram",raw:r,messageId:Number(gl(r).message_id)||void 0}}}}(t,n):"dingding"===n.channel?function(e,t,n){return{bridge:t,send:async(s,i,r={})=>{const o=r.sessionWebhook||n?.chatWebhooks.get(s)||Gc(t.settings.sessionWebhook);if(r.replyMarkup&&n){const a=await qc({fetchImpl:e,bridge:t,runtime:n,chatId:s,text:i,replyMarkup:r.replyMarkup,sessionWebhook:o,senderId:r.senderId||n.senderIds.get(s)||Gc(t.settings.senderId)});if(a?.delivered)return{provider:"dingding",interactionId:a.outTrackId}}if(o)return await Dc(e,o,i,n?.onLog),{provider:"dingding"}}}}(t,n,s):"lark"===n.channel?function(e,t){return{bridge:e,send:async(e,n,s={})=>{if(!t)return;const i=await t.channel.send(e,s.replyMarkup?{card:Qc(n,s.replyMarkup)}:{markdown:n});return{provider:"lark",interactionId:i.messageId,raw:i}}}}(n,i):"wechat"===n.channel?function(e,t){return{bridge:t,send:async(n,s,i={})=>{const r=i.contextToken||Il(t.settings.contextToken);if(r)return await async function(e,t,n,s,i){const r=Il(t.settings.baseUrl)||"https://ilinkai.weixin.qq.com",o=await e(`${r}/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:a.randomUUID(),message_type:2,message_state:2,context_token:s,item_list:[{type:1,text_item:{text:i}}]},base_info:{channel_version:"1.0.2"}})}),d=await o.json().catch(()=>({}));if(!o.ok||d.errcode)throw new Error(Il(d.errmsg)||`WeChat send failed with HTTP ${o.status}`)}(e,t,n,r,s),{provider:"wechat"}}}}(t,n):{bridge:n,send:async()=>{}}}class vl{entries=new Map;fetchImpl;generations=new Map;constructor(e){this.fetchImpl=e}clear(){for(const e of new Set([...this.generations.keys(),...[...this.entries.values()].map(e=>e.bridgeId)]))this.clearBridge(e)}clearBridge(e){this.generations.set(e,this.generation(e)+1),this.clearEntries(t=>t.bridgeId===e)}generation(e){return this.generations.get(e)||0}isCurrent(e,t){return this.generation(e)===t}clearEntries(e){for(const[t,n]of this.entries)e(n)&&(n.timer&&clearTimeout(n.timer),n.cancelPending?.(new Error("DingDing progress update was cancelled.")),this.entries.delete(t))}async applyUpdate(e,t){const n=this.generation(e.bridge.id),s=Kc(e.replyMarkup);let i=this.entries.get(e.key);if(i?.pending&&await i.pending,!this.isCurrent(e.bridge.id,n))return!1;if(i=this.entries.get(e.key),i?.outTrackId){if(i.lastText===e.text&&i.lastActionsFingerprint===s)return!0;const r=Date.now()-(i.lastUpdateAt||0);return r<1e3?(i.pendingText=e.text,i.pendingReplyMarkup=e.replyMarkup,i.timer||(i.pending=new Promise((s,o)=>{i.cancelPending=o,i.timer=setTimeout(()=>{i.timer=void 0,i.cancelPending=void 0;const r=i.pendingText,a=i.pendingReplyMarkup;if(i.pendingText=void 0,i.pendingReplyMarkup=void 0,!r)return s(void 0);this.updateExistingEntry(e,t,i,r,a,Kc(a),n).then(s,o)},1e3-r)}).finally(()=>{i.pending=void 0,i.timer=void 0,i.cancelPending=void 0})),await i.pending,this.isCurrent(e.bridge.id,n)&&this.entries.has(e.key)):(await this.updateExistingEntry(e,t,i,e.text,e.replyMarkup,s,n),this.isCurrent(e.bridge.id,n))}const r={bridgeId:e.bridge.id,lastText:e.text,lastActionsFingerprint:s,lastUpdateAt:Date.now()};return r.pending=qc({fetchImpl:this.fetchImpl,bridge:e.bridge,runtime:t,chatId:e.chatId,text:e.text,replyMarkup:e.replyMarkup,sessionWebhook:t.chatWebhooks.get(e.chatId)||wl(e.bridge.settings.sessionWebhook),senderId:t.senderIds.get(e.chatId)||wl(e.bridge.settings.senderId),title:"TaskHandoff 执行中",step:"progress",forceCard:!0}).then(t=>{this.isCurrent(e.bridge.id,n)&&(t?.outTrackId&&(r.outTrackId=t.outTrackId),t?.delivered&&(r.delivered=!0,r.lastUpdateAt=Date.now()))}).catch(t=>{throw this.isCurrent(e.bridge.id,n)&&this.entries.delete(e.key),t}).finally(()=>{r.pending=void 0}),this.entries.set(e.key,r),await r.pending,this.isCurrent(e.bridge.id,n)&&Boolean(r.delivered)}async updateExistingEntry(e,t,n,s,i,r,o){n.outTrackId&&(await async function(e){await Lc(e.fetchImpl,e.bridge,e.runtime,"PUT","/v1.0/card/instances",{outTrackId:e.outTrackId,cardData:{cardParamMap:xc({type:"actions",title:e.title,description:e.text,list:Rd(e.replyMarkup),biz_step:e.step,error_msg:""})},cardUpdateOptions:{updateCardDataByKey:!0,updatePrivateDataByKey:!1},userIdType:Number(e.bridge.settings.cardUserIdType||1)})}({fetchImpl:this.fetchImpl,bridge:e.bridge,runtime:t,outTrackId:n.outTrackId,text:s,replyMarkup:i,title:"TaskHandoff 执行中",step:"progress"}),this.isCurrent(e.bridge.id,o)&&(n.lastText=s,n.lastActionsFingerprint=r,n.lastUpdateAt=Date.now()))}}function wl(e){return"string"==typeof e?e:""}function Sl(e){const t=new f.DWClient({clientId:e.clientId,clientSecret:e.clientSecret,ua:"task-handoff-control-plane",keepAlive:!1,autoReconnect:!1});let n,s=!1;return{async connect(){s=!1,await t.getEndpoint(),await t._connect();const e=t.socket;e?.once("close",()=>{s||n?.(new Error("DingDing stream connection closed."))})},disconnect(){s=!0,t.disconnect()},onDisconnect(e){n=e},getConfig:()=>t.getConfig(),registerCallbackListener(e,n){t.registerCallbackListener(e,n)},socketCallBackResponse(e,n){t.socketCallBackResponse(e,n)}}}class Al{runtimes=new Map;connected=new Set;reconnectTimers=new Map;progress;options;createClient;constructor(e){this.options=e,this.createClient=e.createClient||Sl,this.progress=new vl(e.fetchImpl)}has(e){return this.runtimes.has(e)}isRunning(e){return this.connected.has(e)}get(e){return this.runtimes.get(e)}ids(){return this.runtimes.keys()}start(e){const t=(n=e.settings?.clientSecret,"string"==typeof n?n:"");var n;if(!e.token||!t)return this.options.onError(e.id,"DingDing client id/secret is not configured."),!1;const s={client:this.createClient({clientId:e.token,clientSecret:t}),chatWebhooks:new Map,senderIds:new Map,conversationTypes:new Map,onLog:(t,n,s)=>{this.options.logger["warn"===t?"warn":"info"]({bridgeId:e.id,...n},s)}};return s.client.onDisconnect?.(t=>{this.runtimes.get(e.id)===s&&this.handleConnectionFailure(e,s,t)}),s.client.registerCallbackListener(f.TOPIC_ROBOT,t=>{this.options.onRobotMessage(e,s,t).catch(t=>{this.options.onError(e.id,t)})}),s.client.registerCallbackListener(f.TOPIC_CARD,t=>{const n=t;this.options.onCardCallback(e,s,n).then(e=>s.client.socketCallBackResponse(n.headers.messageId,e||{})).catch(t=>{this.options.onError(e.id,t),s.client.socketCallBackResponse(n.headers.messageId,{})})}),this.options.clearError(e.id),this.runtimes.set(e.id,s),this.connect(e,s),!0}connect(e,t){this.reconnectTimers.delete(e.id),this.connected.add(e.id),t.client.connect().then(()=>{this.runtimes.get(e.id)===t&&(this.connected.add(e.id),this.options.clearError(e.id))}).catch(n=>{this.runtimes.get(e.id)===t&&this.handleConnectionFailure(e,t,n)})}handleConnectionFailure(e,t,n){if(this.connected.delete(e.id),this.progress.clearBridge(e.id),this.options.onError(e.id,n||"DingDing stream connection failed."),this.reconnectTimers.has(e.id))return;const s=setTimeout(()=>{this.runtimes.get(e.id)===t&&this.connect(e,t)},this.options.reconnectDelayMs??1e3);s.unref?.(),this.reconnectTimers.set(e.id,s)}stop(e){const t=this.reconnectTimers.get(e);t&&clearTimeout(t),this.reconnectTimers.delete(e),this.connected.delete(e);const n=this.runtimes.get(e);if(n){try{n.client.disconnect()}catch{}this.runtimes.delete(e)}this.progress.clearBridge(e)}stopAll(){for(const e of[...this.runtimes.keys()])this.stop(e);this.progress.clear()}applyUpdate(e){const t=this.runtimes.get(e.bridge.id);return t?this.progress.applyUpdate(e,t):Promise.resolve(!1)}applyProgressUpdate(e){return this.applyUpdate(e)}}class kl{entries=new Map;generations=new Map;updateIntervalMs;constructor(e=1e3){this.updateIntervalMs=e}clear(){for(const e of new Set([...this.generations.keys(),...[...this.entries.values()].map(e=>e.bridgeId)]))this.clearBridge(e)}clearBridge(e){this.generations.set(e,this.generation(e)+1);for(const[t,n]of this.entries)n.bridgeId===e&&(n.timer&&clearTimeout(n.timer),n.cancelPending?.(new Error("Lark progress update was cancelled.")),this.entries.delete(t))}generation(e){return this.generations.get(e)||0}isCurrent(e,t){return this.generation(e)===t}async applyUpdate(e,t){const n=this.generation(e.bridge.id),s=Xc(e.replyMarkup);let i=this.entries.get(e.key);if(i?.pending&&await i.pending,!this.isCurrent(e.bridge.id,n))return!1;if(i=this.entries.get(e.key),i?.messageId){if(i.lastText===e.text&&i.lastActionsFingerprint===s)return!0;const r=Date.now()-i.lastUpdateAt;return r<this.updateIntervalMs?(i.pendingText=e.text,i.pendingReplyMarkup=e.replyMarkup,i.timer||(i.pending=new Promise((s,o)=>{i.cancelPending=o,i.timer=setTimeout(()=>{i.timer=void 0,i.cancelPending=void 0;const r=i.pendingText,a=i.pendingReplyMarkup;if(i.pendingText=void 0,i.pendingReplyMarkup=void 0,!r)return s(void 0);this.updateExistingEntry(e,t,i,r,a,Xc(a),n).then(s,o)},this.updateIntervalMs-r)}).finally(()=>{i.pending=void 0,i.timer=void 0,i.cancelPending=void 0})),await i.pending,this.isCurrent(e.bridge.id,n)&&this.entries.has(e.key)):(await this.updateExistingEntry(e,t,i,e.text,e.replyMarkup,s,n),this.isCurrent(e.bridge.id,n))}const r={bridgeId:e.bridge.id,lastText:e.text,lastActionsFingerprint:s,lastUpdateAt:Date.now()};return r.pending=t.channel.send(e.chatId,{card:Qc(e.text,e.replyMarkup)}).then(t=>{this.isCurrent(e.bridge.id,n)&&(r.messageId=t.messageId,r.delivered=!0,r.lastUpdateAt=Date.now())}).catch(t=>{throw this.isCurrent(e.bridge.id,n)&&this.entries.delete(e.key),t}).finally(()=>{r.pending=void 0}),this.entries.set(e.key,r),await r.pending,this.isCurrent(e.bridge.id,n)&&Boolean(r.delivered)}async updateExistingEntry(e,t,n,s,i,r,o){n.messageId&&(await t.channel.updateCard(n.messageId,Qc(s,i)),this.isCurrent(e.bridge.id,o)&&(n.lastText=s,n.lastActionsFingerprint=r,n.lastUpdateAt=Date.now()))}}function zl(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 Tl{runtimes=new Map;connected=new Set;unsubscribe=new Map;reconnectTimers=new Map;options;createChannel;progress;constructor(e){this.options=e,this.createChannel=e.createChannel||zl,this.progress=new kl(e.progressUpdateIntervalMs)}has(e){return this.runtimes.has(e)}isRunning(e){return this.connected.has(e)}get(e){return this.runtimes.get(e)}ids(){return this.runtimes.keys()}start(e){const t=(n=e.settings?.appSecret,"string"==typeof n?n.trim():"");var n;if(!e.token||!t)return this.options.onError(e.id,"Lark app id/secret is not configured."),!1;const s={channel:this.createChannel({appId:e.token,appSecret:t,domain:Cl(e.settings?.domain)})},i=s.channel.on({message:t=>{this.options.onMessage(e,s,t).catch(t=>{this.options.onError(e.id,t)})},cardAction:t=>{this.options.onCardAction(e,s,t).catch(t=>{this.options.onError(e.id,t)})},error:t=>{this.options.onError(e.id,t),this.options.logger.warn({bridgeId:e.id,error:t.message},"lark channel error")},reconnecting:()=>{this.connected.delete(e.id),this.options.onError(e.id,"Lark WebSocket is reconnecting."),this.options.logger.info({bridgeId:e.id},"lark channel reconnecting")},reconnected:()=>{this.runtimes.get(e.id)===s&&(this.connected.add(e.id),this.options.clearError(e.id),this.options.logger.info({bridgeId:e.id},"lark channel reconnected"))}});return this.options.clearError(e.id),this.runtimes.set(e.id,s),this.unsubscribe.set(e.id,i),this.connect(e,s),!0}connect(e,t){this.reconnectTimers.delete(e.id),t.channel.connect().then(()=>{this.runtimes.get(e.id)===t&&(this.connected.add(e.id),this.options.clearError(e.id),this.options.logger.info({bridgeId:e.id},"lark channel connected"))}).catch(n=>{if(this.runtimes.get(e.id)!==t)return;if(this.connected.delete(e.id),this.options.onError(e.id,n),t.channel.rawWsClient||this.reconnectTimers.has(e.id))return;const s=setTimeout(()=>{this.runtimes.get(e.id)===t&&this.connect(e,t)},this.options.reconnectDelayMs??1e3);s.unref?.(),this.reconnectTimers.set(e.id,s)})}stop(e){const t=this.reconnectTimers.get(e);t&&clearTimeout(t),this.reconnectTimers.delete(e),this.unsubscribe.get(e)?.(),this.unsubscribe.delete(e),this.connected.delete(e);const n=this.runtimes.get(e);if(this.runtimes.delete(e),this.progress.clearBridge(e),n){try{n.channel.rawWsClient?.close({force:!0})}catch{}n.channel.disconnect().catch(()=>{})}}stopAll(){for(const e of[...this.runtimes.keys()])this.stop(e);this.progress.clear()}applyUpdate(e){const t=this.runtimes.get(e.bridge.id);return t?this.progress.applyUpdate(e,t):Promise.resolve(!1)}applyProgressUpdate(e){return this.applyUpdate(e)}}function Cl(e){return"lark"===String(e||"").trim().toLowerCase()?I.Domain.Lark:I.Domain.Feishu}class xl{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 El{aggregates=new Map;endTokens=new Map;options;delayMs;constructor(e){this.options=e,this.delayMs=e.delayMs??1e3}async handleIncoming(e,t,n,s,i=[],r={},o={}){const a=s.trim(),d=a.split(/\s+/,1)[0]?.toLowerCase()||"",c=Nl(e.id,t,n),l=this.aggregates.get(c);return o.autoBegin&&!l?(this.start(c,e,t,n,r),this.enqueue(c,e,t,n,s,i,r,!0),void await this.sendCollectionStarted(e,t,c,r.sourceMessageId,"Image received. Continue sending messages, then send /end when done.")):"/begin"===d?(this.start(c,e,t,n,r),void await this.sendCollectionStarted(e,t,c,r.sourceMessageId,"Started collecting messages. Send /end when done.")):void("/end"!==d?l?.explicit?this.enqueue(c,e,t,n,s,i,r,!0):a.startsWith("/")?await this.options.dispatch(e,t,n,s,i,r):this.enqueue(c,e,t,n,s,i,r,!1):await this.flush(c,"manual"))}async handleEndCallback(e,t,n,s,i){const r=this.endTokens.get(s)||"";if(r!==Nl(e.id,t,i))return void await this.options.answerCallback(e,n,"This collection is not active here");const o=await this.flush(r,"callback");await this.options.answerCallback(e,n,o?"Collected message sent":"No messages collected")}stop(){for(const e of this.aggregates.values())e.timer&&clearTimeout(e.timer);this.aggregates.clear(),this.endTokens.clear()}stopBridge(e){for(const[t,n]of this.aggregates)n.bridgeId===e&&(n.timer&&clearTimeout(n.timer),this.aggregates.delete(t));for(const[t,n]of this.endTokens)n.startsWith(`${e}:`)&&this.endTokens.delete(t)}start(e,t,n,s,i){const r=this.aggregates.get(e);r?.timer&&clearTimeout(r.timer),this.aggregates.set(e,{bridgeId:t.id,chatId:n,userId:s,texts:[],attachments:[],context:i,explicit:!0})}enqueue(e,t,n,s,i,r,o,a){const d=this.aggregates.get(e);d?.timer&&clearTimeout(d.timer);const c=d||{bridgeId:t.id,chatId:n,userId:s,texts:[],attachments:[],context:o,explicit:a};var l,p;c.bridgeId=t.id,c.chatId=n,c.userId=s,c.context=(l=c.context,p=o,{sourceMessageId:l?.sourceMessageId??p.sourceMessageId,replyToMessageId:l?.replyToMessageId??p.replyToMessageId,quoteText:l?.quoteText||p.quoteText}),c.explicit=c.explicit||a,i.trim()&&c.texts.push(i),c.attachments.push(...r),c.timer=c.explicit?void 0:setTimeout(()=>{this.flush(e,"timer").catch(e=>this.options.onError?.(c.bridgeId,e))},this.delayMs),this.aggregates.set(e,c)}async flush(e,t){const n=this.aggregates.get(e);if(!n)return!1;n.timer&&clearTimeout(n.timer),this.aggregates.delete(e);const s=this.options.requireBridge(n.bridgeId),i=n.texts.join("\n\n").trim();return i||n.attachments.length?(await this.options.dispatch(s,n.chatId,n.userId,i,n.attachments,n.context||{}),!0):("timer"!==t&&await this.options.send(s,n.chatId,"No messages collected.",{replyToMessageId:n.context?.sourceMessageId}),!1)}sendCollectionStarted(e,t,n,s,i){return this.options.send(e,t,i,{replyToMessageId:s,replyMarkup:Nd([[{text:"/end",callbackData:this.endCallbackData(n)}]])})}endCallbackData(e){const t=a.createHash("sha256").update(e).digest("base64url").slice(0,16);return this.endTokens.set(t,e),`task_handoff:cp_msg_end:${t}`}}function Nl(e,t,n){return[e,t,n||""].join(":")}class _l{cancelTokens=new Map;queueActionTokens=new Map;options;constructor(e){this.options=e}cancelCallbackData(e,t){this.pruneExpired();const n=Rl([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=Pl(e,"task_handoff:cp_ai_cancel:");if(void 0!==n){const e=this.cancelTokens.get(n)?.value;return e?(await this.cancel(t,e.instanceId,e.sessionId),!0):this.expired(t)}const s=Pl(e,"task_handoff:cp_ai_steer:");if(void 0!==s){const e=this.queueActionTokens.get(s)?.value;return e&&"steer"===e.type?(await this.steer(t,e),!0):this.expired(t)}const i=Pl(e,"task_handoff:cp_ai_qdel_menu:");if(void 0!==i){const e=this.queueActionTokens.get(i)?.value;return e&&"delete-menu"===e.type?(await this.deleteMenu(t,e),!0):this.expired(t)}const r=Pl(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=jl(await this.options.queue(t.instanceId,t.sessionId)),s=(Array.isArray(n.items)?n.items:[]).map(jl).filter(e=>"queued"===Ml(e.status)&&Ml(e.id));if(!s.length)return void await this.answer(e,"Queue is empty");const i=s.slice(0,5).map((e,n)=>[{text:Ol(Ml(e.message),n),callbackData:this.queueDeleteItemCallbackData(t.instanceId,t.sessionId,Ml(e.id))}]);await this.send(e,"Delete queued message",{replyMarkup:Nd(i)}),await this.answer(e,"Select a queued message"),this.options.info(this.logData(e,t,{itemCount:s.length}),"chat ai session queue delete menu sent")}catch(t){await this.fail(e,t,"Queue menu failed")}}async deleteItem(e,t){if(await this.requireAllowed(e,t.instanceId,t.sessionId))try{await this.options.remove(t.instanceId,t.sessionId,t.queueId),await this.answer(e,"Queued message deleted"),(e.deleteMessage||Number.isInteger(e.messageId))&&await this.deleteMessage(e).catch(n=>{this.options.warn(this.logData(e,t,{messageId:e.messageId,error:Dl(n)}),"chat ai session queue delete menu message delete failed")}),this.options.info(this.logData(e,t),"chat ai session queued message deleted")}catch(t){await this.fail(e,t,"Delete failed")}}async run(e,t){try{await t.operation(),await this.answer(e,t.successText),this.options.info(this.logData(e,t),t.logMessage)}catch(n){await this.fail(e,n,t.failurePrefix)}}async requireAllowed(e,t,n){return!!(e.actionAllowed?e.actionAllowed(t,n):this.options.actionAllowed(e.bridge,e.chatId,t,n,Number.isInteger(e.messageId)?e.messageId:void 0))||(await this.answer(e,"This chat is not bound to that AI session"),!1)}async fail(e,t,n){const s=Dl(t);this.options.setBridgeError(e.bridge.id,s),await this.answer(e,`${n}: ${function(e){const t=e.replace(/\s+/g," ").trim();return t.length<=120?t:`${t.slice(0,Math.max(0,119))}…`}(s)}`)}async expired(e){return await this.answer(e,"This AI session action expired"),!0}answer(e,t){return e.answer?e.answer(t):this.options.answer(e.bridge,e.callbackQueryId,t)}send(e,t,n){return e.send?e.send(t,n):this.options.send(e.bridge,e.chatId,t,n)}deleteMessage(e){return e.deleteMessage?e.deleteMessage():Number.isInteger(e.messageId)?this.options.deleteMessage(e.bridge,e.chatId,e.messageId):Promise.resolve(void 0)}queueDeleteItemCallbackData(e,t,n){return`task_handoff:cp_ai_qdel:${this.queueActionToken({type:"delete-item",instanceId:e,sessionId:t,queueId:n})}`}queueActionToken(e){this.pruneExpired();const t=Rl([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 Pl(e,t){if(!e.startsWith(t))return;const n=e.slice(t.length);return n&&!n.includes(":")?n:void 0}function Rl(e){return a.createHash("sha256").update(e.join("\0")).digest("base64url").slice(0,16)}function Ol(e,t){const n=`${t+1}. `,s=Ml(e).replace(/\s+/g," ").trim()||"Queued message",i=Math.max(8,48-n.length),r=Array.from(s);return`${n}${r.length>i?`${r.slice(0,Math.max(1,i-3)).join("")}...`:s}`}function jl(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Ml(e){return"string"==typeof e?e.trim():""}function Dl(e){return e instanceof Error?e.message:String(e)}class ql{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=Ll(t,this.options.callbackData),n=t.aiSessionId?this.options.listBindings().filter(e=>e.activeInstanceId===t.instanceId&&e.activeAiSessionId===t.aiSessionId):[];(await this.sendToBindings(n,e)||await this.sendToDefaults(e))&&this.announced.add(t.id)}}async sendToBindings(e,t){let n=!1;for(const s of e){if(!s.bridgeId)continue;const e=this.options.requireBridge(s.bridgeId);if(!e.enabled)continue;const i=await this.send(e,s.chatSessionId,t);n||=i}return n}async sendToDefaults(e){let t=!1;for(const n of this.options.listBridges()){if(!n.enabled||!n.defaultChatId)continue;let s=!1;await this.options.send(n,n.defaultChatId,e).catch(e=>(this.options.setBridgeError(n.id,$l(e)),s=!0,!1))?t=!0:s||this.options.setBridgeError(n.id,"Chat bridge message was not delivered.")}return t}async send(e,t,n){return this.options.send(e,t,n).then(Boolean).catch(t=>(this.options.setBridgeError(e.id,$l(t)),!1))}}function Ll(e,t){const n=`${e.project?.name||e.projectId} / ${e.instance?.name||e.instanceId}`,s="approval"===e.kind?`/approve ${e.id}\n/deny ${e.id}\n/skip ${e.id}`:`/reply ${e.id} <message>`,i=`[${n}]\n${e.result}\n\n${s}`;return"approval"!==e.kind?{text:i}:{text:i,replyMarkup:Nd([[{text:"Allow",callbackData:t(e.id,"allow")},{text:"Skip",callbackData:t(e.id,"skip")},{text:"Deny",callbackData:t(e.id,"deny")}]])}}function $l(e){return e instanceof Error?e.message:String(e)}function Bl(){return e=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(e||"").trim().toLowerCase());var e}class Ul{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||Bl,this.aiSessionInstanceNamesCache=new xl(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 xl(1e3,()=>this.service.listPendingRoutes().catch(()=>[])),this.telegramMessageAggregator=new El({requireBridge:e=>this.service.requireChatBridge(e),send:(e,t,n,s={})=>this.sendTelegramMessage(e,t,n,s),answerCallback:(e,t,n)=>this.answerTelegramCallback(e,t,n),dispatch:(e,t,n,s,i,r)=>this.dispatchTelegramGatewayMessage(e,t,n,s,i,r),onError:(e,t)=>this.bridgeErrors.set(e,Yl(t))}),this.telegramAiSessionCallbacks=new _l({interrupt:(e,t)=>this.service.interruptAiSession(e,t),queue:(e,t)=>this.service.aiSessionQueue(e,t),steer:(e,t,n)=>this.service.steerAiSessionQueuedMessage(e,t,n),remove:(e,t,n)=>this.service.removeAiSessionQueuedMessage(e,t,n),actionAllowed:(e,t,n,s,i)=>this.telegramAiSessionActionAllowed(e,t,n,s,i),answer:(e,t,n)=>this.answerTelegramCallback(e,t,n),send:(e,t,n,s={})=>this.sendTelegramMessage(e,t,n,s),deleteMessage:(e,t,n)=>this.deleteTelegramMessage(e,t,n),setBridgeError:(e,t)=>this.bridgeErrors.set(e,t),info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)}),this.pendingRouteNotifier=new ql({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 cl({updateIntervalMs:n.telegramProgressUpdateIntervalMs,requireBridge:e=>this.service.requireChatBridge(e),send:(e,t,n,s={})=>this.sendTelegramMessage(e,t,n,s),edit:(e,t,n,s,i={})=>this.editTelegramMessage(e,t,n,s,i),deleteMessage:(e,t,n)=>this.deleteTelegramMessage(e,t,n),onLog:e=>this.logWarn({message:e},"telegram progress store warning")}),this.dingdingBridges=new Al({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,Yl(t)),clearError:e=>this.bridgeErrors.delete(e)}),this.larkBridges=new Tl({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,Yl(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:Yl(t)},"chat ai session snapshot delivery failed")})})}logInfo(e,t){this.diagnosticLogsEnabled()&&this.logger?.info?.({component:"control-plane-chat-gateway",...e},t)}logWarn(e,t){this.diagnosticLogsEnabled()&&this.logger?.warn?.({component:"control-plane-chat-gateway",...e},t)}updateChatBridge(e,t){this.service.updateChatBridge?.(e,t)}startEnabled(){this.logAiSessionDelivery({stage:"runtime-start-enabled",bridgeCount:this.service.listChatBridges().length,enabledBridgeCount:this.service.listChatBridges().filter(e=>e.enabled).length});for(const e of this.service.listChatBridges())e.enabled&&this.startBridge(e.id)}startBridge(e){if(this.bridgeTimers.has(e)||this.dingdingBridges.has(e)||this.larkBridges.has(e))return this.logAiSessionDelivery({stage:"bridge-start-skipped-running",bridgeId:e}),this.status();const t=this.service.requireChatBridge(e);return this.logAiSessionDelivery({stage:"bridge-start",bridgeId:t.id,channel:t.channel,enabled:t.enabled,hasToken:Boolean(t.token)}),"wechat"===t.channel?this.startPollingBridge(t,(e,t)=>this.pollWechat(e,t)):"dingding"===t.channel?this.startDingdingBridge(t):"lark"===t.channel?this.startLarkBridge(t):"telegram"!==t.channel?(this.bridgeErrors.set(e,`${t.channel} bridge is not supported in the control plane.`),this.status()):t.token?this.startPollingBridge(t,(e,t)=>this.pollTelegram(e,t)):(this.bridgeErrors.set(e,"Telegram token is not configured."),this.status())}stopBridge(e){this.advanceBridgePollingGeneration(e);const t=`:${e}:`;for(const e of this.deliveredAiSessionFingerprints.keys())e.includes(t)&&this.deliveredAiSessionFingerprints.delete(e);const n=this.bridgeTimers.get(e);return n&&(clearInterval(n),this.bridgeTimers.delete(e)),this.dingdingBridges.stop(e),this.larkBridges.stop(e),this.telegramMessageAggregator.stopBridge(e),this.status()}stopAll(){const e=new Set([...this.service.listChatBridges().map(e=>e.id),...this.bridgePollingGenerations.keys(),...this.bridgeTimers.keys(),...this.bridgePolls.keys(),...this.dingdingBridges.ids(),...this.larkBridges.ids()]);for(const t of e)this.stopBridge(t);this.dingdingBridges.stopAll(),this.larkBridges.stopAll(),this.telegramMessageAggregator.stop(),this.telegramAiSessionCallbacks.clear(),this.stopAiSessionListener?.(),this.stopAiSessionListener=void 0}async pollBridgeNow(e){const t=this.service.requireChatBridge(e),n=this.bridgePollingGeneration(e);return"telegram"===t.channel?(await this.runBridgePoll(t,n,(e,t)=>this.pollTelegram(e,t)),this.status()):"wechat"===t.channel?(await this.runBridgePoll(t,n,(e,t)=>this.pollWechat(e,t)),this.status()):("dingding"===t.channel||"lark"===t.channel||this.bridgeErrors.set(e,`${t.channel} bridge is not supported in the control plane.`),this.status())}async pollAiSessionsNow(){return await this.pollAiSessionUpdates(),this.status()}status(){const e=this.service.listChatBridges().map(e=>({id:e.id,channel:e.channel,name:e.name,running:this.bridgeTimers.has(e.id)||this.dingdingBridges.isRunning(e.id)||this.larkBridges.isRunning(e.id),tokenSet:Boolean(e.tokenSet),defaultChatId:e.defaultChatId,lastUpdateId:this.telegramOffsets.get(e.id),error:this.bridgeErrors.get(e.id)}));return{running:e.some(e=>e.running),bridges:e}}startPollingBridge(e,t){if(!e.token)return this.bridgeErrors.set(e.id,`${e.channel} token is not configured.`),this.status();this.bridgeErrors.delete(e.id);const n=this.advanceBridgePollingGeneration(e.id),s=()=>this.bridgePollingGeneration(e.id)===n,i=i=>{s()&&this.runBridgePoll(i,n,t).catch(t=>{s()&&this.bridgeErrors.set(e.id,t instanceof Error?t.message:String(t))})},r=setInterval(()=>{if(!s())return;const t=this.service.requireChatBridge(e.id);t.enabled?i(t):this.stopBridge(e.id)},e.pollIntervalMs);if(this.bridgeTimers.set(e.id,r),this.logAiSessionDelivery({stage:"bridge-poll-started",bridgeId:e.id,channel:e.channel,intervalMs:e.pollIntervalMs}),e.enabled){const t=this.service.requireChatBridge(e.id);i(t)}return this.status()}runBridgePoll(e,t,n){const s=this.bridgePolls.get(e.id);if(s?.generation===t)return s.promise;const i=(async()=>{const s=()=>this.bridgePollingGeneration(e.id)===t;s()&&await n(e,s)})();this.bridgePolls.set(e.id,{generation:t,promise:i});const r=()=>{this.bridgePolls.get(e.id)?.promise===i&&this.bridgePolls.delete(e.id)};return i.then(r,r),i}bridgePollingGeneration(e){return this.bridgePollingGenerations.get(e)||0}advanceBridgePollingGeneration(e){const t=this.bridgePollingGeneration(e)+1;return this.bridgePollingGenerations.set(e,t),t}startDingdingBridge(e){return this.dingdingBridges.start(e),this.status()}startLarkBridge(e){return this.larkBridges.start(e),this.status()}async handleLarkMessage(e,t,n){const s=this.larkAllowed(e,n.senderId),i=String(n.content||"").trim();if(!s||!i)return void this.logWarn({bridgeId:e.id,chatId:n.chatId,senderId:n.senderId,allowed:s,hasText:Boolean(i)},"lark message ignored");let r;e.defaultChatId||this.updateChatBridge(e.id,{defaultChatId:n.chatId}),this.logInfo({bridgeId:e.id,chatId:n.chatId,senderId:n.senderId,chatType:n.chatType,messageId:n.messageId,textPreview:Zl(i)},"lark chat gateway message received");try{r=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"lark",bridgeId:e.id,chatSessionId:n.chatId,userId:n.senderId},message:{text:i,attachments:[]}})}catch(e){return void await t.channel.send(n.chatId,{markdown:`Failed to handle message: ${Yl(e)}`})}const o=Fl(r);if(!o)return;const a=Wl(r);if(await this.sendLarkRoutedAiSessionProgress(r,e,n.chatId,o,a))return;const d=bl({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===np(r).routed,replyPreview:Zl(o)},"lark chat gateway reply sent")}async sendLarkRoutedAiSessionProgress(e,t,n,s,i){if(!0!==e.routed)return!1;const r=rp(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=pp(o,a,d,t.id,n);return!!await this.larkBridges.applyProgressUpdate({bridge:t,key:c,chatId:n,text:s,replyMarkup:i})&&(this.deliveredAiSessionFingerprints.delete(c),this.logInfo({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,key:c,textPreview:Zl(s)},"lark ai session progress message started"),!0)}async handleLarkCardAction(e,t,n){const s=n.operator.openId||n.operator.userId;if(!this.larkAllowed(e,s))return void this.logWarn({bridgeId:e.id,chatId:n.chatId,messageId:n.messageId,userId:s},"lark card action ignored");const i=Yc(n.action.value),r=(e,s)=>t.channel.updateCard(n.messageId,Qc(e||"Updated",s));if(!i)return void await r("Unsupported action");if(await this.telegramAiSessionCallbacks.tryHandle(i,{bridge:e,chatId:n.chatId,callbackQueryId:n.messageId,userId:s,messageId:n.messageId,actionAllowed:(t,s)=>this.chatAiSessionBindingActive(e,n.chatId,t,s),answer:e=>r(e),send:(e,s)=>t.channel.send(n.chatId,{card:Qc(e,s?.replyMarkup)})}))return;let o;try{o=await this.parseChatGatewayCallbackAction(i)}catch(e){if(Xl(e,"CHAT_PENDING_ACTION_STALE"))return void await r(Yl(e));throw e}if(!o)return void await r("Unsupported action");const a=await this.service.handleChatGatewayAction({source:{channel:"lark",bridgeId:e.id,chatSessionId:n.chatId,userId:s},action:o});if("pending-decision"===o.type&&Hl(a))return void await r(`${o.decision} sent`);const d=Fl(a)||Ql(a.message)||"Updated";await r(d,Wl(a))}async handleDingdingRobotMessage(e,t,n){const s=function(e){const t=Vc(e),n=Gc(t.conversationId),s=Gc(Hc(t.text).content).trim();if(!n||!s)return;const i=Gc(t.senderStaffId||t.senderId);return{chatId:n,userId:i||void 0,senderId:i||void 0,sessionWebhook:Gc(t.sessionWebhook)||void 0,conversationType:Pc(t.conversationType,{robotMessage:!0}),text:s,raw:t}}(n.data);if(t.client.socketCallBackResponse(n.headers.messageId,{}),!s||!this.dingdingAllowed(e,s.senderId))return void this.logWarn({bridgeId:e.id,hasEvent:Boolean(s),senderId:s?.senderId,allowed:s?this.dingdingAllowed(e,s.senderId):void 0},"dingding robot message ignored");const{chatId:i,text:r,senderId:o,sessionWebhook:a}=s;a&&t.chatWebhooks.set(i,a),s.conversationType&&t.conversationTypes.set(i,s.conversationType);const d=a||t.chatWebhooks.get(i)||Ql(e.settings.sessionWebhook);let c;o&&t.senderIds.set(i,o),e.defaultChatId||this.updateChatBridge(e.id,{defaultChatId:i}),this.logInfo({bridgeId:e.id,chatId:i,senderId:o,conversationType:s.conversationType,hasSessionWebhook:Boolean(a),hasCachedSessionWebhook:Boolean(t.chatWebhooks.get(i)),hasResolvedSessionWebhook:Boolean(d),textPreview:Zl(r)},"dingding chat gateway message received");try{c=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"dingding",bridgeId:e.id,chatSessionId:i,userId:o||void 0},message:{text:r,attachments:[]}})}catch(e){if(d)return void await Dc(this.fetchImpl,d,`Failed to handle message: ${Yl(e)}`,t.onLog);throw e}const l=Fl(c);if(l){const n=Wl(c);if(await this.sendDingdingRoutedAiSessionProgress(c,e,t,i,l,{replyMarkup:n,sessionWebhook:d,senderId:o,sourcePrompt:r}))return;const s=bl({fetchImpl:this.fetchImpl,bridge:e,dingdingRuntime:t}),a=await s.send(i,l,{replyMarkup:n,sessionWebhook:d,senderId:o});if(a)return void this.logInfo({bridgeId:e.id,chatId:i,senderId:o,provider:a.provider,interactionId:a.interactionId,routed:!0===np(c).routed,hasReplyMarkup:Boolean(n),replyPreview:Zl(l)},"dingding chat gateway reply sent");this.logWarn({bridgeId:e.id,chatId:i,senderId:o,hasReplyMarkup:Boolean(n),hasSessionWebhook:Boolean(d),hasRobotCode:Boolean(Ql(e.settings.robotCode)),replyPreview:Zl(l)},"dingding chat gateway reply skipped")}}async sendDingdingRoutedAiSessionProgress(e,t,n,s,i,r={}){if(!0!==e.routed)return!1;const o=rp(e),{instanceId:a,sessionId:d,turnId:c}=o;if(!a||!d||!c)return this.logWarn({bridgeId:t.id,chatId:s,instanceId:a,sessionId:d,turnId:c,turnIdSources:o.sources,routed:e.routed},"dingding ai session progress card not started"),!1;const l=pp(a,d,c,t.id,s);return!!await this.dingdingBridges.applyProgressUpdate({bridge:t,key:l,chatId:s,text:i,replyMarkup:r.replyMarkup})&&(this.deliveredAiSessionFingerprints.delete(l),this.logInfo({bridgeId:t.id,chatId:s,instanceId:a,sessionId:d,turnId:c,key:l,hasSessionWebhook:Boolean(r.sessionWebhook),hasSenderId:Boolean(r.senderId),sourcePrompt:Zl(r.sourcePrompt,80),textPreview:Zl(i)},"dingding ai session progress card started"),!0)}async handleDingdingCardCallback(e,t,n){const s=function(e){const t=Vc(e),n=Wc(t.cardActionData||t.content),s=Wc(n.cardPrivateData||t.cardPrivateData||t.content),i=Wc(s.params||n.params||t.params),r=Gc(t.userId),o=Gc(i.biz_sender_id);return{userId:r||void 0,chatId:_c(t,i),senderId:r||void 0,deliverySenderId:o||void 0,sessionWebhook:Gc(i.biz_session_webhook)||void 0,conversationType:Pc(i.biz_conversation_type||t.conversationType||t.conversation_type),callbackData:Rc(jc(t,n,s)),body:t,params:i}}(n.data);if(!this.dingdingAllowed(e,s.userId))return Oc("not authorized",void 0,"unauthorized",s.body,s.params);const i=s.chatId||Ql(e.defaultChatId),r=s.deliverySenderId||s.senderId,o=s.sessionWebhook;let a;i&&o&&t.chatWebhooks.set(i,o),i&&s.conversationType&&t.conversationTypes.set(i,s.conversationType),i&&r&&t.senderIds.set(i,r);try{a=await this.parseChatGatewayCallbackAction(s.callbackData)}catch(e){if(Xl(e,"CHAT_PENDING_ACTION_STALE"))return Oc(Yl(e),void 0,"approval_stale",s.body,s.params);throw e}if(!a)return this.logWarn({bridgeId:e.id,chatId:i,userId:s.userId,senderId:r,...ep(s)},"dingding card callback action unsupported"),Oc("Unsupported action",void 0,"unsupported",s.body,s.params);this.logInfo({bridgeId:e.id,chatId:i,userId:s.userId,senderId:r,actionType:a.type,...ep(s)},"dingding card callback action parsed");const d=await this.service.handleChatGatewayAction({source:{channel:"dingding",bridgeId:e.id,chatSessionId:i,userId:s.userId||void 0},action:a});return"pending-decision"===a.type&&Hl(d)?Oc(`${a.decision} sent`,void 0,"approval_done",s.body,s.params):Oc(Fl(d)||Ql(d.message)||"updated",Wl(d),"updated",s.body,s.params)}async pollWechat(e,t=()=>!0){if(!e.token)return;const n=e.settings||{},s=this.wechatCursors.get(e.id)||Ql(n.updatesBuf),i=await async function(e){const t=Il((e.bridge.settings||{}).baseUrl)||"https://ilinkai.weixin.qq.com",n=await e.fetchImpl(`${t}/ilink/bot/getupdates`,{method:"POST",headers:{"content-type":"application/json",AuthorizationType:"ilink_bot_token",Authorization:`Bearer ${e.bridge.token}`,"X-WECHAT-UIN":String(Math.floor(Math.random()*2**31))},body:JSON.stringify({get_updates_buf:e.cursor,base_info:{channel_version:"1.0.2"}})}),s=await n.json().catch(()=>({}));if(!n.ok)throw new Error(`HTTP ${n.status}`);const i=Number(s.errcode??s.ret??0);if(0!==i)throw new Error(Il(s.errmsg||s.msg)||`chat bridge API returned ${i}`);const r=[];for(const e of Array.isArray(s.msgs)?s.msgs:[]){const t=fl(e);if(1!==t.message_type)continue;const n=Il(t.from_user_id),s=yl(t);n&&s&&r.push({chatId:n,text:s,contextToken:Il(t.context_token)})}return{cursor:Il(s.get_updates_buf),messages:r}}({fetchImpl:this.fetchImpl,bridge:e,cursor:s});if(t()){i.cursor&&(this.wechatCursors.set(e.id,i.cursor),this.updateChatBridge(e.id,{settings:{updatesBuf:i.cursor}}));for(const s of i.messages){if(!t())return;const{chatId:i,contextToken:r,text:o}=s;if(e.defaultChatId||this.updateChatBridge(e.id,{defaultChatId:i,settings:{contextToken:r}}),e.defaultChatId&&e.defaultChatId!==i)continue;const a=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"wechat",bridgeId:e.id,chatSessionId:i},message:{text:o,attachments:[]}});if(!t())return;const d=Fl(a);if(d){const t=bl({fetchImpl:this.fetchImpl,bridge:e});await t.send(i,d,{contextToken:r||Ql(n.contextToken)})}}}}pollPendingRoutes(){return this.pendingRouteNotifier.poll()}async sendToChatBinding(e,t){if(!e.bridgeId)return!1;const n=this.service.requireChatBridge(e.bridgeId);if(!n.enabled)return!1;const s=await this.sendViaBridge(n,e.chatSessionId,t).catch(e=>{this.bridgeErrors.set(n.id,e instanceof Error?e.message:String(e))});return Boolean(s)}async sendViaBridge(e,t,n){const s="string"==typeof n?n:n.text,i="string"==typeof n?void 0:n.replyMarkup;return bl({fetchImpl:this.fetchImpl,bridge:e,dingdingRuntime:this.dingdingBridges.get(e.id),larkRuntime:this.larkBridges.get(e.id)}).send(t,s,{replyMarkup:i})}async pollTelegram(e,t=()=>!0){if(!e.token)return;const n=Number(e.settings?.telegramLastUpdateId),s=this.telegramOffsets.get(e.id)||(Number.isInteger(n)?n:void 0),i=await async function(e){const t=new URLSearchParams({timeout:"0",...e.offset?{offset:String(e.offset+1)}:{}}),n=await e.fetchImpl(`https://api.telegram.org/bot${e.bridge.token}/getUpdates?${t.toString()}`),s=await n.json().catch(()=>({}));if(!n.ok||!1===s.ok){if(409===n.status||/terminated by other getUpdates request/i.test(String(s.description||"")))return{updates:[],conflict:s.description||"Telegram getUpdates conflict: another bot instance is polling this token."};throw new Error(s.description||`Telegram getUpdates failed with HTTP ${n.status}`)}const i=[];for(const t of s.result||[]){const n=Number(t.update_id),s=Number.isInteger(n)?n:void 0,r=gl(t.callback_query);if(Object.keys(r).length>0){i.push({updateId:s,callbackQuery:r});continue}const o=gl(t.message||t.edited_message);if(0===Object.keys(o).length)continue;const a=gl(o.chat),d=gl(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=hl(o.text??o.caption),u=al(o);(p||0!==u.length)&&i.push({updateId:s,chatId:c,userId:l,text:p,rawText:p,message:o,messageId:ul(o),replyToMessageId:ul(gl(o.reply_to_message)),quoteText:hl(gl(o.quote).text),autoBegin:1===u.length&&!p.trim(),hasSingleImageWithoutText:1===u.length&&!p.trim()})}return{updates:i}}({fetchImpl:this.fetchImpl,bridge:e,offset:s});if(t())if(i.conflict)this.bridgeErrors.set(e.id,i.conflict);else for(const n of i.updates){if(!t())return;if(void 0!==n.updateId){const t=`${e.id}:${n.updateId}`;if(this.seenTelegramUpdates.has(t)||n.updateId<=(this.telegramOffsets.get(e.id)||0))continue;this.seenTelegramUpdates.add(t),this.telegramOffsets.set(e.id,n.updateId),this.updateChatBridge(e.id,{settings:{...e.settings,telegramLastUpdateId:n.updateId}})}if("callbackQuery"in n){const t=n.callbackQuery;await this.handleTelegramCallback(e,t).catch(async n=>{const s=np(t.message),i=np(s.chat),r=void 0!==i.id?String(i.id):e.defaultChatId;this.bridgeErrors.set(e.id,Yl(n)),r&&await this.sendTelegramMessage(e,r,`Action failed: ${Yl(n)}`).catch(t=>{this.bridgeErrors.set(e.id,Yl(t))})});continue}if(!this.telegramAllowed(e,n.userId))continue;const s=await ll({fetchImpl:this.fetchImpl,bridge:e,message:n.message,onImageDownloadError:({fileId:t,fileName:n,error:s})=>{this.logWarn({bridgeId:e.id,fileId:t,fileName:n,error:Yl(s)},"telegram image download skipped")}});if(!t())return;const i=n.rawText.trim();(i||s.length)&&(this.logInfo({bridgeId:e.id,chatId:n.chatId,messageId:n.messageId,replyToMessageId:n.replyToMessageId,hasQuote:Boolean(n.quoteText),textPreview:Zl(i)},"telegram chat gateway message received"),await this.telegramMessageAggregator.handleIncoming(e,n.chatId,n.userId,i,s,{sourceMessageId:n.messageId,replyToMessageId:n.replyToMessageId,quoteText:n.quoteText},{autoBegin:n.autoBegin}))}}async dispatchTelegramGatewayMessage(e,t,n,s,i=[],r={}){try{const o=void 0!==r.replyToMessageId?this.telegramReplyAiSessionTarget(e.id,t,r.replyToMessageId):void 0,a=function(e,t){const n=String(t||"").trim(),s=e.trim();return n?[`引用:${n}`,s].filter(Boolean).join("\n"):s}(s,r.quoteText),d=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"telegram",bridgeId:e.id,chatSessionId:t,userId:n},message:{text:a,attachments:i},...o?{target:{instanceId:o.instanceId,aiSessionId:o.sessionId}}:{}}),c=Fl(d),l=Wl(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(np(n).message_id)||void 0,routed:!0===np(d).routed,replyPreview:Zl(c)},"telegram chat gateway reply sent"),await this.rememberTelegramProgressMessage(d,e,t,n,c)}}catch(n){this.bridgeErrors.set(e.id,Yl(n)),await this.sendTelegramMessage(e,t,`Failed to handle message: ${Yl(n)}`,{replyToMessageId:r.sourceMessageId}).catch(t=>{this.bridgeErrors.set(e.id,Yl(t))})}}async handleTelegramCallback(e,t){const n=Ql(t.data),s=np(t.from),i=np(t.message),r=np(i.chat),o=void 0!==r.id?String(r.id):e.defaultChatId,a=void 0!==s.id?String(s.id):void 0;if(!o||!this.telegramAllowed(e,a))return;if(await this.telegramAiSessionCallbacks.tryHandle(n,{bridge:e,chatId:o,callbackQueryId:Ql(t.id),userId:a,messageId:Vl(i)}))return;const d=n.match(/^task_handoff:cp_msg_end:([^:]+)$/);if(d)return void await this.telegramMessageAggregator.handleEndCallback(e,o,Ql(t.id),d[1],a);let c;try{c=await this.parseChatGatewayCallbackAction(n)}catch(n){if(Xl(n,"CHAT_PENDING_ACTION_STALE")){await this.answerTelegramCallback(e,Ql(t.id),Yl(n));const s=Vl(i);return void(void 0!==s&&await this.deleteTelegramStandaloneApprovalMessage(e,o,s))}throw n}if(!c)return void await this.answerTelegramCallback(e,Ql(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&&Hl(l)){await this.answerTelegramCallback(e,Ql(t.id),"");const n=Vl(i);return void(void 0!==n&&await this.deleteTelegramStandaloneApprovalMessage(e,o,n))}await this.answerTelegramCallback(e,Ql(t.id),Ql(l.message)||"updated");const p=Fl(l),u=Wl(l),g=i.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(s=>s.messageId===n&&s.route?.bridgeId===e.id&&s.route?.chatId===t)||await this.deleteTelegramMessage(e,t,n).catch(s=>{this.logWarn({bridgeId:e.id,chatId:t,messageId:n,error:Yl(s)},"telegram callback message delete failed")})}chatAiSessionBindingActive(e,t,n,s){return this.service.listChatSessions().some(i=>i.bridgeId===e.id&&i.chatSessionId===t&&i.activeInstanceId===n&&i.activeAiSessionId===s)}telegramAiSessionActionAllowed(e,t,n,s,i){if(this.chatAiSessionBindingActive(e,t,n,s))return!0;if(!Number.isInteger(i))return!1;const r=this.telegramReplyAiSessionTarget(e.id,t,i);return Boolean(r&&r.instanceId===n&&r.sessionId===s)}async parseChatGatewayCallbackAction(e){const t=function(e){const t=e.match(/^task_handoff:cp_p:v1:([ads]):([A-Za-z0-9_-]{16})$/);if(!t)return;const n=Object.entries(Sd).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&&Ad(e.id)===t.routeFingerprint);if(1!==e.length){const e=new Error("This approval is no longer pending.");throw Object.assign(e,{statusCode:409,code:"CHAT_PENDING_ACTION_STALE"}),e}return{type:"pending-decision",routeId:e[0].id,decision:t.decision}}return function(e,t){const n=e.match(/^task_handoff:cp_session:(\d+)$/);if(n)return{type:"ai-session",index:Number(n[1])};const s=e.match(/^task_handoff:cp_i:([^:]+)$/)||e.match(/^task_handoff:cp_instance_apps:([^:]+)$/);if(s)return s[0].startsWith("task_handoff:cp_i:")?{type:"instance-app-menu",instanceId:Ac(t(s[1],"instance-app-menu").instanceId,"instanceId")}:{type:"instance-app-menu",instanceId:Tc(s[1])};const i=e.match(/^task_handoff:cp_a:([^:]+)$/)||e.match(/^task_handoff:cp_launch_app:([^:]+):([^:]+)$/);if(i){if(i[0].startsWith("task_handoff:cp_a:")){const e=t(i[1],"launch-app");return{type:"launch-app",instanceId:Ac(e.instanceId,"instanceId"),appId:Ac(e.appId,"appId")}}return{type:"launch-app",instanceId:Tc(i[1]),appId:Tc(i[2])}}const r=e.match(/^task_handoff:cp_p:([^:]+)$/);if(r){const e=t(r[1],"pending-decision");return{type:"pending-decision",routeId:Ac(e.routeId,"routeId"),decision:kc(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,s){t.token&&n&&await e(`https://api.telegram.org/bot${t.token}/answerCallbackQuery`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({callback_query_id:n,text:s.slice(0,200)})})}(this.fetchImpl,e,t,n)}async editTelegramMessage(e,t,n,s,i={}){return async function(e,t,n,s,i,r={}){if(t.token)return wc(n=>e(`https://api.telegram.org/bot${t.token}/editMessageText`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)}),"editMessageText",i,{chat_id:n,message_id:s,...r.replyMarkup?{reply_markup:r.replyMarkup}:{}},r)}(this.fetchImpl,e,t,n,s,i)}async sendTelegramMessage(e,t,n,s={}){return bc(this.fetchImpl,e,t,n,s)}async deleteTelegramMessage(e,t,n){return async function(e,t,n,s){if(!t.token||!Number.isInteger(s))return;const i=await e(`https://api.telegram.org/bot${t.token}/deleteMessage`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({chat_id:n,message_id:s})}),r=await i.json().catch(()=>({}));if(!i.ok||!1===r.ok)throw new Error(r.description||`Telegram deleteMessage failed with HTTP ${i.status}`)}(this.fetchImpl,e,t,n)}async rememberTelegramProgressMessage(e,t,n,s,i){if(!0!==e.routed)return;const r=rp(e),{instanceId:o,sessionId:a,turnId:d}=r,c=Number(np(s).message_id);if(!(o&&a&&d&&Number.isInteger(c)))return void this.logWarn({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,turnIdSources:r.sources,messageId:Number.isInteger(c)?c:void 0,routed:e.routed},"telegram ai session progress message not remembered");const l=pp(o,a,d,t.id,n),p=this.telegramProgress.remember(l,c,i,{bridgeId:t.id,chatId:n});this.telegramProgressMessageTargets.set(Kl(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:Zl(i)},"telegram ai session progress message remembered"),"queue"===function(e){return e.aiSession&&"action"in e.aiSession?e.aiSession.action:void 0}(e)&&p?.messageId&&p.messageId!==c&&(this.telegramProgressMessageTargets.delete(Kl(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:Yl(e)},"telegram queued progress message replacement cleanup failed")}))}telegramReplyAiSessionTarget(e,t,n){const s=this.telegramProgressMessageTargets.get(Kl(e,t,n));if(s)return s;for(const[s,i]of this.telegramProgress.entries)if(i.messageId===n&&i.route?.bridgeId===e&&i.route?.chatId===t){const i=Jl(s,e,t);if(i){const s={...i,messageId:n};return this.telegramProgressMessageTargets.set(Kl(e,t,n),s),s}}}async pollAiSessionUpdates(){this.logAiSessionDelivery({stage:"poll-tick"});const e=await this.service.listAiSessions({refresh:!0}).catch(()=>{});if(!e)return void this.logAiSessionDelivery({stage:"poll-no-snapshot"});const t=new Map(e.instances.map(e=>[e.instanceId,e.aiSessions]));this.logAiSessionDelivery({stage:"poll-snapshot",instanceCount:t.size,instances:[...t.entries()].map(([e,t])=>({instanceId:e,sessionCount:t.sessions?.length||0,runningCount:t.runningCount,waitingCount:t.waitingCount,updatedAt:t.updatedAt}))});const n=await this.aiSessionInstanceNames();for(const[e,s]of t)await this.deliverAiSessionSnapshot(e,s,n)}async deliverAiSessionSnapshot(e,t,n){const s=Array.isArray(t.sessions)?t.sessions:[];if(this.pruneAiSessionDeliveryState(e,new Set(s.map(e=>e.id))),0===s.length)return;const i=n||await this.aiSessionInstanceNames(),r=await this.aiSessionPendingApprovalRoutes(e);await this.deliverOwnedTelegramProgress(e,s,i,r),await this.deliverActiveBindingTelegramProgress(e,s,i,r)}pruneAiSessionDeliveryState(e,t){for(const[n,s]of this.telegramProgress.entries){const i=s.route?.bridgeId&&s.route.chatId?this.telegramProgressMessageTargets.get(Kl(s.route.bridgeId,s.route.chatId,s.messageId||0))||Jl(n,s.route.bridgeId,s.route.chatId):void 0;i&&i.instanceId===e&&!t.has(i.sessionId)&&(s.timer&&clearTimeout(s.timer),this.telegramProgress.entries.delete(n),this.deliveredAiSessionFingerprints.delete(n),s.route?.bridgeId&&s.route.chatId&&s.messageId&&this.telegramProgressMessageTargets.delete(Kl(s.route.bridgeId,s.route.chatId,s.messageId)))}}async deliverActiveBindingTelegramProgress(e,t,n,s){for(const i of this.service.listChatSessions()){if(!i.bridgeId||i.activeInstanceId!==e||!i.activeAiSessionId)continue;const r=t.find(e=>e.id===i.activeAiSessionId);if(!r)continue;const o=yp(n.get(e)||e,r),a=mp(r,o);if(!a){this.logAiSessionDelivery({stage:"skip-empty-text",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,status:r.status,phase:r.phase,activeTurnId:r.activeTurnId,latestTurn:tp(Ip(r))});continue}const d=up(r);if(!d){this.logAiSessionDelivery({stage:"skip-empty-turn-id",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,status:r.status,phase:r.phase,activeTurnId:r.activeTurnId,latestTurn:tp(Ip(r))});continue}if(this.listTelegramOwnedProgressEntries(e).some(e=>e.route.bridgeId===i.bridgeId&&e.route.chatId===i.chatSessionId&&e.owner.sessionId===r.id&&e.owner.turnId===d))continue;const c=pp(e,r.id,d,i.bridgeId||"",i.chatSessionId),l=gp(r,o);if(!l||this.deliveredAiSessionFingerprints.get(c)===l){this.logAiSessionDelivery({stage:"skip-duplicate-fingerprint",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,turnId:d,key:c,hasFingerprint:Boolean(l),fingerprintMatched:this.deliveredAiSessionFingerprints.get(c)===l,latestTurn:tp(Ip(r)),textPreview:Zl(a)});continue}const p=dp({cancelCallbackData:this.telegramAiSessionCallbacks.cancelCallbackData(e,r.id),queueSteerCallbackData:t=>this.telegramAiSessionCallbacks.queueSteerCallbackData(e,r.id,t),queueDeleteMenuCallbackData:()=>this.telegramAiSessionCallbacks.queueDeleteMenuCallbackData(e,r.id),permissionCallbackData:(e,t)=>this.service.pendingDecisionCallbackData(e,t),pendingApproval:s.get(r.id)||cp(e,r),session:r});if(this.logAiSessionDelivery({stage:"attempt",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,turnId:d,key:c,relatedProgressKeys:this.telegramProgressKeysFor(e,r.id,i.bridgeId||"",i.chatSessionId),hasProgressEntry:this.telegramProgress.entries.has(c),status:r.status,phase:r.phase,activeTurnId:r.activeTurnId,latestTurn:tp(Ip(r)),textPreview:Zl(a)}),await this.updateChatAiSessionProgress(i,a,c,p).catch(t=>(this.bridgeErrors.set(i.bridgeId||"",t instanceof Error?t.message:String(t)),this.logWarn({bridgeId:i.bridgeId,chatId:i.chatSessionId,instanceId:e,sessionId:r.id,turnId:d,key:c,error:Yl(t)},"chat ai session progress update failed"),!1)))this.logAiSessionDelivery({stage:"delivered",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,turnId:d,key:c,textPreview:Zl(a)}),this.deliveredAiSessionFingerprints.set(c,l);else{if("telegram"===this.service.requireChatBridge(i.bridgeId).channel){const t=this.telegramProgress.entries.get(c),n=this.service.requireChatBridge(i.bridgeId);this.logAiSessionDelivery({stage:t?"telegram-update-not-delivered":"telegram-no-progress-entry",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,turnId:d,key:c,relatedProgressKeys:this.telegramProgressKeysFor(e,r.id,i.bridgeId||"",i.chatSessionId),bridgeEnabled:n.enabled,bridgeChannel:n.channel,progressMessageId:t?.messageId,progressLastText:Zl(t?.lastText),progressHasPending:Boolean(t?.pending),latestTurn:tp(Ip(r)),textPreview:Zl(a)});continue}await this.sendToChatBinding(i,{text:a}).catch(e=>(this.bridgeErrors.set(i.bridgeId||"",e instanceof Error?e.message:String(e)),!1))&&(this.logAiSessionDelivery({stage:"fallback-sent",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,turnId:d,key:c,textPreview:Zl(a)}),this.deliveredAiSessionFingerprints.set(c,l))}}}async deliverOwnedTelegramProgress(e,t,n,s){for(const i of this.listTelegramOwnedProgressEntries(e)){const r=this.service.requireChatBridge(i.route.bridgeId);if("telegram"!==r.channel||!r.enabled)continue;const o=this.matchTelegramOwnedProgressSession(i,t);if(!o)continue;const a={bridgeId:i.route.bridgeId,chatSessionId:i.route.chatId},d=yp(n.get(e)||e,o),c=mp(o,d),l=up(o);if(!c||!l){this.logAiSessionDelivery({stage:"remembered-skip-turn-or-text",key:i.key,parsedTurnId:i.owner.turnId,currentTurnId:l,hasText:Boolean(c),instanceId:e,sessionId:o.id,bridgeId:i.route.bridgeId,chatId:i.route.chatId});continue}if(i.owner.turnId&&l!==i.owner.turnId){this.logAiSessionDelivery({stage:"remembered-skip-different-active-turn",key:i.key,ownerTurnId:i.owner.turnId,currentTurnId:l,instanceId:e,sessionId:o.id,bridgeId:i.route.bridgeId,chatId:i.route.chatId});continue}const p=l===i.owner.turnId?i.key:pp(e,o.id,l,i.route.bridgeId,i.route.chatId);if(p!==i.key&&this.telegramProgress.entries.has(p))continue;if(p!==i.key&&!this.rekeyTelegramOwnedProgress(i,p,{instanceId:e,sessionId:o.id,turnId:l}))continue;const u=gp(o,d);if(!u||this.deliveredAiSessionFingerprints.get(p)===u){this.logAiSessionDelivery({stage:"remembered-skip-fingerprint",key:i.key,hasFingerprint:Boolean(u),fingerprintMatched:this.deliveredAiSessionFingerprints.get(p)===u,instanceId:e,sessionId:o.id,bridgeId:i.route.bridgeId,chatId:i.route.chatId});continue}const g=dp({cancelCallbackData:this.telegramAiSessionCallbacks.cancelCallbackData(e,o.id),queueSteerCallbackData:t=>this.telegramAiSessionCallbacks.queueSteerCallbackData(e,o.id,t),queueDeleteMenuCallbackData:()=>this.telegramAiSessionCallbacks.queueDeleteMenuCallbackData(e,o.id),permissionCallbackData:(e,t)=>this.service.pendingDecisionCallbackData(e,t),pendingApproval:s.get(o.id)||cp(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:i.route.bridgeId,chatId:i.route.chatId,textPreview:Zl(c)}),h&&(this.telegramProgressMessageTargets.set(Kl(i.route.bridgeId,i.route.chatId,i.messageId),{instanceId:e,sessionId:o.id,turnId:l,messageId:i.messageId}),this.deliveredAiSessionFingerprints.set(p,u))}}rekeyTelegramOwnedProgress(e,t,n){return!!this.telegramProgress.rekey(e.key,t)&&(this.deliveredAiSessionFingerprints.delete(e.key),this.telegramProgressMessageTargets.set(Kl(e.route.bridgeId,e.route.chatId,e.messageId),{...n,messageId:e.messageId}),!0)}logAiSessionDelivery(e){this.logInfo(e,"telegram ai session delivery flow")}telegramProgressKeysFor(e,t,n,s){const i=`${e}:${t}:`,r=`:${n}:${s}`;return[...this.telegramProgress.entries.keys()].filter(e=>e.startsWith(i)&&e.endsWith(r))}listTelegramOwnedProgressEntries(e){const t=[];for(const[n,s]of this.telegramProgress.entries){if(!s.route?.bridgeId||!s.route.chatId||!Number.isInteger(s.messageId))continue;const i=this.telegramProgressMessageTargets.get(Kl(s.route.bridgeId,s.route.chatId,s.messageId))||Jl(n,s.route.bridgeId,s.route.chatId);i&&i.instanceId===e&&t.push({key:n,route:{bridgeId:s.route.bridgeId,chatId:s.route.chatId},messageId:s.messageId,owner:{...i,messageId:s.messageId}})}return t}matchTelegramOwnedProgressSession(e,t){const n=t.find(t=>t.id===e.owner.sessionId);if(n)return n;if(e.owner.turnId){const n=t.find(t=>t.activeTurnId===e.owner.turnId||Ip(t)?.id===e.owner.turnId||Ip(t)?.providerTurnId===e.owner.turnId);if(n)return n}}async updateChatAiSessionProgress(e,t,n,s){if(!e.bridgeId)return this.logAiSessionDelivery({stage:"chat-update-skip-missing-bridge",chatId:e.chatSessionId,key:n}),!1;const i=this.service.requireChatBridge(e.bridgeId);if(!i.enabled)return this.logAiSessionDelivery({stage:"chat-update-skip-bridge-state",bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,bridgeEnabled:i.enabled,bridgeChannel:i.channel}),!1;if("dingding"===i.channel){if(!this.dingdingBridges.get(i.id))return!1;const r=await this.dingdingBridges.applyProgressUpdate({bridge:i,key:n,chatId:e.chatSessionId,text:t,replyMarkup:Gl({actionRows:s})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:Zl(t)},"dingding ai session progress updated"),r}if("lark"===i.channel){const r=await this.larkBridges.applyProgressUpdate({bridge:i,key:n,chatId:e.chatSessionId,text:t,replyMarkup:Gl({actionRows:s})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:Zl(t)},"lark ai session progress updated"),r}if("telegram"!==i.channel)return!1;const r=this.telegramProgress.entries.get(n);if(!await this.telegramProgress.applyUpdate({bridge:i,key:n,chatId:e.chatSessionId,text:t,actionRows:s})){const t=this.telegramProgress.entries.get(n);return this.logAiSessionDelivery({stage:"telegram-update-returned-false",bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,progressMessageId:r?.messageId||t?.messageId,progressLastText:Zl(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:Zl(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 Fl(e){return"object"==typeof e&&e&&"reply"in e?String(e.reply||""):""}function Hl(e){return"object"==typeof e&&null!==e&&!0===e.accepted}function Wl(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 Gl(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return Nd(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function Vl(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function Kl(e,t,n){return[e,t,String(n)].join(":")}function Jl(e,t,n){const s=`:${t}:${n}`;if(!e.endsWith(s))return;const i=e.slice(0,-s.length).split(":"),r=i[0]||"",o=i[1]||"",a=i.slice(2).join(":")||void 0;return r&&o?{instanceId:r,sessionId:o,turnId:a}:void 0}function Ql(e){return"string"==typeof e?e:""}function Yl(e){return e instanceof Error?e.message:String(e)}function Xl(e,t){return Boolean(e&&"object"==typeof e&&"code"in e&&e.code===t)}function Zl(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 ep(e){const t=sp(e.body.cardActionData||e.body.content),n=sp(t.cardPrivateData||e.body.cardPrivateData||e.body.content);return{outTrackId:Ql(e.body.outTrackId),spaceId:Ql(e.body.spaceId),conversationType:e.conversationType,hasCallbackData:Boolean(e.callbackData),callbackDataPreview:Zl(e.callbackData,120),actionIds:[...ip(n.actionIdList),...ip(t.actionIdList),Ql(n.actionId),Ql(t.actionId),Ql(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 tp(e){if(e)return{id:e.id,providerTurnId:e.providerTurnId,source:e.source,status:e.status,phase:e.phase,revision:e.revision,userPrompt:Zl(e.userPrompt,80),hasResponse:Boolean(e.lastMessage?.trim()||e.summary?.trim()),responsePreview:Zl(e.lastMessage||e.summary,80),updatedAt:e.updatedAt,observedAt:e.observedAt}}function np(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function sp(e){if(e&&"object"==typeof e&&!Array.isArray(e))return e;if("string"==typeof e&&e.trim())try{return np(JSON.parse(e))}catch{return{}}return{}}function ip(e){return Array.isArray(e)?e.map(e=>Ql(e)).filter(Boolean):[]}function rp(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?up(n):""),sources:{resultTurnId:e.turnId,resultProviderTurnId:e.providerTurnId,actionTurnId:t?.turnId,actionProviderTurnId:t?.providerTurnId,sessionActiveTurnId:n?.activeTurnId,latestTurnId:n?Ip(n)?.id:void 0}}}const op=5,ap=48;function dp(e){const{cancelCallbackData:t,queueSteerCallbackData:n,queueDeleteMenuCallbackData:s,permissionCallbackData:i,pendingApproval:r,session:o}=e,a="approval"===r?.kind?[[{text:"Allow",callbackData:i(r.id,"allow")},{text:"Skip",callbackData:i(r.id,"skip")},{text:"Deny",callbackData:i(r.id,"deny")}]]:[];if("running"!==o.status)return a;const d=(o.queue?.items||[]).filter(e=>"queued"===e.status).slice(0,op);return[...d.map((e,t)=>[{text:lp(e.message,t),callbackData:n(e.id)}]),d.length?[{text:"Delete Queue",callbackData:s()},{text:"Cancel",callbackData:t}]:[{text:"Cancel",callbackData:t}]]}function cp(e,t){if("approval"===t.phase)return{id:`${e}:ai:${t.id}`,kind:"approval"}}function lp(e,t){const n=`${t+1}. `,s=e.replace(/\s+/g," ").trim()||"Queued message",i=Math.max(8,ap-n.length),r=Array.from(s);return`${n}${r.length>i?`${r.slice(0,Math.max(1,i-3)).join("")}...`:s}`}function pp(e,t,...n){return[e,t,...n].join(":")}function up(e){const t=Ip(e);return t?.id?t.id:Ql(e.activeTurnId)}function gp(e,t=""){const n=Ip(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),hp(e)].join("\0")}function hp(e){return(e.queue?.items||[]).map(e=>[e.id,e.status,e.message].join(":")).join("|")}function mp(e,t){const n=function(e,t){let n="";t?"waiting"===t.status&&"approval"===t.phase&&t.summary?.trim()?n=t.summary.trim():t.lastMessage?.trim()?n=t.lastMessage.trim():t.summary?.trim()&&(n=t.summary.trim()):"waiting"===e.status&&"approval"===e.phase&&e.summary?.trim()?n=e.summary.trim():e.lastMessage?.trim()?n=e.lastMessage.trim():e.summary?.trim()?n=e.summary.trim():e.error?.trim()&&(n="failed"===e.status?`${e.agent} session failed:\n${e.error.trim()}`:e.error.trim());const s=function(e){if(e.currentTool?.name)return`Thinking... · ${e.currentTool.name}${e.currentTool.inputPreview?` · ${e.currentTool.inputPreview}`:""}`;const t=e.toolCallsSinceLastMessage??0;return t>0?`Thinking... · ${t} ${1===t?"tool":"tools"} completed`:""}(e);return[n,s&&!fp(n,e)?s:""].filter(Boolean).join("\n\n")}(e,Ip(e));return n?`${t}\n${n}`:""}function yp(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 fp(e,t){if("waiting"!==t.status||"approval"!==t.phase)return!1;const n=t.currentTool?.inputPreview?.trim();return Boolean(n&&e.includes(n))}function Ip(e){return(e.turns||[]).filter(e=>e.id||e.userPrompt?.trim()||e.lastMessage?.trim()||e.summary?.trim()).at(-1)}class bp{clients=new Set;listeners=new Set;seq=0;connect(e){e.topics=new Set(["*"]),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||"{}"));return t&&"object"==typeof t?t:void 0}catch{return}}(t);"subscribe"===n?.type&&(e.topics=new Set(n.topics?.length?n.topics:["*"]))})}publish(e,t,n={}){const s=this.createEvent(e,t,n),i=s.topic,r=JSON.stringify(s);for(const e of this.listeners)try{e(s)}catch{this.listeners.delete(e)}for(const t of this.clients)if(t.readyState===t.OPEN&&vp(t.topics,i,e))try{t.send(r)}catch{this.clients.delete(t)}return s}on(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}send(e,t,n,s={}){const i=this.createEvent(t,n,s);return e.send(JSON.stringify(i)),i}createEvent(e,t,n={}){return{v:1,id:`evt_${Date.now().toString(36)}_${Math.random().toString(16).slice(2)}`,seq:++this.seq,type:e,topic:n.topic||Ti(e),createdAt:(new Date).toISOString(),payload:t,scope:n.scope}}}function vp(e,t,n){return!e||e.has("*")||e.has(t)||e.has(n)}const wp={"image/bmp":".bmp","image/gif":".gif","image/jpeg":".jpg","image/png":".png","image/webp":".webp"},Sp=o.z.object({instanceId:o.z.string().trim().min(1).max(120),sessionId:o.z.string().trim().min(1).max(120),kind:o.z.enum(["image","file"]),name:o.z.string().trim().min(1).max(240),mime:o.z.string().trim().min(1).max(120),data:o.z.string().min(1).max(31457280)}).strict();function Ap(){return t.join(y.tmpdir(),"task-handoff-ai-session-attachments")}class kp{items=new Map;ttlMs;constructor(e=864e5){this.ttlMs=e,this.pruneOrphanFiles()}upload(e){this.pruneExpired();const s=Sp.parse(e),i=function(e,t){const n=/^data:([^;,]+);base64,(.+)$/i.exec(e.trim()),s=n?.[1]||t,i=n?.[2]||e;return{mime:s,buffer:Buffer.from(i,"base64")}}(s.data,s.mime),r=i.mime.toLowerCase(),o=wp[r]||"";if("image"===s.kind&&!o)throw new Error(`Unsupported image type: ${r}`);const d="image"===s.kind?i.buffer.length>z:i.buffer.length>=T;if(!i.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_${a.randomUUID().replace(/-/g,"").slice(0,24)}`,l=new Date,p=new Date(l.getTime()+this.ttlMs),u=Ap();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(o)?g:`${g}${o}`}`);n.writeFileSync(h,i.buffer);const m={id:c,instanceId:s.instanceId,sessionId:s.sessionId,kind:s.kind,name:g,mime:r,size:i.buffer.length,source:{type:"inline",encoding:"base64",data:i.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 s=o.z.array(K).max(6).default([]).parse(e),i=s.map(e=>"runtime-path"===e.source.type?G.parse(e):this.requireAttachment(e,t,n));if(i.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>C)throw new Error("Inline attachments must be 41943040 bytes or less in total.");for(const e of s)"upload-ref"===e.source.type&&this.consumeAttachment(e.id);return i}dispose(){for(const e of[...this.items.keys()])this.consumeAttachment(e)}requireAttachment(e,t,n){const s=this.items.get(e.id);if(!s)throw new Error(`AI session attachment not found or expired: ${e.id}`);if(e.kind&&e.kind!==s.kind)throw new Error(`AI session attachment kind mismatch: ${e.id}`);if(s.instanceId!==t||s.sessionId!==n)throw new Error(`AI session attachment scope mismatch: ${e.id}`);return G.parse({id:s.id,kind:s.kind,name:s.name,mime:s.mime,size:s.size,source:s.source})}consumeAttachment(e){const t=this.items.get(e);if(t){this.items.delete(e);try{n.unlinkSync(t.path)}catch{}}}publicAttachment(e){return{id:e.id,kind:e.kind,name:e.name,mime:e.mime,size:e.size,expiresAt:e.expiresAt}}pruneExpired(){const e=Date.now();for(const[t,s]of this.items)if(!(Date.parse(s.expiresAt)>e)){this.items.delete(t);try{n.unlinkSync(s.path)}catch{}}this.pruneOrphanFiles()}pruneOrphanFiles(){const e=Ap();let s;try{s=n.readdirSync(e)}catch{return}const i=Date.now()-Math.max(this.ttlMs,864e5);for(const r of s){const s=t.join(e,r);try{n.statSync(s).isFile()&&n.statSync(s).mtimeMs<=i&&n.unlinkSync(s)}catch{}}}}const zp={controlPlaneAuthBoundary:"public"},Tp={controlPlaneAuthBoundary:"public-ui"},Cp={controlPlaneAuthBoundary:"proxy-binding"},xp={controlPlaneAuthBoundary:"node-tunnel"};class Ep{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 s=t.setTimeoutFn||setTimeout;return this.timer=s(()=>{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 Np(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function _p(e){return e.unref?.(),e}class Pp{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=Np(e.connectTimeoutMs,1e4),this.handshakeTimeoutMs=Np(e.handshakeTimeoutMs,1e4),this.heartbeatIntervalMs=Np(e.heartbeatIntervalMs,25e3),this.heartbeatTimeoutMs=Np(e.heartbeatTimeoutMs,1e4),this.stableThresholdMs=Np(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=_p(this.setTimeoutFn(()=>this.timeout("connect"),this.connectTimeoutMs))}opened(){this.stopped||(this.clearTimer("connectTimer"),this.setPhase("handshaking"),this.handshakeTimer=_p(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=_p(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=_p(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 Rp{transport;constructor(e){this.transport=e}attachMain(e,t){this.transport.attach(e,t),t.send(JSON.stringify({type:"control-plane.hello",protocolVersion:"2026-08-01",nodeId:e,serverTime:(new Date).toISOString(),capabilities:{reverseTunnel:"request-response",auxiliaryChannels:!0,httpResponseStreaming:!0,lifecycleCommands:!0,instanceApiProxy:!0}})),t.on("message",n=>this.handleMainMessage(e,t,n))}attachAuxiliary(e,t,n){return this.transport.attachAuxiliary(e,t,n)}handleMainMessage(e,t,n){if(!this.transport.isCurrentSocket(e,t))return;let s;try{s=JSON.parse(String(n))}catch{return void t.send(JSON.stringify({type:"control-plane.error",code:"INVALID_JSON"}))}const i=s&&"object"==typeof s?s:{},r=this.transport.handleSocketMessage(e,t,i);if(void 0!==r&&!r){if("node-agent.ping"!==i.type)return"node-agent.identify"===i.type?(this.transport.markHealthy(e,t),void t.send(JSON.stringify({type:"control-plane.identified",nodeId:e,serverTime:(new Date).toISOString()}))):void t.send(JSON.stringify({type:"control-plane.error",code:"UNSUPPORTED_MESSAGE"}));t.send(JSON.stringify({type:"control-plane.pong",nodeId:e,serverTime:(new Date).toISOString()}))}}}const Op={[x]:Be,[E]:Ue,[N]:Fe,[_]:He,[xr]:$r,[Er]:Br,[Nr]:Ur},jp=new Set(Object.keys(Op));class Mp{options;validatedScopes=new Map;validatingScopes=new Map;eventQueues=new Map;scopeEpochs=new Map;constructor(e={}){this.options=e}handle(e,t){const n="string"==typeof t.type?t.type:"";if("node-agent.streams.hello"===n){const n="string"==typeof t.instanceId?t.instanceId:"",s=hr(Ei,t.payload);return n&&s.success&&this.enqueue(e,n,()=>this.options.onStreamsHello?.(n,s.data)),!0}if(!n.startsWith("node-agent.event."))return!1;const s=Dp(t.event),i="string"==typeof s?.type?s.type:"";if(!i)return!0;const r="payload"in s?s.payload:{},o=Dp(s.scope)||{},a="string"==typeof t.instanceId?t.instanceId:void 0,d=function(...e){return e.find(e=>"string"==typeof e)}(o.instanceId,s.instanceId,a);if("instance.metrics.snapshot"===i){const t=hr(Ks,r);return!t.success||t.data.instanceId!==d||(this.enqueue(e,t.data.instanceId,()=>{this.options.events?.publish(i,t.data,{topic:"instances",scope:{...o,nodeId:e,instanceId:t.data.instanceId}})}),!0)}if(i===ui){const t=hr(gi,r);return!t.success||t.data.instanceId!==d||(this.enqueue(e,t.data.instanceId,()=>{this.options.events?.publish(i,t.data,{topic:"instances",scope:{...o,nodeId:e,instanceId:t.data.instanceId}})}),!0)}if(i===Ds||i===qs){const t=hr(i===Ds?$s:Bs,r);return!t.success||t.data.instanceId!==d||(this.enqueue(e,t.data.instanceId,()=>{this.options.events?.publish(i,t.data,{topic:"instances",scope:{...o,nodeId:e,instanceId:t.data.instanceId}})}),!0)}if(jp.has(i)){const t=function(e,t){const n=Op[e];if(!n)return;const s=hr(n,t);if(!s.success)return;const i=s.data;return{instanceId:"meta"in i?i.meta.instanceId:i.instanceId,payload:i}}(i,r);return!t||([o.instanceId,s.instanceId,a].filter(e=>"string"==typeof e&&Boolean(e)).some(e=>e!==t.instanceId)||this.enqueue(e,t.instanceId,()=>{const n={...o,nodeId:e,instanceId:t.instanceId},r={v:1,id:"string"==typeof s.id?s.id:`forwarded_${Date.now().toString(36)}`,seq:"number"==typeof s.seq?s.seq:0,type:i,topic:"string"==typeof s.topic?s.topic:i.startsWith("app-session.")?"app.sessions":"ai.sessions",createdAt:"string"==typeof s.createdAt?s.createdAt:(new Date).toISOString(),payload:t.payload,scope:n};this.options.onSessionEvent&&!this.options.onSessionEvent(r)||this.options.events?.publish(i,t.payload,{topic:r.topic,scope:n})}),!0)}const c=()=>{this.options.events?.publish(i,r,{topic:"string"==typeof s.topic?s.topic:void 0,scope:{...o,nodeId:e,...d?{instanceId:d}:{}}})};return d?this.enqueue(e,d,c):c(),!0}invalidate(e={}){const t=new Set;for(const[n,s]of this.validatedScopes)e.nodeId&&s.nodeId!==e.nodeId||e.instanceId&&s.instanceId!==e.instanceId||t.add(n);for(const n of new Set([...this.validatingScopes.keys(),...this.eventQueues.keys()])){const[s,i]=Lp(n);e.nodeId&&s!==e.nodeId||e.instanceId&&i!==e.instanceId||t.add(n)}for(const e of t)this.scopeEpochs.delete(e),this.validatedScopes.delete(e),this.validatingScopes.delete(e),this.eventQueues.delete(e)}diagnostics(){return{validatedScopes:this.validatedScopes.size,validatingScopes:this.validatingScopes.size,queuedScopes:this.eventQueues.size,scopeEpochs:this.scopeEpochs.size}}enqueue(e,t,n){const s=qp(e,t),i=this.scopeEpoch(s),r=(this.eventQueues.get(s)||Promise.resolve()).catch(()=>{}).then(async()=>{this.scopeEpochs.get(s)===i&&await this.isScopeValid(e,t,i)&&this.scopeEpochs.get(s)===i&&await n()});this.eventQueues.set(s,r);const o=()=>{this.eventQueues.get(s)===r&&this.eventQueues.delete(s),this.scopeEpochs.get(s)!==i||this.eventQueues.has(s)||this.validatingScopes.has(s)||this.scopeEpochs.delete(s)};r.then(o,o)}async isScopeValid(e,t,n){const s=qp(e,t);if((this.validatedScopes.get(s)?.expiresAt||0)>Date.now())return!0;const i=this.validatingScopes.get(s);if(i)return i;const r=Promise.resolve(this.options.validateInstanceScope?.(e,t)).then(Boolean).catch(()=>!1).then(i=>(i&&this.scopeEpochs.get(s)===n&&this.validatedScopes.set(s,{nodeId:e,instanceId:t,expiresAt:Date.now()+(this.options.scopeTtlMs??3e4)}),i));return this.validatingScopes.set(s,r),r.finally(()=>{this.validatingScopes.get(s)===r&&this.validatingScopes.delete(s)})}scopeEpoch(e){const t=this.scopeEpochs.get(e);if(t)return t;const n={};return this.scopeEpochs.set(e,n),n}}function Dp(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:void 0}function qp(e,t){return JSON.stringify([e,t])}function Lp(e){const t=JSON.parse(e);return Array.isArray(t)&&2===t.length?[String(t[0]),String(t[1])]:["",""]}const $p=o.z.object({nodeId:o.z.string().trim().min(1).max(120)}).strict();function Bp(){return`req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}const Up=new Map;function Fp(e,t){if("paired-hmac"!==e.auth.mode||!e.auth.keyId||!e.auth.secret){const e=new Error("Reverse tunnel requires paired-HMAC node auth.");throw Object.assign(e,{statusCode:401,code:"NODE_AGENT_TUNNEL_REQUIRES_PAIRED_HMAC"}),e}const n=function(e){const t=new Map;for(const[n,s]of Object.entries(e)){const e=Array.isArray(s)?s.join(","):"string"==typeof s?s:void 0===s?"":String(s);t.set(n.toLowerCase(),e)}return{nodeId:t.get("x-taskhandoff-node-id")||"",keyId:t.get("x-taskhandoff-key-id")||"",timestamp:t.get("x-taskhandoff-timestamp")||"",nonce:t.get("x-taskhandoff-nonce")||"",bodySha256:t.get("x-taskhandoff-body-sha256")||"",signature:t.get("x-taskhandoff-signature")||""}}(t.headers);if(n.nodeId!==e.id)throw Object.assign(new Error("Invalid reverse tunnel node id."),{statusCode:401,code:"NODE_AGENT_TUNNEL_NODE_MISMATCH"});if(n.keyId!==e.auth.keyId)throw Object.assign(new Error("Invalid reverse tunnel key id."),{statusCode:401,code:"NODE_AGENT_TUNNEL_KEY_INVALID"});const s=Date.parse(n.timestamp);if(!Number.isFinite(s)||Math.abs(Date.now()-s)>vo)throw Object.assign(new Error("Reverse tunnel timestamp is outside the allowed window."),{statusCode:401,code:"NODE_AGENT_TUNNEL_TIMESTAMP_INVALID"});const i=Date.now()-vo;for(const[e,t]of Up)t<=i&&Up.delete(e);const r=`${e.id}:${n.keyId}:${n.nonce}`;if(!n.nonce||Up.has(r))throw Object.assign(new Error("Reverse tunnel nonce is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_NONCE_INVALID"});const o=Ao("");if(n.bodySha256!==o)throw Object.assign(new Error("Reverse tunnel body hash is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_BODY_HASH_INVALID"});const d=t.url||`${wo}?nodeId=${encodeURIComponent(e.id)}`,c=ko(e.auth.secret,{keyId:n.keyId,method:"GET",pathWithQuery:d,timestamp:n.timestamp,nonce:n.nonce,bodySha256:o});if(!function(e,t){const n=Buffer.from(e,"hex"),s=Buffer.from(t,"hex");return n.length===s.length&&a.timingSafeEqual(n,s)}(n.signature,c))throw Object.assign(new Error("Reverse tunnel signature is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_SIGNATURE_INVALID"});Up.set(r,Date.now()+vo)}function Hp(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 Wp{sockets=new Map;eventRouter;httpStreamHeaderTimeoutMs;requestTimeoutMs;auxiliaryAttachTimeoutMs;connectionRuntime;connectionOptions;constructor(e,t={}){this.eventRouter=new Mp({events:e,onStreamsHello:t.onStreamsHello,onSessionEvent:t.onSessionEvent,validateInstanceScope:t.validateInstanceScope}),this.httpStreamHeaderTimeoutMs=t.httpStreamHeaderTimeoutMs??3e4,this.requestTimeoutMs=t.requestTimeoutMs??3e4,this.auxiliaryAttachTimeoutMs=t.auxiliaryAttachTimeoutMs??3e4,this.connectionRuntime=t.connectionRuntime,this.connectionOptions=t}attach(e,t){const n=this.sockets.get(e);if(n?.socket===t)return;n&&this.invalidateInstanceScope({nodeId:e});const s=new Map,i={socket:t,runtimeGeneration:this.connectionRuntime?.begin(e,"reverse-wss","handshaking"),pending:s,streams:new Map,httpStreams:new Map,pendingChannels:new Map},r=new Pp({...this.connectionOptions,ping:()=>t.ping?.(),onTimeout:n=>{this.sockets.get(e)===i&&(void 0!==i.runtimeGeneration&&this.connectionRuntime?.update(e,i.runtimeGeneration,{phase:"suspect",error:`Reverse tunnel ${n} timeout.`}),t.terminate?t.terminate():t.close?.(1011,`Reverse tunnel ${n} timeout.`))},onStable:()=>{void 0!==i.runtimeGeneration&&this.connectionRuntime?.stable(e,i.runtimeGeneration)}});i.supervisor=r,this.sockets.set(e,i),r.start(),r.opened(),t.on?.("pong",()=>{this.sockets.get(e)===i&&(r.pong(),void 0!==i.runtimeGeneration&&this.connectionRuntime?.pong(e,i.runtimeGeneration))}),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,s){e.supervisor?.close();for(const n of[...e.pending.keys()])this.cancelPendingRequest(e,n,t,!1);for(const[t,s]of e.streams)e.streams.delete(t),s.downstream.close(1011,n);for(const s of[...e.httpStreams.keys()])this.cancelHttpStream(e,s,t,n,!1);for(const t of e.pendingChannels.values())clearTimeout(t.timer);if(e.pendingChannels.clear(),s&&e.socket.close&&3!==e.socket.readyState)try{e.socket.close(1e3,n)}catch{}}isCurrentSocket(e,t){return this.sockets.get(e)?.socket===t}handleSocketMessage(e,t,n){if(this.isCurrentSocket(e,t))return this.handleMessage(e,n)}handleMessage(e,t){if(this.eventRouter.handle(e,t))return!0;if(this.handleWebSocketMessage(e,t))return!0;if("node-agent.response"!==t.type)return!1;const n="string"==typeof t.requestId?t.requestId:"",s=this.sockets.get(e),i=s?.pending.get(n);if(!i||!s)return!0;s.pending.delete(n),clearTimeout(i.timer),i.signal&&i.onAbort&&i.signal.removeEventListener("abort",i.onAbort);const r=Number(t.status)||502,o=t.headers&&"object"==typeof t.headers?t.headers:{},a="string"==typeof t.body?t.body:"";if(t.error&&"object"==typeof t.error){const e=t.error,n=new Error("string"==typeof e.message?e.message:`Reverse tunnel request failed with HTTP ${r}`);return Object.assign(n,{statusCode:r,code:"string"==typeof e.code?e.code:"NODE_AGENT_REVERSE_REQUEST_FAILED"}),i.reject(n),!0}return i.resolve(new Response(a,{status:r,headers:o})),!0}invalidateInstanceScope(e={}){this.eventRouter.invalidate(e)}instanceScopeDiagnostics(){return this.eventRouter.diagnostics()}async request(e,t,n={}){const s=this.sockets.get(e.id);if(!s){const t=new Error(`Reverse tunnel for node ${e.id} is not connected.`);throw Object.assign(t,{statusCode:503,code:"NODE_AGENT_REVERSE_TUNNEL_OFFLINE"}),t}const i=Bp(),r=tn(n.body),o={type:"control-plane.request",requestId:i,route:t,init:{method:n.method||"GET",headers:Hp(n.headers),body:r}};return new Promise((r,a)=>{let d;if(d={resolve:r,reject:a,timer:setTimeout(()=>{const n=new Error(`Reverse tunnel request to ${e.id}${t} timed out.`);Object.assign(n,{statusCode:504,code:"NODE_AGENT_REVERSE_REQUEST_TIMEOUT"}),this.cancelPendingRequest(s,i,n)},this.requestTimeoutMs),signal:n.signal||void 0},n.signal&&(d.onAbort=()=>{this.cancelPendingRequest(s,i,Object.assign(new Error("Reverse tunnel request was aborted."),{name:"AbortError",code:"ABORT_ERR"}))},n.signal.addEventListener("abort",d.onAbort,{once:!0})),s.pending.set(i,d),n.signal?.aborted)d.onAbort?.();else try{s.socket.send(JSON.stringify(o))}catch(e){this.cancelPendingRequest(s,i,e instanceof Error?e:new Error(String(e)),!1)}})}cancelPendingRequest(e,t,n,s=!0){const i=e.pending.get(t);if(!i)return!1;if(e.pending.delete(t),clearTimeout(i.timer),i.signal&&i.onAbort&&i.signal.removeEventListener("abort",i.onAbort),i.reject(n),s)try{e.socket.send(JSON.stringify({type:"control-plane.request.cancel",requestId:t}))}catch{}return!0}async requestStream(e,t,n={}){const s=this.sockets.get(e.id);if(!s)throw Object.assign(new Error(`Reverse tunnel for node ${e.id} is not connected.`),{statusCode:503,code:"NODE_AGENT_REVERSE_TUNNEL_OFFLINE"});const i=Bp(),r=tn(n.body);return new Promise((o,a)=>{const d={resolve:o,reject:a,timer:setTimeout(()=>{this.cancelHttpStream(s,i,Object.assign(new Error(`Reverse tunnel stream to ${e.id}${t} timed out.`),{statusCode:504,code:"NODE_AGENT_REVERSE_STREAM_TIMEOUT"}),"Reverse HTTP stream header timeout.")},this.httpStreamHeaderTimeoutMs),settled:!1,finalized:!1,signal:n.signal||void 0};if(s.httpStreams.set(i,d),this.registerPendingChannel(s,{id:i,attach:t=>this.attachHttpStreamChannel(e.id,i,t),cancel:(e,t)=>{this.cancelHttpStream(s,i,e,t)}},"Reverse HTTP channel attach timed out."),n.signal&&(d.onAbort=()=>this.cancelHttpStream(s,i,Object.assign(new Error("Reverse HTTP stream consumer disconnected."),{name:"AbortError",code:"ABORT_ERR"}),"HTTP consumer disconnected."),n.signal.addEventListener("abort",d.onAbort,{once:!0}),n.signal.aborted))d.onAbort();else try{s.socket.send(JSON.stringify({type:"control-plane.http.open",streamId:i,route:t,init:{method:n.method||"GET",headers:Hp(n.headers),body:r}}))}catch(e){this.cancelHttpStream(s,i,e instanceof Error?e:new Error(String(e)),"Reverse tunnel send failed.",!1)}})}cancelHttpStream(e,t,n,s,i=!0){const r=e.httpStreams.get(t);if(!r||r.finalized)return!1;if(r.finalized=!0,e.httpStreams.delete(t),this.removePendingChannel(e,t),clearTimeout(r.timer),r.signal&&r.onAbort&&r.signal.removeEventListener("abort",r.onAbort),r.settled?r.body?.destroy(n):(r.settled=!0,r.reject(n)),1===r.socket?.readyState&&r.socket.close(1e3,s),i)try{e.socket.send(JSON.stringify({type:"control-plane.http.cancel",streamId:t,reason:s}))}catch{}return!0}completeHttpStream(e,t){const n=e.httpStreams.get(t);return!(!n||n.finalized||(n.finalized=!0,e.httpStreams.delete(t),this.removePendingChannel(e,t),clearTimeout(n.timer),n.signal&&n.onAbort&&n.signal.removeEventListener("abort",n.onAbort),n.body?.end(),0))}attachAuxiliary(e,t,n){const s=this.sockets.get(e),i=s?.pendingChannels.get(t);return s&&i?(this.removePendingChannel(s,t),i.attach(n)):(n.close(1008,"Unknown reverse tunnel channel."),!1)}registerPendingChannel(e,t,n){this.removePendingChannel(e,t.id),t.timer=setTimeout(()=>{e.pendingChannels.get(t.id)===t&&(e.pendingChannels.delete(t.id),t.cancel(Object.assign(new Error(n),{code:"NODE_AGENT_REVERSE_CHANNEL_ATTACH_TIMEOUT"}),n))},this.auxiliaryAttachTimeoutMs),t.timer.unref?.(),e.pendingChannels.set(t.id,t)}removePendingChannel(e,t){const n=e.pendingChannels.get(t);return n?.timer&&clearTimeout(n.timer),e.pendingChannels.delete(t),n}attachHttpStream(e,t,n){return this.attachAuxiliary(e,t,n)}attachHttpStreamChannel(e,t,n){const s=this.sockets.get(e),i=s?.httpStreams.get(t);if(!s||!i)return n.close(1008,"Unknown reverse HTTP stream."),!1;i.socket=n;const r=e=>{this.cancelHttpStream(s,t,e,"Reverse HTTP stream failed.")};return n.on("message",(e,o)=>{if(i.finalized||s.httpStreams.get(t)!==i)return;if(o)return i.body?void(i.body.write(Buffer.isBuffer(e)?e:Buffer.from(e))||(n.pause?.(),i.body.once("drain",()=>n.resume?.()))):r(new Error("Reverse HTTP stream received data before response headers."));let a;try{a=JSON.parse(String(e))}catch{return void r(new Error("Reverse HTTP stream sent invalid JSON control data."))}if("node-agent.http.head"===a.type){if(i.settled)return;clearTimeout(i.timer);const e=Number(a.status)||502,n=a.headers&&"object"==typeof a.headers?a.headers:{},r=new g.PassThrough({highWaterMark:65536});return i.body=r,i.settled=!0,r.once("close",()=>{this.cancelHttpStream(s,t,new Error("Reverse HTTP stream consumer closed."),"HTTP consumer closed.")}),void i.resolve(new Response(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.")):i.settled?this.completeHttpStream(s,t):r(new Error("Reverse HTTP stream ended before response headers."))}),n.on("close",()=>{r(new Error("Reverse HTTP stream disconnected."))}),n.on("error",()=>r(new Error("Reverse HTTP stream failed."))),!0}proxyWebSocket(e,t,n,s,i={}){const r=e.id,o=this.sockets.get(r);if(!o)return void t.close(1011,"Reverse tunnel is not connected.");const a=Bp(),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(s)?s:s?[s]:[],headers:i}),t.on("message",(e,n)=>{const s=o.streams.get(a);if(s&&!s.upstream)return s.pendingFrames.length>=256?(this.removePendingChannel(o,a),o.streams.delete(a),t.close(1011,"Reverse websocket stream pending frame limit exceeded."),void d({type:"control-plane.websocket.close",streamId:a,code:1011,reason:"Reverse websocket stream pending frame limit exceeded."})):void s.pendingFrames.push({data:e,isBinary:Boolean(n)})}),t.on("close",(e,t)=>{const n=o.streams.get(a);if(n){this.removePendingChannel(o,a),o.streams.delete(a);const s=mo(e),i=ho(t);n.upstream&&yo(n.upstream,s,i),d({type:"control-plane.websocket.close",streamId:a,...void 0===s?{}:{code:s},...i?{reason:i}:{}})}}),t.on("error",()=>{const e=o.streams.get(a);e&&(this.removePendingChannel(o,a),o.streams.delete(a),e.upstream?.close(1011,"Downstream websocket failed."),d({type:"control-plane.websocket.close",streamId:a,code:1011,reason:"Downstream websocket failed."}))})}attachWebSocketStream(e,t,n){return this.attachAuxiliary(e,t,n)}attachWebSocketStreamChannel(e,t,n){const s=this.sockets.get(e),i=s?.streams.get(t);if(!s||!i)return n.close(1008,"Unknown reverse websocket stream."),!1;i.upstream=n;for(const e of i.pendingFrames.splice(0))n.send(e.data,{binary:e.isBinary});return Io(i.downstream,n,{pendingFrameLimit:256,onClientClose:()=>{this.removePendingChannel(s,t),s.streams.delete(t)},onClientError:()=>{this.removePendingChannel(s,t),s.streams.delete(t)},onUpstreamClose:()=>{this.removePendingChannel(s,t),s.streams.delete(t)},onUpstreamError:()=>{this.removePendingChannel(s,t),s.streams.delete(t)}}),!0}handleWebSocketMessage(e,t){const n="string"==typeof t.type?t.type:"";if(!n.startsWith("node-agent.websocket."))return!1;const s=this.sockets.get(e),i="string"==typeof t.streamId?t.streamId:"",r=s?.streams.get(i);return!r||("node-agent.websocket.close"===n?(s&&this.removePendingChannel(s,i),s?.streams.delete(i),yo(r.downstream,t.code,t.reason),!0):"node-agent.websocket.error"!==n||(s&&this.removePendingChannel(s,i),s?.streams.delete(i),r.downstream.close(1011,"string"==typeof t.message?t.message:"Reverse websocket proxy failed."),!0))}}class Gp{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 s;this.service=e,this.tunnel=t,this.safetyIntervalMs=(s=n.safetyIntervalMs,Math.min(6e4,Math.max(3e4,s??45e3))),this.logger=n.logger,this.connectionRuntime=n.connectionRuntime,this.connectionOptions=n,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 s=this.retries.get(t.id);if(s?.timer.pending&&s.url!==n&&(s.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 s=this.retries.get(t);s?.timer.cancel(),this.retries.delete(t)}for(const[t,n]of this.retries)e.has(t)||(n.timer.cancel(),this.retries.delete(t),this.socketUrls.delete(t))}connect(e,t){const n=zo(t),s=n?void 0:new URL(t),i=So(e,{method:"GET",pathWithQuery:s?`${s.pathname}${s.search}`:"/api/node-agent/events"}),r=n?Co(n,"/events",void 0,i):this.createSocket(t,{headers:i}),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 Ep;this.retries.set(e.id,{timer:a,url:t});const d=new Pp({...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,s="string"==typeof t.type&&t.type.startsWith("node-agent.")?t:{type:"node-agent.event.forwarded",event:t};this.tunnel.handleMessage(e.id,s)}}),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),s=n&&this.nodeEventsUrl(n);if(!this.running||!n||!s)return void(void 0!==t.generation&&this.connectionRuntime?.disconnected(e,t.generation,t));const i=this.retries.get(e)??{timer:new Ep};if(i.timer.pending)return;i.url=s;const r=i.timer.schedule(()=>{this.running&&!this.sockets.has(e)&&this.connect(n,s)});r&&(this.reconnectAttempts+=1,void 0!==t.generation&&this.connectionRuntime?.disconnected(e,t.generation,{...t,nextRetryAt:new Date(Date.now()+r.delay).toISOString()}),this.logger?.info?.({nodeId:e,url:s,attempt:r.attempt,delay:r.delay,reconnectAttempts:this.reconnectAttempts},"session-stream.node-connection.reconnect-scheduled")),this.retries.set(e,i)}nodeEventsUrl(e){if(!1===e.connectionEnabled)return;const t=e.controlEndpoint||e.endpoint;if(t&&"reverse-wss"!==e.connectionMode){if(zo(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 Vp(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"),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 Kp extends Error{code;lockPath;owner;constructor(e,t,n={}){const s=t?.pid?` pid ${t.pid}`:"";super(`${n.label||"Process"} is already running${s}. Lock: ${e}`),this.name="ProcessSingletonError",this.code=n.code||"PROCESS_ALREADY_RUNNING",this.lockPath=e,this.owner=t}}function Jp(e){return t.join(e,"owner.json")}function Qp(e){return t.join(e,"initializing.json")}function Yp(e){return t.join(e,"recovering.json")}function Xp(e){return Number.isInteger(e)&&Number(e)>0}function Zp(e,t=process.platform){if(Xp(e)){if("linux"===t)try{const t=n.readFileSync(`/proc/${e}/stat`,"utf8"),s=t.lastIndexOf(")");if(s<0)return;const i=t.slice(s+2).trim().split(/\s+/)[19];return i?`linux:${i}`:void 0}catch{return}if(["darwin","freebsd","openbsd","aix","sunos"].includes(t)){const n=b.spawnSync("ps",["-o","lstart=","-p",String(e)],{encoding:"utf8",timeout:1e3}),s=0===n.status?n.stdout.trim().replace(/\s+/g," "):"";return s?`${t}:${s}`: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}),s=0===n.status?n.stdout.trim():"";return/^\d+$/.test(s)?`win32:${s}`:void 0}}}const eu=function(e){try{const t=JSON.parse(n.readFileSync(Jp(e),"utf8"));if(Xp(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(!(Xp(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 tu(e){if(!Xp(e))return!1;try{return process.kill(Number(e),0),!0}catch(e){return"EPERM"===e.code}}function nu(e){if(!e||!tu(e.pid))return!1;if(!e.startIdentity)return!0;const t=Zp(e.pid);return void 0===t||t===e.startIdentity}function su(e,s){const i=t.join(e,`.owner-${s.token}.tmp`);n.writeFileSync(i,`${JSON.stringify(s,null,2)}\n`,{encoding:"utf8",mode:384,flag:"wx"});const r=ru(e);if(r?.token!==s.token)throw au(i),new Error(`Process lock initialization was superseded: ${e}`);n.renameSync(i,Jp(e)),au(Qp(e))}function iu(e,s,i){const r=eu(e);if(r?.token!==s.token)return!1;const o={...s};for(const[e,t]of Object.entries(i))void 0===t?delete o[e]:Object.assign(o,{[e]:t});const d=t.join(e,`.owner-update-${s.token}-${a.randomUUID()}.tmp`);try{if(n.writeFileSync(d,`${JSON.stringify(o,null,2)}\n`,{encoding:"utf8",mode:384,flag:"wx"}),eu(e)?.token!==s.token)return!1;n.renameSync(d,Jp(e));for(const e of Object.keys(s))delete s[e];return Object.assign(s,o),!0}catch(e){if("ENOENT"===e.code)return!1;throw e}finally{au(d)}}function ru(e){try{return JSON.parse(n.readFileSync(Qp(e),"utf8"))}catch{return}}function ou(e){const t=ru(e);return Xp(t?.pid)&&nu({pid:t.pid,startIdentity:t.startIdentity})}function au(e){try{n.unlinkSync(e)}catch(e){if("ENOENT"!==e.code)throw e}}function du(){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,20)}function cu(e){try{const t=ru(e),s=Date.parse(t?.startedAt||"");return Number.isFinite(s)?Math.max(0,Date.now()-s):Math.max(0,Date.now()-n.statSync(e).mtimeMs)}catch{return 0}}function lu(e,s){try{return n.writeFileSync(Yp(e),`${JSON.stringify({token:s,pid:process.pid,startedAt:(new Date).toISOString()})}\n`,{encoding:"utf8",mode:384,flag:"wx"}),!0}catch(i){if("EEXIST"===i.code)return!!function(e){const s=Yp(e),i=pu(s),r=Date.parse(i?.startedAt||"");if(tu(i?.pid)||Number.isFinite(r)&&Date.now()-r<2e3)return!1;const o=t.join(e,`.recovering-${a.randomUUID()}.stale`);try{n.renameSync(s,o)}catch(e){if(["ENOENT","EEXIST"].includes(e.code||""))return!1;throw e}const d=pu(o);if(d?.token===i?.token)return au(o),!0;try{n.linkSync(o,s)}catch(e){if("EEXIST"!==e.code)throw e}finally{au(o)}return!1}(e)&&lu(e,s);if("ENOENT"===i.code)return!1;throw i}}function pu(e){try{return JSON.parse(n.readFileSync(e,"utf8"))}catch{return}}function uu(e,t){return pu(Yp(e))?.token===t}function gu(){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 hu(e,s={}){return function(e,s={}){n.mkdirSync(t.dirname(e),{recursive:!0});const i=Zp(process.pid),r={pid:process.pid,hostname:y.hostname(),command:process.argv.join(" "),acquiredAt:(new Date).toISOString(),token:a.randomUUID(),...void 0!==s.component?{component:s.component}:{},...i?{startIdentity:i}:{},...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(Qp(e),`${JSON.stringify({token:r.token,pid:r.pid,startIdentity:r.startIdentity,startedAt:(new Date).toISOString()})}\n`,{encoding:"utf8",mode:384,flag:"wx"}),su(e,r),{lockPath:e,owner:r,updateDetails:t=>iu(e,r,t),release(){const t=eu(e);t?.token===r.token&&n.rmSync(e,{recursive:!0,force:!0})}}}catch(i){if("EEXIST"!==i.code)throw i;const r=eu(e);if(nu(r))throw new Kp(e,r,s.error);if(!r&&(ou(e)||cu(e)<(s.incompleteLockStaleMs??2e3))){if(t+1<5){du();continue}throw new Kp(e,void 0,s.error)}const o=a.randomUUID();if(!lu(e,o)){if(t+1<5){du();continue}throw new Kp(e,eu(e),s.error)}const d=eu(e);if(nu(d))throw au(Yp(e)),new Kp(e,d,s.error);if(r?.token&&d?.token!==r.token){au(Yp(e));continue}if(!uu(e,o))continue;n.rmSync(e,{recursive:!0,force:!0})}const o=eu(e);throw new Kp(e,o,s.error)}(e,{...s,component:"control-plane",error:{label:"Control plane",code:"CONTROL_PLANE_ALREADY_RUNNING"}})}function mu(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):"admin"===e.role||("viewer"===e.role?"read"===t:"operator"===e.role&&function(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))}(t,n)))}(e,t,n))return;const s=new Error(`Actor is not allowed to ${t} ${n.type}${n.id?` ${n.id}`:""}.`);throw Object.assign(s,{statusCode:403,code:"CONTROL_PLANE_FORBIDDEN"}),s}const yu=o.z.string().trim().min(1),fu=o.z.object({id:yu}).strict(),Iu=o.z.object({id:yu,keyId:yu}).strict(),bu=o.z.object({id:yu,connectionId:yu}).strict(),vu=o.z.object({id:yu,runtimeId:yu}).strict(),wu=o.z.object({id:yu,folderId:yu}).strict(),Su=o.z.object({id:yu,sessionId:yu}).strict(),Au=o.z.object({id:yu,sessionId:yu,queueId:yu}).strict(),ku=o.z.object({configHash:yu}).strict(),zu=o.z.object({id:yu,configHash:yu}).strict(),Tu=o.z.object({id:yu,sessionId:yu,configHash:yu}).strict(),Cu=o.z.object({path:o.z.string().optional(),depth:o.z.coerce.number().int().min(0).max(32).optional()}).strict();async function xu(e,t,n){const s=new AbortController,i=()=>s.abort(),r=()=>{t.raw.writableEnded||i()};e.raw.once("aborted",i),t.raw.once("close",r);try{return await n(s.signal)}finally{e.raw.off("aborted",i),t.raw.off("close",r)}}const Eu=o.z.object({ids:o.z.array(o.z.string().trim().min(1).max(120)).default([])}).strict(),Nu=o.z.object({nodeId:o.z.string().trim().min(1).max(120),modelId:o.z.string().trim().min(1).max(120).optional()}).strict(),_u=o.z.object({source:o.z.object({channel:fi,bridgeId:o.z.string().trim().min(1).max(120).optional(),chatSessionId:o.z.string().trim().min(1).max(240),userId:o.z.string().trim().max(240).optional()}).strict(),action:o.z.discriminatedUnion("type",[o.z.object({type:o.z.literal("ai-session"),index:o.z.number().int().nonnegative()}).strict(),o.z.object({type:o.z.literal("instance-app-menu"),instanceId:o.z.string().trim().min(1).max(120)}).strict(),o.z.object({type:o.z.literal("launch-app"),instanceId:o.z.string().trim().min(1).max(120),appId:o.z.string().trim().min(1).max(120)}).strict(),o.z.object({type:o.z.literal("pending-decision"),routeId:o.z.string().trim().min(1).max(120),decision:o.z.enum(["allow","deny","skip"])}).strict()])}).strict();function Pu(e){const t=_u.parse(e);if(!t.action)throw new Error("Chat gateway action is required.");return{source:t.source,action:t.action}}const Ru=o.z.object({path:o.z.string().trim().max(1e3).optional(),depth:o.z.coerce.number().int().min(0).max(2).optional()}).strict(),Ou=o.z.object({id:o.z.string().trim().min(1),appId:o.z.string().trim().min(1)}).strict(),ju=o.z.object({id:o.z.string().trim().min(1),jobId:o.z.string().trim().min(1)}).strict(),Mu=o.z.object({projection:o.z.literal("directory").optional()}).strict(),Du=o.z.object({id:o.z.string().trim().min(1).max(120)}).strict(),qu=o.z.object({nodeId:o.z.string().trim().min(1).max(120),templateId:o.z.string().trim().min(1).max(120)}).strict(),Lu=o.z.object({force:o.z.enum(["true","false"]).optional()}).strict(),$u=o.z.object({projection:o.z.literal("directory").optional()}).strict();const Bu=o.z.object({appId:o.z.string().trim().min(1).max(120).default("terminal-tty"),cwdFolderId:o.z.string().trim().min(1).max(120).optional(),options:o.z.record(o.z.string(),o.z.unknown()).default({})}).strict().default({appId:"terminal-tty",options:{}}),Uu=o.z.object({title:o.z.string().trim().min(1).max(120)}).strict(),Fu=o.z.object({token:o.z.string().trim().min(1).max(512)}).strict(),Hu=o.z.object({}).strict();function Wu(e){const{app:t,service:n,events:s,appSessionAggregator:i,aiSessionAggregator:r,aiSessionUnread:a,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,s)=>{const i=t.createProject(e.body);return n.publish("project.created",{projectId:i.id}),s.code(201).send({data:i})}),e.get("/api/projects/:id",async e=>({data:t.requireProject(fu.parse(e.params).id)})),e.patch("/api/projects/:id",async e=>{const s=t.updateProject(fu.parse(e.params).id,e.body);return n.publish("project.updated",{projectId:s.id}),{data:s}}),e.delete("/api/projects/:id",async e=>{const s=fu.parse(e.params).id,i=t.deleteProject(s);return n.publish("project.deleted",{projectId:s,deleted:i}),{data:{deleted:i}}}),e.get("/api/models",async(e,n)=>xu(e,n,async e=>({data:await t.listFederatedModels(e)}))),e.post("/api/models",async(e,s)=>{const i=await t.createModel(e.body);return n.publish("model.created",{modelId:i.id}),s.code(201).send({data:i})}),e.post("/api/models/reorder",async e=>{const s=Eu.parse(e.body),i=await t.reorderModels(s.ids);return n.publish("model.reordered",{ids:s.ids}),{data:i}}),e.get("/api/models/:id",async e=>({data:t.requireModel(fu.parse(e.params).id)})),e.patch("/api/models/:id",async e=>{const s=await t.updateModel(fu.parse(e.params).id,e.body);return n.publish("model.updated",{modelId:s.id}),{data:s}}),e.delete("/api/models/:id",async e=>{const s=fu.parse(e.params).id,i=await t.deleteModel(s);return n.publish("model.deleted",{modelId:s,deleted:i}),{data:{deleted:i}}}),e.post("/api/nodes/:nodeId/models",async(e,s)=>{const{nodeId:i}=Nu.parse(e.params),r=await t.createNodeModel(i,e.body);return n.publish("model.created",{modelId:r.id,nodeId:i}),s.code(201).send({data:r})}),e.patch("/api/nodes/:nodeId/models/:modelId",async e=>{const{nodeId:s,modelId:i}=Nu.parse(e.params),r=await t.updateNodeModel(s,i,e.body);return n.publish("model.updated",{modelId:i,nodeId:s}),{data:r}}),e.delete("/api/nodes/:nodeId/models/:modelId",async e=>{const{nodeId:s,modelId:i}=Nu.parse(e.params),r=await t.deleteNodeModel(s,i);return n.publish("model.deleted",{modelId:i,nodeId:s,deleted:r.deleted}),{data:r}}),e.get("/api/market/catalog",async()=>({data:t.getMarketCatalog()})),e.post("/api/market/refresh",async()=>{const e=await t.refreshMarketCatalog();return n.publish("market.catalog.updated",{revision:e.catalog.revision,source:e.catalog.source}),{data:e}}),e.get("/api/image-options",async()=>({data:t.listImageOptions()})),e.get("/api/images",async()=>({data:t.listImages()})),e.post("/api/images",async(e,s)=>{const i=t.createImage(e.body);return n.publish("image.created",{imageId:i.id}),s.code(201).send({data:i})}),e.get("/api/images/:id",async e=>({data:t.requireImage(fu.parse(e.params).id)})),e.patch("/api/images/:id",async e=>{const s=t.updateImage(fu.parse(e.params).id,e.body);return n.publish("image.updated",{imageId:s.id}),{data:s}}),e.delete("/api/images/:id",async e=>{const s=fu.parse(e.params).id,i=await t.deleteImage(s);return n.publish("image.deleted",{imageId:s,deleted:i}),{data:{deleted:i}}})}({app:t,service:n,events:s}),function({app:e,service:t,events:n,nodeAgentTunnel:s,nodeEventSubscriber:i,errorPayload:r}){const o=e=>{if(!e||"object"!=typeof e||Array.isArray(e)||!("target"in e))return;const t=e.target;if(!t||"object"!=typeof t||Array.isArray(t)||"controlled-instance"!==t.component)return;const n=new Error("Independent controlled-instance updates were retired; update the Node rollout instead.");throw Object.assign(n,{statusCode:404,code:"LEGACY_INSTANCE_UPDATE_RETIRED"}),n};e.get("/api/nodes",async e=>({data:"directory"===$u.parse(e.query).projection?t.listNodes().map(e=>function(e){const t=e.proxyState?.lastError;return Xo.parse({id:e.id,name:e.name,status:e.status,health:e.health,connectionMode:e.connectionMode,connectionPhase:e.connectionPhase,lastSeenAt:e.lastSeenAt,observedAt:e.updatedAt,capabilities:Object.keys(e.capabilities).sort(),error:t?{code:t.code,message:"Node connection failed. Use the desktop Control Plane for diagnostics."}:void 0})}(t.projectNodeConnection(e))):t.listPublicNodes()})),e.post("/api/nodes/local/sync",async()=>{const e=await t.syncLocalNodeConnection();return i.syncNow(),n.publish("node.local-synced",{nodeId:e.id}),{data:t.requirePublicNode(e.id)}}),e.post("/api/nodes",async(e,s)=>{const r=await t.createNode(e.body);return i.syncNow(),n.publish("node.created",{nodeId:r.id}),s.code(201).send({data:t.requirePublicNode(r.id)})}),e.post("/api/nodes/:id/check",async e=>{const s=await t.checkNode(fu.parse(e.params).id);return n.publish("node.checked",{nodeId:s.id},{topic:"node.state",scope:{nodeId:s.id}}),{data:s}}),e.get("/api/nodes/:id/updates/jobs",async e=>({data:await t.listNodeUpdateJobs(fu.parse(e.params).id)})),e.get("/api/nodes/:id/settings/external-listener",async e=>({data:await t.getLocalNodeExternalListener(fu.parse(e.params).id)})),e.patch("/api/nodes/:id/settings/external-listener",async e=>{const s=fu.parse(e.params).id,i=await t.updateLocalNodeExternalListener(s,e.body);return n.publish("node.external-listener.updated",{nodeId:s,bindScope:i.bindScope,port:i.port}),{data:i}}),e.post("/api/nodes/:id/updates/check",async e=>{o(e.body);const s=fu.parse(e.params).id,i=await t.checkNodeUpdate(s,Zn.parse(e.body));return n.publish("node.update.checked",{nodeId:s,availableVersion:i.availableVersion,impact:i.impact}),{data:i}}),e.post("/api/nodes/:id/updates/apply",async(e,s)=>{o(e.body);const i=fu.parse(e.params).id,r=await t.applyNodeUpdate(i,ns.parse(e.body));return n.publish("node.update.queued",{nodeId:i,updateJobId:r.id,desiredVersion:r.toVersion,impact:r.impact}),s.code(202).send({data:r})}),e.post("/api/nodes/:id/pairing/invites",async(e,s)=>{const i=fu.parse(e.params),r=await t.createNodePairingInvite(i.id,e.body);return n.publish("node.pairing-invite.created",{nodeId:i.id}),s.code(201).send({data:r})}),e.post("/api/nodes/:id/control-plane-connections",async e=>{const s=fu.parse(e.params),i=await t.connectNodeToControlPlane(s.id,e.body);return n.publish("node.remote-connect.requested",{nodeId:s.id}),{data:i}}),e.get("/api/nodes/:id/control-plane-pairings",async e=>{const n=fu.parse(e.params);return{data:await t.listNodeControlPlanePairings(n.id)}}),e.delete("/api/nodes/:id/control-plane-pairings/:keyId",async e=>{const s=Iu.parse(e.params),i=await t.deleteNodeControlPlanePairing(s.id,s.keyId);return n.publish("node.control-plane-pairing.deleted",{nodeId:s.id,keyId:s.keyId}),{data:i}}),e.get("/api/nodes/:id/control-plane-connections",async e=>{const n=fu.parse(e.params);return{data:await t.listNodeControlPlaneConnections(n.id)}}),e.delete("/api/nodes/:id/control-plane-connections/:connectionId",async e=>{const s=bu.parse(e.params),i=await t.deleteNodeControlPlaneConnection(s.id,s.connectionId);return n.publish("node.control-plane-connection.deleted",{nodeId:s.id,connectionId:s.connectionId}),{data:i}}),e.post("/api/node-join/invites",async(e,s)=>{const i=t.createNodeJoinInvite(e.body);return n.publish("node-join.invite.created",{inviteId:i.id}),s.code(201).send({data:i})}),e.post("/api/node-join/complete",{config:zp},async(e,s)=>{const r=t.completeNodeJoin(e.body);return i.syncNow(),n.publish("node.joined",{nodeId:r.id}),s.code(201).send({data:t.requirePublicNode(r.id)})}),e.get("/api/nodes/:id/runtimes",async e=>({data:await t.listNodeRuntimes(fu.parse(e.params).id)})),e.post("/api/nodes/:id/runtimes",async(e,s)=>{const i=fu.parse(e.params),r=await t.createNodeRuntime(i.id,e.body);return n.publish("node.runtime.created",{nodeId:i.id,runtimeId:r.id}),s.code(201).send({data:r})}),e.patch("/api/nodes/:id/runtimes/:runtimeId",async e=>{const s=vu.parse(e.params),i=await t.updateNodeRuntime(s.id,s.runtimeId,e.body);return n.publish("node.runtime.updated",{nodeId:s.id,runtimeId:i.id}),{data:i}}),e.delete("/api/nodes/:id/runtimes/:runtimeId",async e=>{const s=vu.parse(e.params),i=await t.deleteNodeRuntime(s.id,s.runtimeId);return n.publish("node.runtime.deleted",{nodeId:s.id,runtimeId:s.runtimeId}),{data:i}}),e.post("/api/nodes/:id/runtimes/:runtimeId/check",async e=>{const s=vu.parse(e.params),i=await t.checkNodeRuntime(s.id,s.runtimeId);return n.publish("node.runtime.checked",{nodeId:s.id,runtimeId:i.id}),{data:i}}),e.get("/api/nodes/:id/docker/images",async e=>({data:await t.listNodeDockerImages(fu.parse(e.params).id)})),e.get("/api/nodes/:id/image-options",async e=>({data:await t.listNodeImageAvailability(fu.parse(e.params).id)})),e.get("/api/nodes/:id/local-folders",async(e,n)=>xu(e,n,async n=>({data:await t.listNodeLocalFolders(fu.parse(e.params).id,n)}))),e.get("/api/nodes/:id/folders/tree",async e=>{const n=fu.parse(e.params),s=Cu.parse(e.query);return{data:await t.listNodeFolderTree(n.id,{path:s.path,depth:s.depth})}}),e.post("/api/nodes/:id/local-folders",async(e,s)=>{const i=fu.parse(e.params),r=await t.createNodeLocalFolder(i.id,e.body);return n.publish("node.local-folder.created",{nodeId:i.id,folderId:r.id}),s.code(201).send({data:r})}),e.delete("/api/nodes/:id/local-folders/:folderId",async e=>{const s=wu.parse(e.params),i=await t.deleteNodeLocalFolder(s.id,s.folderId);return n.publish("node.local-folder.deleted",{nodeId:s.id,folderId:s.folderId}),{data:i}}),e.get("/api/nodes/:id",async e=>({data:t.requirePublicNode(fu.parse(e.params).id)})),e.patch("/api/nodes/:id",async e=>{const r=t.updateNode(fu.parse(e.params).id,e.body);return r.connectionEnabled||s.disconnect(r.id),i.syncNow(),n.publish("node.updated",{nodeId:r.id}),{data:t.requirePublicNode(r.id)}}),e.delete("/api/nodes/:id",async e=>{const s=fu.parse(e.params).id,r=Lu.parse(e.query),o=await t.deleteNodeWithProxyLifecycle(s,"true"===r.force);return i.syncNow(),n.publish("node.deleted",{nodeId:s,deleted:o.deleted,revoke:o.revoke}),{data:o}}),e.get("/api/node-runtimes",async(e,n)=>xu(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:s,errorPayload:i}=e,r=new Rp(s),o=e=>{if(!1===e.connectionEnabled){const e=new Error("Node agent connection is disabled locally.");throw Object.assign(e,{statusCode:409,code:"NODE_AGENT_CONNECTION_DISABLED"}),e}};t.get(wo,{websocket:!0,config:xp},(e,t)=>{try{const s=$p.parse(t.query),i=n.requireNode(s.nodeId);Fp(i,t),o(i),r.attachMain(i.id,e)}catch(t){const n=i(t);e.send(JSON.stringify({type:"control-plane.error",code:n.code,message:n.message})),e.close(1008,n.message)}}),t.get(`${wo}/streams/:streamId`,{websocket:!0,config:xp},(e,t)=>{try{const s=$p.parse(t.query),i=n.requireNode(s.nodeId);Fp(i,t),o(i);const a=t.params.streamId;r.attachAuxiliary(i.id,a,e)}catch(t){const n=i(t);e.close(1008,n.message)}}),t.get(`${wo}/channels/:channelId`,{websocket:!0,config:xp},(e,t)=>{try{const s=$p.parse(t.query),i=n.requireNode(s.nodeId);Fp(i,t),o(i);const a=t.params.channelId;r.attachAuxiliary(i.id,a,e)}catch(t){const n=i(t);e.close(1008,n.message)}}),t.get(`${wo}/http-streams/:streamId`,{websocket:!0,config:xp},(e,t)=>{try{const s=$p.parse(t.query),i=n.requireNode(s.nodeId);Fp(i,t),o(i);const a=t.params.streamId;r.attachAuxiliary(i.id,a,e)}catch(t){const n=i(t);e.close(1008,n.message)}})}({app:e,service:t,nodeAgentTunnel:s,errorPayload:r})}({app:t,service:n,events:s,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,s)=>{const i=await t.createControlledInstance(e.body);return n.publish("instance.created",{instanceId:i.id}),s.code(201).send({data:i})}),e.get("/api/controlled-instances/:id",async e=>({data:await t.requireControlledInstance(fu.parse(e.params).id)})),e.get("/api/controlled-instances/:id/metrics",async e=>({data:await t.instanceResourceMetrics(fu.parse(e.params).id)})),e.get("/api/controlled-instances/:id/apps/management",async e=>({data:await t.instanceAppManagement(fu.parse(e.params).id)})),e.post("/api/controlled-instances/:id/apps/:appId/install",async e=>{const n=Ou.parse(e.params),s=Hn.parse(e.body||{});return{data:await t.requestInstanceAppOperation(n.id,n.appId,"install",s)}}),e.post("/api/controlled-instances/:id/apps/:appId/uninstall",async e=>{const n=Ou.parse(e.params),s=Hn.parse(e.body||{});return{data:await t.requestInstanceAppOperation(n.id,n.appId,"uninstall",s)}}),e.get("/api/controlled-instances/:id/apps/jobs/:jobId",async e=>{const n=ju.parse(e.params);return{data:await t.instanceAppManagementJob(n.id,n.jobId)}}),e.patch("/api/controlled-instances/:id",async e=>{const s=await t.updateControlledInstance(fu.parse(e.params).id,e.body);return n.publish("instance.updated",{instanceId:s.id}),{data:s}}),e.delete("/api/controlled-instances/:id",async e=>{const s=fu.parse(e.params).id,i=await t.deleteControlledInstance(s,vn.parse(e.body));return i.completed&&n.publish("instance.deleted",{instanceId:s,result:i}),{data:i}}),e.post("/api/controlled-instances/:id/start",async e=>{const s=await t.startControlledInstance(fu.parse(e.params).id);return n.publish("instance.started",{instanceId:s.id}),{data:s}}),e.post("/api/controlled-instances/:id/stop",async e=>{const s=await t.stopControlledInstance(fu.parse(e.params).id);return n.publish("instance.stopped",{instanceId:s.id}),{data:s}}),e.post("/api/controlled-instances/:id/restart",async e=>{const s=await t.restartControlledInstance(fu.parse(e.params).id);return n.publish("instance.restarted",{instanceId:s.id}),{data:s}}),e.post("/api/controlled-instances/:id/image-provisioning/retry",async e=>{const s=await t.retryControlledInstanceImageProvisioning(fu.parse(e.params).id);return n.publish("instance.image-provisioning-retried",{instanceId:s.id}),{data:s}}),e.get("/api/controlled-instances/:id/config-sync",async e=>({data:await t.instanceConfigSyncState(fu.parse(e.params).id)})),e.get("/api/controlled-instances/:id/config-sync/folders",async e=>({data:await t.listInstanceConfigSyncFolders(fu.parse(e.params).id,Ru.parse(e.query))})),e.post("/api/controlled-instances/:id/config-sync",async e=>{const s=fu.parse(e.params).id,i=await t.syncInstanceConfigs(s,e.body);return n.publish("instance.config-synced",{instanceId:s}),{data:i}}),e.get("/api/instance-board",async(e,n)=>xu(e,n,async n=>{const s=Mu.parse(e.query),i=await t.boardWithDiagnostics(n);return{data:"directory"===s.projection?i.items.map(sa):i.items,meta:{nodeErrors:i.nodeErrors}}}))}({app:t,service:n,events:s}),function(e,t,n){e.get("/api/nodes/:id/environment-templates",async e=>({data:await t.listEnvironmentTemplates(Du.parse(e.params).id)})),e.get("/api/nodes/:nodeId/environment-templates/:templateId",async e=>{const n=qu.parse(e.params);return{data:await t.getEnvironmentTemplate(n.nodeId,n.templateId)}}),e.post("/api/controlled-instances/:id/environment-templates",async(e,s)=>{const i=Du.parse(e.params).id,r=await t.createEnvironmentTemplate(i,e.body);return n.publish("environment-template.updated",{templateId:r.id,nodeId:r.nodeId,status:r.status}),s.code(201).send({data:r})}),e.delete("/api/nodes/:nodeId/environment-templates/:templateId",async e=>{const s=qu.parse(e.params),i=await t.deleteEnvironmentTemplate(s.nodeId,s.templateId);return n.publish("environment-template.deleted",i),{data:i}})}(t,n,s),function({app:e,service:t,events:n,appSessionAggregator:s,aiSessionAggregator:i,aiSessionUnread:r,aiSessionAttachments:a}){e.get("/api/app-sessions",async e=>{const t=o.z.object({refresh:o.z.string().optional(),instanceId:o.z.string().trim().min(1).optional(),streamId:o.z.string().trim().min(1).optional(),sinceRevision:o.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 s.delta({instanceId:t.instanceId,streamId:t.streamId,sinceRevision:e})}}return{data:await s.list({refresh:"true"===t.refresh||"1"===t.refresh})}}),e.post("/api/controlled-instances/:id/apps/sessions",async e=>{const s=fu.parse(e.params),i=Bu.parse(e.body),r=await t.launchAppSession(s.id,i.appId,{...i.options,...i.cwdFolderId?{cwdFolderId:i.cwdFolderId}:{}});return n.publish("instance.app-session.launched",{instanceId:s.id,sessionId:"string"==typeof r.id?r.id:void 0,appId:i.appId}),{data:r}}),e.post("/api/controlled-instances/:id/apps/sessions/:sessionId/stop",async e=>{const s=Su.parse(e.params),i=await t.stopAppSession(s.id,s.sessionId);return n.publish("instance.app-session.stopped",{instanceId:s.id,sessionId:s.sessionId}),{data:i}}),e.patch("/api/controlled-instances/:id/apps/sessions/:sessionId",async e=>{const s=Su.parse(e.params),i=Uu.parse(e.body),r=await t.renameAppSession(s.id,s.sessionId,i.title);return n.publish("instance.app-session.renamed",{instanceId:s.id,sessionId:s.sessionId,title:i.title}),{data:r}}),e.post("/api/controlled-instances/:id/apps/sessions/:sessionId/access",async e=>{const n=Su.parse(e.params);Hu.parse(e.body||{});const s=await t.createAppSessionAccessToken({instanceId:n.id,sessionId:n.sessionId});return{data:{mode:s.mode,url:`/apps/access/${s.mode}?token=${encodeURIComponent(s.token)}`,token:s.token,expiresAt:s.expiresAt}}}),e.delete("/api/controlled-instances/:id/apps/sessions/:sessionId/access",async e=>{const n=Su.parse(e.params),s=Fu.parse(e.body||{});return t.revokeAppSessionAccessToken(s.token,{instanceId:n.id,sessionId:n.sessionId}),{data:{revoked:!0}}}),e.get("/api/controlled-instances/:id/app-sessions",async e=>{const t=fu.parse(e.params),n=(await s.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=fu.parse(e.params);return{data:await t.listAiSessionHistory(n.id)}}),e.get("/api/controlled-instances/:id/ai-sessions/history/:sessionId",async e=>{const n=Su.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 s=Su.parse(e.params);Hu.parse(e.body||{});const i=await t.resumeAiSession(s.id,s.sessionId);return n.publish("instance.ai-session.resumed",{instanceId:s.id,sessionId:i.aiSessionId,providerSessionId:i.providerSessionId,appSessionId:i.appSessionId,disposition:i.disposition}),{data:i}}),e.post("/api/controlled-instances/:id/ai-sessions",async e=>{const s=fu.parse(e.params),i=ge.parse(e.body||{}),r=a.resolveRefs(i.attachments,s.id,i.clientRequestId),o=await t.createAiSession(s.id,{...i,attachments:r});return n.publish("instance.ai-session.created",{instanceId:s.id,sessionId:o.aiSessionId,providerSessionId:o.providerSessionId,clientRequestId:i.clientRequestId}),{data:o}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/open-app",async e=>{const s=Su.parse(e.params),i=me.parse(e.body||{}),r=await t.openAiSessionApp(s.id,s.sessionId,i.clientRequestId);return n.publish("instance.ai-session.app-opened",{instanceId:s.id,sessionId:s.sessionId,appSessionId:r.appSessionId}),{data:r}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/close",async e=>{const s=Su.parse(e.params),i=fe.parse(e.body||{}),r=await t.closeAiSession(s.id,s.sessionId,i.clientRequestId);return n.publish("instance.ai-session.closed",{instanceId:s.id,sessionId:s.sessionId,providerSessionId:r.providerSessionId}),{data:r}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/messages",async e=>{const s=Su.parse(e.params),i=pe.parse(e.body||{}),r=a.resolveRefs(i.attachments,s.id,s.sessionId),o=await t.sendAiSessionMessage(s.id,s.sessionId,i.message,i.mode,r,i.references,i.permissionMode);return n.publish("instance.ai-session.message-sent",{instanceId:s.id,sessionId:s.sessionId}),{data:o}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/mentions",async e=>{const n=Su.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=Su.parse(e.params),s=ae.parse(e.body||{});return{data:await t.searchAiSessionMentionFiles(n.id,n.sessionId,s.query)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/commands",async e=>{const s=Su.parse(e.params),i=X.parse(e.body||{}),r=await t.executeAiSessionCommand(s.id,s.sessionId,i);return n.publish("instance.ai-session.command-executed",{instanceId:s.id,sessionId:s.sessionId,command:i.command}),{data:r}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/queue",async e=>{const n=Su.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 s=Au.parse(e.params),i=await t.steerAiSessionQueuedMessage(s.id,s.sessionId,s.queueId);return n.publish("instance.ai-session.message-sent",{instanceId:s.id,sessionId:s.sessionId}),{data:i}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/:queueId/retry",async e=>{const n=Au.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=Au.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=Au.parse(e.params),s=we.parse(e.body||{});return{data:await t.editAiSessionQueuedMessage(n.id,n.sessionId,n.queueId,s)}}),e.patch("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/reorder",async e=>{const n=Su.parse(e.params),s=ve.parse(e.body||{});return{data:await t.reorderAiSessionQueuedMessages(n.id,n.sessionId,s)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/interrupt",async e=>{const s=Su.parse(e.params),i=await t.interruptAiSession(s.id,s.sessionId);return n.publish("instance.ai-session.interrupted",{instanceId:s.id,sessionId:s.sessionId}),{data:i}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/approval",async e=>{const s=Su.parse(e.params),i=be.parse(e.body||{}),r=await t.resolveAiSessionApproval(s.id,s.sessionId,i.decision);return n.publish("instance.ai-session.approval-resolved",{instanceId:s.id,sessionId:s.sessionId,decision:i.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 i.delta({instanceId:n.instanceId,streamId:n.streamId,sinceRevision:e})}:t.code(400).send({error:"stream_id_required"})}catch(e){if("AI_SESSION_DELTA_INSTANCE_ID_REQUIRED"===e.message)return t.code(400).send({error:"instance_id_required"});throw e}}const s=await i.list({refresh:"true"===n.refresh||"1"===n.refresh});for(const e of s.instances)r.reconcile(e.instanceId,e.aiSessions);return{data:{...s,instances:s.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 s=Su.parse(e.params),a=o.z.object({sessionUpdatedAt:o.z.string().datetime()}).strict().parse(e.body||{}),d=(await i.list()).instances.find(e=>e.instanceId===s.id),c=d?.aiSessions.sessions.find(e=>e.id===s.sessionId);if(!d||!c)return t.code(404).send({error:{code:"AI_SESSION_NOT_FOUND",message:"AI session was not found."}});r.reconcile(s.id,d.aiSessions);const l=r.markRead(s.id,s.sessionId,a.sessionUpdatedAt);return l?(n.publish(P,l,{topic:"ai.sessions",scope:{instanceId:s.id,sessionId:s.sessionId}}),{data:l}):t.code(404).send({error:{code:"AI_SESSION_NOT_FOUND",message:"AI session was not found."}})})}({app:t,service:n,events:s,appSessionAggregator:i,aiSessionAggregator:r,aiSessionUnread:a,aiSessionAttachments:c}),function({app:e,service:t,events:n}){e.get("/api/triggers",async()=>({data:await t.listTriggers()})),e.post("/api/triggers",async(e,s)=>{const i=t.createTrigger(e.body);return n.publish("trigger.created",{configHash:i.configHash}),s.code(201).send({data:i})}),e.put("/api/triggers/:configHash",async e=>{const s=ku.parse(e.params),i=await t.updateTrigger(s.configHash,e.body);return n.publish("trigger.updated",{previousConfigHash:s.configHash,configHash:i.trigger.configHash}),{data:i}}),e.delete("/api/triggers/:configHash",async e=>{const s=ku.parse(e.params),i=await t.deleteTrigger(s.configHash);return n.publish("trigger.deleted",{configHash:s.configHash}),{data:i}}),e.post("/api/triggers/:configHash/apply",async e=>{const s=ku.parse(e.params),i=await t.applyTrigger(s.configHash,e.body||{});return n.publish("trigger.applied",{configHash:s.configHash}),{data:i}}),e.get("/api/controlled-instances/:id/triggers",async e=>{const n=fu.parse(e.params);return{data:await t.listInstanceTriggers(n.id)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/triggers",async e=>{const s=Su.parse(e.params),i=await t.bindAiSessionTrigger(s.id,s.sessionId,e.body||{});return n.publish("trigger.deployment.bound",{instanceId:s.id,sessionId:s.sessionId},{topic:"triggers",scope:{instanceId:s.id}}),{data:i}}),e.delete("/api/controlled-instances/:id/ai-sessions/:sessionId/triggers/:configHash",async e=>{const s=Tu.parse(e.params),i=await t.unbindAiSessionTrigger(s.id,s.sessionId,s.configHash);return n.publish("trigger.deployment.unbound",{instanceId:s.id,sessionId:s.sessionId,configHash:s.configHash},{topic:"triggers",scope:{instanceId:s.id}}),{data:i}}),e.post("/api/controlled-instances/:id/triggers/:configHash/run",async e=>{const s=zu.parse(e.params),i=await t.runInstanceTrigger(s.id,s.configHash,e.body||{});return n.publish("trigger.run.requested",{instanceId:s.id,configHash:s.configHash},{topic:"triggers",scope:{instanceId:s.id}}),{data:i}})}({app:t,service:n,events:s}),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(fu.parse(e.params).id)})),e.get("/api/chat-gateway/status",async()=>({data:n.status()})),e.post("/api/chat-gateway/poll-ai-sessions",async()=>({data:await n.pollAiSessionsNow()})),e.get("/api/chat-gateway/bridges",async()=>({data:t.listChatBridges()})),e.post("/api/chat-gateway/bridges",async e=>({data:t.createChatBridge(e.body)})),e.patch("/api/chat-gateway/bridges/:id",async s=>{const i=fu.parse(s.params).id,r=t.requireChatBridge(i),o=za.parse(s.body),a=t.updateChatBridge(i,s.body),d="boolean"==typeof o.enabled?o.enabled:void 0;return e.log.info({component:"control-plane-chat-gateway",action:"bridge-patch",bridgeId:i,hasEnabled:void 0!==d,requestedEnabled:d,previousEnabled:r.enabled,updatedEnabled:t.requireChatBridge(i).enabled},"chat gateway bridge state changed"),void 0!==d&&d!==r.enabled&&(d?n.startBridge(i):n.stopBridge(i)),{data:a}}),e.post("/api/chat-gateway/bridges/:id/start",async s=>{const i=fu.parse(s.params).id,r=t.requireChatBridge(i);return t.updateChatBridge(i,{enabled:!0}),e.log.info({component:"control-plane-chat-gateway",action:"bridge-start-request",bridgeId:i,previousEnabled:r.enabled,updatedEnabled:t.requireChatBridge(i).enabled},"chat gateway bridge state changed"),{data:n.startBridge(i)}}),e.post("/api/chat-gateway/bridges/:id/stop",async s=>{const i=fu.parse(s.params).id,r=t.requireChatBridge(i);return t.updateChatBridge(i,{enabled:!1}),e.log.info({component:"control-plane-chat-gateway",action:"bridge-stop-request",bridgeId:i,previousEnabled:r.enabled,updatedEnabled:t.requireChatBridge(i).enabled},"chat gateway bridge state changed"),{data:n.stopBridge(i)}}),e.delete("/api/chat-gateway/bridges/:id",async e=>{const s=fu.parse(e.params).id;return n.stopBridge(s),{data:{deleted:t.deleteChatBridge(s)}}}),e.post("/api/chat-gateway/messages",{bodyLimit:67108864},async e=>({data:await t.handleChatGatewayMessage(vi.parse(e.body))})),e.post("/api/chat-gateway/actions",async e=>({data:await t.handleChatGatewayAction(Pu(e.body))})),e.get("/api/pending-routes",async()=>({data:await t.listPendingRoutes()}))}({app:t,service:n,chatGateway:d})}const Gu=new Set(["connection","content-length","keep-alive","proxy-authenticate","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),Vu=new Set(["authorization"]),Ku=new Set(["content-encoding"]);function Ju(e){return Object.fromEntries(Object.entries(e).flatMap(([e,t])=>{const n=e.toLowerCase();if(Gu.has(n)||Vu.has(n)||void 0===t)return[];const s=Array.isArray(t)?t.join(", "):String(t);if("cookie"!==n)return[[e,s]];const i=function(e){return e.split(";").map(e=>e.trim()).filter(e=>e&&e.slice(0,e.indexOf("=")).trim()!==Vi).join("; ")}(s);return i?[[e,i]]:[]}))}function Qu(e){return Object.fromEntries(Object.entries(Ju(e)).filter(([e])=>{const t=e.toLowerCase();return"host"!==t&&"cookie"!==t&&"authorization"!==t&&(!t.startsWith("sec-websocket-")||"sec-websocket-origin"===t)}))}function Yu(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 Xu(e,t,n,s,i={}){const r=new AbortController;return t.raw.once("close",()=>r.abort()),e.proxyInstanceHttp(n,s,{...i,signal:r.signal})}function Zu(e,t,n){for(const[n,s]of Object.entries(t.headers)){const t=n.toLowerCase();Gu.has(t)||Ku.has(t)||e.header(n,s)}if(!t.body)return e.code(t.status).send();const s=g.Readable.fromWeb(t.body);return e.raw.once("close",()=>s.destroy()),e.code(t.status).send(n?s.pipe(n):s)}function eg(e){return`/instances/${encodeURIComponent(e)}`}function tg(e,t,n,s){const i=function(e,t){const n=e.split("?",1)[0]||"/";return t.toLowerCase().includes("text/html")&&!n.startsWith("/api/")}(s,Object.entries(t.headers).find(([e])=>"content-type"===e.toLowerCase())?.[1]||"")?function(e){const t=[];let n=0,s=!1;const i=(i,r=!1)=>{if(s)return;const o=Buffer.concat(t,n).toString("utf8");!/<head(\s[^>]*)?>/i.exec(o)&&!r&&n<65536||(s=!0,i.push(function(e,t){if(e.includes("__TASK_HANDOFF_PUBLIC_BASE__"))return e;const n=`<script>window.__TASK_HANDOFF_PUBLIC_BASE__=${JSON.stringify(t)};<\/script>`;return/<head(\s[^>]*)?>/i.test(e)?e.replace(/<head(\s[^>]*)?>/i,e=>`${e}\n${n}`):`${n}\n${e}`}(o,e)),t.length=0,n=0)};return new g.Transform({transform(e,r,o){s?this.push(e):(t.push(Buffer.from(e)),n+=e.length,i(this)),o()},flush(e){i(this,!0),e()}})}(eg(n)):void 0;return Zu(e,t,i)}function ng(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 sg(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 ig(e){return new URL(e,"http://control-plane.local").searchParams.get("token")||""}function rg(e,t,n){const s=encodeURIComponent(e),i=encodeURIComponent(t),r=`apps/access/vnc/${s}/proxy`,o=n.vnc&&"object"==typeof n.vnc?n.vnc:{};return"kasmvnc"===("string"==typeof o.backend?o.backend:"")?`/${r}/api/apps/sessions/${i}/web/`:`/${r}/api/novnc/vnc.html?path=${encodeURIComponent(`${r}/api/apps/sessions/${i}/vnc`)}&autoconnect=1&resize=scale`}class og{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===_){const t=hr(He,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===x?Be:e.type===E?Ue:e.type===N?Fe:void 0;if(!t)return!1;const n=hr(t,e.payload);return n.success?e.type===x?this.applySnapshot(n.data):e.type===E?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:x,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:E,payload:e})}applyRemoved(e){return this.apply({type:N,payload:e})}async list(e={}){return(e.refresh||0===this.snapshots.size)&&await this.bootstrapFromInstances(),this.view()}async streamDescriptors(){return 0===this.snapshots.size&&await this.bootstrapFromInstances(),[...this.snapshots.entries()].map(([e,t])=>({topic:"ai.sessions",instanceId:e,streamId:t.streamId,latestRevision:t.revision,earliestRetainedRevision:this.history.get(e)?.[0]?.payload.meta.revision??t.revision+1}))}async delta(e){0===this.snapshots.size&&await this.bootstrapFromInstances();const t=this.resolveDeltaInstanceId(e.instanceId);this.pruneHistory(t);const n=this.snapshots.get(t)?.revision??0,s=this.snapshots.get(t)?.streamId||"unavailable",i=this.history.get(t)?.[0]?.payload.meta.revision??n+1;if(e.streamId!==s||e.sinceRevision>n)return We.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:!0,events:[]});if(e.sinceRevision===n)return We.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:!1,events:[]});const r=(this.history.get(t)??[]).filter(t=>t.payload.meta.revision>e.sinceRevision),o=!r.length||r[0].payload.meta.revision!==e.sinceRevision+1;return We.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:o,events:o?[]:r.map(({type:e,payload:t})=>({type:e,payload:t}))})}apply(e,t=!1){const{meta:n}=e.payload,s=this.advertisedStreams.get(n.instanceId)?.streamId;if(s&&s!==n.streamId)return this.logger?.warn?.({instanceId:n.instanceId,advertisedStreamId:s,streamId:n.streamId,revision:n.revision},"ai-session.aggregator.event.obsolete-stream"),!1;const i=this.recoveries.get(n.instanceId);if(i&&!t)return i.streamId===n.streamId&&(i.highWater=Math.max(i.highWater,n.revision)),!1;const r=this.snapshots.get(n.instanceId);e.type===x&&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===x)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:Me.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:t.payload.snapshot})};if(!e||e.streamId!==n.streamId)return{kind:"snapshot-required",projection:e,streamId:n.streamId};if(n.revision===e.revision)return{kind:"duplicate",projection:e};if(n.revision<e.revision)return{kind:"stale",projection:e};if(n.revision!==e.revision+1||n.previousRevision!==e.revision)return{kind:"gap",projection:e,expectedRevision:e.revision+1,receivedRevision:n.revision};const s=new Map(e.snapshot.sessions.map(e=>[e.id,e]));if(t.type===E){for(const e of t.payload.upserted)s.set(e.id,e);for(const e of t.payload.removed)s.delete(e)}else for(const e of t.payload.sessionIds)s.delete(e);const i=[...s.values()],r=je.parse({runningCount:i.filter(e=>"running"===e.status).length,waitingCount:i.filter(e=>"waiting"===e.status).length,staleCount:e.snapshot.staleCount,sessions:i,updatedAt:n.generatedAt});return{kind:"applied",projection:Me.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:r})}}(r,e);if("applied"!==o.kind)return this.logger?.warn?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,currentRevision:r?.revision,revision:n.revision,outcome:o.kind},`ai-session.aggregator.event.${o.kind}`),"gap"!==o.kind&&"snapshot-required"!==o.kind||("gap"===o.kind&&(this.counters.gaps+=1),this.recoverStream(n.instanceId,n.streamId,n.revision).catch(e=>{this.logger?.warn?.({instanceId:n.instanceId,streamId:n.streamId,revision:n.revision,error:e instanceof Error?e.message:String(e)},"ai-session.aggregator.recovery.failed")})),!1;const a=o.projection;this.snapshots.set(n.instanceId,a),this.rememberEvent(n.instanceId,e);const d={instanceId:n.instanceId,streamId:a.streamId,aiSessions:a.snapshot,revision:a.revision,lastEventAt:a.lastEventAt};for(const e of this.listeners)try{e(d)}catch{this.listeners.delete(e)}return this.logger?.info?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,revision:n.revision,reason:n.reason,sessionCount:a.snapshot.sessions.length},"ai-session.aggregator.event.accepted"),!0}async bootstrapFromInstances(){this.logger?.info?.({},"ai-session.aggregator.bootstrap");const e=new Map(this.snapshots),t=await this.bootstrap(),n=new Set(t.instances.map(e=>e.instanceId));for(const[t,s]of e)n.has(t)||this.snapshots.get(t)!==s||(this.snapshots.delete(t),this.history.delete(t),this.advertisedStreams.delete(t));for(const n of t.instances){const t=this.snapshots.get(n.instanceId);if(t!==e.get(n.instanceId))continue;const s=this.advertisedStreams.get(n.instanceId)?.streamId;s&&s!==n.streamId||t?.streamId===n.streamId&&t.revision>=n.revision||(t?.streamId!==n.streamId&&this.history.delete(n.instanceId),this.snapshots.set(n.instanceId,{streamId:n.streamId,snapshot:n.aiSessions,revision:n.revision,lastEventAt:n.lastEventAt}))}}recoverStream(e,t,n){const s=this.recoveries.get(e);if(s)return s.streamId===t?s.highWater=Math.max(s.highWater,n):(s.streamId=t,s.highWater=n),s.promise;if(!this.recoverDelta||!this.recoverSnapshot)return Promise.resolve();const i={promise:Promise.resolve(),streamId:t,highWater:n},r=++this.recoveryCount;return this.logger?.info?.({instanceId:e,highWater:n,recoveryNumber:r},"ai-session.aggregator.recovery.started"),i.promise=(async()=>{for(;;){const t=this.advertisedStreams.get(e);if(!t)return;i.streamId!==t.streamId&&(i.streamId=t.streamId,i.highWater=t.latestRevision);const n=this.snapshots.get(e);if(n&&n.streamId===t.streamId){if(n.revision<Math.max(t.latestRevision,i.highWater)){const t=await this.recoverDelta(e,n.streamId,n.revision);if(this.advertisedStreams.get(e)?.streamId!==t.streamId||i.streamId!==t.streamId)continue;if(t.syncRequired){const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:x,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`ais_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot-fallback"},"ai-session.aggregator.recovery.snapshot")}else{for(const e of t.events)this.apply(e,!0)&&this.onRecoveredEvent?.(e);this.counters.deltaRecoveries+=1,i.highWater=Math.max(i.highWater,t.latestRevision),this.logger?.info?.({instanceId:e,streamId:t.streamId,sinceRevision:t.sinceRevision,latestRevision:t.latestRevision,eventCount:t.events.length,recoveryNumber:r,outcome:"delta"},"ai-session.aggregator.recovery.delta")}}}else{const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:x,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`ais_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot"},"ai-session.aggregator.recovery.snapshot")}const s=this.snapshots.get(e),o=this.advertisedStreams.get(e);if(s&&o&&s.streamId===o.streamId&&s.revision>=Math.max(o.latestRevision,i.highWater))return void this.logger?.info?.({instanceId:e,streamId:s.streamId,revision:s.revision,recoveryNumber:r,outcome:"success"},"ai-session.aggregator.recovery.completed")}})().finally(()=>this.recoveries.delete(e)),this.recoveries.set(e,i),i.promise}rememberEvent(e,t){const n=this.history.get(e)??[],s=n.length&&n[0].payload.meta.streamId!==t.payload.meta.streamId?[]:n;s.push({...t,createdAtMs:Date.now()}),this.history.set(e,s),this.pruneHistory(e)}pruneHistory(e){const t=this.history.get(e);if(!t?.length)return;const n=t.filter(e=>e.createdAtMs>=Date.now()-36e5);n.length?this.history.set(e,n):this.history.delete(e)}resolveDeltaInstanceId(e){if(e)return e;const t=[...this.snapshots.keys()];if(1===t.length)return t[0];throw new Error("AI_SESSION_DELTA_INSTANCE_ID_REQUIRED")}view(){return{updatedAt:(new Date).toISOString(),instances:[...this.snapshots.entries()].map(([e,t])=>({instanceId:e,streamId:t.streamId,aiSessions:t.snapshot,revision:t.revision,lastEventAt:t.lastEventAt}))}}}const ag=o.z.object({id:o.z.string().trim().min(1),instanceId:o.z.string().trim().min(1).max(160),sessionId:o.z.string().trim().min(1).max(120),unread:o.z.boolean(),lastStatus:o.z.enum(["running","waiting","idle","failed"]),sessionUpdatedAt:o.z.string().datetime(),createdAt:o.z.string().datetime(),updatedAt:o.z.string().datetime()}).strict();class dg{records;bySession=new Map;listener;constructor(e,t={}){this.records=new Hi(e.aiSessionUnreadDir,{schema:ag}),this.listener=t.onChanged}init(){this.records.init(),this.bySession.clear();for(const e of this.records.list())this.bySession.set(lg(e.instanceId,e.sessionId),e)}reconcile(e,t){const n=new Set;for(const s of t.sessions)n.add(s.id),this.reconcileSession(e,s);for(const t of[...this.bySession.values()])t.instanceId!==e||n.has(t.sessionId)||this.deleteRecord(t)}decorate(e,t){return{...t,sessions:t.sessions.map(t=>({...t,unread:this.bySession.get(lg(e,t.id))?.unread||!1}))}}markRead(e,t,n){const s=this.bySession.get(lg(e,t));return s&&s.sessionUpdatedAt===n&&s.unread?cg(this.store({...s,unread:!1,updatedAt:(new Date).toISOString()},!1)):s?cg(s):void 0}removeInstance(e){for(const t of[...this.bySession.values()])t.instanceId===e&&this.deleteRecord(t)}reconcileSession(e,t){const n=lg(e,t.id),s=this.bySession.get(n),i=(new Date).toISOString();if(!s)return void this.store({id:pg(e,t.id),instanceId:e,sessionId:t.id,unread:!1,lastStatus:t.status,sessionUpdatedAt:t.updatedAt,createdAt:i,updatedAt:i},!1);const r=function(e,t,n){return"running"!==n&&"waiting"!==n&&("running"===t||"waiting"===t||e)}(s.unread,s.lastStatus,t.status),o=r!==s.unread;(o||s.lastStatus!==t.status||s.sessionUpdatedAt!==t.updatedAt)&&this.store({...s,unread:r,lastStatus:t.status,sessionUpdatedAt:t.updatedAt,updatedAt:i},o)}store(e,t){const n=this.records.put(e);return this.bySession.set(lg(n.instanceId,n.sessionId),n),t&&this.listener?.(cg(n)),n}deleteRecord(e){this.records.delete(e.id),this.bySession.delete(lg(e.instanceId,e.sessionId))}}function cg(e){return M.parse({instanceId:e.instanceId,sessionId:e.sessionId,unread:e.unread,sessionUpdatedAt:e.sessionUpdatedAt,updatedAt:e.updatedAt})}function lg(e,t){return`${e}\0${t}`}function pg(e,t){return`ais_unread_${a.createHash("sha256").update(lg(e,t)).digest("hex").slice(0,32)}`}class ug{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===xr?$r:e.type===Er?Br:e.type===Nr?Ur:void 0;if(!t)return!1;const n=hr(t,e.payload);return n.success?e.type===xr?this.applySnapshot(n.data):e.type===Er?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:xr,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:Er,payload:e})}applyRemoved(e){return this.apply({type:Nr,payload:e})}async list(e={}){return(e.refresh||0===this.snapshots.size)&&await this.bootstrapFromInstances(),this.view()}async streamDescriptors(){return 0===this.snapshots.size&&await this.bootstrapFromInstances(),[...this.snapshots.entries()].map(([e,t])=>({topic:"app.sessions",instanceId:e,streamId:t.streamId,latestRevision:t.revision,earliestRetainedRevision:this.history.get(e)?.[0]?.payload.meta.revision??t.revision+1}))}async delta(e){0===this.snapshots.size&&await this.bootstrapFromInstances();const t=this.resolveDeltaInstanceId(e.instanceId);this.pruneHistory(t);const n=this.snapshots.get(t)?.revision??0,s=this.snapshots.get(t)?.streamId||"unavailable",i=this.history.get(t)?.[0]?.payload.meta.revision??n+1;if(e.streamId!==s||e.sinceRevision>n)return Fr.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:!0,events:[]});if(e.sinceRevision===n)return Fr.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:!1,events:[]});const r=(this.history.get(t)??[]).filter(t=>t.payload.meta.revision>e.sinceRevision),o=!r.length||r[0].payload.meta.revision!==e.sinceRevision+1;return Fr.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:o,events:o?[]:r.map(({type:e,payload:t})=>({type:e,payload:t}))})}apply(e,t=!1){const{meta:n}=e.payload,s=this.advertisedStreams.get(n.instanceId)?.streamId;if(s&&s!==n.streamId)return this.logger?.warn?.({instanceId:n.instanceId,advertisedStreamId:s,streamId:n.streamId,revision:n.revision},"app-session.aggregator.event.obsolete-stream"),!1;const i=this.recoveries.get(n.instanceId);if(i&&!t)return i.streamId===n.streamId&&(i.highWater=Math.max(i.highWater,n.revision)),!1;const r=this.snapshots.get(n.instanceId);e.type===xr&&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===xr)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:Dr.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:Wr(t.payload.snapshot.sessions,t.payload.snapshot.updatedAt)})};if(!e||e.streamId!==n.streamId)return{kind:"snapshot-required",projection:e,streamId:n.streamId};if(n.revision===e.revision)return{kind:"duplicate",projection:e};if(n.revision<e.revision)return{kind:"stale",projection:e};if(n.revision!==e.revision+1||n.previousRevision!==e.revision)return{kind:"gap",projection:e,expectedRevision:e.revision+1,receivedRevision:n.revision};const s=[...e.snapshot.sessions];if(t.type===Er){const e=s.findIndex(e=>e.id===t.payload.session.id);Kr(t.payload.session.status)?e<0?s.push(t.payload.session):s[e]=t.payload.session:e>=0&&s.splice(e,1)}else{const e=s.findIndex(e=>e.id===t.payload.sessionId);e>=0&&s.splice(e,1)}const i=Hr(s,n.generatedAt);return{kind:"applied",projection:Dr.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:i})}}(r,e);if("applied"!==o.kind)return this.logger?.warn?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,currentRevision:r?.revision,revision:n.revision,outcome:o.kind},`app-session.aggregator.event.${o.kind}`),"gap"!==o.kind&&"snapshot-required"!==o.kind||("gap"===o.kind&&(this.counters.gaps+=1),this.recoverStream(n.instanceId,n.streamId,n.revision).catch(e=>{this.logger?.warn?.({instanceId:n.instanceId,streamId:n.streamId,revision:n.revision,error:e instanceof Error?e.message:String(e)},"app-session.aggregator.recovery.failed")})),!1;const a=o.projection;return this.snapshots.set(n.instanceId,a),this.rememberEvent(n.instanceId,e),this.logger?.info?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,revision:n.revision,reason:n.reason,sessionCount:a.snapshot.sessions.length,runningCount:a.snapshot.runningCount,problemCount:a.snapshot.problemCount},"app-session.aggregator.event.accepted"),!0}async bootstrapFromInstances(){this.logger?.info?.({},"app-session.aggregator.bootstrap");const e=new Map(this.snapshots),t=await this.bootstrap(),n=new Set(t.instances.map(e=>e.instanceId));for(const[t,s]of e)n.has(t)||this.snapshots.get(t)!==s||(this.snapshots.delete(t),this.history.delete(t),this.advertisedStreams.delete(t));for(const n of t.instances){const t=this.snapshots.get(n.instanceId);if(t!==e.get(n.instanceId))continue;const s=this.advertisedStreams.get(n.instanceId)?.streamId;s&&s!==n.streamId||t?.streamId===n.streamId&&t.revision>=n.revision||(t?.streamId!==n.streamId&&this.history.delete(n.instanceId),this.snapshots.set(n.instanceId,{streamId:n.streamId,snapshot:Wr(n.appSessions.sessions,n.appSessions.updatedAt),revision:n.revision,lastEventAt:n.lastEventAt}))}}recoverStream(e,t,n){const s=this.recoveries.get(e);if(s)return s.streamId===t?s.highWater=Math.max(s.highWater,n):(s.streamId=t,s.highWater=n),s.promise;if(!this.recoverDelta||!this.recoverSnapshot)return Promise.resolve();const i={promise:Promise.resolve(),streamId:t,highWater:n},r=++this.recoveryCount;return this.logger?.info?.({instanceId:e,highWater:n,recoveryNumber:r},"app-session.aggregator.recovery.started"),i.promise=(async()=>{for(;;){const t=this.advertisedStreams.get(e);if(!t)return;i.streamId!==t.streamId&&(i.streamId=t.streamId,i.highWater=t.latestRevision);const n=this.snapshots.get(e);if(n&&n.streamId===t.streamId){if(n.revision<Math.max(t.latestRevision,i.highWater)){const t=await this.recoverDelta(e,n.streamId,n.revision);if(this.advertisedStreams.get(e)?.streamId!==t.streamId||i.streamId!==t.streamId)continue;if(t.syncRequired){const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:xr,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`aps_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot-fallback"},"app-session.aggregator.recovery.snapshot")}else{for(const e of t.events)this.apply(e,!0)&&this.onRecoveredEvent?.(e);this.counters.deltaRecoveries+=1,i.highWater=Math.max(i.highWater,t.latestRevision),this.logger?.info?.({instanceId:e,streamId:t.streamId,sinceRevision:t.sinceRevision,latestRevision:t.latestRevision,eventCount:t.events.length,recoveryNumber:r,outcome:"delta"},"app-session.aggregator.recovery.delta")}}}else{const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:xr,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`aps_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot"},"app-session.aggregator.recovery.snapshot")}const s=this.snapshots.get(e),o=this.advertisedStreams.get(e);if(s&&o&&s.streamId===o.streamId&&s.revision>=Math.max(o.latestRevision,i.highWater))return void this.logger?.info?.({instanceId:e,streamId:s.streamId,revision:s.revision,recoveryNumber:r,outcome:"success"},"app-session.aggregator.recovery.completed")}})().finally(()=>this.recoveries.delete(e)),this.recoveries.set(e,i),i.promise}rememberEvent(e,t){const n=this.history.get(e)??[],s=n.length&&n[0].payload.meta.streamId!==t.payload.meta.streamId?[]:n;s.push({...t,createdAtMs:Date.now()}),this.history.set(e,s),this.pruneHistory(e)}pruneHistory(e){const t=this.history.get(e);if(!t?.length)return;const n=t.filter(e=>e.createdAtMs>=Date.now()-36e5);n.length?this.history.set(e,n):this.history.delete(e)}resolveDeltaInstanceId(e){if(e)return e;const t=[...this.snapshots.keys()];if(1===t.length)return t[0];throw new Error("APP_SESSION_DELTA_INSTANCE_ID_REQUIRED")}view(){return{updatedAt:(new Date).toISOString(),instances:[...this.snapshots.entries()].map(([e,t])=>({instanceId:e,streamId:t.streamId,appSessions:t.snapshot,revision:t.revision,lastEventAt:t.lastEventAt}))}}}function gg(e){return e.raw[0].replace(/\\\$\{/g,"${")}class hg{states=new Map;events;constructor(e){this.events=e}handle(e){if(e.type===ui){const t=hr(gi,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===Ds){const t=hr($s,e.payload);return void(t.success&&this.applyOutput(t.data))}if(e.type===qs){const t=hr(Bs,e.payload);t.success&&this.applyFinished(t.data)}}snapshots(){return[...this.states.values()].filter(e=>e.progress).map(e=>Us.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 Ig,n.terminalTail="",n.layers.clear(),n.terminalTruncated=!1),n.sequence=Math.max(n.sequence,e.sequence),n.observedAt=e.observedAt,n.terminal.write(e.data);const s=`${n.terminalTail}${e.data}`;n.terminalTruncated||=s.length>262144,n.terminalTail=s.slice(-262144),function(e,t){for(const n of t.split("\n")){const t=n.trim().match(/^([a-f0-9]{6,64}):\s+(.+)$/i);if(!t)continue;const[,s,i]=t,r=i.toLowerCase(),o=["pull complete","already exists","download complete","pulling fs layer","waiting","downloading","extracting"].find(e=>r.startsWith(e));if(!o)continue;const a=e.get(s)||{status:o},d=yg(i);e.set(s,{...a,status:o,...d||{}})}}(n.layers,n.terminal.text()),n.progress=mg(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=mg(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 Ig,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=mg(e),this.events.publish("image.pull.progress",e.progress,{topic:"instances",scope:{instanceId:e.identity.instanceId}}),t&&(e.progress=mg(e)))}}function mg(e){const t=[...e.layers.values()],n=t.filter(e=>["pull complete","already exists"].includes(e.status)).length,s=t.filter(e=>"download complete"===e.status).length,i=t.filter(e=>"downloading"===e.status).length,r=t.filter(e=>"extracting"===e.status).length;let o=0,a=0;for(const e of t)e.total&&(a+=e.total,o+=["pull complete","already exists","download complete"].includes(e.status)?e.total:Math.min(e.current||0,e.total));const d="failed"===e.outcome?"failed":"succeeded"===e.outcome?"complete":r>0?"extracting":t.length>0?"pulling":"connecting",c=t.filter(e=>"already exists"!==e.status),l=c.length>0&&c.every(e=>Boolean(e.total)),p=l&&a>0?Math.max(0,Math.min(100,o/a*100)):void 0,u="failed"===d?"Image pull failed":"complete"===d?"Image pull complete":t.length?`${n}/${t.length} layers ready${void 0===p?"":` · ${Math.round(p)}%`}`:"Connecting to image registry";return Us.parse({...e.identity,sequence:e.sequence,observedAt:e.observedAt,status:d,layers:{total:t.length,completed:n,downloaded:s,downloading:i,extracting:r},...l&&a>0?{bytes:{current:o,total:a},percent:p}:{},message:u})}function yg(e){const t=e.match(/([\d.]+)\s*([kmgt]?i?b)\s*\/\s*([\d.]+)\s*([kmgt]?i?b)/i);if(t)return{current:fg(t[1],t[2]),total:fg(t[3],t[4])}}function fg(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 Ig{lines=[[]];row=0;col=0;pending="";write(e){const t=`${this.pending}${e}`;this.pending="";for(let e=0;e<t.length;){const n=t[e];if(""===n&&"["===t[e+1]){let n=e+2;for(;n<t.length&&!/[\x40-\x7e]/.test(t[n]);)n+=1;if(n>=t.length){this.pending=t.slice(e);break}this.csi(t.slice(e+2,n),t[n]),e=n+1;continue}"\r"===n?this.col=0:"\n"===n?(this.row+=1,this.col=0,this.ensureLine()):"\b"===n?this.col=Math.max(0,this.col-1):n>=" "&&(this.ensureLine(),this.lines[this.row][this.col]=n,this.col+=1),e+=1}this.trim()}text(){return this.lines.map(e=>e.join("").trimEnd()).join("\n")}csi(e,t){const n=e.replace(/^\?/,"").split(";").map(e=>Number(e||1)),s=n[0]||1;"A"===t?this.row=Math.max(0,this.row-s):"B"===t?(this.row+=s,this.ensureLine()):"C"===t?this.col+=s:"D"===t?this.col=Math.max(0,this.col-s):"G"===t?this.col=Math.max(0,s-1):"H"===t||"f"===t?(this.row=Math.max(0,s-1),this.col=Math.max(0,(n[1]||1)-1),this.ensureLine()):"K"===t?(this.ensureLine(),2===(n[0]||0)?this.lines[this.row]=[]:this.lines[this.row].splice(this.col)):"J"===t&&2===(n[0]||0)&&(this.lines=[[]],this.row=0,this.col=0)}ensureLine(){for(;this.lines.length<=this.row;)this.lines.push([])}trim(){if(this.lines.length<=500)return;const e=this.lines.length-500;this.lines.splice(0,e),this.row=Math.max(0,this.row-e)}}const bg=o.z.object({revision:o.z.number().int().nonnegative(),invites:o.z.array(Nt),bindings:o.z.array(jt)}).strict(),vg={invite:new Set(Object.keys(Nt.shape)),binding:new Set(Object.keys(jt.shape))};function wg(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 Sg(e,t,n){if(!t||"object"!=typeof t||Array.isArray(t))return t;const s=t,i=vg[e],r=Object.keys(s).filter(e=>!i.has(e));r.length>0&&n?.({kind:e,fields:r});const o=wg(s,i);return"binding"===e&&o.lastError&&(o.lastError=wg(o.lastError,Object.keys(xt.shape))),o}function Ag(e){const{tokenHash:t,...n}=e;return _t.parse(n)}function kg(e){const{credentialHash:t,...n}=e;return Mt.parse(n)}class zg{authority;constructor(e,t){this.authority=new Wi(e,()=>({revision:0,invites:[],bindings:[]}),{schema:bg,sanitize:e=>function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,s=new Set(["revision","invites","bindings"]),i=Object.keys(n).filter(e=>!s.has(e));return i.length>0&&t?.({kind:"authority",fields:i}),{...void 0===n.revision?{}:{revision:n.revision},invites:Array.isArray(n.invites)?n.invites.map(e=>Sg("invite",e,t)):n.invites,bindings:Array.isArray(n.bindings)?n.bindings.map(e=>Sg("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),s=e(n);return JSON.stringify(n)!==JSON.stringify(t)&&this.authority.put({...n,revision:t.revision+1}),s}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 Tg extends Error{code;statusCode;retryable;details;constructor(e,t,n,s=!1,i={}){super(t),this.name="ControlPlaneProxyServiceError",this.code=e,this.statusCode=n,this.retryable=s,this.details=i}}const Cg=e=>a.createHash("sha256").update(e).digest("base64url"),xg=()=>a.randomBytes(32).toString("base64url");function Eg(e,t){const n=Cg(t),s=Buffer.from(e),i=Buffer.from(n);return s.length===i.length&&a.timingSafeEqual(s,i)}function Ng(e,t,n,s=!1,i={}){throw new Tg(e,t,n,s,i)}class _g{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??xg}init(){this.store.init(),this.expireInvites()}createInvite(e,t){const n=this.resolveProxyOrigin();n||Ng(Tt.Unavailable,"Configure an externally reachable HTTPS control-plane proxy origin before creating an invite.",409,!1);const s=Pt.parse(e);this.requireManageableTarget(s.targetNodeId);const i=this.createTokenValue(),r=this.nowIso(),o={id:Ui("proxy_invite"),targetNodeId:s.targetNodeId,tokenHash:Cg(i),status:"active",createdBy:t,expiresAt:new Date(this.now().getTime()+1e3*s.expiresInSeconds).toISOString(),createdAt:r,updatedAt:r},a=Rt.parse({invite:Ag(o),token:i,proxyOrigin:n,protocolVersion:ut});return this.store.transaction(e=>e.invites.push(o)),a}resolveProxyOrigin(){const e=this.configuredProxyOrigin??this.proxyOriginProvider?.();if(!e)return;const t=It.safeParse(e);return t.success?t.data:void 0}listInvites(){return this.expireInvites(),this.store.listInvites().map(Ag)}revokeInvite(e){const t=this.requireInvite(e);if("consumed"===t.status&&Ng(Tt.InviteConsumed,"A consumed proxy invite cannot be revoked independently of its binding.",409,!1,{inviteId:e}),"revoked"===t.status||"expired"===t.status)return Ag(t);const n=this.nowIso(),s={...t,status:"revoked",revokedAt:n,updatedAt:n};return this.store.transaction(t=>{t.invites[t.invites.findIndex(t=>t.id===e)]=s}),Ag(s)}claimInvite(e){const t=Dt.parse(e);this.requireCurrentProtocol(t.protocolVersion),this.expireInvites();const n=Cg(t.credential);return this.store.transaction(e=>{const s=e.bindings.find(e=>e.claimId===t.claimId);if(!t.inviteToken)return s||Ng(Tt.InviteInvalid,"Proxy invite token is required for the first claim.",401),(s.sourceControlPlaneId!==t.sourceControlPlaneId||s.bindingKeyId!==t.bindingKeyId||s.credentialHash!==n||void 0!==t.targetNodeId&&s.targetNodeId!==t.targetNodeId)&&Ng(Tt.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:t.claimId}),"revoked"===s.status&&Ng(Tt.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:s.id}),this.claimResult(s,this.requireKnownTarget(s.targetNodeId));const i=e.invites.find(e=>Eg(e.tokenHash,t.inviteToken));i||Ng(Tt.InviteInvalid,"Proxy invite is invalid.",401),t.targetNodeId&&t.targetNodeId!==i.targetNodeId&&Ng(Tt.TargetMismatch,"Proxy invite is bound to a different target.",409,!1,{inviteId:i.id,targetNodeId:t.targetNodeId});const r=(o=i.id,`proxy_binding_${Cg(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&&Ng(Tt.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:t.claimId}),c)return this.requireExactIdentity(c,r,i.targetNodeId,t,n),"revoked"===c.status&&Ng(Tt.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:c.id}),"consumed"===i.status&&i.consumedByClaimId===t.claimId||Ng(Tt.BindingIdentityConflict,"Proxy binding and invite authority are inconsistent.",409,!1,{claimId:t.claimId}),this.claimResult(c,this.requireKnownTarget(c.targetNodeId));this.requireClaimableInvite(i);const l=this.requireManageableTarget(i.targetNodeId),p=this.nowIso(),u={id:r,claimId:t.claimId,sourceControlPlaneId:t.sourceControlPlaneId,targetNodeId:i.targetNodeId,bindingKeyId:t.bindingKeyId,credentialHash:n,status:"active",revision:1,createdAt:p,updatedAt:p};return e.bindings.push(u),Object.assign(i,{status:"consumed",consumedByClaimId:t.claimId,consumedAt:p,updatedAt:p}),this.claimResult(u,l)})}listBindings(){return this.store.listBindings().map(kg)}authenticateBinding(e,t){const n=qt.parse(t),s=this.store.getBinding(e);return s||Ng(Tt.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),"active"!==s.status&&Ng(Tt.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:e}),s.sourceControlPlaneId===n.sourceControlPlaneId&&s.bindingKeyId===n.bindingKeyId&&Eg(s.credentialHash,n.credential)||Ng(Tt.AuthenticationFailed,"Proxy binding authentication failed.",401,!1,{bindingId:e}),kg(s)}revokeBinding(e){const t=this.requireBinding(e);if("revoked"===t.status)return kg(t);const n=this.nowIso(),s={...t,status:"revoked",revision:t.revision+1,revokedAt:n,updatedAt:n};return this.store.transaction(t=>{t.bindings[t.bindings.findIndex(t=>t.id===e)]=s}),kg(s)}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}),kg(e))),invites:t.invites.filter(t=>t.targetNodeId===e&&"active"===t.status).map(e=>(Object.assign(e,{status:"revoked",revokedAt:n,updatedAt:n}),Ag(e)))}})}nowIso(){return this.now().toISOString()}requireCurrentProtocol(e){e!==ut&&Ng(Tt.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:e,supportedVersion:ut})}requireKnownTarget(e){const t=this.targets.get(e);return t||Ng(Tt.TargetUnavailable,"Proxy target no longer exists.",404,!1,{targetNodeId:e}),t}requireManageableTarget(e){const t=this.requireKnownTarget(e);return t.manageable&&"online"===t.status||Ng(Tt.TargetUnavailable,"Proxy target is not currently manageable.",503,!0,{targetNodeId:e}),t}requireInvite(e){const t=this.store.getInvite(e);return t||Ng(Tt.InviteInvalid,"Proxy invite is unknown.",404,!1,{inviteId:e}),t}requireBinding(e){const t=this.store.getBinding(e);return t||Ng(Tt.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),t}requireClaimableInvite(e){"active"!==e.status&&Ng({expired:Tt.InviteExpired,consumed:Tt.InviteConsumed,revoked:Tt.InviteRevoked}[e.status],`Proxy invite is ${e.status}.`,"expired"===e.status?410:409,!1,{inviteId:e.id})}requireExactIdentity(e,t,n,s,i){e.id===t&&e.claimId===s.claimId&&e.sourceControlPlaneId===s.sourceControlPlaneId&&e.targetNodeId===n&&e.bindingKeyId===s.bindingKeyId&&e.credentialHash===i||Ng(Tt.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:s.claimId})}claimResult(e,t){const{manageable:n,...s}=t;return Wt.parse({protocolVersion:ut,binding:kg(e),target:s})}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 s of t.invites)"active"===s.status&&Date.parse(s.expiresAt)<=e&&(s.status="expired",s.updatedAt=n)})}}class Pg extends Error{statusCode=429;code=Tt.ResourceLimit;retryable=!0;details;constructor(e,t){super(e),this.name="NodeProxyRuntimeError",this.details=t}}class Rg{maxRequestBodyBytes;maxConcurrentHttpPerBinding;maxConcurrentStreamsPerBinding;maxHttpRequestsPerMinutePerBinding;maxConcurrentWebSocketsPerBinding;maxHttpResponseBytes;httpStreamIdleTimeoutMs;maxWebSocketFrameBytes;maxWebSocketBytes;webSocketIdleTimeoutMs;httpRequestWindowMs;bindings=new Map;requestWindows=new Map;requestWindowTimers=new Map;constructor(e={}){this.maxConcurrentHttpPerBinding=e.maxConcurrentHttpPerBinding??32,this.maxConcurrentStreamsPerBinding=e.maxConcurrentStreamsPerBinding??16,this.maxHttpRequestsPerMinutePerBinding=e.maxHttpRequestsPerMinutePerBinding??600,this.maxConcurrentWebSocketsPerBinding=e.maxConcurrentWebSocketsPerBinding??16,this.maxRequestBodyBytes=e.maxRequestBodyBytes??8388608,this.maxHttpResponseBytes=e.maxHttpResponseBytes??268435456,this.httpStreamIdleTimeoutMs=e.httpStreamIdleTimeoutMs??12e4,this.maxWebSocketFrameBytes=e.maxWebSocketFrameBytes??8388608,this.maxWebSocketBytes=e.maxWebSocketBytes??268435456,this.webSocketIdleTimeoutMs=e.webSocketIdleTimeoutMs??3e5,this.httpRequestWindowMs=e.httpRequestWindowMs??6e4}reserveHttp(e){this.consumeRequestRate(e);const t=this.activity(e);if(t.controllers.size>=this.maxConcurrentHttpPerBinding)throw this.deleteIfEmpty(e,t),this.limit("Proxy HTTP concurrency limit exceeded.",e,"http-concurrency",this.maxConcurrentHttpPerBinding);const n=new AbortController;t.controllers.add(n);let s,i=!1,r=!1,o=0;const a=()=>{r&&!i&&(s&&clearTimeout(s),s=setTimeout(()=>{n.abort(Object.assign(new Error("Proxy HTTP stream idle timeout."),{code:Tt.ResourceLimit}))},this.httpStreamIdleTimeoutMs),s.unref?.())};return{controller:n,acceptRequestBody:t=>{if(t>this.maxRequestBodyBytes)throw this.limit("Proxy request body limit exceeded.",e,"request-body",this.maxRequestBodyBytes)},beginResponseStream:()=>{if(!i&&!r){if(t.streams.size>=this.maxConcurrentStreamsPerBinding)throw this.limit("Proxy HTTP stream concurrency limit exceeded.",e,"stream-concurrency",this.maxConcurrentStreamsPerBinding);r=!0,t.streams.add(n),a()}},acceptResponseChunk:t=>{if(!i){if(o+=Og(t),o>this.maxHttpResponseBytes){const t=this.limit("Proxy HTTP response byte limit exceeded.",e,"response-bytes",this.maxHttpResponseBytes);throw n.abort(t),t}a()}},release:()=>{i||(i=!0,s&&clearTimeout(s),t.controllers.delete(n),t.streams.delete(n),this.deleteIfEmpty(e,t))}}}openHttp(e,t){const n=this.reserveHttp(e);try{return n.acceptRequestBody(t),n}catch(e){throw n.release(),e}}openWebSocket(e,t,n){const s=this.activity(e);if(s.sockets.size>=this.maxConcurrentWebSocketsPerBinding)throw this.limit("Proxy WebSocket concurrency limit exceeded.",e,"websocket-concurrency",this.maxConcurrentWebSocketsPerBinding);let i,r=!1,o=0;const a=()=>{r||(r=!0,i&&clearTimeout(i),s.sockets.delete(p),this.deleteIfEmpty(e,s),n?.())},d=e=>{a(),t.close(1009,e)},c=()=>{i&&clearTimeout(i),i=setTimeout(()=>{a(),t.close(1001,"Proxy WebSocket idle timeout.")},this.webSocketIdleTimeoutMs),i.unref?.()},l=e=>{const t=Og(e);return t>this.maxWebSocketFrameBytes?(d("Proxy WebSocket frame limit exceeded."),!1):(o+=t,o>this.maxWebSocketBytes?(d("Proxy WebSocket byte limit exceeded."),!1):(c(),!0))};c();const p={get readyState(){return t.readyState},send:e=>{!r&&l(e)&&t.send(e)},close:(e,n)=>{a(),t.close(e,n)},on:(e,n)=>{"message"!==e?"close"!==e&&"error"!==e?t.on(e,n):t.on(e,(...e)=>{a(),n(...e)}):t.on(e,(e,...t)=>{!r&&l(e)&&n(e,...t)})}};return s.sockets.add(p),p}closeBinding(e,t="Proxy binding was revoked."){const n=this.bindings.get(e);if(!n)return this.clearRequestWindow(e),{abortedRequests:0,closedSockets:0};const s=[...n.controllers],i=[...n.sockets],r=[...n.cleanup];this.bindings.delete(e);for(const e of s)e.abort(Object.assign(new Error(t),{code:Tt.BindingRevoked}));for(const e of r)e();for(const e of i)e.close(1008,t);return n.controllers.clear(),n.streams.clear(),n.sockets.clear(),n.cleanup.clear(),this.clearRequestWindow(e),{abortedRequests:s.length,closedSockets:i.length}}diagnostics(e){if(e){const t=this.bindings.get(e);return{bindingId:e,activeHttp:t?.controllers.size??0,activeStreams:t?.streams.size??0,activeWebSockets:t?.sockets.size??0}}return[...this.bindings].map(([e,t])=>({bindingId:e,activeHttp:t.controllers.size,activeStreams:t.streams.size,activeWebSockets:t.sockets.size}))}registerBindingCleanup(e,t){const n=this.activity(e);return n.cleanup.add(t),()=>{n.cleanup.delete(t),this.deleteIfEmpty(e,n)}}activity(e){const t=this.bindings.get(e);if(t)return t;const n={controllers:new Set,streams:new Set,sockets:new Set,cleanup:new Set};return this.bindings.set(e,n),n}deleteIfEmpty(e,t){0===t.controllers.size&&0===t.streams.size&&0===t.sockets.size&&0===t.cleanup.size&&this.bindings.get(e)===t&&this.bindings.delete(e)}limit(e,t,n,s){return new Pg(e,{bindingId:t,resource:n,limit:s})}consumeRequestRate(e){const t=Date.now(),n=t-this.httpRequestWindowMs,s=(this.requestWindows.get(e)||[]).filter(e=>e>n);if(s.length>=this.maxHttpRequestsPerMinutePerBinding)throw this.limit("Proxy HTTP request rate limit exceeded.",e,"request-rate",this.maxHttpRequestsPerMinutePerBinding);s.push(t),this.requestWindows.set(e,s),this.scheduleRequestWindowCleanup(e)}scheduleRequestWindowCleanup(e){const t=this.requestWindowTimers.get(e);t&&clearTimeout(t);const n=this.requestWindows.get(e);if(!n?.length)return this.requestWindows.delete(e),void this.requestWindowTimers.delete(e);const s=Math.max(1,n[0]+this.httpRequestWindowMs-Date.now()+1),i=setTimeout(()=>{this.requestWindowTimers.delete(e);const t=Date.now()-this.httpRequestWindowMs,n=(this.requestWindows.get(e)||[]).filter(e=>e>t);n.length?(this.requestWindows.set(e,n),this.scheduleRequestWindowCleanup(e)):this.requestWindows.delete(e)},s);i.unref?.(),this.requestWindowTimers.set(e,i)}clearRequestWindow(e){this.requestWindows.delete(e);const t=this.requestWindowTimers.get(e);t&&clearTimeout(t),this.requestWindowTimers.delete(e)}}function Og(e){return Buffer.isBuffer(e)||e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:Buffer.byteLength("string"==typeof e?e:String(e),"utf8")}class jg{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}_${a.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:Mg(t)}}subscribe(e,t,n,s=()=>{}){const{bindingId:i,sourceControlPlaneId:r,targetNodeId:o}=e,a=this.stream(o),d=Mg(a);if(t>a.revision||t<d-1)return n(Ft.parse({type:"control-plane-proxy.snapshot-required",protocolVersion:ut,streamId:a.streamId,bindingId:i,sourceControlPlaneId:r,targetNodeId:o,sinceRevision:t,latestRevision:a.revision,earliestRetainedRevision:d,error:{code:Tt.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(Ut.parse({type:"control-plane-proxy.events.ready",protocolVersion:ut,streamId:a.streamId,bindingId:i,sourceControlPlaneId:r,targetNodeId:o,latestRevision:a.revision,earliestRetainedRevision:d}));for(const e of a.history)e.event.revision>t&&n(Dg(e.event,i,r));const c={bindingId:i,sourceControlPlaneId:r,send:n,onDeliveryFailure:s};a.subscribers.add(c);let l=!1;return{kind:"subscribed",close:()=>{l||(l=!0,a.subscribers.delete(c))}}}diagnostics(e){const t=this.stream(e);return{targetNodeId:e,streamId:t.streamId,revision:t.revision,earliestRetainedRevision:Mg(t),historySize:t.history.length,historyBytes:t.historyBytes,subscribers:t.subscribers.size,subscriberBindings:[...t.subscribers].map(({bindingId:e,sourceControlPlaneId:t})=>({bindingId:e,sourceControlPlaneId:t}))}}accept(e){const t=e.scope?.nodeId;if("string"!=typeof t||!t)return;let n;try{n=this.projectTarget(t)}catch{return}if(!n)return;const s=this.stream(t),i=s.revision+1,r=Bt.safeParse({type:"control-plane-proxy.event",protocolVersion:ut,streamId:s.streamId,bindingId:"proxy_projection",sourceControlPlaneId:"proxy_projection",targetNodeId:t,revision:i,source:{id:e.id,seq:e.seq},target:n,event:{type:e.type,topic:e.topic,createdAt:e.createdAt}});if(!r.success)return;const{bindingId:o,sourceControlPlaneId:a,...d}=r.data,c=qg(d);if(!(void 0===c||c>this.maxEventBytes-512)){for(s.revision=i,s.history.push({event:d,bytes:c}),s.historyBytes+=c;s.history.length>this.historyLimit||s.historyBytes>this.maxHistoryBytes;){const e=s.history.shift();e&&(s.historyBytes-=e.bytes)}for(const e of[...s.subscribers])try{const t=Dg(d,e.bindingId,e.sourceControlPlaneId),n=qg(t);if(void 0===n||n>this.maxEventBytes)throw new Error("Proxy event byte limit exceeded.");e.send(t)}catch{s.subscribers.delete(e);try{e.onDeliveryFailure()}catch{}}}}stream(e){const t=this.streams.get(e);if(t)return t;const n={streamId:this.createStreamId(e),revision:0,history:[],historyBytes:0,subscribers:new Set};return this.streams.set(e,n),n}}function Mg(e){return e.history[0]?.event.revision??e.revision+1}function Dg(e,t,n){return Bt.parse({...e,bindingId:t,sourceControlPlaneId:n})}function qg(e){try{return Buffer.byteLength(JSON.stringify(e),"utf8")}catch{return}}function Lg(e,t){const n=new WeakSet;let s=t,i=0;const r=e=>{if(s-=Buffer.byteLength(e,"utf8"),s<0)throw $g("Proxy target projection byte limit exceeded.",{resource:"target-projection-bytes",limit:t})},o=(e,t)=>{if(i+=1,i>16384||t>24)throw $g("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 $g("Proxy target projection contains a cycle.",void 0,!1);if(n.add(e),Array.isArray(e)){const s=e.map(e=>o(e,t+1)??null);return n.delete(e),s}const s={};for(const[n,i]of Object.entries(e)){if("__proto__"===n||"constructor"===n||"prototype"===n)continue;r(n);const e=o(i,t+1);void 0!==e&&(s[n]=e)}return n.delete(e),s};return o(e,0)}function $g(e,t,n=!0){return Object.assign(new Error(e),{code:"CONTROL_PLANE_PROXY_RESOURCE_LIMIT",statusCode:429,retryable:n,...t?{details:t}:{}})}function Bg(e){const{manageable:t,...n}=e;return n}const Ug=o.z.object({bindingId:o.z.string().trim().min(1).max(160)}).passthrough(),Fg=o.z.object({route:bt}).strict(),Hg=o.z.object({sinceRevision:o.z.coerce.number().int().nonnegative()}).strict(),Wg=new Set(["connection","cookie","host","keep-alive","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),Gg=524288;function Vg(e,t,n){const s=eh(n.headers,St);if(s!==ut)throw Zg(Tt.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:s,supportedVersion:ut});const i=eh(n.headers,At),r=eh(n.headers,kt),o=eh(n.headers,zt);if(!i||!r||!o)throw Zg(Tt.AuthenticationFailed,"Proxy binding authentication headers are incomplete.",401);return e.authenticateBinding(t,{sourceControlPlaneId:i,bindingKeyId:r,credential:o})}function Kg(e,t,n){const s=Vg(e,t.id,n);if(s.id!==t.id||s.revision!==t.revision||s.sourceControlPlaneId!==t.sourceControlPlaneId||s.targetNodeId!==t.targetNodeId||s.bindingKeyId!==t.bindingKeyId||"active"!==s.status)throw Zg(Tt.BindingIdentityConflict,"Proxy binding changed while the request was being established.",409,!0,{bindingId:t.id,expectedRevision:t.revision,actualRevision:s.revision})}function Jg(e,t){if(t.id!==e.targetNodeId)throw Zg(Tt.TargetMismatch,"Proxy target resolver returned another node.",409,!1,{bindingId:e.id,targetNodeId:e.targetNodeId})}function Qg(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 Zg(Tt.HeaderInvalid,"Caller-supplied node transport authentication headers are forbidden.",400,!1,{header:e})}const t=Object.fromEntries([...vt].flatMap(t=>{if(Wg.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=ft.safeParse(t["x-request-id"]);if(!e.success)throw Zg(Tt.HeaderInvalid,"Proxy request correlation id is invalid.",400,!1,{header:"x-request-id"});t["x-request-id"]=e.data}return t}function Yg(e,t,n){const s=Xg(t),i=th(n?.headers);return i&&e.header("x-request-id",i),e.code(s.statusCode).send({error:{code:s.code,message:s.message,retryable:s.retryable,...s.details?{details:s.details}:{}}})}function Xg(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)||Tt.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 Zg(e,t,n,s=!1,i){return Object.assign(new Error(t),{code:e,statusCode:n,retryable:s,...i?{details:i}:{}})}function eh(e,t){const n=e[t];return Array.isArray(n)?n.join(","):"string"==typeof n?n:""}function th(e){if(!e)return;const t=ft.safeParse(eh(e,"x-request-id"));return t.success?t.data:void 0}function nh(e){let t="";for(const n of e){if(Buffer.byteLength(t+n)>123)break;t+=n}return t}const sh=e=>xt.parse({code:Tt.Unavailable,message:e,retryable:!0});class ih{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 s={generation:1,identity:e};this.subscriptions.set(t.id,s),this.connect(t.id,s.generation)}}stop(){this.running=!1;for(const e of[...this.subscriptions.keys()])this.remove(e)}remove(e){const t=this.subscriptions.get(e);t&&(t.generation+=1,t.reconnect&&clearTimeout(t.reconnect),t.socket?.close(),this.subscriptions.delete(e))}async connect(e,t){if(!this.current(e,t))return;const n=this.service.proxyPrivateStore.nodeCredential(e);if(n)try{const s=await this.fetchImpl(function(e){return new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/snapshot`,e.proxyOrigin)}(n),{headers:qo(n)});if(!this.current(e,t))return;const i=await s.json().catch(()=>{});if(!s.ok){const n=hr(xt,i?.error),r=n.success?n.data:sh(`Proxy snapshot failed with HTTP ${s.status}.`);return r.code===Tt.BindingRevoked?void this.onStateChanged(this.service.markProxyBindingRevoked(e,r)):void this.fail(e,t,r,r.retryable)}const r=mr($t,i?.data);if(this.validateIdentity(n,r.binding.id,r.binding.targetNodeId),this.onStateChanged(this.service.applyProxyTargetSnapshot(e,r)),"revoked"===r.binding.status)return void this.onStateChanged(this.service.markProxyBindingRevoked(e,{code:Tt.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:rh(n)},"control-plane proxy state bootstrap failed"),this.fail(e,t,sh("Trusted control-plane proxy is unavailable."),!0)}else this.fail(e,t,sh("Control-plane proxy credential is unavailable."),!1)}openEvents(e,t,n,s){const i=this.current(e,t);if(!i)return;const r=this.openWebSocket(function(e,t){const n=new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/events`,e.proxyOrigin);return n.protocol="wss:",n.searchParams.set("sinceRevision",String(t)),n.toString()}(n,s.revision),qo(n));i.socket=r;let o=!1;const a=n=>{o||(o=!0,this.fail(e,t,sh(n),!0))};r.on("message",i=>{if(this.current(e,t))try{const r=mr(Ht,JSON.parse(String(i)));if(r.bindingId!==n.proxyBindingId||r.sourceControlPlaneId!==n.sourceControlPlaneId||r.targetNodeId!==n.targetNodeId||r.streamId!==s.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:rh(n)},"control-plane proxy event requires a new snapshot"),this.restart(e,t)}}),r.on("error",()=>a("Control-plane proxy event stream failed.")),r.on("close",()=>a("Control-plane proxy event stream disconnected."))}restart(e,t){const n=this.current(e,t);n&&(n.generation+=1,n.socket?.close(),n.socket=void 0,this.connect(e,n.generation))}fail(e,t,n,s){const i=this.current(e,t);if(i){if(this.onStateChanged(this.service.markProxyUnavailable(e,n)),!s)return i.generation+=1,i.socket?.close(),void this.subscriptions.delete(e);i.generation+=1,i.socket?.close(),i.socket=void 0,i.reconnect=setTimeout(()=>{i.reconnect=void 0,this.connect(e,i.generation)},this.reconnectDelayMs),i.reconnect.unref?.()}}current(e,t){const n=this.subscriptions.get(e);return this.running&&n?.generation===t?n:void 0}validateIdentity(e,t,n){if(t!==e.proxyBindingId||n!==e.targetNodeId){const e=new Error("Proxy snapshot identity does not match the private binding credential.");throw Object.assign(e,{code:Tt.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 rh(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 oh=o.z.object({id:o.z.string().trim().min(1).max(160)}).strict(),ah=o.z.object({}).strict(),dh=o.z.object({algorithm:o.z.literal("Ed25519"),publicKey:o.z.string().regex(/^[A-Za-z0-9_-]{43}$/),privateKeyPkcs8:o.z.string().regex(/^[A-Za-z0-9_-]{64}$/)}).strip();function ch(){const{publicKey:e,privateKey:t}=a.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")}}class lh{identity;controlPlaneId;constructor(e,t,n){this.controlPlaneId=t,this.identity=new Wi(e,ch,{schema:dh,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},i=_i.parse({version:1,kind:"control-plane",controlPlaneId:this.controlPlaneId(),publicKey:{algorithm:"Ed25519",encoding:"base64url",value:n.publicKey,fingerprint:(r=n.publicKey,`sha256:${a.createHash("sha256").update(Buffer.from(r,"base64url")).digest("base64url")}`)},capabilities:s,protocolVersion:"2026-08-09",issuedAt:new Date(t).toISOString(),expiresAt:new Date(t+3e5).toISOString()});var r;const o=a.sign(null,Buffer.from((d=i,JSON.stringify(_i.parse(d)))),this.privateKey()).toString("base64url");var d;return Pi.parse({data:{payload:i,signature:o}})}privateKey(){const e=this.identity.get(),t=a.createPrivateKey({key:Buffer.from(e.privateKeyPkcs8,"base64url"),format:"der",type:"pkcs8"});if(a.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 ph{observations=new Map;listeners=new Set;begin(e,t,n="connecting"){const s=this.observations.get(e),i={nodeId:e,transport:t,generation:(s?.generation||0)+1,phase:n,changedAt:(new Date).toISOString(),consecutiveFailures:s?.transport===t?s.consecutiveFailures:0,controlReachability:s?.transport===t?s.controlReachability:"unknown",controlChangedAt:s?.transport===t?s.controlChangedAt:void 0,controlError:s?.transport===t?s.controlError:void 0};return this.observations.set(e,i),this.publish(i),i.generation}update(e,t,n,s=!0){const i=this.observations.get(e);if(!i||i.generation!==t)return!1;const r={...i,...n,changedAt:(new Date).toISOString()};return this.observations.set(e,r),s&&this.publish(r),!0}connected(e,t){const n=(new Date).toISOString();return this.update(e,t,{phase:"healthy",connectedAt:n,lastSeenAt:n,nextRetryAt:void 0,error:void 0})}pong(e,t){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),s=n?.transport===t?n.generation:this.begin(e.id,t,"handshaking");if("direct-http"===t){const t=(new Date).toISOString();return"reachable"===n?.controlReachability?this.update(e.id,s,{lastSeenAt:t},!1):this.update(e.id,s,{controlReachability:"reachable",controlChangedAt:t,controlError:void 0,lastSeenAt:t})}return"healthy"===n?.phase?this.update(e.id,s,{lastSeenAt:(new Date).toISOString()},!1):this.connected(e.id,s)}observedFailure(e,t){if("control-plane-proxy"===e.connectionMode)return!1;const n="reverse-wss"===e.connectionMode?"reverse-wss":"direct-http",s=this.observations.get(e.id),i=s?.transport===n?s.generation:this.begin(e.id,n,"connecting");return"direct-http"===n?"unreachable"===s?.controlReachability?this.update(e.id,i,{controlError:t},!1):this.update(e.id,i,{controlReachability:"unreachable",controlChangedAt:(new Date).toISOString(),controlError:t}):this.disconnected(e.id,i,{error:t})}disconnected(e,t,n={}){const s=this.observations.get(e);return!(!s||s.generation!==t)&&this.update(e,t,{phase:n.nextRetryAt?"reconnecting":"offline",consecutiveFailures:s.consecutiveFailures+1,closeCode:n.closeCode,error:n.error,nextRetryAt:n.nextRetryAt})}observation(e){return this.observations.get(e)}onChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}project(e){if(!1===e.connectionEnabled)return{...e,status:"offline",health:"failed",connectionPhase:"offline"};if("direct-http"!==e.connectionMode&&"reverse-wss"!==e.connectionMode&&"local-ipc"!==e.connectionMode&&"local-loopback"!==e.connectionMode)return e;const t=this.observations.get(e.id),n="reverse-wss"===e.connectionMode?"reverse-wss":"direct-http";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 uh(e,n){const s=t.extname(e);return`${s?e.slice(0,-s.length):e}.${n}${s}`}const gh=1048576,hh=52428800;function mh(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:e}function yh(e){const s=[],i=e=>{if(n.existsSync(e))for(const r of n.readdirSync(e,{withFileTypes:!0})){const n=t.join(e,r.name);r.isSymbolicLink()||(r.isDirectory()?i(n):r.isFile()&&(r.name.endsWith(".log")||r.name.endsWith(".jsonl"))&&s.push(n))}};return i(e),s.sort()}function fh(e,s,i){const r=n.statSync(e),o=Math.min(r.size,gh,i);if(o<=0)return 0;const a=Buffer.allocUnsafe(o),d=n.openSync(e,"r");try{n.readSync(d,a,0,o,Math.max(0,r.size-o))}finally{n.closeSync(d)}return n.mkdirSync(t.dirname(s),{recursive:!0,mode:448}),n.writeFileSync(s,a,{mode:384}),o}const Ih=o.z.object({code:o.z.string().trim().min(1),message:o.z.string(),details:o.z.record(o.z.string(),o.z.unknown()).optional(),retryable:o.z.boolean().optional()}).strict(),bh=o.z.object({error:Ih}).strict();function vh(e){const t=process.env[e]?.trim();return t||void 0}const wh=function(e,t=process.env,n=e){let s;return()=>{const i=t.TASK_HANDOFF_VERSION?.trim();return i||(s||=k(e,t,n),s)}}("@task-handoff/control-plane");function Sh(){return{component:"control-plane",packageName:"@task-handoff/control-plane",packageVersion:wh(),protocolVersion:Kt,buildId:vh("TASK_HANDOFF_BUILD_ID"),builtAt:vh("TASK_HANDOFF_BUILT_AT"),gitCommit:vh("TASK_HANDOFF_GIT_COMMIT"),imageRef:vh("TASK_HANDOFF_IMAGE_REF"),imageDigest:vh("TASK_HANDOFF_IMAGE_DIGEST")}}const Ah={".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 kh(e,s){const i=t.resolve(e),r=t.resolve(i,s);if(r===i||r.startsWith(`${i}${t.sep}`))return n.existsSync(r)&&n.statSync(r).isFile()?r:void 0}function zh(e,s,i){const r=kh(s,i);return r?(e.header("cache-control","no-store"),e.type(Ah[t.extname(r).toLowerCase()]||"application/octet-stream"),e.send(n.createReadStream(r))):e.code(404).send({error:{code:"STATIC_FILE_NOT_FOUND",message:`${i} was not found in the Control Plane UI static directory.`}})}function Th(e){if(e instanceof o.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 Ch(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[Vi],clientType:"web"}}async function xh(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 Eh=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 Nh(e,t){const n=t.split("?")[0]||"/";if(!n.startsWith("/api/"))return;if(Eh.has(n))return;const s=function(e){return"GET"===e||"HEAD"===e?"read":"POST"===e?"create":"PATCH"===e||"PUT"===e?"update":"DELETE"===e?"delete":"read"}(e);return"/api/control-plane/diagnostic-logs/export"===n?{action:"manage-settings",resource:{type:"control-plane-settings"}}:n.startsWith("/api/control-plane/settings")?{action:"GET"===e?"read":"manage-settings",resource:{type:"control-plane-settings"}}:"/api/auth/mobile/logout"===n||n.startsWith("/api/auth/mobile/sessions")||"/api/auth/password"===n?void 0:n.startsWith("/api/models")?{action:"GET"===e?"read":"manage-secrets",resource:{type:"model"}}:n.startsWith("/api/chat-gateway/bridges")?{action:"GET"===e?"read":"manage-secrets",resource:{type:"chat-bridge"}}:"/api/chat-gateway/messages"===n||"/api/chat-gateway/actions"===n?{action:"send-message",resource:{type:"ai-session"}}:"/api/chat-gateway/poll-ai-sessions"===n?{action:"manage-settings",resource:{type:"chat-bridge"}}:"/api/ai-session-attachments"===n?{action:"send-message",resource:{type:"ai-session"}}:"/api/node-join/invites"===n?{action:"manage-node-auth",resource:{type:"node"}}:n.startsWith("/api/control-plane-proxy")?{action:"GET"===e?"read":"manage-node-auth",resource:{type:"node"}}:n.startsWith("/api/nodes")?/\/(runtimes|local-folders)(\/|$)/.test(n)?{action:s,resource:{type:"runtime"}}:{action:"GET"===e?"read":"manage-node-auth",resource:{type:"node"}}:n.startsWith("/api/controlled-instances")?/\/apps\/sessions\/[^/]+\/access$/.test(n)?{action:"read",resource:{type:"instance"}}:n.includes("/ai-sessions")?n.includes("/triggers")?{action:s,resource:{type:"trigger"}}:"POST"===e&&/\/ai-sessions$/.test(n)?{action:"send-message",resource:{type:"ai-session"}}:n.endsWith("/approval")?{action:"approve",resource:{type:"ai-session"}}:n.endsWith("/interrupt")?{action:"interrupt",resource:{type:"ai-session"}}:n.endsWith("/resume")||n.endsWith("/commands")||n.includes("/messages")||n.includes("/queue/")?{action:"send-message",resource:{type:"ai-session"}}:n.endsWith("/read")||n.endsWith("/mentions/files")?{action:"read",resource:{type:"ai-session"}}:{action:s,resource:{type:"ai-session"}}:n.includes("/start")?{action:"start",resource:{type:"instance"}}:n.includes("/stop")?{action:"stop",resource:{type:"instance"}}:n.includes("/restart")?{action:"restart",resource:{type:"instance"}}:/\/config-sync(?:\/|$)/.test(n)?{action:"update",resource:{type:"instance"}}:{action:s,resource:{type:"instance"}}:n.startsWith("/api/projects")?{action:s,resource:{type:"project"}}:n.startsWith("/api/images")||n.startsWith("/api/image-options")||n.startsWith("/api/market")?{action:s,resource:{type:"runtime"}}:n.startsWith("/api/triggers")?{action:s,resource:{type:"trigger"}}:{action:s,resource:{type:"control-plane-settings"}}}async function _h(e={}){const a=Vp(e.dataDir),d=s({logger:e.logger??!0}),c=new bp;let l=(p=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(p||"").trim().toLowerCase()));var p;const u=function(e,s,i,r={}){const o=(o,a,d)=>{if(s()){i[o]?.(a,d);try{!function(e,s,i=10485760,r=2){const o=Buffer.isBuffer(s)?s:Buffer.from(s),a=o.byteLength>i?o.subarray(o.byteLength-i):o;if(n.mkdirSync(t.dirname(e),{recursive:!0,mode:448}),n.existsSync(e)){const t=n.lstatSync(e);if(!t.isFile()||t.isSymbolicLink())throw new Error(`Managed log path must be a regular file: ${e}`);t.size+a.byteLength>i&&(function(e,t){if(!(t<=0)){n.rmSync(uh(e,t),{force:!0});for(let s=t-1;s>=1;s-=1){const t=uh(e,s);n.existsSync(t)&&n.renameSync(t,uh(e,s+1))}}}(e,r),r>0?t.size>i?(n.writeFileSync(uh(e,1),function(e,t){const s=n.statSync(e),i=Math.min(s.size,t),r=Buffer.allocUnsafe(i),o=n.openSync(e,"r");let a=0;try{for(;a<i;){const e=n.readSync(o,r,a,i-a,s.size-i+a);if(0===e)break;a+=e}}finally{n.closeSync(o)}return a===i?r:r.subarray(0,a)}(e,i),{mode:384}),n.rmSync(e,{force:!0})):n.renameSync(e,uh(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:mh(a)},(e,t)=>mh(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)}}(a.logsDir,()=>l,d.log),h=new ph;h.onChange(e=>c.publish("node.connection.updated",e,{topic:"node.state",scope:{nodeId:e.nodeId}}));const m=new hc(a,{...e.service,logger:u,nodeConnectionRuntime:h}),f=new gr(a,e.auth),I=new lh(a.identitySigningPath,()=>m.proxyPrivateStore.controlPlaneId(),(e,t)=>d.log.warn(t,e)),b=new hg(c),v=new dg(a,{onChanged:e=>queueMicrotask(()=>c.publish(P,e,{topic:"ai.sessions",scope:{instanceId:e.instanceId,sessionId:e.sessionId}}))});v.init();const S=new og({bootstrap:()=>m.bootstrapAiSessionsFromInstances(),logger:u,recoverDelta:(e,t,n)=>m.recoverAiSessionDelta(e,t,n),recoverSnapshot:e=>m.recoverAiSessionSnapshot(e),onRecoveredEvent:e=>c.publish(e.type,e.payload)});S.onSnapshot(e=>v.reconcile(e.instanceId,e.aiSessions));const A=new ug({bootstrap:()=>m.bootstrapAppSessionsFromInstances(),logger:u,recoverDelta:(e,t,n)=>m.recoverAppSessionDelta(e,t,n),recoverSnapshot:e=>m.recoverAppSessionSnapshot(e),onRecoveredEvent:e=>c.publish(e.type,e.payload)});m.setAppSessionSnapshotProvider(e=>A.list(e)),m.setAiSessionSnapshotProvider(e=>S.list(e)),c.on(e=>{if(b.handle(e),"instance.deleted"===e.type){const t=e.payload&&"object"==typeof e.payload&&"instanceId"in e.payload?String(e.payload.instanceId||""):"";t&&(A.removeInstance(t),S.removeInstance(t),v.removeInstance(t))}});const k=new kp;d.addHook("onClose",async()=>{k.dispose()});const z=new Wp(c,{connectionRuntime:h,validateInstanceScope:(e,t)=>m.nodeOwnsInstance(e,t),onStreamsHello:(e,t)=>{for(const n of t.streams)"ai.sessions"===n.topic&&S.advertiseStream(e,n),"app.sessions"===n.topic&&A.advertiseStream(e,n)},onSessionEvent:e=>e.type.startsWith("app-session.")?A.handleEvent(e):S.handleEvent(e)}),T=e.proxyOrigin||process.env.TASK_HANDOFF_CONTROL_PLANE_PROXY_ORIGIN,C=e=>{const t=m.nodes.get(e);return t?function(e,t){const n="reverse-wss"===e.connectionMode&&t,s=n?"online":e.status;return{id:e.id,name:e.name||e.id,status:s,health:e.health,...e.lastSeenAt?{lastSeenAt:e.lastSeenAt}:{},capabilities:Lg(e.capabilities||{},262144),manageable:!1!==e.connectionEnabled&&(n||"online"===s)}}(t,z.connected(t.id)):void 0},x=new _g(new zg(a.proxyAuthorityPath,(e,t)=>d.log.warn(t,e)),{get:C},{proxyOrigin:T,proxyOriginProvider:()=>m.getSettings().publicBaseUrl}),E=new Rg,N=new jg(c,{projectTarget:e=>{const t=C(e);return t?Bg(t):void 0}}),_=new ih(m,{fetchImpl:e.service?.fetchImpl,logger:u,onStateChanged:e=>c.publish("node.proxy-state.updated",{nodeId:e.id,proxyState:e.proxyState},{topic:"node.state",scope:{nodeId:e.id}})});let R,O,j;c.on(e=>{if("node.created"!==e.type&&"node.updated"!==e.type&&"node.deleted"!==e.type||_.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&&z.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){z.invalidateInstanceScope({nodeId:t});const e=x.revokeTarget(t);for(const n of e.bindings)E.closeBinding(n.id,"Proxy target was deleted."),c.publish("control-plane-proxy.binding.updated",{binding:n},{topic:"control-plane-proxy",scope:{nodeId:t}})}}}),m.setNodeAgentTransport(z),m.init(),l=m.diagnosticLogsEnabled(),I.init();const M=()=>{if(R)return R;const e=m.recoverPendingPairingRevokes().then(()=>{});return R=e,e.then(()=>{R===e&&(R=void 0)},()=>{R===e&&(R=void 0)}),e};await M().catch(e=>d.log.warn({error:e},"pending node pairing recovery failed")),x.init(),_.start(),await m.syncLocalNodeConnection().catch(()=>{}),f.init();const D=new Ul(m,e.service?.fetchImpl,{aiSessions:S,logger:u,diagnosticLogsEnabled:()=>l});D.startEnabled();const q=new Gp(m,z,{safetyIntervalMs:Number(process.env.TASK_HANDOFF_EVENT_CONNECTION_SAFETY_INTERVAL_MS)||void 0,logger:u,connectionRuntime:h});q.start(),await d.register(i),await d.register(r),d.addHook("onClose",async()=>{O&&clearInterval(O),j&&clearInterval(j),await(R?.catch(()=>{})),b.close(),N.stop(),_.stop(),q.stop(),D.stopAll()}),d.setErrorHandler((e,t,n)=>{const s=Th(e);void 0!==s.retryAfterSeconds&&n.header("retry-after",String(s.retryAfterSeconds)),(l||s.statusCode>=500)&&(s.statusCode>=500?d.log.error.bind(d.log):d.log.warn.bind(d.log))({method:t.method,url:t.url,statusCode:s.statusCode,errorCode:s.code,error:s.message},"control plane request failed"),n.code(s.statusCode).send(bh.parse({error:{code:s.code,message:s.message,...s.details?{details:s.details}:{},...void 0!==s.retryable?{retryable:s.retryable}:{}}}))}),d.addHook("preHandler",async(e,t)=>{const n=e.routeOptions.url,s=n&&"*"!==n?n:e.url,i=e.routeOptions.config.controlPlaneAuthBoundary;if("proxy-binding"===i||"node-tunnel"===i)return;const r="public"===i||"public-ui"===i&&function(e){const t=e.split("?")[0]||"/";return!t.startsWith("/api/")&&"/api"!==t&&!t.startsWith("/instances/")&&"/instances"!==t}(e.url);if(!f.enabled()||r){const t=await xh(f,Ch(e)),n=Nh(e.method,s);return void(n&&mu(t||{type:"system",reason:"auth-disabled"},n.action,n.resource))}const o=await xh(f,Ch(e));if(!o)return t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to access the Control Plane."}});const a=Nh(e.method,s);a&&mu(o,a.action,a.resource)});const L=t.resolve(e.staticDir||process.env.TASK_HANDOFF_CONTROL_PLANE_STATIC_DIR||t.resolve(process.cwd(),"packages","control-plane-ui","dist"));return n.existsSync(L)&&(d.get("/assets/*",{config:zp},async(e,n)=>{const s=e.params["*"];return zh(n,L,t.join("assets",s||""))}),d.get("/favicon.ico",{config:zp},async(e,t)=>kh(L,"favicon.ico")?zh(t,L,"favicon.ico"):t.code(204).send())),d.get("/api/health",{config:zp},async()=>({data:{ok:!0,role:"control-plane",protocolVersion:Kt,build:Sh(),dataDir:a.dataDir,serverTime:(new Date).toISOString()}})),d.get("/api/control-plane/identity",{config:zp},async()=>I.publicDocument(f.enabled()?"required":"disabled")),d.get("/api/session-streams/diagnostics",async()=>({data:{aiSessions:S.diagnostics(),aiSessionActions:m.aiSessionActionDiagnostics(),appSessions:A.diagnostics(),nodeConnections:{...q.diagnostics(),runtime:h.diagnostics()}}})),d.get("/install-node-agent.sh",{config:zp},async(e,t)=>(t.header("cache-control","no-store"),t.type("text/x-shellscript; charset=utf-8"),gg`#!/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"),h=require("node:stream"),g=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 T=20971520,E=512e3,x=41943040,N="ai-session.snapshot",_="ai-session.patch",O="ai-session.removed",P="ai-session.message-delta",R="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}),G=a.z.object({send:a.z.boolean().optional(),interrupt:a.z.boolean().optional(),approval:a.z.boolean().optional(),openApp:a.z.boolean().optional(),close:a.z.boolean().optional()}).strict(),W=a.z.enum(["image","file"]),V=a.z.object({id:a.z.string().trim().min(1).max(120),kind:W,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)}),K=a.z.union([V.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?T:E;(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.`})}),V.extend({source:a.z.object({type:a.z.literal("runtime-path"),path:a.z.string().trim().min(1).max(4096)}).strict()}).strict()]),J=V.extend({sourceType:a.z.enum(["inline","runtime-path"])}).strict(),Y=a.z.union([a.z.object({id:a.z.string().trim().min(1).max(120),kind:W.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:W,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()]),Q=a.z.enum(["auto","queue","steer","immediate"]),X=a.z.enum(["ask","auto-review","full-access"]),Z=a.z.enum(["review","rename","goal","compact"]),ee=a.z.object({command:Z,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.`})}),te=a.z.object({command:Z,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 ne=a.z.object({name:a.z.string().trim().min(1).max(240),path:a.z.string().trim().min(1).max(4096)}),ie=a.z.discriminatedUnion("kind",[ne.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(),ne.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(),ne.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()]),se=a.z.array(ie).max(20).default([]),re=a.z.enum(["plugin","skill","file","directory","app"]),oe=a.z.object({kind:re,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."})}),ae=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(),de=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(oe).max(1e3).default([]),diagnostics:a.z.array(ae).max(20).default([])}).strict(),ce=a.z.object({query:a.z.string().trim().max(240).default("")}).strict(),le=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(oe.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(),pe=a.z.object({message:a.z.string().trim().min(1).max(2e4),mode:Q.optional(),permissionMode:X.optional()}),ue=pe.extend({attachments:a.z.array(K).max(6).default([]),references:se}).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."})}),he=pe.extend({attachments:a.z.array(Y).max(6).default([]),references:se}).strict(),ge=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();ue.extend({agent:j,cwd:ge,clientRequestId:a.z.string().trim().min(1).max(160)}).strict();const me=he.extend({agent:j,cwdFolderId:a.z.string().trim().min(1).max(120).optional(),clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),ye=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(),fe=a.z.object({clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),Ie=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(),be=a.z.object({clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),ve=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 we=a.z.object({decision:a.z.enum(["allow","deny","skip"])}).strict(),Se=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(),Ae=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 ke=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(J).max(6).default([]),references:se,permissionMode:X.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(),ze=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(ke).max(100).default([])}).strict().default({revision:0,pendingCount:0,items:[]}),Ce=a.z.enum(["control","realtime","adapter-snapshot","transcript-tail","transcript-scan","process-scan","app-session"]),Te=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(),Ee=a.z.object({id:a.z.string().trim().min(1).max(240),providerTurnId:a.z.string().trim().max(240).optional(),source:Ce.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(Te).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(),xe=Ee.pick({id:!0,providerTurnId:!0,userPrompt:!0,status:!0,phase:!0,summary:!0,lastMessage:!0,contextCompactions:!0,startedAt:!0,updatedAt:!0,completedAt:!0}).strict(),Ne=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(),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:G.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(),userPrompt:a.z.string().trim().optional(),turns:a.z.array(Ee).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:ze}).strict(),_e=a.z.object({session:Ne,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(),Oe=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),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),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(Oe).max(50).default([])}).strict();const Pe=a.z.object({items:a.z.array(Oe).max(50).default([])}).strict(),Re=a.z.object({item:Oe,turns:a.z.array(xe).max(50).default([])}).strict(),je=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(),De=Ne.pick({id:!0,agent:!0,creationSource:!0,appSessionId:!0,appId:!0,providerSessionId:!0,providerMeta:!0,appBindingKeys:!0,actions:!0,activeTurnId:!0,title:!0,cwd:!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}),Me=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(De).default([]),updatedAt:a.z.string().datetime()}).strict(),Le=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:Me}).strict(),qe=Me.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 $e(e,t={}){const n=e.sessions.filter(e=>"idle"===e.status).length,i=e.sessions.filter(e=>"failed"===e.status).length;return qe.parse({runningCount:e.runningCount,waitingCount:e.waitingCount,staleCount:e.staleCount,idleCount:n,problemCount:i,updatedAt:e.updatedAt,revision:t.revision})}const Be=a.z.enum(["provider-event","app-session-created","app-session-updated","app-session-deleted","discovery-scan","control-action","heartbeat-sync","startup"]),Ue=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:Be}).strict(),Fe=a.z.object({meta:Ue,snapshot:Me}).strict(),He=a.z.object({meta:Ue,upserted:a.z.array(De).default([]),removed:a.z.array(a.z.string().trim().min(1).max(120)).default([])}).strict(),Ge=a.z.object({meta:Ue,sessionIds:a.z.array(a.z.string().trim().min(1).max(120)).default([]),expiresAt:a.z.string().datetime()}).strict(),We=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(),Ve=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:Fe}).strict(),a.z.object({type:a.z.literal(_),payload:He}).strict(),a.z.object({type:a.z.literal(O),payload:Ge}).strict()])).default([])}).strict(),Ke=a.z.object({source:Ce,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(),Je=Ke.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(),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:G.optional(),title:a.z.string().trim().max(240).optional(),cwd:a.z.string().trim().max(4096).optional(),activeTurnId:a.z.string().trim().max(240).optional(),userPrompt:a.z.string().trim().optional(),turns:a.z.array(Ee).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(),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(),Ye=Ke.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","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:Te.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("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",[Je,Ye]);const Qe=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(),Xe="app-session.snapshot",Ze="app-session.patch",et="app-session.removed",tt=a.z.enum(["created","starting","running","stopping","stopped","exited","failed","closed","terminated","unknown"]),nt=a.z.enum(["tty","vnc","web"]);a.z.object({mode:nt,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 it=new Set(["stopped","failed","exited","closed","terminated"]),st=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(),rt=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:tt.default("unknown"),bindings:a.z.array(st).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()})),ot=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(rt).default([]),updatedAt:a.z.string().datetime()}).strict(),at=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:ot}).strict();ot.pick({runningCount:!0,problemCount:!0,updatedAt:!0}).extend({revision:a.z.number().int().min(0).optional()});const dt=a.z.enum(["app-session-created","app-session-updated","app-session-deleted","app-session-recovered","control-action","heartbeat-sync","startup"]),ct=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:dt}).strict(),lt=a.z.object({meta:ct,snapshot:ot}).strict(),pt=a.z.object({meta:ct,session:rt}).strict(),ut=a.z.object({meta:ct,sessionId:a.z.string().trim().min(1).max(160),tombstone:rt.optional(),expiresAt:a.z.string().datetime().optional()}).strict(),ht=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(Xe),payload:lt}).strict(),a.z.object({type:a.z.literal(Ze),payload:pt}).strict(),a.z.object({type:a.z.literal(et),payload:ut}).strict()])).default([])}).strict();function gt(e,t=(new Date).toISOString()){const n=e.map(e=>yt(e));return ot.parse({runningCount:n.filter(e=>"running"===e.status).length,problemCount:n.filter(e=>"failed"===e.status).length,sessions:n,updatedAt:t})}function mt(e,t=(new Date).toISOString()){return gt(e.filter(e=>It("string"==typeof e.status?e.status:void 0)),t)}function yt(e){const t=ft("string"==typeof e.status?e.status:void 0),n="string"==typeof e.id?e.id:"",i=function(e){const t=kt(e.workspace),n=kt(e.tty),i=kt(e.launch),s=kt(e.ai),r=kt(s.claude),o=zt(t.cwd)||zt(n.cwd)||zt(r.cwd)||zt(i.cwd);return o?{cwd:o}:void 0}(e),{workspace:s,...r}=e;return rt.parse({...r,status:t,bindings:At([...(o=e.bindings,Array.isArray(o)?o.flatMap(e=>{const t=st.safeParse(e);return t.success?[t.data]:[]}):[]),...n?[{type:"app-session",id:n}]:[],...wt(e)]),...i?{workspace:i}:{}});var o}function ft(e){const t=(e||"unknown").trim().toLowerCase();return"ended"===t?"closed":"terminating"===t?"stopping":tt.options.includes(t)?t:"unknown"}function It(e){return!it.has(ft(e))}function bt(e){return"tty"===e.kind?"tty":"gui"===e.kind?"vnc":"web"===e.kind?"web":void 0}function vt(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 wt(e){const t=kt(e.ai),n=kt(t.claude),i=kt(t.appServer),s=[],r=zt(n.short);r&&s.push({type:"adapter-key",adapter:"claude",agent:"claude",id:`short:${r}`,key:`short:${r}`});const o=zt(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=zt(t.activeThreadId);for(const e of[...new Set([d,...a].filter(Boolean))])s.push({type:"provider-session",agent:"codex",id:e});const c=zt(i.socketPath);return c&&s.push({type:"adapter-key",adapter:"codex-app-server",agent:"codex",id:`socket:${c}`,key:`socket:${c}`}),s}function St(e){const t="string"==typeof e.id?e.id:"",n=kt(e.ai),i=zt(kt(n.claude).short);return[t?`app:${t}`:"",i?`claude-short:${i}`:""]}function At(e){const t=new Map;for(const n of e)t.set(vt(n),n);return[...t.values()]}function kt(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function zt(e){return"string"==typeof e&&e.trim()?e.trim():""}function Ct(e=(new Date).toISOString()){return ot.parse({runningCount:0,problemCount:0,sessions:[],updatedAt:e})}const Tt=a.z.string().trim().min(3).max(160).regex(/^[a-z][a-z0-9_-]*$/),Et=a.z.string().datetime(),xt=a.z.string().regex(/^sha256:[A-Za-z0-9_-]{43}$/),Nt=a.z.string().min(32).max(4096),_t=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 Ot(e){return Array.isArray(e)?`[${e.map(Ot).join(",")}]`:e&&"object"==typeof e?`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${Ot(t)}`).join(",")}}`:JSON.stringify(e)}const Pt="2026-08-10",Rt="2026-08-10",jt="2026-08-10",Dt=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(Dt.AccountApi)});const Mt=a.z.string().email().max(320).transform(e=>e.trim().toLowerCase()),Lt=a.z.enum(["pending-verification","active","disabled","pending-deletion"]);a.z.strictObject({id:Tt,email:Mt,emailVerified:a.z.boolean(),hasPassword:a.z.boolean().optional(),totpEnabled:a.z.boolean().optional(),displayName:_t.optional(),status:Lt,createdAt:Et}),a.z.strictObject({id:Tt,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:Et,lastSeenAt:Et.optional(),expiresAt:Et,revokedAt:Et.optional()}),a.z.union([a.z.object({code:Nt,state:a.z.string().min(1).max(4096).optional(),redirectUri:a.z.string().url(),expiresAt:Et}),a.z.object({authorizationUrl:a.z.string().url(),expiresAt:Et})]),a.z.object({tokenType:a.z.literal("Bearer"),accessToken:Nt,accessExpiresAt:Et,refreshCredential:Nt,accountId:Tt,deviceSessionId:Tt}),a.z.strictObject({enrollmentToken:Nt,secret:Nt,algorithm:a.z.literal("SHA1"),digits:a.z.literal(6),periodSeconds:a.z.literal(30),otpauthUri:a.z.string().url().startsWith("otpauth://totp/"),expiresAt:Et});const qt=a.z.strictObject({controlPlaneId:Tt,algorithm:a.z.literal("Ed25519"),publicKey:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/),fingerprint:xt});a.z.strictObject({protocolVersion:a.z.literal(Pt),audience:a.z.literal(Dt.Binding),challengeId:Tt,challenge:Nt,serviceOrigin:a.z.string().url(),identity:qt,nonce:a.z.string().min(16).max(256),initiatingAdminSessionId:Tt,issuedAt:Et,expiresAt:Et}),a.z.strictObject({code:a.z.enum(["CONTROL_PLANE_ALREADY_BOUND","REVISION_CONFLICT","REVOCATION_PENDING","IDENTITY_CLONE_CONFLICT"]),controlPlaneId:Tt,expectedRevision:a.z.number().int().nonnegative().optional(),actualRevision:a.z.number().int().nonnegative().optional(),retryable:a.z.boolean()});const $t=a.z.strictObject({bindingId:Tt.optional(),controlPlaneId:Tt,displayName:_t,publicKeyFingerprint:xt,bindingRevision:a.z.number().int().positive(),remoteAccess:a.z.enum(["enabled","disabled","revocation-pending"]),leaseExpiresAt:Et.optional(),lastConnectedAt:Et.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()}),Bt=a.z.enum(["interactive","stream","bulk"]),Ut=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(),Ft=a.z.strictObject({protocolVersion:a.z.literal(Rt),audience:a.z.literal(Dt.CoordinatorControl),connectionId:Tt,processInstanceId:Tt,controlPlaneId:Tt,publicKey:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/),publicKeyFingerprint:xt,bindingId:Tt.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:Et,expiresAt:Et}).superRefine((e,t)=>{Boolean(e.bindingId)!==Boolean(e.bindingRevision)&&t.addIssue({code:"custom",message:"binding id and revision must be supplied together"})});Ft.safeExtend({signature:Nt}),a.z.strictObject({connectionId:Tt,controlPlaneId:Tt,bindingRevision:a.z.number().int().positive(),epoch:a.z.number().int().nonnegative(),relayId:Tt,relayRegion:a.z.string().trim().min(1).max(80),issuedAt:Et,expiresAt:Et});const Ht=a.z.strictObject({protocolVersion:a.z.literal(Rt),audience:a.z.literal(Dt.ControlPlaneAccess),ticketId:Tt,accountId:Tt,deviceSessionId:Tt,controlPlaneId:Tt,bindingId:Tt,bindingRevision:a.z.number().int().positive(),targetPublicKeyFingerprint:xt,nonce:a.z.string().min(16).max(256),trafficClasses:a.z.array(Bt).min(1),issuedAt:Et,expiresAt:Et,signature:Nt});a.z.strictObject({audience:a.z.literal(Dt.ControlPlaneAccess),accountId:Tt,deviceSessionId:Tt,controlPlaneId:Tt,bindingId:Tt,bindingRevision:a.z.number().int().positive(),authenticatedAt:Et,expiresAt:Et,signature:Nt});const Gt=a.z.enum(["client","control-plane"]),Wt=a.z.strictObject({protocolVersion:a.z.literal(jt),audience:a.z.enum([Dt.RelayClientAttach,Dt.RelayControlPlaneAttach]),allocationId:Tt,relayId:Tt,role:Gt,controlPlaneId:Tt,accountId:Tt,deviceSessionId:Tt,bindingId:Tt,ticketId:Tt,bindingRevision:a.z.number().int().positive(),trafficClass:Bt,nonce:a.z.string().min(16).max(256),issuedAt:Et,expiresAt:Et,signature:Nt}).superRefine((e,t)=>{const n="client"===e.role?Dt.RelayClientAttach:Dt.RelayControlPlaneAttach;e.audience!==n&&t.addIssue({code:"custom",path:["audience"],message:`audience must match ${e.role} role`})});a.z.object({allocationId:Tt,relayId:Tt,relayRegion:a.z.string().trim().min(1).max(80),relayUrl:a.z.string().url(),clientAttach:Wt,expiresAt:Et}),a.z.strictObject({channelId:Tt,allocationId:Tt,controlPlaneId:Tt,bindingRevision:a.z.number().int().positive(),trafficClass:Bt,state:a.z.enum(["waiting-for-peer","handshaking","open","closing","closed"]),clientAttached:a.z.boolean(),controlPlaneAttached:a.z.boolean(),openedAt:Et.optional(),leaseExpiresAt:Et}),a.z.strictObject({protocolVersion:a.z.literal(jt),channelId:Tt,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:Tt,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(jt),audience:a.z.literal(Dt.RelayRevocation),revocationId:Tt,relayId:Tt.optional(),allocationId:Tt.optional(),accountId:Tt.optional(),deviceSessionId:Tt.optional(),bindingId:Tt.optional(),issuedAt:Et,expiresAt:Et,signature:Nt}).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(Pt),items:a.z.array($t)})}),Object.keys($t.shape);const Vt=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 Kt(){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 Jt=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()]),Yt=a.z.union([Jt,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()]),Qt=a.z.object({promptTemplate:a.z.string().trim().min(1).max(2e4)}).strict(),Xt=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(),Zt=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:Yt,action:Qt,policy:Xt.default({maxConcurrentRuns:1,whenBusy:"skip"}),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict(),en=a.z.object({type:a.z.literal("ai-session"),aiSessionId:a.z.string().trim().min(1).max(160)}).strict(),tn=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:en,localName:a.z.string().trim().min(1).max(160).optional(),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict(),nn=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(),sn=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:en,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(Zt).default([]),deployments:a.z.array(tn).default([]),runtime:a.z.array(nn).default([]),recentRuns:a.z.array(sn).default([])}).strict();const rn=a.z.object({instanceId:a.z.string().trim().min(1).max(160),instanceName:a.z.string().trim().min(1).max(160),deployment:tn,runtime:nn.optional()}).strip(),on=sn.extend({instanceName:a.z.string().trim().min(1).max(160).optional()}).strip(),an=a.z.object({configHash:a.z.string().trim().min(8).max(80),config:Zt,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(rn),recentRuns:a.z.array(on)}).strip(),dn=a.z.object({updatedAt:a.z.string().datetime(),triggers:a.z.array(an)}).strip();function cn(e){const t=un({source:e.source,action:e.action,policy:Xt.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=pn(t,7)^pn(t,18)^t>>>3,s=pn(n,17)^pn(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+(pn(d,6)^pn(d,11)^pn(d,25))+(d&c^~d&l)+ln[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+((pn(t,2)^pn(t,13)^pn(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:Zt.shape.name,description:Zt.shape.description,source:Yt,action:Qt,policy:Xt.partial().optional()}).strict();const ln=[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 pn(e,t){return e>>>t|e<<32-t}function un(e){return Array.isArray(e)?e.map(un):e&&"object"==typeof e?Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,un(t)])):e}const hn="2026-08-01",gn=a.z.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Proxy protocol version must use YYYY-MM-DD format."),mn=a.z.string().trim().min(1).max(160).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),yn=a.z.string().datetime(),fn=a.z.string().trim().min(32).max(4096),In=mn,bn=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}}),vn=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}}),wn=new Set(["accept","accept-language","authorization","content-type","if-match","if-none-match","range","x-request-id"]),Sn=new Set(["cache-control","content-disposition","content-language","content-length","content-range","content-type","etag","last-modified","x-request-id"]),An="x-task-handoff-proxy-protocol-version",kn="x-task-handoff-proxy-source-control-plane-id",zn="x-task-handoff-proxy-binding-key-id",Cn="x-task-handoff-proxy-credential",Tn={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"},En=a.z.enum(Object.values(Tn)),xn=a.z.object({code:En,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(),Nn=a.z.enum(["active","consumed","revoked","expired"]),_n=a.z.object({id:mn,targetNodeId:mn,tokenHash:a.z.string().trim().min(32).max(256),status:Nn,createdBy:mn,expiresAt:yn,consumedByClaimId:mn.optional(),consumedAt:yn.optional(),revokedAt:yn.optional(),createdAt:yn,updatedAt:yn}).strict(),On=_n.omit({tokenHash:!0}),Pn=a.z.object({targetNodeId:mn,expiresInSeconds:a.z.number().int().min(60).max(3600).default(600)}).strict(),Rn=a.z.object({invite:On,token:a.z.string().trim().min(24).max(512),proxyOrigin:bn,protocolVersion:gn}).strict(),jn=a.z.enum(["active","revoked"]),Dn=a.z.object({id:mn,claimId:mn,sourceControlPlaneId:mn,targetNodeId:mn,bindingKeyId:mn,credentialHash:a.z.string().trim().min(32).max(256),status:jn,revision:a.z.number().int().positive(),lastError:xn.optional(),revokedAt:yn.optional(),createdAt:yn,updatedAt:yn}).strict(),Mn=Dn.omit({credentialHash:!0}),Ln=a.z.object({protocolVersion:gn,inviteToken:a.z.string().trim().min(24).max(512).optional(),claimId:mn,sourceControlPlaneId:mn,targetNodeId:mn.optional(),bindingKeyId:mn,credential:fn}).strict(),qn=a.z.object({sourceControlPlaneId:mn,bindingKeyId:mn,credential:fn}).strict(),$n=a.z.object({id:mn,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:yn.optional(),capabilities:a.z.record(a.z.string(),a.z.unknown()).default({})}).strict(),Bn=a.z.object({protocolVersion:gn,binding:Mn,streamId:mn,revision:a.z.number().int().nonnegative(),observedAt:yn,target:$n}).strict(),Un=a.z.object({type:a.z.literal("control-plane-proxy.event"),protocolVersion:gn,streamId:mn,bindingId:mn,sourceControlPlaneId:mn,targetNodeId:mn,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:$n,event:a.z.object({type:a.z.string().trim().min(1).max(240),topic:a.z.string().trim().min(1).max(240),createdAt:yn}).strict()}).strict(),Fn=a.z.object({type:a.z.literal("control-plane-proxy.events.ready"),protocolVersion:gn,streamId:mn,bindingId:mn,sourceControlPlaneId:mn,targetNodeId:mn,latestRevision:a.z.number().int().nonnegative(),earliestRetainedRevision:a.z.number().int().nonnegative()}).strict(),Hn=a.z.object({type:a.z.literal("control-plane-proxy.snapshot-required"),protocolVersion:gn,streamId:mn,bindingId:mn,sourceControlPlaneId:mn,targetNodeId:mn,sinceRevision:a.z.number().int().nonnegative(),latestRevision:a.z.number().int().nonnegative(),earliestRetainedRevision:a.z.number().int().nonnegative(),error:xn}).strict(),Gn=a.z.discriminatedUnion("type",[Un,Fn,Hn]),Wn=a.z.object({protocolVersion:gn,binding:Mn,target:Bn.shape.target}).strict(),Vn=a.z.object({id:mn,claimId:mn,proxyOrigin:bn,requestedName:a.z.string().trim().min(1).max(160).optional(),sourceControlPlaneId:mn,targetNodeId:mn.optional(),bindingKeyId:mn,credential:fn,status:a.z.enum(["pending","compensation-required"]),createdAt:yn,updatedAt:yn,expiresAt:yn}).strict();Vn.omit({credential:!0});const Kn=a.z.object({id:mn,nodeId:mn,proxyOrigin:bn,proxyBindingId:mn,targetNodeId:mn,sourceControlPlaneId:mn,bindingKeyId:mn,credential:fn,createdAt:yn,updatedAt:yn}).strict(),Jn="2026-08-01",Yn=a.z.string(),Qn=a.z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Xn=a.z.string().datetime(),Zn=a.z.record(a.z.string(),a.z.string()).default({}),ei=a.z.record(a.z.string(),a.z.string()).default({}),ti=a.z.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Protocol version must use YYYY-MM-DD format.");function ni(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 ii=/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/,si=/^sha256:([a-fA-F0-9]{64})$/,ri=/^(?:localhost|[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?)(?::[1-9][0-9]{0,4})?$/,oi=/^[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*$/;function ai(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?si.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&&!ii.test(c))throw new Error("Docker image tag is invalid.");if(!c&&!r)throw new Error("Docker image reference must include an explicit tag or sha256 digest.");const p=l.split("/");if(!p.length||p.some(e=>!e))throw new Error("Docker image repository path is invalid.");const u=p.length>1&&(p[0].includes(".")||p[0].includes(":")||"localhost"===p[0]),h=u?p.slice(1):p;if(u&&!ri.test(p[0].toLowerCase()))throw new Error("Docker image registry host or port is invalid.");if(!h.length||h.some(e=>!oi.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("/"),m=r?`sha256:${r[1].toLowerCase()}`:void 0;return`${g}${c?`:${c}`:""}${m?`@${m}`:""}`}function di(e){const t=ai(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 ci=a.z.string().trim().min(1).max(512).transform((e,t)=>{try{return ai(e)}catch(e){return t.addIssue({code:"custom",message:e instanceof Error?e.message:String(e)}),a.z.NEVER}}),li=a.z.string().trim().transform((e,t)=>{const n=si.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)}),pi=a.z.object({codexModelHash:Qn.nullable().optional(),claudeModelHash:Qn.nullable().optional()}).strict().default({}),ui=a.z.object({imageId:Qn,tag:a.z.string().trim().min(1).max(128).regex(ii).optional()}).strict(),hi=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("image"),imageSelection:ui}).strict(),a.z.object({type:a.z.literal("template"),environmentTemplateId:Qn}).strict()]),gi=a.z.enum(["creating","ready","failed","deleting"]),mi=a.z.enum(["linux","darwin","win32","freebsd","openbsd","aix","sunos","unknown"]),yi=a.z.enum(["x64","arm64","arm","ia32","ppc64","s390x","riscv64","unknown"]),fi=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(),Ii=a.z.object({templateId:Qn,nodeId:Qn,imageId:li,name:a.z.string().trim().min(1).max(160),platform:mi,architecture:yi}).strict(),bi=a.z.enum(["data","agent-home","workspace"]),vi=a.z.object({deleteVolumes:a.z.boolean()}).strict(),wi=a.z.object({role:bi,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(),Si=a.z.object({instanceId:Qn,containerDeleted:a.z.boolean(),completed:a.z.boolean(),deletedVolumes:a.z.array(wi),retainedVolumes:a.z.array(wi),volumeResults:a.z.array(wi)}).strict(),Ai={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&&Ai[t.imageId]||t.imageId,..."string"==typeof t.tag?{tag:t.tag}:{}}}if("string"==typeof t)return{imageId:Ai[t]||t}}function zi(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 Ci=a.z.object({id:Qn,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(),Ti=a.z.object({code:a.z.enum(["APP_CATALOG_INVALID"]),message:a.z.string().trim().min(1).max(500)}).strict(),Ei=a.z.object({items:a.z.array(Ci).max(256),observedAt:Xn,issues:a.z.array(Ti).max(32).default([])}).strict(),xi=a.z.object({id:Qn,name:a.z.string().trim().min(1).max(160),sourceInstanceId:Qn,nodeId:Qn,imageId:li.optional(),internalTag:a.z.string().trim().min(1).max(512).optional(),platform:mi.optional(),architecture:yi.optional(),sizeBytes:a.z.number().int().nonnegative().optional(),status:gi,error:fi.optional(),createdAt:Xn,updatedAt:Xn}).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."})}),Ni=a.z.enum(["apt","dnf","brew","npm"]),_i=a.z.enum(["user","passwordless-sudo","root"]),Oi=a.z.object({platform:mi,arch:yi,installers:a.z.array(Ni).max(8),privilege:_i,installerAccess:a.z.object({npmGlobalWritable:a.z.boolean().optional()}).strict().optional()}).strict(),Pi=a.z.enum(["installed","not-installed","broken","unsupported"]),Ri=a.z.enum(["recipe","bundled","external","none"]),ji=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(),Di=a.z.object({id:Qn,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:Pi,managementSource:Ri,version:a.z.string().trim().max(120).optional(),canInstall:a.z.boolean(),canUninstall:a.z.boolean(),installReason:ji.optional(),uninstallReason:ji.optional(),activeJobId:Qn.optional()}).strict(),Mi=a.z.enum(["install","uninstall"]),Li=a.z.enum(["queued","running","succeeded","failed","cancelled","interrupted"]),qi=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"]}),$i=a.z.object({executable:a.z.string().trim().min(1).max(4096),args:a.z.array(a.z.string().max(4096)).max(128)}).strict(),Bi=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(Qn).max(64).optional()}).strict(),Ui=a.z.object({id:Qn,requestId:Qn.optional(),appId:Qn,operation:Mi,state:Li,phase:a.z.string().trim().min(1).max(120).optional(),progress:qi.optional(),command:$i.optional(),logTail:a.z.string().max(32768).optional(),logTruncated:a.z.boolean().optional(),error:Bi.optional(),requestedAt:Xn,startedAt:Xn.optional(),finishedAt:Xn.optional(),updatedAt:Xn}).strict(),Fi=a.z.object({streamId:Qn,sequence:a.z.number().int().nonnegative(),capabilities:Oi,apps:a.z.array(Di).max(256),activeJobs:a.z.array(Ui).max(256),recentJobs:a.z.array(Ui).max(256),observedAt:Xn}).strict(),Hi=a.z.object({requestId:Qn.optional()}).strict(),Gi=a.z.object({job:Ui}).strict();a.z.object({type:a.z.literal("app-management"),streamId:Qn,sequence:a.z.number().int().nonnegative(),observedAt:Xn,job:Ui.optional(),snapshot:Fi.optional()}).strict().refine(e=>void 0!==e.job||void 0!==e.snapshot,{message:"An app management event requires a job or snapshot."});const Wi=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:Yn.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(),Vi=a.z.enum(["stable","beta","alpha"]),Ki=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(),Ji=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(),Yi=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:Xn.optional(),matchedAt:Xn.optional(),error:Ji.optional()}).strict(),Qi=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(Qn).max(1024).default([]),stoppedInstanceIds:a.z.array(Qn).max(1024).default([]),activeInstanceIds:a.z.array(Qn).max(1024).default([])}).strict(),Xi=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(Qn).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(),Zi=a.z.object({channel:Vi.default("stable")}).strict(),es=a.z.object({source:a.z.literal("npm"),channel:Vi,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(Ki).default([]),impact:Qi,updateAvailable:a.z.boolean(),supported:a.z.boolean().default(!0),reason:a.z.string().trim().max(2048).optional(),checkedAt:Xn,preflightToken:a.z.string().trim().min(16).max(240).optional()}).strict(),ts=a.z.object({id:Qn,nodeId:Qn,source:a.z.literal("npm"),channel:Vi,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(Ki).default([]),impact:Qi,rollout:Xi,status:a.z.enum(["queued","updating-node","restarting-node","converging-instances","succeeded","degraded","failed"]),error:Ji.optional(),startedAt:Xn.optional(),completedAt:Xn.optional(),createdAt:Xn,updatedAt:Xn}).strict(),ns=a.z.object({channel:Vi,targetVersion:a.z.string().trim().min(1).max(240),preflightToken:a.z.string().trim().min(16).max(240)}).strict(),is=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(),ss=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(),rs=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:Qn,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:is.default({type:"branch",name:"main"}),auth:ss.default({type:"none"}),clone:rs.default({submodules:!1,lfs:!1,subdirectory:""}),defaultImageSelection:ui.optional(),labels:Zn,createdAt:Xn,updatedAt:Xn}).strict();const os=a.z.object({id:Qn,nodeId:Qn,name:a.z.string().trim().min(1).max(160),path:a.z.string().trim().min(1).max(4096),defaultImageSelection:ui.optional(),labels:Zn,createdAt:Xn,updatedAt:Xn}).strict(),as=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("git-repository"),repositoryId:Qn.optional(),url:a.z.string().trim().min(1).max(2048),provider:a.z.string().trim().max(80).optional(),ref:is.default({type:"branch",name:"main"}),auth:ss.default({type:"none"}),clone:rs.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:is.default({type:"branch",name:"main"}),auth:ss.default({type:"none"}),clone:rs.default({submodules:!1,lfs:!1,subdirectory:""})}).strict(),a.z.object({type:a.z.literal("local-folder"),localFolderId:Qn.optional(),path:a.z.string().trim().min(1).max(4096),ownerNodeId:Qn.optional()}).strict()]),ds=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(),cs=a.z.enum(["codex","claude"]),ls=a.z.object({id:Qn,name:a.z.string().trim().min(1).max(160),source:as,defaultImageSelection:ui.optional(),defaultNodeId:Qn.optional(),defaultRuntimeId:Qn.optional(),workspacePolicy:ds,labels:Zn,createdAt:Xn,updatedAt:Xn}).strict(),ps=a.z.object({id:Qn,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:cs,enabled:a.z.boolean().default(!0),order:a.z.number().int().min(0).max(1e6).default(0),labels:Zn,createdAt:Xn,updatedAt:Xn}).strict(),us=ps.omit({key:!0}).extend({keyPreview:a.z.string().trim().min(1).max(160),keySet:a.z.boolean()}).strict(),hs=us.extend({referenceCount:a.z.number().int().min(0)}).strict(),gs=a.z.object({instanceId:Qn,codexModelHash:Qn.optional(),claudeModelHash:Qn.optional(),updatedAt:Xn}).strict(),ms=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("control-plane"),name:ps.shape.name,enabled:ps.shape.enabled,order:ps.shape.order}).strict(),a.z.object({type:a.z.literal("node"),nodeId:Qn,name:ps.shape.name,enabled:ps.shape.enabled,order:ps.shape.order,referenceCount:a.z.number().int().min(0)}).strict()]),ys=a.z.object({id:Qn,model:us,locations:a.z.array(ms).min(1),referenceCount:a.z.number().int().min(0).default(0)}).strict(),fs=a.z.object({nodeId:Qn,code:a.z.string().trim().min(1).max(120),message:a.z.string().trim().min(1).max(2e3)}).strict(),Is=a.z.object({models:a.z.array(ys),nodeDiagnostics:a.z.array(fs).default([]),updatedAt:Xn}).strict();function bs(e){const t={app:cs.parse(e.app),endpoint:ps.shape.endpoint.parse(e.endpoint),key:ps.shape.key.parse(e.key),model:ps.shape.model.parse(e.model)};return`mdl_${i.createHash("sha256").update(JSON.stringify(t)).digest("hex")}`}ps.omit({id:!0,createdAt:!0,updatedAt:!0}).strict().partial().strict(),a.z.object({modelSelection:pi,codexModelHash:Qn.optional(),claudeModelHash:Qn.optional()}).strict();const vs=a.z.enum(["market","custom"]),ws=a.z.enum(["active","deprecated","yanked"]),Ss=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:li.optional()}).strict()]),As={kind:"builtin",key:"default-image-cover"},ks=a.z.array(a.z.string().trim().min(1).max(80)).default([]),zs=a.z.array(a.z.string().trim().min(1).max(120)).default([]),Cs=a.z.record(a.z.string().trim().min(2).max(35),a.z.string().trim().min(1).max(4096)),Ts=a.z.object({os:a.z.string().trim().min(1).max(40),architecture:a.z.string().trim().min(1).max(40),digest:li.optional(),downloadSizeBytes:a.z.number().int().positive().optional(),unpackedSizeBytes:a.z.number().int().positive().optional()}).strict(),Es=a.z.object({name:a.z.string().trim().min(1).max(128).regex(ii),version:a.z.string().trim().min(1).max(160).optional(),reference:ci,manifestDigest:li.optional(),publishedAt:Xn.optional(),platforms:a.z.array(Ts).default([]),status:ws.default("active")}).strict(),xs=a.z.object({id:Qn,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:Cs.optional(),cover:Ss.optional(),repository:a.z.string().trim().min(1).max(512),defaultTag:a.z.string().trim().min(1).max(128).regex(ii),tags:a.z.array(Es).min(1),capabilities:ks,optionalApps:zs,defaultEnv:ei,labels:Zn,status:ws.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."})}),Ns=a.z.object({protocolVersion:ti,catalogId:Qn,revision:a.z.string().trim().min(1).max(240),source:a.z.enum(["embedded","remote","cache"]),generatedAt:Xn,expiresAt:Xn.optional(),items:a.z.array(xs)}).strict(),_s=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:Xn,error:a.z.string().trim().max(4096).optional()}).strict(),Os=a.z.object({id:Qn,origin:a.z.literal("custom"),name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().max(4096).optional(),localizedDescriptions:Cs.optional(),cover:Ss.optional(),reference:ci,repository:a.z.string().trim().min(1).max(512),tag:a.z.string().trim().min(1).max(128).regex(ii).optional(),pullPolicy:a.z.literal("if-not-present").default("if-not-present"),capabilities:ks,optionalApps:zs,defaultEnv:ei,labels:Zn,createdAt:Xn,updatedAt:Xn}).strict(),Ps=a.z.object({name:a.z.string().trim().min(1).max(128).regex(ii),version:a.z.string().trim().min(1).max(160).optional(),reference:ci,manifestDigest:li.optional(),status:ws}).strict(),Rs=a.z.object({id:Qn,origin:vs,name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().max(4096).optional(),localizedDescriptions:Cs.optional(),cover:Ss,repository:a.z.string().trim().min(1).max(512),tag:a.z.string().trim().min(1).max(128).regex(ii).optional(),availableTags:a.z.array(Ps),reference:ci,digest:li.optional(),downloadSizeBytes:a.z.number().int().positive().optional(),unpackedSizeBytes:a.z.number().int().positive().optional(),capabilities:ks,optionalApps:zs,defaultEnv:ei,labels:Zn,readOnly:a.z.boolean(),lifecycleStatus:ws.optional(),market:a.z.object({catalogId:Qn,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(),js=a.z.object({id:Qn,origin:vs,name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().max(4096).optional(),localizedDescriptions:Cs.optional(),cover:Ss.optional(),repository:a.z.string().trim().min(1).max(512),tag:a.z.string().trim().min(1).max(128).regex(ii).optional(),requestedReference:ci,resolvedDigest:li.optional(),resolvedReference:ci.optional(),downloadSizeBytes:a.z.number().int().positive().optional(),pullPolicy:a.z.literal("if-not-present").default("if-not-present"),capabilities:ks,optionalApps:zs,defaultEnv:ei,labels:Zn,market:a.z.object({catalogId:Qn,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:Xn,updatedAt:Xn}).strict(),Ds=a.z.object({phase:a.z.enum(["checking-image","pulling-image","resolving-image","ready","failed"]),requestedReference:ci,generation:a.z.number().int().nonnegative().default(0),error:a.z.string().trim().max(4096).optional(),startedAt:Xn,updatedAt:Xn}).strict(),Ms="image.pull.terminal.output",Ls="image.pull.terminal.finished",qs=a.z.object({instanceId:Qn,generation:a.z.number().int().nonnegative(),requestedReference:ci,sequence:a.z.number().int().nonnegative(),observedAt:Xn}).strict(),$s=qs.extend({data:a.z.string().min(1).max(65536),replay:a.z.boolean().optional()}).strict(),Bs=qs.extend({outcome:a.z.enum(["succeeded","failed"])}).strict(),Us=qs.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 Fs(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=ai(a)}catch{if(!a.includes("@")&&a.lastIndexOf(":")<=a.lastIndexOf("/"))try{a=ai(`${a}:latest`),t?.({imageId:s,field:"reference:implicit-latest"})}catch{}}try{o=a?di(a):void 0}catch{}return{id:n.id,origin:"custom",name:n.name,description:n.description,localizedDescriptions:n.localizedDescriptions,cover:yr(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 Hs=a.z.discriminatedUnion("kind",[a.z.object({kind:a.z.literal("direct")}).strict(),a.z.object({kind:a.z.literal("control-plane-proxy"),proxyId:Qn,proxyBindingId:Qn,targetNodeId:Qn}).strict()]),Gs=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:Xn.optional(),target:$n.optional(),lastError:xn.optional(),updatedAt:Xn}).strict(),Ws=a.z.object({id:Qn,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:Hs.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:Qn.optional(),secret:a.z.string().trim().max(4096).optional(),pairedAt:Xn.optional(),pairing:a.z.object({status:a.z.enum(["pending","paired","expired"]).default("pending"),joinToken:a.z.string().trim().max(4096).optional(),expiresAt:Xn.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:Gs.optional(),appInventory:Ei.optional(),labels:Zn,lastSeenAt:Xn.optional(),createdAt:Xn,updatedAt:Xn}).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."})}),Vs=a.z.object({id:Qn,nodeId:Qn,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:Zn,createdAt:Xn,updatedAt:Xn}).strict(),Ks=a.z.object({instanceId:Qn,runtimeKind:a.z.literal("docker"),state:a.z.enum(["pending","available","stopped","unavailable"]),sampledAt:Xn,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(),Js=a.z.object({ok:a.z.boolean().optional(),role:a.z.string().optional(),nodeId:Qn.optional(),platform:mi.optional(),arch:yi.optional(),protocolVersion:Yn.optional(),build:Wi.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:Xn.optional()}).strip(),Ys=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(),Qs=a.z.object({nodeId:Qn,joinToken:a.z.string().trim().min(1),expiresAt:Xn}).passthrough(),Xs=a.z.object({nodeId:Qn,keyId:Qn,secret:a.z.string().regex(/^[A-Za-z0-9_-]{32,128}$/),pairedAt:Xn}).strict(),Zs=a.z.object({id:Qn,keyId:Qn,name:a.z.string().trim().min(1).max(160).optional(),pairedAt:Xn,updatedAt:Xn,current:a.z.boolean()}).passthrough(),er=a.z.object({keyId:Qn,revoked:a.z.literal(!0),revokedAt:Xn}).strict(),tr=a.z.object({id:Qn,pairingKeyId:Qn,url:a.z.string().trim().min(1).max(2048),name:a.z.string().trim().min(1).max(160).optional(),enabled:a.z.boolean(),createdAt:Xn,updatedAt:Xn,status:a.z.enum(["disabled","connecting","connected","reconnecting","failed"]),lastConnectedAt:Xn.optional(),lastDisconnectedAt:Xn.optional(),error:a.z.string().optional()}).passthrough(),nr=a.z.object({pairing:Zs,connection:a.z.object({id:Qn,pairingKeyId:Qn,url:a.z.string().trim().min(1).max(2048),name:a.z.string().trim().min(1).max(160).optional(),enabled:a.z.boolean(),createdAt:Xn,updatedAt:Xn}).passthrough(),tunnel:a.z.object({status:a.z.enum(["disabled","saved","connecting","connected","failed"]),error:a.z.string().trim().max(2048).optional()}).passthrough()}).passthrough(),ir=a.z.object({deleted:a.z.boolean().optional()}).passthrough(),sr=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(),rr=a.z.object({image:Rs,status:a.z.enum(["available","pull-required","unknown"]),localImage:sr.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(),or=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(or)}).passthrough()),ar=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(),dr=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(),cr=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"}),lr=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(),pr=a.z.object({id:Qn,name:a.z.string().trim().min(1).max(160),projectId:Qn.optional(),source:as,sourceSnapshot:a.z.record(a.z.string(),a.z.unknown()).default({}),modelSelection:pi,nodeId:Qn,runtimeId:Qn,imageSelection:ui.optional(),environmentSource:hi.optional(),environmentTemplateOrigin:Ii.optional(),imageSnapshot:js.optional(),imageProvisioning:Ds.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:Yn.optional(),instanceVersion:a.z.string().trim().max(80).optional(),build:Wi.optional(),runtimeVersion:Yi.optional(),ready:a.z.boolean().default(!1),capabilities:a.z.record(a.z.string(),a.z.unknown()).default({}),appInventory:Ei.optional(),config:a.z.object({autoImportAgentConfigs:a.z.boolean().default(!0),defaultCodexPermissionMode:X.default("ask")}).strict().default({autoImportAgentConfigs:!0,defaultCodexPermissionMode:"ask"}),workspace:lr.default({status:"unknown"}),target:dr.default({strategy:"direct-port",status:"unknown"}),access:cr,apps:a.z.object({runningCount:a.z.number().int().min(0).default(0),problemCount:a.z.number().int().min(0).default(0),updatedAt:Xn.optional(),revision:a.z.number().int().min(0).optional()}).strict().default({runningCount:0,problemCount:0}),aiSessions:Me.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:Zt,deployments:a.z.array(tn).default([]),runtime:a.z.array(nn).default([])}).strict()).default([]),recentRuns:a.z.array(sn).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:Xn.optional(),createdAt:Xn,updatedAt:Xn}).strict(),ur="instance.lifecycle.snapshot",hr=a.z.object({instanceId:pr.shape.id,revision:a.z.number().int().min(0),updatedAt:Xn,status:pr.shape.status.unwrap(),health:pr.shape.health.unwrap(),connectionStatus:pr.shape.connectionStatus.unwrap(),accessStatus:a.z.enum(["reachable","endpoint-unreachable"]),imageProvisioning:Ds.optional(),workspace:lr,runtime:pr.shape.runtime.unwrap(),runtimeVersion:Yi.optional(),ready:a.z.boolean(),lastHeartbeatAt:Xn.optional()}).strict();function gr(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=mr(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=mr(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 mr(e,t){let n=e;for(const e of t){if(!n||"object"!=typeof n)return;n=n[e]}return n}function yr(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:Qn.optional(),projectId:Qn.optional(),source:as.optional(),nodeId:Qn.optional(),runtimeId:Qn.optional(),imageSelection:ui.optional(),instanceVersion:a.z.string().trim().max(80).optional(),protocolVersion:Yn,build:Wi.optional(),controlMode:a.z.enum(["standalone","controlled"]).default("controlled"),capabilities:a.z.record(a.z.string(),a.z.unknown()).default({}),appInventory:Ei.optional(),target:dr.default({strategy:"direct-port",status:"unknown"}),workspace:lr.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!==Jn||e.appInventory||t.addIssue({code:"custom",path:["appInventory"],message:"Current protocol register payload requires appInventory."})}),a.z.object({status:pr.shape.status.optional(),health:pr.shape.health.optional(),protocolVersion:Yn,build:Wi.optional(),capabilities:pr.shape.capabilities.optional(),appInventory:Ei.optional(),apps:pr.shape.apps.optional(),aiSessions:pr.shape.aiSessions.optional(),triggers:pr.shape.triggers.optional(),workspace:lr.optional(),target:dr.partial().optional(),processIncarnationId:a.z.string().trim().min(1).max(120).optional()}).strict().superRefine((e,t)=>{e.protocolVersion!==Jn||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"]),Ir=a.z.object({id:Qn,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:Xn,updatedAt:Xn}).strict(),br=a.z.object({id:Qn,channel:fr,bridgeId:Qn.optional(),chatSessionId:a.z.string().trim().min(1).max(240),userId:a.z.string().trim().max(240).optional(),activeProjectId:Qn.optional(),activeInstanceId:Qn.optional(),activeAiSessionId:a.z.string().trim().min(1).max(120).optional(),lastUsedAt:Xn,createdAt:Xn,updatedAt:Xn}).strict(),vr=a.z.object({source:a.z.object({type:a.z.literal("chat-gateway").default("chat-gateway"),channel:fr,bridgeId:Qn.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(K).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:Qn,aiSessionId:a.z.string().trim().min(1).max(120)}).strict().optional()}).strict(),wr=a.z.object({id:Qn,instanceId:Qn,projectId:Qn.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:Xn}).strict();function Sr(e){return!1!==e.ready&&(!e.runtimeVersion||["matched","failed"].includes(e.runtimeVersion.phase))}const Ar=6048e5;function kr(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 zr(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 Cr(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 Tr=a.z.enum(["ai.sessions","app.sessions"]),Er=a.z.object({topic:Tr,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(),xr=a.z.object({protocolVersion:a.z.literal(1),streams:a.z.array(Er)}).strict(),Nr=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(),_r=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:Nr,protocolVersion:a.z.string().regex(/^\d{4}-\d{2}-\d{2}$/),issuedAt:a.z.string().datetime(),expiresAt:a.z.string().datetime()}).strict(),Or=a.z.object({data:a.z.object({payload:_r,signature:a.z.string().regex(/^[A-Za-z0-9_-]{86}$/)}).strict()}).strict(),Pr=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(),Rr=a.z.object({username:a.z.string().trim().min(1).max(80),password:a.z.string().min(1).max(4096),device:Pr}).strict(),jr=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(),Dr=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:Pr,user:jr}).strict();a.z.object({data:a.z.object({sessionToken:a.z.string().trim().min(32),session:Dr}).strict()}).strict(),a.z.object({data:a.z.array(Dr)}).strict(),a.z.object({data:a.z.object({revoked:a.z.boolean()}).strict()}).strict();function Mr(e,t=448){n.mkdirSync(e,{recursive:!0,mode:t}),n.chmodSync(e,t)}function Lr(e,i,s={}){const r=s.directoryMode??448,o=s.fileMode??384;Mr(t.dirname(e),r),c.sync(e,`${JSON.stringify(i,null,2)}\n`,{encoding:"utf8",mode:o}),n.chmodSync(e,o)}function qr(e,t){console.warn(JSON.stringify({message:e,...t}))}function $r(e){return e&&"object"==typeof e&&"issues"in e?{issues:e.issues}:{error:e instanceof Error?e.message:String(e)}}function Br(e,t){const i=t.logger||qr;let s;try{s=JSON.parse(n.readFileSync(e,"utf8"))}catch(t){return void i("stored JSON could not be read",{filePath:e,...$r(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 Ur(e){return`${e}_${i.randomUUID().replace(/-/g,"").slice(0,20)}`}function Fr(){return i.randomBytes(24).toString("base64url")}class Hr{directory;options;permissionsInitialized=!1;constructor(e,t={}){this.directory=e,this.options=t}init(){if(this.permissionsInitialized&&n.existsSync(this.directory))return;Mr(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=Br(t.join(this.directory,e),this.options);return n?[n]:[]})}get(e){this.init();const t=this.filePath(e);return n.existsSync(t)?Br(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 Lr(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 Gr{filePathValue;defaults;options;constructor(e,t,n={}){this.filePathValue=e,this.defaults=t,this.options=n}init(){Mr(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)?Br(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 Lr(this.filePathValue,n,this.options),n}}const Wr=d.promisify(i.scrypt),Vr="task_handoff_cp_session",Kr=a.z.enum(["disabled","password"]),Jr=a.z.string().trim().min(1).max(80).regex(/^[a-zA-Z0-9_.@-]+$/),Yr=a.z.string().min(8).max(4096),Qr=a.z.object({username:Jr,password:Yr}).strict(),Xr=a.z.object({username:a.z.string().trim().min(1).max(80),password:a.z.string().min(1).max(4096)}).strict(),Zr=a.z.object({currentPassword:a.z.string().min(1).max(4096),newPassword:Yr}).strict(),eo=a.z.object({username:Jr,password:Yr}).strict(),to=a.z.object({id:a.z.string().trim().min(1),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}),no=to.extend({username:Jr,passwordHash:a.z.string().trim().min(1),role:a.z.enum(["viewer","operator","admin"]),lastLoginAt:a.z.string().datetime().optional()}).strict(),io=to.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:Pr.optional()}).strict().refine(e=>"mobile"!==e.clientType||Boolean(e.device),{path:["device"],message:"Mobile sessions require device metadata."});function so(){return(new Date).toISOString()}function ro(e,t){return Number.isInteger(e)&&Number(e)>0?Number(e):t}class oo{options;sourceFailures=new Map;usernameFailures=new Map;concurrent=0;constructor(e={}){this.options=function(e={}){return{windowMs:ro(e.windowMs,9e5),maxFailuresPerSource:ro(e.maxFailuresPerSource,20),maxFailuresPerUsername:ro(e.maxFailuresPerUsername,10),maxConcurrent:ro(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 ao("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 ao("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 ao(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 co(e){return i.createHash("sha256").update(e).digest("base64url")}async function lo(e){const t=i.randomBytes(16).toString("base64url");return`scrypt$${t}$${(await Wr(e,t,64)).toString("base64url")}`}async function po(e,t){const[n,s,r]=t.split("$");if("scrypt"!==n||!s||!r)return!1;const o=await Wr(e,s,64),a=Buffer.from(r,"base64url");return a.length===o.length&&i.timingSafeEqual(a,o)}function uo(e){return{id:e.id,username:e.username,role:e.role,createdAt:e.createdAt,updatedAt:e.updatedAt,lastLoginAt:e.lastLoginAt}}function ho(e,t){return Dr.parse({id:e.id,expiresAt:e.expiresAt,createdAt:e.createdAt,lastSeenAt:e.lastSeenAt,device:e.device,user:uo(t)})}class go{mode;users;sessions;loginRateLimiter;bootstrapAdminInProgress=!1;credentialUpdateInProgress=!1;constructor(e,t={}){this.mode=function(e={}){return Kr.parse(e.mode||process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"disabled")}(t),this.users=new Hr(e.authUsersDir,{schema:no}),this.sessions=new Hr(e.authSessionsDir,{schema:io}),this.loginRateLimiter=new oo(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=Qr.parse(e);this.bootstrapAdminInProgress=!0;try{const e=so();return uo(this.users.put({id:Ur("user"),username:t.username,passwordHash:await lo(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=Xr.parse(e),i=await this.authenticate(n.username,n.password,t),s=this.createSession(i,"web");return{user:uo(i),sessionToken:s.token,expiresAt:s.record.expiresAt}}async loginMobile(e,t={}){const n=Rr.parse(e),i=await this.authenticate(n.username,n.password,t),s=this.createSession(i,"mobile",n.device);return{sessionToken:s.token,session:ho(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=Zr.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 po(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 po(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=so(),t=this.users.put({...i.storedUser,passwordHash:await lo(s.newPassword),updatedAt:e});this.revokeUserSessions(t.id);const n=this.createSession(t,"web");return{user:uo(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=so(),s=this.users.put({...n[0],username:t.username,passwordHash:await lo(t.password),updatedAt:i});return this.revokeUserSessions(s.id),uo(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 po(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=so();return this.users.put({...n,lastLoginAt:r,updatedAt:r})}finally{this.loginRateLimiter.finish()}}createSession(e,t,n){const i=so(),s=Fr(),r=this.sessions.put({id:Ur("mobile"===t?"msess":"sess"),userId:e.id,tokenHash:co(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<=so()||s.tokenHash!==co(i))return;const r=this.users.get(s.userId);if(!r)return;const o=so();return{session:this.sessions.put({...s,lastSeenAt:o,updatedAt:o}),user:uo(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>so()).map(e=>ho(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 mo(e,t){let n=vo(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=bo(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 yo(e,t){const n=mo(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)=>Io(t)<Io(e)?t:e);n.push(...fo(s,[...t,...i.path]))}return n}function Io(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(Io)):1)},0)}function bo(e,t){let n=e;for(const e of t){if(!n||"object"!=typeof n)return;n=n[e]}return n}function vo(e){return Array.isArray(e)?e.map(vo):e&&"object"==typeof e?Object.getPrototypeOf(e)!==Object.prototype&&null!==Object.getPrototypeOf(e)?e:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,vo(t)])):e}const wo=a.z.enum(["import","export"]),So=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(),Ao=a.z.object({direction:wo,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(),ko=a.z.object({import:a.z.string().trim().min(1).max(1e3).default("."),export:a.z.string().trim().min(1).max(1e3).default(".")}).strict(),zo=a.z.object({programs:a.z.array(So),preferences:ko}).strict(),Co=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(),To=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:wo,items:a.z.array(Co).max(100)}).strict(),Eo=a.z.object({direction:wo,workspaceFolder:a.z.string().trim().min(1).max(1e3),programs:a.z.array(To).min(1).max(20)}).strict();class xo{options;resumeSnapshotRefreshFailures=0;lastResumeSnapshotRefreshFailure;constructor(e){this.options=e}async resolveApproval(e,t,n){return yo(_e,await this.post(e,Oo(t,"approval"),{decision:n}))}async listHistory(e){return yo(Pe,await this.get(e,"/ai-sessions/history"))}async historyDetail(e,t){return yo(Re,await this.get(e,`/ai-sessions/history/${encodeURIComponent(t)}`))}async resume(e,t){const n=yo(je,await this.post(e,Oo(t,"resume"),{}));return await this.refreshAfterCommittedResume(e,t),n}async create(e,t){Ro(t.attachments||[]);const n=await this.options.requireInstance(e),i=t.permissionMode||("codex"===t.agent?n.config.defaultCodexPermissionMode:void 0);return yo(ye,await this.options.request(n,"/ai-sessions",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...t,...i?{permissionMode:i}:{}})}))}async openApp(e,t,n){return yo(Ie,await this.post(e,Oo(t,"open-app"),{clientRequestId:n}))}async close(e,t,n){return yo(ve,await this.post(e,Oo(t,"close"),{clientRequestId:n}))}async refreshAfterCommittedResume(e,t){try{await this.options.refreshSnapshots()}catch(n){const i={instanceId:e,aiSessionId:t,code:No(n),message:_o(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){Ro(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 yo(_e,await this.options.request(a,Oo(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 yo(de,await this.get(e,Oo(t,"mentions")))}async searchMentionFiles(e,t,n){return yo(le,await this.post(e,Oo(t,"mentions/files"),{query:n}))}async executeCommand(e,t,n){return yo(te,await this.post(e,Oo(t,"commands"),n))}async queue(e,t){return yo(ze,await this.get(e,Oo(t,"queue")))}async steerQueuedMessage(e,t,n){return yo(_e,await this.post(e,Po(t,n,"steer"),{}))}async retryQueuedMessage(e,t,n){return yo(Ne,await this.post(e,Po(t,n,"retry"),{}))}async removeQueuedMessage(e,t,n){const i=await this.options.requireInstance(e);return yo(Ne,await this.options.request(i,Po(t,n),{method:"DELETE"}))}async editQueuedMessage(e,t,n,i){const s=Ae.parse(i);return yo(Ne,await this.patch(e,Po(t,n),s))}async reorderQueuedMessages(e,t,n){const i=Se.parse(n);return yo(Ne,await this.patch(e,Oo(t,"queue/reorder"),i))}async interrupt(e,t){return yo(_e,await this.post(e,Oo(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 No(e){return e&&"object"==typeof e&&"code"in e&&"string"==typeof e.code?e.code:"AI_SESSION_SNAPSHOT_REFRESH_FAILED"}function _o(e){return e instanceof Error?e.message:String(e)}function Oo(e,t){return`/ai-sessions/${encodeURIComponent(e)}/${t}`}function Po(e,t,n){return`${Oo(e,"queue")}/${encodeURIComponent(t)}${n?`/${n}`:""}`}function Ro(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 jo(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 Do{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=mo(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 Mo{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",Js)}checkUpdate(e,t){return this.client.requestSchema(e,"/updates/check",es,{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",Ys)}updateExternalListener(e,t){return this.client.requestSchema(e,"/settings/external-listener",Ys,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}createPairingInvite(e,t={}){return this.client.requestSchema(e,"/pairing/invites",Qs,{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",nr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}listControlPlanePairings(e){return this.client.requestSchema(e,"/control-plane-pairings",a.z.array(Zs))}deleteControlPlanePairing(e,t){return this.client.requestSchema(e,`/control-plane-pairings/${encodeURIComponent(t)}`,ir,{method:"DELETE"})}listControlPlaneConnections(e){return this.client.requestSchema(e,"/control-plane-connections",a.z.array(tr))}deleteControlPlaneConnection(e,t){return this.client.requestSchema(e,`/control-plane-connections/${encodeURIComponent(t)}`,ir,{method:"DELETE"})}listDockerImages(e){return this.client.requestSchema(e,"/docker/images",a.z.array(sr))}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(or))}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(Vs),t)}createRuntime(e,t){return this.client.requestSchema(e,"/runtimes",Vs,{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,Vs,{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,Vs,{method:"POST"})}deleteRuntime(e,t){return this.client.requestSchema(e,`/runtimes/${encodeURIComponent(t)}`,ir,{method:"DELETE"})}deleteLocalFolder(e,t){return this.client.requestSchema(e,`/local-folders/${encodeURIComponent(t)}`,ir,{method:"DELETE"})}listModels(e,t={}){return this.client.requestSchema(e,"/models",a.z.array(hs),t)}createModel(e,t){return this.client.requestSchema(e,"/models",hs,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}deployModel(e,t,n){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}/deploy`,hs,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}updateModel(e,t,n){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}`,hs,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteModel(e,t){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}`,ir,{method:"DELETE"})}assignInstanceModels(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/model-assignment`,a.z.object({assignment:gs,instance:pr}).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(jo(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",pr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}updateInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}`,pr,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/delete`,Si,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}listEnvironmentTemplates(e,t={}){return this.client.requestSchema(e,"/environment-templates",a.z.array(xi),t)}getEnvironmentTemplate(e,t,n={}){return this.client.requestSchema(e,`/environment-templates/${encodeURIComponent(t)}`,xi,n)}createEnvironmentTemplate(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/environment-templates`,xi,{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:xi.shape.id}).strict(),{method:"DELETE"})}startInstance(e,t,n={}){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/start`,pr,{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`,pr,{method:"POST"})}stopInstance(e,t){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/stop`,pr,{method:"POST"})}restartInstance(e,t,n={}){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/restart`,pr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}instanceResourceMetrics(e,t){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/metrics`,Ks)}proxyRawInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/proxy/raw`,ar,{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:[jo(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,pr.safeParse(function(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,n=new Set(Object.keys(pr.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=yr(e,["id","name","kind","source","availability","diagnosticCode"]);return!t||"object"!=typeof t||Array.isArray(t)?t:{...t,capabilities:yr(e.capabilities,["automation","supportsCwdSelection"])}}):t.items,issues:Array.isArray(t.issues)?t.issues.map(e=>yr(e,["code","message"])):t.issues},i=Ei.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=as.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=yr(t,s);if("local-folder"!==n){const e=gr(is,yr(t.ref,["type","name","commit"])),n=gr(ss,yr(t.auth,["type","secretId"])),i=gr(rs,yr(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=gr(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=gr(Wi,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=gr(De,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:Xn.safeParse(t.updatedAt).success?t.updatedAt:(new Date).toISOString()};return Object.keys(t).some(e=>!["runningCount","waitingCount","staleCount","sessions","updatedAt"].includes(e)),Me.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=gr(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=yr(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=yr(e,i)}return n.action=yr(t.action,["promptTemplate"]),n.policy=yr(t.policy,["cooldownMs","maxConcurrentRuns","whenBusy"]),gr(Zt,n)}(i.config);return"string"==typeof i.configHash&&s?[{configHash:i.configHash,config:s,deployments:n(i.deployments,tn),runtime:n(i.runtime,nn)}]:[]}):[];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,sn)}}(t.triggers,"string"==typeof t.id&&t.id),i.apps=gr(pr.shape.apps.unwrap(),yr(t.apps,["runningCount","problemCount","updatedAt","revision"]),0,0,"string"==typeof t.id&&t.id)||{runningCount:0,problemCount:0},i.config=gr(pr.shape.config.unwrap(),yr(t.config,["autoImportAgentConfigs","defaultCodexPermissionMode"]),0,0,"string"==typeof t.id&&t.id)||{autoImportAgentConfigs:!0,defaultCodexPermissionMode:"ask"},i.modelSelection=gr(pi.unwrap(),yr(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=Fs(n),{reference:s,...r}=i,o=n.requestedReference??s;let a;try{a="string"==typeof o?di(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?yr(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=yr(t.imageSelection,["imageId","tag"]);i.imageSelection=r||(s?{imageId:s,tag:i.imageSnapshot?.tag}:void 0),i.imageProvisioning=gr(Ds,yr(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(Yi.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(Ji.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=Xn.safeParse(t.lastAttemptAt),l=Xn.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=gr(lr,t.workspace,0,0,"string"==typeof t.id&&t.id)||{status:"unknown"},i.environmentSource=gr(hi,t.environmentSource,0,0,"string"==typeof t.id&&t.id),i.environmentTemplateOrigin=gr(Ii,t.environmentTemplateOrigin,0,0,"string"==typeof t.id&&t.id),i.runtime=gr(pr.shape.runtime.unwrap(),t.runtime,0,0,"string"==typeof t.id&&t.id)||{labels:{}},i.target=gr(dr,yr(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=gr(cr,yr(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(pr.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!==Jn?(this.client.logger?.warn?.({nodeId:e.id,instanceId:n.data.id,expectedProtocolVersion:Jn,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 Lo(e){return e.readyState===(e.OPEN??1)}function qo(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 $o(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 Bo(e,t,n){e.close($o(t),qo(n)||void 0)}function Uo(e,t,n,i){if(Lo(e))for(const e of t.splice(0))if(i(e),!n(e))return}function Fo(e,t,n={}){const i=n.pendingFrameLimit??256,s=n.maxFrameBytes??8388608,r=n.maxTotalBytes??1073741824,o=n.maxBufferedBytes??16777216;let a=!1,d=Lo(t);const c=[],l=[];let p,u=0,h=0,g=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 g+=a,n.onFrame?.(i,a),!(a>s||g>r)||(Bo(e,1009,"WebSocket bridge traffic limit exceeded."),Bo(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 Bo(e,1013,"WebSocket bridge consumer is too slow."),Bo(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 Bo(e,1011,"WebSocket bridge send failed."),Bo(t,1011,"WebSocket bridge send failed."),!1}},b=(n,s,r)=>{if(s.length>=i)return Bo(e,1011,"WebSocket bridge pending frame limit exceeded."),void Bo(t,1011,"WebSocket bridge pending frame limit exceeded.");const a="upstream"===n?u:h;if((("upstream"===n?t:e).bufferedAmount??0)+a+r.bytes>o)return Bo(e,1013,"WebSocket bridge consumer is too slow."),void Bo(t,1013,"WebSocket bridge consumer is too slow.");s.push(r),"upstream"===n?u+=r.bytes:h+=r.bytes};return n.upstreamOpenTimeoutMs&&!d&&(p=setTimeout(()=>{d||a||(Bo(e,1011,"Upstream websocket did not open."),Bo(t))},n.upstreamOpenTimeoutMs)),e.on("open",()=>Uo(e,l,t=>I(e,t),e=>{h-=e.bytes})),t.on("open",()=>{f(),d=!0,n.onUpstreamOpen?.(),Uo(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)};Lo(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)};Lo(e)?I(e,i):b("client",l,i)}),t.on("close",(t,i)=>{f(),n.onUpstreamClose?.(t,i),(d||a||!n.onUpstreamCloseBeforeOpen?.())&&Bo(e,t,i)}),t.on("error",t=>{n.onUpstreamError?.(t),(d||a||!n.onUpstreamErrorBeforeOpen?.(t))&&Bo(e)}),e.on("close",(e,i)=>{f(),a=!0,n.onClientClose?.(e,i),Bo(t,e,i)}),e.on("error",e=>{f(),a=!0,n.onClientError?.(e),Bo(t,1011,"WebSocket bridge client failed.")}),{close:(n,i)=>{f(),Bo(t,n,i),Bo(e,n,i)}}}const Ho="TASK_HANDOFF_NODE_AGENT_V1",Go=6e4,Wo="/api/node-tunnel";function Vo(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=Ko(e.body||""),r=Jo(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 Ko(e=""){return i.createHash("sha256").update(e).digest("hex")}function Jo(e,t){return i.createHmac("sha256",e).update(function(e){return[Ho,e.keyId,e.method.toUpperCase(),e.pathWithQuery,e.timestamp,e.nonce,e.bodySha256].join("\n")}(t)).digest("hex")}function Yo(e){if(e.startsWith("ipc://"))return decodeURIComponent(e.slice(6))}function Qo(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 Xo(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 Zo(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function ea(e,t){const n=AbortSignal.timeout(t);return e?AbortSignal.any([e,n]):n}async function ta(e,t,n,i={}){const s=Yo(t);return s?(Qo(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?h.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 na(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 ia(e,t,n,i){const s=na(e),r=Yo(s),o=`/api/node-agent${t}`;if(r)return Qo(r),Xo(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 sa(e,t,n){const i=new Headers(n),s=Vo(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 ra(e=fetch,t={}){const n=t.openWebSocket||ia,i=Zo(t.requestTimeoutMs,3e4),s=Zo(t.streamHeaderTimeoutMs,3e4),r=Zo(t.websocketOpenTimeoutMs,1e4);return{request:async(t,n,s={})=>{const r=na(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=sa(t,{method:o,pathWithQuery:`/api/node-agent${n}`,body:a||""},s.headers);return ta(e,r,n,{...s,body:a,headers:d,signal:ea(s.signal,i)})},requestStream:async(t,n,i={})=>{const r=na(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=sa(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 ta(e,r,n,{...i,body:a,headers:d,signal:l})}finally{clearTimeout(c)}}(0,s,c)},proxyWebSocket(e,t,i,s,o={}){const a=sa(e,{method:"GET",pathWithQuery:`/api/node-agent${i}`},o);Fo(t,n(e,i,s,a),{upstreamOpenTimeoutMs:r,onUpstreamError:()=>t.close(1011,"Instance websocket proxy failed."),onUpstreamErrorBeforeOpen:()=>!0})}}}class oa{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 aa(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 da(e,t){if("control-plane-proxy"!==e.connectionPath.kind)throw aa("Control-plane proxy transport requires a proxy connection path.","CONTROL_PLANE_PROXY_CONFIGURATION_INVALID",400);const n=t(e);if(!n)throw aa("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 aa("Control-plane proxy credential does not match the node connection identity.","CONTROL_PLANE_PROXY_CREDENTIAL_MISMATCH",409);return n}function ca(e,t){const n=new Headers(t);n.set(An,hn),n.set(kn,e.sourceControlPlaneId),n.set(zn,e.bindingKeyId),n.set(Cn,e.credential);const s=In.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 la(e){const t=vn.safeParse(e);if(t.success)return t.data;const n=aa("Control-plane proxy route is invalid.",Tn.RouteInvalid,400);throw Object.assign(n,{issues:t.error.issues}),n}function pa(e,t,n){return t?new l.WebSocket(e,t,{headers:n}):new l.WebSocket(e,{headers:n})}class ua{credentialForNode;fetchImpl;openWebSocket;constructor(e){this.credentialForNode=e.credentialForNode,this.fetchImpl=e.fetchImpl||fetch,this.openWebSocket=e.openWebSocket||pa}async fetch(e,t,n={}){const i=da(e,this.credentialForNode),s=function(e,t){const n=new URL(la(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:ca(i,n.headers)})}catch(e){if(function(e){return e instanceof Error&&("AbortError"===e.name||"ABORT_ERR"===e.code)}(e))throw e;throw aa(`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=da(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",la(t)),n}(r,n).toString(),i,ca(r,s));Fo(t,o,{onUpstreamError:()=>t.close(1011,"Control-plane proxy websocket failed."),onUpstreamErrorBeforeOpen:()=>!0})}}const ha=new Set(Object.keys(Vn.shape)),ga=new Set(Object.keys(Kn.shape));function ma(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 ya(e){const{credential:t,...n}=e;return n}class fa{pendingClaims;nodeCredentials;identity;constructor(e,t){this.pendingClaims=new Hr(e.pendingClaimsDir,{schema:Vn,sanitize:e=>function(e){return ma(e,ha,e=>t?.("unknown stored pending proxy claim fields were ignored",{fields:e}))}(e),logger:t,directoryMode:448,fileMode:384}),this.nodeCredentials=new Hr(e.nodeCredentialsDir,{schema:Kn,sanitize:e=>function(e){return ma(e,ga,e=>t?.("unknown stored proxy node credential fields were ignored",{fields:e}))}(e),logger:t,directoryMode:448,fileMode:384}),this.identity=new Gr(e.identityPath,()=>({controlPlaneId:Ur("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(ya)}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 Ia=a.z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),ba=a.z.string().datetime(),va=a.z.enum(["connecting","handshaking","healthy","reconnecting","suspect","offline"]),wa=a.z.enum(["start","stop","restart","retry-image"]);a.z.object({instanceId:Ia,revision:a.z.number().int().nonnegative(),updatedAt:ba,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:ba.optional()}).strip();const Sa=a.z.object({code:a.z.string().trim().min(1).max(120),message:a.z.string().trim().min(1).max(2048)}).strict(),Aa=a.z.object({id:Ia,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:va.optional(),lastSeenAt:ba.optional(),observedAt:ba,capabilities:a.z.array(a.z.string().trim().min(1).max(120)).max(256),error:Sa.optional()}).strict();a.z.array(Aa);const ka=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(),za=a.z.object({id:Ia,name:a.z.string().trim().min(1).max(160),nodeId:Ia,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:X.default("ask")}).strict().default({defaultCodexPermissionMode:"ask"}),lastHeartbeatAt:ba.optional(),heartbeatAgeMs:a.z.number().int().nonnegative().optional(),observedAt:ba,runtime:a.z.object({id:Ia,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:qe,availableActions:a.z.array(wa).max(4).default([]),availableApps:a.z.array(ka).max(256).default([]),availableAgents:a.z.array(ka).max(256),error:Sa.optional()}).strict();function Ca(e){if(!e||"object"!=typeof e)return;const t=e,n=Wi.safeParse(t.build),i=mi.safeParse(t.platform),s=yi.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 Ta(e){const{agent:t,...n}=e.capabilities,{secret:i,...s}=e.auth,r=s.pairing?{...s.pairing,joinToken:void 0}:void 0,o=Ca(t);return{...e,auth:r?{...s,pairing:r}:s,capabilities:o?{...n,agent:o}:n}}function Ea(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===Jn,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 za.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})}function xa(e){return"local-folder"===e.type?{mode:"local-bind",path:"/workspace",readOnly:!1}:{mode:"git-clone",path:"/workspace",readOnly:!1}}function Na(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 _a(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 Oa(){return(new Date).toISOString()}function Pa(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 Ra(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 ja(e){return e instanceof Error?e.message:String(e)}function Da(e,t){const n=new Error(t);throw Object.assign(n,{statusCode:404,code:e}),n}a.z.array(za);const Ma=a.z.object({proxyOrigin:bn,inviteToken:a.z.string().trim().min(24).max(512),name:a.z.string().trim().min(1).max(160).optional()}).strict(),La=a.z.object({data:a.z.object({binding:Mn,closed:a.z.object({abortedRequests:a.z.number().int().nonnegative(),closedSockets:a.z.number().int().nonnegative()}).strict()}).strict()}).strict();class qa{claimOperations=new Map;options;constructor(e){this.options=e}listPendingClaims(){return this.options.privateStore.publicPendingClaims()}async claimNode(e){const t=Ma.parse(e),n=Oa(),i=Ur("proxy_claim"),s={id:i,claimId:i,proxyOrigin:t.proxyOrigin,...t.name?{requestedName:t.name}:{},sourceControlPlaneId:this.options.privateStore.controlPlaneId(),bindingKeyId:Ur("proxy_key"),credential:Fr(),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||Da("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===Tn.InviteInvalid||s===Tn.BindingRevoked)return{deleted:this.options.privateStore.completePendingClaimCompensation(e),compensationRequired:!1,remoteRevoke:s===Tn.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=yo(Wn,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!==Tn.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,Tn.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:Tn.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=Oa();return this.options.nodes.put(Ws.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=Oa();return this.options.nodes.put(Ws.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===Tn.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=yo(Wn,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:Oa()},d=r||Ws.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:Oa(),target:s.target,updatedAt:Oa()},labels:{},lastSeenAt:s.target.lastSeenAt,createdAt:Oa(),updatedAt:Oa()});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:Ta(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:Tn.BindingIdentityConflict,statusCode:409,retryable:!1}),e}return i}putTargetState(e,t,n){const i=Oa();return this.options.nodes.put(Ws.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:hn,...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:ca(e)})}async responsePayload(e){return e.json().catch(()=>{})}requireRevocationReceipt(e,t){const n=mo(La,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:Tn.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:Tn.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:Oa()}}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 $a=a.z.object({id:ls.shape.id.optional(),name:ls.shape.name,source:as,defaultImageSelection:ls.shape.defaultImageSelection,defaultNodeId:ls.shape.defaultNodeId,defaultRuntimeId:ls.shape.defaultRuntimeId,workspacePolicy:ds.optional(),labels:ls.shape.labels.optional()}).strict(),Ba=$a.omit({id:!0}).partial().strict();function Ua(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"/"!==e&&"\\"!==e}const Fa=a.z.string().refine(Ua,"Mention trigger must be one printable non-alphanumeric character other than / or \\.");function Ha(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"\\"!==e}const Ga=a.z.string().refine(Ha,"Command trigger must be one printable non-alphanumeric character other than \\."),Wa=a.z.object({publicBaseUrl:a.z.string().trim().max(2048).optional(),updateChannel:Vi.default("stable"),mentionTrigger:Fa.default("@"),commandTrigger:Ga.default("/"),diagnosticLogs:a.z.boolean().default(!1)}).strict().refine(e=>e.mentionTrigger!==e.commandTrigger,{path:["commandTrigger"],message:"Command and mention triggers must be different."}),Va=a.z.object({publicBaseUrl:a.z.string().trim().max(2048).optional(),updateChannel:Vi.optional(),mentionTrigger:Fa.optional(),commandTrigger:Ga.optional(),diagnosticLogs:a.z.boolean().optional()}).strict(),Ka=a.z.object({id:Os.shape.id.optional(),name:Os.shape.name,description:Os.shape.description,cover:Os.shape.cover,reference:Os.shape.reference,pullPolicy:Os.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:Os.shape.defaultEnv.optional(),labels:Os.shape.labels.optional()}).strict(),Ja=Ka.omit({id:!0}).partial().strict(),Ya=a.z.object({name:Ir.shape.name.optional(),channel:Ir.shape.channel.optional(),enabled:a.z.boolean().optional(),token:Ir.shape.token,defaultChatId:Ir.shape.defaultChatId,allowedUserIds:a.z.array(a.z.string().trim().min(1).max(240)).optional(),pollIntervalMs:Ir.shape.pollIntervalMs.optional(),settings:Ir.shape.settings.optional()}).strict(),Qa=Ya.extend({channel:Ir.shape.channel,name:Ir.shape.name.optional()}),Xa=Zt.extend({id:Zt.shape.configHash}),Za=a.z.object({name:Zt.shape.name,description:Zt.shape.description,source:Yt,action:Qt,policy:Xt.partial().optional()}).strict(),ed=Za,td=a.z.object({instanceIds:a.z.array(pr.shape.id).min(1),target:en,enabled:a.z.boolean().optional()}).strict(),nd=a.z.object({configHash:Zt.shape.configHash,enabled:a.z.boolean().optional()}).strict(),id=a.z.object({mode:a.z.enum(["local-static-key","paired-hmac","proxy-binding"]).default("local-static-key"),keyId:Ws.shape.id.optional(),secret:a.z.string().trim().max(4096).optional(),pairedAt:Ws.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:Ws.shape.createdAt.optional()}).strict().optional()}).strict(),sd=a.z.object({autoImportAgentConfigs:a.z.boolean().optional(),defaultCodexPermissionMode:X.optional()}).strict(),rd=a.z.object({id:pr.shape.id.optional(),name:pr.shape.name.optional(),projectId:pr.shape.projectId,source:as.optional(),sourceSnapshot:a.z.record(a.z.string(),a.z.unknown()).optional(),nodeId:pr.shape.nodeId.optional(),runtimeId:pr.shape.runtimeId.optional(),environmentSource:hi.optional(),imageSelection:pr.shape.imageSelection,config:sd.optional(),modelSelection:pr.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."})}),od=a.z.object({name:pr.shape.name.optional(),config:sd.optional(),modelSelection:pr.shape.modelSelection.optional()}).strict(),ad=a.z.object({name:ps.shape.name,endpoint:ps.shape.endpoint,key:ps.shape.key,model:ps.shape.model,app:ps.shape.app,enabled:ps.shape.enabled.optional(),order:ps.shape.order.optional(),labels:ps.shape.labels.optional()}).strict(),dd=ad.partial().strict(),cd=a.z.object({id:Ws.shape.id.optional(),name:Ws.shape.name,connectionMode:Ws.shape.connectionMode.optional(),connectionPath:Ws.shape.connectionPath.optional(),connectionEnabled:Ws.shape.connectionEnabled.optional(),auth:id.optional(),joinToken:a.z.string().trim().min(1).max(4096).optional(),endpoint:Ws.shape.endpoint,controlEndpoint:Ws.shape.controlEndpoint,containerEndpoint:Ws.shape.containerEndpoint,publicWebBase:Ws.shape.publicWebBase,status:a.z.enum(["unknown","online","offline","degraded"]).optional(),health:a.z.enum(["unknown","ok","degraded","failed"]).optional(),capabilities:Ws.shape.capabilities.optional(),labels:Ws.shape.labels.optional(),lastSeenAt:Ws.shape.lastSeenAt}).strict(),ld=a.z.object({name:Ws.shape.name.optional(),connectionMode:Ws.shape.connectionMode.unwrap().optional(),connectionPath:Ws.shape.connectionPath.unwrap().optional(),connectionEnabled:Ws.shape.connectionEnabled.unwrap().optional(),auth:id.optional(),endpoint:Ws.shape.endpoint,controlEndpoint:Ws.shape.controlEndpoint,containerEndpoint:Ws.shape.containerEndpoint,publicWebBase:Ws.shape.publicWebBase,status:Ws.shape.status.unwrap().optional(),health:Ws.shape.health.unwrap().optional(),capabilities:Ws.shape.capabilities.unwrap().optional(),labels:Ws.shape.labels.unwrap().optional(),lastSeenAt:Ws.shape.lastSeenAt}).strict(),pd=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(),ud=a.z.object({nodeName:a.z.string().trim().min(1).max(160).optional(),expiresInMs:a.z.number().int().positive().max(36e5).optional()}).strict(),hd=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 gd{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 Yo(e)?"local-ipc":"local-loopback"}(n),s=Ws.parse({id:"node_local_probe",name:"Local Node Probe",connectionMode:i,auth:{mode:"local-static-key",secret:t},labels:e,createdAt:Oa(),updatedAt:Oa()}),r=await this.inspect(n,s),o=Oa(),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(Ws.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:Ca(r.data)},labels:{...a?.labels||{},...e},createdAt:a?.createdAt||o,updatedAt:o}))}async create(e){const t=cd.parse(e),n=Oa(),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 md("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 md("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 md("Remote node connections require a paired node secret or join token.","NODE_AGENT_REMOTE_SECRET_REQUIRED");if(r&&!s.keyId)throw md("Remote node connections require a paired key id.","NODE_AGENT_REMOTE_KEY_ID_REQUIRED");const e=t.id||a?.nodeId||Ur("node"),u=Ws.parse({id:e,name:t.name,connectionMode:i,auth:s,labels:t.labels||{},createdAt:n,updatedAt:n}),h="reverse-wss"===i&&(t.id||a?.nodeId)?void 0:await this.inspect(o||"",u),g=t.id||a?.nodeId||h?.nodeId||e;if(!g)throw md("Node id is required.","NODE_ID_REQUIRED");if(a&&t.id&&t.id!==a.nodeId)throw md(`Paired node id ${a.nodeId} does not match requested node id ${t.id}.`,"NODE_AGENT_ID_MISMATCH");if(t.id&&h?.nodeId&&h.nodeId!==t.id)throw md(`Node agent id ${h.nodeId} does not match requested node id ${t.id}.`,"NODE_AGENT_ID_MISMATCH");if(a&&h?.nodeId&&h.nodeId!==a.nodeId)throw Object.assign(new Error("Node agent health identity did not match the completed pairing."),{statusCode:502,code:"NODE_AGENT_PAIRING_IDENTITY_MISMATCH"});const{joinToken:m,...y}=t,f=Ws.parse({...y,id:g,connectionMode:i,auth:s,endpoint:o,controlEndpoint:o,status:t.status||(h?"online":"unknown"),health:t.health||(h?"ok":"unknown"),capabilities:{...t.capabilities||{},...h?{agent:Ca(h.data)}:{}},labels:t.labels||{},createdAt:n,updatedAt:n});if(a&&(l=f,p=a.secret,vd(Ta(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 wd(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),wd(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=Oa();return hd.parse({id:Ur("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?Id(t.nodeId,t.secret):void 0,keyId:t?Id(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?Vo(t,{method:"GET",pathWithQuery:`/api/node-agent${n}`}):{},s=await ta(this.options.fetchImpl,e,n,{headers:i}),r=await s.json().catch(()=>({}));if(!s.ok)throw this.options.warn(bd({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(bd({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=mo(Wi,r.data?.build);return r.data?.protocolVersion!==Jn&&this.options.warn(bd({nodeId:o,nodeEndpoint:e,expectedProtocolVersion:Jn,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(bd({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=mo(Xs,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:Oa(),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 ta(this.options.fetchImpl,e,i,{method:"DELETE",headers:Vo(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:fd(a.error?.code,t.secret,"NODE_AGENT_PAIRING_REVOKE_FAILED"),retryable:408===o.status||429===o.status||o.status>=500});const d=mo(er,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:Id(t.nodeId,t.secret),keyId:Id(t.keyId,t.secret),originalErrorCode:yd(n,t.secret)},"node agent pairing revoked after node creation failed")}catch{}}catch(e){const i={nodeId:Id(t.nodeId,t.secret),keyId:Id(t.keyId,t.secret),originalErrorCode:yd(n,t.secret),compensationErrorCode:yd(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 md(e,t){return Object.assign(new Error(e),{statusCode:400,code:t})}function yd(e,t){return fd(e&&"object"==typeof e&&"code"in e?e.code:void 0,t,"UNKNOWN_ERROR")}function fd(e,t,n){return"string"!=typeof e||!/^[A-Z][A-Z0-9_]{0,127}$/.test(e)||e.includes(t)?n:e}function Id(e,t){return e.includes(t)?"[redacted]":e}function bd(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 vd(e,t){return"string"==typeof e?e.includes(t):Array.isArray(e)?e.some(e=>vd(e,t)):!(!e||"object"!=typeof e)&&Object.entries(e).some(([e,n])=>e.includes(t)||vd(n,t))}function wd(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:yd(e,t)});return e&&"object"==typeof e&&"retryable"in e&&"boolean"==typeof e.retryable&&Object.assign(s,{retryable:e.retryable}),s}class Sd{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 Ad=a.z.object({joinToken:a.z.string().trim().min(1).max(4096),nodeId:Ws.shape.id,nodeName:Ws.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 kd{options;invites=new Sd;constructor(e){this.options=e}createInvite(e={}){const t=ud.parse(e&&"object"==typeof e?e:{}),n=Fr(),i={id:Ur("node_join"),tokenHash:zd(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=Ad.parse(e),n=zd(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=Oa();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(Ws.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 zd(e){return i.createHash("sha256").update(e).digest("hex")}class Cd{options;constructor(e){this.options=e}list(){return this.listAll().map(_a)}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:_a(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 Is.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:Oa()})}create(e){const t=ad.parse(e),n=Oa(),i=bs(t),s=this.options.models.get(i),r=ps.parse({...t,id:i,enabled:t.enabled??!0,order:t.order??this.nextOrder(),labels:t.labels||{},createdAt:s?.createdAt||n,updatedAt:n});return _a(this.options.models.put(r))}update(e,t){const n=dd.parse(t),i=this.requireSecret(e),s=ps.parse({...i,...n,key:n.key?.trim()?n.key:i.key,createdAt:i.createdAt,updatedAt:Oa()}),r=bs(s);return _a(this.options.models.put(ps.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)||Da("MODEL_NOT_FOUND",`Model ${e} was not found.`);return t.forEach((e,t)=>{const i=n.get(e);this.options.models.put(ps.parse({...i,order:100*(t+1),updatedAt:Oa()}))}),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:_a(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 Td(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||Da("MODEL_NOT_FOUND",`Model ${i} was not found on control-plane or node ${e.id}.`),Td(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||Da("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,ps.parse(t)}return ps.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 Td(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 Ed{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}xd(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:Pa(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}xd(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:Pa(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}xd(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 xd(e){if(Sr(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 Nd{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=Na(e.instance);return{...i,aiSessions:$e(i.aiSessions),connectionStatus:n,heartbeatAgeMs:t,project:e.project,image:e.image,node:e.node?Ta(e.node):void 0,runtime:e.runtime,protocolCompatible:!e.instance.protocolVersion||e.instance.protocolVersion===Jn}}({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 _d{options;constructor(e){this.options=e}async create(e){const t=rd.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 Pd("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 Pd(`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 Pd(`Environment template ${p.id} is ${p.status}.`,409,"ENVIRONMENT_TEMPLATE_NOT_READY");if(p&&p.nodeId!==r.id)throw Pd(`Environment template ${p.id} belongs to node ${p.nodeId}.`,409,"ENVIRONMENT_TEMPLATE_NODE_MISMATCH");if(a&&!l&&!p)throw Pd(`Runtime ${o.name} requires an image.`,400,"RUNTIME_IMAGE_REQUIRED");const u=await this.resolveSource({node:r,runtime:o,project:n,source:t.source,sourceSnapshot:t.sourceSnapshot,imageOption:l}),h=await this.options.prepareModels(r,t.modelSelection||{}),g=l?function(e){const t=Oa();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&&g?{image:g}:{},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,h)).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:Od(e,"INSTANCE_START_FAILED")},y=await this.options.gateway.listInstances(r).then(e=>e.find(e=>e.id===y.id)||y).catch(()=>y)}return{...Na(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 Pd("Instance source is required.",400,"INSTANCE_SOURCE_REQUIRED");if("local"===e.runtime.type&&"local-folder"!==t.type)throw Pd("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 Pd(`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 Od(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 Pd(e,t,n){return Object.assign(new Error(e),{statusCode:t,code:n})}class Rd{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:jd(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 dn.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=Za.parse(e||{}),n=Oa(),i={maxConcurrentRuns:t.policy?.maxConcurrentRuns??1,whenBusy:t.policy?.whenBusy??"skip",cooldownMs:t.policy?.cooldownMs},s=cn({source:t.source,action:t.action,policy:i}),r=Xa.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=ed.parse(t||{}),s=Oa(),r={maxConcurrentRuns:i.policy?.maxConcurrentRuns??1,whenBusy:i.policy?.whenBusy??"skip",cooldownMs:i.policy?.cooldownMs},o=cn({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=Xa.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?Dd(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||Da("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),{configHash:e,deletedTemplate:t,results:i}}async applyTrigger(e,t){const n=this.requireTrigger(e),i=td.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=nd.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:Dd(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=Dd(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||Da("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),t}}function jd(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 Dd(e,t){return`ai_${Buffer.from(e).toString("base64url")}_${t}`}class Md{options;constructor(e){this.options=e}getSettings(){return Wa.parse(this.options.settings.get())}updateSettings(e){const t=Va.parse(e),n=Wa.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=$a.parse(e),n=Oa(),i=as.parse(t.source);return this.options.projects.put(ls.parse({...t,id:t.id||Ur("proj"),source:i,defaultImageSelection:t.defaultImageSelection||{imageId:"market_taskhandoff_browser"},defaultNodeId:t.defaultNodeId||this.options.defaultNodeId(),defaultRuntimeId:t.defaultRuntimeId||"runtime_local_docker",workspacePolicy:ds.parse(t.workspacePolicy||xa(i)),labels:t.labels||{},createdAt:n,updatedAt:n}))}updateProject(e,t){const n=Ba.parse(t),i=this.requireProject(e),s=n.source?as.parse(n.source):i.source;return this.options.projects.put(ls.parse({...i,...n,id:e,source:s,workspacePolicy:n.workspacePolicy?ds.parse(n.workspacePolicy):i.workspacePolicy,createdAt:i.createdAt,updatedAt:Oa()}))}deleteProject(e){return this.options.projects.delete(e)}requireProject(e){const t=this.getProject(e);return t||Da("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||Da("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=Ka.parse(e),n=Oa(),i=di(t.reference);return this.options.images.put(Os.parse({...t,id:t.id||Ur("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=Ja.parse(t),i=this.requireImage(e),s=di(n.reference||i.reference);return this.options.images.put(Os.parse({...i,...n,id:e,origin:"custom",reference:s.reference,repository:s.repository,tag:s.tag,createdAt:i.createdAt,updatedAt:Oa()}))}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||Da("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={...zi(e)};return"defaultRuntimeId"in t||(t.defaultRuntimeId="runtime_local_docker"),ls.parse(t)}return ls.parse(e)}(e);return t!==e&&this.options.projects.put(t),t}customImageOption(e){return Rs.parse({id:e.id,origin:"custom",name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover||As,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 Rs.parse({id:e.id,origin:"market",name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover||As,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 Ld(e){const t=di(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:As,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 qd(){const e=(t=process.env.TASK_HANDOFF_BUILT_AT)&&!Number.isNaN(Date.parse(t))?new Date(t).toISOString():(new Date).toISOString();var t;return Ns.parse({protocolVersion:"2026-07-29",catalogId:"task_handoff_embedded",revision:process.env.TASK_HANDOFF_VERSION||"0.0.1",source:"embedded",generatedAt:e,items:[Ld({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"]}),Ld({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"]}),Ld({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"]}),Ld({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 $d{async loadCatalog(){return qd()}}class Bd{snapshot;status;constructor(e=qd()){this.snapshot=Ns.parse(e),this.status=_s.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=Ns.safeParse(e);return t.success?(this.snapshot=t.data,this.status=_s.parse({source:t.data.source,state:"ready",revision:t.data.revision,updatedAt:(new Date).toISOString()}),{accepted:!0,snapshot:t.data}):(this.status=_s.parse({...this.status,state:"failed",updatedAt:(new Date).toISOString(),error:t.error.message}),{accepted:!1,error:t.error})}recordRefreshFailure(e){return this.status=_s.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 Ud{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 Fd{requireInstance;listAppSessions;tokens=new Ud({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=bt(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:Hd(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=>Wd(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 Hd(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):Wd(Gd(n.vnc).noVncPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`:Wd(Gd(n.web).webPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`}function Gd(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Wd(e){return"string"==typeof e&&e.trim()?e.trim():void 0}const Vd={allow:"a",deny:"d",skip:"s"};function Kd(e){return i.createHash("sha256").update(e).digest("base64url").slice(0,Math.ceil(16))}class Jd{tokens=new Ud({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:${Vd[t]}:${Kd(e)}`}}function Yd(e){const{token:t,...n}=e;return{...n,settings:Xd(e.settings),tokenSet:Boolean(e.token)}}function Qd(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 Xd(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 Zd{chatBridges;chatSessions;constructor(e){this.chatBridges=e.chatBridges,this.chatSessions=e.chatSessions}list(){return this.chatBridges.list().map(Yd)}require(e){const t=this.chatBridges.get(e);return t||Da("CHAT_BRIDGE_NOT_FOUND",`Chat bridge ${e} was not found.`),t}create(e){const t=Qa.parse(e),n=Oa(),i=Ir.parse({...t,id:Ur(`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:Qd({},t.settings),createdAt:n,updatedAt:n});var s,r;return this.chatBridges.put(i),Yd(i)}update(e,t){const n=Ya.parse(t),i=this.require(e),s=Qd(i.settings,n.settings),r=Ir.parse({...i,...n,id:e,channel:i.channel,name:n.name||i.name,settings:s,updatedAt:Oa()});return this.chatBridges.put(r),Yd(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 ec{chatSessions;constructor(e){this.chatSessions=e.chatSessions}list(){return this.chatSessions.list()}require(e){const t=this.chatSessions.get(e);return t||Da("CHAT_SESSION_NOT_FOUND",`Chat session ${e} was not found.`),t}upsert(e){const t=Oa(),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=br.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 tc(e){return{inline_keyboard:e.map(e=>e.map(e=>({text:e.text,...e.url?{url:e.url}:{callback_data:e.callbackData||""}})))}}function nc(e,t=40){return tc(e.slice(0,t).map(e=>[e]))}function ic(e){return Buffer.from(e,"utf8").toString("base64url")}function sc(e){const t=oc(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=oc(t),n=String(e.callback_data||""),s=String(e.text||"").trim();s&&n&&i.push({text:s,id:`th_cb_${ic(n)}`})}return i.slice(0,40)}function rc(e,t){const n=String(e||"").replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-3))}...`}function oc(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function ac(e){return(e.aiSessions?.sessions||[]).filter(t=>function(e,t){const n=(e.apps?.sessions||[]).filter(hc);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[...yt(e).bindings.map(vt),...St(e)].filter(Boolean)}(e).some(e=>i.has(e))))}(e,t))}function dc(e){return"waiting"===e.status?4:"failed"===e.status?3:"running"===e.status?2:"idle"===e.status?1:0}function cc(e){return[e.cwd||"",e.agent||"",e.providerSessionId||e.id].join("\0")}function lc(e){const t=e.session.title||e.session.userPrompt||e.session.summary||e.session.lastMessage||"",n=t?` - ${rc(t,18)}`:"";return`${e.instance.name} - ${e.session.agent} ${e.session.status}${n}`}function pc(e,t=(e,t)=>`task_handoff:approval:${e.id}:${t}`){return nc(e.flatMap(e=>"approval"!==e.kind?[]:[{text:rc(`Allow ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"allow")},{text:rc(`Skip ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"skip")},{text:rc(`Deny ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"deny")}]))}function uc(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 hc(e){const t=e&&"object"==typeof e&&!Array.isArray(e)?e:{};return It("string"==typeof t.status?t.status:void 0)}class gc{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?nc(t.map(e=>({text:`${e.active?"✓ ":""}${lc(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:Na(t),aiSession:n,reply:`Interrupt sent to ${t.name} / ${e.activeAiSessionId}.`}}}function mc(e){return e.providerTurnId||e.turnId||""}function yc(e){return It(vc(e.status))}function fc(e,t){const n=vc(t.appId)||"App",i=vc(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 Ic(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=wc(e);t&&!n.has(t.id)&&n.set(t.id,t)}return[...n.values()]}function bc(e,t,n,i){const s=vc(t.id)&&function(e,t){const n=bt(e);if(!n)return;return`/apps/access/${n}?token=${encodeURIComponent(t(n))}`}(t,i)||`/instances/${encodeURIComponent(e.id)}/`,r=function(e,t){const n=vc(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 vc(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function wc(e){if("string"==typeof e&&e.trim())return{id:e,label:Sc(e)};const t=function(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}(e),n=vc(t.id).trim();return n?{id:n,label:vc(t.name).trim()||Sc(n)}:void 0}function Sc(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 Ac{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?nc(t.map(e=>{return{text:rc(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=Ic(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?nc(i.map(e=>{return{text:rc(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=Ic(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(yc).filter(e=>Boolean(vc(e.id))).map(e=>({instance:t,session:e,link:bc(t,e,this.deps.controlPlanePublicBaseUrl(),n=>this.deps.createAppAccessToken({instanceId:t.id,sessionId:vc(e.id)||"",mode:n}).token)})):[]}),s=i.filter(e=>e.link.url).map(e=>({text:rc(`${e.instance.name} · ${fc(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?nc(s):void 0};var r,o}}class kc{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:Na(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}: ${ja(t)}`}}}failedSendResult(e,t,n,i){return{accepted:!1,routed:!1,binding:e,project:t||void 0,instance:Na(n),reply:i}}sentResult(e,t,n,i,s){return{accepted:!0,routed:!0,binding:e,project:t||void 0,instance:Na(n),aiSession:s,instanceId:n.id,aiSessionId:i,turnId:(r=s,r.turnId||r.providerTurnId||r.session.activeTurnId||""),providerTurnId:mc(s),reply:`Sent to ${t?.name||n.sourceSnapshot.name||"Source"} / ${n.name} / ${i}.`};var r}}class zc{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(uc).join("\n"):"No pending routes.",replyMarkup:n.length?pc(n,(e,t)=>this.deps.pendingDecisionCallbackData(e.id,t)):void 0}}async handlePendingDecisionCommand(e,t,n){const i=Ra(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=Ra(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 Cc{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 Tc{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?ac({...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=>ac(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=dc(t.session)-dc(e.session);return n||(String(e.instance.name||"").localeCompare(String(t.instance.name||""))||e.instance.id.localeCompare(t.instance.id)||cc(e.session).localeCompare(cc(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||Da("PROJECT_NOT_FOUND",`Project ${e} was not found.`),t}async resolveInstance(e,t){const n=await this.findInstance(e,t);return n||Da("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 Ec{deps;targets;sender;appCommands;pendingCommands;aiSessionCommands;targetCommands;constructor(e){this.deps=e,this.targets=new Tc(e),this.sender=new kc(e,this.targets),this.appCommands=new Ac(e,this.targets),this.pendingCommands=new zc(e),this.aiSessionCommands=new gc(e,this.targets),this.targetCommands=new Cc(e,this.targets)}async handleChatGatewayMessage(e){const t=vr.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 xc=a.z.object({id:a.z.string().trim().min(1),preferences:ko,createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict();function Nc(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 _c(){return ko.parse({})}function Oc(e){return/^[a-z]:[\\/]/i.test(e)||/^[\\/]{2}[^\\/]+[\\/]+[^\\/]+/.test(e)}function Pc(e){return Oc(e)?t.win32:t.posix}class Rc{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??Ar,s=[];for(const r of n.readdirSync(e.trashRoot,{withFileTypes:!0})){const o=kr(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??Ar,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=kr(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}`);zr(e.trashRoot);const s=e.nowMs??Date.now();let r=0,o=`${s}-${e.entryName}`;for(;n.existsSync(kr(e.trashRoot,o));)r+=1,o=`${s}-${r}-${e.entryName}`;const a=kr(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)})}}zr(e)}now(){return this.options.now?.()??Date.now()}}const jc="task-handoff.control-plane.local",Dc="task-handoff.control-plane.builtin";function Mc(e){return"true"===e.labels[jc]}function Lc(e){return"true"===e.labels[Dc]}class qc{projects;models;modelService;images;nodes;pendingPairingRevokes;chatSessions;chatBridges;triggers;nodeJoinService;configSyncPreferences;settings;paths;fetchImpl;dockerCommandRunner;logger;diagnosticLogsState;nodeConnectionRuntime;appAccessService;persistenceMaintenance;chatActionTokenService=new Jd;nodeAgentTransportResolver;proxyPrivateStore;proxyLifecycle;nodeConnectionManager;nodeAgentGateway;controlledInstanceGateway;aiSessionActionService;controlledInstanceCreator;instanceBoardReader=new Nd;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 Rc(e,{logger:(e,t)=>this.logWarn(t,e)});const i=e=>({schema:e,logger:(e,t)=>this.logWarn(t,e)});this.proxyPrivateStore=new fa(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 oa({direct:ra(this.fetchImpl),tunnel:n.nodeAgentTransport,proxy:new ua({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 Gr(e.settingsPath,()=>Wa.parse({diagnosticLogs:s}),{...i(Wa),sanitize:e=>function(e,t={}){if(!e||"object"!=typeof e||Array.isArray(e))return{};const n={...e};return"string"==typeof n.mentionTrigger&&Ua(n.mentionTrigger)||(n.mentionTrigger="@"),"string"==typeof n.commandTrigger&&Ha(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 Do({request:(e,t,n)=>this.nodeAgentFetch(e,t,n),logger:this.logger});this.nodeAgentGateway=new Mo(o),this.controlledInstanceGateway=new Ed({requireNode:e=>this.requireNode(e),nodeAgentTransport:e=>this.nodeAgentTransportResolver.resolve(e)}),this.aiSessionActionService=new xo({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 Hr(e.projectsDir,{...i(ls),sanitize:zi}),this.models=new Hr(e.modelsDir,i(ps)),this.modelService=new Cd({models:this.models,gateway:this.nodeAgentGateway,listNodes:()=>this.listNodes(),requireNode:e=>this.requireNode(e)}),this.images=new Hr(e.imagesDir,{...i(Os),sanitize:e=>Fs(e,e=>this.logWarn(e,"legacy image profile field was migrated"))}),this.nodes=new Hr(e.nodesDir,{...i(Ws),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)?yr(n.auth,["mode","keyId","secret","pairedAt","pairing"]):n.auth;s&&"object"==typeof s&&"pairing"in s&&(s.pairing=yr(s.pairing,["status","joinToken","expiresAt"]));const r=n.connectionPath&&"object"==typeof n.connectionPath&&!Array.isArray(n.connectionPath)?"control-plane-proxy"===n.connectionPath.kind?yr(n.connectionPath,["kind","proxyId","proxyBindingId","targetNodeId"]):yr(n.connectionPath,["kind"]):{kind:"direct"},o=n.proxyState&&"object"==typeof n.proxyState&&!Array.isArray(n.proxyState)?yr(n.proxyState,["reachability","bindingStatus","bindingRevision","streamId","revision","observedAt","target","lastError","updatedAt"]):n.proxyState;if(o&&"object"==typeof o){const e=o;e.target=yr(e.target,["id","name","status","health","lastSeenAt","capabilities"]),e.lastError=yr(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 Hr(e.pendingPairingRevokesDir,i(hd)),this.proxyLifecycle=new qa({nodes:this.nodes,privateStore:this.proxyPrivateStore,fetchImpl:this.fetchImpl,requireNode:e=>this.requireNode(e),deleteNode:e=>this.deleteNode(e)}),this.nodeConnectionManager=new gd({nodes:this.nodes,pendingPairingRevokes:this.pendingPairingRevokes,fetchImpl:this.fetchImpl,localNodeLabel:jc,builtinNodeLabel:Dc,info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)}),this.chatSessions=new Hr(e.chatSessionsDir,i(br)),this.chatBridges=new Hr(e.chatBridgesDir,i(Ir)),this.triggers=new Hr(e.triggersDir,i(Xa)),this.nodeJoinService=new kd({nodes:this.nodes}),this.configSyncPreferences=new Hr(t.join(e.dataDir,"config-sync-preferences"),{...i(xc),sanitize:Nc}),this.marketCatalogService=new Bd,this.catalogService=new Md({projects:this.projects,images:this.images,market:this.marketCatalogService,settings:this.settings,defaultNodeId:()=>this.defaultNodeId()}),this.controlledInstanceCreator=new _d({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 Rd({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 Fd({requireInstance:async e=>this.requireControlledInstance(e,!0),listAppSessions:()=>this.listAppSessions()}),this.chatBridgeService=new Zd({chatBridges:this.chatBridges,chatSessions:this.chatSessions}),this.chatSessionService=new ec({chatSessions:this.chatSessions}),this.chatSessionRuntime=new Ec({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(Ai),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:ja(e)}),void this.logWarn({legacyId:t,error:ja(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=ls.parse(zi(t));r.push({filePath:e,raw:t,migrated:i})}catch(t){return this.writeMarketMigrationState("failed",{code:"PROJECT_REFERENCE_VALIDATION_FAILED",filePath:e,error:ja(t)}),void this.logWarn({filePath:e,error:ja(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:Jn,createdAt:Oa(),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:Ai[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:Oa(),...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(Mc)?.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 $d),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 rr.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=>rr.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=Ws.parse({...t,id:i,status:"online",health:"ok",capabilities:"object"==typeof e&&e?{...t.capabilities,agent:Ca(e)}:t.capabilities,lastSeenAt:Oa(),updatedAt:Oa()});return i!==t.id&&this.nodes.delete(t.id),this.nodes.put(s),this.nodeConnectionRuntime?.observedReachable(s),{id:s.id,status:"online",checkedAt:Oa(),agent:e}}catch(e){const n=Ws.parse({...t,status:"offline",health:"failed",updatedAt:Oa()});return this.nodes.put(n),this.nodeConnectionRuntime?.observedFailure(n,ja(e)),{id:t.id,status:"offline",checkedAt:Oa(),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(!Lc(t)||!Mc(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=pd.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=>Ta(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=ld.parse(t),i=this.requireNode(e);this.proxyLifecycle.assertIdentityPatch(i,n);const s=Ws.parse({...i,...n,id:e,createdAt:i.createdAt,updatedAt:Oa()});return this.nodes.put(s)}deleteNode(e){if(Lc(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(Na)}async listControlledInstancesWithDiagnostics(){const e=await this.listNodeInstancesWithDiagnostics();return{items:e.items.map(Na),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=od.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 Na(a)}async deleteControlledInstance(e,t){const n=vi.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),Na(await this.nodeAgentGateway.startInstance(n,e))}async stopControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return Na(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),Na(await this.nodeAgentGateway.restartInstance(n,e))}async retryControlledInstanceImageProvisioning(e){const t=await this.requireNodeInstance(e);return Na(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(!Sr(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 yo(Le,await this.instanceRequest(e,"/ai-sessions/state"))}catch(t){return this.logWarn({instanceId:e.id,error:ja(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(!Sr(e)||!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=Ct();return{streamId:`bootstrap:${e.id}:app.sessions`,revision:0,lastEventAt:t.updatedAt,snapshot:t}}try{return yo(at,await this.instanceRequest(e,"/apps/sessions/state"))}catch(t){this.logWarn({instanceId:e.id,error:ja(t),errorCode:"APP_SESSION_LIVE_REFRESH_FAILED"},"control plane failed to refresh live app sessions");const n=Ct();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 yo(Ve,await this.instanceRequest(i,`/ai-sessions?${s}`))}async recoverAiSessionSnapshot(e){const t=await this.requireControlledInstance(e,!0);return yo(Le,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 yo(ht,await this.instanceRequest(i,`/apps/sessions?${s}`))}async recoverAppSessionSnapshot(e){const t=await this.requireControlledInstance(e,!0);return yo(at,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=Oa(),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=wr.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:Na(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||xa(n.source).path||"/workspace"};return this.aiSessionActionService.create(e,{...s,cwd:r})}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 yo(Fi,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 yo(Gi,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 yo(Gi,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(So).parse(await this.instanceRequest(t,"/config-sync/programs"));return zo.parse({programs:n,preferences:this.configSyncPreferences.get(e)?.preferences||_c()})}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(or).parse(await this.instanceRequest(n,"/config-sync/folders"+(i.size?`?${i}`:"")))}async syncInstanceConfigs(e,t){const n=Ao.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=yo(Eo,await this.instanceRequest(i,"/config-sync",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(r)})),a=Oa(),d=this.configSyncPreferences.get(e);return this.configSyncPreferences.put({id:e,preferences:{...d?.preferences||_c(),[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,ja(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{}Da("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||Da("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 Pc(s=n).resolve(s);var s;if("local-folder"!==e.source.type)return;const r=function(e,t){if(Oc(e)!==Oc(t))return;const n=Pc(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||xa(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||Da("NODE_NOT_FOUND",`Node ${e} was not found.`),t}requirePublicNode(e){return Ta(this.projectNodeConnection(this.requireNode(e)))}async requireControlledInstance(e,t=!1){const n=await this.requireNodeInstance(e);return t?n:Na(n)}}function $c(e){return g(String(e),"escape").replace(/\n+$/,"")}function Bc(e){const[t,...n]=String(e).split("\n");return[`*${$c(t)}*`,...n.map($c)].join("\n")}function Uc(e,t=4e3){const n=String(e),i=Bc(n);if(i.length<=t)return i;const[s,...r]=n.split("\n"),o=r.join("\n"),a="...\n";let d=s;for(;Bc(`${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=Bc(`${d}\n${a}`);for(;c<=l;){const e=Math.floor((c+l)/2),n=Bc(`${d}\n${a}${o.slice(-e)}`);n.length<=t?(u=n,p=e,c=e+1):l=e-1}const h=o.slice(-p),g=h.indexOf("\n");return g>=0&&g<200&&(u=Bc(`${d}\n${a}${h.slice(g+1)}`)),u}function Fc(e){return String(e).replace(/\\([_*\[\]()~`>#+\-=|{}.!\\])/g,"$1")}async function Hc(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:$c;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 Wc(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 Gc(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 Wc(e,t,n,i,s){const r=s.parseMode||"MarkdownV2",o=s.rawMarkdownV2?String(n):$c(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&&Vc(d.description))return;if(s.rawMarkdownV2&&"MarkdownV2"===r){const s=await e({...i,text:Fc(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&&Vc(r.description))return}const c=await e({...i,text:s.rawMarkdownV2?Fc(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||!Vc(l.description))throw new Error(l.description||d.description||`Telegram ${t} failed with HTTP ${c.status}`)}function Vc(e){return"string"==typeof e&&e.toLowerCase().includes("message is not modified")}function Kc(e,t){if("string"==typeof e&&e.trim())return e.trim();Yc(`Chat action token is missing ${t}.`)}function Jc(e){if("allow"===e||"deny"===e||"skip"===e)return e;Yc("Chat action token has an invalid decision.")}function Yc(e){const t=new Error(e);throw Object.assign(t,{statusCode:400,code:"CHAT_ACTION_TOKEN_INVALID"}),t}function Qc(e){return Buffer.from(e,"base64url").toString("utf8")}function Xc(e){return String(e||"").split(/\r?\n/,1)[0].replace(/^#+\s*/,"").trim().slice(0,20)||"消息通知"}function Zc(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,"string"==typeof t?t:JSON.stringify(t)]))}function el(e){return`dtv1.card//IM_GROUP.${e}`}function tl(e){return`dtv1.card//IM_ROBOT.${e}`}function nl(e,t){return fl(t.biz_conversation_id).trim()||fl(e.spaceId).replace(/^dtv1\.card\/\/(?:IM_GROUP|IM_SINGLE|IM_ROBOT)\./,"")}function il(e,t={}){const n=fl(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 sl(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 rl(e,t,n,i,s){const r=nl(i,s);return{cardUpdateOptions:{updateCardDataByKey:!0,updatePrivateDataByKey:!1},cardData:{cardParamMap:Zc({type:"actions",title:"TaskHandoff",description:e,list:sc(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 ol(e,t,n){const i=[];return al(i,n),al(i,t),al(i,e),i.find(e=>sl(e))||""}function al(e,t){for(const n of["actionIdList","actionIds"]){const i=t[n];Array.isArray(i)&&e.push(...i.map(e=>fl(e)).filter(Boolean))}for(const n of["actionId","action_id","id","actionValue"]){const i=fl(t[n]);i&&e.push(i)}}async function dl(e,t,n,i){i?.("info",{target:"sessionWebhook",hasSessionWebhook:Boolean(t),textPreview:gl(n)},"dingding webhook send requested");const s=await e(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({msgtype:"markdown",markdown:{title:Xc(n),text:n}})}),r=await s.json().catch(()=>{});if(i?.(s.ok?"info":"warn",{target:"sessionWebhook",status:s.status,response:hl(r)},"dingding webhook send completed"),!s.ok)throw new Error(`DingDing webhook failed with HTTP ${s.status}`)}async function cl(e){const t=sc(e.replyMarkup);if(!t.length&&!e.forceCard)return e.sessionWebhook&&await dl(e.fetchImpl,e.sessionWebhook,e.text,e.runtime.onLog),e.sessionWebhook?{delivered:!0}:void 0;const n=e.bridge.settings||{},i=fl(n.robotCode),s=fl(n.cardTemplateId)||"13fc6717-12e4-43ed-8533-111a310d4995.schema",r=fl(n.cardCallbackRouteKey)||"task_handoff_message",o=e.senderId||e.runtime.senderIds.get(e.chatId)||fl(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 dl(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=Zc({type:"actions",title:e.title||Xc(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:tl(n),imRobotOpenSpaceModel:{supportForward:!1},imRobotOpenDeliverModel:{extension:{},robotCode:i,spaceType:"IM_ROBOT"}}:{openSpaceId:el(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:gl(e.text)},"dingding card send requested"),await ll(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 ll(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=fl(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:pl(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:hl(d)},"dingding api response"),!a.ok)throw new Error(`DingDing API failed with HTTP ${a.status}`);const c=ml(d),l=c.code??c.errcode,p=c.success;if(void 0!==l&&"0"!==String(l)||!1===p)throw new Error(fl(c.message||c.errmsg)||`DingDing API returned ${String(l||"failure")}`);const u=function(e){const t=ml(ml(e).result).deliverResults;if(!Array.isArray(t))return"";const n=t.find(e=>!1===ml(e).success);if(!n)return"";const i=ml(n),s=fl(i.spaceId),r=fl(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 pl(e){const t=ml(e),n=ml(t.cardData),i=ml(n.cardParamMap);return{openSpaceId:fl(t.openSpaceId),outTrackId:fl(t.outTrackId),userId:fl(t.userId),userIdType:t.userIdType,callbackType:fl(t.callbackType),callbackRouteKey:fl(t.callbackRouteKey),hasImGroupTarget:Boolean(t.imGroupOpenSpaceModel||t.imGroupOpenDeliverModel),hasImSingleTarget:Boolean(t.imSingleOpenSpaceModel||t.imSingleOpenDeliverModel),hasImRobotTarget:Boolean(t.imRobotOpenSpaceModel||t.imRobotOpenDeliverModel),imGroupOpenDeliverModel:ul(t.imGroupOpenDeliverModel),imSingleOpenDeliverModel:ul(t.imSingleOpenDeliverModel),imRobotOpenDeliverModel:ul(t.imRobotOpenDeliverModel),bizConversationId:fl(i.biz_conversation_id),bizConversationType:fl(i.biz_conversation_type),bizSenderId:fl(i.biz_sender_id),hasBizSessionWebhook:Boolean(fl(i.biz_session_webhook))}}function ul(e){const t=ml(e);if(Object.keys(t).length)return{hasExtension:Boolean(t.extension),hasRobotCode:Boolean(fl(t.robotCode)),spaceType:fl(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 hl(e){const t=ml(e),n=ml(t.result);return{code:t.code??t.errcode,message:gl(t.message||t.errmsg,240),success:t.success,requestId:t.requestId,result:Object.keys(n).length?n:void 0}}function gl(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 ml(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function yl(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:"string"==typeof e&&e.trim()?Il(e):{}}function fl(e){return"string"==typeof e?e:""}function Il(e){try{return ml(JSON.parse(String(e||"{}")))}catch{return{}}}function bl(e){return JSON.stringify(sc(e))}const vl="task_handoff_action_id";function wl(e,t){const n=sc(t);return{schema:"2.0",config:{summary:{content:kl(e)}},body:{elements:[{tag:"markdown",content:e},...n.map(e=>({tag:"button",text:{tag:"plain_text",content:e.text},type:zl(e.text),width:"fill",size:"medium",behaviors:[{type:"callback",value:{[vl]:e.id}}]}))]}}}function Sl(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[vl]||t.action_id||t.actionId||t.id||e)}function Al(e){return JSON.stringify(sc(e))}function kl(e){const t=e.replace(/\s+/g," ").trim();return t.length<=50?t:`${t.slice(0,47)}...`}function zl(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 Cl(e){return e instanceof Error?e.message:String(e)}function Tl(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 El(e){return Array.isArray(e?.actionRows)?e.actionRows:(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e])}function xl(e,t){const n=El(e),i=El(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 Nl{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||Tl,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&&xl(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: ${Cl(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&&xl(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&&xl(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: ${Cl(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: ${Cl(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 _l=20971520;function Ol(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 Pl(e,n,i="telegram-image",s){if(s&&s>_l)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>_l)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",h=t.join(p,`telegram-${Date.now()}-${Math.random().toString(16).slice(2)}${u}`),g=Buffer.from(await a.arrayBuffer());if(g.length>_l)throw new Error(`image is too large: ${g.length} bytes`);return await m.writeFile(h,g),h}class Rl{store;constructor(e){this.store=new Nl({updateIntervalMs:e.updateIntervalMs,send:(t,n,i)=>e.send(e.requireBridge(n?.bridgeId||""),n?.chatId||"",Uc(t),{rawMarkdownV2:!0,replyMarkup:$l(i)}),edit:(t,n,i,s)=>e.edit(e.requireBridge(i?.bridgeId||""),i?.chatId||"",t,Uc(n),{rawMarkdownV2:!0,replyMarkup:$l(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 jl(e){return(await async function(e,t,n,i){const s=[];for(const r of Ol(n))try{const n=await Pl({getFileLink:n=>Gc(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:Dl(e),size:r.length,source:{type:"inline",encoding:"base64",data:r.toString("base64")}}})}function Dl(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 Ml(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function Ll(e){return e&&"object"==typeof e?e:{}}function ql(e){return"string"==typeof e?e:""}function $l(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return tc(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function Bl(e){const t=Array.isArray(e.item_list)?e.item_list:[];for(const e of t){const t=Ul(e);if(1!==t.type)continue;const n=Fl(Ul(t.text_item).text).trim();if(n)return n}return""}function Ul(e){return e&&"object"==typeof e?e:{}}function Fl(e){return"string"==typeof e?e:""}function Hl(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 Hc(e,t,n,i,{replyMarkup:s.replyMarkup,replyToMessageId:s.replyToMessageId,rawMarkdownV2:s.rawMarkdownV2,parseMode:s.parseMode});return{provider:"telegram",raw:r,messageId:Number(Ll(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)||fl(t.settings.sessionWebhook);if(r.replyMarkup&&n){const a=await cl({fetchImpl:e,bridge:t,runtime:n,chatId:i,text:s,replyMarkup:r.replyMarkup,sessionWebhook:o,senderId:r.senderId||n.senderIds.get(i)||fl(t.settings.senderId)});if(a?.delivered)return{provider:"dingding",interactionId:a.outTrackId}}if(o)return await dl(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:wl(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||Fl(t.settings.contextToken);if(o)return await async function(e,t,n,s,r){const o=Fl(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(Fl(d.errmsg)||`WeChat send failed with HTTP ${a.status}`)}(e,t,n,o,s),{provider:"wechat"}}}}(t,n):{bridge:n,send:async()=>{}}}class Gl{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=bl(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,bl(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=cl({fetchImpl:this.fetchImpl,bridge:e.bridge,runtime:t,chatId:e.chatId,text:e.text,replyMarkup:e.replyMarkup,sessionWebhook:t.chatWebhooks.get(e.chatId)||Wl(e.bridge.settings.sessionWebhook),senderId:t.senderIds.get(e.chatId)||Wl(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 ll(e.fetchImpl,e.bridge,e.runtime,"PUT","/v1.0/card/instances",{outTrackId:e.outTrackId,cardData:{cardParamMap:Zc({type:"actions",title:e.title,description:e.text,list:sc(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 Wl(e){return"string"==typeof e?e:""}function Vl(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 Kl{runtimes=new Map;connected=new Set;reconnectTimers=new Map;progress;options;createClient;constructor(e){this.options=e,this.createClient=e.createClient||Vl,this.progress=new Gl(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 Jl{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=Al(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,Al(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:wl(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,wl(i,s)),this.isCurrent(e.bridge.id,o)&&(n.lastText=i,n.lastActionsFingerprint=r,n.lastUpdateAt=Date.now()))}}function Yl(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 Ql{runtimes=new Map;connected=new Set;unsubscribe=new Map;reconnectTimers=new Map;options;createChannel;progress;constructor(e){this.options=e,this.createChannel=e.createChannel||Yl,this.progress=new Jl(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:Xl(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 Xl(e){return"lark"===String(e||"").trim().toLowerCase()?I.Domain.Lark:I.Domain.Feishu}class Zl{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 ep{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=tp(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!==tp(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:tc([[{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 tp(e,t,n){return[e,t,n||""].join(":")}class np{cancelTokens=new Map;queueActionTokens=new Map;options;constructor(e){this.options=e}cancelCallbackData(e,t){this.pruneExpired();const n=sp([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=ip(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=ip(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=ip(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=ip(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=op(await this.options.queue(t.instanceId,t.sessionId)),i=(Array.isArray(n.items)?n.items:[]).map(op).filter(e=>"queued"===ap(e.status)&&ap(e.id));if(!i.length)return void await this.answer(e,"Queue is empty");const s=i.slice(0,5).map((e,n)=>[{text:rp(ap(e.message),n),callbackData:this.queueDeleteItemCallbackData(t.instanceId,t.sessionId,ap(e.id))}]);await this.send(e,"Delete queued message",{replyMarkup:tc(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:dp(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=dp(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=sp([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 ip(e,t){if(!e.startsWith(t))return;const n=e.slice(t.length);return n&&!n.includes(":")?n:void 0}function sp(e){return i.createHash("sha256").update(e.join("\0")).digest("base64url").slice(0,16)}function rp(e,t){const n=`${t+1}. `,i=ap(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 op(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function ap(e){return"string"==typeof e?e.trim():""}function dp(e){return e instanceof Error?e.message:String(e)}class cp{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=lp(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,pp(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,pp(t)),!1))}}function lp(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:tc([[{text:"Allow",callbackData:t(e.id,"allow")},{text:"Skip",callbackData:t(e.id,"skip")},{text:"Deny",callbackData:t(e.id,"deny")}]])}}function pp(e){return e instanceof Error?e.message:String(e)}function up(){return e=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(e||"").trim().toLowerCase());var e}class hp{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||up,this.aiSessionInstanceNamesCache=new Zl(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 Zl(1e3,()=>this.service.listPendingRoutes().catch(()=>[])),this.telegramMessageAggregator=new ep({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,Sp(t))}),this.telegramAiSessionCallbacks=new np({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 cp({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 Rl({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 Kl({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,Sp(t)),clearError:e=>this.bridgeErrors.delete(e)}),this.larkBridges=new Ql({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,Sp(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:Sp(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:kp(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: ${Sp(e)}`})}const o=gp(r);if(!o)return;const a=yp(r);if(await this.sendLarkRoutedAiSessionProgress(r,e,n.chatId,o,a))return;const d=Hl({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===Tp(r).routed,replyPreview:kp(o)},"lark chat gateway reply sent")}async sendLarkRoutedAiSessionProgress(e,t,n,i,s){if(!0!==e.routed)return!1;const r=Np(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=Dp(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:kp(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=Sl(n.action.value),r=(e,i)=>t.channel.updateCard(n.messageId,wl(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:wl(e,i?.replyMarkup)})}))return;let o;try{o=await this.parseChatGatewayCallbackAction(s)}catch(e){if(Ap(e,"CHAT_PENDING_ACTION_STALE"))return void await r(Sp(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&&mp(a))return void await r(`${o.decision} sent`);const d=gp(a)||wp(a.message)||"Updated";await r(d,yp(a))}async handleDingdingRobotMessage(e,t,n){const i=function(e){const t=Il(e),n=fl(t.conversationId),i=fl(ml(t.text).content).trim();if(!n||!i)return;const s=fl(t.senderStaffId||t.senderId);return{chatId:n,userId:s||void 0,senderId:s||void 0,sessionWebhook:fl(t.sessionWebhook)||void 0,conversationType:il(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)||wp(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:kp(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 dl(this.fetchImpl,d,`Failed to handle message: ${Sp(e)}`,t.onLog);throw e}const l=gp(c);if(l){const n=yp(c);if(await this.sendDingdingRoutedAiSessionProgress(c,e,t,s,l,{replyMarkup:n,sessionWebhook:d,senderId:o,sourcePrompt:r}))return;const i=Hl({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===Tp(c).routed,hasReplyMarkup:Boolean(n),replyPreview:kp(l)},"dingding chat gateway reply sent");this.logWarn({bridgeId:e.id,chatId:s,senderId:o,hasReplyMarkup:Boolean(n),hasSessionWebhook:Boolean(d),hasRobotCode:Boolean(wp(e.settings.robotCode)),replyPreview:kp(l)},"dingding chat gateway reply skipped")}}async sendDingdingRoutedAiSessionProgress(e,t,n,i,s,r={}){if(!0!==e.routed)return!1;const o=Np(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=Dp(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:kp(r.sourcePrompt,80),textPreview:kp(s)},"dingding ai session progress card started"),!0)}async handleDingdingCardCallback(e,t,n){const i=function(e){const t=Il(e),n=yl(t.cardActionData||t.content),i=yl(n.cardPrivateData||t.cardPrivateData||t.content),s=yl(i.params||n.params||t.params),r=fl(t.userId),o=fl(s.biz_sender_id);return{userId:r||void 0,chatId:nl(t,s),senderId:r||void 0,deliverySenderId:o||void 0,sessionWebhook:fl(s.biz_session_webhook)||void 0,conversationType:il(s.biz_conversation_type||t.conversationType||t.conversation_type),callbackData:sl(ol(t,n,i)),body:t,params:s}}(n.data);if(!this.dingdingAllowed(e,i.userId))return rl("not authorized",void 0,"unauthorized",i.body,i.params);const s=i.chatId||wp(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(Ap(e,"CHAT_PENDING_ACTION_STALE"))return rl(Sp(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,...zp(i)},"dingding card callback action unsupported"),rl("Unsupported action",void 0,"unsupported",i.body,i.params);this.logInfo({bridgeId:e.id,chatId:s,userId:i.userId,senderId:r,actionType:a.type,...zp(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&&mp(d)?rl(`${a.decision} sent`,void 0,"approval_done",i.body,i.params):rl(gp(d)||wp(d.message)||"updated",yp(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)||wp(n.updatesBuf),s=await async function(e){const t=Fl((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(Fl(i.errmsg||i.msg)||`chat bridge API returned ${s}`);const r=[];for(const e of Array.isArray(i.msgs)?i.msgs:[]){const t=Ul(e);if(1!==t.message_type)continue;const n=Fl(t.from_user_id),i=Bl(t);n&&i&&r.push({chatId:n,text:i,contextToken:Fl(t.context_token)})}return{cursor:Fl(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=gp(a);if(d){const t=Hl({fetchImpl:this.fetchImpl,bridge:e});await t.send(s,d,{contextToken:r||wp(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 Hl({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=Ll(t.callback_query);if(Object.keys(r).length>0){s.push({updateId:i,callbackQuery:r});continue}const o=Ll(t.message||t.edited_message);if(0===Object.keys(o).length)continue;const a=Ll(o.chat),d=Ll(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=ql(o.text??o.caption),u=Ol(o);(p||0!==u.length)&&s.push({updateId:i,chatId:c,userId:l,text:p,rawText:p,message:o,messageId:Ml(o),replyToMessageId:Ml(Ll(o.reply_to_message)),quoteText:ql(Ll(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=Tp(t.message),s=Tp(i.chat),r=void 0!==s.id?String(s.id):e.defaultChatId;this.bridgeErrors.set(e.id,Sp(n)),r&&await this.sendTelegramMessage(e,r,`Action failed: ${Sp(n)}`).catch(t=>{this.bridgeErrors.set(e.id,Sp(t))})});continue}if(!this.telegramAllowed(e,n.userId))continue;const i=await jl({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:Sp(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:kp(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=gp(d),l=yp(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(Tp(n).message_id)||void 0,routed:!0===Tp(d).routed,replyPreview:kp(c)},"telegram chat gateway reply sent"),await this.rememberTelegramProgressMessage(d,e,t,n,c)}}catch(n){this.bridgeErrors.set(e.id,Sp(n)),await this.sendTelegramMessage(e,t,`Failed to handle message: ${Sp(n)}`,{replyToMessageId:r.sourceMessageId}).catch(t=>{this.bridgeErrors.set(e.id,Sp(t))})}}async handleTelegramCallback(e,t){const n=wp(t.data),i=Tp(t.from),s=Tp(t.message),r=Tp(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:wp(t.id),userId:a,messageId:Ip(s)}))return;const d=n.match(/^task_handoff:cp_msg_end:([^:]+)$/);if(d)return void await this.telegramMessageAggregator.handleEndCallback(e,o,wp(t.id),d[1],a);let c;try{c=await this.parseChatGatewayCallbackAction(n)}catch(n){if(Ap(n,"CHAT_PENDING_ACTION_STALE")){await this.answerTelegramCallback(e,wp(t.id),Sp(n));const i=Ip(s);return void(void 0!==i&&await this.deleteTelegramStandaloneApprovalMessage(e,o,i))}throw n}if(!c)return void await this.answerTelegramCallback(e,wp(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&&mp(l)){await this.answerTelegramCallback(e,wp(t.id),"");const n=Ip(s);return void(void 0!==n&&await this.deleteTelegramStandaloneApprovalMessage(e,o,n))}await this.answerTelegramCallback(e,wp(t.id),wp(l.message)||"updated");const p=gp(l),u=yp(l),h=s.message_id;p&&"number"==typeof h?await this.editTelegramMessage(e,o,h,p,{replyMarkup:u}):p&&await this.sendTelegramMessage(e,o,p,{replyMarkup:u})}async deleteTelegramStandaloneApprovalMessage(e,t,n){[...this.telegramProgress.entries.values()].find(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:Sp(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(Vd).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&&Kd(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:Kc(t(i[1],"instance-app-menu").instanceId,"instanceId")}:{type:"instance-app-menu",instanceId:Qc(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:Kc(e.instanceId,"instanceId"),appId:Kc(e.appId,"appId")}}return{type:"launch-app",instanceId:Qc(s[1]),appId:Qc(s[2])}}const r=e.match(/^task_handoff:cp_p:([^:]+)$/);if(r){const e=t(r[1],"pending-decision");return{type:"pending-decision",routeId:Kc(e.routeId,"routeId"),decision:Jc(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 Wc(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 Hc(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=Np(e),{instanceId:o,sessionId:a,turnId:d}=r,c=Number(Tp(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=Dp(o,a,d,t.id,n),p=this.telegramProgress.remember(l,c,s,{bridgeId:t.id,chatId:n});this.telegramProgressMessageTargets.set(bp(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:kp(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(bp(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:Sp(e)},"telegram queued progress message replacement cleanup failed")}))}telegramReplyAiSessionTarget(e,t,n){const i=this.telegramProgressMessageTargets.get(bp(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=vp(i,e,t);if(s){const i={...s,messageId:n};return this.telegramProgressMessageTargets.set(bp(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(bp(i.route.bridgeId,i.route.chatId,i.messageId||0))||vp(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(bp(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=Bp(n.get(e)||e,r),a=$p(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:Cp(Fp(r))});continue}const d=Mp(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:Cp(Fp(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=Dp(e,r.id,d,s.bridgeId||"",s.chatSessionId),l=Lp(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:Cp(Fp(r)),textPreview:kp(a)});continue}const p=Pp({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)||Rp(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:Cp(Fp(r)),textPreview:kp(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:Sp(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:kp(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:kp(t?.lastText),progressHasPending:Boolean(t?.pending),latestTurn:Cp(Fp(r)),textPreview:kp(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:kp(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=Bp(n.get(e)||e,o),c=$p(o,d),l=Mp(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:Dp(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=Lp(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 h=Pp({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)||Rp(e,o),session:o}),g=await this.updateChatAiSessionProgress(a,c,p,h).catch(e=>(this.bridgeErrors.set(a.bridgeId||"",e instanceof Error?e.message:String(e)),!1));this.logAiSessionDelivery({stage:g?"remembered-delivered":"remembered-not-delivered",key:p,instanceId:e,sessionId:o.id,bridgeId:s.route.bridgeId,chatId:s.route.chatId,textPreview:kp(c)}),g&&(this.telegramProgressMessageTargets.set(bp(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(bp(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(bp(i.route.bridgeId,i.route.chatId,i.messageId))||vp(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||Fp(t)?.id===e.owner.turnId||Fp(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:fp({actionRows:i})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:kp(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:fp({actionRows:i})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:kp(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:kp(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:kp(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 gp(e){return"object"==typeof e&&e&&"reply"in e?String(e.reply||""):""}function mp(e){return"object"==typeof e&&null!==e&&!0===e.accepted}function yp(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 fp(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return tc(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function Ip(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function bp(e,t,n){return[e,t,String(n)].join(":")}function vp(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 wp(e){return"string"==typeof e?e:""}function Sp(e){return e instanceof Error?e.message:String(e)}function Ap(e,t){return Boolean(e&&"object"==typeof e&&"code"in e&&e.code===t)}function kp(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 zp(e){const t=Ep(e.body.cardActionData||e.body.content),n=Ep(t.cardPrivateData||e.body.cardPrivateData||e.body.content);return{outTrackId:wp(e.body.outTrackId),spaceId:wp(e.body.spaceId),conversationType:e.conversationType,hasCallbackData:Boolean(e.callbackData),callbackDataPreview:kp(e.callbackData,120),actionIds:[...xp(n.actionIdList),...xp(t.actionIdList),wp(n.actionId),wp(t.actionId),wp(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 Cp(e){if(e)return{id:e.id,providerTurnId:e.providerTurnId,source:e.source,status:e.status,phase:e.phase,revision:e.revision,userPrompt:kp(e.userPrompt,80),hasResponse:Boolean(e.lastMessage?.trim()||e.summary?.trim()),responsePreview:kp(e.lastMessage||e.summary,80),updatedAt:e.updatedAt,observedAt:e.observedAt}}function Tp(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Ep(e){if(e&&"object"==typeof e&&!Array.isArray(e))return e;if("string"==typeof e&&e.trim())try{return Tp(JSON.parse(e))}catch{return{}}return{}}function xp(e){return Array.isArray(e)?e.map(e=>wp(e)).filter(Boolean):[]}function Np(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?Mp(n):""),sources:{resultTurnId:e.turnId,resultProviderTurnId:e.providerTurnId,actionTurnId:t?.turnId,actionProviderTurnId:t?.providerTurnId,sessionActiveTurnId:n?.activeTurnId,latestTurnId:n?Fp(n)?.id:void 0}}}const _p=5,Op=48;function Pp(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,_p);return[...d.map((e,t)=>[{text:jp(e.message,t),callbackData:n(e.id)}]),d.length?[{text:"Delete Queue",callbackData:i()},{text:"Cancel",callbackData:t}]:[{text:"Cancel",callbackData:t}]]}function Rp(e,t){if("approval"===t.phase)return{id:`${e}:ai:${t.id}`,kind:"approval"}}function jp(e,t){const n=`${t+1}. `,i=e.replace(/\s+/g," ").trim()||"Queued message",s=Math.max(8,Op-n.length),r=Array.from(i);return`${n}${r.length>s?`${r.slice(0,Math.max(1,s-3)).join("")}...`:i}`}function Dp(e,t,...n){return[e,t,...n].join(":")}function Mp(e){const t=Fp(e);return t?.id?t.id:wp(e.activeTurnId)}function Lp(e,t=""){const n=Fp(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),qp(e)].join("\0")}function qp(e){return(e.queue?.items||[]).map(e=>[e.id,e.status,e.message].join(":")).join("|")}function $p(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&&!Up(n,e)?i:""].filter(Boolean).join("\n\n")}(e,Fp(e));return n?`${t}\n${n}`:""}function Bp(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 Up(e,t){if("waiting"!==t.status||"approval"!==t.phase)return!1;const n=t.currentTool?.inputPreview?.trim();return Boolean(n&&e.includes(n))}function Fp(e){return(e.turns||[]).filter(e=>e.id||e.userPrompt?.trim()||e.lastMessage?.trim()||e.summary?.trim()).at(-1)}class Hp{clients=new Set;listeners=new Set;seq=0;connect(e){e.topics=new Set(["*"]),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||"{}"));return t&&"object"==typeof t?t:void 0}catch{return}}(t);"subscribe"===n?.type&&(e.topics=new Set(n.topics?.length?n.topics:["*"]))})}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&&Gp(t.topics,s,e))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||Cr(e),createdAt:(new Date).toISOString(),payload:t,scope:n.scope}}}function Gp(e,t,n){return!e||e.has("*")||e.has(t)||e.has(n)}const Wp={"image/bmp":".bmp","image/gif":".gif","image/jpeg":".jpg","image/png":".png","image/webp":".webp"},Vp=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 Kp(){return t.join(y.tmpdir(),"task-handoff-ai-session-attachments")}class Jp{items=new Map;ttlMs;constructor(e=864e5){this.ttlMs=e,this.pruneOrphanFiles()}upload(e){this.pruneExpired();const s=Vp.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=Wp[o]||"";if("image"===s.kind&&!a)throw new Error(`Unsupported image type: ${o}`);const d="image"===s.kind?r.buffer.length>T:r.buffer.length>=E;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=Kp();n.mkdirSync(u,{recursive:!0});const h=function(e){return t.basename(e).replace(/[^\w.\- ()\u4e00-\u9fff]/g,"_").slice(0,160)||"attachment"}(s.name),g=t.join(u,`${c}-${h.endsWith(a)?h:`${h}${a}`}`);n.writeFileSync(g,r.buffer);const m={id:c,instanceId:s.instanceId,sessionId:s.sessionId,kind:s.kind,name:h,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,m),this.publicAttachment(m)}resolveRefs(e,t,n){this.pruneExpired();const i=a.z.array(Y).max(6).default([]).parse(e),s=i.map(e=>"runtime-path"===e.source.type?K.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 K.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=Kp();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 Yp={controlPlaneAuthBoundary:"public"},Qp={controlPlaneAuthBoundary:"public-ui"},Xp={controlPlaneAuthBoundary:"proxy-binding"},Zp={controlPlaneAuthBoundary:"node-tunnel"};class eu{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 tu(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function nu(e){return e.unref?.(),e}class iu{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=tu(e.connectTimeoutMs,1e4),this.handshakeTimeoutMs=tu(e.handshakeTimeoutMs,1e4),this.heartbeatIntervalMs=tu(e.heartbeatIntervalMs,25e3),this.heartbeatTimeoutMs=tu(e.heartbeatTimeoutMs,1e4),this.stableThresholdMs=tu(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=nu(this.setTimeoutFn(()=>this.timeout("connect"),this.connectTimeoutMs))}opened(){this.stopped||(this.clearTimer("connectTimer"),this.setPhase("handshaking"),this.handshakeTimer=nu(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=nu(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=nu(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 su{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 ru={[N]:Fe,[_]:He,[O]:Ge,[P]:We,[Xe]:lt,[Ze]:pt,[et]:ut},ou=new Set(Object.keys(ru));class au{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=mo(xr,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=du(t.event),s="string"==typeof i?.type?i.type:"";if(!s)return!0;const r="payload"in i?i.payload:{},o=du(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=mo(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(s===ur){const t=mo(hr,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===Ms||s===Ls){const t=mo(s===Ms?$s:Bs,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(ou.has(s)){const t=function(e,t){const n=ru[e];if(!n)return;const i=mo(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]=lu(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=cu(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=cu(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 du(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:void 0}function cu(e,t){return JSON.stringify([e,t])}function lu(e){const t=JSON.parse(e);return Array.isArray(t)&&2===t.length?[String(t[0]),String(t[1])]:["",""]}const pu=a.z.object({nodeId:a.z.string().trim().min(1).max(120)}).strict();function uu(){return`req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}const hu=new Map;function gu(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)>Go)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()-Go;for(const[e,t]of hu)t<=r&&hu.delete(e);const o=`${e.id}:${n.keyId}:${n.nonce}`;if(!n.nonce||hu.has(o))throw Object.assign(new Error("Reverse tunnel nonce is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_NONCE_INVALID"});const a=Ko("");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||`${Wo}?nodeId=${encodeURIComponent(e.id)}`,c=Jo(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"});hu.set(o,Date.now()+Go)}function mu(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 yu{sockets=new Map;eventRouter;httpStreamHeaderTimeoutMs;requestTimeoutMs;auxiliaryAttachTimeoutMs;connectionRuntime;connectionOptions;constructor(e,t={}){this.eventRouter=new au({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 iu({...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=uu(),r=ni(n.body),o={type:"control-plane.request",requestId:s,route:t,init:{method:n.method||"GET",headers:mu(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=uu(),r=ni(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:mu(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 h.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(h.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=uu(),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=$o(e),s=qo(t);n.upstream&&Bo(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 Fo(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),Bo(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 fu{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=Yo(t),i=n?void 0:new URL(t),s=Vo(e,{method:"GET",pathWithQuery:i?`${i.pathname}${i.search}`:"/api/node-agent/events"}),r=n?Xo(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 eu;this.retries.set(e.id,{timer:a,url:t});const d=new iu({...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 eu};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(Yo(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 Iu(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 bu 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 vu(e){return t.join(e,"owner.json")}function wu(e){return t.join(e,"initializing.json")}function Su(e){return t.join(e,"recovering.json")}function Au(e){return Number.isInteger(e)&&Number(e)>0}function ku(e,t=process.platform){if(Au(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 zu=function(e){try{const t=JSON.parse(n.readFileSync(vu(e),"utf8"));if(Au(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(!(Au(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 Cu(e){if(!Au(e))return!1;try{return process.kill(Number(e),0),!0}catch(e){return"EPERM"===e.code}}function Tu(e){if(!e||!Cu(e.pid))return!1;if(!e.startIdentity)return!0;const t=ku(e.pid);return void 0===t||t===e.startIdentity}function Eu(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=Nu(e);if(r?.token!==i.token)throw Ou(s),new Error(`Process lock initialization was superseded: ${e}`);n.renameSync(s,vu(e)),Ou(wu(e))}function xu(e,s,r){const o=zu(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"}),zu(e)?.token!==s.token)return!1;n.renameSync(d,vu(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{Ou(d)}}function Nu(e){try{return JSON.parse(n.readFileSync(wu(e),"utf8"))}catch{return}}function _u(e){const t=Nu(e);return Au(t?.pid)&&Tu({pid:t.pid,startIdentity:t.startIdentity})}function Ou(e){try{n.unlinkSync(e)}catch(e){if("ENOENT"!==e.code)throw e}}function Pu(){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,20)}function Ru(e){try{const t=Nu(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 ju(e,s){try{return n.writeFileSync(Su(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=Su(e),r=Du(s),o=Date.parse(r?.startedAt||"");if(Cu(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=Du(a);if(d?.token===r?.token)return Ou(a),!0;try{n.linkSync(a,s)}catch(e){if("EEXIST"!==e.code)throw e}finally{Ou(a)}return!1}(e)&&ju(e,s);if("ENOENT"===r.code)return!1;throw r}}function Du(e){try{return JSON.parse(n.readFileSync(e,"utf8"))}catch{return}}function Mu(e,t){return Du(Su(e))?.token===t}function Lu(){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 qu(e,s={}){return function(e,s={}){n.mkdirSync(t.dirname(e),{recursive:!0});const r=ku(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(wu(e),`${JSON.stringify({token:o.token,pid:o.pid,startIdentity:o.startIdentity,startedAt:(new Date).toISOString()})}\n`,{encoding:"utf8",mode:384,flag:"wx"}),Eu(e,o),{lockPath:e,owner:o,updateDetails:t=>xu(e,o,t),release(){const t=zu(e);t?.token===o.token&&n.rmSync(e,{recursive:!0,force:!0})}}}catch(r){if("EEXIST"!==r.code)throw r;const o=zu(e);if(Tu(o))throw new bu(e,o,s.error);if(!o&&(_u(e)||Ru(e)<(s.incompleteLockStaleMs??2e3))){if(t+1<5){Pu();continue}throw new bu(e,void 0,s.error)}const a=i.randomUUID();if(!ju(e,a)){if(t+1<5){Pu();continue}throw new bu(e,zu(e),s.error)}const d=zu(e);if(Tu(d))throw Ou(Su(e)),new bu(e,d,s.error);if(o?.token&&d?.token!==o.token){Ou(Su(e));continue}if(!Mu(e,a))continue;n.rmSync(e,{recursive:!0,force:!0})}const a=zu(e);throw new bu(e,a,s.error)}(e,{...s,component:"control-plane",error:{label:"Control plane",code:"CONTROL_PLANE_ALREADY_RUNNING"}})}function $u(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:Bu(e,t))}(t,n):"admin"===e.role||("viewer"===e.role?"read"===t:"operator"===e.role&&Bu(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 Bu(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 Uu=a.z.string().trim().min(1),Fu=a.z.object({id:Uu}).strict(),Hu=a.z.object({id:Uu,keyId:Uu}).strict(),Gu=a.z.object({id:Uu,connectionId:Uu}).strict(),Wu=a.z.object({id:Uu,runtimeId:Uu}).strict(),Vu=a.z.object({id:Uu,folderId:Uu}).strict(),Ku=a.z.object({id:Uu,sessionId:Uu}).strict(),Ju=a.z.object({id:Uu,sessionId:Uu,queueId:Uu}).strict(),Yu=a.z.object({configHash:Uu}).strict(),Qu=a.z.object({id:Uu,configHash:Uu}).strict(),Xu=a.z.object({id:Uu,sessionId:Uu,configHash:Uu}).strict(),Zu=a.z.object({path:a.z.string().optional(),depth:a.z.coerce.number().int().min(0).max(32).optional()}).strict();async function eh(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 th=a.z.object({ids:a.z.array(a.z.string().trim().min(1).max(120)).default([])}).strict(),nh=a.z.object({nodeId:a.z.string().trim().min(1).max(120),modelId:a.z.string().trim().min(1).max(120).optional()}).strict(),ih=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 sh(e){const t=ih.parse(e);if(!t.action)throw new Error("Chat gateway action is required.");return{source:t.source,action:t.action}}const rh=a.z.object({path:a.z.string().trim().max(1e3).optional(),depth:a.z.coerce.number().int().min(0).max(2).optional()}).strict(),oh=a.z.object({id:a.z.string().trim().min(1),appId:a.z.string().trim().min(1)}).strict(),ah=a.z.object({id:a.z.string().trim().min(1),jobId:a.z.string().trim().min(1)}).strict(),dh=a.z.object({projection:a.z.literal("directory").optional()}).strict(),ch=a.z.object({id:a.z.string().trim().min(1).max(120)}).strict(),lh=a.z.object({nodeId:a.z.string().trim().min(1).max(120),templateId:a.z.string().trim().min(1).max(120)}).strict(),ph=a.z.object({force:a.z.enum(["true","false"]).optional()}).strict(),uh=a.z.object({projection:a.z.literal("directory").optional()}).strict();const hh=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:{}}),gh=a.z.object({title:a.z.string().trim().min(1).max(120)}).strict(),mh=a.z.object({token:a.z.string().trim().min(1).max(512)}).strict(),yh=a.z.object({}).strict();function fh(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(Fu.parse(e.params).id)})),e.patch("/api/projects/:id",async e=>{const i=t.updateProject(Fu.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=Fu.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)=>eh(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=th.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(Fu.parse(e.params).id)})),e.patch("/api/models/:id",async e=>{const i=await t.updateModel(Fu.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=Fu.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}=nh.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}=nh.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}=nh.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(Fu.parse(e.params).id)})),e.patch("/api/images/:id",async e=>{const i=t.updateImage(Fu.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=Fu.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"===uh.parse(e.query).projection?t.listNodes().map(e=>function(e){const t=e.proxyState?.lastError;return Aa.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(Fu.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(Fu.parse(e.params).id)})),e.get("/api/nodes/:id/settings/external-listener",async e=>({data:await t.getLocalNodeExternalListener(Fu.parse(e.params).id)})),e.patch("/api/nodes/:id/settings/external-listener",async e=>{const i=Fu.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=Fu.parse(e.params).id,s=await t.checkNodeUpdate(i,Zi.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=Fu.parse(e.params).id,r=await t.applyNodeUpdate(s,ns.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=Fu.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=Fu.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=Fu.parse(e.params);return{data:await t.listNodeControlPlanePairings(n.id)}}),e.delete("/api/nodes/:id/control-plane-pairings/:keyId",async e=>{const i=Hu.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=Fu.parse(e.params);return{data:await t.listNodeControlPlaneConnections(n.id)}}),e.delete("/api/nodes/:id/control-plane-connections/:connectionId",async e=>{const i=Gu.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:Yp},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(Fu.parse(e.params).id)})),e.post("/api/nodes/:id/runtimes",async(e,i)=>{const s=Fu.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=Wu.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=Wu.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=Wu.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(Fu.parse(e.params).id)})),e.get("/api/nodes/:id/image-options",async e=>({data:await t.listNodeImageAvailability(Fu.parse(e.params).id)})),e.get("/api/nodes/:id/local-folders",async(e,n)=>eh(e,n,async n=>({data:await t.listNodeLocalFolders(Fu.parse(e.params).id,n)}))),e.get("/api/nodes/:id/folders/tree",async e=>{const n=Fu.parse(e.params),i=Zu.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=Fu.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=Vu.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(Fu.parse(e.params).id)})),e.patch("/api/nodes/:id",async e=>{const r=t.updateNode(Fu.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=Fu.parse(e.params).id,r=ph.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)=>eh(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 su(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(Wo,{websocket:!0,config:Zp},(e,t)=>{try{const i=pu.parse(t.query),s=n.requireNode(i.nodeId);gu(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(`${Wo}/streams/:streamId`,{websocket:!0,config:Zp},(e,t)=>{try{const i=pu.parse(t.query),s=n.requireNode(i.nodeId);gu(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(`${Wo}/channels/:channelId`,{websocket:!0,config:Zp},(e,t)=>{try{const i=pu.parse(t.query),s=n.requireNode(i.nodeId);gu(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(`${Wo}/http-streams/:streamId`,{websocket:!0,config:Zp},(e,t)=>{try{const i=pu.parse(t.query),s=n.requireNode(i.nodeId);gu(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(Fu.parse(e.params).id)})),e.get("/api/controlled-instances/:id/metrics",async e=>({data:await t.instanceResourceMetrics(Fu.parse(e.params).id)})),e.get("/api/controlled-instances/:id/apps/management",async e=>({data:await t.instanceAppManagement(Fu.parse(e.params).id)})),e.post("/api/controlled-instances/:id/apps/:appId/install",async e=>{const n=oh.parse(e.params),i=Hi.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=oh.parse(e.params),i=Hi.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=ah.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(Fu.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=Fu.parse(e.params).id,s=await t.deleteControlledInstance(i,vi.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(Fu.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(Fu.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(Fu.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(Fu.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(Fu.parse(e.params).id)})),e.get("/api/controlled-instances/:id/config-sync/folders",async e=>({data:await t.listInstanceConfigSyncFolders(Fu.parse(e.params).id,rh.parse(e.query))})),e.post("/api/controlled-instances/:id/config-sync",async e=>{const i=Fu.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)=>eh(e,n,async n=>{const i=dh.parse(e.query),s=await t.boardWithDiagnostics(n);return{data:"directory"===i.projection?s.items.map(Ea):s.items,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(ch.parse(e.params).id)})),e.get("/api/nodes/:nodeId/environment-templates/:templateId",async e=>{const n=lh.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=ch.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=lh.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})}}return{data:await i.list({refresh:"true"===t.refresh||"1"===t.refresh})}}),e.post("/api/controlled-instances/:id/apps/sessions",async e=>{const i=Fu.parse(e.params),s=hh.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=Ku.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=Ku.parse(e.params),s=gh.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=Ku.parse(e.params);yh.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=Ku.parse(e.params),i=mh.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=Fu.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=Fu.parse(e.params);return{data:await t.listAiSessionHistory(n.id)}}),e.get("/api/controlled-instances/:id/ai-sessions/history/:sessionId",async e=>{const n=Ku.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=Ku.parse(e.params);yh.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.post("/api/controlled-instances/:id/ai-sessions",async e=>{const i=Fu.parse(e.params),s=me.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=Ku.parse(e.params),s=fe.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/close",async e=>{const i=Ku.parse(e.params),s=be.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=Ku.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=Ku.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=Ku.parse(e.params),i=ce.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=Ku.parse(e.params),s=ee.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=Ku.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=Ju.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=Ju.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=Ju.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=Ju.parse(e.params),i=Ae.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=Ku.parse(e.params),i=Se.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=Ku.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=Ku.parse(e.params),s=we.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});for(const e of i.instances)r.reconcile(e.instanceId,e.aiSessions);return{data:{...i,instances:i.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=Ku.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(R,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=Yu.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=Yu.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=Yu.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=Fu.parse(e.params);return{data:await t.listInstanceTriggers(n.id)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/triggers",async e=>{const i=Ku.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=Xu.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=Qu.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(Fu.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=Fu.parse(i.params).id,r=t.requireChatBridge(s),o=Ya.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=Fu.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=Fu.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=Fu.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(vr.parse(e.body))})),e.post("/api/chat-gateway/actions",async e=>({data:await t.handleChatGatewayAction(sh(e.body))})),e.get("/api/pending-routes",async()=>({data:await t.listPendingRoutes()}))}({app:t,service:n,chatGateway:d})}const Ih=new Set(["connection","content-length","keep-alive","proxy-authenticate","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),bh=new Set(["authorization"]),vh=new Set(["content-encoding"]);function wh(e){return Object.fromEntries(Object.entries(e).flatMap(([e,t])=>{const n=e.toLowerCase();if(Ih.has(n)||bh.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()!==Vr).join("; ")}(i);return s?[[e,s]]:[]}))}function Sh(e){return Object.fromEntries(Object.entries(wh(e)).filter(([e])=>{const t=e.toLowerCase();return"host"!==t&&"cookie"!==t&&"authorization"!==t&&(!t.startsWith("sec-websocket-")||"sec-websocket-origin"===t)}))}function Ah(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 kh(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 zh(e,t,n){for(const[n,i]of Object.entries(t.headers)){const t=n.toLowerCase();Ih.has(t)||vh.has(t)||e.header(n,i)}if(!t.body)return e.code(t.status).send();const i=h.Readable.fromWeb(t.body);return e.raw.once("close",()=>i.destroy()),e.code(t.status).send(n?i.pipe(n):i)}function Ch(e){return`/instances/${encodeURIComponent(e)}`}function Th(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 h.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()}})}(Ch(n)):void 0;return zh(e,t,s)}function Eh(e){return Buffer.isBuffer(e)?e:e instanceof Uint8Array?Buffer.from(e):e instanceof URLSearchParams?e.toString():"string"==typeof e?e:null==e?void 0:JSON.stringify(e)}function xh(e,t){if("string"!=typeof t||!e.hasContentTypeParser(t))try{e.addContentTypeParser(t,{parseAs:"buffer"},(e,t,n)=>n(null,t))}catch(e){if(e instanceof Error&&/Content type parser .* already present/i.test(e.message))return;throw e}}function Nh(e){return new URL(e,"http://control-plane.local").searchParams.get("token")||""}function _h(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 Oh{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===P){const t=mo(We,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?Fe:e.type===_?He:e.type===O?Ge:void 0;if(!t)return!1;const n=mo(t,e.payload);return n.success?e.type===N?this.applySnapshot(n.data):e.type===_?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:_,payload:e})}applyRemoved(e){return this.apply({type:O,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 Ve.parse({streamId:i,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:s,syncRequired:!0,events:[]});if(e.sinceRevision===n)return Ve.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 Ve.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:Le.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===_){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=Me.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:Le.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 Ph=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 Rh{records;bySession=new Map;listener;constructor(e,t={}){this.records=new Hr(e.aiSessionUnreadDir,{schema:Ph}),this.listener=t.onChanged}init(){this.records.init(),this.bySession.clear();for(const e of this.records.list())this.bySession.set(Dh(e.instanceId,e.sessionId),e)}reconcile(e,t){const n=new Set;for(const i of t.sessions)n.add(i.id),this.reconcileSession(e,i);for(const t of[...this.bySession.values()])t.instanceId!==e||n.has(t.sessionId)||this.deleteRecord(t)}decorate(e,t){return{...t,sessions:t.sessions.map(t=>({...t,unread:this.bySession.get(Dh(e,t.id))?.unread||!1}))}}markRead(e,t,n){const i=this.bySession.get(Dh(e,t));return i&&i.sessionUpdatedAt===n&&i.unread?jh(this.store({...i,unread:!1,updatedAt:(new Date).toISOString()},!1)):i?jh(i):void 0}removeInstance(e){for(const t of[...this.bySession.values()])t.instanceId===e&&this.deleteRecord(t)}reconcileSession(e,t){const n=Dh(e,t.id),i=this.bySession.get(n),s=(new Date).toISOString();if(!i)return void this.store({id:Mh(e,t.id),instanceId:e,sessionId:t.id,unread:!1,lastStatus:t.status,sessionUpdatedAt:t.updatedAt,createdAt:s,updatedAt:s},!1);const r=function(e,t,n){return"running"!==n&&"waiting"!==n&&("running"===t||"waiting"===t||e)}(i.unread,i.lastStatus,t.status),o=r!==i.unread;(o||i.lastStatus!==t.status||i.sessionUpdatedAt!==t.updatedAt)&&this.store({...i,unread:r,lastStatus:t.status,sessionUpdatedAt:t.updatedAt,updatedAt:s},o)}store(e,t){const n=this.records.put(e);return this.bySession.set(Dh(n.instanceId,n.sessionId),n),t&&this.listener?.(jh(n)),n}deleteRecord(e){this.records.delete(e.id),this.bySession.delete(Dh(e.instanceId,e.sessionId))}}function jh(e){return L.parse({instanceId:e.instanceId,sessionId:e.sessionId,unread:e.unread,sessionUpdatedAt:e.sessionUpdatedAt,updatedAt:e.updatedAt})}function Dh(e,t){return`${e}\0${t}`}function Mh(e,t){return`ais_unread_${i.createHash("sha256").update(Dh(e,t)).digest("hex").slice(0,32)}`}class Lh{snapshots=new Map;history=new Map;advertisedStreams=new Map;recoveries=new Map;bootstrap;logger;recoverDelta;recoverSnapshot;onRecoveredEvent;recoveryCount=0;counters={streamResets:0,gaps:0,deltaRecoveries:0,snapshotRecoveries:0,recoveryFailures:0};constructor(e){this.bootstrap=e.bootstrap,this.logger=e.logger,this.recoverDelta=e.recoverDelta,this.recoverSnapshot=e.recoverSnapshot,this.onRecoveredEvent=e.onRecoveredEvent}handleEvent(e){const t=e.type===Xe?lt:e.type===Ze?pt:e.type===et?ut:void 0;if(!t)return!1;const n=mo(t,e.payload);return n.success?e.type===Xe?this.applySnapshot(n.data):e.type===Ze?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:Xe,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:Ze,payload:e})}applyRemoved(e){return this.apply({type:et,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 ht.parse({streamId:i,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:s,syncRequired:!0,events:[]});if(e.sinceRevision===n)return ht.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 ht.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===Xe&&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===Xe)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:at.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:mt(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===Ze){const e=i.findIndex(e=>e.id===t.payload.session.id);It(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=gt(i,n.generatedAt);return{kind:"applied",projection:at.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:mt(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:Xe,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:Xe,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 qh(e){return e.raw[0].replace(/\\\$\{/g,"${")}class $h{states=new Map;events;constructor(e){this.events=e}handle(e){if(e.type===ur){const t=mo(hr,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===Ms){const t=mo($s,e.payload);return void(t.success&&this.applyOutput(t.data))}if(e.type===Ls){const t=mo(Bs,e.payload);t.success&&this.applyFinished(t.data)}}snapshots(){return[...this.states.values()].filter(e=>e.progress).map(e=>Us.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 Hh,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=Bh(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=Bh(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 Hh,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=Bh(e),this.events.publish("image.pull.progress",e.progress,{topic:"instances",scope:{instanceId:e.identity.instanceId}}),t&&(e.progress=Bh(e)))}}function Bh(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 Us.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:Fh(t[1],t[2]),total:Fh(t[3],t[4])}}function Fh(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 Hh{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 Gh=a.z.object({revision:a.z.number().int().nonnegative(),invites:a.z.array(_n),bindings:a.z.array(Dn)}).strict(),Wh={invite:new Set(Object.keys(_n.shape)),binding:new Set(Object.keys(Dn.shape))};function Vh(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 Kh(e,t,n){if(!t||"object"!=typeof t||Array.isArray(t))return t;const i=t,s=Wh[e],r=Object.keys(i).filter(e=>!s.has(e));r.length>0&&n?.({kind:e,fields:r});const o=Vh(i,s);return"binding"===e&&o.lastError&&(o.lastError=Vh(o.lastError,Object.keys(xn.shape))),o}function Jh(e){const{tokenHash:t,...n}=e;return On.parse(n)}function Yh(e){const{credentialHash:t,...n}=e;return Mn.parse(n)}class Qh{authority;constructor(e,t){this.authority=new Gr(e,()=>({revision:0,invites:[],bindings:[]}),{schema:Gh,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=>Kh("invite",e,t)):n.invites,bindings:Array.isArray(n.bindings)?n.bindings.map(e=>Kh("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 Xh extends Error{code;statusCode;retryable;details;constructor(e,t,n,i=!1,s={}){super(t),this.name="ControlPlaneProxyServiceError",this.code=e,this.statusCode=n,this.retryable=i,this.details=s}}const Zh=e=>i.createHash("sha256").update(e).digest("base64url"),eg=()=>i.randomBytes(32).toString("base64url");function tg(e,t){const n=Zh(t),s=Buffer.from(e),r=Buffer.from(n);return s.length===r.length&&i.timingSafeEqual(s,r)}function ng(e,t,n,i=!1,s={}){throw new Xh(e,t,n,i,s)}class ig{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??eg}init(){this.store.init(),this.expireInvites()}createInvite(e,t){const n=this.resolveProxyOrigin();n||ng(Tn.Unavailable,"Configure an externally reachable HTTPS control-plane proxy origin before creating an invite.",409,!1);const i=Pn.parse(e);this.requireManageableTarget(i.targetNodeId);const s=this.createTokenValue(),r=this.nowIso(),o={id:Ur("proxy_invite"),targetNodeId:i.targetNodeId,tokenHash:Zh(s),status:"active",createdBy:t,expiresAt:new Date(this.now().getTime()+1e3*i.expiresInSeconds).toISOString(),createdAt:r,updatedAt:r},a=Rn.parse({invite:Jh(o),token:s,proxyOrigin:n,protocolVersion:hn});return this.store.transaction(e=>e.invites.push(o)),a}resolveProxyOrigin(){const e=this.configuredProxyOrigin??this.proxyOriginProvider?.();if(!e)return;const t=bn.safeParse(e);return t.success?t.data:void 0}listInvites(){return this.expireInvites(),this.store.listInvites().map(Jh)}revokeInvite(e){const t=this.requireInvite(e);if("consumed"===t.status&&ng(Tn.InviteConsumed,"A consumed proxy invite cannot be revoked independently of its binding.",409,!1,{inviteId:e}),"revoked"===t.status||"expired"===t.status)return Jh(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}),Jh(i)}claimInvite(e){const t=Ln.parse(e);this.requireCurrentProtocol(t.protocolVersion),this.expireInvites();const n=Zh(t.credential);return this.store.transaction(e=>{const i=e.bindings.find(e=>e.claimId===t.claimId);if(!t.inviteToken)return i||ng(Tn.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)&&ng(Tn.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:t.claimId}),"revoked"===i.status&&ng(Tn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:i.id}),this.claimResult(i,this.requireKnownTarget(i.targetNodeId));const s=e.invites.find(e=>tg(e.tokenHash,t.inviteToken));s||ng(Tn.InviteInvalid,"Proxy invite is invalid.",401),t.targetNodeId&&t.targetNodeId!==s.targetNodeId&&ng(Tn.TargetMismatch,"Proxy invite is bound to a different target.",409,!1,{inviteId:s.id,targetNodeId:t.targetNodeId});const r=(o=s.id,`proxy_binding_${Zh(o).slice(0,32)}`);var o;const a=e.bindings.find(e=>e.id===r),d=e.bindings.find(e=>e.claimId===t.claimId),c=a??d;if(a&&d&&a.id!==d.id&&ng(Tn.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&&ng(Tn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:c.id}),"consumed"===s.status&&s.consumedByClaimId===t.claimId||ng(Tn.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(Yh)}authenticateBinding(e,t){const n=qn.parse(t),i=this.store.getBinding(e);return i||ng(Tn.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),"active"!==i.status&&ng(Tn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:e}),i.sourceControlPlaneId===n.sourceControlPlaneId&&i.bindingKeyId===n.bindingKeyId&&tg(i.credentialHash,n.credential)||ng(Tn.AuthenticationFailed,"Proxy binding authentication failed.",401,!1,{bindingId:e}),Yh(i)}revokeBinding(e){const t=this.requireBinding(e);if("revoked"===t.status)return Yh(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}),Yh(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}),Yh(e))),invites:t.invites.filter(t=>t.targetNodeId===e&&"active"===t.status).map(e=>(Object.assign(e,{status:"revoked",revokedAt:n,updatedAt:n}),Jh(e)))}})}nowIso(){return this.now().toISOString()}requireCurrentProtocol(e){e!==hn&&ng(Tn.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:e,supportedVersion:hn})}requireKnownTarget(e){const t=this.targets.get(e);return t||ng(Tn.TargetUnavailable,"Proxy target no longer exists.",404,!1,{targetNodeId:e}),t}requireManageableTarget(e){const t=this.requireKnownTarget(e);return t.manageable&&"online"===t.status||ng(Tn.TargetUnavailable,"Proxy target is not currently manageable.",503,!0,{targetNodeId:e}),t}requireInvite(e){const t=this.store.getInvite(e);return t||ng(Tn.InviteInvalid,"Proxy invite is unknown.",404,!1,{inviteId:e}),t}requireBinding(e){const t=this.store.getBinding(e);return t||ng(Tn.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),t}requireClaimableInvite(e){"active"!==e.status&&ng({expired:Tn.InviteExpired,consumed:Tn.InviteConsumed,revoked:Tn.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||ng(Tn.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:i.claimId})}claimResult(e,t){const{manageable:n,...i}=t;return Wn.parse({protocolVersion:hn,binding:Yh(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 sg extends Error{statusCode=429;code=Tn.ResourceLimit;retryable=!0;details;constructor(e,t){super(e),this.name="NodeProxyRuntimeError",this.details=t}}class rg{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:Tn.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+=og(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=og(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:Tn.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 sg(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 og(e){return Buffer.isBuffer(e)||e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:Buffer.byteLength("string"==typeof e?e:String(e),"utf8")}class ag{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:dg(t)}}subscribe(e,t,n,i=()=>{}){const{bindingId:s,sourceControlPlaneId:r,targetNodeId:o}=e,a=this.stream(o),d=dg(a);if(t>a.revision||t<d-1)return n(Hn.parse({type:"control-plane-proxy.snapshot-required",protocolVersion:hn,streamId:a.streamId,bindingId:s,sourceControlPlaneId:r,targetNodeId:o,sinceRevision:t,latestRevision:a.revision,earliestRetainedRevision:d,error:{code:Tn.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(Fn.parse({type:"control-plane-proxy.events.ready",protocolVersion:hn,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(cg(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:dg(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=Un.safeParse({type:"control-plane-proxy.event",protocolVersion:hn,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=lg(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=cg(d,e.bindingId,e.sourceControlPlaneId),n=lg(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 dg(e){return e.history[0]?.event.revision??e.revision+1}function cg(e,t,n){return Un.parse({...e,bindingId:t,sourceControlPlaneId:n})}function lg(e){try{return Buffer.byteLength(JSON.stringify(e),"utf8")}catch{return}}function pg(e,t){const n=new WeakSet;let i=t,s=0;const r=e=>{if(i-=Buffer.byteLength(e,"utf8"),i<0)throw ug("Proxy target projection byte limit exceeded.",{resource:"target-projection-bytes",limit:t})},o=(e,t)=>{if(s+=1,s>16384||t>24)throw ug("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 ug("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 ug(e,t,n=!0){return Object.assign(new Error(e),{code:"CONTROL_PLANE_PROXY_RESOURCE_LIMIT",statusCode:429,retryable:n,...t?{details:t}:{}})}function hg(e){const{manageable:t,...n}=e;return n}const gg=a.z.object({bindingId:a.z.string().trim().min(1).max(160)}).passthrough(),mg=a.z.object({route:vn}).strict(),yg=a.z.object({sinceRevision:a.z.coerce.number().int().nonnegative()}).strict(),fg=new Set(["connection","cookie","host","keep-alive","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),Ig=524288;function bg(e,t,n){const i=Cg(n.headers,An);if(i!==hn)throw zg(Tn.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:i,supportedVersion:hn});const s=Cg(n.headers,kn),r=Cg(n.headers,zn),o=Cg(n.headers,Cn);if(!s||!r||!o)throw zg(Tn.AuthenticationFailed,"Proxy binding authentication headers are incomplete.",401);return e.authenticateBinding(t,{sourceControlPlaneId:s,bindingKeyId:r,credential:o})}function vg(e,t,n){const i=bg(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 zg(Tn.BindingIdentityConflict,"Proxy binding changed while the request was being established.",409,!0,{bindingId:t.id,expectedRevision:t.revision,actualRevision:i.revision})}function wg(e,t){if(t.id!==e.targetNodeId)throw zg(Tn.TargetMismatch,"Proxy target resolver returned another node.",409,!1,{bindingId:e.id,targetNodeId:e.targetNodeId})}function Sg(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 zg(Tn.HeaderInvalid,"Caller-supplied node transport authentication headers are forbidden.",400,!1,{header:e})}const t=Object.fromEntries([...wn].flatMap(t=>{if(fg.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=In.safeParse(t["x-request-id"]);if(!e.success)throw zg(Tn.HeaderInvalid,"Proxy request correlation id is invalid.",400,!1,{header:"x-request-id"});t["x-request-id"]=e.data}return t}function Ag(e,t,n){const i=kg(t),s=Tg(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 kg(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)||Tn.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 zg(e,t,n,i=!1,s){return Object.assign(new Error(t),{code:e,statusCode:n,retryable:i,...s?{details:s}:{}})}function Cg(e,t){const n=e[t];return Array.isArray(n)?n.join(","):"string"==typeof n?n:""}function Tg(e){if(!e)return;const t=In.safeParse(Cg(e,"x-request-id"));return t.success?t.data:void 0}function Eg(e){let t="";for(const n of e){if(Buffer.byteLength(t+n)>123)break;t+=n}return t}const xg=e=>xn.parse({code:Tn.Unavailable,message:e,retryable:!0});class Ng{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:ca(n)});if(!this.current(e,t))return;const s=await i.json().catch(()=>{});if(!i.ok){const n=mo(xn,s?.error),r=n.success?n.data:xg(`Proxy snapshot failed with HTTP ${i.status}.`);return r.code===Tn.BindingRevoked?void this.onStateChanged(this.service.markProxyBindingRevoked(e,r)):void this.fail(e,t,r,r.retryable)}const r=yo(Bn,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:Tn.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:_g(n)},"control-plane proxy state bootstrap failed"),this.fail(e,t,xg("Trusted control-plane proxy is unavailable."),!0)}else this.fail(e,t,xg("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),ca(n));s.socket=r;let o=!1;const a=n=>{o||(o=!0,this.fail(e,t,xg(n),!0))};r.on("message",s=>{if(this.current(e,t))try{const r=yo(Gn,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:_g(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:Tn.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 _g(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 Og=a.z.object({id:a.z.string().trim().min(1).max(160)}).strict(),Pg=a.z.object({}).strict(),Rg=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 jg(){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 Dg(e){return`sha256:${i.createHash("sha256").update(Buffer.from(e,"base64url")).digest("base64url")}`}function Mg(e){return Array.isArray(e)?`[${e.map(Mg).join(",")}]`:e&&"object"==typeof e?`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${Mg(t)}`).join(",")}}`:JSON.stringify(e)}class Lg{identity;controlPlaneId;constructor(e,t,n){this.controlPlaneId=t,this.identity=new Gr(e,jg,{schema:Rg,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=_r.parse({version:1,kind:"control-plane",controlPlaneId:this.controlPlaneId(),publicKey:{algorithm:"Ed25519",encoding:"base64url",value:n.publicKey,fingerprint:Dg(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(_r.parse(a)))),this.privateKey()).toString("base64url");var a;return Or.parse({data:{payload:r,signature:o}})}publicIdentity(){const e=this.identity.get();return{controlPlaneId:this.controlPlaneId(),algorithm:e.algorithm,publicKey:e.publicKey,fingerprint:Dg(e.publicKey)}}signCloudBindingChallenge(e){return i.sign(null,Buffer.from(`task-handoff:cloud-binding-challenge:v1\n${Mg(e)}`),this.privateKey()).toString("base64url")}signCloudOutboundRegistration(e){return i.sign(null,Buffer.from((t=e,`task-handoff:outbound-control-registration:v1\n${Ot(Ft.parse(t))}`)),this.privateKey()).toString("base64url");var t}acceptCloudAccessHandshake(e,t){return function(e){const t=Ht.parse(e.ticket),n=Vt.parse(e.clientHello);if(t.ticketId!==n.ticketId||t.deviceSessionId!==n.deviceSessionId||t.targetPublicKeyFingerprint!==e.controlPlaneFingerprint)throw Kt();const s=i.generateKeyPairSync("x25519"),r=function(e){const t=e.export({format:"jwk"}).x;if(!t)throw Kt();return t}(s.publicKey),o=function(e,t,n){return i.createHash("sha256").update(Ot({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 qg{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 $g(e,n){const i=t.extname(e);return`${i?e.slice(0,-i.length):e}.${n}${i}`}const Bg=1048576,Ug=52428800;function Fg(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:e}function Hg(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 Gg(e,i,s){const r=n.statSync(e),o=Math.min(r.size,Bg,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 Wg=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 Vg{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 Gr(e.statePath,()=>({version:1,serviceOrigin:this.serviceOrigin,status:"unbound",remoteAccessEnabled:!0,updatedAt:new Date(this.clock()).toISOString(),connectionEpoch:0}),{schema:Wg,directoryMode:448,fileMode:384})}init(){if(this.state.init(),this.state.get().serviceOrigin!==this.serviceOrigin)throw Jg("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 Jg("active"===e.status?"CONTROL_PLANE_ALREADY_BOUND":"BINDING_STATE_CONFLICT","Existing cloud binding must be resolved first.");this.prune();const t=Ur("binding_challenge"),n=i.randomBytes(32).toString("base64url"),s=this.challengePayload(t);return this.challenges.set(t,{digest:Kg(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=Kg(s),o.length!==a.length||!i.timingSafeEqual(o,a)))throw Jg("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 Jg("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 Jg("CONTROL_PLANE_ALREADY_BOUND","Control Plane is already bound to another account.")}if("pending-claim"!==t.status)throw Jg("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 Kg(e){return i.createHash("sha256").update(e).digest()}function Jg(e,t){return Object.assign(new Error(t),{code:e,statusCode:e.includes("CONFLICT")||e.includes("BOUND")?409:400})}class Yg{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 Qg{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 Xg{connection;processInstanceId=`control_plane_process_${i.randomUUID().replaceAll("-","_")}`;backoff;options;constructor(e){this.options=e,this.backoff=e.backoff??new Qg}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 Zg{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 em{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 tm{options;constructor(e){this.options=e}async connect(e){const t=e.allocation,n=Wt.parse(t.attach),i=Ht.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(rm("RELAY_SOCKET_CLOSED")))})}(s),s.send(JSON.stringify({type:"attach",capability:n})),async function(e,t,n,i,s){const r=await im(e,e=>"frame"===e?.type&&"handshake"===e.frame?.kind);if(r.frame.channelId!==t||0!==r.frame.sequence)throw rm("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 nm(e,t,a.sessionKey,c,s);return l.start(),{close:(e="normal")=>l.close(e)}}(s,(await im(s,e=>"attached"===e?.type)).channelId,i,this.options.identity,this.options.bridge)}}class nm{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 rm("RELAY_FRAME_SEQUENCE_INVALID");const i=w.secretbox.open(Buffer.from(n.ciphertext,"base64url"),sm(1,this.receiveCounter++),this.key);if(!i)throw rm("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 rm("RELAY_ENVELOPE_UNSUPPORTED")}send(e){if(this.socket.readyState!==l.OPEN||this.socket.bufferedAmount>2097152)throw rm("RELAY_BACKPRESSURE_LIMIT");const t=w.secretbox(Buffer.from(JSON.stringify(e)),sm(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 im(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(rm("RELAY_SOCKET_CLOSED"))},o=()=>{e.off("message",s),e.off("close",r)};e.on("message",s),e.once("close",r)})}function sm(e,t){const n=new Uint8Array(24);return n[0]=e,new DataView(n.buffer).setBigUint64(16,BigInt(t),!1),n}function rm(e){return Object.assign(new Error("Cloud Relay session is invalid."),{code:e,retryable:!0})}class om{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(dm("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(dm("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 dm("CLOUD_CONTROL_CONNECTION_UNAVAILABLE");return this.current.request(e,t)}}class am{lifecycle;dataConnections;connector;control;events;timer;running=!1;connecting;options;constructor(e){this.options=e,this.connector=new om({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 tm({identity:e.identity,bridge:e.relayBridge,webSocket:e.webSocket}):{async connect(){throw dm("CLOUD_RELAY_CONNECTOR_UNAVAILABLE")}});this.dataConnections=new Zg({verifyAllocation:e.verifyAllocation??(t=>function(e,t){const n=e,i=Wt.parse(n?.attach),s=Ht.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 rm("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 rm("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 Yg({state:e.state,connections:{stop:e=>this.control.stop(e)},dataConnections:this.dataConnections}),this.control=new Xg({state:e.state,connector:this.connector,onEvent:async e=>{await this.events.apply(e)}}),this.lifecycle=new em({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 dm("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 dm("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 dm(e){return Object.assign(new Error("Cloud background connection is unavailable."),{code:e,retryable:!0})}const cm="x-task-handoff-cloud-internal-actor",lm=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(),pm=a.z.object({error:lm}).strict(),um="https://cloud.thandoff.com";function hm(e,t={}){const n=new URL(e||um).origin;if(n===um)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 gm(e){const t=process.env[e]?.trim();return t||void 0}const mm=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 ym(){return{component:"control-plane",packageName:"@task-handoff/control-plane",packageVersion:mm(),protocolVersion:Jn,buildId:gm("TASK_HANDOFF_BUILD_ID"),builtAt:gm("TASK_HANDOFF_BUILT_AT"),gitCommit:gm("TASK_HANDOFF_GIT_COMMIT"),imageRef:gm("TASK_HANDOFF_IMAGE_REF"),imageDigest:gm("TASK_HANDOFF_IMAGE_DIGEST")}}const fm={".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 Im(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 bm(e,i,s){const r=Im(i,s);return r?(e.header("cache-control","no-store"),e.type(fm[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 vm(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 wm(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[Vr],clientType:"web"}}async function Sm(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 Am=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 km(e,t){const n=t.split("?")[0]||"/";if(!n.startsWith("/api/"))return;if(Am.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("/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 zm(e={}){const d=Iu(e.dataDir),c=s({logger:e.logger??!0}),l=new Hp,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 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($g(e,t),{force:!0});for(let i=t-1;i>=1;i-=1){const t=$g(e,i);n.existsSync(t)&&n.renameSync(t,$g(e,i+1))}}}(e,r),r>0?t.size>s?(n.writeFileSync($g(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,$g(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:Fg(a)},(e,t)=>Fg(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 qg;f.onChange(e=>l.publish("node.connection.updated",e,{topic:"node.state",scope:{nodeId:e.nodeId}}));const I=new qc(d,{...e.service,logger:m,nodeConnectionRuntime:f}),b=new go(d,e.auth),v=new Lg(d.identitySigningPath,()=>I.proxyPrivateStore.controlPlaneId(),(e,t)=>c.log.warn(t,e)),w=new Vg({statePath:d.cloudConnectivityPath,identity:v,serviceOrigin:hm(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 am({state:w,identity:v,relayBridge:{async request(e,t){const n=String(t?.method||"GET").toUpperCase(),s=String(t?.path||""),r=km(n,s);if(!s.startsWith("/api/")||!r||Am.has(s.split("?")[0]))throw Object.assign(new Error("Cloud access route is not available."),{code:"CLOUD_ROUTE_FORBIDDEN",statusCode:403});$u(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",cm].includes(e.toLowerCase())).map(([e,t])=>[e,String(t)])),i=await c.inject({method:n,url:s,headers:{...e,[cm]: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($u(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=Qe.parse(t);n(Ut.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)),T=new $h(l),E=new Rh(d,{onChanged:e=>queueMicrotask(()=>l.publish(R,e,{topic:"ai.sessions",scope:{instanceId:e.instanceId,sessionId:e.sessionId}}))});E.init();const x=new Oh({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)});x.onSnapshot(e=>E.reconcile(e.instanceId,e.aiSessions));const N=new Lh({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=>x.list(e)),l.on(e=>{if(T.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),E.removeInstance(t))}});const _=new Jp;c.addHook("onClose",async()=>{_.dispose()});const O=new yu(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)}),P=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:pg(e.capabilities||{},262144),manageable:!1!==e.connectionEnabled&&(n||"online"===i)}}(t,O.connected(t.id)):void 0},D=new ig(new Qh(d.proxyAuthorityPath,(e,t)=>c.log.warn(t,e)),{get:j},{proxyOrigin:P,proxyOriginProvider:()=>I.getSettings().publicBaseUrl}),M=new rg,L=new ag(l,{projectTarget:e=>{const t=j(e);return t?hg(t):void 0}}),q=new Ng(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&&O.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){O.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(O),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 hp(I,e.service?.fetchImpl,{aiSessions:x,logger:m,diagnosticLogsEnabled:()=>u});H.startEnabled();const G=new fu(I,O,{safetyIntervalMs:Number(process.env.TASK_HANDOFF_EVENT_CONNECTION_SAFETY_INTERVAL_MS)||void 0,logger:m,connectionRuntime:f});G.start(),await c.register(r),await c.register(o),c.addHook("onClose",async()=>{await k.stop(),B&&clearInterval(B),U&&clearInterval(U),await($?.catch(()=>{})),T.close(),L.stop(),q.stop(),G.stop(),H.stopAll()}),c.setErrorHandler((e,t,n)=>{const i=vm(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(pm.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[cm],o="string"==typeof r?S.get(r):void 0;if(o){S.delete(r);const t=km(e.method,i);if(!t)throw Object.assign(new Error("Cloud access route is not authorized."),{code:"CLOUD_ROUTE_FORBIDDEN",statusCode:403});return void $u(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 Sm(b,wm(e)),n=km(e.method,i);return void(n&&$u(t||{type:"system",reason:"auth-disabled"},n.action,n.resource))}const d=await Sm(b,wm(e));if(!d)return t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to access the Control Plane."}});const c=km(e.method,i);c&&$u(d,c.action,c.resource)});const W=t.resolve(e.staticDir||process.env.TASK_HANDOFF_CONTROL_PLANE_STATIC_DIR||t.resolve(process.cwd(),"packages","control-plane-ui","dist"));n.existsSync(W)&&(c.get("/assets/*",{config:Yp},async(e,n)=>{const i=e.params["*"];return bm(n,W,t.join("assets",i||""))}),c.get("/favicon.ico",{config:Yp},async(e,t)=>Im(W,"favicon.ico")?bm(t,W,"favicon.ico"):t.code(204).send())),c.get("/api/health",{config:Yp},async()=>({data:{ok:!0,role:"control-plane",protocolVersion:Jn,build:ym(),dataDir:d.dataDir,serverTime:(new Date).toISOString()}})),c.get("/api/control-plane/identity",{config:Yp},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});$u(await Sm(b,wm(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:x.diagnostics(),aiSessionActions:I.aiSessionActionDiagnostics(),appSessions:N.diagnostics(),nodeConnections:{...G.diagnostics(),runtime:f.diagnostics()}}})),c.get("/install-node-agent.sh",{config:Yp},async(e,t)=>(t.header("cache-control","no-store"),t.type("text/x-shellscript; charset=utf-8"),qh`#!/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
- `)),d.get("/api/events",{websocket:!0},async e=>{const t=[];let n=!1;const s={get readyState(){return e.readyState},OPEN:e.OPEN,send(s){n?e.send(s):t.push(s)},on(t,n){e.on(t,n)}};c.connect(s);const[i,r]=await Promise.all([S.streamDescriptors(),A.streamDescriptors()]);c.send(e,"streams.hello",{protocolVersion:1,streams:[...i,...r]}),n=!0;for(const n of t)e.send(n);for(const t of b.snapshots())c.send(e,"image.pull.snapshot",t,{topic:"instances",scope:{instanceId:t.instanceId}})}),d.get("/api/auth/session",{config:zp},async e=>{const t=Ch(e);return{data:await f.currentSession(t.token,t.clientType)}}),d.post("/api/auth/bootstrap-admin",{config:zp},async(e,t)=>{const n=await f.bootstrapAdmin(e.body);return t.code(201).send({data:n})}),d.post("/api/auth/login",{config:zp},async(e,t)=>{const n=await f.login(e.body,{sourceId:e.ip});return t.setCookie(Vi,n.sessionToken,{path:"/",httpOnly:!0,sameSite:"lax",expires:new Date(n.expiresAt)}),{data:{user:n.user}}}),d.post("/api/auth/mobile/login",{config:zp},async e=>({data:await f.loginMobile(e.body,{sourceId:e.ip})})),d.patch("/api/auth/password",async(e,t)=>{const n=await f.changePassword(e.cookies[Vi],e.body,{sourceId:e.ip});return t.setCookie(Vi,n.sessionToken,{path:"/",httpOnly:!0,sameSite:"lax",expires:new Date(n.expiresAt)}),{data:{user:n.user}}}),d.post("/api/auth/mobile/logout",async e=>{const t=Ch(e);return{data:f.logout("mobile"===t.clientType?t.token:void 0)}}),d.get("/api/auth/mobile/sessions",async(e,t)=>{const n=f.mobileSessions(Ch(e).token);return n?{data:n}:t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to access mobile sessions."}})}),d.delete("/api/auth/mobile/sessions/:id",async(e,t)=>{const n=o.z.object({id:o.z.string().trim().min(1)}).parse(e.params),s=f.revokeMobileSession(Ch(e).token,n.id);return void 0===s?t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to revoke mobile sessions."}}):{data:{revoked:s}}}),d.post("/api/auth/logout",{config:zp},async(e,t)=>{const n=f.logout(e.cookies[Vi]);return t.clearCookie(Vi,{path:"/"}),{data:n}}),d.get("/api/control-plane/status",async()=>({data:{protocolVersion:Kt,build:Sh(),storage:a}})),d.get("/api/control-plane/settings",async()=>({data:m.getSettings()})),d.patch("/api/control-plane/settings",async e=>{const t=m.updateSettings(e.body||{});return l=t.diagnosticLogs,{data:t}}),d.get("/api/control-plane/diagnostic-logs/export",async(e,s)=>{const i=await async function(e){const s=n.mkdtempSync(t.join(y.tmpdir(),"task-handoff-diagnostic-logs-")),i=t.resolve(e.nodeAgentDataDir||t.join(e.dataDir,"node-agent")),r=t.join(i,"local-instances"),o=n.existsSync(r)?n.readdirSync(r,{withFileTypes:!0}).filter(e=>e.isDirectory()&&!e.isSymbolicLink()).map(e=>({label:t.join("local-instances",e.name),root:t.join(r,e.name,"logs")})):[],a=[{label:"control-plane",root:t.join(e.dataDir,"logs")},{label:"desktop",root:t.join(e.dataDir,"log")},{label:"node-agent",root:t.join(i,"logs")},...o],d=[];let c=0;for(const e of a)for(const i of yh(e.root)){if(c>=hh)break;const r=t.relative(e.root,i);if(!r||r.startsWith("..")||t.isAbsolute(r))continue;const o=t.join("logs",e.label,r),a=n.statSync(i).size,l=fh(i,t.join(s,o),hh-c);l&&(c+=l,d.push({source:i,archivePath:o,bytes:l,originalBytes:a}))}n.writeFileSync(t.join(s,"manifest.json"),`${JSON.stringify({createdAt:(new Date).toISOString(),diagnosticLogsEnabled:e.diagnosticLogsEnabled,limits:{perFileBytes:gh,totalBytes:hh},files:d.map(({archivePath:e,bytes:t,originalBytes:n})=>({archivePath:e,bytes:t,originalBytes:n,truncated:t<n}))},null,2)}\n`,{mode:384});const l=["manifest.json",...n.existsSync(t.join(s,"logs"))?["logs"]:[]],p=w.create({cwd:s,gzip:!0,portable:!0,noMtime:!0},l),u=()=>n.rmSync(s,{recursive:!0,force:!0});return p.once("close",u),p.once("error",u),{filename:`task-handoff-diagnostic-logs-${(new Date).toISOString().replace(/[:.]/g,"-")}.tar.gz`,stream:p}}({dataDir:a.dataDir,nodeAgentDataDir:process.env.TASK_HANDOFF_DESKTOP_NODE_AGENT_DATA_DIR||process.env.TASK_HANDOFF_NODE_AGENT_DATA_DIR,diagnosticLogsEnabled:l});return s.header("content-type","application/gzip"),s.header("content-disposition",`attachment; filename="${i.filename}"`),s.send(i.stream)}),d.post("/api/ai-session-attachments",{bodyLimit:33554432},async(e,t)=>{try{return t.code(201).send({data:k.upload(e.body)})}catch(e){return t.code(400).send({error:{code:"AI_SESSION_ATTACHMENT_INVALID",message:e instanceof Error?e.message:String(e)}})}}),Wu({app:d,service:m,events:c,appSessionAggregator:A,aiSessionAggregator:S,aiSessionUnread:v,chatGateway:D,aiSessionAttachments:k,nodeAgentTunnel:z,nodeEventSubscriber:q,errorPayload:Th}),function(e){const{app:t,authority:n,resolveTarget:s,projectTarget:i,eventHub:r}=e,o=e.runtime??new Rg,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:Cp,bodyLimit:o.maxRequestBodyBytes,logLevel:"silent",async onRequest(e,t){try{const s=Ug.parse(e.params).bindingId,i=Vg(n,s,e),r=function(e){const t=e.raw.url||e.url,n=/^\/api\/node-proxy\/bindings\/[^/]+\/http(\/[^#]*)$/.exec(t);if(!n||/%(?:2f|5c)/i.test(n[1]))throw Zg(Tt.RouteInvalid,"Proxy route is invalid.",400);const s=bt.safeParse(n[1]);if(!s.success)throw Zg(Tt.RouteInvalid,s.error.issues[0]?.message||"Proxy route is invalid.",400);return s.data}(e),c=Qg(e.headers),l=o.reserveHttp(i.id),p=()=>{l.controller.abort(Object.assign(new Error("Proxy HTTP consumer disconnected."),{name:"AbortError",code:"ABORT_ERR"})),d(e,t)};a.set(e,{binding:i,route:r,forwardedHeaders:c,tracked:l,abort:p}),e.raw.once("aborted",p),t.raw.once("close",p)}catch(n){return Yg(t,n,e)}},async onError(e,t){d(e,t);const n=th(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 Zg(Tt.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 s=new URL(t,"https://node-agent.invalid").searchParams,i=[s.get("nodeId"),s.get("targetNodeId")];if(n&&"object"==typeof n&&!Array.isArray(n)){const e=n;"string"==typeof e.nodeId&&i.push(e.nodeId),"string"==typeof e.targetNodeId&&i.push(e.targetNodeId)}const r=i.find(t=>null!==t&&t!==e.targetNodeId);if(void 0!==r)throw Zg(Tt.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==(i=e.body)?void 0:Buffer.isBuffer(i)?i:i instanceof Uint8Array||"string"==typeof i?Buffer.from(i):Buffer.from(JSON.stringify(i));p.acceptRequestBody(h?.byteLength??0);try{const{node:i,transport:r}=await s(o.targetNodeId);return Kg(n,o,e),Jg(o,i),function(e,t,n,s,i,r){t.body&&n.beginResponseStream();for(const[n,s]of Object.entries(function(e,t){const n=Object.fromEntries([...wt].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,s);const o=()=>{n.release(),i.raw.removeListener("aborted",s),e.raw.removeListener("close",s)};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(i,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),Yg(t,n,e)}var i}),t.get("/api/node-proxy/bindings/:bindingId/websocket",{websocket:!0,logLevel:"silent",config:Cp},async(e,t)=>{let i;try{const r=Ug.parse(t.params).bindingId,a=Vg(n,r,t),d=Fg.parse(t.query).route,{node:c,transport:l}=await s(a.targetNodeId);Kg(n,a,t),Jg(a,c),i=o.openWebSocket(a.id,e),l.proxyWebSocket(c,i,d,function(e){const t=eh(e,"sec-websocket-protocol").split(",").map(e=>e.trim()).filter(Boolean);return t.length?t:void 0}(t.headers),Qg(t.headers))}catch(t){const n=Xg(t);i?.close(1008,n.message),i||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,nh(n.message))}}),t.get("/api/node-proxy/bindings/:bindingId/snapshot",{config:Cp},async(e,t)=>{try{const t=Ug.parse(e.params).bindingId,a=Vg(n,t,e),{node:d}=await s(a.targetNodeId);Kg(n,a,e),Jg(a,d);const c=i(a.targetNodeId);if(!c)throw Zg(Tt.TargetUnavailable,"Proxy target no longer exists.",404,!1,{targetNodeId:a.targetNodeId});const l=r.cursor(a.targetNodeId),p=$t.parse({protocolVersion:ut,binding:a,streamId:l.streamId,revision:l.revision,observedAt:(new Date).toISOString(),target:Bg(c)});if(o=p,Buffer.byteLength(JSON.stringify(o),"utf8")>Gg)throw Zg(Tt.ResourceLimit,"Proxy target snapshot byte limit exceeded.",429,!0,{bindingId:a.id,resource:"snapshot-bytes",limit:Gg});return{data:p}}catch(n){return Yg(t,n,e)}var o}),t.get("/api/node-proxy/bindings/:bindingId/events",{websocket:!0,logLevel:"silent",config:Cp},async(e,t)=>{let i,a,d;try{const c=Ug.parse(t.params).bindingId,l=Vg(n,c,t),p=Hg.parse(t.query),{node:u}=await s(l.targetNodeId);Kg(n,l,t),Jg(l,u),i=o.openWebSocket(l.id,e,()=>a?.()),i.on("message",()=>i?.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=>{i?.send(JSON.stringify(e))},()=>{i?.close(1011,"Proxy event delivery failed.")});a=g.close,d=o.registerBindingCleanup(l.id,a);const h=()=>{a?.(),d?.()};i.on("close",h),i.on("error",h),"snapshot-required"===g.kind?(a(),i.close(1008,"Proxy target snapshot is required.")):1!==i.readyState&&a()}catch(t){a?.(),d?.();const n=Xg(t);i?.close(1008,n.message),i||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,nh(n.message))}}),t.delete("/api/node-proxy/bindings/:bindingId",{config:Cp},async(t,s)=>{try{const s=Ug.parse(t.params).bindingId;Vg(n,s,t);const i=n.revokeBinding(s),r=o.closeBinding(s);return e.onBindingRevoked?.(i),{data:{binding:i,closed:r}}}catch(e){return Yg(s,e,t)}})}({app:d,authority:x,resolveTarget:e=>{const t=m.requireNode(e);return{node:t,transport:m.resolveNodeAgentTransport(t)}},projectTarget:C,runtime:E,eventHub:N,onBindingRevoked:e=>c.publish("control-plane-proxy.binding.updated",{binding:e,audit:{action:"binding.revoke",actor:`control-plane:${e.sourceControlPlaneId}`}},{topic:"control-plane-proxy",scope:{nodeId:e.targetNodeId}})}),function(e){const{app:t,service:n,proxy:s,runtime:i,events:r,actorId:o}=e;t.get("/api/control-plane-proxy/invites",async()=>({data:s.listInvites()})),t.post("/api/control-plane-proxy/invites",async(e,t)=>{const n=await o(e),i=s.createInvite(e.body,n);return r.publish("control-plane-proxy.invite.created",{invite:i.invite,audit:{action:"invite.create",actor:n}},{topic:"control-plane-proxy",scope:{nodeId:i.invite.targetNodeId}}),t.code(201).send({data:i})}),t.delete("/api/control-plane-proxy/invites/:id",async e=>{const t=await o(e),n=s.revokeInvite(oh.parse(e.params).id);return r.publish("control-plane-proxy.invite.updated",{invite:n,audit:{action:"invite.revoke",actor:t}},{topic:"control-plane-proxy",scope:{nodeId:n.targetNodeId}}),{data:n}}),t.get("/api/control-plane-proxy/bindings",async()=>({data:s.listBindings()})),t.delete("/api/control-plane-proxy/bindings/:id",async e=>{const t=await o(e),n=oh.parse(e.params).id,a=s.revokeBinding(n),d=i.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:i.diagnostics()})),t.post("/api/node-proxy/claims",{config:zp},async(e,t)=>{const n=s.claimInvite(e.body);return r.publish("control-plane-proxy.binding.created",{binding:n.binding,audit:{action:"binding.claim",actor:`control-plane:${n.binding.sourceControlPlaneId}`}},{topic:"control-plane-proxy",scope:{nodeId:n.binding.targetNodeId}}),t.code(201).send({data:n})}),t.get("/api/control-plane-proxy/pending-claims",async()=>({data:n.listPendingProxyClaims()})),t.post("/api/control-plane-proxy/claims",async(e,t)=>{const s=await n.claimProxyNode(e.body);return r.publish("node.created",{nodeId:s.node.id}),t.code(201).send({data:s})}),t.post("/api/control-plane-proxy/pending-claims/:id/resume",async e=>{const t=oh.parse(e.params).id;ah.parse(e.body||{});const s=await n.resumeProxyClaim(t);return r.publish("node.created",{nodeId:s.node.id}),{data:s}}),t.delete("/api/control-plane-proxy/pending-claims/:id",async e=>({data:await n.cancelProxyClaim(oh.parse(e.params).id)}))}({app:d,service:m,proxy:x,runtime:E,events:c,actorId:async e=>{const t=await xh(f,Ch(e));return t?"user"===t.type?`user:${t.userId}`:"system"===t.type?`system:${t.reason}`:`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"])sg(e,t);sg(e,/^multipart\/form-data(?:;.*)?$/i)}(e),e.get("/api/app-access/session",{config:zp},async e=>{const n=ig(e.url),s="vnc"===e.query.mode?"vnc":"web"===e.query.mode?"web":"tty",i=await t.appAccessProxyTarget(n,s);return{data:{mode:s,instance:{id:i.instance.id,name:i.instance.name,projectId:i.instance.projectId,projectName:"string"==typeof i.instance.sourceSnapshot.name?i.instance.sourceSnapshot.name:void 0},session:i.session,expiresAt:i.access.expiresAt,ttySocketPath:"tty"===s?`/apps/access/tty/ws?token=${encodeURIComponent(n)}`:void 0,vncFramePath:"vnc"===s?rg(n,i.access.sessionId,i.session):void 0}}}),e.get("/apps/access/tty/ws",{websocket:!0,config:zp},async(e,n)=>{try{const s=await t.appAccessProxyTarget(ig(n.url),"tty");await t.proxyInstanceWebSocket(s.instance.id,e,s.path,Yu(n.headers),Qu(n.headers))}catch{e.close(1011,"TTY access link is invalid or expired.")}});const n=async(e,n)=>{const s=n.params;try{const i=await t.appAccessProxyTarget(s.token||ig(n.url),"vnc",s["*"]||"");await t.proxyInstanceWebSocket(i.instance.id,e,i.path,Yu(n.headers),Qu(n.headers))}catch{e.close(1011,"VNC access link is invalid or expired.")}};e.route({method:"GET",url:"/apps/access/vnc/proxy/*",config:zp,wsHandler:n,handler:async(e,n)=>{const s=e.params,i=await t.appAccessProxyTarget(ig(e.url),"vnc",s["*"]||"");return tg(n,await Xu(t,n,i.instance.id,i.path,{method:e.method,headers:Ju(e.headers)}),i.instance.id,i.path)}}),e.route({method:"GET",url:"/apps/access/vnc/:token/proxy/*",config:zp,wsHandler:n,handler:async(e,n)=>{const s=e.params,i=await t.appAccessProxyTarget(s.token,"vnc",s["*"]||"");return tg(n,await Xu(t,n,i.instance.id,i.path,{method:e.method,headers:Ju(e.headers)}),i.instance.id,i.path)}}),e.all("/instances/:id",{bodyLimit:67108864},async(e,n)=>{const s=e.params;return"GET"===e.method||"HEAD"===e.method?n.redirect(`${eg(s.id)}/`):tg(n,await Xu(t,n,s.id,"/",{method:e.method,headers:Ju(e.headers),body:ng(e.body)}),s.id,"/")}),e.route({method:"GET",url:"/instances/:id/*",wsHandler:async(e,n)=>{const s=n.params,i=s["*"]||"",r=n.url.indexOf("?"),o=r>=0?n.url.slice(r):"";try{await t.proxyInstanceWebSocket(s.id,e,`/${i}${o}`,Yu(n.headers),Qu(n.headers))}catch{e.close(1011,"Instance websocket endpoint is not reachable.")}},handler:async(e,n)=>{const s=e.params,i=s["*"]||"",r=e.url.indexOf("?"),o=`/${i}${r>=0?e.url.slice(r):""}`;return tg(n,await Xu(t,n,s.id,o,{method:e.method,headers:Ju(e.headers)}),s.id,o)}}),e.route({method:["POST","PUT","PATCH","DELETE","OPTIONS"],url:"/instances/:id/*",bodyLimit:67108864,handler:async(e,n)=>{const s=e.params,i=s["*"]||"",r=e.url.indexOf("?"),o=r>=0?e.url.slice(r):"";return Zu(n,await Xu(t,n,s.id,`/${i}${o}`,{method:e.method,headers:Ju(e.headers),body:ng(e.body)}))}})}({app:d,service:m}),d.get("*",{config:Tp},async(e,t)=>n.existsSync(L)?zh(t,L,"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."}})),O=setInterval(()=>{M().catch(e=>d.log.warn({error:e},"pending node pairing recovery failed"))},3e4),O.unref(),j=setInterval(()=>{m.runPersistenceMaintenance()},216e5),j.unref(),d}function Ph(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 Rh(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(k("@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",Ph,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",Rh,process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"password").action(async e=>{await async function(e){const t=Vp(e.dataDir),n=hu(gu(),{dataDir:t.dataDir,host:e.host,port:e.port});try{const t=await _h(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$/,""),s=await async function(e,t,n={}){const s=Vp(e),i=hu(n.lockPath||gu(),{dataDir:s.dataDir});try{const e=new gr(s,{mode:"password"});return e.init(),await e.replaceCredentials(t)}finally{i.release()}}(e.dataDir,{username:e.username,password:n});console.log(`Updated Control Plane credentials for ${s.username}. Existing sessions were revoked.`)}),await n.parseAsync(process.argv)})().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});
223
+ `)),c.get("/api/events",{websocket:!0},async e=>{const t=[];let n=!1;const i={get readyState(){return e.readyState},OPEN:e.OPEN,send(i){n?e.send(i):t.push(i)},on(t,n){e.on(t,n)}};l.connect(i);const[s,r]=await Promise.all([x.streamDescriptors(),N.streamDescriptors()]);l.send(e,"streams.hello",{protocolVersion:1,streams:[...s,...r]}),n=!0;for(const n of t)e.send(n);for(const t of T.snapshots())l.send(e,"image.pull.snapshot",t,{topic:"instances",scope:{instanceId:t.instanceId}})}),c.get("/api/auth/session",{config:Yp},async e=>{const t=wm(e);return{data:await b.currentSession(t.token,t.clientType)}}),c.post("/api/auth/bootstrap-admin",{config:Yp},async(e,t)=>{const n=await b.bootstrapAdmin(e.body);return t.code(201).send({data:n})}),c.post("/api/auth/login",{config:Yp},async(e,t)=>{const n=await b.login(e.body,{sourceId:e.ip});return t.setCookie(Vr,n.sessionToken,{path:"/",httpOnly:!0,sameSite:"lax",expires:new Date(n.expiresAt)}),{data:{user:n.user}}}),c.post("/api/auth/mobile/login",{config:Yp},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[Vr],e.body,{sourceId:e.ip});return t.setCookie(Vr,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=wm(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(wm(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(wm(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:Yp},async(e,t)=>{const n=b.logout(e.cookies[Vr]);return t.clearCookie(Vr,{path:"/"}),{data:n}}),c.get("/api/control-plane/status",async()=>({data:{protocolVersion:Jn,build:ym(),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 Hg(e.root)){if(c>=Ug)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=Gg(s,t.join(i,o),Ug-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:Bg,totalBytes:Ug},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:_.upload(e.body)})}catch(e){return t.code(400).send({error:{code:"AI_SESSION_ATTACHMENT_INVALID",message:e instanceof Error?e.message:String(e)}})}}),fh({app:c,service:I,events:l,appSessionAggregator:N,aiSessionAggregator:x,aiSessionUnread:E,chatGateway:H,aiSessionAttachments:_,nodeAgentTunnel:O,nodeEventSubscriber:G,errorPayload:vm}),function(e){const{app:t,authority:n,resolveTarget:i,projectTarget:s,eventHub:r}=e,o=e.runtime??new rg,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:Xp,bodyLimit:o.maxRequestBodyBytes,logLevel:"silent",async onRequest(e,t){try{const i=gg.parse(e.params).bindingId,s=bg(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 zg(Tn.RouteInvalid,"Proxy route is invalid.",400);const i=vn.safeParse(n[1]);if(!i.success)throw zg(Tn.RouteInvalid,i.error.issues[0]?.message||"Proxy route is invalid.",400);return i.data}(e),c=Sg(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 Ag(t,n,e)}},async onError(e,t){d(e,t);const n=Tg(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 zg(Tn.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 zg(Tn.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 vg(n,o,e),wg(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([...Sn].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=h.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),Ag(t,n,e)}var s}),t.get("/api/node-proxy/bindings/:bindingId/websocket",{websocket:!0,logLevel:"silent",config:Xp},async(e,t)=>{let s;try{const r=gg.parse(t.params).bindingId,a=bg(n,r,t),d=mg.parse(t.query).route,{node:c,transport:l}=await i(a.targetNodeId);vg(n,a,t),wg(a,c),s=o.openWebSocket(a.id,e),l.proxyWebSocket(c,s,d,function(e){const t=Cg(e,"sec-websocket-protocol").split(",").map(e=>e.trim()).filter(Boolean);return t.length?t:void 0}(t.headers),Sg(t.headers))}catch(t){const n=kg(t);s?.close(1008,n.message),s||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,Eg(n.message))}}),t.get("/api/node-proxy/bindings/:bindingId/snapshot",{config:Xp},async(e,t)=>{try{const t=gg.parse(e.params).bindingId,a=bg(n,t,e),{node:d}=await i(a.targetNodeId);vg(n,a,e),wg(a,d);const c=s(a.targetNodeId);if(!c)throw zg(Tn.TargetUnavailable,"Proxy target no longer exists.",404,!1,{targetNodeId:a.targetNodeId});const l=r.cursor(a.targetNodeId),p=Bn.parse({protocolVersion:hn,binding:a,streamId:l.streamId,revision:l.revision,observedAt:(new Date).toISOString(),target:hg(c)});if(o=p,Buffer.byteLength(JSON.stringify(o),"utf8")>Ig)throw zg(Tn.ResourceLimit,"Proxy target snapshot byte limit exceeded.",429,!0,{bindingId:a.id,resource:"snapshot-bytes",limit:Ig});return{data:p}}catch(n){return Ag(t,n,e)}var o}),t.get("/api/node-proxy/bindings/:bindingId/events",{websocket:!0,logLevel:"silent",config:Xp},async(e,t)=>{let s,a,d;try{const c=gg.parse(t.params).bindingId,l=bg(n,c,t),p=yg.parse(t.query),{node:u}=await i(l.targetNodeId);vg(n,l,t),wg(l,u),s=o.openWebSocket(l.id,e,()=>a?.()),s.on("message",()=>s?.close(1008,"Proxy event streams do not accept client messages."));const h=r.subscribe({bindingId:l.id,sourceControlPlaneId:l.sourceControlPlaneId,targetNodeId:l.targetNodeId},p.sinceRevision,e=>{s?.send(JSON.stringify(e))},()=>{s?.close(1011,"Proxy event delivery failed.")});a=h.close,d=o.registerBindingCleanup(l.id,a);const g=()=>{a?.(),d?.()};s.on("close",g),s.on("error",g),"snapshot-required"===h.kind?(a(),s.close(1008,"Proxy target snapshot is required.")):1!==s.readyState&&a()}catch(t){a?.(),d?.();const n=kg(t);s?.close(1008,n.message),s||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,Eg(n.message))}}),t.delete("/api/node-proxy/bindings/:bindingId",{config:Xp},async(t,i)=>{try{const i=gg.parse(t.params).bindingId;bg(n,i,t);const s=n.revokeBinding(i),r=o.closeBinding(i);return e.onBindingRevoked?.(s),{data:{binding:s,closed:r}}}catch(e){return Ag(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(Og.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=Og.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:Yp},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=Og.parse(e.params).id;Pg.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(Og.parse(e.params).id)}))}({app:c,service:I,proxy:D,runtime:M,events:l,actorId:async e=>{const t=await Sm(b,wm(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"])xh(e,t);xh(e,/^multipart\/form-data(?:;.*)?$/i)}(e),e.get("/api/app-access/session",{config:Yp},async e=>{const n=Nh(e.url),i="vnc"===e.query.mode?"vnc":"web"===e.query.mode?"web":"tty",s=await t.appAccessProxyTarget(n,i);return{data:{mode:i,instance:{id:s.instance.id,name:s.instance.name,projectId:s.instance.projectId,projectName:"string"==typeof s.instance.sourceSnapshot.name?s.instance.sourceSnapshot.name:void 0},session:s.session,expiresAt:s.access.expiresAt,ttySocketPath:"tty"===i?`/apps/access/tty/ws?token=${encodeURIComponent(n)}`:void 0,vncFramePath:"vnc"===i?_h(n,s.access.sessionId,s.session):void 0}}}),e.get("/apps/access/tty/ws",{websocket:!0,config:Yp},async(e,n)=>{try{const i=await t.appAccessProxyTarget(Nh(n.url),"tty");await t.proxyInstanceWebSocket(i.instance.id,e,i.path,Ah(n.headers),Sh(n.headers))}catch{e.close(1011,"TTY access link is invalid or expired.")}});const n=async(e,n)=>{const i=n.params;try{const s=await t.appAccessProxyTarget(i.token||Nh(n.url),"vnc",i["*"]||"");await t.proxyInstanceWebSocket(s.instance.id,e,s.path,Ah(n.headers),Sh(n.headers))}catch{e.close(1011,"VNC access link is invalid or expired.")}};e.route({method:"GET",url:"/apps/access/vnc/proxy/*",config:Yp,wsHandler:n,handler:async(e,n)=>{const i=e.params,s=await t.appAccessProxyTarget(Nh(e.url),"vnc",i["*"]||"");return Th(n,await kh(t,n,s.instance.id,s.path,{method:e.method,headers:wh(e.headers)}),s.instance.id,s.path)}}),e.route({method:"GET",url:"/apps/access/vnc/:token/proxy/*",config:Yp,wsHandler:n,handler:async(e,n)=>{const i=e.params,s=await t.appAccessProxyTarget(i.token,"vnc",i["*"]||"");return Th(n,await kh(t,n,s.instance.id,s.path,{method:e.method,headers:wh(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(`${Ch(i.id)}/`):Th(n,await kh(t,n,i.id,"/",{method:e.method,headers:wh(e.headers),body:Eh(e.body)}),i.id,"/")}),e.route({method:"GET",url:"/instances/:id/*",wsHandler:async(e,n)=>{const i=n.params,s=i["*"]||"",r=n.url.indexOf("?"),o=r>=0?n.url.slice(r):"";try{await t.proxyInstanceWebSocket(i.id,e,`/${s}${o}`,Ah(n.headers),Sh(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 Th(n,await kh(t,n,i.id,o,{method:e.method,headers:wh(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 zh(n,await kh(t,n,i.id,`/${s}${o}`,{method:e.method,headers:wh(e.headers),body:Eh(e.body)}))}})}({app:c,service:I}),c.get("*",{config:Qp},async(e,t)=>n.existsSync(W)?bm(t,W,"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 Cm(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 Tm(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",Cm,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",Tm,process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"password").action(async e=>{await async function(e){const t=Iu(e.dataDir),n=qu(Lu(),{dataDir:t.dataDir,host:e.host,port:e.port});try{const t=await zm(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=Iu(e),s=qu(n.lockPath||Lu(),{dataDir:i.dataDir});try{const e=new go(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});