chainlesschain 0.166.81 → 0.166.83

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 (189) hide show
  1. package/package.json +1 -1
  2. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  3. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-BZPs-bVl.js → AIOps-D5a4i3N7.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-BP1iLSwn.js → ActionButton-DxsRk5n1.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-WxwtPqcd.js → Analytics-D-7EvH4S.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-DvcgeNkP.js → AppLayout-DDEWVr-d.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-CtYGOtnT.js → Artifacts-CAlJAjRB.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-BBzFYWMk.js → Audit-tuaWDOAM.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-Dl9wCt0Y.js → BackgroundAgents-CIwRFJ50.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-CAL13Eak.js → Backup-CpBepJlH.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-f_lncpU_.js → BaseInput-eKguCzQc.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-DLEbkiqI.js → Chat-CFrUfXDV.js} +4 -4
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-1tCmIvv1.js → ChatBubbleRenderer-DaRtY87l.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-SNvgd2UG.js → Checkbox-o5FEn6a1.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-BG0D-INl.js → Codegen-Dih8HogC.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-DUBBZz0e.js → Col-D5r-6WZe.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-8LfuBDPs.js → Community-jeQ6bGey.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-GWs7Ka6o.js → Compact-CEP7QsWp.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-CXRhB-KC.js → Compliance-B8NydOHd.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-OpW8dLKg.js → Cowork-Bmi1zuPy.js} +2 -2
  22. package/src/assets/web-panel/assets/{Cron-6e47Syc_.js → Cron-BAL9bwSp.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-D-vGH4nC.js → Crosschain-D8WUi2dS.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-zEIa2jNx.js → DID-CQCkYcLY.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-BfUbZxsl.js → Dashboard-DogXg6kh.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-BeCD8gf0.js → Dropdown-BJBJyQJn.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-apOBM2r2.js → EmailListRenderer-CxPWquJx.js} +1 -1
  28. package/src/assets/web-panel/assets/{EvolutionSettings-C2dK36po.js → EvolutionSettings-BijH1x8G.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DPMLWPTR.js → FamilyGuardDashboard-DStwf-00.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-CivI2pzm.js → Federation-LU9_sNxC.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-B3zrwBDw.js → FormItemContext-DNfWhj7P.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-jGgdcPck.js → GenericCardRenderer-DWYsPjzk.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-Cpfkrasd.js → Git-CA0O9ulB.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-DG8_7YS3.js → Governance-ECShL7BJ.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference-TQgUqPXx.js → Inference-9GA2542e.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-By657fHZ.js → KnowledgeGraph-nC5mTbEH.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-CFJ_70-E.js → Logs-B7IqgnDy.js} +2 -2
  38. package/src/assets/web-panel/assets/MarkdownRenderer-BqlqrJkY.js +1 -0
  39. package/src/assets/web-panel/assets/{Marketplace-BWC3xler.js → Marketplace-CEr0suM8.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-B0NkUzeJ.js → McpTools-DhTPQKOE.js} +3 -3
  41. package/src/assets/web-panel/assets/{Memory-DBnXwjWD.js → Memory-mHRZP1w4.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-BNWDrEJ4.js → MobileBridge-BNfX6Rdo.js} +1 -1
  43. package/src/assets/web-panel/assets/{MobileProjects-BaE94B_N.js → MobileProjects-8zG8f5li.js} +1 -1
  44. package/src/assets/web-panel/assets/{Mtc-Bp3OAEYb.js → Mtc-CzkV3wsn.js} +5 -5
  45. package/src/assets/web-panel/assets/{MtcAudit-_1T24zO3.js → MtcAudit-DWYljJik.js} +4 -4
  46. package/src/assets/web-panel/assets/{Multisig-C2i6Yi0B.js → Multisig-kHgtvZY_.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-CBq3ujGE.js → NLProgramming-56uQiPiY.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-BxRmci_W.js → Notes-DxGOZqRf.js} +3 -3
  49. package/src/assets/web-panel/assets/{NotificationSettings-CqBLgOdv.js → NotificationSettings-DabaCpmo.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-cODPlpK7.js → OrderTableRenderer-SzeQNlGT.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-DlTnQBlp.js → Organization-D9gnPpK2.js} +4 -4
  52. package/src/assets/web-panel/assets/{Overflow-Df2jS2Ep.js → Overflow-Cqp_bXm4.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-BwieT0aA.js → P2P-DTeK-r0G.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-Btw816xR.js → PdhVaultBrowser-CsjG85GT.js} +3 -3
  55. package/src/assets/web-panel/assets/{Permissions-BhVYLcqT.js → Permissions-B4ofZq3j.js} +4 -4
  56. package/src/assets/web-panel/assets/{PersonalDataHub-CPbNKPCA.js → PersonalDataHub-Cvas5cYd.js} +4 -4
  57. package/src/assets/web-panel/assets/{Pipeline-B1BuhoY3.js → Pipeline-Er3wmAew.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-BWeikVbU.js → Privacy-DMFYeZox.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-BVXcimHE.js → ProjectInit-DaVaYPy0.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-CX87x3rT.js → ProjectSettings-dPx5q2Ac.js} +2 -2
  61. package/src/assets/web-panel/assets/Projects-N0JNeCui.js +1 -0
  62. package/src/assets/web-panel/assets/{Providers-CGm0Wuer.js → Providers-BPQo_gQa.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-DJxv7J64.js → QrScannerModal-CD-sEsWh.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-DOXBReRk.js → QuickAsk-LOKRJiN_.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend--MiLwmLM.js → Recommend-BwPXqcWy.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-D6LoXH94.js → RemoteSession-BjotndxF.js} +3 -3
  67. package/src/assets/web-panel/assets/{Reputation-G2jToiqh.js → Reputation-BlZ2gcbU.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-B79ZV_lZ.js → Row-D399HM-d.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-CHQN68w_.js → RssFeed-C7H-ibnY.js} +2 -2
  70. package/src/assets/web-panel/assets/{Search-j7v5S2Fa.js → Search-CNHCVmM1.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-B2ykFZJH.js → Security-C70eDGYY.js} +3 -3
  72. package/src/assets/web-panel/assets/{Services-H8BK8uX0.js → Services-6xfq9G-H.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-XEUUrOTK.js → Skeleton-BbY2zeZV.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-B387UJPk.js → Skills-DYtyZ7_6.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-CWWBujpe.js → Sla-CkWcl5OH.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-Q2AOv9DV.js → SpeechSettings-CiknYk2P.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-OSNyOUr8.js → SyncSettings-D-8JVip4.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-DfUDrno5.js → Tasks-B2KnR9XC.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-CSTkzDRS.js → Templates-CipXkOE-.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-BR__gCTG.js → Tenant-DbwgIMmx.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-Bv4DM5OI.js → Terminal-OtCriHEE.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-DUnZuAtn.js → TimelineRenderer-B9LU5qrl.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-Dm0sczRV.js → Tokens-B4iFVxvH.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-DsSOp0Ob.js → Trigger-BegM2v8q.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-C0HJtFwV.js → Trust-COkqnnFj.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-BbqIZiX-.js → UkeySign-BzqKPChj.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-D7dDTt3D.js → VideoEditing-D-F2XL3C.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-DJGu0KWq.js → Wallet-22PzRY9T.js} +2 -2
  89. package/src/assets/web-panel/assets/{WebAuthn-x8OoogZU.js → WebAuthn-eSMq_qtz.js} +4 -4
  90. package/src/assets/web-panel/assets/{WorkflowEditor-CC3jIUqx.js → WorkflowEditor-BvdAakpq.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-Bqgv5oe8.js → chat-C6jhpF7E.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-CbAMqLFr.js → colors-BbbW2Pfv.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-B-zIDFg3.js → compact-item-CVFeLTqt.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-D_s1ZLtZ.js → createContext-DS0m7NZc.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-D50gzPS9.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-Cj_J9Eb9.js → hasIn-DVouP0t6.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BtJzqXCQ.js → index--AdzSlH7.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-D_igPAXH.js → index-54aHB4FL.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BivQyKes.js → index-8QbwhE3i.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-3o8DjHHt.js → index-B5JRIZXi.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-0je3TLmx.js → index-B8a_c_qZ.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cz0blpuN.js → index-BE_u-rXr.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-Cu3FtpNc.js → index-BOOsA080.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-KY7udrs-.js → index-BXw6ivB8.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-J4JLWUMK.js → index-BaUah6TO.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-C6bAvixK.js → index-Be12HoCS.js} +3 -3
  107. package/src/assets/web-panel/assets/{index-Cy3XOp7S.js → index-BhvnNFfd.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C6lO24YD.js → index-BrIv7C9a.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BPdH-XTd.js → index-BvCgzl0X.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Cg0oYTy5.js → index-Bw-ZGQCH.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-ab6FUgkq.js → index-BwZnPiFd.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DuqVIsHL.js → index-BwozzG6k.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-B6qoyCkx.js → index-ByLsH9CL.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BjfpW5s3.js → index-BzL3LWFX.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BFNO6ycz.js → index-C4xmLgLa.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-dg0JqQDA.js → index-C6q2MkIG.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DtplHZ5o.js → index-C74emdKD.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Bi1E5h9V.js → index-CIg4nqyp.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-C-Z13SCI.js → index-CIk7mg6G.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-JdSkHz64.js → index-CPS8E-J6.js} +1 -1
  121. package/src/assets/web-panel/assets/index-CgensV-n.js +1 -0
  122. package/src/assets/web-panel/assets/{index-DVjFV2mg.js → index-CkdYB0_g.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CsHTqPTg.js → index-CpTbnbUI.js} +1 -1
  124. package/src/assets/web-panel/assets/index-Ctkf06Z_.js +1 -0
  125. package/src/assets/web-panel/assets/{index-nEWJobH4.js → index-CwYFDMn_.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BN5sO3kL.js → index-DGYX17YW.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CD_A-N7c.js → index-DR6TDz5H.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-ggeC-_dR.js → index-DUBkae39.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-D9CqHOgd.js → index-DotRL126.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CSzWODfj.js → index-DpReoAGb.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Bw88Mk2t.js → index-Ds4wbrgk.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-BGxI_Qxg.js → index-DuVjTDcW.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BLwUCYDf.js → index-JeJqXbUU.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-D1t2IqNU.js → index-SdFkCtiC.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CVPI_iIh.js → index-eaXEQFuP.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-DDIGXQ08.js → initDefaultProps-CB5cUnQ5.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-97SXSYE4.js → motion-bn_fWhQV.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-CfDQMFRe.js → move-DY4-Odtu.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-qLYCGwY8.js → mtc-parser-B5l5mjoh.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-xVqy1mCI.js → omit-rJ-Ci8CW.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-DCGlFyfv.js → pickAttrs-BMwGJd6C.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-DYgPuMk3.js → placementArrow-CaiQyGXG.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-7zUIdAWH.js → responsiveObserve-DQTO5wDH.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-TyaiZlSh.js → slide-Dg6ZDtbz.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-BPd13Fae.js → statusUtils-bvjrktKc.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-A44XGgQ0.js → styleChecker-C1geIU_x.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-ZX5EUa8B.js → useFlexGapSupport-BzU3RJRi.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-Sh_fBPqz.js → useFs-B7l6OwLe.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-DhR6Izei.js → usePersonalDataHub-BYF1L_8x.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-DC8g6oRh.js → vnode-6c2GVkT-.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-DRjJmOwj.js → zoom-BYAY6QeD.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/commands/agent.js +21 -10
  154. package/src/data/changelog.json +39 -0
  155. package/src/gateways/ws/session-protocol.js +19 -5
  156. package/src/gateways/ws/ws-agent-handler.js +6 -0
  157. package/src/gateways/ws/ws-session-gateway.js +133 -21
  158. package/src/lib/agent-execution-policy.js +177 -0
  159. package/src/lib/authority-launch-environment.js +99 -0
  160. package/src/lib/auto-mode-config.js +129 -45
  161. package/src/lib/claude-project-auto-memory.js +7 -30
  162. package/src/lib/context-memory-kernel/task-worklog-port.js +73 -24
  163. package/src/lib/diagnostic-excerpt.js +91 -10
  164. package/src/lib/diagnostic-workflow.js +2 -0
  165. package/src/lib/evolution/volcengine-function-replay-store.js +38 -28
  166. package/src/lib/git-tool-input.js +7 -0
  167. package/src/lib/host-tool-policy-authority.js +151 -0
  168. package/src/lib/permission-authority.js +67 -5
  169. package/src/lib/plugin-runtime/settings.js +9 -1
  170. package/src/lib/remote-read-loop-guard.js +59 -14
  171. package/src/lib/sandbox-egress-authority-monitor.js +3 -2
  172. package/src/lib/session-manager.js +20 -5
  173. package/src/lib/settings-loader.cjs +175 -19
  174. package/src/lib/settings-source-observation.cjs +270 -0
  175. package/src/lib/sub-agent-context.js +36 -18
  176. package/src/lib/task-progress-tracker.js +112 -12
  177. package/src/lib/unattended-action-policy.js +456 -38
  178. package/src/repl/agent-repl.js +58 -29
  179. package/src/repl/repl-tool-executor.js +39 -0
  180. package/src/runtime/agent-core.js +272 -5
  181. package/src/runtime/agent-runtime.js +15 -3
  182. package/src/runtime/headless-runner.js +13 -4
  183. package/src/runtime/headless-stream.js +9 -0
  184. package/src/runtime/policies/agent-policy.js +5 -4
  185. package/src/assets/web-panel/assets/MarkdownRenderer-BpRWpN1E.js +0 -1
  186. package/src/assets/web-panel/assets/Projects-3Qo2Mvxb.js +0 -1
  187. package/src/assets/web-panel/assets/devWarning-QMSC9xgn.js +0 -1
  188. package/src/assets/web-panel/assets/index-DVq7UuW0.js +0 -1
  189. package/src/assets/web-panel/assets/index-DYVepsIV.js +0 -1
@@ -18,6 +18,42 @@
18
18
  * PURE: no fs / clock / RNG / process.
19
19
  */
20
20
 
21
+ import { snapshotMcpJsonRpcInput } from "./mcp-call-ledger.js";
22
+
23
+ /** Bind startup-only authority without retaining caller-owned mutable data. */
24
+ export function captureUnattendedActionPolicy(policy) {
25
+ if (policy == null) return null;
26
+ try {
27
+ const snapshot = snapshotMcpJsonRpcInput(policy);
28
+ if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot))
29
+ throw new TypeError();
30
+ for (const flag of ["unattended", "protectedBranch", "budgetExhausted"]) {
31
+ if (snapshot[flag] !== undefined && typeof snapshot[flag] !== "boolean")
32
+ throw new TypeError();
33
+ }
34
+ if (
35
+ snapshot.allowlist !== undefined &&
36
+ (!Array.isArray(snapshot.allowlist) ||
37
+ snapshot.allowlist.some((value) => typeof value !== "string"))
38
+ )
39
+ throw new TypeError();
40
+ if (
41
+ snapshot.trigger !== undefined &&
42
+ (!snapshot.trigger ||
43
+ typeof snapshot.trigger !== "object" ||
44
+ Array.isArray(snapshot.trigger) ||
45
+ (snapshot.trigger.trusted !== undefined &&
46
+ typeof snapshot.trigger.trusted !== "boolean"))
47
+ )
48
+ throw new TypeError();
49
+ return snapshot;
50
+ } catch {
51
+ const error = new TypeError("Unattended action policy is invalid");
52
+ error.code = "CC_UNATTENDED_POLICY_INVALID";
53
+ throw error;
54
+ }
55
+ }
56
+
21
57
  /** Canonical action classes, ordered low → high consequence. */
22
58
  export const ACTION_CLASS = Object.freeze({
23
59
  READ: "read",
@@ -86,6 +122,54 @@ export const TOOL_ACTION_CLASS = Object.freeze({
86
122
  notify: ACTION_CLASS.EXTERNAL_MESSAGE,
87
123
  });
88
124
 
125
+ // Fixed built-ins with local effects. Peer annotations and generic runtime
126
+ // descriptors cannot add to this list. Shell/Git have their own command
127
+ // ceilings; opaque executors and persistent/delegated runs remain unknown.
128
+ const LOCAL_TOOL_ACTION_CLASS = Object.freeze({
129
+ read_file: ACTION_CLASS.READ,
130
+ search_files: ACTION_CLASS.READ,
131
+ list_dir: ACTION_CLASS.READ,
132
+ list_skills: ACTION_CLASS.READ,
133
+ search_sessions: ACTION_CLASS.READ,
134
+ ask_user_question: ACTION_CLASS.READ,
135
+ write_file: ACTION_CLASS.LOCAL_WRITE,
136
+ edit_file: ACTION_CLASS.LOCAL_WRITE,
137
+ edit_file_hashed: ACTION_CLASS.LOCAL_WRITE,
138
+ delete_file: ACTION_CLASS.LOCAL_WRITE,
139
+ move_file: ACTION_CLASS.LOCAL_WRITE,
140
+ notebook_edit: ACTION_CLASS.LOCAL_WRITE,
141
+ todo_write: ACTION_CLASS.LOCAL_WRITE,
142
+ check_shell: ACTION_CLASS.LOCAL_WRITE,
143
+ });
144
+
145
+ /** Execution guard for built-ins; an opaque host/MCP executor stays unknown. */
146
+ export function evaluateUnattendedToolAction(
147
+ name,
148
+ args,
149
+ policy,
150
+ { external = false } = {},
151
+ ) {
152
+ let actionClass = null;
153
+ if (!external) {
154
+ actionClass = Object.hasOwn(TOOL_ACTION_CLASS, name)
155
+ ? TOOL_ACTION_CLASS[name]
156
+ : Object.hasOwn(LOCAL_TOOL_ACTION_CLASS, name)
157
+ ? LOCAL_TOOL_ACTION_CLASS[name]
158
+ : null;
159
+ if (["run_shell", "git"].includes(name)) actionClass = ACTION_CLASS.READ;
160
+ // Persistent child runs do not yet carry a durable parent effect ceiling.
161
+ if (
162
+ name === "schedule" &&
163
+ ["list", "cancel"].includes(String(args?.action || "").toLowerCase())
164
+ )
165
+ actionClass = ACTION_CLASS.LOCAL_WRITE;
166
+ }
167
+ return {
168
+ actionClass,
169
+ ...evaluateUnattendedAction({ ...policy, actionClass, attended: false }),
170
+ };
171
+ }
172
+
89
173
  /**
90
174
  * The agent tools an UNATTENDED run must be denied — the enforcement projection
91
175
  * of `evaluateUnattendedAction` onto the tool layer (P1-8). A scheduled
@@ -127,10 +211,10 @@ export function classifyActionRisk(actionClass) {
127
211
  * the highest-risk segment and unknown commands remain unknown so an
128
212
  * unattended caller can fail closed.
129
213
  */
130
- export function classifyShellAction(command) {
131
- if (typeof command !== "string" || !command.trim()) return null;
214
+ function classifyShellSegments(command) {
215
+ if (typeof command !== "string" || !command.trim()) return [];
132
216
  const segments = command
133
- .split(/&&|\|\||[;\n]|\|/)
217
+ .split(/&&|\|\||[;&\n]|\|/)
134
218
  .map((part) =>
135
219
  part
136
220
  .trim()
@@ -139,15 +223,29 @@ export function classifyShellAction(command) {
139
223
  )
140
224
  .filter(Boolean);
141
225
  const classifySegment = (segment) => {
142
- if (/^git\s+push\b/.test(segment)) return ACTION_CLASS.PUSH;
143
- if (/^git\s+(?:merge|rebase|cherry-pick)\b/.test(segment)) {
226
+ // Substitution and executable search/filter options can hide effects
227
+ // inside a nominally read-only command. Unsupported syntax is unknown.
228
+ if (
229
+ /[$`'"\\^(){}]/.test(segment) ||
230
+ /(?:^|\s)(?:-exec(?:dir)?|-ok(?:dir)?|--pre)(?:\s|=|$)/.test(segment)
231
+ )
232
+ return null;
233
+ if (
234
+ /^git(?:\s|$)/.test(segment) &&
235
+ !hasKnownGitOptions(segment.split(/\s+/).slice(1))
236
+ )
237
+ return null;
238
+ if (/^git\s+push(?:\s|$)/.test(segment)) return ACTION_CLASS.PUSH;
239
+ if (/^git\s+(?:add|commit|fetch)(?:\s|$)/.test(segment))
240
+ return ACTION_CLASS.LOCAL_WRITE;
241
+ if (/^git\s+(?:merge|rebase|cherry-pick)(?:\s|$)/.test(segment)) {
144
242
  return ACTION_CLASS.MERGE;
145
243
  }
146
- if (/^(?:npm|pnpm|yarn|bun)\s+publish\b/.test(segment)) {
244
+ if (/^(?:npm|pnpm|yarn|bun)(?:\.cmd)?\s+publish(?:\s|$)/.test(segment)) {
147
245
  return ACTION_CLASS.PUBLISH;
148
246
  }
149
247
  if (
150
- /^(?:terraform\s+(?:apply|destroy)|pulumi\s+up|kubectl\s+(?:apply|delete|rollout)|helm\s+(?:install|upgrade)|docker\s+push)\b/.test(
248
+ /^(?:terraform\s+(?:apply|destroy)|pulumi\s+up|kubectl\s+(?:apply|delete|rollout)|helm\s+(?:install|upgrade)|docker\s+push)(?:\s|$)/.test(
151
249
  segment,
152
250
  )
153
251
  ) {
@@ -155,55 +253,375 @@ export function classifyShellAction(command) {
155
253
  ? ACTION_CLASS.DEPLOY
156
254
  : ACTION_CLASS.INFRA_MUTATION;
157
255
  }
158
- if (/\b(?:deploy|rollout)\b/.test(segment)) return ACTION_CLASS.DEPLOY;
159
- if (/^(?:git\s+(?:status|diff|log|show|branch)|ls\b|dir\b|pwd\b|cat\b|type\b|rg\b|grep\b|find\b|where\b)/.test(segment)) {
256
+ if (
257
+ /^(?:npm|pnpm|yarn|bun)(?:\.cmd)?\s+run\s+(?:deploy|rollout)(?:\s|$)/.test(
258
+ segment,
259
+ )
260
+ )
261
+ return ACTION_CLASS.DEPLOY;
262
+ if (
263
+ /^(?:git\s+(?:status|diff|log|show)(?:\s|$)|git\s+branch\s*$|(?:ls|dir|pwd|cat|type|rg|grep|find|where)(?:\s|$))/.test(
264
+ segment,
265
+ )
266
+ ) {
160
267
  return ACTION_CLASS.READ;
161
268
  }
162
- if (/^(?:npm|pnpm|yarn|bun)\s+(?:test|run\s+(?:test|lint|build)|install\b)/.test(segment) || /^(?:pytest|vitest|jest|cargo\s+test|go\s+test)\b/.test(segment)) {
269
+ if (
270
+ /^(?:npm|pnpm|yarn|bun)(?:\.cmd)?\s+(?:test|run\s+(?:test|lint|build)|install)(?:\s|$)/.test(
271
+ segment,
272
+ ) ||
273
+ /^(?:pytest|vitest|jest|cargo\s+test|go\s+test)(?:\s|$)/.test(segment)
274
+ ) {
163
275
  return ACTION_CLASS.LOCAL_WRITE;
164
276
  }
165
- if (/^echo\b/.test(segment) && />/.test(segment)) {
277
+ if (/^echo(?:\s|$)/.test(segment) && />/.test(segment)) {
166
278
  return ACTION_CLASS.LOCAL_WRITE;
167
279
  }
168
280
  return null;
169
281
  };
170
- const rank = [
171
- ACTION_CLASS.READ,
172
- ACTION_CLASS.LOCAL_WRITE,
173
- ACTION_CLASS.COMMIT,
174
- ACTION_CLASS.PUSH,
175
- ACTION_CLASS.PUBLISH,
176
- ACTION_CLASS.MERGE,
177
- ACTION_CLASS.DEPLOY,
178
- ACTION_CLASS.INFRA_MUTATION,
179
- ACTION_CLASS.EXTERNAL_MESSAGE,
180
- ];
181
- const classified = segments.map(classifySegment);
182
- return classified.reduce((highest, current) => {
183
- if (!current) return null;
184
- if (!highest) return current;
185
- return rank.indexOf(current) > rank.indexOf(highest) ? current : highest;
186
- }, null);
282
+ return segments.map((segment) => ({
283
+ command: segment,
284
+ actionClass: classifySegment(segment),
285
+ }));
187
286
  }
188
287
 
189
- /** Apply the unattended policy to a shell command, including protected push targets. */
190
- export function evaluateUnattendedShellAction(command, params = {}) {
191
- const actionClass = classifyShellAction(command);
192
- const protectedBranch =
193
- params.protectedBranch === true ||
194
- /\bgit\s+push\b[^\n]*(?:^|\s)(?:main|master|develop|production)(?:\s|$)/i.test(
195
- command || "",
288
+ const ACTION_RANK = [
289
+ ACTION_CLASS.READ,
290
+ ACTION_CLASS.LOCAL_WRITE,
291
+ ACTION_CLASS.COMMIT,
292
+ ACTION_CLASS.PUSH,
293
+ ACTION_CLASS.PUBLISH,
294
+ ACTION_CLASS.MERGE,
295
+ ACTION_CLASS.DEPLOY,
296
+ ACTION_CLASS.INFRA_MUTATION,
297
+ ACTION_CLASS.EXTERNAL_MESSAGE,
298
+ ];
299
+
300
+ // Unknown Git options may select executable helpers (upload-pack,
301
+ // receive-pack, rebase --exec, custom merge strategies, external diff, ...).
302
+ // Accept complete known options only; Git's long-option abbreviations do not
303
+ // inherit authority. These are command-specific because -s means different
304
+ // things for status, commit and merge.
305
+ const SAFE_GIT_OPTIONS = Object.freeze({
306
+ status: [
307
+ "--short",
308
+ "-s",
309
+ "--branch",
310
+ "-b",
311
+ "--porcelain",
312
+ "--porcelain=v1",
313
+ "--porcelain=v2",
314
+ "--untracked-files",
315
+ "--untracked-files=all",
316
+ "--untracked-files=no",
317
+ "--ignored",
318
+ ],
319
+ diff: [
320
+ "--stat",
321
+ "--name-only",
322
+ "--name-status",
323
+ "--numstat",
324
+ "--shortstat",
325
+ "--patch",
326
+ "-p",
327
+ "--no-patch",
328
+ "-s",
329
+ "--cached",
330
+ "--staged",
331
+ "--no-ext-diff",
332
+ "--no-textconv",
333
+ "--no-renames",
334
+ "--no-color",
335
+ ],
336
+ log: [
337
+ "--oneline",
338
+ "--stat",
339
+ "--name-only",
340
+ "--name-status",
341
+ "--patch",
342
+ "-p",
343
+ "--no-patch",
344
+ "--all",
345
+ "--graph",
346
+ "--decorate",
347
+ "--no-color",
348
+ "-n",
349
+ ],
350
+ show: [
351
+ "--oneline",
352
+ "--stat",
353
+ "--name-only",
354
+ "--name-status",
355
+ "--patch",
356
+ "-p",
357
+ "--no-patch",
358
+ "--no-ext-diff",
359
+ "--no-textconv",
360
+ "--no-color",
361
+ ],
362
+ "rev-parse": [
363
+ "--show-toplevel",
364
+ "--git-dir",
365
+ "--is-inside-work-tree",
366
+ "--verify",
367
+ "--short",
368
+ ],
369
+ "ls-files": [
370
+ "--cached",
371
+ "--others",
372
+ "--modified",
373
+ "--deleted",
374
+ "--exclude-standard",
375
+ "--stage",
376
+ "--error-unmatch",
377
+ ],
378
+ branch: [],
379
+ remote: ["-v"],
380
+ add: [
381
+ "--all",
382
+ "-A",
383
+ "--force",
384
+ "-f",
385
+ "--update",
386
+ "-u",
387
+ "--intent-to-add",
388
+ "-N",
389
+ "--dry-run",
390
+ "-n",
391
+ "--verbose",
392
+ "-v",
393
+ ],
394
+ commit: [
395
+ "-m",
396
+ "--message",
397
+ "-a",
398
+ "--all",
399
+ "--amend",
400
+ "--no-verify",
401
+ "--allow-empty",
402
+ "--allow-empty-message",
403
+ "--signoff",
404
+ "-s",
405
+ "--no-gpg-sign",
406
+ "--quiet",
407
+ "-q",
408
+ "--dry-run",
409
+ ],
410
+ fetch: [
411
+ "--all",
412
+ "--prune",
413
+ "-p",
414
+ "--tags",
415
+ "-t",
416
+ "--no-tags",
417
+ "--quiet",
418
+ "-q",
419
+ "--verbose",
420
+ "-v",
421
+ "--dry-run",
422
+ "--no-recurse-submodules",
423
+ "--unshallow",
424
+ ],
425
+ push: [
426
+ "-u",
427
+ "--set-upstream",
428
+ "--force",
429
+ "-f",
430
+ "--force-with-lease",
431
+ "--no-verify",
432
+ "--dry-run",
433
+ "-n",
434
+ "--all",
435
+ "--mirror",
436
+ "--tags",
437
+ "--delete",
438
+ "-d",
439
+ ],
440
+ merge: [
441
+ "--ff-only",
442
+ "--no-ff",
443
+ "--squash",
444
+ "--abort",
445
+ "--continue",
446
+ "--quit",
447
+ "--no-edit",
448
+ "--no-verify",
449
+ "--no-gpg-sign",
450
+ ],
451
+ rebase: [
452
+ "--abort",
453
+ "--continue",
454
+ "--skip",
455
+ "--quit",
456
+ "--autostash",
457
+ "--no-autostash",
458
+ "--no-gpg-sign",
459
+ ],
460
+ "cherry-pick": [
461
+ "--abort",
462
+ "--continue",
463
+ "--skip",
464
+ "--quit",
465
+ "--no-commit",
466
+ "-n",
467
+ "--no-gpg-sign",
468
+ ],
469
+ });
470
+
471
+ function hasKnownGitOptions(argv) {
472
+ const [subcommand, ...args] = argv;
473
+ const known = SAFE_GIT_OPTIONS[subcommand];
474
+ if (!Array.isArray(known)) return false;
475
+ let pathOperands = false;
476
+ let valueOperand = false;
477
+ return args.every((value) => {
478
+ if (valueOperand) {
479
+ valueOperand = false;
480
+ return true;
481
+ }
482
+ if (/^[a-z][a-z0-9+.-]*::/i.test(value)) return false;
483
+ if (pathOperands) return true;
484
+ if (value === "--") {
485
+ pathOperands = true;
486
+ return true;
487
+ }
488
+ if (!value.startsWith("-")) return true;
489
+ if (
490
+ ["log", "show"].includes(subcommand) &&
491
+ /^--(?:format|pretty)=/.test(value)
492
+ )
493
+ return true;
494
+ if (subcommand === "log" && /^(?:-\d+|--max-count=\d+)$/.test(value))
495
+ return true;
496
+ if (subcommand === "fetch" && /^--depth=\d+$/.test(value)) return true;
497
+ if (subcommand === "commit" && /^--message=/.test(value)) return true;
498
+ if (!known.includes(value)) return false;
499
+ if (
500
+ (subcommand === "commit" && ["-m", "--message"].includes(value)) ||
501
+ (subcommand === "log" && value === "-n")
502
+ )
503
+ valueOperand = true;
504
+ return true;
505
+ });
506
+ }
507
+
508
+ export function classifyShellAction(command) {
509
+ const segments = classifyShellSegments(command);
510
+ if (!segments.length || segments.some((segment) => !segment.actionClass))
511
+ return null;
512
+ return segments.reduce(
513
+ (highest, { actionClass }) =>
514
+ ACTION_RANK.indexOf(actionClass) > ACTION_RANK.indexOf(highest)
515
+ ? actionClass
516
+ : highest,
517
+ null,
518
+ );
519
+ }
520
+
521
+ function pushNeedsMergeAuthorization(argv) {
522
+ const positional = [];
523
+ for (const value of argv) {
524
+ if (
525
+ [
526
+ "-u",
527
+ "--set-upstream",
528
+ "--force",
529
+ "-f",
530
+ "--force-with-lease",
531
+ "--no-verify",
532
+ "--dry-run",
533
+ "-n",
534
+ ].includes(value)
535
+ )
536
+ continue;
537
+ if (value.startsWith("-")) return true;
538
+ positional.push(value);
539
+ }
540
+ // Require an explicit remote AND every destination ref. Git configuration
541
+ // controls omitted refspecs and may include protected branches.
542
+ if (positional.length < 2) return true;
543
+ return positional.slice(1).some((refspec) => {
544
+ const destination = refspec.replace(/^\+/, "").split(":").at(-1);
545
+ if (
546
+ !destination ||
547
+ !/^[a-z0-9._/-]+$/i.test(destination) ||
548
+ destination.toUpperCase() === "HEAD"
549
+ )
550
+ return true;
551
+ const branch = destination.replace(/^refs\/heads\//, "");
552
+ return (
553
+ /^(?:main|master|develop|production)$/i.test(branch) ||
554
+ (/^refs\//.test(destination) && !destination.startsWith("refs/heads/"))
196
555
  );
556
+ });
557
+ }
558
+
559
+ /** Classify the exact argv used by the git tool, never a shell string. */
560
+ export function evaluateUnattendedGitAction(argv, params = {}) {
561
+ const validArgv =
562
+ Array.isArray(argv) && argv.every((value) => typeof value === "string");
563
+ const subcommand = validArgv ? argv[0] : null;
564
+ const actionClass =
565
+ !validArgv || !hasKnownGitOptions(argv)
566
+ ? null
567
+ : subcommand === "push"
568
+ ? ACTION_CLASS.PUSH
569
+ : ["merge", "rebase", "cherry-pick"].includes(subcommand)
570
+ ? ACTION_CLASS.MERGE
571
+ : ["add", "commit", "fetch"].includes(subcommand)
572
+ ? ACTION_CLASS.LOCAL_WRITE
573
+ : [
574
+ "status",
575
+ "diff",
576
+ "log",
577
+ "show",
578
+ "rev-parse",
579
+ "ls-files",
580
+ ].includes(subcommand) ||
581
+ (subcommand === "branch" && argv.length === 1) ||
582
+ (subcommand === "remote" &&
583
+ argv.slice(1).every((value) => value === "-v"))
584
+ ? ACTION_CLASS.READ
585
+ : null;
197
586
  return {
198
587
  actionClass,
199
588
  ...evaluateUnattendedAction({
200
- ...params,
201
- actionClass,
202
- protectedBranch,
589
+ ...params,
590
+ actionClass,
591
+ protectedBranch:
592
+ params.protectedBranch === true ||
593
+ (subcommand === "push" && pushNeedsMergeAuthorization(argv.slice(1))),
203
594
  }),
204
595
  };
205
596
  }
206
597
 
598
+ /** Apply the unattended policy to a shell command, including protected push targets. */
599
+ export function evaluateUnattendedShellAction(command, params = {}) {
600
+ const segments = classifyShellSegments(command);
601
+ const verdicts = (segments.length ? segments : [{ actionClass: null }]).map(
602
+ (segment) => ({
603
+ actionClass: segment.actionClass,
604
+ ...evaluateUnattendedAction({
605
+ ...params,
606
+ actionClass: segment.actionClass,
607
+ protectedBranch:
608
+ params.protectedBranch === true ||
609
+ (segment.actionClass === ACTION_CLASS.PUSH &&
610
+ pushNeedsMergeAuthorization(segment.command.split(/\s+/).slice(2))),
611
+ }),
612
+ }),
613
+ );
614
+ // An allowlist grants individual classes, never all lower-ranked actions.
615
+ const denied = verdicts.find((verdict) => !verdict.allow);
616
+ if (denied) return denied;
617
+ return verdicts.reduce((highest, current) =>
618
+ ACTION_RANK.indexOf(current.actionClass) >
619
+ ACTION_RANK.indexOf(highest.actionClass)
620
+ ? current
621
+ : highest,
622
+ );
623
+ }
624
+
207
625
  /**
208
626
  * Decide whether a fired task may perform one action. Fail-closed.
209
627
  *