chainlesschain 0.162.151 → 0.162.153

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 (187) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-DuEOzebi.js → AIOps-CBilhs1R.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-C6GiJa5H.js → ActionButton-Cf-RnC5Y.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-BBIiL_pO.js → Analytics-S8tkGhw0.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CuI2gZRy.js → AppLayout-CNXI3Bw5.js} +5 -5
  8. package/src/assets/web-panel/assets/{Audit-CbUjfr-K.js → Audit-DF2zVFZ0.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-CsSW9ljf.js → Backup-CMEiwQZL.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-kM3rLe7F.js → BaseInput-rwLw4K70.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-kfE51YN3.js → Chat-C478H8u9.js} +5 -5
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-DNQsKN61.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-jYb1uj-M.js → Checkbox-D-47X635.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-X9XiD5Lj.js → Codegen-Cb9Ihed5.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-BfbHu1xI.js → Col-CQsdzczt.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-c4oJMFS-.js → Community-DiqzeAy-.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-BFmnZpH7.js → Compact-Bq-APyyF.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-s9shVHBS.js → Compliance-Dnb1YxPr.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-C5da--TC.js → Cowork-CZljerdQ.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-9kNbyNE4.js → Cron-gAdbZOq7.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-C1k3NJD4.js → Crosschain-DMPGXttD.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-DkheEvNK.js → DID-C7dBDAv8.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-C3FuSGmJ.js → Dashboard-ByR4VcF8.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-CAV6FMFD.js → Dropdown-Bc4tbiQN.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-Cc-Ulc4l.js → EmailListRenderer-BhUN2pDw.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-8CitHEtv.js → FamilyGuardDashboard-DpJuANCD.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-DFSZ5KDt.js → Federation-BEm4TvcE.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CEWCtnG2.js → FormItemContext-JnkPkhiC.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-CwRzNzmX.js → GenericCardRenderer-BfCzFUIC.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-0rgDM7cJ.js → Git-1c0MWpmD.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-CfBKtK9F.js → Governance-C_j3EBpv.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-CzcUVvud.js → Inference-Cb7XRgtY.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-Dwc4YL4A.js → KnowledgeGraph-DoHPvHyK.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-DgFPwR2F.js → Logs-CYriKpy-.js} +2 -2
  35. package/src/assets/web-panel/assets/{Marketplace-DnpPTbGU.js → Marketplace-BT56-GD0.js} +1 -1
  36. package/src/assets/web-panel/assets/{McpTools-DRxxINyW.js → McpTools-B6XX_wnZ.js} +4 -4
  37. package/src/assets/web-panel/assets/{Memory-OhmW_6Z3.js → Memory-DRgNuaQc.js} +2 -2
  38. package/src/assets/web-panel/assets/{MobileBridge-DkTW-RK5.js → MobileBridge-B0qgvBN2.js} +1 -1
  39. package/src/assets/web-panel/assets/MobileProjects-CRRfswf7.js +1 -0
  40. package/src/assets/web-panel/assets/{Mtc--vmkL0AS.js → Mtc-DnSFj9jw.js} +4 -4
  41. package/src/assets/web-panel/assets/{MtcAudit-DGoFWjD4.js → MtcAudit-c0tuz1sm.js} +4 -4
  42. package/src/assets/web-panel/assets/{Multisig-B4kWgq95.js → Multisig-CVLBGioX.js} +3 -3
  43. package/src/assets/web-panel/assets/{NLProgramming-YQwvommE.js → NLProgramming-CFaqmNbx.js} +1 -1
  44. package/src/assets/web-panel/assets/{Notes-CgjtUADJ.js → Notes-BM_mNwU_.js} +3 -3
  45. package/src/assets/web-panel/assets/{NotificationSettings-6JDrpBG5.js → NotificationSettings-Sa1k3ReS.js} +1 -1
  46. package/src/assets/web-panel/assets/OrderTableRenderer-lWzmtqBh.js +1 -0
  47. package/src/assets/web-panel/assets/{Organization-8McOT_OF.js → Organization-C2blcq-P.js} +4 -4
  48. package/src/assets/web-panel/assets/{Overflow-DAZpSCGc.js → Overflow-B3PwOJnK.js} +1 -1
  49. package/src/assets/web-panel/assets/{P2P-B7l2ZWLy.js → P2P-DaB9T6tb.js} +2 -2
  50. package/src/assets/web-panel/assets/{PdhVaultBrowser-W1Ud-NAL.js → PdhVaultBrowser-BpEBZ72n.js} +5 -5
  51. package/src/assets/web-panel/assets/{Permissions-Czm_w9u_.js → Permissions-BTkWInyH.js} +4 -4
  52. package/src/assets/web-panel/assets/{PersonalDataHub-B4F0_ZVM.js → PersonalDataHub-LHEwNmyL.js} +2 -2
  53. package/src/assets/web-panel/assets/{Pipeline-B37aFiWv.js → Pipeline-DvWIxqH-.js} +1 -1
  54. package/src/assets/web-panel/assets/{Privacy-94KBnRrD.js → Privacy-BDbpBagU.js} +1 -1
  55. package/src/assets/web-panel/assets/{ProjectInit-B5h8_dlh.js → ProjectInit-DLeMDWWv.js} +2 -2
  56. package/src/assets/web-panel/assets/ProjectSettings-BK3NsxIz.js +2 -0
  57. package/src/assets/web-panel/assets/Projects-BPWPg9zA.js +1 -0
  58. package/src/assets/web-panel/assets/{Providers-B3cNWwJg.js → Providers-D2EvmPAd.js} +1 -1
  59. package/src/assets/web-panel/assets/{QrScannerModal-CHRvOw1R.js → QrScannerModal-DAcu2fNg.js} +1 -1
  60. package/src/assets/web-panel/assets/{QuickAsk-D1JMgFEd.js → QuickAsk-B7U850Yt.js} +1 -1
  61. package/src/assets/web-panel/assets/{Recommend-EYWGR79p.js → Recommend-bxNXLzOR.js} +1 -1
  62. package/src/assets/web-panel/assets/{RemoteSession-BAMC2pJt.js → RemoteSession-BsCjAfSJ.js} +2 -2
  63. package/src/assets/web-panel/assets/{Reputation-X2Hk1XG_.js → Reputation-DZ9LPu-R.js} +1 -1
  64. package/src/assets/web-panel/assets/{Row-Eq98LRtU.js → Row-cIYkCB3Y.js} +1 -1
  65. package/src/assets/web-panel/assets/{RssFeed-i76s6z_o.js → RssFeed-BxTNTtTp.js} +2 -2
  66. package/src/assets/web-panel/assets/{Search-D_Es7CAI.js → Search-DSar6GhE.js} +1 -1
  67. package/src/assets/web-panel/assets/{Security-kayD2e94.js → Security-oCbIGysL.js} +4 -4
  68. package/src/assets/web-panel/assets/{Services-Ctsm6ul8.js → Services-D8yojrNv.js} +2 -2
  69. package/src/assets/web-panel/assets/{Skeleton-CRNYlfdf.js → Skeleton-vTA6P1eL.js} +1 -1
  70. package/src/assets/web-panel/assets/{Skills-DkZYpF4-.js → Skills-BXLf_KgZ.js} +1 -1
  71. package/src/assets/web-panel/assets/{Sla-DXkoBcOP.js → Sla-Cpwxzz__.js} +1 -1
  72. package/src/assets/web-panel/assets/{SpeechSettings-DXi_GI1d.js → SpeechSettings-DcPN9kCb.js} +1 -1
  73. package/src/assets/web-panel/assets/{SyncSettings-rNKpfomn.js → SyncSettings-DY0U5Vuj.js} +2 -2
  74. package/src/assets/web-panel/assets/{Tasks-XF4uPtG-.js → Tasks-DKu3-sZJ.js} +1 -1
  75. package/src/assets/web-panel/assets/{Templates-i0Hzfeyu.js → Templates-MD3nfWGm.js} +1 -1
  76. package/src/assets/web-panel/assets/{Tenant-sMpHAi27.js → Tenant-DKVnyGXM.js} +1 -1
  77. package/src/assets/web-panel/assets/Terminal-DQMIZfWf.js +3 -0
  78. package/src/assets/web-panel/assets/{TimelineRenderer-yuC6K7Rf.js → TimelineRenderer-CugmNZTs.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tokens-B8O8i0s6.js → Tokens-Cjvlttu6.js} +1 -1
  80. package/src/assets/web-panel/assets/{Trigger-Bv6yrlCr.js → Trigger-CzNOEcoI.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trust-C4mW95Ev.js → Trust-D5jg9iPA.js} +1 -1
  82. package/src/assets/web-panel/assets/{UkeySign-DV6yKaHn.js → UkeySign-59bMlvxY.js} +1 -1
  83. package/src/assets/web-panel/assets/{VideoEditing-UI479-sD.js → VideoEditing-DmCzSBqn.js} +1 -1
  84. package/src/assets/web-panel/assets/{Wallet-M5oV9EVP.js → Wallet-DoFe8V6W.js} +4 -4
  85. package/src/assets/web-panel/assets/{WebAuthn-DDyDHPDR.js → WebAuthn-9POLER-w.js} +5 -5
  86. package/src/assets/web-panel/assets/{WorkflowEditor-RoBv4rqk.js → WorkflowEditor-cFQH0Og6.js} +1 -1
  87. package/src/assets/web-panel/assets/{chat-Cw1mE5LS.js → chat-D3fR2NkZ.js} +1 -1
  88. package/src/assets/web-panel/assets/{colors-BFP62Gwf.js → colors-DiLEwE_P.js} +1 -1
  89. package/src/assets/web-panel/assets/{compact-item-17HL6pyC.js → compact-item-CGfFDdic.js} +1 -1
  90. package/src/assets/web-panel/assets/{createContext-D55X4fZX.js → createContext-BbIbOPL2.js} +1 -1
  91. package/src/assets/web-panel/assets/devWarning-B6FRgsmP.js +1 -0
  92. package/src/assets/web-panel/assets/{hasIn-D3E5mNsP.js → hasIn-DqyWp63_.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-DOjA8bvj.js → index-BCoDp6o_.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-tVRPgYGr.js → index-BKeRBUtO.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-RYZgFIwo.js → index-BKxvHCqz.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Da27u6j0.js → index-BiLP6SNu.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-CFYGn88j.js → index-BtcjYHgn.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-paVubXzn.js → index-BtwvOuvO.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D4LHSde4.js → index-ByE5tKjP.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-C_MfcrLf.js → index-C1S30j-Z.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DkBVYlE4.js → index-C2lZXIEA.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-ITeEHb8L.js → index-CH8gSMSA.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BC6zxOlU.js → index-CHpI6g_S.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-KtLJXn4s.js → index-CIleIMTT.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BY_xZ2jy.js → index-CToOzfR2.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Bzpp2z2S.js → index-CZQshOyI.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CvCFKojj.js → index-ComvO4hy.js} +1 -1
  108. package/src/assets/web-panel/assets/index-Cq411qtc.js +1 -0
  109. package/src/assets/web-panel/assets/{index-tUH_6bdJ.js → index-CweXQM71.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Cdvk2_2q.js → index-CySlHabI.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-gAVxDiTZ.js → index-D16FSRMW.js} +1 -1
  112. package/src/assets/web-panel/assets/index-D1oX0DK3.js +1 -0
  113. package/src/assets/web-panel/assets/{index-CLEzsZ8A.js → index-D3vQv3Kq.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BEa1RW4c.js → index-DH6qaU1a.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BQmZg5si.js → index-DPxmTldu.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-ASPYTzMK.js → index-DQH--Uw5.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-uSsiwgZ2.js → index-Db9UJVjj.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CR9rNUvi.js → index-DdLwxj-F.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Bq83UBDr.js → index-DdjXemK-.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-H9_X1Cg_.js → index-DzuGkFvy.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DD_qGBrt.js → index-FFlp8Jx9.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BnGpft-Z.js → index-Km36XQ3z.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CjCwi7we.js → index-auI9fxYH.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DzG7mkgW.js → index-fCfaVIr7.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DtAnPBWP.js → index-hVGbmc7y.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DCLu84x-.js → index-kL8f4MRS.js} +1 -1
  127. package/src/assets/web-panel/assets/{index--44J50mc.js → index-ns6bNnGo.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CW6LLoJO.js → index-qHvMk0U3.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DIRvdwBX.js → index-rTrejDjk.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CGyTos4p.js → index-tLaW5UzZ.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BgN5G5vF.js → index-xm1KHUEQ.js} +27 -27
  132. package/src/assets/web-panel/assets/{initDefaultProps-Ckp7xVZS.js → initDefaultProps-pg_7pnd6.js} +1 -1
  133. package/src/assets/web-panel/assets/{motion-DUZgCpn6.js → motion-B5GoJSZL.js} +1 -1
  134. package/src/assets/web-panel/assets/{move-B2rttglH.js → move-BaJoe2FW.js} +1 -1
  135. package/src/assets/web-panel/assets/{mtc-parser-BYWcLTuN.js → mtc-parser-CiQGbqtr.js} +1 -1
  136. package/src/assets/web-panel/assets/{omit-DhHqKeFx.js → omit-BFNEsKvU.js} +1 -1
  137. package/src/assets/web-panel/assets/{pickAttrs-ANpJaWMO.js → pickAttrs-YbSoANHm.js} +1 -1
  138. package/src/assets/web-panel/assets/{placementArrow-CfZWe7CA.js → placementArrow-C40MJPIH.js} +1 -1
  139. package/src/assets/web-panel/assets/{responsiveObserve-D7Xz2y-R.js → responsiveObserve-LaVz2zF6.js} +1 -1
  140. package/src/assets/web-panel/assets/{slide-DekqCBY9.js → slide-BkSoAGxF.js} +1 -1
  141. package/src/assets/web-panel/assets/{statusUtils-BET6XU7h.js → statusUtils-C4jWjohA.js} +1 -1
  142. package/src/assets/web-panel/assets/{styleChecker-qHmJjV62.js → styleChecker-BGqeIh-m.js} +1 -1
  143. package/src/assets/web-panel/assets/{useFlexGapSupport-BoMCTNyu.js → useFlexGapSupport-JsR5NMrM.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFs-TdW-NgFC.js → useFs-DOiP38RR.js} +1 -1
  145. package/src/assets/web-panel/assets/{usePersonalDataHub-Dyox7wCu.js → usePersonalDataHub-C-nC0ymt.js} +1 -1
  146. package/src/assets/web-panel/assets/{vnode-XUn5S8CP.js → vnode-BalilHOU.js} +1 -1
  147. package/src/assets/web-panel/assets/{zoom-Ls77i8hn.js → zoom-DjUELqks.js} +1 -1
  148. package/src/assets/web-panel/index.html +1 -1
  149. package/src/commands/agent.js +8 -1
  150. package/src/commands/eval.js +88 -23
  151. package/src/commands/plugin.js +10 -0
  152. package/src/commands/team.js +60 -3
  153. package/src/data/changelog.json +17 -2
  154. package/src/harness/mcp-client.js +115 -1
  155. package/src/harness/remote-command-ledger.js +60 -10
  156. package/src/lib/agent-sandbox.js +11 -5
  157. package/src/lib/agent-team/task-lease.js +28 -0
  158. package/src/lib/agent-team/team-runner.js +45 -0
  159. package/src/lib/config-manager.js +14 -1
  160. package/src/lib/eval/tasks.js +62 -41
  161. package/src/lib/eval/trend.js +7 -1
  162. package/src/lib/lsp/__tests__/lsp-client.test.js +12 -6
  163. package/src/lib/lsp/code-intelligence.js +55 -17
  164. package/src/lib/lsp/lsp-client.js +7 -1
  165. package/src/lib/plugin-runtime/install.js +20 -1
  166. package/src/lib/plugin-runtime/policy.js +13 -0
  167. package/src/lib/plugin-runtime/remote-source.js +34 -0
  168. package/src/lib/plugin-runtime/signature.js +79 -22
  169. package/src/lib/plugin-security.js +13 -14
  170. package/src/lib/sub-agent-context.js +28 -7
  171. package/src/lib/telemetry/span-recorder.js +30 -7
  172. package/src/repl/agent-repl.js +64 -21
  173. package/src/repl/permission-prompt.js +58 -0
  174. package/src/runtime/__tests__/auto-pin.test.js +27 -4
  175. package/src/runtime/agent-core.js +236 -1
  176. package/src/runtime/auto-pin.js +19 -0
  177. package/src/runtime/coding-agent-contract-shared.cjs +5 -0
  178. package/src/runtime/headless-runner.js +23 -5
  179. package/src/assets/web-panel/assets/ChatBubbleRenderer-Bg2FTW6A.js +0 -1
  180. package/src/assets/web-panel/assets/MobileProjects-DpCGV_lI.js +0 -1
  181. package/src/assets/web-panel/assets/OrderTableRenderer-PM6IlxjO.js +0 -1
  182. package/src/assets/web-panel/assets/ProjectSettings-lmeI3Lpm.js +0 -2
  183. package/src/assets/web-panel/assets/Projects-D5AYOasl.js +0 -1
  184. package/src/assets/web-panel/assets/Terminal-BoZvaYAl.js +0 -3
  185. package/src/assets/web-panel/assets/devWarning-CqbHYuRc.js +0 -1
  186. package/src/assets/web-panel/assets/index-CKBI1U5K.js +0 -1
  187. package/src/assets/web-panel/assets/index-CkLp6DTO.js +0 -1
@@ -80,16 +80,19 @@ export function verifyPluginManifest({
80
80
 
81
81
  const wantsSignature = requireSignature || signatureFile || publicKeyFile;
82
82
  let signatureVerified = false;
83
+ let signature = null;
84
+ let publicKeyPem = null;
85
+ let publicKeySha256 = null;
83
86
  if (wantsSignature) {
84
87
  if (!signatureFile || !publicKeyFile) {
85
88
  throw new Error(
86
89
  "plugin signature verification requires --signature and --public-key",
87
90
  );
88
91
  }
89
- const signature = readFileSync(signatureFile);
90
- const publicKey = readFileSync(publicKeyFile, "utf8");
91
- const keyObject = createPublicKey(publicKey);
92
- const publicKeySha256 = createHash("sha256")
92
+ signature = readFileSync(signatureFile);
93
+ publicKeyPem = readFileSync(publicKeyFile, "utf8");
94
+ const keyObject = createPublicKey(publicKeyPem);
95
+ publicKeySha256 = createHash("sha256")
93
96
  .update(keyObject.export({ type: "spki", format: "der" }))
94
97
  .digest("hex");
95
98
  const trusted = stringSet(trustedKeySha256);
@@ -110,16 +113,12 @@ export function verifyPluginManifest({
110
113
  bytes,
111
114
  sha256,
112
115
  signatureVerified,
113
- publicKeySha256: signatureVerified
114
- ? createHash("sha256")
115
- .update(
116
- createPublicKey(readFileSync(publicKeyFile, "utf8")).export({
117
- type: "spki",
118
- format: "der",
119
- }),
120
- )
121
- .digest("hex")
122
- : null,
116
+ publicKeySha256: signatureVerified ? publicKeySha256 : null,
117
+ // The raw signature material, so the installer can persist it and load-time
118
+ // enforcement can CRYPTOGRAPHICALLY re-verify (not merely trust a recorded
119
+ // boolean, which a hand-written lock file could forge).
120
+ signatureBase64: signatureVerified ? signature.toString("base64") : null,
121
+ publicKeyPem: signatureVerified ? publicKeyPem : null,
123
122
  };
124
123
  }
125
124
 
@@ -336,13 +336,19 @@ export class SubAgentContext {
336
336
 
337
337
  // Check abort signal
338
338
  if (this._signal?.aborted) {
339
- this.forceComplete("cancelled");
339
+ this.forceComplete("cancelled", {
340
+ partialContent: lastContent,
341
+ artifacts,
342
+ });
340
343
  break;
341
344
  }
342
345
 
343
346
  // Enforce token budget
344
347
  if (this.tokenBudget && this._tokenCount >= this.tokenBudget) {
345
- this.forceComplete("token-budget-exceeded");
348
+ this.forceComplete("token-budget-exceeded", {
349
+ partialContent: lastContent,
350
+ artifacts,
351
+ });
346
352
  break;
347
353
  }
348
354
 
@@ -355,9 +361,17 @@ export class SubAgentContext {
355
361
  } catch (err) {
356
362
  this.status = "failed";
357
363
  this.completedAt = new Date().toISOString();
364
+ // Return partial work to the parent instead of discarding it: the
365
+ // summary is the only channel the parent model sees, so a mid-run API
366
+ // error (rate limit, network drop) must not erase what was already
367
+ // produced. Artifacts collected before the failure are kept as-is.
368
+ const partial =
369
+ lastContent && lastContent.length > 0
370
+ ? `\n\nPartial output before failure:\n${this.summarize(lastContent)}`
371
+ : "";
358
372
  this.result = {
359
- summary: `Sub-agent failed: ${err.message}`,
360
- artifacts: [],
373
+ summary: `Sub-agent failed: ${err.message}${partial}`,
374
+ artifacts,
361
375
  tokenCount: this._tokenCount,
362
376
  toolsUsed: [...new Set(this._toolsUsed)],
363
377
  iterationCount: this._iterationCount,
@@ -447,15 +461,22 @@ export class SubAgentContext {
447
461
  /**
448
462
  * Force-complete this sub-agent (e.g. on timeout or parent cancellation).
449
463
  * @param {string} [reason] - Reason for force-completion
464
+ * @param {{partialContent?: string, artifacts?: Array}} [partial] - Work
465
+ * produced before the cutoff; returned to the parent instead of being
466
+ * discarded (a truncated run should still hand over what it has).
450
467
  */
451
- forceComplete(reason = "forced") {
468
+ forceComplete(reason = "forced", partial = {}) {
452
469
  if (this.status === "active") {
453
470
  this.status = "completed";
454
471
  this.completedAt = new Date().toISOString();
455
472
  if (!this.result) {
473
+ const partialText =
474
+ partial.partialContent && partial.partialContent.length > 0
475
+ ? `\n\nPartial output before cutoff:\n${this.summarize(partial.partialContent)}`
476
+ : "";
456
477
  this.result = {
457
- summary: `(Sub-agent force-completed: ${reason})`,
458
- artifacts: [],
478
+ summary: `(Sub-agent force-completed: ${reason})${partialText}`,
479
+ artifacts: Array.isArray(partial.artifacts) ? partial.artifacts : [],
459
480
  tokenCount: this._tokenCount,
460
481
  toolsUsed: [...new Set(this._toolsUsed)],
461
482
  iterationCount: this._iterationCount,
@@ -22,27 +22,46 @@ function spanId() {
22
22
 
23
23
  // One trace per recorder (a "run"). The OTLP/OTel spec treats an ALL-ZERO
24
24
  // traceId as INVALID, so a strict collector would drop every span exported with
25
- // `"0".repeat(32)` — defeating toOtlp()'s purpose. Derive a non-zero, monotonic
26
- // (RNG-free, snapshot-replayable) 32-hex traceId per recorder instead.
25
+ // `"0".repeat(32)` — defeating toOtlp()'s purpose. A bare counter is non-zero
26
+ // but resets every PROCESS, so successive CLI runs all exported trace
27
+ // `000…001` and a collector merged them into one giant trace. Prefix the
28
+ // counter with per-process entropy (start time + pid — RNG-free, so ids stay
29
+ // deterministic WITHIN a run) to make traces practically unique ACROSS runs.
30
+ const _traceBase = (
31
+ Date.now().toString(16).padStart(12, "0") +
32
+ (process.pid >>> 0).toString(16).padStart(8, "0")
33
+ ).slice(0, 20);
27
34
  let _traceSeq = 0;
28
35
  function newTraceId() {
29
36
  _traceSeq = (_traceSeq + 1) % Number.MAX_SAFE_INTEGER;
30
- return _traceSeq.toString(16).padStart(32, "0"); // never all-zero (starts at 1)
37
+ return _traceBase + _traceSeq.toString(16).padStart(12, "0"); // 32 hex, never all-zero
31
38
  }
32
39
 
33
40
  export class TelemetryRecorder {
34
41
  constructor({
35
42
  now = () => Date.now(),
36
43
  serviceName = "chainlesschain-cli",
44
+ defaultAttributes = {},
37
45
  } = {}) {
38
46
  this._now = typeof now === "function" ? now : () => now;
39
47
  this.serviceName = serviceName;
40
48
  this.traceId = newTraceId(); // one trace per recorder (valid non-zero id)
49
+ // Stamped onto EVERY span (per-span attributes win on key collision).
50
+ // Used for run-level correlation: workflow.run_id / workflow.name let a
51
+ // collector group all model/tool/task spans of one run (Claude-Code
52
+ // 2.1.202 workflow-tracing attributes).
53
+ this.defaultAttributes = { ...defaultAttributes };
41
54
  this._spans = []; // completed spans
42
55
  this._counters = new Map(); // name → { total, byAttr }
43
56
  this._failures = new Map(); // category → count
44
57
  }
45
58
 
59
+ /** Set (or overwrite) an attribute stamped onto every span from now on. */
60
+ setDefaultAttribute(key, value) {
61
+ this.defaultAttributes[key] = value;
62
+ return this;
63
+ }
64
+
46
65
  /**
47
66
  * Start a span. Returns a handle; call `.end()` (optionally with a status /
48
67
  * extra attributes) to record it. Nesting is expressed via `parentId`.
@@ -50,7 +69,7 @@ export class TelemetryRecorder {
50
69
  startSpan(name, attributes = {}, { parentId = null } = {}) {
51
70
  const id = spanId();
52
71
  const start = this._now();
53
- const attrs = { ...attributes };
72
+ const attrs = { ...this.defaultAttributes, ...attributes };
54
73
  const events = [];
55
74
  const self = this;
56
75
  let ended = false;
@@ -186,8 +205,12 @@ export class TelemetryRecorder {
186
205
  spanId: s.id,
187
206
  parentSpanId: s.parentId || "",
188
207
  name: s.name,
189
- startTimeUnixNano: s.startTime * 1e6,
190
- endTimeUnixNano: s.endTime * 1e6,
208
+ // proto3 JSON mapping: (s)fixed64/(u)int64 fields MUST be
209
+ // decimal STRINGS — ms×1e6 ≈ 1.8e18 exceeds 2^53, so a JSON
210
+ // number both violates the OTLP/JSON spec (strict collectors
211
+ // reject the span) and quantizes (~256 ns spacing).
212
+ startTimeUnixNano: String(Math.round(s.startTime * 1e6)),
213
+ endTimeUnixNano: String(Math.round(s.endTime * 1e6)),
191
214
  status: { code: s.status === "error" ? 2 : 1 },
192
215
  attributes: Object.entries(s.attributes).map(([k, v]) => ({
193
216
  key: k,
@@ -200,7 +223,7 @@ export class TelemetryRecorder {
200
223
  })),
201
224
  events: s.events.map((e) => ({
202
225
  name: e.name,
203
- timeUnixNano: e.time * 1e6,
226
+ timeUnixNano: String(Math.round(e.time * 1e6)),
204
227
  attributes: Object.entries(e.attributes).map(([k, v]) => ({
205
228
  key: k,
206
229
  value: { stringValue: String(v) },
@@ -64,7 +64,10 @@ import {
64
64
  PromptCompressor,
65
65
  getContextWindow,
66
66
  } from "../harness/prompt-compressor.js";
67
- import { buildAutoPinPredicate } from "../runtime/auto-pin.js";
67
+ import {
68
+ buildAutoPinPredicate,
69
+ resolveAutoPinOption,
70
+ } from "../runtime/auto-pin.js";
68
71
  import { feature } from "../lib/feature-flags.js";
69
72
  import { recordCompressionMetric } from "../lib/compression-telemetry.js";
70
73
  import {
@@ -102,7 +105,11 @@ import { parseThinkCommand, parseEffortCommand } from "./think-command.js";
102
105
  import { parseBtwCommand, buildAsideBlock, applyAside } from "./btw-command.js";
103
106
  import { shouldStreamLive } from "./stream-decision.js";
104
107
  import { emptyTurnNotice } from "./empty-turn-notice.js";
105
- import { buildPermissionPrompt } from "./permission-prompt.js";
108
+ import {
109
+ buildPermissionPrompt,
110
+ resolveAskIdleTimeoutMs,
111
+ questionWithIdleTimeout,
112
+ } from "./permission-prompt.js";
106
113
  import {
107
114
  parsePermissionTier,
108
115
  describeTier,
@@ -417,15 +424,22 @@ export async function startAgentRepl(options = {}) {
417
424
  // Unset → agent-core's 180s default (matches cc chat/ask). Set to 0 to
418
425
  // disable. Left undefined here means "use the default".
419
426
  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;
427
+ // Auto-pin (default ON since 2026-07-07): compaction pins the original task
428
+ // (first user turn) so it survives context compression. Resolution order:
429
+ // CC_AUTO_PIN env ("1"/"0") > config `context.autoPin` (true/false/object) >
430
+ // default on. See resolveAutoPinOption.
431
+ let _autoPinCfgValue;
432
+ // Idle timeout for interactive permission prompts (0 = wait forever).
433
+ // CC_PERMISSION_ASK_TIMEOUT_MS env > config permissions.askTimeoutMs > off.
434
+ let _askIdleTimeoutMs = resolveAskIdleTimeoutMs();
424
435
  try {
425
436
  const { loadConfig } = await import("../lib/config-manager.js");
426
437
  const _cfg = loadConfig();
427
438
  _visionModel = _cfg?.llm?.visionModel || undefined;
428
- _autoPinOpt = _cfg?.context?.autoPin;
439
+ _autoPinCfgValue = _cfg?.context?.autoPin;
440
+ _askIdleTimeoutMs = resolveAskIdleTimeoutMs({
441
+ config: _cfg?.permissions?.askTimeoutMs,
442
+ });
429
443
  const raw = _cfg?.llm?.streamStallTimeoutMs;
430
444
  const t = Number(raw);
431
445
  // Accept 0 (explicit disable) — only ignore absent/invalid values.
@@ -483,8 +497,8 @@ export async function startAgentRepl(options = {}) {
483
497
  if (feature("PROMPT_COMPRESSOR")) {
484
498
  _compressor = new PromptCompressor({ model, provider });
485
499
  }
486
- if (process.env.CC_AUTO_PIN === "1") _autoPinOpt = _autoPinOpt || true;
487
- // Compaction options shared by /compact + auto-compact. Adds the opt-in
500
+ const _autoPinOpt = resolveAutoPinOption({ config: _autoPinCfgValue });
501
+ // Compaction options shared by /compact + auto-compact. Adds the
488
502
  // pin predicate only when auto-pin is enabled; otherwise byte-identical.
489
503
  const _compactOpts = (msgs) => {
490
504
  const base = { preserveToolPairs: true };
@@ -555,17 +569,24 @@ export async function startAgentRepl(options = {}) {
555
569
  });
556
570
  const q = (p) => new Promise((res) => rlConfirm.question(p, res));
557
571
  const cmd = args?.command ? ` ${args.command}` : "";
558
- const ans = (
559
- await q(
572
+ const res = await questionWithIdleTimeout(
573
+ q,
574
+ chalk.yellow(
575
+ `\n[ApprovalGate] ${riskLevel || "medium"} risk command:${cmd}\n` +
576
+ ` Proceed? [y]es once / [a]lways allow / [N]o: `,
577
+ ),
578
+ _askIdleTimeoutMs,
579
+ );
580
+ rlConfirm.close();
581
+ if (res.timedOut) {
582
+ process.stdout.write(
560
583
  chalk.yellow(
561
- `\n[ApprovalGate] ${riskLevel || "medium"} risk command:${cmd}\n` +
562
- ` Proceed? [y]es once / [a]lways allow / [N]o: `,
584
+ `\n no response in ${_askIdleTimeoutMs}ms auto-denied\n`,
563
585
  ),
564
- )
565
- )
566
- .trim()
567
- .toLowerCase();
568
- rlConfirm.close();
586
+ );
587
+ return false;
588
+ }
589
+ const ans = res.answer.trim().toLowerCase();
569
590
  if (ans === "a" || ans === "always") {
570
591
  const saved = await _persistAlwaysAllow(tool || "run_shell", args);
571
592
  if (saved) {
@@ -621,10 +642,21 @@ export async function startAgentRepl(options = {}) {
621
642
  // (settings/hook ask) or a `reason` (destructive-git / sensitive-file
622
643
  // guards) — avoids the literal "null" the old template printed.
623
644
  const header = buildPermissionPrompt({ tool, args, rule, reason });
624
- const ans = (await q(chalk.yellow(`\n${header}\n Proceed? (y/N) `)))
625
- .trim()
626
- .toLowerCase();
645
+ const res = await questionWithIdleTimeout(
646
+ q,
647
+ chalk.yellow(`\n${header}\n Proceed? (y/N) `),
648
+ _askIdleTimeoutMs,
649
+ );
627
650
  rl.close();
651
+ if (res.timedOut) {
652
+ process.stdout.write(
653
+ chalk.yellow(
654
+ `\n ⏱ no response in ${_askIdleTimeoutMs}ms — auto-denied\n`,
655
+ ),
656
+ );
657
+ return false;
658
+ }
659
+ const ans = res.answer.trim().toLowerCase();
628
660
  return ans === "y" || ans === "yes";
629
661
  };
630
662
  } catch (_err) {
@@ -2379,6 +2411,17 @@ export async function startAgentRepl(options = {}) {
2379
2411
  const expanded = target.replace(/^~(?=$|[\\/])/, os.homedir());
2380
2412
  process.chdir(path.resolve(process.cwd(), expanded));
2381
2413
  logger.log(chalk.green(`cwd → ${process.cwd()}`));
2414
+ // MCP roots derive from cwd — tell connected servers to re-query
2415
+ // roots/list (Claude-Code 2.1.203 change-notification parity).
2416
+ for (const c of [_adhocMcp?.mcpClient, _bundleMcpClient]) {
2417
+ if (c && typeof c.notifyRootsListChanged === "function") {
2418
+ try {
2419
+ c.notifyRootsListChanged();
2420
+ } catch {
2421
+ /* best-effort */
2422
+ }
2423
+ }
2424
+ }
2382
2425
  } catch (err) {
2383
2426
  logger.error(`/cd failed: ${err.message}`);
2384
2427
  }
@@ -24,3 +24,61 @@ export function buildPermissionPrompt({ tool, args, rule, reason } = {}) {
24
24
  if (reason) return `[Permission] ${reason}`;
25
25
  return `[Permission] confirm ${tool}:${detail}`;
26
26
  }
27
+
28
+ /**
29
+ * Resolve the idle timeout (ms) for interactive permission prompts.
30
+ *
31
+ * An unanswered prompt blocks the whole agent turn forever (e.g. the user
32
+ * walked away mid-run). With a timeout configured, the prompt auto-denies
33
+ * after `ms` of silence — deny is the only safe unattended answer.
34
+ *
35
+ * Precedence: CC_PERMISSION_ASK_TIMEOUT_MS env > config
36
+ * `permissions.askTimeoutMs` > default 0 (disabled — waits forever, the
37
+ * historical behavior). Non-finite / non-positive values disable it.
38
+ *
39
+ * @param {{env?: string, config?: unknown}} [opts] - injectable for tests
40
+ * @returns {number} timeout in ms, 0 = disabled
41
+ */
42
+ export function resolveAskIdleTimeoutMs({ env, config } = {}) {
43
+ const envRaw =
44
+ env !== undefined ? env : process.env.CC_PERMISSION_ASK_TIMEOUT_MS;
45
+ const candidate =
46
+ envRaw !== undefined && envRaw !== null && envRaw !== ""
47
+ ? Number(envRaw)
48
+ : typeof config === "number" || typeof config === "string"
49
+ ? Number(config)
50
+ : NaN; // booleans/objects are not a timeout — disabled
51
+ return Number.isFinite(candidate) && candidate > 0 ? candidate : 0;
52
+ }
53
+
54
+ /**
55
+ * Race an interactive question against an idle timeout.
56
+ *
57
+ * `ask` is the readline-question-as-promise (never rejects). On timeout the
58
+ * caller must still close its readline interface; the stranded question
59
+ * callback becomes a no-op once the interface is closed.
60
+ *
61
+ * @param {(prompt: string) => Promise<string>} ask
62
+ * @param {string} prompt
63
+ * @param {number} timeoutMs - 0/negative = no timeout (plain await)
64
+ * @returns {Promise<{answer: string|null, timedOut: boolean}>}
65
+ */
66
+ export async function questionWithIdleTimeout(ask, prompt, timeoutMs) {
67
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
68
+ return { answer: await ask(prompt), timedOut: false };
69
+ }
70
+ let timer = null;
71
+ try {
72
+ return await Promise.race([
73
+ ask(prompt).then((answer) => ({ answer, timedOut: false })),
74
+ new Promise((res) => {
75
+ timer = setTimeout(
76
+ () => res({ answer: null, timedOut: true }),
77
+ timeoutMs,
78
+ );
79
+ }),
80
+ ]);
81
+ } finally {
82
+ if (timer) clearTimeout(timer);
83
+ }
84
+ }
@@ -1,13 +1,14 @@
1
1
  /**
2
- * auto-pin policy tests the OPT-IN compaction pin policy. Verifies it is off
3
- * by default (returns nullcaller passes no predicate → byte-identical), and
4
- * when enabled pins the original task (first user turn) plus explicit pins,
5
- * honoring the token cap.
2
+ * auto-pin policy tests. The PREDICATE layer stays opt-valued (null when the
3
+ * resolved option is falsy → byte-identical compaction); the EFFECTIVE default
4
+ * is decided by resolveAutoPinOption ON since 2026-07-07, opt out via
5
+ * CC_AUTO_PIN=0 or config context.autoPin=false.
6
6
  */
7
7
 
8
8
  import { describe, it, expect } from "vitest";
9
9
  import {
10
10
  resolveAutoPinConfig,
11
+ resolveAutoPinOption,
11
12
  buildAutoPinPredicate,
12
13
  describeAutoPin,
13
14
  } from "../auto-pin.js";
@@ -102,3 +103,25 @@ describe("describeAutoPin", () => {
102
103
  );
103
104
  });
104
105
  });
106
+
107
+ describe("resolveAutoPinOption (effective default — ON since 2026-07-07)", () => {
108
+ it("defaults ON when nothing is set", () => {
109
+ expect(resolveAutoPinOption({ env: undefined, config: undefined })).toBe(
110
+ true,
111
+ );
112
+ });
113
+ it("CC_AUTO_PIN=0 opts out; =1 forces on over a config false", () => {
114
+ expect(resolveAutoPinOption({ env: "0", config: true })).toBe(false);
115
+ expect(resolveAutoPinOption({ env: "1", config: false })).toBe(true);
116
+ });
117
+ it("config false opts out; a config object passes through", () => {
118
+ expect(resolveAutoPinOption({ env: undefined, config: false })).toBe(false);
119
+ const cfg = { maxPinTokens: 99 };
120
+ expect(resolveAutoPinOption({ env: undefined, config: cfg })).toBe(cfg);
121
+ });
122
+ it("an explicit --auto-pin flag wins over everything", () => {
123
+ expect(resolveAutoPinOption({ flag: true, env: "0", config: false })).toBe(
124
+ true,
125
+ );
126
+ });
127
+ });