chainlesschain 0.166.103 → 0.166.105

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 (183) hide show
  1. package/README.md +14 -2
  2. package/package.json +2 -1
  3. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  4. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  5. package/src/assets/web-panel/assets/{AIOps-BLrXpdnP.js → AIOps-CcD-AVDw.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-C0xy9uFy.js → ActionButton-CYy-g36A.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-C6EephQP.js → Analytics-DPFDNaBL.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-ZCXdOD9y.js → AppLayout-PVIuRdgN.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-D4MfZ-pl.js → Artifacts-BXGD3bM-.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-BQ8c3bBu.js → Audit-Bu5s_4tu.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-BOA7_ljM.js → BackgroundAgents-BHmgpnzo.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-60uiQjGT.js → Backup-C872jURx.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-BDvEbGs_.js → BaseInput-Bh7xO30H.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-B3IkAuFQ.js → Chat-DaacK53T.js} +6 -6
  15. package/src/assets/web-panel/assets/ChatBubbleRenderer-PYrSKMM_.js +1 -0
  16. package/src/assets/web-panel/assets/{Checkbox-njGbfJWq.js → Checkbox-Cnt7_8I2.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-CF7DtdxC.js → Codegen-AZRz6kmW.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-C_3Zix40.js → Col-BtOXzMFt.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-CzU-ZC2d.js → Community-BFmFygS7.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-BgeqsPRh.js → Compact-2z5CfKpR.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-6l7cwiqp.js → Compliance-B5hKrPVF.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-D4s905fI.js → Cowork-CxEyp2ww.js} +3 -3
  23. package/src/assets/web-panel/assets/{Cron-CGTYSxRS.js → Cron-B-8f9_qF.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-BnSo-Yt3.js → Crosschain-XARMOcc4.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-Dm4vk2X1.js → DID-DwLtEKAe.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-D7H-PZ_N.js → Dashboard-Cjw0L_iA.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-COslkgxn.js → Dropdown-BBGWIP7l.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-CJWEetmk.js → EmailListRenderer-DG4kZFkm.js} +1 -1
  29. package/src/assets/web-panel/assets/{EvolutionSettings-BbzebAWe.js → EvolutionSettings-D8vuNDde.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BsoTOXwk.js → FamilyGuardDashboard-COXCzDXI.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-Ck5kM_5H.js → Federation-Btb-aMhW.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-gShxCqtF.js → FormItemContext-TO-E6l6e.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-DarN1G-z.js → GenericCardRenderer-BWXdJCT0.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-CJfpLyP5.js → Git-B6icGhEv.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-CVcJmpQz.js → Governance-C5Y__K6S.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-ComU_ig8.js → Inference-DZGEKnbN.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-35hprFJy.js → KnowledgeGraph--Kga5yvm.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-BQDqBTz0.js → Logs-BXs3EPKj.js} +2 -2
  39. package/src/assets/web-panel/assets/MarkdownRenderer-BsSiyE-A.js +1 -0
  40. package/src/assets/web-panel/assets/{Marketplace-B9O9OKnn.js → Marketplace-JSEAu0su.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-VMKxA4Wc.js → McpTools-BUBifkKP.js} +3 -3
  42. package/src/assets/web-panel/assets/{Memory-CcBbf3Bc.js → Memory-Cb7sE4a-.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-D7myz46N.js → MobileBridge-BOzmmNV2.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-Da5KBXyx.js → MobileProjects-ClRlavdF.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-x3NPZfuL.js → Mtc-DmMWErG1.js} +5 -5
  46. package/src/assets/web-panel/assets/{MtcAudit-CwnzptEC.js → MtcAudit-DnGkRVXF.js} +2 -2
  47. package/src/assets/web-panel/assets/{Multisig-CCAxf4Ye.js → Multisig-C3mzascL.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-CptHKz-Q.js → NLProgramming-CrmMZZ1t.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-0uEp4DCJ.js → Notes-4S6uts9Q.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-DthvrOLd.js → NotificationSettings-gn3UrWwW.js} +1 -1
  51. package/src/assets/web-panel/assets/OrderTableRenderer-CDVAlBUf.js +1 -0
  52. package/src/assets/web-panel/assets/{Organization-BWf2tmQQ.js → Organization-fMlkdgpW.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-BbvAtEth.js → Overflow-DGwCUPU1.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-zBo6enit.js → P2P-BDGcpPmf.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-D_LMQ4A4.js → PdhVaultBrowser-CccRPAB9.js} +3 -3
  56. package/src/assets/web-panel/assets/{Permissions-C1ucb2ck.js → Permissions-C33dNECx.js} +4 -4
  57. package/src/assets/web-panel/assets/{PersonalDataHub-Bz64RddJ.js → PersonalDataHub-BeqbCStc.js} +5 -5
  58. package/src/assets/web-panel/assets/{Pipeline-DXJt3y3_.js → Pipeline-CTmasgbQ.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-DiZ8b_ut.js → Privacy-ktd37BSp.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-DfLKKrJ4.js → ProjectInit-KOGvQtBX.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-Ct6kJuIY.js → ProjectSettings-CUvH_hC6.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-BBUMlZ3m.js → Projects-BvP_Os-1.js} +1 -1
  63. package/src/assets/web-panel/assets/{Providers-DYVQPHvc.js → Providers-C-hmLXlO.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-23Il7iPp.js → QrScannerModal-DzG_rbSL.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-WgOZKrv1.js → QuickAsk-ShwiATg4.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-CRIka6xT.js → Recommend-DkV8Ruep.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-DOy3GjVZ.js → RemoteSession-Ca2dOx_G.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-BXyi6xeR.js → Reputation-DYA5BJ6A.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-CoMxuIcR.js → Row-DvGDgxLS.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-87hPkoM6.js → RssFeed-DbwTBSPw.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-B1EqFCO4.js → Search-C5XAMQ9T.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-HcC41eGs.js → Security-CKWT60Qt.js} +3 -3
  73. package/src/assets/web-panel/assets/{Services-BqLwmvCM.js → Services-CZvASlWL.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-CIMmjW4r.js → Skeleton-DFkMVqws.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-CgurezJU.js → Skills-hslZ_GyP.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-CJuRuqPE.js → Sla-BLW5rmZ5.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-BUwsbd1o.js → SpeechSettings-Cn4ffCi5.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-qo04TOX-.js → SyncSettings-D1K0nJuo.js} +2 -2
  79. package/src/assets/web-panel/assets/Tasks-CCRu0xoN.js +1 -0
  80. package/src/assets/web-panel/assets/{Templates-D1PTczPW.js → Templates-L19GYuS4.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-Bi0FkEPR.js → Tenant-CZ6HE3PF.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-DfSt3bIF.js → Terminal-BiAwzaBT.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-B7bIVs4R.js → TimelineRenderer-DRHSWQT5.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-B6w5XrMb.js → Tokens-Cm-XATgh.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-XXVSDWiF.js → Trigger-BVXtx3kn.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-DYvlgcK-.js → Trust-Bb0TmkLJ.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-XyYwJMBM.js → UkeySign-Dbt9R7l0.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-C47WbtHH.js → VideoEditing-z0-Ti8eJ.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-CYfqTj_C.js → Wallet-BZh31tI-.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-3AduFn1l.js → WebAuthn-DQ0yIr5K.js} +4 -4
  91. package/src/assets/web-panel/assets/{WorkflowEditor-DHYEHjMJ.js → WorkflowEditor-DCt_yuWG.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-AeehErSw.js → chat-BLgtmFeS.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-DKXJ8paX.js → colors-xU4UH8M1.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-BOlCiomD.js → compact-item-C4w4v16T.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-BAP6U85b.js → createContext-CZM9hAaj.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-BZUZgMkO.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-BLmeL1Xe.js → hasIn-DvHqEpE7.js} +1 -1
  98. package/src/assets/web-panel/assets/index--_-pNhk0.js +1 -0
  99. package/src/assets/web-panel/assets/{index-wyKpTsGM.js → index-55Rkd1KA.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CaHhfpBi.js → index-B0IvKEVO.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-EKNODw4P.js → index-B4jIcYSv.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-C5AKY6bJ.js → index-B64Vf-8H.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-C8qi53Ki.js → index-B6AQ2b5U.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-FPXLIXoy.js → index-BHK3CQHq.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CRa4pAaM.js → index-BHg9NoJ5.js} +3 -3
  106. package/src/assets/web-panel/assets/{index-Bn54FU3i.js → index-BIWumeQl.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CdNSmvog.js → index-BRhD9RMV.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-De2fPxdb.js → index-BTxhDCtg.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CgtaOzMo.js → index-BaQZvM4m.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CFKzWIo8.js → index-Bf8Wm4ks.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-OLKhib9T.js → index-Bh14b1k0.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-B0IjlB9m.js → index-BkTKWAgq.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-PEe9OWEQ.js → index-BlN5KPq6.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DpZqbc4w.js → index-C6ZrTSw5.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Bpx54vfs.js → index-C9YnZFv2.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DsQ38fVY.js → index-CExiTobS.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BTnp4Nt3.js → index-CF9ebAIB.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BuUwKmEI.js → index-CKugxsw3.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-IlzfIRNh.js → index-CPC7OGCe.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BSOenF5s.js → index-CPDw21XY.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-T28naovw.js → index-CQEzxnYS.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DWYqOI1A.js → index-CRLP56-W.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-ZMbXl5lo.js → index-CYrQnkqA.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DQLQuwpA.js → index-Cm00787d.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Co7pjF53.js → index-CpiuuIww.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-urPvyUVk.js → index-CqDiY-jl.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BhcpWl5z.js → index-CyV8fNBg.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BAS2QqLn.js → index-DGdLkss8.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BRcJlKSa.js → index-DifMvnMQ.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dv8-g1pY.js → index-Ds1tM734.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DE7cbDDe.js → index-Ds6wKTMh.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-Bt-FCVzh.js → index-QHmhwgfc.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-Bs2O3f81.js → index-SNV95Zen.js} +1 -1
  134. package/src/assets/web-panel/assets/index-ftwO31cp.js +1 -0
  135. package/src/assets/web-panel/assets/{index-ClpwxOXo.js → index-n6SAUmmI.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-CiqeF0Pf.js → index-wYRjvvbl.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-CDWa1rnn.js → initDefaultProps-C44ZER6c.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-CX2Cnsd5.js → motion-DbNzzScd.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-Bfe1NcEF.js → move-BrRrDH2u.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-DbdqleHE.js → mtc-parser-DZ_T_Pw8.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-CE2K7NVv.js → omit-5QHHk_V3.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-y_bZgxWG.js → pickAttrs-BdxEl0G2.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-BOHR4zwr.js → placementArrow-CGyD615D.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-B8Jwq05-.js → responsiveObserve-QqcWAQmN.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-BD7RJ3Kn.js → slide-BumQrJ5R.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-BuxDJeDx.js → statusUtils-Pf64olM7.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-DgYQ2Q0o.js → styleChecker-DNwm5SQZ.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-DAHF0Fwi.js → useFlexGapSupport-c3gLKs6e.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-D4kDyLFp.js → useFs-TzTd6NDM.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-BHtSxW4A.js → usePersonalDataHub-BP5E_0Fe.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-CHKtdqW0.js → vnode-CVEkRfZU.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-CIZAMma9.js → zoom-C18X_8TJ.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/commands/agent.js +56 -20
  155. package/src/commands/batch.js +17 -12
  156. package/src/commands/eval.js +24 -8
  157. package/src/data/changelog.json +26 -0
  158. package/src/harness/mcp-client.js +187 -26
  159. package/src/lib/background-session-transport.js +21 -5
  160. package/src/lib/coding-task-guidance.js +13 -0
  161. package/src/lib/decision-layer/runtime.js +180 -10
  162. package/src/lib/direct-model-usage.js +34 -0
  163. package/src/lib/evolution/agent-evolution-ingress.js +63 -7
  164. package/src/lib/evolution/evolution-evidence-artifact-adapter.js +10 -0
  165. package/src/lib/evolution/evolution-evidence-projector.js +46 -7
  166. package/src/lib/evolution/skill-decision-projection.js +211 -0
  167. package/src/lib/evolution/skill-retrieval-revocation-authority.js +17 -2
  168. package/src/lib/file-import-diagnostics.js +246 -0
  169. package/src/lib/skill-loader.js +16 -0
  170. package/src/lib/transport-error-details.js +83 -0
  171. package/src/repl/agent-repl.js +86 -7
  172. package/src/runtime/agent-core.js +248 -15
  173. package/src/runtime/headless-runner.js +295 -71
  174. package/src/runtime/headless-stream.js +197 -27
  175. package/src/runtime/mcp-config.js +26 -17
  176. package/src/runtime/mcp-tool-search.js +44 -14
  177. package/src/assets/web-panel/assets/ChatBubbleRenderer-n6BVStHf.js +0 -1
  178. package/src/assets/web-panel/assets/MarkdownRenderer-BpdGAVCC.js +0 -1
  179. package/src/assets/web-panel/assets/OrderTableRenderer-CxXuPzZg.js +0 -1
  180. package/src/assets/web-panel/assets/Tasks-QEFENVsp.js +0 -1
  181. package/src/assets/web-panel/assets/devWarning-rGldFhxo.js +0 -1
  182. package/src/assets/web-panel/assets/index-Cw-lfvvV.js +0 -1
  183. package/src/assets/web-panel/assets/index-QBXRSyoZ.js +0 -1
@@ -0,0 +1,211 @@
1
+ import { types } from "node:util";
2
+ import { createSkillDecisionRequest } from "../decision-layer/contracts.js";
3
+
4
+ const MAX_BYTES = 256 * 1024;
5
+
6
+ function canonical(value) {
7
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
8
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
9
+ return `{${Object.keys(value)
10
+ .sort()
11
+ .map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
12
+ .join(",")}}`;
13
+ }
14
+
15
+ // Capture descriptors before any authority await. Never evaluate source getters
16
+ // or allow caller mutation to change committed evidence or outbound bytes.
17
+ function snapshot(value) {
18
+ let nodes = 0;
19
+ let bytes = 0;
20
+ const seen = new Set();
21
+ const visit = (entry, depth) => {
22
+ if (++nodes > 4096 || depth > 16)
23
+ throw new TypeError("Skill decision input exceeds its structural budget");
24
+ if (typeof entry === "string") {
25
+ bytes += Buffer.byteLength(entry, "utf8");
26
+ if (bytes > MAX_BYTES)
27
+ throw new TypeError("Skill decision input exceeds its byte budget");
28
+ return entry;
29
+ }
30
+ if (
31
+ entry === null ||
32
+ typeof entry === "boolean" ||
33
+ (typeof entry === "number" && Number.isFinite(entry))
34
+ )
35
+ return entry;
36
+ if (
37
+ !entry ||
38
+ typeof entry !== "object" ||
39
+ types.isProxy(entry) ||
40
+ seen.has(entry)
41
+ )
42
+ throw new TypeError(
43
+ "Skill decision input must be acyclic plain JSON data",
44
+ );
45
+ const array = Array.isArray(entry);
46
+ if (
47
+ !array &&
48
+ ![Object.prototype, null].includes(Object.getPrototypeOf(entry))
49
+ )
50
+ throw new TypeError("Skill decision input must use plain objects");
51
+ const keys = Reflect.ownKeys(entry).filter(
52
+ (key) => !(array && key === "length"),
53
+ );
54
+ if (
55
+ array &&
56
+ (keys.length !== entry.length ||
57
+ keys.some((key, index) => key !== String(index)))
58
+ )
59
+ throw new TypeError("Skill decision arrays must be dense data");
60
+ seen.add(entry);
61
+ const output = array ? [] : Object.create(null);
62
+ for (const key of keys) {
63
+ const property = Object.getOwnPropertyDescriptor(entry, key);
64
+ if (
65
+ typeof key !== "string" ||
66
+ !property?.enumerable ||
67
+ !("value" in property)
68
+ )
69
+ throw new TypeError(
70
+ "Skill decision input cannot contain accessors or symbols",
71
+ );
72
+ bytes += Buffer.byteLength(key, "utf8");
73
+ if (bytes > MAX_BYTES)
74
+ throw new TypeError("Skill decision input exceeds its byte budget");
75
+ Object.defineProperty(output, key, {
76
+ value: visit(property.value, depth + 1),
77
+ enumerable: true,
78
+ });
79
+ }
80
+ seen.delete(entry);
81
+ return Object.freeze(output);
82
+ };
83
+ const result = visit(value, 0);
84
+ if (Buffer.byteLength(JSON.stringify(result), "utf8") > MAX_BYTES)
85
+ throw new TypeError("Skill decision input exceeds its byte budget");
86
+ return result;
87
+ }
88
+
89
+ function exact(value, keys) {
90
+ if (
91
+ !value ||
92
+ typeof value !== "object" ||
93
+ Array.isArray(value) ||
94
+ Object.keys(value).sort().join("\0") !== [...keys].sort().join("\0")
95
+ )
96
+ throw new TypeError("Skill decision has an unsupported protocol shape");
97
+ }
98
+
99
+ function text(value) {
100
+ if (typeof value !== "string" || !value.length)
101
+ throw new TypeError("Skill decision requires nonempty text");
102
+ }
103
+
104
+ export function snapshotSkillDecisionPayload(value) {
105
+ const payload = snapshot(value);
106
+ exact(payload, ["state", "questions"]);
107
+ exact(payload.state, ["task", "candidates"]);
108
+ text(payload.state.task);
109
+ const candidates = payload.state.candidates;
110
+ if (
111
+ !Array.isArray(candidates) ||
112
+ candidates.length < 1 ||
113
+ candidates.length > 8
114
+ )
115
+ throw new TypeError("Skill decision requires bounded candidates");
116
+ candidates.forEach((candidate, index) => {
117
+ exact(candidate, [
118
+ "candidateId",
119
+ "name",
120
+ "description",
121
+ "category",
122
+ "tags",
123
+ ]);
124
+ if (candidate.candidateId !== `c${index + 1}`)
125
+ throw new TypeError("Skill decision candidate identity changed");
126
+ for (const key of ["name", "description", "category"]) text(candidate[key]);
127
+ if (!Array.isArray(candidate.tags) || candidate.tags.length > 32)
128
+ throw new TypeError("Skill decision tags are unbounded");
129
+ candidate.tags.forEach(text);
130
+ });
131
+ const ids = candidates.map(({ candidateId }) => candidateId);
132
+ exact(payload.questions, [
133
+ "needs_skill",
134
+ "best_skill",
135
+ ...ids.map((id) => `fits_${id}`),
136
+ ]);
137
+ for (const key of ["needs_skill", ...ids.map((id) => `fits_${id}`)]) {
138
+ exact(payload.questions[key], ["type", "instructions"]);
139
+ if (payload.questions[key].type !== "noul")
140
+ throw new TypeError("Skill decision question type changed");
141
+ text(payload.questions[key].instructions);
142
+ }
143
+ const choice = payload.questions.best_skill;
144
+ exact(choice, ["type", "instructions", "criteria"]);
145
+ if (choice.type !== "choice")
146
+ throw new TypeError("Skill decision question type changed");
147
+ text(choice.instructions);
148
+ exact(choice.criteria, [...ids, "none"]);
149
+ Object.values(choice.criteria).forEach(text);
150
+ return payload;
151
+ }
152
+
153
+ export function snapshotSkillDecisionRequest(value) {
154
+ const request = snapshot(value);
155
+ const rebuilt = createSkillDecisionRequest({
156
+ decisionId: request.decisionId,
157
+ ...request.binding,
158
+ query: request.payload?.state?.task,
159
+ candidates: request.candidates,
160
+ });
161
+ if (canonical(request) !== canonical(rebuilt))
162
+ throw new TypeError("Skill decision request identity or contract changed");
163
+ snapshotSkillDecisionPayload(request.payload);
164
+ return request;
165
+ }
166
+
167
+ function textPath(path) {
168
+ return (
169
+ /^state\.task$/u.test(path) ||
170
+ /^state\.candidates\.\d+\.(?:name|description|category|tags\.\d+)$/u.test(
171
+ path,
172
+ ) ||
173
+ /^questions\.best_skill\.criteria\.c[1-8]$/u.test(path)
174
+ );
175
+ }
176
+
177
+ export function buildSkillDecisionPayload(original, projection) {
178
+ if (
179
+ projection.visibility !== "model-visible" ||
180
+ projection.truncated ||
181
+ (projection.redactionSummary?.byType?.["content-truncation"] ?? 0) > 0
182
+ )
183
+ throw new Error("Skill decision projection is opaque or truncated");
184
+ const captured = snapshotSkillDecisionPayload(original);
185
+ const projected = snapshotSkillDecisionPayload(projection.content);
186
+ const compare = (before, after, path = "") => {
187
+ if (
188
+ typeof before === "string" &&
189
+ typeof after === "string" &&
190
+ textPath(path)
191
+ )
192
+ return;
193
+ if (before === null || typeof before !== "object") {
194
+ if (before !== after)
195
+ throw new Error("Skill decision projection changed protocol metadata");
196
+ return;
197
+ }
198
+ if (
199
+ !after ||
200
+ typeof after !== "object" ||
201
+ Array.isArray(before) !== Array.isArray(after) ||
202
+ Object.keys(before).sort().join("\0") !==
203
+ Object.keys(after).sort().join("\0")
204
+ )
205
+ throw new Error("Skill decision projection changed protocol structure");
206
+ for (const key of Object.keys(before))
207
+ compare(before[key], after[key], path ? `${path}.${key}` : key);
208
+ };
209
+ compare(captured, projected);
210
+ return projected;
211
+ }
@@ -239,9 +239,19 @@ export async function openSkillRetrievalRevocationAuthority({
239
239
  ) {
240
240
  throw new Error("Retrieval revocation load is not authoritative");
241
241
  }
242
- state = loaded.found
242
+ const loadedState = loaded.found
243
243
  ? verifySkillRetrievalRevocationState(loaded.state, tenantId)
244
244
  : null;
245
+ if (
246
+ state !== null &&
247
+ (loadedState === null ||
248
+ loadedState.revision < state.revision ||
249
+ (loadedState.revision === state.revision &&
250
+ loadedState.stateDigest !== state.stateDigest))
251
+ ) {
252
+ throw new Error("Retrieval revocation state regressed");
253
+ }
254
+ state = loadedState;
245
255
  return state;
246
256
  }
247
257
 
@@ -265,6 +275,10 @@ export async function openSkillRetrievalRevocationAuthority({
265
275
  receiptDigest: entry?.propagationRequestDigest ?? null,
266
276
  });
267
277
  },
278
+ async refresh() {
279
+ const current = await reload();
280
+ return current?.stateDigest ?? null;
281
+ },
268
282
  async invalidateRetrieval(input) {
269
283
  const request = normalizeRequest(input, tenantId);
270
284
  const contentDigest = request.dependency.digest;
@@ -351,7 +365,8 @@ export function captureSkillRetrievalRevocationReader(reader) {
351
365
  if (
352
366
  !readerBrand.has(reader) ||
353
367
  reader.schema !== SKILL_RETRIEVAL_REVOCATION_READER_SCHEMA ||
354
- typeof reader.inspect !== "function"
368
+ typeof reader.inspect !== "function" ||
369
+ typeof reader.refresh !== "function"
355
370
  ) {
356
371
  throw new TypeError(
357
372
  "A branded Skill retrieval revocation reader is required",
@@ -0,0 +1,246 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { parse } from "acorn";
4
+
5
+ export const FILE_IMPORT_LIMITS = Object.freeze({
6
+ contentBytes: 256 * 1024,
7
+ references: 64,
8
+ specifierChars: 512,
9
+ });
10
+
11
+ const JS_EXTENSION = /\.(?:js|mjs|cjs)$/;
12
+
13
+ function inside(root, target) {
14
+ const relative = path.relative(root, target);
15
+ return (
16
+ relative === "" ||
17
+ (!path.isAbsolute(relative) &&
18
+ relative !== ".." &&
19
+ !relative.startsWith(`..${path.sep}`))
20
+ );
21
+ }
22
+
23
+ // Inspect each component before descending. Never stat/realpath a link, read
24
+ // target contents, enumerate directories, or include OS errors in feedback.
25
+ // As with other path-based Node APIs, this is not atomic against directory
26
+ // replacement by another process. The caller supplies its authorized root.
27
+ function inspectPath(root, target) {
28
+ if (!inside(root, target)) return "outside-workspace";
29
+ const components = path
30
+ .relative(root, target)
31
+ .split(path.sep)
32
+ .filter(Boolean);
33
+ let current = root;
34
+ for (let index = -1; index < components.length; index++) {
35
+ if (index >= 0) current = path.join(current, components[index]);
36
+ let stat;
37
+ try {
38
+ stat = fs.lstatSync(current);
39
+ } catch (error) {
40
+ return error?.code === "ENOENT" ? "missing" : "unavailable";
41
+ }
42
+ if (stat.isSymbolicLink()) return "symbolic-link";
43
+ if (index < components.length - 1 && !stat.isDirectory()) {
44
+ return "missing";
45
+ }
46
+ if (index === components.length - 1) {
47
+ return stat.isFile() ? "file" : "not-file";
48
+ }
49
+ }
50
+ return "not-file";
51
+ }
52
+
53
+ function inspectReference(root, target, kind) {
54
+ const state = inspectPath(root, target);
55
+ if (kind !== "require") return state;
56
+ // CommonJS can load directories and append extensions even when a request
57
+ // already has a suffix. Do not claim those uncertain cases are unresolved.
58
+ if (state === "not-file") return "commonjs-resolution";
59
+ if (state === "missing") {
60
+ for (const extension of [".js", ".json", ".node"]) {
61
+ const fallback = inspectPath(root, target + extension);
62
+ if (fallback !== "missing" && fallback !== "not-file") {
63
+ return "commonjs-resolution";
64
+ }
65
+ }
66
+ }
67
+ return state;
68
+ }
69
+
70
+ function parseSource(content, extension) {
71
+ const options = { ecmaVersion: "latest", locations: true };
72
+ if (extension === ".cjs") {
73
+ return parse(content, {
74
+ ...options,
75
+ sourceType: "script",
76
+ allowReturnOutsideFunction: true,
77
+ });
78
+ }
79
+ try {
80
+ return parse(content, { ...options, sourceType: "module" });
81
+ } catch (error) {
82
+ if (extension === ".mjs") throw error;
83
+ return parse(content, {
84
+ ...options,
85
+ sourceType: "script",
86
+ allowReturnOutsideFunction: true,
87
+ });
88
+ }
89
+ }
90
+
91
+ function collectReferences(ast) {
92
+ const references = [];
93
+ const pending = [{ node: ast, parent: null }];
94
+ let uncertainRequire = false;
95
+ let truncated = false;
96
+ while (pending.length) {
97
+ const { node, parent } = pending.pop();
98
+ // Conservative across the whole file: local bindings, assignments, and
99
+ // indirect uses make require's meaning uncertain. Imports remain useful.
100
+ if (
101
+ (node.type === "Identifier" &&
102
+ node.name === "require" &&
103
+ !(parent?.type === "CallExpression" && parent.callee === node)) ||
104
+ node.type === "WithStatement" ||
105
+ (node.type === "CallExpression" && node.callee?.name === "eval")
106
+ ) {
107
+ uncertainRequire = true;
108
+ }
109
+ let source;
110
+ let kind;
111
+ if (
112
+ node.type === "ImportDeclaration" ||
113
+ node.type === "ExportNamedDeclaration" ||
114
+ node.type === "ExportAllDeclaration" ||
115
+ node.type === "ImportExpression"
116
+ ) {
117
+ source = node.source;
118
+ kind = "import";
119
+ } else if (
120
+ node.type === "CallExpression" &&
121
+ !node.optional &&
122
+ node.callee?.type === "Identifier" &&
123
+ node.callee.name === "require" &&
124
+ node.arguments.length === 1
125
+ ) {
126
+ source = node.arguments[0];
127
+ kind = "require";
128
+ }
129
+ if (
130
+ source?.type === "Literal" &&
131
+ typeof source.value === "string" &&
132
+ /^\.{1,2}\//.test(source.value) &&
133
+ JS_EXTENSION.test(source.value) &&
134
+ !/[\\%?#:\u0000-\u001f\u007f]/.test(source.value)
135
+ ) {
136
+ if (references.length < FILE_IMPORT_LIMITS.references) {
137
+ references.push({ source, kind });
138
+ } else {
139
+ truncated = true;
140
+ }
141
+ }
142
+ const children = [];
143
+ for (const value of Object.values(node)) {
144
+ if (value?.type) children.push(value);
145
+ else if (Array.isArray(value)) {
146
+ for (const child of value) if (child?.type) children.push(child);
147
+ }
148
+ }
149
+ for (let index = children.length - 1; index >= 0; index--) {
150
+ pending.push({ node: children[index], parent: node });
151
+ }
152
+ }
153
+ return { references, uncertainRequire, truncated };
154
+ }
155
+
156
+ /**
157
+ * Best-effort feedback after an authorized write. Only explicit JS relative
158
+ * runtime references are checked, using supplied content and metadata inside
159
+ * workspaceRoot. This does not run code, resolve packages, or prove tests pass.
160
+ * Missing/inaccessible inputs and unsupported syntax never throw to the writer.
161
+ * line/column are one-based. uncheckedReferences never disclose resolved paths.
162
+ */
163
+ export function collectFileImportDiagnostics(input) {
164
+ const result = {
165
+ status: "skipped",
166
+ diagnostics: [],
167
+ checkedReferences: 0,
168
+ uncheckedReferences: [],
169
+ truncated: false,
170
+ };
171
+ const skip = (reason) => ({ ...result, reason });
172
+ try {
173
+ const { filePath, content, workspaceRoot } = input ?? {};
174
+ if (
175
+ typeof filePath !== "string" ||
176
+ !filePath ||
177
+ filePath.length > 4096 ||
178
+ typeof workspaceRoot !== "string" ||
179
+ !workspaceRoot ||
180
+ workspaceRoot.length > 4096 ||
181
+ !path.isAbsolute(workspaceRoot) ||
182
+ typeof content !== "string"
183
+ ) {
184
+ return skip("invalid-input");
185
+ }
186
+ if (!JS_EXTENSION.test(filePath)) return skip("unsupported-file");
187
+ if (
188
+ content.length > FILE_IMPORT_LIMITS.contentBytes ||
189
+ Buffer.byteLength(content, "utf8") > FILE_IMPORT_LIMITS.contentBytes
190
+ ) {
191
+ return skip("content-limit");
192
+ }
193
+ const root = path.resolve(workspaceRoot);
194
+ const file = path.resolve(root, filePath);
195
+ if (!inside(root, file)) return skip("outside-workspace");
196
+ const fileState = inspectPath(root, file);
197
+ if (fileState !== "file") return skip(fileState);
198
+ let ast;
199
+ try {
200
+ ast = parseSource(content, path.extname(file));
201
+ } catch {
202
+ return skip("unsupported-syntax");
203
+ }
204
+ const { references, uncertainRequire, truncated } = collectReferences(ast);
205
+ result.status = "checked";
206
+ result.truncated = truncated;
207
+ for (const { source, kind } of references) {
208
+ const location = {
209
+ specifier: source.value.slice(0, FILE_IMPORT_LIMITS.specifierChars),
210
+ line: source.loc.start.line,
211
+ column: source.loc.start.column + 1,
212
+ };
213
+ let state;
214
+ if (source.value.length > FILE_IMPORT_LIMITS.specifierChars) {
215
+ state = "specifier-limit";
216
+ } else if (kind === "require" && uncertainRequire) {
217
+ state = "uncertain-require";
218
+ } else {
219
+ state = inspectReference(
220
+ root,
221
+ path.resolve(path.dirname(file), source.value),
222
+ kind,
223
+ );
224
+ }
225
+ if (state === "file" || state === "missing" || state === "not-file") {
226
+ result.checkedReferences++;
227
+ if (state !== "file") {
228
+ result.diagnostics.push({
229
+ source: "relative-import",
230
+ code: "UNRESOLVED_RELATIVE_IMPORT",
231
+ severity: "error",
232
+ filePath: file,
233
+ ...location,
234
+ message: `Relative import ${JSON.stringify(location.specifier)} does not point to an existing file from this file's directory. Verify the importing file's location before running tests.`,
235
+ });
236
+ }
237
+ } else {
238
+ result.uncheckedReferences.push({ ...location, reason: state });
239
+ }
240
+ }
241
+ return result;
242
+ } catch {
243
+ // Do not allow optional feedback to turn a completed mutation into failure.
244
+ return skip("unavailable");
245
+ }
246
+ }
@@ -392,6 +392,7 @@ export class CLISkillLoader {
392
392
  throw new TypeError("reauthorizeSkill must be a function or null");
393
393
  }
394
394
  this._cache = null;
395
+ this._lastLoadOptions = null;
395
396
  bindSkillRuntimeAdmission(this, skillRuntimeAdmission, {
396
397
  required: skillRuntimeAdmissionRequired,
397
398
  });
@@ -1264,6 +1265,12 @@ export class CLISkillLoader {
1264
1265
  */
1265
1266
  loadAll(options = {}) {
1266
1267
  this._cacheStats.descriptorScans += 1;
1268
+ // Preserve explicit layer policy for a later freshness scan. In particular,
1269
+ // refreshing an opt-in decision must not re-enable a disabled skill layer.
1270
+ this._lastLoadOptions = {
1271
+ ...options,
1272
+ ...(options.env ? { env: { ...options.env } } : {}),
1273
+ };
1267
1274
  // `cc agent --bare` (CC_SKILLS=0): no skill layer loads at all — cache the
1268
1275
  // empty result so getResolvedSkills stays cheap on every call.
1269
1276
  if (allSkillsDisabled(options)) {
@@ -1336,6 +1343,14 @@ export class CLISkillLoader {
1336
1343
  return this.loadAll();
1337
1344
  }
1338
1345
 
1346
+ /** Rescan the same layers under the options used for the current cache. */
1347
+ refreshResolvedSkills() {
1348
+ // A failed scan must not leave a previous descriptor set available as if
1349
+ // it were current on the next lookup.
1350
+ this._cache = null;
1351
+ return this.loadAll(this._lastLoadOptions ?? {});
1352
+ }
1353
+
1339
1354
  /**
1340
1355
  * Get auto-activated persona skills
1341
1356
  * @returns {object[]} skills with category "persona" and activation "auto"
@@ -1367,6 +1382,7 @@ export class CLISkillLoader {
1367
1382
  */
1368
1383
  clearCache() {
1369
1384
  this._cache = null;
1385
+ this._lastLoadOptions = null;
1370
1386
  this._bodyCache.clear();
1371
1387
  this._cacheStats = {
1372
1388
  descriptorScans: 0,
@@ -0,0 +1,83 @@
1
+ import { types } from "node:util";
2
+
3
+ const NAMES = new Set([
4
+ "Error",
5
+ "TypeError",
6
+ "AggregateError",
7
+ "AbortError",
8
+ "TimeoutError",
9
+ "ConnectTimeoutError",
10
+ "HeadersTimeoutError",
11
+ "BodyTimeoutError",
12
+ "SocketError",
13
+ "RequestAbortedError",
14
+ "ClientDestroyedError",
15
+ "ClientClosedError",
16
+ ]);
17
+ const CODES = new Set([
18
+ "ECONNRESET",
19
+ "ECONNREFUSED",
20
+ "ENOTFOUND",
21
+ "EAI_AGAIN",
22
+ "ETIMEDOUT",
23
+ "EHOSTUNREACH",
24
+ "ENETUNREACH",
25
+ "EPIPE",
26
+ "ERR_TLS_CERT_ALTNAME_INVALID",
27
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
28
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
29
+ "CERT_HAS_EXPIRED",
30
+ "ABORT_ERR",
31
+ "UND_ERR_SOCKET",
32
+ "UND_ERR_CONNECT_TIMEOUT",
33
+ "UND_ERR_HEADERS_TIMEOUT",
34
+ "UND_ERR_BODY_TIMEOUT",
35
+ "UND_ERR_ABORTED",
36
+ "UND_ERR_DESTROYED",
37
+ "UND_ERR_CLOSED",
38
+ "UND_ERR_REQ_CONTENT_LENGTH_MISMATCH",
39
+ "UND_ERR_RES_CONTENT_LENGTH_MISMATCH",
40
+ ]);
41
+
42
+ // Never invoke accessors, coercion hooks or Proxy traps. Native Error.name is
43
+ // inherited, so inspect a bounded number of prototype data descriptors.
44
+ function data(object, key) {
45
+ for (let depth = 0; depth < 4 && object !== null; depth++) {
46
+ if (typeof object !== "object" || types.isProxy(object)) return undefined;
47
+ const descriptor = Object.getOwnPropertyDescriptor(object, key);
48
+ if (descriptor) return "value" in descriptor ? descriptor.value : undefined;
49
+ object = Object.getPrototypeOf(object);
50
+ }
51
+ return undefined;
52
+ }
53
+
54
+ /** Optional diagnostic projection only: no messages, endpoints or request data. */
55
+ export function transportErrorDetails(error) {
56
+ try {
57
+ const name = data(error, "name");
58
+ const code = data(error, "code");
59
+ let causeCode;
60
+ const seen = new Set([error]);
61
+ let cause = error;
62
+ for (let depth = 0; depth < 4; depth++) {
63
+ cause = data(cause, "cause");
64
+ if (!cause || seen.has(cause)) break;
65
+ seen.add(cause);
66
+ const value = data(cause, "code");
67
+ if (CODES.has(value)) {
68
+ causeCode = value;
69
+ break;
70
+ }
71
+ }
72
+ if (!CODES.has(code) && !causeCode) return undefined;
73
+ return {
74
+ kind: "transport",
75
+ ...(NAMES.has(name) ? { name } : {}),
76
+ ...(CODES.has(code) ? { code } : {}),
77
+ ...(causeCode ? { causeCode } : {}),
78
+ };
79
+ } catch {
80
+ // Diagnostics must never replace the original error or exit outcome.
81
+ return undefined;
82
+ }
83
+ }