chainlesschain 0.166.13 → 0.166.14

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 (173) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-BN25cNOD.js → AIOps-C8SyFhOo.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-Da9IP-m5.js → ActionButton-Dup5gFK0.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-D7hkEvQm.js → Analytics-8FyOWA7V.js} +2 -2
  5. package/src/assets/web-panel/assets/{AppLayout-CCV4Xnbc.js → AppLayout-DBzdU9dg.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-CVSnVJeA.js → Artifacts-C_0Z8gNy.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-CuYdw5Ag.js → Audit-Cf2a-58m.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-DZCnK-Tf.js → BackgroundAgents-M7w-2zgB.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-cV9FdpTy.js → Backup-CCTHQXoL.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-BRnv6YSp.js → BaseInput-DjXpeFwJ.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-Bw5w87P4.js → Chat-cAvchsJU.js} +5 -5
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-C0GjtUAw.js → ChatBubbleRenderer-DvEvxlZv.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-DaoTqcdt.js → Checkbox-DKs6qvOn.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-B4dYcEIi.js → Codegen-DlkA7b9X.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-mAhuOeuD.js → Col-CkfdKhyJ.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-BK6KEdBk.js → Community-iNXMHzj6.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-CCglmNu5.js → Compact-DQxPEd09.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-Cm8S4of7.js → Compliance-CSKvMCjs.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-Dhs1QLMe.js → Cowork-CkWqazpD.js} +2 -2
  20. package/src/assets/web-panel/assets/{Cron-CLlhmXWk.js → Cron-k6W8IzhB.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BnHVbaNs.js → Crosschain-C8MS1OuY.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-UzQP9-0O.js → DID-DJuCcgiQ.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-CBdlPClz.js → Dashboard-LeThKzp3.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-axIRPdq1.js → Dropdown-BvxwgpE4.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-DUalW5rx.js → EmailListRenderer-n3e_a1M3.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bl4W9luY.js → FamilyGuardDashboard-509W6W6v.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-C1yP-uEu.js → Federation-xgZReQm0.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-Xh6Ig5q8.js → FormItemContext-jZOhKcQx.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-C2cz3bt2.js → GenericCardRenderer-Jo0ULzHv.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-C_z63ixg.js → Git-BsRcyWQP.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-BYqB33_3.js → Governance-JlpMYTAk.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-CEULuArm.js → Inference-CUEz872-.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-fgMsu-0H.js → KnowledgeGraph-DgrvvEDU.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-DO9Hdcec.js → Logs-Df-KY4U3.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-BEPDcSwz.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-B8zyLiFe.js → Marketplace-kPZDTOeI.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-BLAN2mWW.js → McpTools-CRRzPqNX.js} +3 -3
  38. package/src/assets/web-panel/assets/{Memory-CrQcFM7u.js → Memory-D6pNSkg9.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-DVnyiiU-.js → MobileBridge-g-pvtwRC.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-qjCME5OD.js → MobileProjects-Bzayfrfe.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-4JE3C3It.js → Mtc-B7S3W-XL.js} +2 -2
  42. package/src/assets/web-panel/assets/{MtcAudit-CjBuak9I.js → MtcAudit-B8OMEWVb.js} +5 -5
  43. package/src/assets/web-panel/assets/{Multisig-BtPcYQcC.js → Multisig-CowRp7GH.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-Cx653_Ba.js → NLProgramming-BkQNyi4c.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-CkuD3YzS.js → Notes-Cm7gtkKz.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-BgNgU7HH.js → NotificationSettings-CbPTVh9m.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-BTC8W0a-.js → OrderTableRenderer-Dswi26mJ.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-Dmd4Hjxz.js → Organization-BkjQ9yy7.js} +2 -2
  49. package/src/assets/web-panel/assets/{Overflow-C_5DA-G0.js → Overflow-DmRFXP7Y.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-uwslV4XC.js → P2P-DQE1toAu.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CuNgwVnX.js → PdhVaultBrowser-BujyoDRG.js} +4 -4
  52. package/src/assets/web-panel/assets/{Permissions-CJayVX9H.js → Permissions-xSjfOaiU.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-Cb05H5go.js → PersonalDataHub-B9ICLqVP.js} +4 -4
  54. package/src/assets/web-panel/assets/{Pipeline-BZlGKapZ.js → Pipeline-CUNwyN9E.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-BIzZWYzd.js → Privacy-SOoCricX.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-vEYYyQXQ.js → ProjectInit-CSaFul0F.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-MZqTy5CC.js → ProjectSettings-CueiB_oe.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-CRARUOl8.js → Projects-BOeXvU7y.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-80VAK8PX.js → Providers-CTqf_31h.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-CzRSoIwK.js → QrScannerModal-C8ZP31E9.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-BpwQ2n4C.js → QuickAsk-CPgn4713.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-BC03TZ79.js → Recommend-8_e0zw0i.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-DE59-jaa.js → RemoteSession-iT7lbGqw.js} +3 -3
  64. package/src/assets/web-panel/assets/{Reputation-DOHmeWyA.js → Reputation-B4q9SUOz.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-hc5RZl1D.js → Row-CA_nASyL.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-Cv5uMP7E.js → RssFeed-Cwb0E3yv.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-qohu7Ug0.js → Search-D9iVsOxJ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-drCPFWV5.js → Security-DPLbYchG.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-BAEgUeRy.js → Services-DGMVL_LF.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-CkJkKBlo.js → Skeleton-B_6kym0D.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-bMuKEpez.js → Skills-Ds6r0dXB.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-DxWQVHRC.js → Sla-BLHAbBhb.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-BpS8idmV.js → SpeechSettings-CZuddd14.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-BPBLlW5v.js → SyncSettings-CdBq7oSl.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-C4SLEeUh.js → Tasks-DfT60Nyl.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-r-wfU39U.js → Templates-RLfsKy2V.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-C7vjRmLN.js → Tenant-Cw8xCNLE.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-DdzeFCV2.js → Terminal-BOUkNu4f.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-CYyWN2KD.js → TimelineRenderer-CgGZWaRm.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-D8A9osUg.js → Tokens-CpwjVyir.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-DBvrNlyS.js → Trigger-DL21H-eb.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-DBVAGc7o.js → Trust-B3ffFclW.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-C1vQUCRJ.js → UkeySign-CkBeb5aI.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-BKs4dah4.js → VideoEditing-U2iVaE3r.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-ByIuj3lD.js → Wallet-CQk2wzYd.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-DYlAFCm9.js → WebAuthn-DYIuIYzT.js} +5 -5
  87. package/src/assets/web-panel/assets/{WorkflowEditor-Dwyadd0c.js → WorkflowEditor-tg1c2mZQ.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-Bm2f3s08.js → chat-CtL61spq.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-C8ORSh7V.js → colors-DKpbeo8s.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-1iVlnsM-.js → compact-item-gPZsrswt.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-CmqNyUSL.js → createContext-CfHlwzVr.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-DdqnMhzi.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-rUMaX3Ul.js → hasIn-MV47g_6X.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-CCEyz58d.js → index-6G0ETFTW.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BVtnizyC.js → index-BBw52sEl.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BIvM-uAX.js → index-BN-wxSQ8.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DvedhJeM.js → index-BOyGUuBE.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BCOhTILd.js → index-BQp5M0s1.js} +1 -1
  99. package/src/assets/web-panel/assets/index-BcK8o4ke.js +1 -0
  100. package/src/assets/web-panel/assets/{index-DVJ1uKf4.js → index-BjlPD7GO.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BQL9r73Y.js → index-C4lF-f_z.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-C5RfRciU.js → index-C6nC_DyY.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DgUE51Pz.js → index-C9RF4ieu.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CkFvuAex.js → index-C9gtY4nG.js} +3 -3
  105. package/src/assets/web-panel/assets/{index-C-J5-pGH.js → index-CB1HnbNK.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Bf1PlIHp.js → index-CRv_uMLV.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-tqTx5wXo.js → index-C_B9LiKs.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Bgw4Y2rU.js → index-Cjv0kKCU.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DJxtPFOh.js → index-CmM9jqwe.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-pHWA7bmM.js → index-CmPJpLoD.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Dsve5Gkv.js → index-CzfxTSPW.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-B59OWAs7.js → index-D1XB5-t5.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BK-RY0-7.js → index-DGtEBodr.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BC32_0xT.js → index-DIeJmlAA.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-OcbzdRpT.js → index-DMMvlLp9.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-geQinnns.js → index-DU4rZpiK.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-D98FXb0w.js → index-D_Pl1GnW.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BC8Wb6cy.js → index-Dd19vRwy.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-fPK6GFEg.js → index-Ddcpj1El.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CfiHyVyl.js → index-Df9sWKpl.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-C-ZIHi42.js → index-DfLyHCWi.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DDHk911Q.js → index-DnZ_zS1M.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BFniLMn9.js → index-DsH-i_3d.js} +1 -1
  124. package/src/assets/web-panel/assets/index-DvbAjyYI.js +1 -0
  125. package/src/assets/web-panel/assets/{index-Dcck8QfW.js → index-ExAGPAnX.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DwMdWKiF.js → index-Rb7CRMw9.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-reUHhuz8.js → index-Zvkt9xqi.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BgwLNxmr.js → index-bSFrAszw.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-C3B1S-mW.js → index-fYcS7NS0.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CTfEmKK0.js → index-srBc9U_s.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-B53c3diB.js → index-xUlgG0Xe.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-B8BrB0Ls.js → index-yxxXlqBA.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-CuA-cpkL.js → initDefaultProps-BeOZoSZ4.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-CimmE_9b.js → motion-BXE8VMKx.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-DlGlrltz.js → move-I9sdvPGX.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-CK6BJQ07.js → mtc-parser-d25zrJd0.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-BKjBfZfB.js → omit-D71V_T4e.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-B2chVYw9.js → pickAttrs-BNZKpIAR.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-BW8aLJJ3.js → placementArrow-jOcgxTTz.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-dXlPl66S.js → responsiveObserve-pta_O8AU.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-hSa89S4G.js → slide-Dlq6om7z.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-DM6KLt-s.js → statusUtils-BnkO_yRv.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-C9MQAK15.js → styleChecker-p8NfWmcG.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-BpQDpP0z.js → useFlexGapSupport-KcjZZ5U7.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-C7rtRViA.js → useFs-gqonDMWB.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-Dm15xafq.js → usePersonalDataHub-jIIfE4go.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-mEiEytw4.js → vnode-Dyo7fBrM.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-DzPxflhY.js → zoom-6l8BMg9W.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +2 -2
  151. package/src/commands/agent.js +49 -27
  152. package/src/commands/record-replay.js +772 -0
  153. package/src/commands/skill.js +3 -0
  154. package/src/data/changelog.json +13 -0
  155. package/src/lib/agent-sandbox.js +4 -8
  156. package/src/lib/agent-team/team-message-tools.js +23 -5
  157. package/src/lib/process-execution-broker/credential-transport.js +31 -0
  158. package/src/lib/process-execution-broker/index.js +74 -0
  159. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  160. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  161. package/src/lib/process-execution-broker/windows-sandbox.cs +7 -3
  162. package/src/lib/record-replay/browser-target-policy.js +406 -0
  163. package/src/lib/record-replay/index.js +4 -0
  164. package/src/lib/record-replay/playwright-ui-driver.js +83 -20
  165. package/src/lib/record-replay/playwright-ui-recorder.js +611 -0
  166. package/src/lib/record-replay/recorded-skill-package.js +486 -0
  167. package/src/lib/record-replay/recorded-skill-store.js +1166 -0
  168. package/src/lib/record-replay/skill-recorder.js +634 -64
  169. package/src/runtime/headless-runner.js +72 -51
  170. package/src/assets/web-panel/assets/MarkdownRenderer-BkrK04xW.js +0 -1
  171. package/src/assets/web-panel/assets/devWarning-B69RCDDH.js +0 -1
  172. package/src/assets/web-panel/assets/index-9biMQ-tw.js +0 -1
  173. package/src/assets/web-panel/assets/index-COie87kl.js +0 -1
@@ -58,6 +58,7 @@ import {
58
58
  removeCliPacks,
59
59
  } from "../lib/skill-packs/generator.js";
60
60
  import { CLI_PACK_DOMAINS } from "../lib/skill-packs/schema.js";
61
+ import { registerRecordReplayCommands } from "./record-replay.js";
61
62
 
62
63
  const LAYER_LABELS = {
63
64
  bundled: chalk.blue("[bundled]"),
@@ -291,6 +292,8 @@ export function registerSkillCommand(program) {
291
292
 
292
293
  const loader = new CLISkillLoader();
293
294
 
295
+ registerRecordReplayCommands(skill);
296
+
294
297
  // skill list
295
298
  skill
296
299
  .command("list")
@@ -1,6 +1,19 @@
1
1
  {
2
2
  "source": "CHANGELOG.md",
3
3
  "releases": [
4
+ {
5
+ "productVersion": null,
6
+ "cliVersion": "0.166.14",
7
+ "cliVersions": ["0.166.13", "0.166.14"],
8
+ "date": "2026-08-30",
9
+ "title": "",
10
+ "sections": [
11
+ {
12
+ "heading": "Fixed - cc CLI 0.166.14: restore Docker-optional startup on Windows",
13
+ "body": "> `chainlesschain` **0.166.13 -> 0.166.14** (hotfix candidate, 2026-08-30).\n\n- **Docker remains opt-in**: a normal agent session no longer probes or\n requires Docker unless the CLI flag, settings, or managed policy explicitly\n selects container isolation.\n- **Windows executable lookup**: bare commands resolve through `PATHEXT`\n before launch, so Docker Desktop's POSIX `docker` script cannot shadow\n `docker.exe` and trigger `CreateProcessAsUser` error 193.\n- **Explicit isolation stays fail-closed**: `workspace-write`, `strict`, and\n managed sandbox requirements still reject unavailable engines instead of\n silently degrading."
14
+ }
15
+ ]
16
+ },
4
17
  {
5
18
  "productVersion": null,
6
19
  "cliVersion": "0.166.13",
@@ -259,14 +259,10 @@ export function normalizeAgentSandbox(value, options = {}) {
259
259
  */
260
260
  export function normalizeAgentSandboxMode(mode, value, options = {}) {
261
261
  if (mode == null || mode === "") {
262
- // Public agent execution defaults to a real, fail-closed workspace
263
- // sandbox with networking disabled. Bare-host execution remains available
264
- // only through the explicit `off` mode below, where managed policy can
265
- // prohibit it and the CLI records a high-risk security event.
266
- return normalizeAgentSandboxMode("workspace-write", value || true, {
267
- ...options,
268
- network: false,
269
- });
262
+ // Keep the container sandbox opt-in unless CLI/settings policy explicitly
263
+ // enables it. The platform process broker still applies its native
264
+ // boundary, but starting a normal agent must not require Docker.
265
+ return normalizeAgentSandbox(value, options);
270
266
  }
271
267
  if (!AGENT_SANDBOX_MODES.includes(mode)) {
272
268
  const error = new Error(
@@ -5,6 +5,7 @@ import {
5
5
  TEAM_MESSAGE_BRIDGE_MAX_WAIT_MS,
6
6
  TEAM_MESSAGE_BRIDGE_PROTOCOL,
7
7
  } from "./team-message-bridge.js";
8
+ import { resolveCredentialEnvironmentValue } from "../process-execution-broker/credential-transport.js";
8
9
 
9
10
  export const TEAM_MESSAGE_TOOL_NAMES = Object.freeze([
10
11
  "team_send",
@@ -177,21 +178,38 @@ function descriptor(name) {
177
178
  });
178
179
  }
179
180
 
180
- export function resolveTeamMessageToolBundle({
181
+ export async function resolveTeamMessageToolBundle({
181
182
  env = process.env,
182
183
  call = callTeamMessageBridge,
184
+ resolveCredential = resolveCredentialEnvironmentValue,
183
185
  } = {}) {
184
186
  const endpoint = env.CC_TEAM_MESSAGE_BRIDGE_ENDPOINT;
185
- const token = env.CC_TEAM_MESSAGE_BRIDGE_TOKEN;
187
+ const tokenReference = env.CC_CRED_REF_CC_TEAM_MESSAGE_BRIDGE_TOKEN;
186
188
  const protocol = Number(env.CC_TEAM_MESSAGE_BRIDGE_PROTOCOL);
187
- if (!endpoint && !token && !env.CC_TEAM_MESSAGE_BRIDGE_PROTOCOL) return null;
189
+ if (
190
+ !endpoint &&
191
+ !env.CC_TEAM_MESSAGE_BRIDGE_TOKEN &&
192
+ !tokenReference &&
193
+ !env.CC_TEAM_MESSAGE_BRIDGE_PROTOCOL
194
+ ) {
195
+ return null;
196
+ }
188
197
  if (
189
198
  typeof endpoint !== "string" ||
190
199
  !endpoint ||
200
+ protocol !== TEAM_MESSAGE_BRIDGE_PROTOCOL
201
+ ) {
202
+ const error = new Error("Team message bridge environment is invalid");
203
+ error.code = "TEAM_MESSAGE_BRIDGE_CONFIG_INVALID";
204
+ throw error;
205
+ }
206
+ const token = await resolveCredential("CC_TEAM_MESSAGE_BRIDGE_TOKEN", {
207
+ env,
208
+ });
209
+ if (
191
210
  typeof token !== "string" ||
192
211
  token.length !== 64 ||
193
- !/^[a-f0-9]{64}$/u.test(token) ||
194
- protocol !== TEAM_MESSAGE_BRIDGE_PROTOCOL
212
+ !/^[a-f0-9]{64}$/u.test(token)
195
213
  ) {
196
214
  const error = new Error("Team message bridge environment is invalid");
197
215
  error.code = "TEAM_MESSAGE_BRIDGE_CONFIG_INVALID";
@@ -375,4 +375,35 @@ export async function resolveCredentialRefOverTransport(refId, options = {}) {
375
375
  });
376
376
  }
377
377
 
378
+ /**
379
+ * Resolve one named environment credential without copying plaintext back into
380
+ * process.env. Direct launches keep accepting the original environment value;
381
+ * brokered launches exchange the short-lived, target-bound reference that the
382
+ * ProcessExecutionBroker placed in CC_CRED_REF_<NAME>.
383
+ */
384
+ export async function resolveCredentialEnvironmentValue(key, options = {}) {
385
+ if (!/^[A-Z][A-Z0-9_]*$/u.test(String(key || ""))) {
386
+ throw transportError(
387
+ "CC_CREDENTIAL_INVALID_REQUEST",
388
+ "Credential environment key is invalid",
389
+ );
390
+ }
391
+ const env = options.env || process.env;
392
+ const value = env[key];
393
+ const refId = env[`CC_CRED_REF_${key}`];
394
+ const hasValue = typeof value === "string" && value.length > 0;
395
+ const hasReference = typeof refId === "string" && refId.length > 0;
396
+ if (hasValue && hasReference) {
397
+ throw transportError(
398
+ "CC_CREDENTIAL_INVALID_REQUEST",
399
+ "Credential environment contains both plaintext and a broker reference",
400
+ );
401
+ }
402
+ if (hasValue) return value;
403
+ if (!hasReference) return null;
404
+ const resolveReference =
405
+ options.resolveReference || resolveCredentialRefOverTransport;
406
+ return await resolveReference(refId, { env });
407
+ }
408
+
378
409
  export { TRANSPORT_VERSION };
@@ -29,6 +29,7 @@ import path from "node:path";
29
29
  import * as fs from "node:fs";
30
30
  import * as tty from "node:tty";
31
31
  import { createRequire } from "node:module";
32
+ import { AsyncLocalStorage } from "node:async_hooks";
32
33
 
33
34
  const require = createRequire(import.meta.url);
34
35
 
@@ -996,6 +997,7 @@ class ProcessExecutionBroker extends EventEmitter {
996
997
  this._ptyAdapter = createNativePtyAdapter();
997
998
  this._hooksEventSink = null;
998
999
  this._workspaceTransactionManagers = new Map();
1000
+ this._ambientProcessContext = new AsyncLocalStorage();
999
1001
 
1000
1002
  this._ensureLogDir();
1001
1003
  this._loadPermissions();
@@ -1029,6 +1031,76 @@ class ProcessExecutionBroker extends EventEmitter {
1029
1031
  return "prompt";
1030
1032
  }
1031
1033
 
1034
+ _withAmbientProcessContext(command, options = {}) {
1035
+ const context = this._ambientProcessContext.getStore();
1036
+ if (!context) return options;
1037
+ const commandIdentity = (() => {
1038
+ if (typeof command !== "string" || !command) return "";
1039
+ const normalized = path.isAbsolute(command)
1040
+ ? path.resolve(command)
1041
+ : command;
1042
+ return process.platform === "win32"
1043
+ ? normalized.toLowerCase()
1044
+ : normalized;
1045
+ })();
1046
+ const allowed = context.allowedCommands.includes(commandIdentity);
1047
+ return {
1048
+ ...options,
1049
+ origin: context.origin,
1050
+ scope: context.scope,
1051
+ policy: allowed ? context.policy : "deny",
1052
+ auditContext: context.auditContext,
1053
+ };
1054
+ }
1055
+
1056
+ runWithProcessContext(
1057
+ {
1058
+ origin,
1059
+ policy = "allow",
1060
+ scope = "default",
1061
+ allowedCommands = [],
1062
+ auditContext,
1063
+ } = {},
1064
+ operation,
1065
+ ) {
1066
+ const safeOrigin = String(origin || "");
1067
+ if (
1068
+ !/^[A-Za-z][A-Za-z0-9:._-]{0,127}$/u.test(safeOrigin) ||
1069
+ !["allow", "deny", "prompt"].includes(policy) ||
1070
+ typeof operation !== "function" ||
1071
+ !Array.isArray(allowedCommands) ||
1072
+ allowedCommands.length < 1 ||
1073
+ allowedCommands.length > 16
1074
+ ) {
1075
+ const error = new Error("Process execution context is invalid");
1076
+ error.code = "PROCESS_CONTEXT_INVALID";
1077
+ throw error;
1078
+ }
1079
+ const normalizedCommands = allowedCommands.map((command) => {
1080
+ if (typeof command !== "string" || !path.isAbsolute(command)) {
1081
+ const error = new Error(
1082
+ "Process execution context commands must be absolute paths",
1083
+ );
1084
+ error.code = "PROCESS_CONTEXT_INVALID";
1085
+ throw error;
1086
+ }
1087
+ const normalized = path.resolve(command);
1088
+ return process.platform === "win32"
1089
+ ? normalized.toLowerCase()
1090
+ : normalized;
1091
+ });
1092
+ return this._ambientProcessContext.run(
1093
+ Object.freeze({
1094
+ origin: safeOrigin,
1095
+ policy,
1096
+ scope: String(scope || "default").slice(0, 128),
1097
+ allowedCommands: Object.freeze([...new Set(normalizedCommands)]),
1098
+ auditContext,
1099
+ }),
1100
+ operation,
1101
+ );
1102
+ }
1103
+
1032
1104
  _isDangerousCommand(command) {
1033
1105
  if (typeof command !== "string") return false;
1034
1106
  const lower = command.toLowerCase();
@@ -4470,6 +4542,7 @@ class ProcessExecutionBroker extends EventEmitter {
4470
4542
  }
4471
4543
 
4472
4544
  spawn(command, args, options = {}) {
4545
+ options = this._withAmbientProcessContext(command, options);
4473
4546
  const executionId = crypto.randomUUID();
4474
4547
  const startTime = Date.now();
4475
4548
  const origin = options.origin || "unknown";
@@ -4857,6 +4930,7 @@ class ProcessExecutionBroker extends EventEmitter {
4857
4930
  }
4858
4931
 
4859
4932
  spawnSync(command, args, options = {}) {
4933
+ options = this._withAmbientProcessContext(command, options);
4860
4934
  const executionId = crypto.randomUUID();
4861
4935
  const startTime = Date.now();
4862
4936
  const origin = options.origin || "unknown";
@@ -1683,8 +1683,12 @@ namespace ChainlessChain.WindowsSandbox
1683
1683
  string[] configured = pathExt.Split(
1684
1684
  new[] { ';' },
1685
1685
  StringSplitOptions.RemoveEmptyEntries);
1686
- extensions = new string[configured.Length + 1];
1687
- extensions[0] = String.Empty;
1686
+ // Match Windows command lookup: a bare command name is
1687
+ // resolved through PATHEXT. Trying an extensionless file first
1688
+ // can select Docker's adjacent POSIX `docker` shell script
1689
+ // instead of docker.exe, which CreateProcessAsUser rejects
1690
+ // with ERROR_BAD_EXE_FORMAT (193).
1691
+ extensions = new string[configured.Length];
1688
1692
  for (int index = 0; index < configured.Length; index++)
1689
1693
  {
1690
1694
  string extension = configured[index].Trim();
@@ -1697,7 +1701,7 @@ namespace ChainlessChain.WindowsSandbox
1697
1701
  throw new InvalidDataException(
1698
1702
  "Target PATHEXT contains an invalid extension");
1699
1703
  }
1700
- extensions[index + 1] = extension;
1704
+ extensions[index] = extension;
1701
1705
  }
1702
1706
  }
1703
1707
 
@@ -0,0 +1,406 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ const MAX_HTML_CHARS = 1_000_000;
4
+ const MAX_ALLOWED_ORIGINS = 8;
5
+ const MAX_URL_CHARS = 4_096;
6
+ const MAX_STORAGE_STATE_BYTES = 2 * 1024 * 1024;
7
+ const MAX_STORAGE_STATE_DEPTH = 16;
8
+ const MAX_STORAGE_STATE_NODES = 10_000;
9
+ const SHA256_PATTERN = /^sha256:[a-f0-9]{64}$/u;
10
+
11
+ function targetError(code, message) {
12
+ const error = new Error(message);
13
+ error.name = "RecordedSkillBrowserTargetError";
14
+ error.code = code;
15
+ return error;
16
+ }
17
+
18
+ function canonicalValue(value) {
19
+ if (Array.isArray(value)) return value.map(canonicalValue);
20
+ if (!value || typeof value !== "object") return value;
21
+ return Object.fromEntries(
22
+ Object.keys(value)
23
+ .sort()
24
+ .map((key) => [key, canonicalValue(value[key])]),
25
+ );
26
+ }
27
+
28
+ function deepFreeze(value) {
29
+ if (!value || typeof value !== "object" || Object.isFrozen(value))
30
+ return value;
31
+ for (const child of Object.values(value)) deepFreeze(child);
32
+ return Object.freeze(value);
33
+ }
34
+
35
+ function boundedCanonicalStorageState(value) {
36
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
37
+ throw targetError(
38
+ "CC_RECORD_TARGET_INVALID",
39
+ "browser storage state must be a JSON object",
40
+ );
41
+ }
42
+ const seen = new WeakSet();
43
+ const pending = [{ value, depth: 0 }];
44
+ let nodes = 0;
45
+ while (pending.length > 0) {
46
+ const current = pending.pop();
47
+ const item = current.value;
48
+ nodes += 1;
49
+ if (
50
+ nodes > MAX_STORAGE_STATE_NODES ||
51
+ current.depth > MAX_STORAGE_STATE_DEPTH
52
+ ) {
53
+ throw targetError(
54
+ "CC_RECORD_TARGET_INVALID",
55
+ "browser storage state exceeds its structural limits",
56
+ );
57
+ }
58
+ if (!item || typeof item !== "object") {
59
+ if (
60
+ typeof item === "undefined" ||
61
+ typeof item === "bigint" ||
62
+ typeof item === "function" ||
63
+ typeof item === "symbol" ||
64
+ (typeof item === "number" && !Number.isFinite(item))
65
+ ) {
66
+ throw targetError(
67
+ "CC_RECORD_TARGET_INVALID",
68
+ "browser storage state must contain only JSON values",
69
+ );
70
+ }
71
+ continue;
72
+ }
73
+ if (seen.has(item)) {
74
+ throw targetError(
75
+ "CC_RECORD_TARGET_INVALID",
76
+ "browser storage state must not contain cycles or shared objects",
77
+ );
78
+ }
79
+ seen.add(item);
80
+ if (
81
+ !Array.isArray(item) &&
82
+ Object.getPrototypeOf(item) !== Object.prototype
83
+ ) {
84
+ throw targetError(
85
+ "CC_RECORD_TARGET_INVALID",
86
+ "browser storage state must contain plain JSON objects",
87
+ );
88
+ }
89
+ const children = Array.isArray(item) ? item : Object.values(item);
90
+ if (children.length > MAX_STORAGE_STATE_NODES) {
91
+ throw targetError(
92
+ "CC_RECORD_TARGET_INVALID",
93
+ "browser storage state exceeds its structural limits",
94
+ );
95
+ }
96
+ for (const child of children) {
97
+ pending.push({ value: child, depth: current.depth + 1 });
98
+ }
99
+ }
100
+ const canonical = canonicalValue(value);
101
+ if (
102
+ Buffer.byteLength(JSON.stringify(canonical), "utf8") >
103
+ MAX_STORAGE_STATE_BYTES
104
+ ) {
105
+ throw targetError(
106
+ "CC_RECORD_TARGET_INVALID",
107
+ "browser storage state exceeds the 2 MiB limit",
108
+ );
109
+ }
110
+ return deepFreeze(canonical);
111
+ }
112
+
113
+ function digest(value, domain) {
114
+ const bytes = Buffer.isBuffer(value)
115
+ ? value
116
+ : Buffer.from(
117
+ typeof value === "string"
118
+ ? value
119
+ : JSON.stringify(canonicalValue(value)),
120
+ );
121
+ return `sha256:${createHash("sha256")
122
+ .update(domain)
123
+ .update("\0")
124
+ .update(bytes)
125
+ .digest("hex")}`;
126
+ }
127
+
128
+ function isLoopback(hostname) {
129
+ const normalized = String(hostname || "").toLowerCase();
130
+ return (
131
+ normalized === "localhost" ||
132
+ normalized === "127.0.0.1" ||
133
+ normalized === "[::1]" ||
134
+ normalized === "::1"
135
+ );
136
+ }
137
+
138
+ function safeUrl(value, { originOnly = false } = {}) {
139
+ if (
140
+ typeof value !== "string" ||
141
+ value.length < 1 ||
142
+ value.length > MAX_URL_CHARS
143
+ ) {
144
+ throw targetError(
145
+ "CC_RECORD_TARGET_INVALID",
146
+ `browser target URL must be no longer than ${MAX_URL_CHARS} characters`,
147
+ );
148
+ }
149
+ let parsed;
150
+ try {
151
+ parsed = new URL(String(value));
152
+ } catch {
153
+ throw targetError(
154
+ "CC_RECORD_TARGET_INVALID",
155
+ "browser target must be an absolute URL",
156
+ );
157
+ }
158
+ if (
159
+ parsed.username ||
160
+ parsed.password ||
161
+ (parsed.protocol !== "https:" &&
162
+ !(parsed.protocol === "http:" && isLoopback(parsed.hostname)))
163
+ ) {
164
+ throw targetError(
165
+ "CC_RECORD_TARGET_INVALID",
166
+ "browser targets require HTTPS; HTTP is allowed only for loopback testing and URL credentials are forbidden",
167
+ );
168
+ }
169
+ if (originOnly && parsed.href !== `${parsed.origin}/`) {
170
+ throw targetError(
171
+ "CC_RECORD_TARGET_INVALID",
172
+ "allowed origins must not contain a path, query, or fragment",
173
+ );
174
+ }
175
+ return parsed;
176
+ }
177
+
178
+ export function createRecordedSkillNetworkPolicy({
179
+ mode = "deny",
180
+ allowedOrigins = [],
181
+ } = {}) {
182
+ if (mode === "deny") {
183
+ if (!Array.isArray(allowedOrigins) || allowedOrigins.length > 0) {
184
+ throw targetError(
185
+ "CC_RECORD_TARGET_INVALID",
186
+ "deny network policy cannot retain allowed origins",
187
+ );
188
+ }
189
+ const body = { mode: "deny", allowedOrigins: [] };
190
+ return deepFreeze({
191
+ ...body,
192
+ digest: digest(body, "cc.record-replay.network-policy/v1"),
193
+ });
194
+ }
195
+ if (mode !== "allowlist" || !Array.isArray(allowedOrigins)) {
196
+ throw targetError(
197
+ "CC_RECORD_TARGET_INVALID",
198
+ "browser network policy is invalid",
199
+ );
200
+ }
201
+ const origins = [
202
+ ...new Set(
203
+ allowedOrigins.map(
204
+ (value) => safeUrl(value, { originOnly: true }).origin,
205
+ ),
206
+ ),
207
+ ].sort();
208
+ if (origins.length < 1 || origins.length > MAX_ALLOWED_ORIGINS) {
209
+ throw targetError(
210
+ "CC_RECORD_TARGET_INVALID",
211
+ `browser target requires between 1 and ${MAX_ALLOWED_ORIGINS} allowed origins`,
212
+ );
213
+ }
214
+ const body = { mode: "allowlist", allowedOrigins: origins };
215
+ return deepFreeze({
216
+ ...body,
217
+ digest: digest(body, "cc.record-replay.network-policy/v1"),
218
+ });
219
+ }
220
+
221
+ export function digestRecordedSkillStorageState(storageState) {
222
+ if (storageState == null) return null;
223
+ return digest(
224
+ boundedCanonicalStorageState(storageState),
225
+ "cc.record-replay.browser-storage-state/v1",
226
+ );
227
+ }
228
+
229
+ export function prepareRecordedSkillBrowserTarget({
230
+ html,
231
+ url,
232
+ allowedOrigins = [],
233
+ storageState,
234
+ identity = "anonymous",
235
+ } = {}) {
236
+ const hasHtml = typeof html === "string" && html.length > 0;
237
+ const hasUrl = typeof url === "string" && url.length > 0;
238
+ if (hasHtml === hasUrl) {
239
+ throw targetError(
240
+ "CC_RECORD_TARGET_INVALID",
241
+ "provide exactly one self-contained HTML fixture or URL target",
242
+ );
243
+ }
244
+ const safeIdentity = String(identity || "anonymous").trim();
245
+ if (!/^[A-Za-z][A-Za-z0-9._-]{0,127}$/u.test(safeIdentity)) {
246
+ throw targetError(
247
+ "CC_RECORD_TARGET_INVALID",
248
+ "browser identity label is invalid",
249
+ );
250
+ }
251
+ if (hasHtml) {
252
+ if (
253
+ html.length > MAX_HTML_CHARS ||
254
+ allowedOrigins.length > 0 ||
255
+ storageState != null
256
+ ) {
257
+ throw targetError(
258
+ "CC_RECORD_TARGET_INVALID",
259
+ "self-contained HTML recording cannot use network origins or browser credentials",
260
+ );
261
+ }
262
+ const networkPolicy = createRecordedSkillNetworkPolicy({ mode: "deny" });
263
+ return deepFreeze({
264
+ adapter: "self-contained-html",
265
+ html,
266
+ url: null,
267
+ targetDigest: digest(html, "cc.record-replay.ui-fixture/v1"),
268
+ networkPolicy,
269
+ storageState: null,
270
+ storageStateDigest: null,
271
+ identity: safeIdentity,
272
+ });
273
+ }
274
+ const target = safeUrl(url);
275
+ const networkPolicy = createRecordedSkillNetworkPolicy({
276
+ mode: "allowlist",
277
+ allowedOrigins:
278
+ allowedOrigins.length > 0 ? allowedOrigins : [target.origin],
279
+ });
280
+ if (!networkPolicy.allowedOrigins.includes(target.origin)) {
281
+ throw targetError(
282
+ "CC_RECORD_TARGET_INVALID",
283
+ "target origin must be present in the network allowlist",
284
+ );
285
+ }
286
+ const normalizedStorageState =
287
+ storageState == null ? null : boundedCanonicalStorageState(storageState);
288
+ return deepFreeze({
289
+ adapter: "url-origin",
290
+ html: null,
291
+ url: target.href,
292
+ targetDigest: digest(target.href, "cc.record-replay.ui-url/v1"),
293
+ networkPolicy,
294
+ storageState: normalizedStorageState,
295
+ storageStateDigest: digestRecordedSkillStorageState(normalizedStorageState),
296
+ identity: safeIdentity,
297
+ });
298
+ }
299
+
300
+ export function recordedSkillBrowserEnvironment(target) {
301
+ if (
302
+ !target ||
303
+ !["self-contained-html", "url-origin"].includes(target.adapter) ||
304
+ !SHA256_PATTERN.test(String(target.targetDigest || ""))
305
+ ) {
306
+ throw targetError(
307
+ "CC_RECORD_TARGET_INVALID",
308
+ "prepared browser target is invalid",
309
+ );
310
+ }
311
+ return deepFreeze({
312
+ adapter: target.adapter,
313
+ browser: "chromium",
314
+ targetDigest: target.targetDigest,
315
+ selectorContract: "record-replay-dom-v1",
316
+ networkPolicy: Object.freeze({
317
+ mode: target.networkPolicy.mode,
318
+ allowedOrigins: Object.freeze([...target.networkPolicy.allowedOrigins]),
319
+ digest: target.networkPolicy.digest,
320
+ }),
321
+ identity: target.identity,
322
+ storageStateDigest: target.storageStateDigest,
323
+ });
324
+ }
325
+
326
+ export function assertRecordedSkillBrowserBinding(
327
+ target,
328
+ { source, environment } = {},
329
+ ) {
330
+ let reviewedPolicy;
331
+ try {
332
+ reviewedPolicy = createRecordedSkillNetworkPolicy({
333
+ mode: environment?.networkPolicy?.mode,
334
+ allowedOrigins: environment?.networkPolicy?.allowedOrigins || [],
335
+ });
336
+ } catch {
337
+ reviewedPolicy = null;
338
+ }
339
+ if (
340
+ !source ||
341
+ target?.adapter !== source.adapter ||
342
+ target?.targetDigest !== source.targetDigest ||
343
+ environment?.adapter !== source.adapter ||
344
+ environment?.targetDigest !== source.targetDigest
345
+ ) {
346
+ throw targetError(
347
+ "CC_RECORD_TARGET_DRIFT",
348
+ "browser target no longer matches the reviewed recording",
349
+ );
350
+ }
351
+ if (
352
+ (environment.storageStateDigest || null) !==
353
+ (target.storageStateDigest || null)
354
+ ) {
355
+ throw targetError(
356
+ "CC_RECORD_CREDENTIAL_DRIFT",
357
+ "browser storage state no longer matches the reviewed credential binding",
358
+ );
359
+ }
360
+ if (
361
+ environment.identity !== target.identity ||
362
+ reviewedPolicy?.digest !== environment.networkPolicy?.digest ||
363
+ reviewedPolicy?.digest !== target.networkPolicy?.digest
364
+ ) {
365
+ throw targetError(
366
+ "CC_RECORD_ENVIRONMENT_DRIFT",
367
+ "browser identity or network policy no longer matches the reviewed recording",
368
+ );
369
+ }
370
+ return true;
371
+ }
372
+
373
+ export function requestAllowedByRecordedSkillPolicy(rawUrl, target) {
374
+ let parsed;
375
+ try {
376
+ parsed = new URL(String(rawUrl));
377
+ } catch {
378
+ return false;
379
+ }
380
+ if (["about:", "data:"].includes(parsed.protocol)) return true;
381
+ if (parsed.protocol === "blob:") {
382
+ return (
383
+ target.networkPolicy.mode === "allowlist" &&
384
+ target.networkPolicy.allowedOrigins.includes(parsed.origin)
385
+ );
386
+ }
387
+ if (!["http:", "https:"].includes(parsed.protocol)) return false;
388
+ return (
389
+ target.networkPolicy.mode === "allowlist" &&
390
+ target.networkPolicy.allowedOrigins.includes(parsed.origin)
391
+ );
392
+ }
393
+
394
+ export function navigationAllowedByRecordedSkillPolicy(rawUrl, target) {
395
+ let parsed;
396
+ try {
397
+ parsed = new URL(String(rawUrl));
398
+ } catch {
399
+ return false;
400
+ }
401
+ return (
402
+ ["http:", "https:"].includes(parsed.protocol) &&
403
+ target.networkPolicy.mode === "allowlist" &&
404
+ target.networkPolicy.allowedOrigins.includes(parsed.origin)
405
+ );
406
+ }
@@ -1,2 +1,6 @@
1
1
  export * from "./skill-recorder.js";
2
2
  export * from "./playwright-ui-driver.js";
3
+ export * from "./playwright-ui-recorder.js";
4
+ export * from "./recorded-skill-store.js";
5
+ export * from "./recorded-skill-package.js";
6
+ export * from "./browser-target-policy.js";