@xenosystem/agent-sdk 0.9.0 → 0.9.9

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 (43) hide show
  1. package/dist/artifacts/index.cjs +1 -1
  2. package/dist/artifacts/index.js +1 -1
  3. package/dist/artifacts/metafile-cjs.json +1 -1
  4. package/dist/artifacts/metafile-esm.json +1 -1
  5. package/dist/automation/index.cjs +478 -17
  6. package/dist/automation/index.js +478 -17
  7. package/dist/automation/metafile-cjs.json +1 -1
  8. package/dist/automation/metafile-esm.json +1 -1
  9. package/dist/control-plane/index.cjs +1 -1
  10. package/dist/control-plane/index.js +1 -1
  11. package/dist/control-plane/metafile-cjs.json +1 -1
  12. package/dist/control-plane/metafile-esm.json +1 -1
  13. package/dist/electron/index.cjs +614 -153
  14. package/dist/electron/index.d.cts +0 -1
  15. package/dist/electron/index.d.ts +0 -1
  16. package/dist/electron/index.js +617 -156
  17. package/dist/electron/metafile-cjs.json +1 -1
  18. package/dist/electron/metafile-esm.json +1 -1
  19. package/dist/index.cjs +787 -316
  20. package/dist/index.d.cts +15 -4
  21. package/dist/index.d.ts +15 -4
  22. package/dist/index.js +788 -317
  23. package/dist/metafile-cjs.json +1 -1
  24. package/dist/metafile-esm.json +1 -1
  25. package/dist/providers/index.cjs +8 -8
  26. package/dist/providers/index.js +7 -7
  27. package/dist/providers/metafile-cjs.json +1 -1
  28. package/dist/providers/metafile-esm.json +1 -1
  29. package/dist/recipes/metafile-cjs.json +1 -1
  30. package/dist/recipes/metafile-esm.json +1 -1
  31. package/dist/research/metafile-cjs.json +1 -1
  32. package/dist/research/metafile-esm.json +1 -1
  33. package/dist/session/index.cjs +6 -6
  34. package/dist/session/index.js +10 -10
  35. package/dist/session/metafile-cjs.json +1 -1
  36. package/dist/session/metafile-esm.json +1 -1
  37. package/dist/ui/index.cjs +3 -3
  38. package/dist/ui/index.js +3 -3
  39. package/dist/ui/metafile-cjs.json +1 -1
  40. package/dist/ui/metafile-esm.json +1 -1
  41. package/ownership/audit.mjs +758 -727
  42. package/ownership/ownership-policy.json +273 -273
  43. package/package.json +4 -1
@@ -1,7 +1,9 @@
1
- var T=1;var L=new Set(["browser.navigate","browser.back","browser.forward","browser.reload","browser.wait","browser.snapshot","browser.screenshot","browser.locate","browser.tabs.list","browser.tabs.open","browser.console.read","browser.network.read","browser.storage.read","browser.page-errors.read"]),D=new Set(["browser.click","browser.type","browser.key","browser.select","browser.scroll","browser.tabs.close","browser.upload","browser.download","browser.record.start","browser.record.stop"]),k=new Set(["computer.observe","computer.screenshot","computer.window-state","computer.wait"]),M=new Set(["computer.point","computer.click","computer.double-click","computer.right-click","computer.drag","computer.type","computer.key","computer.scroll","computer.launch"]),U=[...L,...D,...k,...M];function h(e){if(L.has(e))return{operation:e,surface:"browser",effect:"observe",evidence:{before:"disabled",after:e==="browser.wait"||e==="browser.tabs.list"?"optional":"required",recording:"optional"}};if(D.has(e)){let t=e==="browser.record.start"||e==="browser.record.stop";return{operation:e,surface:"browser",effect:"act",evidence:{before:"required",after:"required",recording:e==="browser.record.stop"?"required":"optional"}}}if(k.has(e))return{operation:e,surface:"computer",effect:"observe",evidence:{before:"disabled",after:e==="computer.wait"?"optional":"required",recording:"optional"}};if(M.has(e))return{operation:e,surface:"computer",effect:"act",evidence:{before:"required",after:"required",recording:"optional"}};throw new TypeError(`Unsupported XENO automation operation: ${e}`)}function V(e){return L.has(e)||D.has(e)||k.has(e)||M.has(e)}var a=class extends Error{constructor(r,n,o,i){super(n,i);this.code=r;this.detail=o;this.name="XenoAutomationError"}code;detail};import{createHash as Ce}from"node:crypto";function Te(e,t){let r=0;for(let n=0;n<t;n+=1)r=r<<1|e>>>n&1;return r}function re(e,t=!1){let r=e.reduce((s,u)=>Math.max(s,u),0);if(r===0){if(t)return{tree:null,codes:e.map(()=>({bits:0,length:0}))};throw new Error("DEFLATE Huffman tree has no symbols")}if(r>15||e.some(s=>!Number.isInteger(s)||s<0||s>15))throw new Error("Invalid DEFLATE Huffman code length");let n=new Uint16Array(r+1);for(let s of e)s>0&&(n[s]+=1);let o=1;for(let s=1;s<=r;s+=1)if(o=(o<<1)-n[s],o<0)throw new Error("Oversubscribed DEFLATE Huffman tree");let i=new Uint32Array(r+1),d=0;for(let s=1;s<=r;s+=1)d=d+n[s-1]<<1,i[s]=d;let c=new Array(r+1),l=e.map(()=>({bits:0,length:0}));for(let s=0;s<e.length;s+=1){let u=e[s];if(u===0)continue;let p=i[u]++,v=Te(p,u),f=c[u]??new Map;f.set(v,s),c[u]=f,l[s]={bits:v,length:u}}return{tree:{maxBits:r,byLength:c},codes:l}}function Se(){let e=new Array(288).fill(0);for(let t=0;t<=143;t+=1)e[t]=8;for(let t=144;t<=255;t+=1)e[t]=9;for(let t=256;t<=279;t+=1)e[t]=7;for(let t=280;t<=287;t+=1)e[t]=8;return e}var Pt=re(Se()),Xt=re(new Array(32).fill(5));var Mt=String.raw`
1
+ var T=1;var L=new Set(["browser.navigate","browser.back","browser.forward","browser.reload","browser.wait","browser.snapshot","browser.screenshot","browser.locate","browser.tabs.list","browser.tabs.open","browser.console.read","browser.network.read","browser.storage.read","browser.page-errors.read"]),D=new Set(["browser.click","browser.type","browser.key","browser.select","browser.scroll","browser.tabs.close","browser.upload","browser.download","browser.record.start","browser.record.stop"]),k=new Set(["computer.observe","computer.screenshot","computer.window-state","computer.wait"]),U=new Set(["computer.point","computer.click","computer.double-click","computer.right-click","computer.drag","computer.type","computer.key","computer.scroll","computer.launch"]),M=[...L,...D,...k,...U];function I(e){if(L.has(e))return{operation:e,surface:"browser",effect:"observe",evidence:{before:"disabled",after:e==="browser.wait"||e==="browser.tabs.list"?"optional":"required",recording:"optional"}};if(D.has(e)){let t=e==="browser.record.start"||e==="browser.record.stop";return{operation:e,surface:"browser",effect:"act",evidence:{before:"required",after:"required",recording:e==="browser.record.stop"?"required":"optional"}}}if(k.has(e))return{operation:e,surface:"computer",effect:"observe",evidence:{before:"disabled",after:e==="computer.wait"?"optional":"required",recording:"optional"}};if(U.has(e))return{operation:e,surface:"computer",effect:"act",evidence:{before:"required",after:"required",recording:"optional"}};throw new TypeError(`Unsupported XENO automation operation: ${e}`)}function B(e){return L.has(e)||D.has(e)||k.has(e)||U.has(e)}var a=class extends Error{constructor(r,n,o,i){super(n,i);this.code=r;this.detail=o;this.name="XenoAutomationError"}code;detail};import{createHash as Ce}from"node:crypto";function Te(e,t){let r=0;for(let n=0;n<t;n+=1)r=r<<1|e>>>n&1;return r}function re(e,t=!1){let r=e.reduce((s,u)=>Math.max(s,u),0);if(r===0){if(t)return{tree:null,codes:e.map(()=>({bits:0,length:0}))};throw new Error("DEFLATE Huffman tree has no symbols")}if(r>15||e.some(s=>!Number.isInteger(s)||s<0||s>15))throw new Error("Invalid DEFLATE Huffman code length");let n=new Uint16Array(r+1);for(let s of e)s>0&&(n[s]+=1);let o=1;for(let s=1;s<=r;s+=1)if(o=(o<<1)-n[s],o<0)throw new Error("Oversubscribed DEFLATE Huffman tree");let i=new Uint32Array(r+1),d=0;for(let s=1;s<=r;s+=1)d=d+n[s-1]<<1,i[s]=d;let c=new Array(r+1),l=e.map(()=>({bits:0,length:0}));for(let s=0;s<e.length;s+=1){let u=e[s];if(u===0)continue;let p=i[u]++,v=Te(p,u),f=c[u]??new Map;f.set(v,s),c[u]=f,l[s]={bits:v,length:u}}return{tree:{maxBits:r,byLength:c},codes:l}}function Se(){let e=new Array(288).fill(0);for(let t=0;t<=143;t+=1)e[t]=8;for(let t=144;t<=255;t+=1)e[t]=9;for(let t=256;t<=279;t+=1)e[t]=7;for(let t=280;t<=287;t+=1)e[t]=8;return e}var Pt=re(Se()),Xt=re(new Array(32).fill(5));var Ut=String.raw`
2
2
  using System;
3
3
  using System.ComponentModel;
4
4
  using System.Runtime.InteropServices;
5
+ using System.Security.AccessControl;
6
+ using System.Security.Principal;
5
7
  using System.Text;
6
8
 
7
9
  namespace Xeno.Security
@@ -15,6 +17,16 @@ namespace Xeno.Security
15
17
  private const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;
16
18
  private const UInt32 DISABLE_MAX_PRIVILEGE = 0x0001;
17
19
  private const UInt32 LUA_TOKEN = 0x0004;
20
+ // TOKEN_INFORMATION_CLASS members used by the owner/default-DACL diagnostic.
21
+ private const Int32 TokenUser = 1;
22
+ private const Int32 TokenOwner = 4;
23
+ private const Int32 TokenDefaultDacl = 6;
24
+ private const UInt32 GenericAll = 0x10000000;
25
+ private const Byte GenericAclRevision = 2;
26
+ // Set when a diagnostic probe could not APPLY its change. Reported separately from the
27
+ // launch result, because "the fix did not help" and "the fix never went on" are different
28
+ // answers and only one of them is about the product.
29
+ private static string ownerDaclError = "";
18
30
  private const UInt32 SE_GROUP_INTEGRITY = 0x00000020;
19
31
  private const UInt32 CREATE_SUSPENDED = 0x00000004;
20
32
  private const UInt32 EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
@@ -135,6 +147,25 @@ namespace Xeno.Security
135
147
  [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
136
148
  private static extern bool ConvertStringSidToSid(string StringSid, out IntPtr Sid);
137
149
 
150
+ [DllImport("advapi32.dll", SetLastError = true)]
151
+ private static extern bool GetTokenInformation(
152
+ IntPtr TokenHandle,
153
+ Int32 TokenInformationClass,
154
+ IntPtr TokenInformation,
155
+ UInt32 TokenInformationLength,
156
+ out UInt32 ReturnLength);
157
+
158
+ // A second, POINTER-typed declaration of the same export. The one below is typed
159
+ // 'ref SID_AND_ATTRIBUTES' for its original caller; the owner/default-DACL diagnostic
160
+ // passes a TOKEN_OWNER / TOKEN_DEFAULT_DACL buffer instead, and C# resolves overloads
161
+ // before the marshaller ever sees them.
162
+ [DllImport("advapi32.dll", SetLastError = true, EntryPoint = "SetTokenInformation")]
163
+ private static extern bool SetTokenInformationPtr(
164
+ IntPtr TokenHandle,
165
+ Int32 TokenInformationClass,
166
+ IntPtr TokenInformation,
167
+ UInt32 TokenInformationLength);
168
+
138
169
  [DllImport("advapi32.dll", SetLastError = true)]
139
170
  private static extern bool SetTokenInformation(
140
171
  IntPtr TokenHandle,
@@ -229,6 +260,264 @@ namespace Xeno.Security
229
260
  [DllImport("kernel32.dll")]
230
261
  private static extern IntPtr LocalFree(IntPtr hMem);
231
262
 
263
+ // ---- Window station / desktop access for the restricted token -------------------
264
+ //
265
+ // MSDN, CreateProcessAsUser: "If lpDesktop is NULL, the new process inherits the desktop
266
+ // and window station of its parent process. You must add permission for the specified
267
+ // account to the specified window station and desktop, EVEN FOR WinSta0\Default."
268
+ //
269
+ // That requirement was unmet, and it is why a hardened launch from an ELEVATED parent died
270
+ // with 0xC0000142 (STATUS_DLL_INIT_FAILED) while the identical code from an unelevated
271
+ // parent worked: the interactive window station's DACL is written at logon for the
272
+ // FILTERED token's SIDs, so the unelevated case was being granted by accident.
273
+ // What the last grant actually DID, per object, so one diagnostic line distinguishes
274
+ // "never ran", "already present" and "added" — three states that look identical from
275
+ // outside and imply completely different next steps.
276
+ private static string lastGrantReport = "not-run";
277
+ private const UInt32 DACL_SECURITY_INFORMATION = 0x00000004;
278
+ private const UInt32 WINSTA_ALL_ACCESS = 0x0000037F;
279
+ private const UInt32 DESKTOP_ALL_ACCESS = 0x000001FF;
280
+ private const UInt32 GENERIC_ACCESS_ALL = 0xF0000000;
281
+ private const UInt32 ACL_REVISION_2 = 2;
282
+ private const UInt32 CONTAINER_INHERIT_ACE = 0x02;
283
+ private const UInt32 INHERIT_ONLY_ACE = 0x08;
284
+ private const UInt32 OBJECT_INHERIT_ACE = 0x01;
285
+ private const UInt32 NO_PROPAGATE_INHERIT_ACE = 0x04;
286
+ private const UInt32 SECURITY_DESCRIPTOR_REVISION = 1;
287
+ private const UInt32 TokenUserClass = 1;
288
+ private const UInt32 AclSizeInformationClass = 2;
289
+ private const Byte ACCESS_ALLOWED_ACE_TYPE = 0;
290
+
291
+ [StructLayout(LayoutKind.Sequential)]
292
+ private struct ACL_SIZE_INFORMATION
293
+ {
294
+ public UInt32 AceCount;
295
+ public UInt32 AclBytesInUse;
296
+ public UInt32 AclBytesFree;
297
+ }
298
+
299
+ [StructLayout(LayoutKind.Sequential)]
300
+ private struct ACE_HEADER
301
+ {
302
+ public Byte AceType;
303
+ public Byte AceFlags;
304
+ public UInt16 AceSize;
305
+ }
306
+
307
+ [DllImport("user32.dll", SetLastError = true)]
308
+ private static extern IntPtr GetProcessWindowStation();
309
+
310
+ [DllImport("user32.dll", SetLastError = true)]
311
+ private static extern IntPtr GetThreadDesktop(UInt32 dwThreadId);
312
+
313
+ [DllImport("kernel32.dll")]
314
+ private static extern UInt32 GetCurrentThreadId();
315
+
316
+ [DllImport("user32.dll", SetLastError = true)]
317
+ private static extern bool GetUserObjectSecurity(IntPtr hObj, ref UInt32 pSIRequested, IntPtr pSid, UInt32 nLength, out UInt32 lpnLengthNeeded);
318
+
319
+ [DllImport("user32.dll", SetLastError = true)]
320
+ private static extern bool SetUserObjectSecurity(IntPtr hObj, ref UInt32 pSIRequested, IntPtr pSid);
321
+
322
+ [DllImport("advapi32.dll", SetLastError = true)]
323
+ private static extern bool GetTokenInformation(IntPtr TokenHandle, UInt32 TokenInformationClass, IntPtr TokenInformation, UInt32 TokenInformationLength, out UInt32 ReturnLength);
324
+
325
+ [DllImport("advapi32.dll", SetLastError = true)]
326
+ private static extern bool GetSecurityDescriptorDacl(IntPtr pSecurityDescriptor, out bool lpbDaclPresent, out IntPtr pDacl, out bool lpbDaclDefaulted);
327
+
328
+ [DllImport("advapi32.dll", SetLastError = true)]
329
+ private static extern bool InitializeSecurityDescriptor(IntPtr pSecurityDescriptor, UInt32 dwRevision);
330
+
331
+ [DllImport("advapi32.dll", SetLastError = true)]
332
+ private static extern bool SetSecurityDescriptorDacl(IntPtr pSecurityDescriptor, bool bDaclPresent, IntPtr pDacl, bool bDaclDefaulted);
333
+
334
+ [DllImport("advapi32.dll", SetLastError = true)]
335
+ private static extern bool GetAclInformation(IntPtr pAcl, ref ACL_SIZE_INFORMATION pAclInformation, UInt32 nAclInformationLength, UInt32 dwAclInformationClass);
336
+
337
+ [DllImport("advapi32.dll", SetLastError = true)]
338
+ private static extern bool InitializeAcl(IntPtr pAcl, UInt32 nAclLength, UInt32 dwAclRevision);
339
+
340
+ [DllImport("advapi32.dll", SetLastError = true)]
341
+ private static extern bool GetAce(IntPtr pAcl, UInt32 dwAceIndex, out IntPtr pAce);
342
+
343
+ [DllImport("advapi32.dll", SetLastError = true)]
344
+ private static extern bool AddAce(IntPtr pAcl, UInt32 dwAceRevision, UInt32 dwStartingAceIndex, IntPtr pAceList, UInt32 nAceListLength);
345
+
346
+ [DllImport("advapi32.dll", SetLastError = true)]
347
+ private static extern bool AddAccessAllowedAceEx(IntPtr pAcl, UInt32 dwAceRevision, UInt32 AceFlags, UInt32 AccessMask, IntPtr pSid);
348
+
349
+ [DllImport("advapi32.dll", SetLastError = true)]
350
+ private static extern bool EqualSid(IntPtr pSid1, IntPtr pSid2);
351
+
352
+ // Copy the token's user SID into unmanaged memory the caller frees with FreeHGlobal.
353
+ private static IntPtr CopyTokenUserSid(IntPtr token)
354
+ {
355
+ UInt32 needed = 0;
356
+ GetTokenInformation(token, TokenUserClass, IntPtr.Zero, 0, out needed);
357
+ if (needed == 0) ThrowLastError("GetTokenInformation(TokenUser size)");
358
+ IntPtr buffer = Marshal.AllocHGlobal(checked((int)needed));
359
+ try
360
+ {
361
+ if (!GetTokenInformation(token, TokenUserClass, buffer, needed, out needed))
362
+ ThrowLastError("GetTokenInformation(TokenUser)");
363
+ // TOKEN_USER's first field is a POINTER into this buffer, so the SID has to be
364
+ // copied out before the buffer is freed.
365
+ IntPtr sidPtr = Marshal.ReadIntPtr(buffer);
366
+ UInt32 sidLength = GetLengthSid(sidPtr);
367
+ IntPtr copy = Marshal.AllocHGlobal(checked((int)sidLength));
368
+ for (UInt32 i = 0; i < sidLength; i++)
369
+ Marshal.WriteByte(copy, checked((int)i), Marshal.ReadByte(sidPtr, checked((int)i)));
370
+ return copy;
371
+ }
372
+ finally
373
+ {
374
+ Marshal.FreeHGlobal(buffer);
375
+ }
376
+ }
377
+
378
+ // Add an access-allowed ACE for the given SID to a USER OBJECT's DACL, preserving every existing
379
+ // ACE. Returns without writing when the SID is already present: a window station lives for
380
+ // the whole logon session, so a launch-time mutation that appended unconditionally would
381
+ // grow a shared descriptor without bound.
382
+ private static string GrantUserObjectAccess(IntPtr userObject, IntPtr sid, UInt32 accessMask, UInt32 inheritFlags, string label)
383
+ {
384
+ UInt32 requested = DACL_SECURITY_INFORMATION;
385
+ UInt32 needed = 0;
386
+ GetUserObjectSecurity(userObject, ref requested, IntPtr.Zero, 0, out needed);
387
+ if (needed == 0) ThrowLastError("GetUserObjectSecurity(" + label + " size)");
388
+ IntPtr sd = Marshal.AllocHGlobal(checked((int)needed));
389
+ IntPtr newSd = IntPtr.Zero;
390
+ IntPtr newAcl = IntPtr.Zero;
391
+ try
392
+ {
393
+ UInt32 ignored;
394
+ if (!GetUserObjectSecurity(userObject, ref requested, sd, needed, out ignored))
395
+ ThrowLastError("GetUserObjectSecurity(" + label + ")");
396
+
397
+ bool present, defaulted;
398
+ IntPtr dacl;
399
+ if (!GetSecurityDescriptorDacl(sd, out present, out dacl, out defaulted))
400
+ ThrowLastError("GetSecurityDescriptorDacl(" + label + ")");
401
+
402
+ var info = new ACL_SIZE_INFORMATION();
403
+ UInt32 existingBytes = 8;
404
+ UInt32 aceCount = 0;
405
+ if (present && dacl != IntPtr.Zero)
406
+ {
407
+ if (!GetAclInformation(dacl, ref info, checked((UInt32)Marshal.SizeOf(typeof(ACL_SIZE_INFORMATION))), AclSizeInformationClass))
408
+ ThrowLastError("GetAclInformation(" + label + ")");
409
+ existingBytes = info.AclBytesInUse;
410
+ aceCount = info.AceCount;
411
+ for (UInt32 i = 0; i < aceCount; i++)
412
+ {
413
+ IntPtr existing;
414
+ if (!GetAce(dacl, i, out existing)) continue;
415
+ var header = (ACE_HEADER)Marshal.PtrToStructure(existing, typeof(ACE_HEADER));
416
+ if (header.AceType != ACCESS_ALLOWED_ACE_TYPE) continue;
417
+ if (header.AceFlags != (Byte)inheritFlags) continue;
418
+ // ACCESS_ALLOWED_ACE is header(4) + mask(4) + SID.
419
+ UInt32 existingMask = (UInt32)Marshal.ReadInt32(existing, 4);
420
+ IntPtr aceSid = new IntPtr(existing.ToInt64() + 8);
421
+ if (!EqualSid(aceSid, sid)) continue;
422
+ // 🔴 The MASK is part of the question, and leaving it out was a real bug.
423
+ // This window station already grants the logged-in user
424
+ // mask=0x24 flags=0x04 (clipboard + global atoms) at logon. Matching on
425
+ // SID and flags alone treated that as "already granted" and skipped
426
+ // WINSTA_ALL_ACCESS entirely — the grant silently did nothing, and the
427
+ // only reason it was caught is that the DACL was read back and compared.
428
+ if ((existingMask & accessMask) == accessMask)
429
+ return label + "=present(0x" + existingMask.ToString("x") + ")";
430
+ }
431
+ }
432
+
433
+ UInt32 sidLength = GetLengthSid(sid);
434
+ UInt32 newSize = existingBytes + sidLength + 64;
435
+ newAcl = Marshal.AllocHGlobal(checked((int)newSize));
436
+ if (!InitializeAcl(newAcl, newSize, ACL_REVISION_2))
437
+ ThrowLastError("InitializeAcl(" + label + ")");
438
+
439
+ for (UInt32 i = 0; i < aceCount; i++)
440
+ {
441
+ IntPtr existing;
442
+ if (!GetAce(dacl, i, out existing)) ThrowLastError("GetAce(" + label + ")");
443
+ var header = (ACE_HEADER)Marshal.PtrToStructure(existing, typeof(ACE_HEADER));
444
+ if (!AddAce(newAcl, ACL_REVISION_2, UInt32.MaxValue, existing, header.AceSize))
445
+ ThrowLastError("AddAce(" + label + ")");
446
+ }
447
+
448
+ if (!AddAccessAllowedAceEx(newAcl, ACL_REVISION_2, inheritFlags, accessMask, sid))
449
+ ThrowLastError("AddAccessAllowedAceEx(" + label + ")");
450
+
451
+ newSd = Marshal.AllocHGlobal(128);
452
+ if (!InitializeSecurityDescriptor(newSd, SECURITY_DESCRIPTOR_REVISION))
453
+ ThrowLastError("InitializeSecurityDescriptor(" + label + ")");
454
+ if (!SetSecurityDescriptorDacl(newSd, true, newAcl, false))
455
+ ThrowLastError("SetSecurityDescriptorDacl(" + label + ")");
456
+ if (!SetUserObjectSecurity(userObject, ref requested, newSd))
457
+ ThrowLastError("SetUserObjectSecurity(" + label + ")");
458
+ return label + "=added";
459
+ }
460
+ finally
461
+ {
462
+ if (newAcl != IntPtr.Zero) Marshal.FreeHGlobal(newAcl);
463
+ if (newSd != IntPtr.Zero) Marshal.FreeHGlobal(newSd);
464
+ Marshal.FreeHGlobal(sd);
465
+ }
466
+ }
467
+
468
+ // Grant the restricted token's own user SID access to this process's window station and
469
+ // desktop. Returns null on success, or a description of what failed.
470
+ //
471
+ // Best-effort BY DESIGN, and this is deliberately NOT the usual fail-closed case. A
472
+ // hardened launch from an unelevated parent already works with no grant at all, so
473
+ // treating a grant failure as fatal would convert a working configuration into a broken
474
+ // one. The real gate is whether the child starts; when it does not, this reason is
475
+ // reported alongside, which is what turns an opaque NTSTATUS into something actionable.
476
+ private static string GrantDesktopAccessForToken(IntPtr token, string tokenProbe)
477
+ {
478
+ IntPtr sid = IntPtr.Zero;
479
+ try
480
+ {
481
+ sid = CopyTokenUserSid(token);
482
+ IntPtr winsta = GetProcessWindowStation();
483
+ if (winsta == IntPtr.Zero) return "GetProcessWindowStation returned NULL";
484
+ IntPtr desktop = GetThreadDesktop(GetCurrentThreadId());
485
+ if (desktop == IntPtr.Zero) return "GetThreadDesktop returned NULL";
486
+ // Two ACEs on the window station, as the documented sequence requires: an
487
+ // inherit-only one so desktops created later in this session carry the grant, and
488
+ // a non-propagating one for the station itself.
489
+ lastGrantReport =
490
+ GrantUserObjectAccess(winsta, sid, GENERIC_ACCESS_ALL, CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE, "winsta-inherit")
491
+ + " " + GrantUserObjectAccess(winsta, sid, WINSTA_ALL_ACCESS, NO_PROPAGATE_INHERIT_ACE, "winsta")
492
+ + " " + GrantUserObjectAccess(desktop, sid, DESKTOP_ALL_ACCESS, 0, "desktop");
493
+ if (tokenProbe == "grant-everyone")
494
+ {
495
+ // DIAGNOSTIC ONLY, and never a fix: this asks whether the denied object is
496
+ // the window station/desktop at all, by granting a SID no access check can
497
+ // miss. A pass here means the real fix is naming the right SID.
498
+ IntPtr everyone = IntPtr.Zero;
499
+ if (ConvertStringSidToSid("S-1-1-0", out everyone))
500
+ {
501
+ try
502
+ {
503
+ lastGrantReport += " " + GrantUserObjectAccess(winsta, everyone, WINSTA_ALL_ACCESS, NO_PROPAGATE_INHERIT_ACE, "winsta-everyone");
504
+ lastGrantReport += " " + GrantUserObjectAccess(desktop, everyone, DESKTOP_ALL_ACCESS, 0, "desktop-everyone");
505
+ }
506
+ finally { LocalFree(everyone); }
507
+ }
508
+ }
509
+ return null;
510
+ }
511
+ catch (Exception error)
512
+ {
513
+ return error.Message;
514
+ }
515
+ finally
516
+ {
517
+ if (sid != IntPtr.Zero) Marshal.FreeHGlobal(sid);
518
+ }
519
+ }
520
+
232
521
  private static void ThrowLastError(string operation)
233
522
  {
234
523
  throw new Win32Exception(Marshal.GetLastWin32Error(), operation);
@@ -267,25 +556,123 @@ namespace Xeno.Security
267
556
  ThrowLastError("UpdateProcThreadAttribute(HANDLE_LIST)");
268
557
  }
269
558
 
270
- private static void ApplyLowIntegrity(IntPtr token)
559
+ private static void ApplyIntegrity(IntPtr token, string integritySid, string label_)
271
560
  {
272
- IntPtr lowSid = IntPtr.Zero;
561
+ IntPtr sid = IntPtr.Zero;
273
562
  try
274
563
  {
275
- if (!ConvertStringSidToSid("S-1-16-4096", out lowSid))
276
- ThrowLastError("ConvertStringSidToSid(low integrity)");
277
- var label = new SID_AND_ATTRIBUTES { Sid = lowSid, Attributes = SE_GROUP_INTEGRITY };
278
- UInt32 size = checked((UInt32)Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES)) + GetLengthSid(lowSid));
564
+ if (!ConvertStringSidToSid(integritySid, out sid))
565
+ ThrowLastError("ConvertStringSidToSid(" + label_ + " integrity)");
566
+ var label = new SID_AND_ATTRIBUTES { Sid = sid, Attributes = SE_GROUP_INTEGRITY };
567
+ UInt32 size = checked((UInt32)Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES)) + GetLengthSid(sid));
279
568
  if (!SetTokenInformation(token, TokenIntegrityLevel, ref label, size))
280
- ThrowLastError("SetTokenInformation(TokenIntegrityLevel)");
569
+ ThrowLastError("SetTokenInformation(TokenIntegrityLevel/" + label_ + ")");
570
+ }
571
+ finally
572
+ {
573
+ if (sid != IntPtr.Zero) LocalFree(sid);
574
+ }
575
+ }
576
+
577
+ private static void ApplyLowIntegrity(IntPtr token)
578
+ {
579
+ ApplyIntegrity(token, "S-1-16-4096", "low");
580
+ }
581
+
582
+ /// Read the token's own user SID.
583
+ ///
584
+ /// Needed because the fix under test has to name the USER, and on an elevated process the
585
+ /// user is exactly what the owner and default DACL do NOT name.
586
+ private static SecurityIdentifier TokenUserSid(IntPtr token)
587
+ {
588
+ UInt32 needed = 0;
589
+ GetTokenInformation(token, TokenUser, IntPtr.Zero, 0, out needed);
590
+ IntPtr buffer = Marshal.AllocHGlobal(checked((int)needed));
591
+ try
592
+ {
593
+ if (!GetTokenInformation(token, TokenUser, buffer, needed, out needed))
594
+ ThrowLastError("GetTokenInformation(TokenUser)");
595
+ var user = (SID_AND_ATTRIBUTES)Marshal.PtrToStructure(buffer, typeof(SID_AND_ATTRIBUTES));
596
+ return new SecurityIdentifier(user.Sid);
281
597
  }
282
598
  finally
283
599
  {
284
- if (lowSid != IntPtr.Zero) LocalFree(lowSid);
600
+ Marshal.FreeHGlobal(buffer);
601
+ }
602
+ }
603
+
604
+ /// DIAGNOSTIC: give the restricted token an owner and a default DACL that name its own USER.
605
+ ///
606
+ /// A token created from an ELEVATED parent carries an owner and a default DACL that name
607
+ /// BUILTIN\\Administrators. Every kernel object the child creates during startup inherits
608
+ /// that DACL — and in a token where Administrators is deny-only, the child cannot open what
609
+ /// it just created. That is a textbook STATUS_DLL_INIT_FAILED, and it explains the whole
610
+ /// measurement table: the two sufficient single factors both remove Administrators, and
611
+ /// forcing the integrity level back to High changes nothing.
612
+ ///
613
+ /// Returns an empty string on success so the caller can report WHY it could not apply it,
614
+ /// rather than reporting a launch failure that is really a probe failure.
615
+ private static string ApplyOwnerAndDefaultDacl(IntPtr token, bool setOwner, bool setDacl)
616
+ {
617
+ try
618
+ {
619
+ SecurityIdentifier user = TokenUserSid(token);
620
+ if (setDacl)
621
+ {
622
+ var acl = new RawAcl(GenericAclRevision, 2);
623
+ acl.InsertAce(0, new CommonAce(
624
+ AceFlags.None, AceQualifier.AccessAllowed, unchecked((int)GenericAll), user, false, null));
625
+ acl.InsertAce(1, new CommonAce(
626
+ AceFlags.None, AceQualifier.AccessAllowed, unchecked((int)GenericAll),
627
+ new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), false, null));
628
+ var raw = new byte[acl.BinaryLength];
629
+ acl.GetBinaryForm(raw, 0);
630
+ IntPtr aclBuffer = Marshal.AllocHGlobal(raw.Length);
631
+ IntPtr daclBuffer = Marshal.AllocHGlobal(IntPtr.Size);
632
+ try
633
+ {
634
+ Marshal.Copy(raw, 0, aclBuffer, raw.Length);
635
+ Marshal.WriteIntPtr(daclBuffer, aclBuffer);
636
+ if (!SetTokenInformationPtr(token, TokenDefaultDacl, daclBuffer, (UInt32)IntPtr.Size))
637
+ return "set-default-dacl-failed:" + Marshal.GetLastWin32Error();
638
+ }
639
+ finally
640
+ {
641
+ Marshal.FreeHGlobal(daclBuffer);
642
+ Marshal.FreeHGlobal(aclBuffer);
643
+ }
644
+ }
645
+ if (setOwner)
646
+ {
647
+ var sidBytes = new byte[user.BinaryLength];
648
+ user.GetBinaryForm(sidBytes, 0);
649
+ IntPtr sidBuffer = Marshal.AllocHGlobal(sidBytes.Length);
650
+ IntPtr ownerBuffer = Marshal.AllocHGlobal(IntPtr.Size);
651
+ try
652
+ {
653
+ Marshal.Copy(sidBytes, 0, sidBuffer, sidBytes.Length);
654
+ Marshal.WriteIntPtr(ownerBuffer, sidBuffer);
655
+ if (!SetTokenInformationPtr(token, TokenOwner, ownerBuffer, (UInt32)IntPtr.Size))
656
+ return "set-owner-failed:" + Marshal.GetLastWin32Error();
657
+ }
658
+ finally
659
+ {
660
+ Marshal.FreeHGlobal(ownerBuffer);
661
+ Marshal.FreeHGlobal(sidBuffer);
662
+ }
663
+ }
664
+ return "";
665
+ }
666
+ catch (Exception error)
667
+ {
668
+ return "owner-dacl-threw:" + error.Message;
285
669
  }
286
670
  }
287
671
 
288
- private static IntPtr CreateHardenedToken(bool lowIntegrity)
672
+ /// The tokenProbe argument drops ONE restriction so a failure can be attributed to it. Diagnostic
673
+ /// only — the caller passes "" unless XENO_CONTAINMENT_DIAGNOSTICS=1, so a normal launch
674
+ /// is unaffected and cannot be weakened by an environment variable alone.
675
+ private static IntPtr CreateHardenedToken(bool lowIntegrity, string tokenProbe)
289
676
  {
290
677
  IntPtr sourceToken = IntPtr.Zero;
291
678
  IntPtr restrictedToken = IntPtr.Zero;
@@ -302,18 +689,67 @@ namespace Xeno.Security
302
689
  var disabledSid = new SID_AND_ATTRIBUTES { Sid = adminSid, Attributes = 0 };
303
690
  disabledSidBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES)));
304
691
  Marshal.StructureToPtr(disabledSid, disabledSidBuffer, false);
692
+ UInt32 probeFlags = DISABLE_MAX_PRIVILEGE | LUA_TOKEN;
693
+ UInt32 disabledSidCount = 1;
694
+ // "plain" keeps CreateProcessAsUser but removes EVERY restriction, so a failure
695
+ // here means the restrictions are innocent and the call itself is implicated.
696
+ if (tokenProbe == "plain") { probeFlags = 0; disabledSidCount = 0; }
697
+ // Singles complete the table. Every PAIR fails and the empty set succeeds, so
698
+ // more than one restriction is independently sufficient; these say which.
699
+ else if (tokenProbe == "only-lua") { probeFlags = LUA_TOKEN; disabledSidCount = 0; }
700
+ else if (tokenProbe == "only-privilege-drop") { probeFlags = DISABLE_MAX_PRIVILEGE; disabledSidCount = 0; }
701
+ else if (tokenProbe == "only-disable-admin") { probeFlags = 0; disabledSidCount = 1; }
702
+ else if (tokenProbe == "no-lua") probeFlags = DISABLE_MAX_PRIVILEGE;
703
+ else if (tokenProbe == "no-privilege-drop") probeFlags = LUA_TOKEN;
704
+ else if (tokenProbe == "no-disable-admin") disabledSidCount = 0;
705
+ // The owner/default-DACL probes sit on top of the FAILING 'only-disable-admin'
706
+ // baseline, so a success is attributable to the fix and to nothing else.
707
+ else if (tokenProbe == "set-default-dacl" || tokenProbe == "set-owner" || tokenProbe == "set-both")
708
+ { probeFlags = 0; disabledSidCount = 1; }
305
709
  if (!CreateRestrictedToken(
306
710
  sourceToken,
307
- DISABLE_MAX_PRIVILEGE | LUA_TOKEN,
308
- 1,
309
- disabledSidBuffer,
711
+ probeFlags,
712
+ disabledSidCount,
713
+ disabledSidCount == 0 ? IntPtr.Zero : disabledSidBuffer,
310
714
  0,
311
715
  IntPtr.Zero,
312
716
  0,
313
717
  IntPtr.Zero,
314
718
  out restrictedToken))
315
719
  ThrowLastError("CreateRestrictedToken");
720
+ // The restricted token gets a default DACL naming its OWN user.
721
+ //
722
+ // 🔴 Without this, a hardened launch from an ELEVATED parent cannot start ANY
723
+ // process. A token created by an elevated process carries a default DACL naming
724
+ // BUILTIN\Administrators; every kernel object the child creates during startup
725
+ // inherits it, and in a token where that SID is deny-only the child cannot open
726
+ // what it just created. The loader reports STATUS_DLL_INIT_FAILED (0xC0000142),
727
+ // which reads as a missing or blocked DLL and is nothing of the kind.
728
+ //
729
+ // Proven on a hosted Windows runner, not reasoned about: with Administrators
730
+ // deny-only the launch failed 0xC0000142; adding ONLY this made it succeed;
731
+ // setting the token OWNER instead did not. The measurement is in the diagnostic
732
+ // table below, and 'fix-candidate' confirmed it with every restriction still on.
733
+ //
734
+ // ⚠️ Throws rather than continuing. A silent skip leaves a non-elevated parent
735
+ // working and an elevated one failing with an unexplained loader error — exactly
736
+ // the environment-dependent divergence that made this take four rounds to find.
737
+ string defaultDaclError = ApplyOwnerAndDefaultDacl(restrictedToken, false, true);
738
+ if (defaultDaclError != "")
739
+ throw new InvalidOperationException(
740
+ "Could not give the restricted token a default DACL naming its own user: " + defaultDaclError);
316
741
  if (lowIntegrity) ApplyLowIntegrity(restrictedToken);
742
+ // DIAGNOSTIC: keep the restrictions, put the integrity level back to High. The
743
+ // group change and the integrity drop have co-varied in every measurement so
744
+ // far; this is the only way to tell which one the child actually needs.
745
+ if (tokenProbe == "force-high-il") ApplyIntegrity(restrictedToken, "S-1-16-12288", "high");
746
+ // DIAGNOSTIC: the last standing hypothesis. 'fix-candidate' keeps every restriction
747
+ // and applies both, because that is the shape a real fix would ship — a probe that
748
+ // only works with the restrictions removed would prove nothing about the product.
749
+ if (tokenProbe == "set-default-dacl") ownerDaclError = ApplyOwnerAndDefaultDacl(restrictedToken, false, true);
750
+ else if (tokenProbe == "set-owner") ownerDaclError = ApplyOwnerAndDefaultDacl(restrictedToken, true, false);
751
+ else if (tokenProbe == "set-both" || tokenProbe == "fix-candidate")
752
+ ownerDaclError = ApplyOwnerAndDefaultDacl(restrictedToken, true, true);
317
753
  return restrictedToken;
318
754
  }
319
755
  finally
@@ -354,7 +790,7 @@ namespace Xeno.Security
354
790
  }
355
791
  }
356
792
 
357
- public static int Run(string command, string workingDirectory, bool lowIntegrity, bool restrictedToken)
793
+ public static int Run(string command, string workingDirectory, bool lowIntegrity, bool restrictedToken, string tokenProbe)
358
794
  {
359
795
  IntPtr token = IntPtr.Zero;
360
796
  IntPtr job = IntPtr.Zero;
@@ -363,7 +799,23 @@ namespace Xeno.Security
363
799
  var startup = new STARTUPINFOEX();
364
800
  try
365
801
  {
366
- if (restrictedToken) token = CreateHardenedToken(lowIntegrity);
802
+ string desktopGrantError = null;
803
+ if (restrictedToken)
804
+ {
805
+ token = CreateHardenedToken(lowIntegrity, tokenProbe);
806
+ desktopGrantError = GrantDesktopAccessForToken(token, tokenProbe);
807
+ // 🔴 Report the grant when asked, because otherwise a FAILED grant is
808
+ // invisible on every machine where the launch succeeds without it — which is
809
+ // every unelevated parent. A sensor that only speaks when something else has
810
+ // already failed cannot tell you the sensor itself is broken.
811
+ if (Environment.GetEnvironmentVariable("XENO_CONTAINMENT_DIAGNOSTICS") == "1")
812
+ {
813
+ Console.Error.WriteLine("[xeno-containment] desktop-grant="
814
+ + (desktopGrantError == null ? "ok" : "FAILED: " + desktopGrantError)
815
+ + (ownerDaclError == "" ? "" : " owner-dacl=" + ownerDaclError)
816
+ + " detail=" + lastGrantReport);
817
+ }
818
+ }
367
819
  job = CreateKillOnCloseJob();
368
820
  string shell = Environment.GetEnvironmentVariable("COMSPEC");
369
821
  if (String.IsNullOrWhiteSpace(shell))
@@ -402,7 +854,16 @@ namespace Xeno.Security
402
854
  workingDirectory,
403
855
  ref startup,
404
856
  out processInfo);
405
- if (!created) ThrowLastError(restrictedToken ? "CreateProcessAsUser" : "CreateProcess");
857
+ if (!created)
858
+ {
859
+ // A failed launch names the desktop grant when that grant also failed. Without
860
+ // this the caller sees only a Win32 code and has no way to reach the cause.
861
+ ThrowLastError(restrictedToken
862
+ ? (desktopGrantError == null
863
+ ? "CreateProcessAsUser"
864
+ : "CreateProcessAsUser (window station/desktop grant failed first: " + desktopGrantError + ")")
865
+ : "CreateProcess");
866
+ }
406
867
  if (!AssignProcessToJobObject(job, processInfo.hProcess))
407
868
  {
408
869
  TerminateProcess(processInfo.hProcess, 126);
@@ -435,4 +896,4 @@ namespace Xeno.Security
435
896
  }
436
897
  }
437
898
  }
438
- `;var $t=512*1024,Bt=744*60*60*1e3,Ft=Object.freeze(["allowedFilesystemRead","allowedFilesystemWrite","outsideFilesystemReadDenied","outsideFilesystemWriteDenied","unlistedFilesystemReadDenied","unlistedFilesystemWriteDenied","symlinkEscapeDenied","networkDefaultDeny","environmentSecretsExcluded","childProcessPolicyInherited","standardCommandLaunch","processTreeCleanup","timeoutEnforced","hostPolicyRecoveryClean","uiRestrictionsEnforced"]);var Gt=10*6e4,qt=Object.freeze({"win32-x64-wxc-exec.exe":"db0a3422be9e1b396cc1b2547c70ff16b27412438a31c10a45abf370cac86ae2","win32-arm64-wxc-exec.exe":"e430d0e4f44f616e91db684f8d825a6dc93e06a1262b8d00bcaac7522a317aab","linux-x64-lxc-exec":"1efe3f817f5ae9ba9f9f2fd59142e79b2dde7a4dd024576b0ddb635fc87edeb5","linux-arm64-lxc-exec":"fdc00ccecf362ae3ddd8ccad93fd7c8b5b1f03c68897ab05ef1c9f1d327ea3fe","darwin-arm64-mxc-exec-mac":"77c07a86f483ed91dd5be290cd77878ac0c56fe113cdb8c764e7e5201c744ad2"}),Kt=Object.freeze({"win32-x64-wxc-host-prep.exe":"531fb3cdb4b0c964908fd71b71d40961417afb399cbab72f92a25e95309a6416","win32-arm64-wxc-host-prep.exe":"3ef702332286a39153fc259310b5021e3de3c191751d7522684f6475f73af5ef"});var ur=Object.freeze({policyEnforcement:!0,restrictedIdentity:!1,lowIntegrity:!1,processTreeControl:!1,filesystemIsolation:!1,networkIsolation:!1,inheritedHandleAllowlist:!1,environmentSanitization:!0}),fr=Object.freeze({policyEnforcement:!0,restrictedIdentity:!0,lowIntegrity:!0,processTreeControl:!0,filesystemIsolation:!1,networkIsolation:!1,inheritedHandleAllowlist:!0,environmentSanitization:!0}),pr=Object.freeze({policyEnforcement:!0,restrictedIdentity:!0,lowIntegrity:!1,processTreeControl:!0,filesystemIsolation:!1,networkIsolation:!1,inheritedHandleAllowlist:!1,environmentSanitization:!0}),mr=Object.freeze({policyEnforcement:!0,restrictedIdentity:!0,lowIntegrity:!1,processTreeControl:!0,filesystemIsolation:!0,networkIsolation:!0,inheritedHandleAllowlist:!0,environmentSanitization:!0}),Ar=Object.freeze({policyEnforcement:!0,restrictedIdentity:!1,lowIntegrity:!1,processTreeControl:!1,filesystemIsolation:!1,networkIsolation:!1,inheritedHandleAllowlist:!1,environmentSanitization:!0});var Re=1,$=class extends Error{constructor(r,n){super(n);this.code=r;this.name="XenoSecureExecutionContractError"}code};function _e(e){let t=[];if(!e||typeof e!="object")return["Contract must be an object"];if(e.schemaVersion!==Re&&t.push("Unsupported schemaVersion"),e.contractId?.trim()||t.push("contractId is required"),(!e.identity?.runId?.trim()||!e.identity?.agentId?.trim())&&t.push("runId and agentId are required"),oe(e.createdAt)||t.push("createdAt must be an ISO 8601 timestamp"),e.expiresAt&&(!oe(e.expiresAt)||Date.parse(e.expiresAt)<=Date.parse(e.createdAt))&&t.push("expiresAt must be later than createdAt"),e.requestedLevel!==e.effectiveLevel&&t.push("requestedLevel and effectiveLevel must match"),e.trustMode==="untrusted"&&e.effectiveLevel!=="contained"&&t.push("Untrusted execution requires contained mode"),e.effectiveLevel==="contained"&&(e.adapter.certified||t.push("Contained mode requires a certified adapter"),e.adapter.certificationArtifactId||t.push("Contained mode requires a certification artifact"),(!e.adapter.capabilities.filesystemIsolation||e.filesystem.enforcement!=="os")&&t.push("Contained mode requires OS filesystem isolation"),(!e.adapter.capabilities.networkIsolation||e.network.enforcement!=="os")&&t.push("Contained mode requires OS network isolation"),e.network.default!=="deny"&&t.push("Contained networking must default deny")),e.network.enforcement==="none"&&!e.network.acknowledgedUnrestricted&&t.push("Unrestricted networking must be explicitly acknowledged"),e.filesystem.writeRoots.length>0&&e.profile.permissionProfile==="read-only"&&t.push("Read-only profiles cannot receive write roots"),(!Array.isArray(e.browser.readAllowedDomains)||!Array.isArray(e.browser.actAllowedDomains))&&t.push("Browser read/action domain policies are required"),(!Array.isArray(e.browser.allowedSchemes)||e.browser.allowedSchemes.some(r=>r!=="http"&&r!=="https"))&&t.push("Browser allowed schemes are invalid"),(!Array.isArray(e.browser.allowedPorts)||e.browser.allowedPorts.some(r=>!Number.isInteger(r)||r<1||r>65535))&&t.push("Browser allowed ports are invalid"),e.secrets.some(r=>!r.secretId.trim())&&t.push("Secret projections require non-empty secret IDs"),new Set(e.secrets.map(r=>r.secretId)).size!==e.secrets.length&&t.push("Secret IDs must be unique"),new Set(e.capabilityLeaseIds).size!==e.capabilityLeaseIds.length&&t.push("Capability lease IDs must be unique"),/^[a-f0-9]{64}$/.test(e.profile.fingerprint)||t.push("Profile fingerprint is invalid"),!/^[a-f0-9]{64}$/.test(e.fingerprint))t.push("Contract fingerprint is invalid");else{let r={...e};delete r.fingerprint,xe(r)!==e.fingerprint&&t.push("Contract fingerprint does not match content")}return t}function ie(e){let t=_e(e);if(t.length>0){let r=t.includes("Contract fingerprint does not match content");throw new $(r?"SECURITY_CONTRACT_FINGERPRINT_MISMATCH":"SECURITY_CONTRACT_INVALID",t.join("; "))}}function xe(e){return Ce("sha256").update(JSON.stringify(B(e))).digest("hex")}function B(e){return Array.isArray(e)?e.map(B):!e||typeof e!="object"?e:Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>[t,B(r)]))}function oe(e){return typeof e=="string"&&e.includes("T")&&Number.isFinite(Date.parse(e))}var Oe=/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$/,ae=1048576;function ue(e){(!e||typeof e!="object")&&I("Automation request must be an object"),e.protocolVersion!==1&&I("Unsupported automation protocol version"),E(e.operationId,"operationId"),E(e.idempotencyKey,"idempotencyKey"),E(e.capabilityLeaseId,"capabilityLeaseId"),E(e.governingToolName,"governingToolName"),(!Number.isSafeInteger(e.expectedLeaseVersion)||e.expectedLeaseVersion<1)&&I("expectedLeaseVersion must be a positive safe integer"),me(e.requestedAt)||I("requestedAt must be an ISO 8601 timestamp"),V(e.operation)||I(`Unsupported automation operation: ${e.operation}`),(!e.parameters||typeof e.parameters!="object"||Array.isArray(e.parameters))&&I("parameters must be a JSON object");let t;try{t=Buffer.byteLength(JSON.stringify(e.parameters),"utf8")}catch(r){throw new a("AUTOMATION_REQUEST_INVALID","parameters must be serializable JSON",void 0,{cause:r})}if(t>ae&&I(`parameters exceed ${ae} bytes`),E(e.identity?.runId,"identity.runId"),E(e.identity?.agentId,"identity.agentId"),ie(e.executionContract),Ne(e),!e.executionContract.capabilityLeaseIds.includes(e.capabilityLeaseId))throw new a("AUTOMATION_CONTRACT_INVALID",`Capability lease ${e.capabilityLeaseId} is not bound to the execution contract`);if(e.executionContract.expiresAt&&Date.parse(e.executionContract.expiresAt)<=Date.now())throw new a("AUTOMATION_CONTRACT_EXPIRED","Execution contract has expired")}function R(e){(!e||typeof e!="object")&&m("Adapter manifest must be an object"),e.protocolVersion!==1&&m("Adapter protocol version is unsupported"),C(e.adapterId,"adapterId"),C(e.adapterVersion,"adapterVersion"),C(e.platform,"platform"),C(e.architecture,"architecture"),e.targetBinding!=="atomic-preflight"&&m("Adapter must implement atomic preflight target binding"),(!Array.isArray(e.operations)||e.operations.length===0)&&m("Adapter must declare operations");let t=new Set;for(let r of e.operations)V(r)||m(`Adapter declares unknown operation ${r}`),t.has(r)&&m(`Adapter declares duplicate operation ${r}`),t.add(r);e.certified&&!e.certificationArtifactId&&m("A certified automation adapter requires a certification artifact"),Array.isArray(e.limitations)||m("Adapter limitations must be an array"),e.operations.some(r=>r.startsWith("browser."))&&(!e.policyEnforcement.domain||!e.policyEnforcement.scheme||!e.policyEnforcement.port)&&m("Browser adapters must enforce domain, scheme, and port policy"),e.operations.some(r=>r.startsWith("computer."))&&!e.supports.immediateStop&&m("Computer-use adapters must support immediate stop")}function H(e,t,r){let n=h(e.operation);if(!t.operations.includes(e.operation))throw new a("AUTOMATION_OPERATION_UNSUPPORTED",`Adapter ${t.adapterId} does not support ${e.operation}`);if(n.surface==="browser"){let o=e.executionContract.browser.mode;if(o==="none"||n.effect==="act"&&o!=="act")throw new a("AUTOMATION_POLICY_DENIED",`Execution contract denies ${e.operation}`);if(Pe(e,r,n.effect==="act"),e.operation==="browser.download"&&e.executionContract.browser.downloads==="deny")throw new a("AUTOMATION_POLICY_DENIED","Execution contract denies browser downloads");if(e.operation==="browser.upload"&&e.executionContract.browser.uploads==="deny")throw new a("AUTOMATION_POLICY_DENIED","Execution contract denies browser uploads");if(e.operation.startsWith("browser.record.")&&e.executionContract.browser.recording!=="bounded")throw new a("AUTOMATION_POLICY_DENIED","Execution contract denies browser recording")}else{let o=e.executionContract.computer.mode;if(o==="none"||n.effect==="act"&&o!=="act")throw new a("AUTOMATION_POLICY_DENIED",`Execution contract denies ${e.operation}`);let i=e.executionContract.computer.allowedApplications,d=e.operation==="computer.launch"?Le(e):r.applicationId??e.declaredTarget?.applicationId;if((e.operation==="computer.launch"||i.length>0)&&(!d||!i.includes(d)))throw new a("AUTOMATION_POLICY_DENIED",`Application ${d??"<unknown>"} is not allowed`)}}function fe(e,t){let r=h(e.operation),n=r.surface==="browser"?r.effect==="act"?"browser-act":"browser-read":r.effect==="act"?"computer-act":"computer-observe";return{subject:{runId:e.identity.runId,agentId:e.identity.agentId,...e.identity.turnId?{turnId:e.identity.turnId}:{},toolName:e.governingToolName,operationId:e.operationId},kind:n,operation:e.operation,...se(e,t)?{resource:se(e,t)}:{},...de(t)?{destination:de(t)}:{}}}function se(e,t){return e.declaredTarget?.resource??Xe(t)}function pe(e){let t=h(e.operation).evidence,r=e.evidencePolicy??{},n=F(t.before,r.before),o=F(t.after,r.after),i=F(t.recording,r.recording),d=r.retainUntil;return d&&!me(d)&&I("evidencePolicy.retainUntil must be an ISO 8601 timestamp"),{before:n,after:o,recording:i,sensitivity:r.sensitivity??"confidential",...d?{retainUntil:d}:{},...r.legalHold!==void 0?{legalHold:r.legalHold}:{}}}function Ne(e){let t=e.executionContract.identity,r=["runId","agentId","sessionId","turnId","taskId","workspaceId"];for(let n of r){let o=t[n],i=e.identity[n];if(o!==void 0&&o!==i)throw new a("AUTOMATION_IDENTITY_MISMATCH",`Automation identity ${n} does not match the execution contract`)}}function Pe(e,t,r){let n=t.url??t.origin??e.declaredTarget?.url??e.declaredTarget?.origin;if(!n){if(["browser.tabs.list","browser.wait"].includes(e.operation))return;throw new a("AUTOMATION_PREFLIGHT_INVALID","Browser preflight did not bind an effective URL")}let o;try{o=new URL(n)}catch{throw new a("AUTOMATION_POLICY_DENIED","Browser target URL is invalid")}if(o.username||o.password)throw new a("AUTOMATION_POLICY_DENIED","Browser target URLs cannot contain credentials");let i=o.protocol.replace(/:$/,"");i!=="http"&&i!=="https"&&w(`Browser scheme ${o.protocol} is not supported`);let d=i,c=o.hostname.toLowerCase().replace(/\.$/,""),l=o.port?Number(o.port):d==="https"?443:80,s=e.executionContract.browser,u=De(c);if(le(c,s.deniedDomains)&&w(`Browser domain ${c} is denied`),ce(o,e.executionContract.network.denyDestinations)&&w(`Network policy explicitly denies ${d}://${c}:${l}`),u&&s.allowLoopbackDevelopment)return;s.allowedSchemes.includes(d)||w(`Browser scheme ${o.protocol} is not allowed`),s.allowedPorts.includes(l)||w(`Browser port ${l} is not allowed`);let p=r?s.actAllowedDomains:s.readAllowedDomains;le(c,p)||w(`Browser domain ${c} is outside the ${r?"action":"read"} allowlist`),e.executionContract.network.default==="deny"&&(ce(o,e.executionContract.network.allowDestinations)||w(`Network policy does not allow ${d}://${c}:${l}`))}function ce(e,t){let r=e.protocol.replace(/:$/,""),n=e.hostname.toLowerCase().replace(/\.$/,""),o=e.port?Number(e.port):r==="https"?443:80;return t.some(i=>{let d=i.scheme?.replace(/^custom:/,"");return i.host===n&&(i.port===void 0||i.port===o)&&(d===void 0||d===r)})}function Xe(e){return e.resource??e.tabId??e.pageId??e.deviceId??e.applicationId}function de(e){let t=e.origin??e.url;if(!t)return e.domain;try{return new URL(t).origin}catch{return t}}function Le(e){let t=e.parameters.target,r=t&&typeof t=="object"&&!Array.isArray(t)?t.app_id:void 0,n=e.parameters.applicationId??r??e.declaredTarget?.applicationId;return typeof n=="string"&&n.length>0?n:void 0}function le(e,t){return t.some(r=>{let n=r.toLowerCase();if(n.startsWith(".")){let o=n.slice(1);return e===o||e.endsWith(`.${o}`)}return e===n})}function De(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function F(e,t){let r={disabled:0,optional:1,required:2};return!t||r[t]<=r[e]?e:t}function E(e,t){(typeof e!="string"||!Oe.test(e))&&I(`${t} is invalid`)}function C(e,t){(typeof e!="string"||e.trim().length===0||e.length>256)&&m(`${t} is invalid`)}function me(e){return typeof e=="string"&&e.includes("T")&&Number.isFinite(Date.parse(e))}function w(e){throw new a("AUTOMATION_POLICY_DENIED",e)}function I(e){throw new a("AUTOMATION_REQUEST_INVALID",e)}function m(e){throw new a("AUTOMATION_OPERATION_UNSUPPORTED",e)}import{createHash as Ue}from"node:crypto";import{createHash as ke}from"node:crypto";function _(e){return{algorithm:"sha256",value:ke("sha256").update(e).digest("hex")}}var Me="[\\u0000-\\u001f\\u007f]",Xr=new RegExp(Me);var x=class extends Error{constructor(r,n,o,i){super(n,i);this.code=r;this.detail=o;this.name="XenoArtifactRepositoryError"}code;detail};var z=32*1024*1024,Ve=1024*1024*1024,$e=/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$/;function W(e){let r=(e.now??(()=>new Date().toISOString()))(),n=new Set;return e.evidence.map((o,i)=>{if(Fe(o),n.has(o.evidenceId))throw new a("AUTOMATION_EVIDENCE_INVALID",`Duplicate evidence ID ${o.evidenceId}`);n.add(o.evidenceId);let d=Be(o),c=Ue("sha256").update(`${e.request.operationId}\0${o.evidenceId}\0${d.hash.value}`).digest("hex").slice(0,32);return{schemaVersion:1,artifactId:`automation_${c}`,revision:1,kind:o.kind,title:o.title,...o.description?{description:o.description}:{},state:"draft",createdAt:r,mediaType:o.mediaType,sensitivity:o.sensitivity??e.policy.sensitivity,identity:{...e.request.identity},content:d,provenance:{producer:{kind:"tool",id:e.request.governingToolName,displayName:e.manifest.adapterId,profileFingerprint:e.request.executionContract.profile.fingerprint},operationId:e.request.operationId,executionContractFingerprint:e.request.executionContract.fingerprint,capabilityLeaseIds:[e.request.capabilityLeaseId],attributes:{automationProtocolVersion:e.request.protocolVersion,automationOperation:e.request.operation,automationEvidenceId:o.evidenceId,automationEvidencePhase:o.phase,adapterId:e.manifest.adapterId,adapterVersion:e.manifest.adapterVersion,evidenceIndex:i}},...o.anchors?{anchors:structuredClone(o.anchors)}:{},...e.policy.retainUntil||e.policy.legalHold!==void 0?{retention:{...e.policy.retainUntil?{retainUntil:e.policy.retainUntil}:{},...e.policy.legalHold!==void 0?{legalHold:e.policy.legalHold}:{}}}:{},extensions:{...o.extensions??{},xenoAutomation:{phase:o.phase,adapter:e.manifest.adapterId,certifiedAdapter:e.manifest.certified}}}})}async function J(e,t){if(!e)return t.map(n=>structuredClone(n));let r=[];for(let n of t)try{let o=await e.create(n);r.push(o.artifact)}catch(o){if(o instanceof x&&o.code==="ARTIFACT_ALREADY_EXISTS"){let i=await e.require(n.artifactId,n.revision);if(i.artifact.content.hash.value===n.content.hash.value){r.push(i.artifact);continue}}throw new a("AUTOMATION_EVIDENCE_PERSISTENCE_FAILED",`Failed to persist automation evidence ${n.artifactId}`,{artifactId:n.artifactId},{cause:o})}return r}function O(e,t,r){if(t[r]==="required"&&!e.some(n=>n.phase===r))throw new a("AUTOMATION_EVIDENCE_REQUIRED",`Automation operation requires ${r} evidence before it can be trusted`)}function Be(e){if(e.content.type==="text"){let t=Buffer.byteLength(e.content.text,"utf8");return Ae(t),{hash:_(e.content.text),sizeBytes:t,storage:{type:"inline",text:e.content.text},encoding:"utf8",...e.redactedPreview?{redactedPreview:e.redactedPreview}:{}}}if(e.content.type==="base64"){let t=He(e.content.base64);return Ae(t.byteLength),{hash:_(t),sizeBytes:t.byteLength,storage:{type:"inline",base64:e.content.base64},encoding:"base64",...e.redactedPreview?{redactedPreview:e.redactedPreview}:{}}}if(!Number.isSafeInteger(e.content.sizeBytes)||e.content.sizeBytes<0||e.content.sizeBytes>Ve)throw new a("AUTOMATION_EVIDENCE_INVALID","Referenced evidence size is invalid");if(!e.content.hash?.algorithm||!e.content.hash.value)throw new a("AUTOMATION_EVIDENCE_INVALID","Referenced evidence requires a content hash");if(e.content.hash.algorithm==="sha256"&&!/^[a-f0-9]{64}$/.test(e.content.hash.value))throw new a("AUTOMATION_EVIDENCE_INVALID","Referenced evidence SHA-256 is invalid");return{hash:{...e.content.hash},sizeBytes:e.content.sizeBytes,storage:structuredClone(e.content.storage),...e.content.encoding?{encoding:e.content.encoding}:{},...e.redactedPreview?{redactedPreview:e.redactedPreview}:{}}}function Fe(e){(!e||typeof e!="object")&&g("Evidence must be an object"),$e.test(e.evidenceId)||g("Evidence ID is invalid"),["before","action","after","recording","diagnostic"].includes(e.phase)||g("Evidence phase is invalid"),(!e.kind||!e.title?.trim()||e.title.length>512)&&g("Evidence kind and title are required"),/^[\w!#$&^_.+-]+\/[\w!#$&^_.+-]+(?:;.*)?$/.test(e.mediaType)||g("Evidence media type is invalid")}function He(e){(e.length===0||e.length>Math.ceil(z/3)*4+4)&&g("Inline base64 evidence is empty or too large"),(!/^[A-Za-z0-9+/]*={0,2}$/.test(e)||e.length%4!==0)&&g("Inline evidence is not canonical base64");let t=Buffer.from(e,"base64");return t.toString("base64")!==e&&g("Inline evidence is not canonical base64"),t}function Ae(e){e>z&&g(`Inline evidence exceeds ${z} bytes`)}function g(e){throw new a("AUTOMATION_EVIDENCE_INVALID",e)}import{createHash as je}from"node:crypto";var he=3e4,ze=1e3,Ie=class{adapter;leaseAuthority;artifactRepository;now;executions=new Map;active=new Map;constructor(t){this.adapter=t.adapter,this.leaseAuthority=t.leaseAuthority,this.artifactRepository=t.artifactRepository,this.now=t.now??(()=>new Date().toISOString())}execute(t,r){let n=Ke(t),o=this.executions.get(t.operationId);if(o){if(o.fingerprint!==n)throw new a("AUTOMATION_OPERATION_CONFLICT",`Operation ${t.operationId} was already submitted with different authority or parameters`);return o.promise}let i=new AbortController,d=Ye(r,i);this.active.set(t.operationId,i);let c=this.executeFresh(t,i.signal).finally(()=>{d(),this.active.delete(t.operationId)});return this.executions.set(t.operationId,{fingerprint:n,promise:c}),this.trimIdempotencyRecords(),c}async stop(t,r="human-stop"){let n=this.active.get(t);return n?(n.abort(new Error(r)),await this.adapter.stop?.(t,r),!0):!1}async executeFresh(t,r){ue(t),q(r);let n=await this.adapter.manifest();R(n);let o=h(t.operation),i=pe(t),d=this.now(),c=await this.adapter.preflight(t,r);We(c,this.now()),H(t,n,c.observedTarget),q(r);let l=c.evidence??[];O(l,i,"before");let s=await J(this.artifactRepository,W({request:t,manifest:n,policy:i,evidence:l,now:this.now}));if(q(r),Date.parse(c.expiresAt)<=Date.parse(this.now()))throw new a("AUTOMATION_PREFLIGHT_INVALID","Automation preflight expired before authority consumption");let u=fe(t,c.observedTarget),p=await this.leaseAuthority.consume(t.capabilityLeaseId,t.expectedLeaseVersion,u),v={contractFingerprint:t.executionContract.fingerprint,lease:p,capabilityUse:u},f;try{f=await this.adapter.execute(t,c,v,r)}catch(A){return G({request:t,manifest:n,descriptorEffect:o.effect,target:c.observedTarget,lease:p,artifacts:s,startedAt:d,completedAt:this.now(),status:r.aborted?"cancelled":"error",code:r.aborted?"AUTOMATION_CANCELLED":"AUTOMATION_ADAPTER_ERROR",message:r.aborted?"Automation operation was stopped":Ze(A)})}Je(f);let ee=Ge(c.observedTarget,f.observedTarget),N;try{H(t,n,f.observedTarget)}catch(A){N=A instanceof Error?A:new Error(String(A))}let S=f.evidence??[];qe(l,S);let te=[],P;try{O(S,i,"after"),O([...l,...S],i,"recording"),te=await J(this.artifactRepository,W({request:t,manifest:n,policy:i,evidence:S,now:this.now}))}catch(A){P=A instanceof Error?A:new Error(String(A))}let X=[...s,...te];return ee||N?G({request:t,manifest:n,descriptorEffect:o.effect,target:f.observedTarget,lease:p,artifacts:X,startedAt:f.startedAt,completedAt:f.completedAt,status:"error",code:"AUTOMATION_TARGET_CHANGED",message:ee??N.message}):P?G({request:t,manifest:n,descriptorEffect:o.effect,target:f.observedTarget,lease:p,artifacts:X,startedAt:f.startedAt,completedAt:f.completedAt,status:"evidence-incomplete",code:"AUTOMATION_EVIDENCE_INCOMPLETE",message:P.message}):{operationId:t.operationId,status:f.status,effect:o.effect,startedAt:f.startedAt,completedAt:f.completedAt,adapter:ge(n),target:structuredClone(f.observedTarget),...f.data!==void 0?{data:structuredClone(f.data)}:{},artifacts:X,lease:be(p),...f.error?{error:{...f.error}}:{}}}trimIdempotencyRecords(){for(;this.executions.size>ze;){let t=this.executions.keys().next().value;if(!t||this.active.has(t))break;this.executions.delete(t)}}};function We(e,t){if(!e||typeof e!="object"||!e.token?.trim())throw new a("AUTOMATION_PREFLIGHT_INVALID","Adapter returned an invalid preflight token");let r=Date.parse(e.preparedAt),n=Date.parse(e.expiresAt),o=Date.parse(t);if(!Number.isFinite(r)||!Number.isFinite(n)||n<=r||n<=o)throw new a("AUTOMATION_PREFLIGHT_INVALID","Adapter returned an expired or invalid preflight window");if(n-r>he)throw new a("AUTOMATION_PREFLIGHT_INVALID",`Preflight TTL exceeds ${he} ms`);if(!e.observedTarget||typeof e.observedTarget!="object")throw new a("AUTOMATION_PREFLIGHT_INVALID","Adapter did not bind an observed target")}function Je(e){if(!e||typeof e!="object")throw new a("AUTOMATION_REQUEST_INVALID","Adapter returned no result");if(!["ok","denied","cancelled","error"].includes(e.status))throw new a("AUTOMATION_REQUEST_INVALID","Adapter returned an invalid status");if(!Number.isFinite(Date.parse(e.startedAt))||!Number.isFinite(Date.parse(e.completedAt)))throw new a("AUTOMATION_REQUEST_INVALID","Adapter result timestamps are invalid");if(Date.parse(e.completedAt)<Date.parse(e.startedAt))throw new a("AUTOMATION_REQUEST_INVALID","Adapter completion precedes its start");if(!e.observedTarget||typeof e.observedTarget!="object")throw new a("AUTOMATION_REQUEST_INVALID","Adapter result has no observed target")}function Ge(e,t){let r=["tabId","deviceId","displayId"];for(let n of r)if(e[n]!==void 0&&e[n]!==t[n])return`Adapter changed bound ${n} between preflight and execution`}function qe(e,t){let r=new Set(e.map(n=>n.evidenceId));for(let n of t){if(r.has(n.evidenceId))throw new a("AUTOMATION_EVIDENCE_INVALID",`Duplicate evidence ID ${n.evidenceId}`);r.add(n.evidenceId)}}function G(e){return{operationId:e.request.operationId,status:e.status,effect:e.descriptorEffect,startedAt:e.startedAt,completedAt:e.completedAt,adapter:ge(e.manifest),target:structuredClone(e.target),artifacts:e.artifacts,lease:be(e.lease),error:{code:e.code,message:e.message}}}function ge(e){return{adapterId:e.adapterId,adapterVersion:e.adapterVersion,platform:e.platform,architecture:e.architecture}}function be(e){return{leaseId:e.leaseId,version:e.version,state:e.state,useCount:e.useCount}}function Ke(e){return je("sha256").update(JSON.stringify(K(e))).digest("hex")}function K(e){return Array.isArray(e)?e.map(K):!e||typeof e!="object"?e:Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>[t,K(r)]))}function Ye(e,t){if(!e)return()=>{};let r=()=>t.abort(e.reason);return e.aborted?r():e.addEventListener("abort",r,{once:!0}),()=>e.removeEventListener("abort",r)}function q(e){if(e.aborted)throw new a("AUTOMATION_CANCELLED","Automation operation was stopped before dispatch")}function Ze(e){return e instanceof Error&&e.message.slice(0,1024)||"Automation adapter failed"}function Qe(e,t=()=>new Date().toISOString()){let r=[];et(r,"manifest.valid",()=>R(e));let n=new Set(e.operations);return y(r,n,e.supports.consoleInspection,"browser.console.read","console inspection"),y(r,n,e.supports.networkInspection,"browser.network.read","network inspection"),y(r,n,e.supports.storageInspection,"browser.storage.read","storage inspection"),y(r,n,e.supports.pageErrorInspection,"browser.page-errors.read","page-error inspection"),y(r,n,e.supports.recordings,"browser.record.start","recording start"),y(r,n,e.supports.recordings,"browser.record.stop","recording stop"),n.has("browser.upload")&&b(r,"policy.upload",e.policyEnforcement.upload,"Upload policy is enforced"),n.has("browser.download")&&b(r,"policy.download",e.policyEnforcement.download,"Download policy is enforced"),[...n].some(o=>o.startsWith("browser."))&&(b(r,"policy.redirect",e.policyEnforcement.redirect,"Redirect policy is enforced"),b(r,"control.handback",e.supports.deterministicHandback,"Deterministic hand-back is supported")),[...n].some(o=>o.startsWith("computer."))&&(b(r,"control.stop",e.supports.immediateStop,"Immediate human stop is supported"),b(r,"privacy.redaction",e.supports.sensitiveRegionRedaction,"Sensitive-region redaction is supported")),b(r,"certification.binding",!e.certified||!!e.certificationArtifactId,e.certified?"Certification artifact is bound":"Adapter does not claim certification"),{protocolVersion:1,adapter:{adapterId:e.adapterId,adapterVersion:e.adapterVersion,platform:e.platform,architecture:e.architecture},generatedAt:t(),passed:r.every(o=>o.status==="pass"),checks:r}}function on(e){let r=Qe(e).checks.filter(n=>n.status==="fail");if(r.length>0)throw new a("AUTOMATION_OPERATION_UNSUPPORTED",r.map(n=>`${n.id}: ${n.message}`).join("; "))}function y(e,t,r,n,o){let i=t.has(n);b(e,`capability.${n}`,r===i,r===i?`${o} declaration matches the operation catalog`:`${o} declaration does not match ${n}`)}function et(e,t,r){try{r(),e.push({id:t,status:"pass",message:"Manifest satisfies the protocol contract"})}catch(n){e.push({id:t,status:"fail",message:n instanceof Error?n.message:String(n)})}}function b(e,t,r,n){e.push({id:t,status:r?"pass":"fail",message:n})}var tt=6e4,rt=48*1024*1024,we=class{endpoint;token;timeoutMs;maxResponseBytes;fetchImpl;constructor(t){if(this.endpoint=nt(t.baseUrl),this.token=ot(t.token),this.timeoutMs=Ee(t.timeoutMs??tt,1e3,3e5,"timeoutMs"),this.maxResponseBytes=Ee(t.maxResponseBytes??rt,1024,128*1024*1024,"maxResponseBytes"),this.fetchImpl=t.fetch??globalThis.fetch,typeof this.fetchImpl!="function")throw new a("AUTOMATION_TRANSPORT_ERROR","A Fetch API implementation is required")}manifest(){return this.request("manifest","GET")}preflight(t,r){return this.request("preflight","POST",t,r)}execute(t,r,n,o){return this.request("execute","POST",{request:t,preflight:r,grant:n},o)}async stop(t,r){await this.request("stop","POST",{operationId:t,reason:r.slice(0,512)})}async request(t,r,n,o){let i=new AbortController,d=st(o,i),c=setTimeout(()=>i.abort(new Error("automation transport timeout")),this.timeoutMs);c.unref?.();try{let l=new URL(t,this.endpoint),s=await this.fetchImpl(l,{method:r,redirect:"error",cache:"no-store",credentials:"omit",headers:{authorization:`Bearer ${this.token}`,accept:"application/json",...r==="POST"?{"content-type":"application/json"}:{}},...r==="POST"?{body:JSON.stringify(n??{})}:{},signal:i.signal}),u=await it(s,this.maxResponseBytes);if(!s.ok){let p=at(u);throw new a("AUTOMATION_TRANSPORT_ERROR",`XENO Browser rejected ${t}: ${p.message}`,{status:s.status,route:t,adapterCode:p.code})}if(!Y(u)||u.ok!==!0||!("result"in u))throw new a("AUTOMATION_RESPONSE_INVALID",`XENO Browser returned an invalid ${t} envelope`);return u.result}catch(l){if(l instanceof a)throw l;let s=o?.aborted;throw new a(s?"AUTOMATION_CANCELLED":"AUTOMATION_TRANSPORT_ERROR",s?"Automation transport was stopped":`XENO Browser ${t} transport failed`,{route:t},{cause:l})}finally{clearTimeout(c),d()}}};function nt(e){let t;try{t=new URL(e)}catch(n){throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser base URL is invalid",void 0,{cause:n})}if(t.protocol!=="http:"&&t.protocol!=="https:")throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser transport requires HTTP(S)");if(t.username||t.password||t.search||t.hash)throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser base URL cannot contain credentials, query, or fragment");let r=t.hostname.toLowerCase().replace(/^\[|\]$/g,"").replace(/\.$/,"");if(r!=="localhost"&&r!=="127.0.0.1"&&r!=="::1")throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser transport must use a loopback host");if(!t.port)throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser transport requires an explicit port");return t.pathname="/v1/automation/",t}function ot(e){if(typeof e!="string"||e.length<32||e.length>512||/\s/.test(e))throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser session token is invalid");return e}async function it(e,t){let r=Number(e.headers.get("content-length"));if(Number.isFinite(r)&&r>t)throw new a("AUTOMATION_RESPONSE_INVALID",`XENO Browser response exceeds ${t} bytes`);if(e.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase()!=="application/json")throw new a("AUTOMATION_RESPONSE_INVALID","XENO Browser response is not application/json");if(!e.body)throw new a("AUTOMATION_RESPONSE_INVALID","XENO Browser response body is missing");let o=e.body.getReader(),i=[],d=0;for(;;){let{done:s,value:u}=await o.read();if(s)break;if(d+=u.byteLength,d>t)throw await o.cancel("response too large"),new a("AUTOMATION_RESPONSE_INVALID",`XENO Browser response exceeds ${t} bytes`);i.push(u)}let c=new Uint8Array(d),l=0;for(let s of i)c.set(s,l),l+=s.byteLength;try{return JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(c))}catch(s){throw new a("AUTOMATION_RESPONSE_INVALID","XENO Browser response contains invalid JSON",void 0,{cause:s})}}function at(e){return Y(e)&&Y(e.error)?{code:typeof e.error.code=="string"?e.error.code.slice(0,128):"UNKNOWN",message:typeof e.error.message=="string"?e.error.message.slice(0,1024):"request failed"}:{code:"UNKNOWN",message:"request failed"}}function st(e,t){if(!e)return()=>{};let r=()=>t.abort(e.reason);return e.aborted?r():e.addEventListener("abort",r,{once:!0}),()=>e.removeEventListener("abort",r)}function Ee(e,t,r,n){if(!Number.isSafeInteger(e)||e<t||e>r)throw new a("AUTOMATION_TRANSPORT_ERROR",`${n} must be an integer from ${t} to ${r}`);return e}function Y(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}import{createHash as ct,randomUUID as dt}from"node:crypto";var lt=8*1024*1024,ut=4;function un(e){return Tt(e.operations??U).map(r=>ft(r,e.runtime))}function ft(e,t){return{definition:{name:e,description:It(e),input_schema:pt(e)},projectPolicyInput(r){let n=wt(e,r),o=bt(e,r);return{observabilityInput:n,permissionInput:o,permissionPreview:Et(e,r),approvalKey:`xeno-automation:${e}:${St(r)}`,riskLevel:gt(e)}},async execute(r,n){let o=n?.authorization;if(!o||o.toolName!==e)return{success:!1,output:"",error:"Governed automation requires a host-issued authorization receipt",errorCode:"AUTOMATION_AUTHORIZATION_RECEIPT_REQUIRED",retryable:!1};let i=n.operationId??`automation_${dt()}`,d=Q(e,r);n.reportProgress?.({activity:"state",message:`Authorizing ${e}`});try{let c=await t.execute({operation:e,governingToolName:e,operationId:i,idempotencyKey:i,parameters:structuredClone(r),...d?{declaredTarget:d}:{},authorization:o,...n.signal?{signal:n.signal}:{},...n.reportProgress?{reportProgress:n.reportProgress}:{}}),l=c.status==="ok";return{success:l,output:JSON.stringify(yt(c)),...l?{}:{error:c.error?.message??`Governed automation ended with ${c.status}`,errorCode:c.error?.code??`AUTOMATION_${c.status.toUpperCase().replaceAll("-","_")}`},assistantContent:vt(c),evidence:c.artifacts.map(s=>({id:s.artifactId,kind:"artifact",status:c.status==="evidence-incomplete"?"failed":"verified",observedAt:s.updatedAt??s.createdAt,operationId:i,detail:{artifact_kind:s.kind,revision:s.revision,sensitivity:s.sensitivity}})),retryable:c.error?.retryable??!1}}catch(c){let l=n.signal?.aborted===!0;return{success:!1,output:"",error:l?"Governed automation was stopped":Ct(c),errorCode:l?"AUTOMATION_CANCELLED":Rt(c),retryable:!l}}}}}function pt(e){let t=mt(e),r=At(e);return{type:"object",properties:t,...r.length>0?{required:r}:{},...e==="browser.locate"?{oneOf:[{required:["selector"]},{required:["text"]}]}:{},additionalProperties:!1}}function mt(e){let t=(d,c=8192)=>({type:"string",minLength:1,maxLength:c,description:d}),r={type:"number"},n={type:"boolean"},o={type:"object",properties:{x:r,y:r},required:["x","y"],additionalProperties:!1},i={deviceId:t("Target xeno-use device ID.",256),applicationId:t("Expected or launch-target application ID.",512),displayId:t("Target display ID.",256)};switch(e){case"browser.navigate":return{url:t("Destination URL."),waitUntil:{enum:["load","none"]},tabId:t("Expected active tab ID. Hosts with multiple visible tabs should require this.",256)};case"browser.wait":return{until:{enum:["load","ms"]},value:{type:"integer",minimum:0,maximum:6e4}};case"browser.snapshot":return{mode:{enum:["text","html","markdown","a11y"]},tabId:t("Expected active tab ID.",256)};case"browser.screenshot":return{tabId:t("Expected active tab ID.",256)};case"browser.locate":return{selector:t("CSS selector."),text:t("Visible text to locate.")};case"browser.click":return{selector:t("CSS selector returned by browser.snapshot or browser.locate."),tabId:t("Expected active tab ID.",256)};case"browser.type":return{selector:t("CSS selector."),text:{type:"string",maxLength:65536},clear:n,submit:n,tabId:t("Expected active tab ID.",256)};case"browser.key":return{combo:t("Key combo such as Control+a or Enter.",256),tabId:t("Expected active tab ID.",256)};case"browser.select":return{selector:t("CSS selector."),value:t("Option value."),tabId:t("Expected active tab ID.",256)};case"browser.scroll":return{selector:t("Optional CSS selector."),dx:r,dy:r,tabId:t("Expected active tab ID.",256)};case"browser.tabs.open":return{url:t("URL to open in an isolated browser tab.")};case"browser.tabs.close":return{tabId:t("Tab ID to close.",256)};case"browser.console.read":case"browser.network.read":case"browser.page-errors.read":return{limit:{type:"integer",minimum:1,maximum:1e3},clear:n,tabId:t("Expected active tab ID.",256)};case"browser.storage.read":return{tabId:t("Expected active tab ID.",256)};case"browser.upload":return{selector:t("File input or drop-target selector."),backendNodeId:{type:"integer",minimum:1},hostPaths:{type:"array",items:t("Host file path.",32768),minItems:1,maxItems:64},drop:n,tabId:t("Expected active tab ID.",256)};case"browser.download":return{toPath:t("Approved destination path.",32768),trigger:{type:"object",properties:{url:t("Download URL."),selector:t("Download trigger selector.")},oneOf:[{required:["url"]},{required:["selector"]}],additionalProperties:!1},tabId:t("Expected active tab ID.",256)};case"browser.record.start":return{maxDurationMs:{type:"integer",minimum:1e3,maximum:6e4},intervalMs:{type:"integer",minimum:100,maximum:5e3},tabId:t("Expected active tab ID.",256)};case"browser.record.stop":return{tabId:t("Expected active tab ID.",256)};case"computer.observe":case"computer.screenshot":case"computer.window-state":return i;case"computer.point":return{...i,point:o,durationMs:{type:"integer",minimum:0,maximum:6e4}};case"computer.click":return{...i,point:o,button:{enum:["left","right","middle"]},modifiers:ht()};case"computer.double-click":case"computer.right-click":return{...i,point:o};case"computer.drag":return{...i,from:o,to:o,durationMs:{type:"integer",minimum:0,maximum:6e4}};case"computer.type":return{...i,text:{type:"string",maxLength:65536}};case"computer.key":return{...i,combo:t("Key combo such as Control+a or Enter.",256)};case"computer.scroll":return{...i,at:o,delta:o};case"computer.wait":return{...i,milliseconds:{type:"integer",minimum:0,maximum:3e5}};case"computer.launch":return{...i,applicationId:t("Explicitly allowlisted application ID.",512)};case"browser.back":case"browser.forward":case"browser.reload":return{tabId:t("Expected active tab ID.",256)};case"browser.tabs.list":return{}}}function At(e){switch(e){case"browser.navigate":case"browser.tabs.open":return["url"];case"browser.click":return["selector"];case"browser.type":return["selector","text"];case"browser.key":return["combo"];case"browser.select":return["selector","value"];case"browser.upload":return["hostPaths"];case"browser.download":return["toPath","trigger"];case"computer.point":case"computer.click":case"computer.double-click":case"computer.right-click":return["point"];case"computer.drag":return["from","to"];case"computer.type":return["text"];case"computer.key":return["combo"];case"computer.scroll":return["at","delta"];case"computer.launch":return["applicationId"];default:return[]}}function ht(){return{type:"object",properties:{shift:{type:"boolean"},ctrl:{type:"boolean"},alt:{type:"boolean"},meta:{type:"boolean"}},additionalProperties:!1}}function It(e){let t=h(e),r=e.split(".").slice(1).join(" ");return`${t.effect==="act"?"Act on":"Inspect"} the ${t.surface} using governed ${r} automation. The host requires policy approval, an exact capability lease, target-bound preflight, and durable evidence.`}function gt(e){return h(e).effect==="observe"?e==="browser.navigate"||e==="browser.tabs.open"?"medium":"low":["browser.type","browser.upload","browser.download","computer.type","computer.key","computer.launch"].includes(e)?"high":"medium"}function bt(e,t){let r=Q(e,t),n={operation:e};r&&(n.target=r);for(let o of["selector","clear","submit","combo","value","dx","dy","point","from","to","at","delta","milliseconds"])t[o]!==void 0&&(n[o]=structuredClone(t[o]));return typeof t.text=="string"&&(n.text=`[redacted ${t.text.length} characters]`),Array.isArray(t.hostPaths)&&(n.hostPaths=t.hostPaths.map(()=>"[redacted host path]")),typeof t.toPath=="string"&&(n.toPath="[redacted destination path]"),n}function wt(e,t){let r=structuredClone(t);return typeof r.text=="string"&&(r.text=`[redacted ${r.text.length} characters]`),Array.isArray(r.hostPaths)&&(r.hostPaths=r.hostPaths.map(()=>"[redacted host path]")),typeof r.toPath=="string"&&(r.toPath="[redacted destination path]"),ve(r.trigger)&&typeof r.trigger.url=="string"&&(r.trigger={...r.trigger,url:ye(r.trigger.url)}),typeof r.url=="string"&&(r.url=ye(r.url)),{operation:e,...r}}function Et(e,t){let r=Q(e,t),n=r?.url??r?.applicationId??r?.deviceId??r?.tabId??r?.resource??"current target";return`${e} on ${n}`}function Q(e,t){let r={};return typeof t.url=="string"&&(r.url=t.url),typeof t.tabId=="string"&&(r.tabId=t.tabId),typeof t.deviceId=="string"&&(r.deviceId=t.deviceId),typeof t.applicationId=="string"&&(r.applicationId=t.applicationId),typeof t.displayId=="string"&&(r.displayId=t.displayId),(e==="browser.navigate"||e==="browser.tabs.list"||e==="browser.tabs.open")&&(r.resource="browser-tabs"),Object.keys(r).length>0?r:void 0}function yt(e){return{operationId:e.operationId,status:e.status,effect:e.effect,startedAt:e.startedAt,completedAt:e.completedAt,adapter:e.adapter,target:e.target,...e.data!==void 0?{data:e.data}:{},artifacts:e.artifacts.map(t=>({artifactId:t.artifactId,revision:t.revision,kind:t.kind,title:t.title,state:t.state,mediaType:t.mediaType,sensitivity:t.sensitivity,hash:t.content.hash,sizeBytes:t.content.sizeBytes})),lease:e.lease,...e.error?{error:e.error}:{}}}function vt(e){let t=[];for(let r of e.artifacts){if(t.length>=ut||!r.mediaType.startsWith("image/"))continue;let n=r.content.storage;if(n.type!=="inline"||typeof n.base64!="string")continue;let o=Math.floor(n.base64.length*.75);o<=0||o>lt||t.push({type:"image_url",image_url:{url:`data:${r.mediaType};base64,${n.base64}`,detail:"high"}})}return t}function Tt(e){let t=new Set(U),r=new Set;for(let n of e){if(!t.has(n))throw new TypeError(`Unsupported XENO automation operation: ${String(n)}`);r.add(n)}return Array.from(r)}function St(e){return ct("sha256").update(Z(e)).digest("hex")}function Z(e){return Array.isArray(e)?`[${e.map(Z).join(",")}]`:ve(e)?`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${Z(e[t])}`).join(",")}}`:JSON.stringify(e)??"null"}function ye(e){try{let t=new URL(e);return`${t.origin}${t.pathname}`}catch{return"[invalid URL]"}}function Ct(e){return e instanceof Error?e.message:String(e)}function Rt(e){return e&&typeof e=="object"&&"code"in e&&typeof e.code=="string"?e.code:"AUTOMATION_EXECUTION_FAILED"}function ve(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}export{U as XENO_AUTOMATION_OPERATIONS,T as XENO_AUTOMATION_PROTOCOL_VERSION,a as XenoAutomationError,Ie as XenoGovernedAutomationExecutor,we as XenoLoopbackAutomationAdapter,O as assertRequiredXenoAutomationEvidence,R as assertValidXenoAutomationAdapterManifest,ue as assertValidXenoAutomationRequest,on as assertXenoAutomationAdapterConformant,H as assertXenoAutomationAuthority,fe as buildXenoAutomationCapabilityUse,Qe as createXenoAutomationConformanceReport,un as createXenoGovernedAutomationTools,h as describeXenoAutomationOperation,V as isXenoAutomationOperation,W as materializeXenoAutomationEvidence,J as persistXenoAutomationEvidence,pe as resolveXenoAutomationEvidencePolicy};
899
+ `;var Vt=512*1024,$t=744*60*60*1e3,Ft=Object.freeze(["allowedFilesystemRead","allowedFilesystemWrite","outsideFilesystemReadDenied","outsideFilesystemWriteDenied","unlistedFilesystemReadDenied","unlistedFilesystemWriteDenied","symlinkEscapeDenied","networkDefaultDeny","environmentSecretsExcluded","childProcessPolicyInherited","standardCommandLaunch","processTreeCleanup","timeoutEnforced","hostPolicyRecoveryClean","uiRestrictionsEnforced"]);var Jt=10*6e4,qt=Object.freeze({"win32-x64-wxc-exec.exe":"db0a3422be9e1b396cc1b2547c70ff16b27412438a31c10a45abf370cac86ae2","win32-arm64-wxc-exec.exe":"e430d0e4f44f616e91db684f8d825a6dc93e06a1262b8d00bcaac7522a317aab","linux-x64-lxc-exec":"1efe3f817f5ae9ba9f9f2fd59142e79b2dde7a4dd024576b0ddb635fc87edeb5","linux-arm64-lxc-exec":"fdc00ccecf362ae3ddd8ccad93fd7c8b5b1f03c68897ab05ef1c9f1d327ea3fe","darwin-arm64-mxc-exec-mac":"77c07a86f483ed91dd5be290cd77878ac0c56fe113cdb8c764e7e5201c744ad2"}),Kt=Object.freeze({"win32-x64-wxc-host-prep.exe":"531fb3cdb4b0c964908fd71b71d40961417afb399cbab72f92a25e95309a6416","win32-arm64-wxc-host-prep.exe":"3ef702332286a39153fc259310b5021e3de3c191751d7522684f6475f73af5ef"});var ur=Object.freeze({policyEnforcement:!0,restrictedIdentity:!1,lowIntegrity:!1,processTreeControl:!1,filesystemIsolation:!1,networkIsolation:!1,inheritedHandleAllowlist:!1,environmentSanitization:!0}),fr=Object.freeze({policyEnforcement:!0,restrictedIdentity:!0,lowIntegrity:!0,processTreeControl:!0,filesystemIsolation:!1,networkIsolation:!1,inheritedHandleAllowlist:!0,environmentSanitization:!0}),pr=Object.freeze({policyEnforcement:!0,restrictedIdentity:!0,lowIntegrity:!1,processTreeControl:!0,filesystemIsolation:!1,networkIsolation:!1,inheritedHandleAllowlist:!1,environmentSanitization:!0}),mr=Object.freeze({policyEnforcement:!0,restrictedIdentity:!0,lowIntegrity:!1,processTreeControl:!0,filesystemIsolation:!0,networkIsolation:!0,inheritedHandleAllowlist:!0,environmentSanitization:!0}),hr=Object.freeze({policyEnforcement:!0,restrictedIdentity:!1,lowIntegrity:!1,processTreeControl:!1,filesystemIsolation:!1,networkIsolation:!1,inheritedHandleAllowlist:!1,environmentSanitization:!0});var _e=1,V=class extends Error{constructor(r,n){super(n);this.code=r;this.name="XenoSecureExecutionContractError"}code};function Re(e){let t=[];if(!e||typeof e!="object")return["Contract must be an object"];if(e.schemaVersion!==_e&&t.push("Unsupported schemaVersion"),e.contractId?.trim()||t.push("contractId is required"),(!e.identity?.runId?.trim()||!e.identity?.agentId?.trim())&&t.push("runId and agentId are required"),oe(e.createdAt)||t.push("createdAt must be an ISO 8601 timestamp"),e.expiresAt&&(!oe(e.expiresAt)||Date.parse(e.expiresAt)<=Date.parse(e.createdAt))&&t.push("expiresAt must be later than createdAt"),e.requestedLevel!==e.effectiveLevel&&t.push("requestedLevel and effectiveLevel must match"),e.trustMode==="untrusted"&&e.effectiveLevel!=="contained"&&t.push("Untrusted execution requires contained mode"),e.effectiveLevel==="contained"&&(e.adapter.certified||t.push("Contained mode requires a certified adapter"),e.adapter.certificationArtifactId||t.push("Contained mode requires a certification artifact"),(!e.adapter.capabilities.filesystemIsolation||e.filesystem.enforcement!=="os")&&t.push("Contained mode requires OS filesystem isolation"),(!e.adapter.capabilities.networkIsolation||e.network.enforcement!=="os")&&t.push("Contained mode requires OS network isolation"),e.network.default!=="deny"&&t.push("Contained networking must default deny")),e.network.enforcement==="none"&&!e.network.acknowledgedUnrestricted&&t.push("Unrestricted networking must be explicitly acknowledged"),e.filesystem.writeRoots.length>0&&e.profile.permissionProfile==="read-only"&&t.push("Read-only profiles cannot receive write roots"),(!Array.isArray(e.browser.readAllowedDomains)||!Array.isArray(e.browser.actAllowedDomains))&&t.push("Browser read/action domain policies are required"),(!Array.isArray(e.browser.allowedSchemes)||e.browser.allowedSchemes.some(r=>r!=="http"&&r!=="https"))&&t.push("Browser allowed schemes are invalid"),(!Array.isArray(e.browser.allowedPorts)||e.browser.allowedPorts.some(r=>!Number.isInteger(r)||r<1||r>65535))&&t.push("Browser allowed ports are invalid"),e.secrets.some(r=>!r.secretId.trim())&&t.push("Secret projections require non-empty secret IDs"),new Set(e.secrets.map(r=>r.secretId)).size!==e.secrets.length&&t.push("Secret IDs must be unique"),new Set(e.capabilityLeaseIds).size!==e.capabilityLeaseIds.length&&t.push("Capability lease IDs must be unique"),/^[a-f0-9]{64}$/.test(e.profile.fingerprint)||t.push("Profile fingerprint is invalid"),!/^[a-f0-9]{64}$/.test(e.fingerprint))t.push("Contract fingerprint is invalid");else{let r={...e};delete r.fingerprint,Oe(r)!==e.fingerprint&&t.push("Contract fingerprint does not match content")}return t}function ie(e){let t=Re(e);if(t.length>0){let r=t.includes("Contract fingerprint does not match content");throw new V(r?"SECURITY_CONTRACT_FINGERPRINT_MISMATCH":"SECURITY_CONTRACT_INVALID",t.join("; "))}}function Oe(e){return Ce("sha256").update(JSON.stringify($(e))).digest("hex")}function $(e){return Array.isArray(e)?e.map($):!e||typeof e!="object"?e:Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>[t,$(r)]))}function oe(e){return typeof e=="string"&&e.includes("T")&&Number.isFinite(Date.parse(e))}var Ne=/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$/,ae=1048576;function ue(e){(!e||typeof e!="object")&&A("Automation request must be an object"),e.protocolVersion!==1&&A("Unsupported automation protocol version"),E(e.operationId,"operationId"),E(e.idempotencyKey,"idempotencyKey"),E(e.capabilityLeaseId,"capabilityLeaseId"),E(e.governingToolName,"governingToolName"),(!Number.isSafeInteger(e.expectedLeaseVersion)||e.expectedLeaseVersion<1)&&A("expectedLeaseVersion must be a positive safe integer"),me(e.requestedAt)||A("requestedAt must be an ISO 8601 timestamp"),B(e.operation)||A(`Unsupported automation operation: ${e.operation}`),(!e.parameters||typeof e.parameters!="object"||Array.isArray(e.parameters))&&A("parameters must be a JSON object");let t;try{t=Buffer.byteLength(JSON.stringify(e.parameters),"utf8")}catch(r){throw new a("AUTOMATION_REQUEST_INVALID","parameters must be serializable JSON",void 0,{cause:r})}if(t>ae&&A(`parameters exceed ${ae} bytes`),E(e.identity?.runId,"identity.runId"),E(e.identity?.agentId,"identity.agentId"),ie(e.executionContract),xe(e),!e.executionContract.capabilityLeaseIds.includes(e.capabilityLeaseId))throw new a("AUTOMATION_CONTRACT_INVALID",`Capability lease ${e.capabilityLeaseId} is not bound to the execution contract`);if(e.executionContract.expiresAt&&Date.parse(e.executionContract.expiresAt)<=Date.now())throw new a("AUTOMATION_CONTRACT_EXPIRED","Execution contract has expired")}function _(e){(!e||typeof e!="object")&&m("Adapter manifest must be an object"),e.protocolVersion!==1&&m("Adapter protocol version is unsupported"),C(e.adapterId,"adapterId"),C(e.adapterVersion,"adapterVersion"),C(e.platform,"platform"),C(e.architecture,"architecture"),e.targetBinding!=="atomic-preflight"&&m("Adapter must implement atomic preflight target binding"),(!Array.isArray(e.operations)||e.operations.length===0)&&m("Adapter must declare operations");let t=new Set;for(let r of e.operations)B(r)||m(`Adapter declares unknown operation ${r}`),t.has(r)&&m(`Adapter declares duplicate operation ${r}`),t.add(r);e.certified&&!e.certificationArtifactId&&m("A certified automation adapter requires a certification artifact"),Array.isArray(e.limitations)||m("Adapter limitations must be an array"),e.operations.some(r=>r.startsWith("browser."))&&(!e.policyEnforcement.domain||!e.policyEnforcement.scheme||!e.policyEnforcement.port)&&m("Browser adapters must enforce domain, scheme, and port policy"),e.operations.some(r=>r.startsWith("computer."))&&!e.supports.immediateStop&&m("Computer-use adapters must support immediate stop")}function H(e,t,r){let n=I(e.operation);if(!t.operations.includes(e.operation))throw new a("AUTOMATION_OPERATION_UNSUPPORTED",`Adapter ${t.adapterId} does not support ${e.operation}`);if(n.surface==="browser"){let o=e.executionContract.browser.mode;if(o==="none"||n.effect==="act"&&o!=="act")throw new a("AUTOMATION_POLICY_DENIED",`Execution contract denies ${e.operation}`);if(Pe(e,r,n.effect==="act"),e.operation==="browser.download"&&e.executionContract.browser.downloads==="deny")throw new a("AUTOMATION_POLICY_DENIED","Execution contract denies browser downloads");if(e.operation==="browser.upload"&&e.executionContract.browser.uploads==="deny")throw new a("AUTOMATION_POLICY_DENIED","Execution contract denies browser uploads");if(e.operation.startsWith("browser.record.")&&e.executionContract.browser.recording!=="bounded")throw new a("AUTOMATION_POLICY_DENIED","Execution contract denies browser recording")}else{let o=e.executionContract.computer.mode;if(o==="none"||n.effect==="act"&&o!=="act")throw new a("AUTOMATION_POLICY_DENIED",`Execution contract denies ${e.operation}`);let i=e.executionContract.computer.allowedApplications,d=e.operation==="computer.launch"?Le(e):r.applicationId??e.declaredTarget?.applicationId;if((e.operation==="computer.launch"||i.length>0)&&(!d||!i.includes(d)))throw new a("AUTOMATION_POLICY_DENIED",`Application ${d??"<unknown>"} is not allowed`)}}function fe(e,t){let r=I(e.operation),n=r.surface==="browser"?r.effect==="act"?"browser-act":"browser-read":r.effect==="act"?"computer-act":"computer-observe";return{subject:{runId:e.identity.runId,agentId:e.identity.agentId,...e.identity.turnId?{turnId:e.identity.turnId}:{},toolName:e.governingToolName,operationId:e.operationId},kind:n,operation:e.operation,...se(e,t)?{resource:se(e,t)}:{},...de(t)?{destination:de(t)}:{}}}function se(e,t){return e.declaredTarget?.resource??Xe(t)}function pe(e){let t=I(e.operation).evidence,r=e.evidencePolicy??{},n=F(t.before,r.before),o=F(t.after,r.after),i=F(t.recording,r.recording),d=r.retainUntil;return d&&!me(d)&&A("evidencePolicy.retainUntil must be an ISO 8601 timestamp"),{before:n,after:o,recording:i,sensitivity:r.sensitivity??"confidential",...d?{retainUntil:d}:{},...r.legalHold!==void 0?{legalHold:r.legalHold}:{}}}function xe(e){let t=e.executionContract.identity,r=["runId","agentId","sessionId","turnId","taskId","workspaceId"];for(let n of r){let o=t[n],i=e.identity[n];if(o!==void 0&&o!==i)throw new a("AUTOMATION_IDENTITY_MISMATCH",`Automation identity ${n} does not match the execution contract`)}}function Pe(e,t,r){let n=t.url??t.origin??e.declaredTarget?.url??e.declaredTarget?.origin;if(!n){if(["browser.tabs.list","browser.wait"].includes(e.operation))return;throw new a("AUTOMATION_PREFLIGHT_INVALID","Browser preflight did not bind an effective URL")}let o;try{o=new URL(n)}catch{throw new a("AUTOMATION_POLICY_DENIED","Browser target URL is invalid")}if(o.username||o.password)throw new a("AUTOMATION_POLICY_DENIED","Browser target URLs cannot contain credentials");let i=o.protocol.replace(/:$/,"");i!=="http"&&i!=="https"&&w(`Browser scheme ${o.protocol} is not supported`);let d=i,c=o.hostname.toLowerCase().replace(/\.$/,""),l=o.port?Number(o.port):d==="https"?443:80,s=e.executionContract.browser,u=De(c);if(le(c,s.deniedDomains)&&w(`Browser domain ${c} is denied`),ce(o,e.executionContract.network.denyDestinations)&&w(`Network policy explicitly denies ${d}://${c}:${l}`),u&&s.allowLoopbackDevelopment)return;s.allowedSchemes.includes(d)||w(`Browser scheme ${o.protocol} is not allowed`),s.allowedPorts.includes(l)||w(`Browser port ${l} is not allowed`);let p=r?s.actAllowedDomains:s.readAllowedDomains;le(c,p)||w(`Browser domain ${c} is outside the ${r?"action":"read"} allowlist`),e.executionContract.network.default==="deny"&&(ce(o,e.executionContract.network.allowDestinations)||w(`Network policy does not allow ${d}://${c}:${l}`))}function ce(e,t){let r=e.protocol.replace(/:$/,""),n=e.hostname.toLowerCase().replace(/\.$/,""),o=e.port?Number(e.port):r==="https"?443:80;return t.some(i=>{let d=i.scheme?.replace(/^custom:/,"");return i.host===n&&(i.port===void 0||i.port===o)&&(d===void 0||d===r)})}function Xe(e){return e.resource??e.tabId??e.pageId??e.deviceId??e.applicationId}function de(e){let t=e.origin??e.url;if(!t)return e.domain;try{return new URL(t).origin}catch{return t}}function Le(e){let t=e.parameters.target,r=t&&typeof t=="object"&&!Array.isArray(t)?t.app_id:void 0,n=e.parameters.applicationId??r??e.declaredTarget?.applicationId;return typeof n=="string"&&n.length>0?n:void 0}function le(e,t){return t.some(r=>{let n=r.toLowerCase();if(n.startsWith(".")){let o=n.slice(1);return e===o||e.endsWith(`.${o}`)}return e===n})}function De(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function F(e,t){let r={disabled:0,optional:1,required:2};return!t||r[t]<=r[e]?e:t}function E(e,t){(typeof e!="string"||!Ne.test(e))&&A(`${t} is invalid`)}function C(e,t){(typeof e!="string"||e.trim().length===0||e.length>256)&&m(`${t} is invalid`)}function me(e){return typeof e=="string"&&e.includes("T")&&Number.isFinite(Date.parse(e))}function w(e){throw new a("AUTOMATION_POLICY_DENIED",e)}function A(e){throw new a("AUTOMATION_REQUEST_INVALID",e)}function m(e){throw new a("AUTOMATION_OPERATION_UNSUPPORTED",e)}import{createHash as Me}from"node:crypto";import{createHash as ke}from"node:crypto";function R(e){return{algorithm:"sha256",value:ke("sha256").update(e).digest("hex")}}var Ue="[\\u0000-\\u001f\\u007f]",Xr=new RegExp(Ue);var O=class extends Error{constructor(r,n,o,i){super(n,i);this.code=r;this.detail=o;this.name="XenoArtifactRepositoryError"}code;detail};var G=32*1024*1024,Be=1024*1024*1024,Ve=/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$/;function W(e){let r=(e.now??(()=>new Date().toISOString()))(),n=new Set;return e.evidence.map((o,i)=>{if(Fe(o),n.has(o.evidenceId))throw new a("AUTOMATION_EVIDENCE_INVALID",`Duplicate evidence ID ${o.evidenceId}`);n.add(o.evidenceId);let d=$e(o),c=Me("sha256").update(`${e.request.operationId}\0${o.evidenceId}\0${d.hash.value}`).digest("hex").slice(0,32);return{schemaVersion:1,artifactId:`automation_${c}`,revision:1,kind:o.kind,title:o.title,...o.description?{description:o.description}:{},state:"draft",createdAt:r,mediaType:o.mediaType,sensitivity:o.sensitivity??e.policy.sensitivity,identity:{...e.request.identity},content:d,provenance:{producer:{kind:"tool",id:e.request.governingToolName,displayName:e.manifest.adapterId,profileFingerprint:e.request.executionContract.profile.fingerprint},operationId:e.request.operationId,executionContractFingerprint:e.request.executionContract.fingerprint,capabilityLeaseIds:[e.request.capabilityLeaseId],attributes:{automationProtocolVersion:e.request.protocolVersion,automationOperation:e.request.operation,automationEvidenceId:o.evidenceId,automationEvidencePhase:o.phase,adapterId:e.manifest.adapterId,adapterVersion:e.manifest.adapterVersion,evidenceIndex:i}},...o.anchors?{anchors:structuredClone(o.anchors)}:{},...e.policy.retainUntil||e.policy.legalHold!==void 0?{retention:{...e.policy.retainUntil?{retainUntil:e.policy.retainUntil}:{},...e.policy.legalHold!==void 0?{legalHold:e.policy.legalHold}:{}}}:{},extensions:{...o.extensions??{},xenoAutomation:{phase:o.phase,adapter:e.manifest.adapterId,certifiedAdapter:e.manifest.certified}}}})}async function z(e,t){if(!e)return t.map(n=>structuredClone(n));let r=[];for(let n of t)try{let o=await e.create(n);r.push(o.artifact)}catch(o){if(o instanceof O&&o.code==="ARTIFACT_ALREADY_EXISTS"){let i=await e.require(n.artifactId,n.revision);if(i.artifact.content.hash.value===n.content.hash.value){r.push(i.artifact);continue}}throw new a("AUTOMATION_EVIDENCE_PERSISTENCE_FAILED",`Failed to persist automation evidence ${n.artifactId}`,{artifactId:n.artifactId},{cause:o})}return r}function N(e,t,r){if(t[r]==="required"&&!e.some(n=>n.phase===r))throw new a("AUTOMATION_EVIDENCE_REQUIRED",`Automation operation requires ${r} evidence before it can be trusted`)}function $e(e){if(e.content.type==="text"){let t=Buffer.byteLength(e.content.text,"utf8");return he(t),{hash:R(e.content.text),sizeBytes:t,storage:{type:"inline",text:e.content.text},encoding:"utf8",...e.redactedPreview?{redactedPreview:e.redactedPreview}:{}}}if(e.content.type==="base64"){let t=He(e.content.base64);return he(t.byteLength),{hash:R(t),sizeBytes:t.byteLength,storage:{type:"inline",base64:e.content.base64},encoding:"base64",...e.redactedPreview?{redactedPreview:e.redactedPreview}:{}}}if(!Number.isSafeInteger(e.content.sizeBytes)||e.content.sizeBytes<0||e.content.sizeBytes>Be)throw new a("AUTOMATION_EVIDENCE_INVALID","Referenced evidence size is invalid");if(!e.content.hash?.algorithm||!e.content.hash.value)throw new a("AUTOMATION_EVIDENCE_INVALID","Referenced evidence requires a content hash");if(e.content.hash.algorithm==="sha256"&&!/^[a-f0-9]{64}$/.test(e.content.hash.value))throw new a("AUTOMATION_EVIDENCE_INVALID","Referenced evidence SHA-256 is invalid");return{hash:{...e.content.hash},sizeBytes:e.content.sizeBytes,storage:structuredClone(e.content.storage),...e.content.encoding?{encoding:e.content.encoding}:{},...e.redactedPreview?{redactedPreview:e.redactedPreview}:{}}}function Fe(e){(!e||typeof e!="object")&&g("Evidence must be an object"),Ve.test(e.evidenceId)||g("Evidence ID is invalid"),["before","action","after","recording","diagnostic"].includes(e.phase)||g("Evidence phase is invalid"),(!e.kind||!e.title?.trim()||e.title.length>512)&&g("Evidence kind and title are required"),/^[\w!#$&^_.+-]+\/[\w!#$&^_.+-]+(?:;.*)?$/.test(e.mediaType)||g("Evidence media type is invalid")}function He(e){(e.length===0||e.length>Math.ceil(G/3)*4+4)&&g("Inline base64 evidence is empty or too large"),(!/^[A-Za-z0-9+/]*={0,2}$/.test(e)||e.length%4!==0)&&g("Inline evidence is not canonical base64");let t=Buffer.from(e,"base64");return t.toString("base64")!==e&&g("Inline evidence is not canonical base64"),t}function he(e){e>G&&g(`Inline evidence exceeds ${G} bytes`)}function g(e){throw new a("AUTOMATION_EVIDENCE_INVALID",e)}import{createHash as je}from"node:crypto";var Ie=3e4,Ge=1e3,Ae=class{adapter;leaseAuthority;artifactRepository;now;executions=new Map;active=new Map;constructor(t){this.adapter=t.adapter,this.leaseAuthority=t.leaseAuthority,this.artifactRepository=t.artifactRepository,this.now=t.now??(()=>new Date().toISOString())}execute(t,r){let n=Ke(t),o=this.executions.get(t.operationId);if(o){if(o.fingerprint!==n)throw new a("AUTOMATION_OPERATION_CONFLICT",`Operation ${t.operationId} was already submitted with different authority or parameters`);return o.promise}let i=new AbortController,d=Ye(r,i);this.active.set(t.operationId,i);let c=this.executeFresh(t,i.signal).finally(()=>{d(),this.active.delete(t.operationId)});return this.executions.set(t.operationId,{fingerprint:n,promise:c}),this.trimIdempotencyRecords(),c}async stop(t,r="human-stop"){let n=this.active.get(t);return n?(n.abort(new Error(r)),await this.adapter.stop?.(t,r),!0):!1}async executeFresh(t,r){ue(t),q(r);let n=await this.adapter.manifest();_(n);let o=I(t.operation),i=pe(t),d=this.now(),c=await this.adapter.preflight(t,r);We(c,this.now()),H(t,n,c.observedTarget),q(r);let l=c.evidence??[];N(l,i,"before");let s=await z(this.artifactRepository,W({request:t,manifest:n,policy:i,evidence:l,now:this.now}));if(q(r),Date.parse(c.expiresAt)<=Date.parse(this.now()))throw new a("AUTOMATION_PREFLIGHT_INVALID","Automation preflight expired before authority consumption");let u=fe(t,c.observedTarget),p=await this.leaseAuthority.consume(t.capabilityLeaseId,t.expectedLeaseVersion,u),v={contractFingerprint:t.executionContract.fingerprint,lease:p,capabilityUse:u},f;try{f=await this.adapter.execute(t,c,v,r)}catch(h){return J({request:t,manifest:n,descriptorEffect:o.effect,target:c.observedTarget,lease:p,artifacts:s,startedAt:d,completedAt:this.now(),status:r.aborted?"cancelled":"error",code:r.aborted?"AUTOMATION_CANCELLED":"AUTOMATION_ADAPTER_ERROR",message:r.aborted?"Automation operation was stopped":Ze(h)})}ze(f);let ee=Je(c.observedTarget,f.observedTarget),x;try{H(t,n,f.observedTarget)}catch(h){x=h instanceof Error?h:new Error(String(h))}let S=f.evidence??[];qe(l,S);let te=[],P;try{N(S,i,"after"),N([...l,...S],i,"recording"),te=await z(this.artifactRepository,W({request:t,manifest:n,policy:i,evidence:S,now:this.now}))}catch(h){P=h instanceof Error?h:new Error(String(h))}let X=[...s,...te];return ee||x?J({request:t,manifest:n,descriptorEffect:o.effect,target:f.observedTarget,lease:p,artifacts:X,startedAt:f.startedAt,completedAt:f.completedAt,status:"error",code:"AUTOMATION_TARGET_CHANGED",message:ee??x.message}):P?J({request:t,manifest:n,descriptorEffect:o.effect,target:f.observedTarget,lease:p,artifacts:X,startedAt:f.startedAt,completedAt:f.completedAt,status:"evidence-incomplete",code:"AUTOMATION_EVIDENCE_INCOMPLETE",message:P.message}):{operationId:t.operationId,status:f.status,effect:o.effect,startedAt:f.startedAt,completedAt:f.completedAt,adapter:ge(n),target:structuredClone(f.observedTarget),...f.data!==void 0?{data:structuredClone(f.data)}:{},artifacts:X,lease:be(p),...f.error?{error:{...f.error}}:{}}}trimIdempotencyRecords(){for(;this.executions.size>Ge;){let t=this.executions.keys().next().value;if(!t||this.active.has(t))break;this.executions.delete(t)}}};function We(e,t){if(!e||typeof e!="object"||!e.token?.trim())throw new a("AUTOMATION_PREFLIGHT_INVALID","Adapter returned an invalid preflight token");let r=Date.parse(e.preparedAt),n=Date.parse(e.expiresAt),o=Date.parse(t);if(!Number.isFinite(r)||!Number.isFinite(n)||n<=r||n<=o)throw new a("AUTOMATION_PREFLIGHT_INVALID","Adapter returned an expired or invalid preflight window");if(n-r>Ie)throw new a("AUTOMATION_PREFLIGHT_INVALID",`Preflight TTL exceeds ${Ie} ms`);if(!e.observedTarget||typeof e.observedTarget!="object")throw new a("AUTOMATION_PREFLIGHT_INVALID","Adapter did not bind an observed target")}function ze(e){if(!e||typeof e!="object")throw new a("AUTOMATION_REQUEST_INVALID","Adapter returned no result");if(!["ok","denied","cancelled","error"].includes(e.status))throw new a("AUTOMATION_REQUEST_INVALID","Adapter returned an invalid status");if(!Number.isFinite(Date.parse(e.startedAt))||!Number.isFinite(Date.parse(e.completedAt)))throw new a("AUTOMATION_REQUEST_INVALID","Adapter result timestamps are invalid");if(Date.parse(e.completedAt)<Date.parse(e.startedAt))throw new a("AUTOMATION_REQUEST_INVALID","Adapter completion precedes its start");if(!e.observedTarget||typeof e.observedTarget!="object")throw new a("AUTOMATION_REQUEST_INVALID","Adapter result has no observed target")}function Je(e,t){let r=["tabId","deviceId","displayId"];for(let n of r)if(e[n]!==void 0&&e[n]!==t[n])return`Adapter changed bound ${n} between preflight and execution`}function qe(e,t){let r=new Set(e.map(n=>n.evidenceId));for(let n of t){if(r.has(n.evidenceId))throw new a("AUTOMATION_EVIDENCE_INVALID",`Duplicate evidence ID ${n.evidenceId}`);r.add(n.evidenceId)}}function J(e){return{operationId:e.request.operationId,status:e.status,effect:e.descriptorEffect,startedAt:e.startedAt,completedAt:e.completedAt,adapter:ge(e.manifest),target:structuredClone(e.target),artifacts:e.artifacts,lease:be(e.lease),error:{code:e.code,message:e.message}}}function ge(e){return{adapterId:e.adapterId,adapterVersion:e.adapterVersion,platform:e.platform,architecture:e.architecture}}function be(e){return{leaseId:e.leaseId,version:e.version,state:e.state,useCount:e.useCount}}function Ke(e){return je("sha256").update(JSON.stringify(K(e))).digest("hex")}function K(e){return Array.isArray(e)?e.map(K):!e||typeof e!="object"?e:Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>[t,K(r)]))}function Ye(e,t){if(!e)return()=>{};let r=()=>t.abort(e.reason);return e.aborted?r():e.addEventListener("abort",r,{once:!0}),()=>e.removeEventListener("abort",r)}function q(e){if(e.aborted)throw new a("AUTOMATION_CANCELLED","Automation operation was stopped before dispatch")}function Ze(e){return e instanceof Error&&e.message.slice(0,1024)||"Automation adapter failed"}function Qe(e,t=()=>new Date().toISOString()){let r=[];et(r,"manifest.valid",()=>_(e));let n=new Set(e.operations);return y(r,n,e.supports.consoleInspection,"browser.console.read","console inspection"),y(r,n,e.supports.networkInspection,"browser.network.read","network inspection"),y(r,n,e.supports.storageInspection,"browser.storage.read","storage inspection"),y(r,n,e.supports.pageErrorInspection,"browser.page-errors.read","page-error inspection"),y(r,n,e.supports.recordings,"browser.record.start","recording start"),y(r,n,e.supports.recordings,"browser.record.stop","recording stop"),n.has("browser.upload")&&b(r,"policy.upload",e.policyEnforcement.upload,"Upload policy is enforced"),n.has("browser.download")&&b(r,"policy.download",e.policyEnforcement.download,"Download policy is enforced"),[...n].some(o=>o.startsWith("browser."))&&(b(r,"policy.redirect",e.policyEnforcement.redirect,"Redirect policy is enforced"),b(r,"control.handback",e.supports.deterministicHandback,"Deterministic hand-back is supported")),[...n].some(o=>o.startsWith("computer."))&&(b(r,"control.stop",e.supports.immediateStop,"Immediate human stop is supported"),b(r,"privacy.redaction",e.supports.sensitiveRegionRedaction,"Sensitive-region redaction is supported")),b(r,"certification.binding",!e.certified||!!e.certificationArtifactId,e.certified?"Certification artifact is bound":"Adapter does not claim certification"),{protocolVersion:1,adapter:{adapterId:e.adapterId,adapterVersion:e.adapterVersion,platform:e.platform,architecture:e.architecture},generatedAt:t(),passed:r.every(o=>o.status==="pass"),checks:r}}function on(e){let r=Qe(e).checks.filter(n=>n.status==="fail");if(r.length>0)throw new a("AUTOMATION_OPERATION_UNSUPPORTED",r.map(n=>`${n.id}: ${n.message}`).join("; "))}function y(e,t,r,n,o){let i=t.has(n);b(e,`capability.${n}`,r===i,r===i?`${o} declaration matches the operation catalog`:`${o} declaration does not match ${n}`)}function et(e,t,r){try{r(),e.push({id:t,status:"pass",message:"Manifest satisfies the protocol contract"})}catch(n){e.push({id:t,status:"fail",message:n instanceof Error?n.message:String(n)})}}function b(e,t,r,n){e.push({id:t,status:r?"pass":"fail",message:n})}var tt=6e4,rt=48*1024*1024,we=class{endpoint;token;timeoutMs;maxResponseBytes;fetchImpl;constructor(t){if(this.endpoint=nt(t.baseUrl),this.token=ot(t.token),this.timeoutMs=Ee(t.timeoutMs??tt,1e3,3e5,"timeoutMs"),this.maxResponseBytes=Ee(t.maxResponseBytes??rt,1024,128*1024*1024,"maxResponseBytes"),this.fetchImpl=t.fetch??globalThis.fetch,typeof this.fetchImpl!="function")throw new a("AUTOMATION_TRANSPORT_ERROR","A Fetch API implementation is required")}manifest(){return this.request("manifest","GET")}preflight(t,r){return this.request("preflight","POST",t,r)}execute(t,r,n,o){return this.request("execute","POST",{request:t,preflight:r,grant:n},o)}async stop(t,r){await this.request("stop","POST",{operationId:t,reason:r.slice(0,512)})}async request(t,r,n,o){let i=new AbortController,d=st(o,i),c=setTimeout(()=>i.abort(new Error("automation transport timeout")),this.timeoutMs);c.unref?.();try{let l=new URL(t,this.endpoint),s=await this.fetchImpl(l,{method:r,redirect:"error",cache:"no-store",credentials:"omit",headers:{authorization:`Bearer ${this.token}`,accept:"application/json",...r==="POST"?{"content-type":"application/json"}:{}},...r==="POST"?{body:JSON.stringify(n??{})}:{},signal:i.signal}),u=await it(s,this.maxResponseBytes);if(!s.ok){let p=at(u);throw new a("AUTOMATION_TRANSPORT_ERROR",`XENO Browser rejected ${t}: ${p.message}`,{status:s.status,route:t,adapterCode:p.code})}if(!Y(u)||u.ok!==!0||!("result"in u))throw new a("AUTOMATION_RESPONSE_INVALID",`XENO Browser returned an invalid ${t} envelope`);return u.result}catch(l){if(l instanceof a)throw l;let s=o?.aborted;throw new a(s?"AUTOMATION_CANCELLED":"AUTOMATION_TRANSPORT_ERROR",s?"Automation transport was stopped":`XENO Browser ${t} transport failed`,{route:t},{cause:l})}finally{clearTimeout(c),d()}}};function nt(e){let t;try{t=new URL(e)}catch(n){throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser base URL is invalid",void 0,{cause:n})}if(t.protocol!=="http:"&&t.protocol!=="https:")throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser transport requires HTTP(S)");if(t.username||t.password||t.search||t.hash)throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser base URL cannot contain credentials, query, or fragment");let r=t.hostname.toLowerCase().replace(/^\[|\]$/g,"").replace(/\.$/,"");if(r!=="localhost"&&r!=="127.0.0.1"&&r!=="::1")throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser transport must use a loopback host");if(!t.port)throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser transport requires an explicit port");return t.pathname="/v1/automation/",t}function ot(e){if(typeof e!="string"||e.length<32||e.length>512||/\s/.test(e))throw new a("AUTOMATION_TRANSPORT_ERROR","XENO Browser session token is invalid");return e}async function it(e,t){let r=Number(e.headers.get("content-length"));if(Number.isFinite(r)&&r>t)throw new a("AUTOMATION_RESPONSE_INVALID",`XENO Browser response exceeds ${t} bytes`);if(e.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase()!=="application/json")throw new a("AUTOMATION_RESPONSE_INVALID","XENO Browser response is not application/json");if(!e.body)throw new a("AUTOMATION_RESPONSE_INVALID","XENO Browser response body is missing");let o=e.body.getReader(),i=[],d=0;for(;;){let{done:s,value:u}=await o.read();if(s)break;if(d+=u.byteLength,d>t)throw await o.cancel("response too large"),new a("AUTOMATION_RESPONSE_INVALID",`XENO Browser response exceeds ${t} bytes`);i.push(u)}let c=new Uint8Array(d),l=0;for(let s of i)c.set(s,l),l+=s.byteLength;try{return JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(c))}catch(s){throw new a("AUTOMATION_RESPONSE_INVALID","XENO Browser response contains invalid JSON",void 0,{cause:s})}}function at(e){return Y(e)&&Y(e.error)?{code:typeof e.error.code=="string"?e.error.code.slice(0,128):"UNKNOWN",message:typeof e.error.message=="string"?e.error.message.slice(0,1024):"request failed"}:{code:"UNKNOWN",message:"request failed"}}function st(e,t){if(!e)return()=>{};let r=()=>t.abort(e.reason);return e.aborted?r():e.addEventListener("abort",r,{once:!0}),()=>e.removeEventListener("abort",r)}function Ee(e,t,r,n){if(!Number.isSafeInteger(e)||e<t||e>r)throw new a("AUTOMATION_TRANSPORT_ERROR",`${n} must be an integer from ${t} to ${r}`);return e}function Y(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}import{createHash as ct,randomUUID as dt}from"node:crypto";var lt=8*1024*1024,ut=4;function un(e){return Tt(e.operations??M).map(r=>ft(r,e.runtime))}function ft(e,t){return{definition:{name:e,description:At(e),input_schema:pt(e)},projectPolicyInput(r){let n=wt(e,r),o=bt(e,r);return{observabilityInput:n,permissionInput:o,permissionPreview:Et(e,r),approvalKey:`xeno-automation:${e}:${St(r)}`,riskLevel:gt(e)}},async execute(r,n){let o=n?.authorization;if(!o||o.toolName!==e)return{success:!1,output:"",error:"Governed automation requires a host-issued authorization receipt",errorCode:"AUTOMATION_AUTHORIZATION_RECEIPT_REQUIRED",retryable:!1};let i=n.operationId??`automation_${dt()}`,d=Q(e,r);n.reportProgress?.({activity:"state",message:`Authorizing ${e}`});try{let c=await t.execute({operation:e,governingToolName:e,operationId:i,idempotencyKey:i,parameters:structuredClone(r),...d?{declaredTarget:d}:{},authorization:o,...n.signal?{signal:n.signal}:{},...n.reportProgress?{reportProgress:n.reportProgress}:{}}),l=c.status==="ok";return{success:l,output:JSON.stringify(yt(c)),...l?{}:{error:c.error?.message??`Governed automation ended with ${c.status}`,errorCode:c.error?.code??`AUTOMATION_${c.status.toUpperCase().replaceAll("-","_")}`},assistantContent:vt(c),evidence:c.artifacts.map(s=>({id:s.artifactId,kind:"artifact",status:c.status==="evidence-incomplete"?"failed":"verified",observedAt:s.updatedAt??s.createdAt,operationId:i,detail:{artifact_kind:s.kind,revision:s.revision,sensitivity:s.sensitivity}})),retryable:c.error?.retryable??!1}}catch(c){let l=n.signal?.aborted===!0;return{success:!1,output:"",error:l?"Governed automation was stopped":Ct(c),errorCode:l?"AUTOMATION_CANCELLED":_t(c),retryable:!l}}}}}function pt(e){let t=mt(e),r=ht(e);return{type:"object",properties:t,...r.length>0?{required:r}:{},...e==="browser.locate"?{oneOf:[{required:["selector"]},{required:["text"]}]}:{},additionalProperties:!1}}function mt(e){let t=(d,c=8192)=>({type:"string",minLength:1,maxLength:c,description:d}),r={type:"number"},n={type:"boolean"},o={type:"object",properties:{x:r,y:r},required:["x","y"],additionalProperties:!1},i={deviceId:t("Target xeno-use device ID.",256),applicationId:t("Expected or launch-target application ID.",512),displayId:t("Target display ID.",256)};switch(e){case"browser.navigate":return{url:t("Destination URL."),waitUntil:{enum:["load","none"]},tabId:t("Expected active tab ID. Hosts with multiple visible tabs should require this.",256)};case"browser.wait":return{until:{enum:["load","ms"]},value:{type:"integer",minimum:0,maximum:6e4}};case"browser.snapshot":return{mode:{enum:["text","html","markdown","a11y"]},tabId:t("Expected active tab ID.",256)};case"browser.screenshot":return{tabId:t("Expected active tab ID.",256)};case"browser.locate":return{selector:t("CSS selector."),text:t("Visible text to locate.")};case"browser.click":return{selector:t("CSS selector returned by browser.snapshot or browser.locate."),tabId:t("Expected active tab ID.",256)};case"browser.type":return{selector:t("CSS selector."),text:{type:"string",maxLength:65536},clear:n,submit:n,tabId:t("Expected active tab ID.",256)};case"browser.key":return{combo:t("Key combo such as Control+a or Enter.",256),tabId:t("Expected active tab ID.",256)};case"browser.select":return{selector:t("CSS selector."),value:t("Option value."),tabId:t("Expected active tab ID.",256)};case"browser.scroll":return{selector:t("Optional CSS selector."),dx:r,dy:r,tabId:t("Expected active tab ID.",256)};case"browser.tabs.open":return{url:t("URL to open in an isolated browser tab.")};case"browser.tabs.close":return{tabId:t("Tab ID to close.",256)};case"browser.console.read":case"browser.network.read":case"browser.page-errors.read":return{limit:{type:"integer",minimum:1,maximum:1e3},clear:n,tabId:t("Expected active tab ID.",256)};case"browser.storage.read":return{tabId:t("Expected active tab ID.",256)};case"browser.upload":return{selector:t("File input or drop-target selector."),backendNodeId:{type:"integer",minimum:1},hostPaths:{type:"array",items:t("Host file path.",32768),minItems:1,maxItems:64},drop:n,tabId:t("Expected active tab ID.",256)};case"browser.download":return{toPath:t("Approved destination path.",32768),trigger:{type:"object",properties:{url:t("Download URL."),selector:t("Download trigger selector.")},oneOf:[{required:["url"]},{required:["selector"]}],additionalProperties:!1},tabId:t("Expected active tab ID.",256)};case"browser.record.start":return{maxDurationMs:{type:"integer",minimum:1e3,maximum:6e4},intervalMs:{type:"integer",minimum:100,maximum:5e3},tabId:t("Expected active tab ID.",256)};case"browser.record.stop":return{tabId:t("Expected active tab ID.",256)};case"computer.observe":case"computer.screenshot":case"computer.window-state":return i;case"computer.point":return{...i,point:o,durationMs:{type:"integer",minimum:0,maximum:6e4}};case"computer.click":return{...i,point:o,button:{enum:["left","right","middle"]},modifiers:It()};case"computer.double-click":case"computer.right-click":return{...i,point:o};case"computer.drag":return{...i,from:o,to:o,durationMs:{type:"integer",minimum:0,maximum:6e4}};case"computer.type":return{...i,text:{type:"string",maxLength:65536}};case"computer.key":return{...i,combo:t("Key combo such as Control+a or Enter.",256)};case"computer.scroll":return{...i,at:o,delta:o};case"computer.wait":return{...i,milliseconds:{type:"integer",minimum:0,maximum:3e5}};case"computer.launch":return{...i,applicationId:t("Explicitly allowlisted application ID.",512)};case"browser.back":case"browser.forward":case"browser.reload":return{tabId:t("Expected active tab ID.",256)};case"browser.tabs.list":return{}}}function ht(e){switch(e){case"browser.navigate":case"browser.tabs.open":return["url"];case"browser.click":return["selector"];case"browser.type":return["selector","text"];case"browser.key":return["combo"];case"browser.select":return["selector","value"];case"browser.upload":return["hostPaths"];case"browser.download":return["toPath","trigger"];case"computer.point":case"computer.click":case"computer.double-click":case"computer.right-click":return["point"];case"computer.drag":return["from","to"];case"computer.type":return["text"];case"computer.key":return["combo"];case"computer.scroll":return["at","delta"];case"computer.launch":return["applicationId"];default:return[]}}function It(){return{type:"object",properties:{shift:{type:"boolean"},ctrl:{type:"boolean"},alt:{type:"boolean"},meta:{type:"boolean"}},additionalProperties:!1}}function At(e){let t=I(e),r=e.split(".").slice(1).join(" ");return`${t.effect==="act"?"Act on":"Inspect"} the ${t.surface} using governed ${r} automation. The host requires policy approval, an exact capability lease, target-bound preflight, and durable evidence.`}function gt(e){return I(e).effect==="observe"?e==="browser.navigate"||e==="browser.tabs.open"?"medium":"low":["browser.type","browser.upload","browser.download","computer.type","computer.key","computer.launch"].includes(e)?"high":"medium"}function bt(e,t){let r=Q(e,t),n={operation:e};r&&(n.target=r);for(let o of["selector","clear","submit","combo","value","dx","dy","point","from","to","at","delta","milliseconds"])t[o]!==void 0&&(n[o]=structuredClone(t[o]));return typeof t.text=="string"&&(n.text=`[redacted ${t.text.length} characters]`),Array.isArray(t.hostPaths)&&(n.hostPaths=t.hostPaths.map(()=>"[redacted host path]")),typeof t.toPath=="string"&&(n.toPath="[redacted destination path]"),n}function wt(e,t){let r=structuredClone(t);return typeof r.text=="string"&&(r.text=`[redacted ${r.text.length} characters]`),Array.isArray(r.hostPaths)&&(r.hostPaths=r.hostPaths.map(()=>"[redacted host path]")),typeof r.toPath=="string"&&(r.toPath="[redacted destination path]"),ve(r.trigger)&&typeof r.trigger.url=="string"&&(r.trigger={...r.trigger,url:ye(r.trigger.url)}),typeof r.url=="string"&&(r.url=ye(r.url)),{operation:e,...r}}function Et(e,t){let r=Q(e,t),n=r?.url??r?.applicationId??r?.deviceId??r?.tabId??r?.resource??"current target";return`${e} on ${n}`}function Q(e,t){let r={};return typeof t.url=="string"&&(r.url=t.url),typeof t.tabId=="string"&&(r.tabId=t.tabId),typeof t.deviceId=="string"&&(r.deviceId=t.deviceId),typeof t.applicationId=="string"&&(r.applicationId=t.applicationId),typeof t.displayId=="string"&&(r.displayId=t.displayId),(e==="browser.navigate"||e==="browser.tabs.list"||e==="browser.tabs.open")&&(r.resource="browser-tabs"),Object.keys(r).length>0?r:void 0}function yt(e){return{operationId:e.operationId,status:e.status,effect:e.effect,startedAt:e.startedAt,completedAt:e.completedAt,adapter:e.adapter,target:e.target,...e.data!==void 0?{data:e.data}:{},artifacts:e.artifacts.map(t=>({artifactId:t.artifactId,revision:t.revision,kind:t.kind,title:t.title,state:t.state,mediaType:t.mediaType,sensitivity:t.sensitivity,hash:t.content.hash,sizeBytes:t.content.sizeBytes})),lease:e.lease,...e.error?{error:e.error}:{}}}function vt(e){let t=[];for(let r of e.artifacts){if(t.length>=ut||!r.mediaType.startsWith("image/"))continue;let n=r.content.storage;if(n.type!=="inline"||typeof n.base64!="string")continue;let o=Math.floor(n.base64.length*.75);o<=0||o>lt||t.push({type:"image_url",image_url:{url:`data:${r.mediaType};base64,${n.base64}`,detail:"high"}})}return t}function Tt(e){let t=new Set(M),r=new Set;for(let n of e){if(!t.has(n))throw new TypeError(`Unsupported XENO automation operation: ${String(n)}`);r.add(n)}return Array.from(r)}function St(e){return ct("sha256").update(Z(e)).digest("hex")}function Z(e){return Array.isArray(e)?`[${e.map(Z).join(",")}]`:ve(e)?`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${Z(e[t])}`).join(",")}}`:JSON.stringify(e)??"null"}function ye(e){try{let t=new URL(e);return`${t.origin}${t.pathname}`}catch{return"[invalid URL]"}}function Ct(e){return e instanceof Error?e.message:String(e)}function _t(e){return e&&typeof e=="object"&&"code"in e&&typeof e.code=="string"?e.code:"AUTOMATION_EXECUTION_FAILED"}function ve(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}export{M as XENO_AUTOMATION_OPERATIONS,T as XENO_AUTOMATION_PROTOCOL_VERSION,a as XenoAutomationError,Ae as XenoGovernedAutomationExecutor,we as XenoLoopbackAutomationAdapter,N as assertRequiredXenoAutomationEvidence,_ as assertValidXenoAutomationAdapterManifest,ue as assertValidXenoAutomationRequest,on as assertXenoAutomationAdapterConformant,H as assertXenoAutomationAuthority,fe as buildXenoAutomationCapabilityUse,Qe as createXenoAutomationConformanceReport,un as createXenoGovernedAutomationTools,I as describeXenoAutomationOperation,B as isXenoAutomationOperation,W as materializeXenoAutomationEvidence,z as persistXenoAutomationEvidence,pe as resolveXenoAutomationEvidencePolicy};