chainlesschain 0.162.149 → 0.162.150

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 (273) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-BJif14yR.js → AIOps-CBLvrjeG.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-CXek6gJY.js → ActionButton-DYv2GtE0.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-BgQhdAJi.js → Analytics-CL6PZ-Ww.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-DTYl5NtR.js → AppLayout-xuyHt4uA.js} +3 -3
  6. package/src/assets/web-panel/assets/{Audit-BzATQAeR.js → Audit-DOvSVycq.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-BzdPEQhL.js → Backup-DMhfTswr.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-BM0KVh8E.js → BaseInput-CQxDdm63.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-D7fHXHkz.js → Chat-BEeNhK2a.js} +5 -5
  10. package/src/assets/web-panel/assets/{ChatBubbleRenderer-Wm34RR-b.js → ChatBubbleRenderer-8nul8eTq.js} +1 -1
  11. package/src/assets/web-panel/assets/{Checkbox-CAiSQ9vO.js → Checkbox-CL04O-ER.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-Df40CrEe.js → Codegen-C50o-n7x.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-DIT2fNFU.js → Col-CH-bDkzs.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-CSTIbW2k.js → Community-DqAIMvSe.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-DtqXZZUi.js → Compact-C43fo_my.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-CUtzw6o7.js → Compliance-BERnMrdP.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-CezmlnmU.js → Cowork-Baw3w1gp.js} +4 -4
  18. package/src/assets/web-panel/assets/{Cron-P4BITarg.js → Cron-BEqAHF1-.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-BRRiYwvq.js → Crosschain-CvnmKwK4.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-L5ijB9i4.js → DID-iMPxgVdt.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-CFxro4ob.js → Dashboard--4SJX3YR.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-BmAFCQ71.js → Dropdown-BgLV6xgz.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-DJBCEuon.js → EmailListRenderer-Bvb8oUD8.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-z4oLq6eT.js → FamilyGuardDashboard-DpXPjJB5.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-DsVCpHMF.js → Federation-BbFfJ1Xi.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-DP3bP5th.js → FormItemContext-DeGq1B-q.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-BAXP2Gc6.js → GenericCardRenderer-CNW7s9zM.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-I3g_bAw9.js → Git-L1PjW-lT.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-jHS5-ioS.js → Governance-PK-X58to.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-CPL7sfx9.js → Inference-BePWEH-d.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-Jf236h4C.js → KnowledgeGraph-LF_sBvdL.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-Cm2tcSKg.js → Logs-BKkfk9hy.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-CZK82rhi.js → Marketplace-BNMqUDla.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-CZCeji7a.js → McpTools-w4WPiyz2.js} +5 -5
  35. package/src/assets/web-panel/assets/{Memory-3l2KVS9k.js → Memory-DUKMVGNi.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-VYdpoLh6.js → MobileBridge-BWhiEyTJ.js} +1 -1
  37. package/src/assets/web-panel/assets/{MobileProjects-CiB9cmm1.js → MobileProjects-Ocf5JEkX.js} +1 -1
  38. package/src/assets/web-panel/assets/{Mtc-wCFZbBuL.js → Mtc-D2B6MMhU.js} +4 -4
  39. package/src/assets/web-panel/assets/{MtcAudit-1a3THIyG.js → MtcAudit-DdYjCq1O.js} +2 -2
  40. package/src/assets/web-panel/assets/{Multisig-DMzLB2hG.js → Multisig-Cb1hfuUZ.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-D9wZbf6l.js → NLProgramming-CTeImGp7.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-hrFe2ZM-.js → Notes-BjYNc7eQ.js} +4 -4
  43. package/src/assets/web-panel/assets/{NotificationSettings-CHGX5Jwm.js → NotificationSettings-Dn_NtRXQ.js} +1 -1
  44. package/src/assets/web-panel/assets/OrderTableRenderer-DVYYIizh.js +1 -0
  45. package/src/assets/web-panel/assets/{Organization-By7FkhtY.js → Organization-Be2Kmr5j.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow--khGSzJn.js → Overflow-Cu_-qRlR.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-CAG9dH35.js → P2P-DD2HoGzE.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-B3SQZmK9.js → PdhVaultBrowser-BRI7DVth.js} +3 -3
  49. package/src/assets/web-panel/assets/{Permissions-D35ec6JA.js → Permissions-C9Srcs2M.js} +3 -3
  50. package/src/assets/web-panel/assets/{PersonalDataHub-CxBF7hW_.js → PersonalDataHub-CUqcMgo1.js} +3 -3
  51. package/src/assets/web-panel/assets/{Pipeline-s6EtOO1s.js → Pipeline-HBrQGLXt.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-BbJYmWmO.js → Privacy-D-B0vjwh.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-VGQq1jMT.js → ProjectInit-eTeLIu9e.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-B1ew3Teh.js → ProjectSettings-DrRqCsC6.js} +2 -2
  55. package/src/assets/web-panel/assets/Projects-1G9DNOhI.js +1 -0
  56. package/src/assets/web-panel/assets/{Providers-mrO47FIK.js → Providers-RkTZzpxP.js} +1 -1
  57. package/src/assets/web-panel/assets/{QrScannerModal-IJF2mHyw.js → QrScannerModal-BSCUgsgC.js} +1 -1
  58. package/src/assets/web-panel/assets/{QuickAsk-CU0wN_Z0.js → QuickAsk-CHgyM3Bz.js} +1 -1
  59. package/src/assets/web-panel/assets/{Recommend-DhN37R6G.js → Recommend-0lry4OZq.js} +1 -1
  60. package/src/assets/web-panel/assets/{RemoteSession-D_xOX_hu.js → RemoteSession-Cn45UroZ.js} +2 -2
  61. package/src/assets/web-panel/assets/{Reputation-D_Ssv7uH.js → Reputation-Q-Zjb707.js} +1 -1
  62. package/src/assets/web-panel/assets/{Row-Kx5dKxX7.js → Row-BdM70oda.js} +1 -1
  63. package/src/assets/web-panel/assets/{RssFeed-BlGwqZkY.js → RssFeed-DmOAKKap.js} +2 -2
  64. package/src/assets/web-panel/assets/{Search-hLFQzxpb.js → Search-Dwavbm07.js} +1 -1
  65. package/src/assets/web-panel/assets/{Security-DMlvsVt4.js → Security-DukXFCnk.js} +3 -3
  66. package/src/assets/web-panel/assets/{Services-Bd0Qsj2m.js → Services-BIlRnITu.js} +2 -2
  67. package/src/assets/web-panel/assets/{Skeleton-DFclq9X3.js → Skeleton-YYVQdhhQ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Skills-BNtln2qY.js → Skills-B8_iYHz2.js} +1 -1
  69. package/src/assets/web-panel/assets/{Sla-Dch5H19G.js → Sla-BdVrhT31.js} +1 -1
  70. package/src/assets/web-panel/assets/{SpeechSettings-2UfQcU1g.js → SpeechSettings-CD3ggRx7.js} +1 -1
  71. package/src/assets/web-panel/assets/{SyncSettings-CD9YQr4i.js → SyncSettings-Bp02VZFH.js} +2 -2
  72. package/src/assets/web-panel/assets/{Tasks-BNu-7MzI.js → Tasks-DEVmCEsr.js} +1 -1
  73. package/src/assets/web-panel/assets/{Templates-D1n9CaIR.js → Templates-B6czWc4N.js} +1 -1
  74. package/src/assets/web-panel/assets/{Tenant-DenL3iBW.js → Tenant-BCJLv17r.js} +1 -1
  75. package/src/assets/web-panel/assets/{Terminal-ZzU0Io1Y.js → Terminal-CD132d2Y.js} +2 -2
  76. package/src/assets/web-panel/assets/{TimelineRenderer-D87IfukO.js → TimelineRenderer-ZB-CvkZl.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tokens-BkiZc8E3.js → Tokens-BnSY0S-s.js} +1 -1
  78. package/src/assets/web-panel/assets/{Trigger-BNRSytGN.js → Trigger-VZw9Oy2w.js} +1 -1
  79. package/src/assets/web-panel/assets/{Trust-Bwbd4X2m.js → Trust-pZq7Hjd2.js} +1 -1
  80. package/src/assets/web-panel/assets/{UkeySign-B8O2bs0o.js → UkeySign-DnQaqk4q.js} +1 -1
  81. package/src/assets/web-panel/assets/{VideoEditing-C2fL8zmH.js → VideoEditing-BEUfmvJV.js} +1 -1
  82. package/src/assets/web-panel/assets/{Wallet-BORYDdE1.js → Wallet-CoZKMXJ2.js} +4 -4
  83. package/src/assets/web-panel/assets/{WebAuthn-C0V5S2FM.js → WebAuthn-CBOGVx1I.js} +5 -5
  84. package/src/assets/web-panel/assets/{WorkflowEditor-2dR0fcHL.js → WorkflowEditor-huSKn7TT.js} +1 -1
  85. package/src/assets/web-panel/assets/{chat-BmuAFAn8.js → chat-A_3w6FBO.js} +1 -1
  86. package/src/assets/web-panel/assets/{colors-CN3smMcK.js → colors-D1Bem9Oy.js} +1 -1
  87. package/src/assets/web-panel/assets/{compact-item-DCnxb4kW.js → compact-item-CJYJj0oO.js} +1 -1
  88. package/src/assets/web-panel/assets/{createContext-vlR43pHn.js → createContext-BkbFiKT4.js} +1 -1
  89. package/src/assets/web-panel/assets/devWarning-WDr3_M_N.js +1 -0
  90. package/src/assets/web-panel/assets/{hasIn-D04tHYFd.js → hasIn-CKvUafVY.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-0DnaZGkC.js → index-AjrSPnvv.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-BudvKQfG.js → index-B8i0lViZ.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-BeGDEXFs.js → index-B9Svn0zc.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-D5LZVZ0L.js → index-BHdHSX06.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BTPEZTk1.js → index-BHdailyo.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DIpY0qM5.js → index-BJwlEnYo.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-CsAsCPJ6.js → index-BOoAQjJz.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-ljuBiQW9.js → index-BSgWxAOG.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-hpvvtAZ3.js → index-BdutMsne.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-_FIkN3jd.js → index-BiDWxzbn.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-C-6NO5il.js → index-By5a0T_W.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-B78xL3s2.js → index-C-WIY-FQ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-ClhAHDK3.js → index-C37f6iey.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-ToUh2b1-.js → index-C9bWmTcO.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-D28DeAAB.js → index-CBaosWRO.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-D8vwp4qp.js → index-CBlBVJ_m.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BqhASEL4.js → index-CD62EEGo.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DDwLgQY9.js → index-CUj-l7GM.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DbVsQBOH.js → index-CVS8Ymuq.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Cr-A0FYJ.js → index-ChkXUj3f.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-D65_XseV.js → index-Cj0OZ-37.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BXRg8GFQ.js → index-Co3OFL0t.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-430S68MN.js → index-Crp8CbRg.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CngCC8hC.js → index-D22zNXiS.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-HhNjnCfe.js → index-DTs_D1OL.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CP9m9Ggr.js → index-DfgCdFrN.js} +3 -3
  117. package/src/assets/web-panel/assets/{index-jzR7Ujuw.js → index-DjYrecNb.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CTOCnIQ7.js → index-DpW9cf3e.js} +1 -1
  119. package/src/assets/web-panel/assets/index-Dwix3p4g.js +1 -0
  120. package/src/assets/web-panel/assets/{index-D_n8_vfI.js → index-F--HuPG1.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BasvsWDM.js → index-Fuk6t_3K.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CnXebZLL.js → index-JEAGMii9.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DYAtmqiv.js → index-PF-mpv8K.js} +1 -1
  124. package/src/assets/web-panel/assets/index-SHaoZ0CA.js +1 -0
  125. package/src/assets/web-panel/assets/{index-DTWg-18U.js → index-b-sbVdjQ.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-C5Sxb1sE.js → index-pyvMVX8r.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-TslMTwNy.js → index-qNTtOVi_.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DTtRscUa.js → index-tgO8iza6.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DbADHwhr.js → index-ttDQVhZy.js} +1 -1
  130. package/src/assets/web-panel/assets/{initDefaultProps-C3wUb4je.js → initDefaultProps-DtrnfsZH.js} +1 -1
  131. package/src/assets/web-panel/assets/{motion-D-jYFUNA.js → motion-D4zqSaX3.js} +1 -1
  132. package/src/assets/web-panel/assets/{move-tqb8nwJ2.js → move-CGFGOUQj.js} +1 -1
  133. package/src/assets/web-panel/assets/{mtc-parser-DSOjMJMz.js → mtc-parser-DH2HvkJl.js} +1 -1
  134. package/src/assets/web-panel/assets/{omit-CJ7VimIW.js → omit-jJ2at5HX.js} +1 -1
  135. package/src/assets/web-panel/assets/{pickAttrs-qXiG1iT3.js → pickAttrs-CRyMT1Fv.js} +1 -1
  136. package/src/assets/web-panel/assets/{placementArrow-CkGBcy1Z.js → placementArrow-DZ_CX0Pt.js} +1 -1
  137. package/src/assets/web-panel/assets/{responsiveObserve-D3WvTlLO.js → responsiveObserve-wruHk-h5.js} +1 -1
  138. package/src/assets/web-panel/assets/{slide-BEE2ftge.js → slide-BGgx8q67.js} +1 -1
  139. package/src/assets/web-panel/assets/{statusUtils-CsfBpxiG.js → statusUtils-Do5M7gKm.js} +1 -1
  140. package/src/assets/web-panel/assets/{styleChecker-xPrIiJPI.js → styleChecker-CRa-GZpX.js} +1 -1
  141. package/src/assets/web-panel/assets/{useFlexGapSupport-C5Yd-SCR.js → useFlexGapSupport-BxPcq6pj.js} +1 -1
  142. package/src/assets/web-panel/assets/{useFs-D_MDS8HI.js → useFs-v5O2ZcJm.js} +1 -1
  143. package/src/assets/web-panel/assets/{usePersonalDataHub-BqJh-usA.js → usePersonalDataHub--z2FU0Px.js} +1 -1
  144. package/src/assets/web-panel/assets/{vnode-chm_p-gz.js → vnode-1emidVKd.js} +1 -1
  145. package/src/assets/web-panel/assets/{zoom-3-YDNz0Z.js → zoom-CcJaRyHs.js} +1 -1
  146. package/src/assets/web-panel/index.html +1 -1
  147. package/src/commands/a2a.js +19 -4
  148. package/src/commands/activitypub.js +20 -3
  149. package/src/commands/agent.js +27 -5
  150. package/src/commands/audit.js +40 -24
  151. package/src/commands/codeintel.js +68 -0
  152. package/src/commands/collab.js +15 -2
  153. package/src/commands/compliance.js +5 -0
  154. package/src/commands/config.js +4 -1
  155. package/src/commands/dao.js +86 -14
  156. package/src/commands/dev.js +2 -0
  157. package/src/commands/did.js +7 -1
  158. package/src/commands/dlp.js +23 -1
  159. package/src/commands/economy.js +29 -3
  160. package/src/commands/eval.js +7 -0
  161. package/src/commands/evomap.js +26 -0
  162. package/src/commands/governance.js +17 -3
  163. package/src/commands/hardening.js +18 -0
  164. package/src/commands/incentive.js +5 -0
  165. package/src/commands/init.js +46 -2
  166. package/src/commands/kg.js +4 -0
  167. package/src/commands/loop.js +6 -1
  168. package/src/commands/lowcode.js +15 -2
  169. package/src/commands/marketplace.js +40 -6
  170. package/src/commands/matrix.js +20 -1
  171. package/src/commands/memory.js +4 -1
  172. package/src/commands/mtc.js +7 -1
  173. package/src/commands/nostr.js +31 -4
  174. package/src/commands/note.js +7 -4
  175. package/src/commands/plugin.js +125 -5
  176. package/src/commands/pqc.js +5 -0
  177. package/src/commands/reputation.js +10 -1
  178. package/src/commands/scim.js +6 -0
  179. package/src/commands/session.js +32 -10
  180. package/src/commands/siem.js +11 -0
  181. package/src/commands/sla.js +18 -3
  182. package/src/commands/social.js +38 -5
  183. package/src/commands/sso.js +10 -2
  184. package/src/commands/stress.js +23 -4
  185. package/src/commands/team.js +9 -2
  186. package/src/commands/tech.js +2 -0
  187. package/src/commands/tenant.js +10 -1
  188. package/src/commands/terraform.js +6 -0
  189. package/src/commands/update.js +1 -1
  190. package/src/commands/zkp.js +20 -0
  191. package/src/gateways/ws/message-dispatcher.js +5 -2
  192. package/src/gateways/ws/remote-session-protocol.js +103 -42
  193. package/src/harness/jsonl-session-store.js +12 -5
  194. package/src/harness/plugin-manager.js +16 -4
  195. package/src/harness/remote-command-ledger.js +46 -15
  196. package/src/harness/worktree-isolator.js +16 -6
  197. package/src/lib/__tests__/logger.test.js +5 -2
  198. package/src/lib/a2a-protocol.js +25 -1
  199. package/src/lib/activitypub-bridge.js +61 -0
  200. package/src/lib/agent-core.js +2 -0
  201. package/src/lib/agent-economy.js +262 -29
  202. package/src/lib/agent-network.js +7 -1
  203. package/src/lib/agent-team/team-runner.js +25 -9
  204. package/src/lib/agent-team/team-worktree.js +36 -4
  205. package/src/lib/async-hook-supervisor.cjs +102 -16
  206. package/src/lib/audit-logger.js +7 -6
  207. package/src/lib/autonomous-developer.js +60 -0
  208. package/src/lib/chat-core.js +17 -4
  209. package/src/lib/collaboration-governance.js +56 -0
  210. package/src/lib/community-governance.js +68 -0
  211. package/src/lib/compliance-manager.js +63 -0
  212. package/src/lib/cross-chain.js +5 -0
  213. package/src/lib/dao-governance.js +151 -2
  214. package/src/lib/did-manager.js +23 -10
  215. package/src/lib/dlp-engine.js +70 -0
  216. package/src/lib/eval/runner.js +89 -1
  217. package/src/lib/eval/tasks.js +170 -0
  218. package/src/lib/eval/trend.js +16 -1
  219. package/src/lib/evolution-system.js +92 -0
  220. package/src/lib/evomap-federation.js +55 -0
  221. package/src/lib/evomap-governance.js +94 -0
  222. package/src/lib/fatal-handler.js +17 -1
  223. package/src/lib/hardening-manager.js +73 -0
  224. package/src/lib/hierarchical-memory.js +14 -8
  225. package/src/lib/knowledge-exporter.js +8 -2
  226. package/src/lib/knowledge-graph.js +79 -0
  227. package/src/lib/llm-providers.js +23 -14
  228. package/src/lib/logger.js +4 -1
  229. package/src/lib/lsp/__tests__/benchmark.test.js +88 -0
  230. package/src/lib/lsp/__tests__/lsp-client.test.js +11 -0
  231. package/src/lib/lsp/__tests__/lsp-manager.test.js +69 -0
  232. package/src/lib/lsp/benchmark.js +257 -0
  233. package/src/lib/lsp/lsp-client.js +30 -9
  234. package/src/lib/lsp/lsp-manager.js +54 -2
  235. package/src/lib/matrix-bridge.js +84 -0
  236. package/src/lib/memory-manager.js +5 -3
  237. package/src/lib/nostr-bridge.js +53 -0
  238. package/src/lib/permission-engine.js +22 -4
  239. package/src/lib/plugin-runtime/__tests__/remote-source.test.js +256 -0
  240. package/src/lib/plugin-runtime/install.js +9 -1
  241. package/src/lib/plugin-runtime/policy.js +9 -1
  242. package/src/lib/plugin-runtime/remote-source.js +240 -0
  243. package/src/lib/pqc-manager.js +64 -0
  244. package/src/lib/reputation-optimizer.js +101 -0
  245. package/src/lib/sandbox-egress-proxy.js +159 -59
  246. package/src/lib/sandbox-fs-policy.js +112 -0
  247. package/src/lib/sandbox-network-policy.js +18 -1
  248. package/src/lib/sandbox-v2.js +14 -14
  249. package/src/lib/scim-manager.js +36 -0
  250. package/src/lib/session-manager.js +5 -2
  251. package/src/lib/settings-hooks.cjs +1 -0
  252. package/src/lib/siem-exporter.js +45 -0
  253. package/src/lib/skill-loader.js +20 -2
  254. package/src/lib/skill-marketplace.js +83 -0
  255. package/src/lib/sla-manager.js +88 -0
  256. package/src/lib/social-manager.js +74 -0
  257. package/src/lib/stress-tester.js +65 -0
  258. package/src/lib/tech-learning-engine.js +75 -0
  259. package/src/lib/tenant-saas.js +107 -0
  260. package/src/lib/terraform-manager.js +67 -0
  261. package/src/lib/token-incentive.js +180 -29
  262. package/src/lib/wallet-manager.js +81 -35
  263. package/src/lib/zkp-engine.js +87 -0
  264. package/src/repl/agent-repl.js +17 -2
  265. package/src/runtime/__tests__/auto-pin.test.js +104 -0
  266. package/src/runtime/agent-core.js +241 -68
  267. package/src/runtime/auto-pin.js +117 -0
  268. package/src/runtime/headless-runner.js +35 -0
  269. package/src/assets/web-panel/assets/OrderTableRenderer-CRIFE2Tj.js +0 -1
  270. package/src/assets/web-panel/assets/Projects-CGcNIs_g.js +0 -1
  271. package/src/assets/web-panel/assets/devWarning-DxwmsL4j.js +0 -1
  272. package/src/assets/web-panel/assets/index-Cg2ldRfU.js +0 -1
  273. package/src/assets/web-panel/assets/index-Dwzo-dtJ.js +0 -1
@@ -224,14 +224,15 @@ function _recordTransaction(db, config) {
224
224
  createdAt: now,
225
225
  _seq: ++_seq,
226
226
  };
227
- _transactions.set(id, tx);
228
-
229
227
  if (db) {
230
228
  db.prepare(
231
229
  `INSERT INTO token_transactions (id, from_account, to_account, amount, reason, type, created_at)
232
230
  VALUES (?, ?, ?, ?, ?, ?, ?)`,
233
231
  ).run(id, tx.fromAccount, tx.toAccount, tx.amount, tx.reason, tx.type, now);
234
232
  }
233
+ // Register in the in-memory ledger only after the row is persisted, so a
234
+ // failed INSERT (e.g. inside a rolled-back transaction) leaves no phantom.
235
+ _transactions.set(id, tx);
235
236
  return tx;
236
237
  }
237
238
 
@@ -255,6 +256,21 @@ export function transfer(db, config = {}) {
255
256
  throw new Error(`Insufficient balance: ${fromAccount.balance} < ${amount}`);
256
257
  }
257
258
 
259
+ // The debit, the credit and the ledger row must all land or none of them.
260
+ // Without an enclosing transaction a mid-way failure would persist the debit
261
+ // but not the credit (tokens vanish) or move the balances yet never record
262
+ // the ledger — and the CLI re-hydrates from these tables, so it survives.
263
+ const fromSnap = {
264
+ balance: fromAccount.balance,
265
+ totalSpent: fromAccount.totalSpent,
266
+ updatedAt: fromAccount.updatedAt,
267
+ };
268
+ const toSnap = {
269
+ balance: toAccount.balance,
270
+ totalEarned: toAccount.totalEarned,
271
+ updatedAt: toAccount.updatedAt,
272
+ };
273
+
258
274
  fromAccount.balance -= amount;
259
275
  fromAccount.totalSpent += amount;
260
276
  fromAccount.updatedAt = now;
@@ -262,17 +278,33 @@ export function transfer(db, config = {}) {
262
278
  toAccount.totalEarned += amount;
263
279
  toAccount.updatedAt = now;
264
280
 
265
- _persistAccount(db, fromAccount);
266
- _persistAccount(db, toAccount);
281
+ let tx;
282
+ const applyWrites = () => {
283
+ _persistAccount(db, fromAccount);
284
+ _persistAccount(db, toAccount);
285
+ tx = _recordTransaction(db, {
286
+ from,
287
+ to,
288
+ amount,
289
+ reason: config.reason,
290
+ type: TX_TYPES.TRANSFER,
291
+ now,
292
+ });
293
+ };
294
+
295
+ try {
296
+ if (db && typeof db.transaction === "function") {
297
+ db.transaction(applyWrites)();
298
+ } else {
299
+ applyWrites();
300
+ }
301
+ } catch (err) {
302
+ // Roll the in-memory Maps back so they match the rolled-back DB.
303
+ Object.assign(fromAccount, fromSnap);
304
+ Object.assign(toAccount, toSnap);
305
+ throw err;
306
+ }
267
307
 
268
- const tx = _recordTransaction(db, {
269
- from,
270
- to,
271
- amount,
272
- reason: config.reason,
273
- type: TX_TYPES.TRANSFER,
274
- now,
275
- });
276
308
  return _strip(tx);
277
309
  }
278
310
 
@@ -425,28 +457,59 @@ export function rewardContribution(db, contributionId, opts = {}) {
425
457
 
426
458
  const now = Number(opts.now ?? Date.now());
427
459
  const account = _ensureAccount(db, contribution.userId, now);
460
+
461
+ // Credit the account, record the ledger row and mark the contribution
462
+ // rewarded atomically. A partial failure would otherwise credit the balance
463
+ // without flipping `rewarded`, letting the same contribution be rewarded
464
+ // again after the next re-hydrate (double-reward).
465
+ const acctSnap = {
466
+ balance: account.balance,
467
+ totalEarned: account.totalEarned,
468
+ updatedAt: account.updatedAt,
469
+ };
470
+ const contribSnap = {
471
+ rewarded: contribution.rewarded,
472
+ rewardAmount: contribution.rewardAmount,
473
+ txId: contribution.txId,
474
+ };
475
+
428
476
  account.balance += amount;
429
477
  account.totalEarned += amount;
430
478
  account.updatedAt = now;
431
- _persistAccount(db, account);
432
-
433
- const tx = _recordTransaction(db, {
434
- from: null,
435
- to: contribution.userId,
436
- amount,
437
- reason: `contribution:${contribution.type}:${contributionId.slice(0, 8)}`,
438
- type: TX_TYPES.REWARD,
439
- now,
440
- });
441
479
 
442
- contribution.rewarded = true;
443
- contribution.rewardAmount = amount;
444
- contribution.txId = tx.id;
480
+ let tx;
481
+ const applyWrites = () => {
482
+ _persistAccount(db, account);
483
+ tx = _recordTransaction(db, {
484
+ from: null,
485
+ to: contribution.userId,
486
+ amount,
487
+ reason: `contribution:${contribution.type}:${contributionId.slice(0, 8)}`,
488
+ type: TX_TYPES.REWARD,
489
+ now,
490
+ });
491
+ contribution.rewarded = true;
492
+ contribution.rewardAmount = amount;
493
+ contribution.txId = tx.id;
494
+ if (db) {
495
+ db.prepare(
496
+ `UPDATE contributions SET rewarded = ?, reward_amount = ?, tx_id = ? WHERE id = ?`,
497
+ ).run(1, amount, tx.id, contributionId);
498
+ }
499
+ };
445
500
 
446
- if (db) {
447
- db.prepare(
448
- `UPDATE contributions SET rewarded = ?, reward_amount = ?, tx_id = ? WHERE id = ?`,
449
- ).run(1, amount, tx.id, contributionId);
501
+ try {
502
+ if (db && typeof db.transaction === "function") {
503
+ db.transaction(applyWrites)();
504
+ } else {
505
+ applyWrites();
506
+ }
507
+ } catch (err) {
508
+ // Roll the in-memory Maps back to match the rolled-back DB.
509
+ Object.assign(account, acctSnap);
510
+ Object.assign(contribution, contribSnap);
511
+ if (tx) _transactions.delete(tx.id);
512
+ throw err;
450
513
  }
451
514
 
452
515
  return { contribution: _strip(contribution), tx: _strip(tx) };
@@ -512,6 +575,94 @@ export function _resetState() {
512
575
  _seq = 0;
513
576
  }
514
577
 
578
+ /**
579
+ * Rehydrate the in-memory ledger Maps from the persisted token_* tables. The CLI
580
+ * runs each `cc incentive` subcommand in a fresh node process, so these
581
+ * module-level Maps start empty every invocation. Every write dual-writes (Map +
582
+ * INSERT into token_accounts/token_transactions/contributions) but every read
583
+ * (getBalance/listAccounts/getTransactionHistory/getContributions/
584
+ * getLeaderboard) is Map-only and nothing SELECTed the tables back.
585
+ *
586
+ * This is worse than mere invisibility: `_ensureAccount` does `_accounts.get`
587
+ * (miss on a cold Map) → creates balance 0 → `_persistAccount` INSERT OR REPLACE,
588
+ * so a second process minting/rewarding an existing account CLOBBERS the
589
+ * persisted balance to 0 before applying its delta — balances never accumulate
590
+ * and transfers fail with "Insufficient balance: 0". Call after
591
+ * ensureTokenTables(db).
592
+ */
593
+ export function loadFromDb(db) {
594
+ if (!db) return 0;
595
+ ensureTokenTables(db);
596
+ _accounts.clear();
597
+ _transactions.clear();
598
+ _contributions.clear();
599
+
600
+ for (const r of db
601
+ .prepare(
602
+ `SELECT id, account_id, balance, total_earned, total_spent, created_at, updated_at
603
+ FROM token_accounts ORDER BY created_at ASC`,
604
+ )
605
+ .all()) {
606
+ _accounts.set(r.account_id, {
607
+ id: r.id,
608
+ accountId: r.account_id,
609
+ balance: Number(r.balance) || 0,
610
+ totalEarned: Number(r.total_earned) || 0,
611
+ totalSpent: Number(r.total_spent) || 0,
612
+ createdAt: Number(r.created_at),
613
+ updatedAt: Number(r.updated_at),
614
+ _seq: ++_seq,
615
+ });
616
+ }
617
+
618
+ for (const r of db
619
+ .prepare(
620
+ `SELECT id, from_account, to_account, amount, reason, type, created_at
621
+ FROM token_transactions ORDER BY created_at ASC`,
622
+ )
623
+ .all()) {
624
+ _transactions.set(r.id, {
625
+ id: r.id,
626
+ fromAccount: r.from_account ?? null,
627
+ toAccount: r.to_account ?? null,
628
+ amount: Number(r.amount),
629
+ reason: r.reason ?? null,
630
+ type: r.type,
631
+ createdAt: Number(r.created_at),
632
+ _seq: ++_seq,
633
+ });
634
+ }
635
+
636
+ for (const r of db
637
+ .prepare(
638
+ `SELECT id, user_id, type, value, metadata, rewarded, reward_amount, tx_id, created_at
639
+ FROM contributions ORDER BY created_at ASC`,
640
+ )
641
+ .all()) {
642
+ // One corrupt metadata cell must not sink the whole ledger load.
643
+ let metadata = null;
644
+ try {
645
+ metadata = r.metadata ? JSON.parse(r.metadata) : null;
646
+ } catch {
647
+ metadata = null;
648
+ }
649
+ _contributions.set(r.id, {
650
+ id: r.id,
651
+ userId: r.user_id,
652
+ type: r.type,
653
+ value: Number(r.value) || 0,
654
+ metadata,
655
+ rewarded: !!r.rewarded,
656
+ rewardAmount: Number(r.reward_amount) || 0,
657
+ txId: r.tx_id ?? null,
658
+ createdAt: Number(r.created_at),
659
+ _seq: ++_seq,
660
+ });
661
+ }
662
+
663
+ return _accounts.size + _transactions.size + _contributions.size;
664
+ }
665
+
515
666
  // ═══════════════════════════════════════════════════════════════
516
667
  // Phase 66 V2 — Account + Claim lifecycle, per-user claim cap
517
668
  // ═══════════════════════════════════════════════════════════════
@@ -159,10 +159,23 @@ export function setDefaultWallet(db, address) {
159
159
  const wallet = getWallet(db, address);
160
160
  if (!wallet) return false;
161
161
 
162
- db.prepare("UPDATE wallets SET is_default = 0 WHERE address LIKE ?").run("%");
163
- db.prepare("UPDATE wallets SET is_default = 1 WHERE address = ?").run(
164
- address,
165
- );
162
+ // Clear the current default(s) then set the new one atomically. Without a
163
+ // transaction, a failure on the second UPDATE leaves every wallet non-default
164
+ // (the default signing/sending wallet silently disappears until re-set),
165
+ // breaking the exactly-one-default invariant.
166
+ const applyWrites = () => {
167
+ db.prepare("UPDATE wallets SET is_default = 0 WHERE address LIKE ?").run(
168
+ "%",
169
+ );
170
+ db.prepare("UPDATE wallets SET is_default = 1 WHERE address = ?").run(
171
+ address,
172
+ );
173
+ };
174
+ if (db && typeof db.transaction === "function") {
175
+ db.transaction(applyWrites)();
176
+ } else {
177
+ applyWrites();
178
+ }
166
179
  return true;
167
180
  }
168
181
 
@@ -171,21 +184,36 @@ export function setDefaultWallet(db, address) {
171
184
  */
172
185
  export function deleteWallet(db, address) {
173
186
  ensureWalletTables(db);
174
- const result = db
175
- .prepare("DELETE FROM wallets WHERE address = ?")
176
- .run(address);
177
- if (result.changes > 0) {
178
- // Promote next wallet to default
179
- const next = db
180
- .prepare("SELECT address FROM wallets ORDER BY created_at ASC LIMIT 1")
181
- .get();
182
- if (next) {
183
- db.prepare("UPDATE wallets SET is_default = 1 WHERE address = ?").run(
184
- next.address,
185
- );
187
+ const wallet = getWallet(db, address);
188
+ if (!wallet) return false;
189
+ const wasDefault = Number(wallet.is_default) === 1;
190
+
191
+ const doDelete = () => {
192
+ const result = db
193
+ .prepare("DELETE FROM wallets WHERE address = ?")
194
+ .run(address);
195
+ // Only promote a new default when the DELETED wallet was the default —
196
+ // otherwise the existing default is untouched and promoting the oldest
197
+ // remaining wallet would leave two defaults. Promote the oldest remaining
198
+ // so exactly one default survives.
199
+ if (result.changes > 0 && wasDefault) {
200
+ const next = db
201
+ .prepare("SELECT address FROM wallets ORDER BY created_at ASC LIMIT 1")
202
+ .get();
203
+ if (next) {
204
+ db.prepare("UPDATE wallets SET is_default = 1 WHERE address = ?").run(
205
+ next.address,
206
+ );
207
+ }
186
208
  }
187
- }
188
- return result.changes > 0;
209
+ return result.changes;
210
+ };
211
+
212
+ const changes =
213
+ db && typeof db.transaction === "function"
214
+ ? db.transaction(doDelete)()
215
+ : doDelete();
216
+ return changes > 0;
189
217
  }
190
218
 
191
219
  /**
@@ -278,28 +306,46 @@ export function transferAsset(db, assetId, toAddress, amount) {
278
306
  const asset = getAsset(db, assetId);
279
307
  if (!asset) throw new Error(`Asset not found: ${assetId}`);
280
308
 
309
+ // The destination must be a real local wallet — createAsset enforces the same
310
+ // invariant on the way in. Without this, a transfer to a bogus address moves
311
+ // the asset out of the sender's wallet to an address no wallet owns, so it
312
+ // disappears from every getAssets/getWalletSummary view (permanently orphaned).
313
+ const dest = getWallet(db, toAddress);
314
+ if (!dest) throw new Error(`Destination wallet not found: ${toAddress}`);
315
+
281
316
  const txId = `tx-${crypto.randomBytes(8).toString("hex")}`;
282
317
  const fromAddress = asset.wallet_address;
283
318
  const txAmount = amount || asset.amount;
284
319
 
285
- db.prepare(
286
- `INSERT INTO transactions (id, from_address, to_address, asset_id, amount, tx_type, status)
287
- VALUES (?, ?, ?, ?, ?, ?, ?)`,
288
- ).run(
289
- txId,
290
- fromAddress,
291
- toAddress,
292
- assetId,
293
- txAmount,
294
- "transfer",
295
- "confirmed",
296
- );
320
+ // Record the ledger row and move ownership atomically. Without a transaction,
321
+ // a failure on the ownership UPDATE would leave a "confirmed" transactions row
322
+ // for a transfer that never happened (the asset stays with the sender).
323
+ const applyWrites = () => {
324
+ db.prepare(
325
+ `INSERT INTO transactions (id, from_address, to_address, asset_id, amount, tx_type, status)
326
+ VALUES (?, ?, ?, ?, ?, ?, ?)`,
327
+ ).run(
328
+ txId,
329
+ fromAddress,
330
+ toAddress,
331
+ assetId,
332
+ txAmount,
333
+ "transfer",
334
+ "confirmed",
335
+ );
297
336
 
298
- // Update asset ownership
299
- db.prepare("UPDATE digital_assets SET wallet_address = ? WHERE id = ?").run(
300
- toAddress,
301
- assetId,
302
- );
337
+ // Update asset ownership
338
+ db.prepare("UPDATE digital_assets SET wallet_address = ? WHERE id = ?").run(
339
+ toAddress,
340
+ assetId,
341
+ );
342
+ };
343
+
344
+ if (db && typeof db.transaction === "function") {
345
+ db.transaction(applyWrites)();
346
+ } else {
347
+ applyWrites();
348
+ }
303
349
 
304
350
  return {
305
351
  txId,
@@ -471,6 +471,93 @@ export function _resetState() {
471
471
  _proofExpiryMs = ZKP_DEFAULT_PROOF_EXPIRY_MS;
472
472
  }
473
473
 
474
+ /**
475
+ * Rehydrate the in-memory Maps from the persisted zkp_* tables. The CLI runs
476
+ * each `cc zkp` subcommand in a fresh node process, so _circuits/_proofs/
477
+ * _verificationKeys/_credentials start empty every invocation. Every write
478
+ * dual-writes (Map + INSERT into zkp_circuits/zkp_proofs/zkp_credentials) but
479
+ * every read (listCircuits/listProofs/listCredentials/getZKPStats + the
480
+ * generateProof/verifyProof/selectiveDisclose lookups) is Map-only and nothing
481
+ * SELECTed the tables back — so `zkp circuits`/`proofs`/`credentials` were always
482
+ * empty, and `prove`/`verify`/`disclose` threw "not found" for a circuit/proof/
483
+ * credential that genuinely exists on disk. Call after ensureZKPTables(db).
484
+ */
485
+ export function loadFromDb(db) {
486
+ if (!db) return 0;
487
+ ensureZKPTables(db);
488
+ _circuits.clear();
489
+ _proofs.clear();
490
+ _verificationKeys.clear();
491
+ _credentials.clear();
492
+
493
+ const parse = (v, fallback) => {
494
+ try {
495
+ return v ? JSON.parse(v) : fallback;
496
+ } catch {
497
+ return fallback;
498
+ }
499
+ };
500
+
501
+ for (const r of db
502
+ .prepare(
503
+ `SELECT id, name, definition, compiled, verification_key, status, created_at
504
+ FROM zkp_circuits ORDER BY created_at ASC`,
505
+ )
506
+ .all()) {
507
+ const definition = parse(r.definition, {});
508
+ const constraints = Array.isArray(definition.constraints)
509
+ ? definition.constraints
510
+ : [];
511
+ _circuits.set(r.id, {
512
+ id: r.id,
513
+ name: r.name,
514
+ definition,
515
+ compiled: parse(r.compiled, {}),
516
+ constraints: constraints.length || 1,
517
+ inputs: definition.inputs || [],
518
+ outputs: definition.outputs || [],
519
+ verificationKey: r.verification_key,
520
+ status: r.status,
521
+ createdAt: r.created_at,
522
+ });
523
+ if (r.verification_key) _verificationKeys.set(r.id, r.verification_key);
524
+ }
525
+
526
+ for (const r of db
527
+ .prepare(
528
+ `SELECT id, circuit_id, proof, public_inputs, verified, scheme, created_at
529
+ FROM zkp_proofs ORDER BY created_at ASC`,
530
+ )
531
+ .all()) {
532
+ _proofs.set(r.id, {
533
+ id: r.id,
534
+ circuitId: r.circuit_id,
535
+ scheme: r.scheme,
536
+ proof: parse(r.proof, {}),
537
+ publicInputs: parse(r.public_inputs, []),
538
+ verified: !!r.verified,
539
+ createdAt: r.created_at,
540
+ });
541
+ }
542
+
543
+ for (const r of db
544
+ .prepare(
545
+ `SELECT id, did, claims, merkle_root, created_at
546
+ FROM zkp_credentials ORDER BY created_at ASC`,
547
+ )
548
+ .all()) {
549
+ _credentials.set(r.id, {
550
+ id: r.id,
551
+ did: r.did ?? null,
552
+ claims: parse(r.claims, {}),
553
+ merkleRoot: r.merkle_root,
554
+ createdAt: r.created_at,
555
+ });
556
+ }
557
+
558
+ return _circuits.size + _proofs.size + _credentials.size;
559
+ }
560
+
474
561
  /* ──────────────────────────────────────────────────────────
475
562
  * V2 — Phase 88 surface (strictly additive)
476
563
  * ────────────────────────────────────────────────────────── */
@@ -64,6 +64,7 @@ import {
64
64
  PromptCompressor,
65
65
  getContextWindow,
66
66
  } from "../harness/prompt-compressor.js";
67
+ import { buildAutoPinPredicate } from "../runtime/auto-pin.js";
67
68
  import { feature } from "../lib/feature-flags.js";
68
69
  import { recordCompressionMetric } from "../lib/compression-telemetry.js";
69
70
  import {
@@ -416,10 +417,15 @@ export async function startAgentRepl(options = {}) {
416
417
  // Unset → agent-core's 180s default (matches cc chat/ask). Set to 0 to
417
418
  // disable. Left undefined here means "use the default".
418
419
  let _streamStallTimeoutMs;
420
+ // Auto-pin (OPT-IN, off by default): when set, compaction pins the original
421
+ // task. Resolved from config `context.autoPin` or CC_AUTO_PIN=1; falsy → the
422
+ // compress calls below pass no pin predicate (byte-identical default).
423
+ let _autoPinOpt;
419
424
  try {
420
425
  const { loadConfig } = await import("../lib/config-manager.js");
421
426
  const _cfg = loadConfig();
422
427
  _visionModel = _cfg?.llm?.visionModel || undefined;
428
+ _autoPinOpt = _cfg?.context?.autoPin;
423
429
  const raw = _cfg?.llm?.streamStallTimeoutMs;
424
430
  const t = Number(raw);
425
431
  // Accept 0 (explicit disable) — only ignore absent/invalid values.
@@ -477,6 +483,15 @@ export async function startAgentRepl(options = {}) {
477
483
  if (feature("PROMPT_COMPRESSOR")) {
478
484
  _compressor = new PromptCompressor({ model, provider });
479
485
  }
486
+ if (process.env.CC_AUTO_PIN === "1") _autoPinOpt = _autoPinOpt || true;
487
+ // Compaction options shared by /compact + auto-compact. Adds the opt-in
488
+ // pin predicate only when auto-pin is enabled; otherwise byte-identical.
489
+ const _compactOpts = (msgs) => {
490
+ const base = { preserveToolPairs: true };
491
+ if (!_autoPinOpt) return base;
492
+ const isPinned = buildAutoPinPredicate(msgs, _autoPinOpt);
493
+ return isPinned ? { ...base, isPinned } : base;
494
+ };
480
495
 
481
496
  // Initialize permanent memory
482
497
  let permanentMemory = null;
@@ -2533,7 +2548,7 @@ export async function startAgentRepl(options = {}) {
2533
2548
  if (_compressor && messages.length > 3) {
2534
2549
  const { messages: compacted, stats } = await _compressor.compress(
2535
2550
  messages,
2536
- { preserveToolPairs: true },
2551
+ _compactOpts(messages),
2537
2552
  );
2538
2553
  messages.length = 0;
2539
2554
  messages.push(...compacted);
@@ -4460,7 +4475,7 @@ export async function startAgentRepl(options = {}) {
4460
4475
  try {
4461
4476
  const { messages: compacted, stats } = await _compressor.compress(
4462
4477
  messages,
4463
- { preserveToolPairs: true },
4478
+ _compactOpts(messages),
4464
4479
  );
4465
4480
  messages.length = 0;
4466
4481
  messages.push(...compacted);
@@ -0,0 +1,104 @@
1
+ /**
2
+ * auto-pin policy tests — the OPT-IN compaction pin policy. Verifies it is off
3
+ * by default (returns null → caller passes no predicate → byte-identical), and
4
+ * when enabled pins the original task (first user turn) plus explicit pins,
5
+ * honoring the token cap.
6
+ */
7
+
8
+ import { describe, it, expect } from "vitest";
9
+ import {
10
+ resolveAutoPinConfig,
11
+ buildAutoPinPredicate,
12
+ describeAutoPin,
13
+ } from "../auto-pin.js";
14
+
15
+ const MSGS = [
16
+ { role: "system", content: "you are a coding agent" },
17
+ { role: "user", content: "Refactor the auth module to use async/await" },
18
+ { role: "assistant", content: "ok, reading files" },
19
+ { role: "user", content: "also add tests" },
20
+ ];
21
+
22
+ describe("resolveAutoPinConfig", () => {
23
+ it("returns null when off (falsy)", () => {
24
+ expect(resolveAutoPinConfig(undefined)).toBeNull();
25
+ expect(resolveAutoPinConfig(false)).toBeNull();
26
+ expect(resolveAutoPinConfig(0)).toBeNull();
27
+ });
28
+ it("defaults firstUserGoal on when enabled with true", () => {
29
+ expect(resolveAutoPinConfig(true)).toMatchObject({ firstUserGoal: true });
30
+ });
31
+ it("accepts an object and can disable firstUserGoal", () => {
32
+ expect(resolveAutoPinConfig({ firstUserGoal: false })).toMatchObject({
33
+ firstUserGoal: false,
34
+ });
35
+ expect(resolveAutoPinConfig({ maxPinTokens: 50 }).maxPinTokens).toBe(50);
36
+ });
37
+ });
38
+
39
+ describe("buildAutoPinPredicate", () => {
40
+ it("returns null when auto-pin is off (→ default compaction, byte-identical)", () => {
41
+ expect(buildAutoPinPredicate(MSGS, false)).toBeNull();
42
+ expect(buildAutoPinPredicate(MSGS, undefined)).toBeNull();
43
+ });
44
+
45
+ it("pins the first user turn (the original task) when enabled", () => {
46
+ const isPinned = buildAutoPinPredicate(MSGS, true);
47
+ expect(isPinned(MSGS[1])).toBe(true); // first user
48
+ expect(isPinned(MSGS[3])).toBe(false); // second user NOT pinned
49
+ expect(isPinned(MSGS[0])).toBe(false); // system not pinned
50
+ expect(isPinned(MSGS[2])).toBe(false); // assistant not pinned
51
+ });
52
+
53
+ it("always honors explicit pins on top of the policy", () => {
54
+ const msgs = [
55
+ ...MSGS,
56
+ { role: "assistant", content: "important decision", pinned: true },
57
+ { role: "assistant", content: "legacy marker", _pin: true },
58
+ ];
59
+ const isPinned = buildAutoPinPredicate(msgs, true);
60
+ expect(isPinned(msgs[4])).toBe(true); // pinned:true
61
+ expect(isPinned(msgs[5])).toBe(true); // _pin
62
+ });
63
+
64
+ it("honors explicit pins even with firstUserGoal disabled", () => {
65
+ const msgs = [
66
+ MSGS[0],
67
+ MSGS[1],
68
+ { role: "user", content: "x", pinned: true },
69
+ ];
70
+ const isPinned = buildAutoPinPredicate(msgs, { firstUserGoal: false });
71
+ expect(isPinned(msgs[1])).toBe(false); // first user NOT auto-pinned
72
+ expect(isPinned(msgs[2])).toBe(true); // explicit pin still honored
73
+ });
74
+
75
+ it("skips a first user turn that exceeds the token cap", () => {
76
+ const big = { role: "user", content: "x".repeat(10_000) }; // ~2500 tokens
77
+ const msgs = [MSGS[0], big, MSGS[2]];
78
+ const isPinned = buildAutoPinPredicate(msgs, { maxPinTokens: 100 });
79
+ expect(isPinned(big)).toBe(false); // too big to pin
80
+ });
81
+
82
+ it("matches by identity, not by value (compaction filters the same array)", () => {
83
+ const isPinned = buildAutoPinPredicate(MSGS, true);
84
+ const clone = { ...MSGS[1] }; // same content, different object
85
+ expect(isPinned(clone)).toBe(false);
86
+ });
87
+ });
88
+
89
+ describe("describeAutoPin", () => {
90
+ it("reports disabled when off", () => {
91
+ expect(describeAutoPin(MSGS, false)).toEqual({
92
+ enabled: false,
93
+ reasons: [],
94
+ });
95
+ });
96
+ it("explains the original-task pin", () => {
97
+ const d = describeAutoPin(MSGS, true);
98
+ expect(d.enabled).toBe(true);
99
+ expect(d.reasons.some((r) => r.why.includes("original task"))).toBe(true);
100
+ expect(d.reasons[d.reasons.length - 1].preview).toContain(
101
+ "Refactor the auth",
102
+ );
103
+ });
104
+ });