chainlesschain 0.162.35 → 0.162.37

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 (193) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-CJn02U42.js → AIOps-_oxz4VHy.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-ewURAAoy.js → ActionButton-uaeqFuDj.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-BiSadESb.js → Analytics-BPVV0OUf.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BR0WOEug.js → AppLayout-ppCYKm3I.js} +4 -4
  6. package/src/assets/web-panel/assets/{Audit-CrqcYx0e.js → Audit-DFAY6umk.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-DtbSBn4e.js → Backup-pAPBFDyP.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-BjSc9j0o.js → BaseInput-BbBl0uT2.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-ixzrlCJE.js → Chat-Ct22JUnT.js} +6 -6
  10. package/src/assets/web-panel/assets/{ChatBubbleRenderer-B78nEq05.js → ChatBubbleRenderer-DPlsLl22.js} +1 -1
  11. package/src/assets/web-panel/assets/{Checkbox-UGYeSsgr.js → Checkbox-DEkCollc.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-B97OOAg4.js → Codegen-Tor-de39.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-D9aGkaZ6.js → Col-ojNrLQU7.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-Dc2v2RGS.js → Community-CLOGhqMF.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-B_FYlUQR.js → Compact-CYKNlSZ4.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-C4FiTHyC.js → Compliance-C5E6ABuA.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-CQ8j3LIg.js → Cowork-CHeEsZ3W.js} +2 -2
  18. package/src/assets/web-panel/assets/{Cron-Dzjs9Z9Z.js → Cron-B4e1n2e7.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-BXI24uzI.js → Crosschain-DbNV8P9R.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-C-I4_d07.js → DID-C5_Tk3nC.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-BzzGh5mo.js → Dashboard-BhdV_c4N.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-Bh8H70De.js → Dropdown-CEi5AMtM.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-DI_qybJP.js → EmailListRenderer-DOhPiYng.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DkKTsfc4.js → FamilyGuardDashboard-fu4NRP3X.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-DS7CmvVG.js → Federation-B7BtIWKL.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-CI97WsB5.js → FormItemContext-BmPWZVLP.js} +1 -1
  27. package/src/assets/web-panel/assets/GenericCardRenderer-hsOPNJq8.js +1 -0
  28. package/src/assets/web-panel/assets/{Git-CEh0gR2W.js → Git-Bi_EFBUH.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-kIr3tls2.js → Governance-emf2ubDK.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-CC1GzyC1.js → Inference-B7KjKzkI.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-BNgTiWOB.js → KnowledgeGraph-uAaBK0F3.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-B2P10gB1.js → Logs-utK7hNpj.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-HPfBvbFZ.js → Marketplace-CzQe6n3z.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-ByYotSKb.js → McpTools-CuAaJr51.js} +5 -5
  35. package/src/assets/web-panel/assets/{Memory-BGIAzFVS.js → Memory-CRuZZJ75.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-CroNYTAH.js → MobileBridge-Cp06wunh.js} +2 -2
  37. package/src/assets/web-panel/assets/MobileProjects-DJEdUwhr.js +1 -0
  38. package/src/assets/web-panel/assets/{Mtc-BqhyIwo9.js → Mtc-8YY4dR7g.js} +2 -2
  39. package/src/assets/web-panel/assets/{MtcAudit-BpEKOvx9.js → MtcAudit-BmPJYHar.js} +2 -2
  40. package/src/assets/web-panel/assets/{Multisig-DST1d_Qo.js → Multisig-d-ydyVdq.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-DlMsZcK_.js → NLProgramming-DA_ikw_n.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-C734UJvD.js → Notes-DIyF-fRe.js} +3 -3
  43. package/src/assets/web-panel/assets/{NotificationSettings-C0-pPxvk.js → NotificationSettings-CzPZXEtK.js} +1 -1
  44. package/src/assets/web-panel/assets/OrderTableRenderer-BiLtg-LY.js +1 -0
  45. package/src/assets/web-panel/assets/{Organization-C5iHC_yW.js → Organization-DdDZ_Ap6.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-CovuHHVR.js → Overflow-BnMBkttv.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-Dx9QL-Gy.js → P2P-Es1050f-.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-IP1dEt6-.js → PdhVaultBrowser-CKkRmyn9.js} +4 -4
  49. package/src/assets/web-panel/assets/{Permissions-BrR1XZG5.js → Permissions-zU9n9cAD.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-BgqxVE5m.js → PersonalDataHub-BZi5Xwas.js} +2 -2
  51. package/src/assets/web-panel/assets/{Pipeline-DzMk5HAz.js → Pipeline-CRfeGiFc.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-CDoLa6tk.js → Privacy-CQA_IgLA.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-Dy5gc6ve.js → ProjectInit-C9hmEvoT.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-DXy-k4hG.js → ProjectSettings-yXA72ws4.js} +2 -2
  55. package/src/assets/web-panel/assets/Projects-BpWS-qam.js +1 -0
  56. package/src/assets/web-panel/assets/Providers-Cxe55dRD.js +1 -0
  57. package/src/assets/web-panel/assets/{QuickAsk-B8KEHCnd.js → QuickAsk-Do0aUTQr.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-DNVHGYYZ.js → Recommend--ysZHjyA.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-CaDhWP03.js → Reputation-BOBU8JrH.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-CrGLI02x.js → Row-C6X7bRKE.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-BX7P8I6i.js → RssFeed-D8AwqlkQ.js} +3 -3
  62. package/src/assets/web-panel/assets/Search-Bi3rCZD4.js +1 -0
  63. package/src/assets/web-panel/assets/{Security-B6J7IFc1.js → Security-DxUDVrtY.js} +4 -4
  64. package/src/assets/web-panel/assets/{Services-vvdcO3mM.js → Services-BXXN7yC1.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-BoAoPTzZ.js → Skeleton-B3BR34tZ.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-CyIQV5b3.js → Skills-BjYu8OQ1.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-BAQVgdZV.js → Sla-DDkCtD8w.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-Bxcn1Jkj.js → SpeechSettings-CGhYzP7V.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-Dpaj3hDM.js → SyncSettings-CYNKVAHA.js} +2 -2
  70. package/src/assets/web-panel/assets/{Tasks-Bwqo89En.js → Tasks-DavmlJpd.js} +1 -1
  71. package/src/assets/web-panel/assets/{Templates-Bowcqifn.js → Templates-CQuYFf2C.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-DOkf85uG.js → Tenant-DdzZh8vE.js} +1 -1
  73. package/src/assets/web-panel/assets/Terminal-D75WeG9d.js +3 -0
  74. package/src/assets/web-panel/assets/{TimelineRenderer-B9A3zDXA.js → TimelineRenderer-DKOARnc_.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-jtVVqKFr.js → Tokens-D7QRNG8y.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-26Iw-iIl.js → Trigger-BCsqLZl4.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-DqY5ORrH.js → Trust-BarGUa6p.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-BFsbr3y7.js → UkeySign-pHrg5a8E.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-BtDbj3oa.js → VideoEditing-Dug3m1py.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-BAwmwHbk.js → Wallet-BfK3Z_Ez.js} +4 -4
  81. package/src/assets/web-panel/assets/{WebAuthn-DINJTsfq.js → WebAuthn-CYRdl9td.js} +5 -5
  82. package/src/assets/web-panel/assets/{WorkflowEditor-BEorm8SK.js → WorkflowEditor-DTW5AcqM.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-CE39-Dxg.js → chat-CCXz4j38.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-C_cLZ93a.js → colors-BJBOhAqa.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-BSioWA2c.js → compact-item-E9M6BQcM.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-CGTk4mhN.js → createContext-Cg9CAws4.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-BrsbTJUv.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-Dl1fRwS_.js → hasIn-DhVtqv5L.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-pngH1and.js → index--7o5YdL6.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-BmbVyhk1.js → index-4N5lNXGP.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-BnEPB1Mz.js → index-6-04M2Nx.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-Cxw3p73X.js → index-B111fZ21.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-CST381Qf.js → index-B4NBF4Sa.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-ChwpS1f0.js → index-B8bjEHrQ.js} +1 -1
  95. package/src/assets/web-panel/assets/{index--SWvw6yW.js → index-BAB0nGP7.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-CAwVwBOL.js → index-BFZPRd0T.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-hv4jUdG3.js → index-B_SMPD4L.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-Qj2x55mz.js → index-BxSzyly9.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BWpfxzVm.js → index-ByazO4Q9.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-Di6nvW1N.js → index-C-2dUIli.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BhqOTuMW.js → index-CFarAlXj.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CA6K7lZB.js → index-CFp-wdrQ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DTKEXyaW.js → index-CJ8nNT8h.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-iiZfONfx.js → index-CSiyjCYi.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DTpCUi0m.js → index-CUp_c8Le.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Bvi14vJ7.js → index-CVR_s-pT.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DKEipmR8.js → index-Ca8BYV1g.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DJyeeygd.js → index-CeRlLp3F.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-C9tq8Da8.js → index-ChsSljaN.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-B2QiUEgK.js → index-CkTeBHI9.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-OCxo0X6J.js → index-Cm1m7BJh.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DrWERr8C.js → index-ComyTKz-.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-B016Fsqr.js → index-CznfPnOx.js} +3 -3
  114. package/src/assets/web-panel/assets/{index-CisXVbSt.js → index-D5yC2Ps8.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-C-VVk1Jg.js → index-D7DXdf7x.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DDQx2YFc.js → index-DDcJO27F.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Ds2RzRG0.js → index-DSQazU6J.js} +1 -1
  118. package/src/assets/web-panel/assets/index-DSTQDO-Y.js +1 -0
  119. package/src/assets/web-panel/assets/{index-C4JXchTG.js → index-DaFe1aqY.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BAhinBPR.js → index-DdhnGez0.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-9_mmaR42.js → index-Di5LBXcE.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-D9D4q-qI.js → index-Dwvewrul.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CbXnyoSO.js → index-MdXEhfdJ.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-II3JhQu2.js → index-_PNqQ5mE.js} +1 -1
  125. package/src/assets/web-panel/assets/index-c2U6LV3Q.js +1 -0
  126. package/src/assets/web-panel/assets/{index-C2ly7sCw.js → index-kz1oXl1a.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Ceo9P9tQ.js → index-wkt-o5q5.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-GOhLA2-f.js → initDefaultProps-iyBaePF-.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-jqxFzHTx.js → motion-RWtj4rgu.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-CSLsp6TA.js → move-CqPRVzpH.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-Cnlrb25c.js → omit-DsvJze25.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-CLqlxWWD.js → pickAttrs-B4tfZBhc.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-BAWIWtul.js → placementArrow-KvHUwXMA.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-CSR1DayS.js → responsiveObserve-DGdJ-b7W.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-CNhoPJOp.js → slide-Cd6ebRmw.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-BZiYHRHW.js → statusUtils-Bg9GcIAn.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-BMoY-Fm5.js → styleChecker-MQjKsG84.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-DhtNdlaS.js → useFlexGapSupport-C241WujP.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-DNPtDOZ4.js → useFs-CMpy7RS4.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-DTdjNvAI.js → usePersonalDataHub-BLHtapKb.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-C9zW9IJ2.js → vnode-DmcTV67c.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-D-6RYJJr.js → zoom-DHL8_0Y8.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/agent.js +161 -6
  145. package/src/commands/agents.js +8 -2
  146. package/src/commands/cli-anything.js +14 -6
  147. package/src/commands/command.js +7 -2
  148. package/src/commands/hook.js +136 -28
  149. package/src/commands/ide.js +168 -0
  150. package/src/commands/loop.js +450 -0
  151. package/src/commands/mcp.js +92 -0
  152. package/src/commands/output-style.js +127 -0
  153. package/src/commands/permissions.js +211 -0
  154. package/src/commands/statusline.js +93 -0
  155. package/src/index.js +10 -2
  156. package/src/lib/agent-core.js +7 -0
  157. package/src/lib/agents.js +5 -0
  158. package/src/lib/hook-manager.js +1 -0
  159. package/src/lib/hook-runner.cjs +183 -0
  160. package/src/lib/ide-bridge.js +310 -0
  161. package/src/lib/image-input.js +156 -0
  162. package/src/lib/loop.js +198 -0
  163. package/src/lib/mcp-oauth.js +415 -0
  164. package/src/lib/output-styles.js +179 -0
  165. package/src/lib/permission-rules.cjs +325 -0
  166. package/src/lib/provider-options.js +11 -7
  167. package/src/lib/settings-hook-events.cjs +102 -0
  168. package/src/lib/settings-hooks.cjs +163 -0
  169. package/src/lib/settings-loader.cjs +244 -0
  170. package/src/lib/slash-commands.js +4 -0
  171. package/src/lib/status-line.cjs +204 -0
  172. package/src/lib/sub-agent-profiles.js +3 -0
  173. package/src/lib/web-search.js +487 -0
  174. package/src/repl/agent-repl.js +450 -35
  175. package/src/repl/slash-macro.js +45 -0
  176. package/src/runtime/agent-core.js +799 -21
  177. package/src/runtime/coding-agent-contract-shared.cjs +94 -4
  178. package/src/runtime/coding-agent-policy.cjs +24 -0
  179. package/src/runtime/headless-runner.js +162 -6
  180. package/src/runtime/headless-stream.js +133 -7
  181. package/src/runtime/mcp-config.js +161 -15
  182. package/src/runtime/policies/agent-policy.js +4 -0
  183. package/src/runtime/system-prompt.js +6 -1
  184. package/src/assets/web-panel/assets/GenericCardRenderer-Da27EdR4.js +0 -1
  185. package/src/assets/web-panel/assets/MobileProjects-CH-qnGEV.js +0 -1
  186. package/src/assets/web-panel/assets/OrderTableRenderer-C7zT9eFc.js +0 -1
  187. package/src/assets/web-panel/assets/Projects-DvsaEbZR.js +0 -1
  188. package/src/assets/web-panel/assets/Providers-Demck9PO.js +0 -1
  189. package/src/assets/web-panel/assets/Search-laS6rz8M.js +0 -1
  190. package/src/assets/web-panel/assets/Terminal-v4MM9dCj.js +0 -3
  191. package/src/assets/web-panel/assets/devWarning-PObcVnJR.js +0 -1
  192. package/src/assets/web-panel/assets/index-BNwIzLyX.js +0 -1
  193. package/src/assets/web-panel/assets/index-Dh6FxR9B.js +0 -1
@@ -0,0 +1,211 @@
1
+ /**
2
+ * cc permissions — inspect, dry-run, and edit the `.claude/settings.json`
3
+ * permission ruleset (Claude-Code `permissions.{allow,ask,deny}` parity).
4
+ *
5
+ * cc permissions list [--json] merged ruleset + source file
6
+ * cc permissions test <tool> <args...> dry-run: which rule decides?
7
+ * cc permissions add <allow|ask|deny> <rule> append a rule to a settings file
8
+ * [--local | --user] (default target: project)
9
+ *
10
+ * The ruleset is loaded by settings-loader (user < project < local < env) and
11
+ * evaluated by permission-rules (deny > ask > allow). This command only reads
12
+ * and edits the files / runs the engine — it does not yet gate the agent tool
13
+ * loop (that wiring is a separate, riskier step).
14
+ */
15
+
16
+ import chalk from "chalk";
17
+ import { logger } from "../lib/logger.js";
18
+
19
+ const KIND_COLOR = {
20
+ allow: chalk.green,
21
+ ask: chalk.yellow,
22
+ deny: chalk.red,
23
+ };
24
+
25
+ /** Resolve an umbrella token (Bash) to a concrete tool name for dry-run. */
26
+ function resolveConcreteTool(token, groups) {
27
+ const t = String(token || "");
28
+ const lower = t.toLowerCase();
29
+ if (Object.prototype.hasOwnProperty.call(groups, lower)) {
30
+ return groups[lower][0];
31
+ }
32
+ return t;
33
+ }
34
+
35
+ /** Build the tool args object a dry-run target needs from positional args. */
36
+ function buildArgs(tool, positional, rulesMod) {
37
+ const joined = positional.join(" ").trim();
38
+ if (rulesMod.COMMAND_TOOLS.has(tool)) return { command: joined };
39
+ if (rulesMod.PATH_TOOLS.has(tool)) return { path: positional[0] || "" };
40
+ if (rulesMod.URL_TOOLS.has(tool)) return { url: positional[0] || "" };
41
+ return {};
42
+ }
43
+
44
+ export function registerPermissionsCommand(program) {
45
+ const cmd = program
46
+ .command("permissions")
47
+ .alias("perms")
48
+ .description(
49
+ "Inspect / dry-run / edit .claude/settings.json permission rules",
50
+ );
51
+
52
+ // ── list ──────────────────────────────────────────────────────────────
53
+ cmd
54
+ .command("list")
55
+ .alias("ls")
56
+ .description("Show the merged permission ruleset and where each rule came from")
57
+ .option("--json", "Output as JSON")
58
+ .option("--settings <file>", "Also merge an explicit settings file")
59
+ .action(async (options) => {
60
+ try {
61
+ const { loadSettings } = await import("../lib/settings-loader.cjs");
62
+ const { rules, sources, files } = loadSettings({
63
+ cwd: process.cwd(),
64
+ settingsFile: options.settings,
65
+ });
66
+ if (options.json) {
67
+ console.log(JSON.stringify({ rules, sources, files }, null, 2));
68
+ return;
69
+ }
70
+ const total =
71
+ rules.allow.length + rules.ask.length + rules.deny.length;
72
+ if (total === 0) {
73
+ logger.log(
74
+ chalk.gray(
75
+ "No permission rules. Add one: cc permissions add deny \"Bash(rm:*)\"\n" +
76
+ "(or create .claude/settings.json with a permissions block)",
77
+ ),
78
+ );
79
+ return;
80
+ }
81
+ for (const kind of ["deny", "ask", "allow"]) {
82
+ if (rules[kind].length === 0) continue;
83
+ logger.log(KIND_COLOR[kind].bold(`${kind} (${rules[kind].length})`));
84
+ for (const rule of rules[kind]) {
85
+ const src = sources[`${kind}:${rule}`] || "?";
86
+ logger.log(` ${rule.padEnd(34)} ${chalk.gray(src)}`);
87
+ }
88
+ }
89
+ if (files.length) {
90
+ logger.log(chalk.dim(`\nsources: ${files.join(", ")}`));
91
+ }
92
+ } catch (err) {
93
+ logger.error(chalk.red(`permissions list failed: ${err.message}`));
94
+ process.exitCode = 1;
95
+ }
96
+ });
97
+
98
+ // ── test (dry-run) ─────────────────────────────────────────────────────
99
+ cmd
100
+ .command("test <tool> [args...]")
101
+ .description(
102
+ 'Dry-run a tool call against the ruleset, e.g. permissions test run_shell "git push"',
103
+ )
104
+ .option("--json", "Output as JSON")
105
+ .option("--settings <file>", "Also merge an explicit settings file")
106
+ .action(async (tool, args, options) => {
107
+ try {
108
+ const { loadSettings, ruleSource } =
109
+ await import("../lib/settings-loader.cjs");
110
+ // .cjs default-export interop: module.exports surfaces as `.default`.
111
+ const rulesMod = await import("../lib/permission-rules.cjs");
112
+ const mod = rulesMod.default || rulesMod;
113
+
114
+ const { rules, sources } = loadSettings({
115
+ cwd: process.cwd(),
116
+ settingsFile: options.settings,
117
+ });
118
+ const concrete = resolveConcreteTool(tool, mod.TOOL_GROUPS);
119
+ const toolArgs = buildArgs(concrete, args || [], mod);
120
+ const result = mod.evaluatePermissionRules({
121
+ tool: concrete,
122
+ args: toolArgs,
123
+ cwd: process.cwd(),
124
+ rules,
125
+ });
126
+ const decision = result.decision || "fallthrough";
127
+ const source = result.rule
128
+ ? ruleSource(sources, result.decision, result.rule)
129
+ : null;
130
+
131
+ if (options.json) {
132
+ console.log(
133
+ JSON.stringify(
134
+ { tool: concrete, args: toolArgs, decision, rule: result.rule, source },
135
+ null,
136
+ 2,
137
+ ),
138
+ );
139
+ return;
140
+ }
141
+
142
+ const color = KIND_COLOR[result.decision] || chalk.gray;
143
+ logger.log(
144
+ `${chalk.bold(concrete)} ${chalk.gray(JSON.stringify(toolArgs))}`,
145
+ );
146
+ logger.log(` decision: ${color.bold(decision)}`);
147
+ if (result.rule) {
148
+ logger.log(` rule: ${result.rule}`);
149
+ if (source) logger.log(` source: ${chalk.gray(source)}`);
150
+ } else {
151
+ logger.log(
152
+ chalk.gray(
153
+ " no rule matched → falls back to risk-tier / --permission-mode logic",
154
+ ),
155
+ );
156
+ }
157
+ } catch (err) {
158
+ logger.error(chalk.red(`permissions test failed: ${err.message}`));
159
+ process.exitCode = 1;
160
+ }
161
+ });
162
+
163
+ // ── add ────────────────────────────────────────────────────────────────
164
+ cmd
165
+ .command("add <decision> <rule>")
166
+ .description("Append a rule (allow|ask|deny) to a settings file")
167
+ .option("--local", "Write to .claude/settings.local.json (personal, gitignored)")
168
+ .option("--user", "Write to ~/.claude/settings.json (all projects)")
169
+ .action(async (decision, rule, options) => {
170
+ try {
171
+ const kind = String(decision || "").toLowerCase();
172
+ if (!["allow", "ask", "deny"].includes(kind)) {
173
+ logger.error(
174
+ chalk.red(`decision must be allow | ask | deny (got "${decision}")`),
175
+ );
176
+ process.exitCode = 1;
177
+ return;
178
+ }
179
+ const rulesMod = await import("../lib/permission-rules.cjs");
180
+ const mod = rulesMod.default || rulesMod;
181
+ if (!mod.parseRule(rule)) {
182
+ logger.error(
183
+ chalk.red(
184
+ `not a valid rule: "${rule}" (expected Tool or Tool(pattern), e.g. Bash(rm:*))`,
185
+ ),
186
+ );
187
+ process.exitCode = 1;
188
+ return;
189
+ }
190
+
191
+ const scope = options.user ? "user" : options.local ? "local" : "project";
192
+ const { addRule } = await import("../lib/settings-loader.cjs");
193
+ const { file, added } = addRule({
194
+ cwd: process.cwd(),
195
+ kind,
196
+ rule,
197
+ scope,
198
+ });
199
+ if (!added) {
200
+ logger.log(chalk.gray(`already present in ${file}: ${kind} ${rule}`));
201
+ return;
202
+ }
203
+ logger.log(
204
+ `${KIND_COLOR[kind].bold("✓ " + kind)} ${rule} ${chalk.gray("→ " + file)}`,
205
+ );
206
+ } catch (err) {
207
+ logger.error(chalk.red(`permissions add failed: ${err.message}`));
208
+ process.exitCode = 1;
209
+ }
210
+ });
211
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * cc statusline — preview the configured `statusLine` (Claude-Code parity).
3
+ *
4
+ * cc statusline preview the rendered status line
5
+ * cc statusline show show the resolved config (+ source)
6
+ *
7
+ * Configure in .claude/settings.json:
8
+ * { "statusLine": { "type": "command", "command": "~/.claude/status.sh" } }
9
+ * The command receives a JSON context on stdin and its first stdout line is the
10
+ * status line (shown above the REPL prompt each turn).
11
+ */
12
+
13
+ import chalk from "chalk";
14
+ import { logger } from "../lib/logger.js";
15
+
16
+ export function registerStatuslineCommand(program) {
17
+ const cmd = program
18
+ .command("statusline")
19
+ .alias("status-line")
20
+ .description("Preview / show the .claude/settings.json statusLine");
21
+
22
+ cmd
23
+ .command("preview", { isDefault: true })
24
+ .description("Render the configured status line once")
25
+ .option("--model <m>", "Model to pass in the context", "opus")
26
+ .option("--json", "Output as JSON")
27
+ .action(async (options) => {
28
+ try {
29
+ const { loadStatusLineConfig, buildContext, renderStatusLine } =
30
+ await import("../lib/status-line.cjs");
31
+ const cfg = loadStatusLineConfig({ cwd: process.cwd() });
32
+ if (!cfg) {
33
+ logger.log(
34
+ chalk.gray(
35
+ 'No statusLine configured. Add to .claude/settings.json:\n' +
36
+ ' { "statusLine": { "type": "command", "command": "./status.sh" } }',
37
+ ),
38
+ );
39
+ return;
40
+ }
41
+ const line = renderStatusLine(
42
+ cfg,
43
+ buildContext({
44
+ sessionId: "preview",
45
+ model: options.model,
46
+ cwd: process.cwd(),
47
+ }),
48
+ { cwd: process.cwd() },
49
+ );
50
+ if (options.json) {
51
+ console.log(JSON.stringify({ config: cfg, line }, null, 2));
52
+ return;
53
+ }
54
+ if (line == null) {
55
+ logger.error(
56
+ chalk.red(
57
+ `statusLine command produced no output (or failed): ${cfg.command}`,
58
+ ),
59
+ );
60
+ process.exitCode = 1;
61
+ return;
62
+ }
63
+ process.stdout.write(line + "\n");
64
+ } catch (err) {
65
+ logger.error(chalk.red(`statusline preview failed: ${err.message}`));
66
+ process.exitCode = 1;
67
+ }
68
+ });
69
+
70
+ cmd
71
+ .command("show")
72
+ .description("Show the resolved statusLine config")
73
+ .option("--json", "Output as JSON")
74
+ .action(async (options) => {
75
+ try {
76
+ const { loadStatusLineConfig } = await import("../lib/status-line.cjs");
77
+ const cfg = loadStatusLineConfig({ cwd: process.cwd() });
78
+ if (options.json) {
79
+ console.log(JSON.stringify(cfg, null, 2));
80
+ return;
81
+ }
82
+ if (!cfg) {
83
+ logger.log(chalk.gray("No statusLine configured."));
84
+ return;
85
+ }
86
+ logger.log(`command: ${chalk.cyan(cfg.command)}`);
87
+ logger.log(chalk.gray(`type: ${cfg.type} padding: ${cfg.padding}`));
88
+ } catch (err) {
89
+ logger.error(chalk.red(`statusline show failed: ${err.message}`));
90
+ process.exitCode = 1;
91
+ }
92
+ });
93
+ }
package/src/index.js CHANGED
@@ -58,11 +58,15 @@ import { registerRCacheCommand } from "./commands/rcache.js";
58
58
  import { registerSessionCommand } from "./commands/session.js";
59
59
  import { registerCostCommand } from "./commands/cost.js";
60
60
  import { registerContextCommand } from "./commands/context.js";
61
- import { registerAgentsCommand } from "./commands/agents.js";
62
61
  import { registerCheckpointCommand } from "./commands/checkpoint.js";
63
62
  import { registerGoalCommand } from "./commands/goal.js";
64
63
  import { registerCommandCommand } from "./commands/command.js";
65
64
  import { registerCompactCommand } from "./commands/compact.js";
65
+ import { registerLoopCommand } from "./commands/loop.js";
66
+ import { registerPermissionsCommand } from "./commands/permissions.js";
67
+ import { registerOutputStyleCommand } from "./commands/output-style.js";
68
+ import { registerStatuslineCommand } from "./commands/statusline.js";
69
+ import { registerIdeCommand } from "./commands/ide.js";
66
70
  import { registerConsolCommand } from "./commands/consol.js";
67
71
  import { registerImportCommand } from "./commands/import.js";
68
72
  import { registerExportCommand } from "./commands/export.js";
@@ -457,11 +461,15 @@ export function createProgram(opts = {}) {
457
461
  registerSessionCommand(program);
458
462
  registerCostCommand(program);
459
463
  registerContextCommand(program);
460
- registerAgentsCommand(program);
461
464
  registerCheckpointCommand(program);
462
465
  registerGoalCommand(program);
463
466
  registerCommandCommand(program);
464
467
  registerCompactCommand(program);
468
+ registerLoopCommand(program);
469
+ registerPermissionsCommand(program);
470
+ registerOutputStyleCommand(program);
471
+ registerStatuslineCommand(program);
472
+ registerIdeCommand(program);
465
473
  registerConsolCommand(program);
466
474
 
467
475
  // Phase 2: Knowledge & content management
@@ -24,5 +24,12 @@ export {
24
24
  agentLoop,
25
25
  formatToolArgs,
26
26
  getActiveMcpServers,
27
+ listBackgroundShellTasks,
28
+ killAllBackgroundShellTasks,
27
29
  _accumulateOllamaStream,
30
+ _accumulateOpenAIStream,
31
+ _accumulateAnthropicStream,
32
+ _toAnthropicMessages,
33
+ _anthropicThinkingParams,
34
+ _normalizeAnthropicResponse,
28
35
  } from "../runtime/agent-core.js";
package/src/lib/agents.js CHANGED
@@ -57,7 +57,12 @@ export function normalizeTools(tools) {
57
57
  export function agentDirs(cwd = process.cwd(), opts = {}) {
58
58
  const path = opts.deps?.path || _deps.path;
59
59
  const home = opts.home || homedir();
60
+ // Project-native first (highest precedence), then the Claude-Code-portable
61
+ // location (so existing `.claude/agents/*.md` work unchanged), then personal.
62
+ // discoverAgents reverses + last-write-wins, so `.chainlesschain/agents/`
63
+ // shadows `.claude/agents/` shadows `~/.claude/agents/` on a name clash.
60
64
  return [
65
+ { dir: path.join(cwd, ".chainlesschain", "agents"), scope: "project" },
61
66
  { dir: path.join(cwd, ".claude", "agents"), scope: "project" },
62
67
  { dir: path.join(home, ".claude", "agents"), scope: "personal" },
63
68
  ];
@@ -40,6 +40,7 @@ export const HookEvents = {
40
40
  SessionEnd: "SessionEnd",
41
41
  PreCompact: "PreCompact",
42
42
  PostCompact: "PostCompact",
43
+ Notification: "Notification",
43
44
  UserPromptSubmit: "UserPromptSubmit",
44
45
  AssistantResponse: "AssistantResponse",
45
46
  AgentStart: "AgentStart",
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * hook-runner — execute a Claude-Code `command` hook with the JSON protocol.
5
+ *
6
+ * Protocol (Claude-Code parity):
7
+ * - the hook event payload is written to the command's STDIN as JSON;
8
+ * - exit code 2 → BLOCK (reason = stderr) — the canonical "deny" path;
9
+ * - exit code 0 + JSON stdout → honored decision:
10
+ * { "decision": "block"|"approve"|"ask", "reason": "..." }
11
+ * { "hookSpecificOutput": { "permissionDecision": "deny"|"allow"|"ask",
12
+ * "permissionDecisionReason": "..." } }
13
+ * { "continue": false, "stopReason": "..." } → block
14
+ * { "additionalContext": "..." } → continue
15
+ * - any other non-zero → non-blocking error (surfaced, never blocks);
16
+ * - spawn failure / timeout → non-blocking (a broken hook must not wedge the
17
+ * agent — only an explicit block decision blocks).
18
+ *
19
+ * Returns a normalized `{ decision, reason, exitCode, stdout, stderr, ... }`.
20
+ * `_deps.spawnSync` is injected for unit tests (no real process needed).
21
+ */
22
+
23
+ const cpDefault = require("node:child_process");
24
+
25
+ const _deps = { spawnSync: cpDefault.spawnSync };
26
+
27
+ const HOOK_DECISIONS = Object.freeze({
28
+ BLOCK: "block",
29
+ ALLOW: "allow",
30
+ ASK: "ask",
31
+ CONTINUE: "continue",
32
+ });
33
+
34
+ /** Parse a hook's stdout JSON into a normalized decision, or null if not JSON. */
35
+ function tryParseDecision(stdout) {
36
+ const text = String(stdout || "").trim();
37
+ if (!text || text[0] !== "{") return null;
38
+ let obj;
39
+ try {
40
+ obj = JSON.parse(text);
41
+ } catch {
42
+ return null;
43
+ }
44
+ // PreToolUse-specific permission decision
45
+ const hso = obj.hookSpecificOutput;
46
+ if (hso && hso.permissionDecision) {
47
+ const pd = String(hso.permissionDecision).toLowerCase();
48
+ const decision =
49
+ pd === "deny"
50
+ ? HOOK_DECISIONS.BLOCK
51
+ : pd === "ask"
52
+ ? HOOK_DECISIONS.ASK
53
+ : pd === "allow"
54
+ ? HOOK_DECISIONS.ALLOW
55
+ : HOOK_DECISIONS.CONTINUE;
56
+ return { decision, reason: hso.permissionDecisionReason || null };
57
+ }
58
+ // Generic decision field
59
+ if (obj.decision) {
60
+ const d = String(obj.decision).toLowerCase();
61
+ const decision =
62
+ d === "block" || d === "deny"
63
+ ? HOOK_DECISIONS.BLOCK
64
+ : d === "approve" || d === "allow"
65
+ ? HOOK_DECISIONS.ALLOW
66
+ : d === "ask"
67
+ ? HOOK_DECISIONS.ASK
68
+ : HOOK_DECISIONS.CONTINUE;
69
+ return { decision, reason: obj.reason || null };
70
+ }
71
+ // continue:false → stop/block
72
+ if (obj.continue === false) {
73
+ return {
74
+ decision: HOOK_DECISIONS.BLOCK,
75
+ reason: obj.stopReason || obj.reason || "hook requested stop",
76
+ };
77
+ }
78
+ return {
79
+ decision: HOOK_DECISIONS.CONTINUE,
80
+ reason: null,
81
+ additionalContext: obj.additionalContext || null,
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Run one command hook. `input` is JSON-serialized to the hook's stdin.
87
+ *
88
+ * @param {string} command
89
+ * @param {object} [input] the hook event payload (tool_name, tool_input, …)
90
+ * @param {object} [opts] { timeout=60000, cwd, event }
91
+ * @returns {{ decision:string, reason:string|null, exitCode:number|null,
92
+ * stdout?:string, stderr?:string, additionalContext?:string,
93
+ * nonBlockingError?:boolean, error?:string }}
94
+ */
95
+ function runCommandHook(command, input = {}, opts = {}) {
96
+ const { timeout = 60000, cwd, event } = opts;
97
+ if (!command) {
98
+ return { decision: HOOK_DECISIONS.CONTINUE, reason: null, exitCode: 0 };
99
+ }
100
+ let res;
101
+ try {
102
+ res = _deps.spawnSync(command, {
103
+ input: JSON.stringify(input),
104
+ cwd: cwd || process.cwd(),
105
+ encoding: "utf-8",
106
+ timeout,
107
+ shell: true,
108
+ maxBuffer: 8 * 1024 * 1024,
109
+ env: {
110
+ ...process.env,
111
+ CLAUDE_HOOK_EVENT: event || input.hook_event_name || "",
112
+ },
113
+ });
114
+ } catch (err) {
115
+ return {
116
+ decision: HOOK_DECISIONS.CONTINUE,
117
+ reason: `hook spawn failed: ${err.message}`,
118
+ exitCode: null,
119
+ error: err.message,
120
+ nonBlockingError: true,
121
+ };
122
+ }
123
+ // spawnSync surfaces timeout/ENOENT on res.error (status null) — non-blocking.
124
+ if (res.error) {
125
+ return {
126
+ decision: HOOK_DECISIONS.CONTINUE,
127
+ reason: `hook error: ${res.error.message}`,
128
+ exitCode: null,
129
+ stdout: String(res.stdout || ""),
130
+ stderr: String(res.stderr || ""),
131
+ error: res.error.message,
132
+ nonBlockingError: true,
133
+ };
134
+ }
135
+ const exitCode = res.status;
136
+ const stdout = String(res.stdout || "");
137
+ const stderr = String(res.stderr || "");
138
+
139
+ if (exitCode === 2) {
140
+ return {
141
+ decision: HOOK_DECISIONS.BLOCK,
142
+ reason: stderr.trim() || "hook exited 2 (blocked)",
143
+ exitCode,
144
+ stdout,
145
+ stderr,
146
+ };
147
+ }
148
+ if (exitCode === 0) {
149
+ const parsed = tryParseDecision(stdout);
150
+ if (parsed) return { ...parsed, exitCode, stdout, stderr };
151
+ return { decision: HOOK_DECISIONS.CONTINUE, reason: null, exitCode, stdout, stderr };
152
+ }
153
+ // Other non-zero → non-blocking error.
154
+ return {
155
+ decision: HOOK_DECISIONS.CONTINUE,
156
+ reason: stderr.trim() || `hook exited ${exitCode}`,
157
+ exitCode,
158
+ stdout,
159
+ stderr,
160
+ nonBlockingError: true,
161
+ };
162
+ }
163
+
164
+ /**
165
+ * Run a list of command hooks in order; first BLOCK (or ASK) short-circuits.
166
+ * @returns {{ decision, reason, hook?, results }}
167
+ */
168
+ function runHooks(commandHooks, input = {}, opts = {}) {
169
+ const results = [];
170
+ for (const h of commandHooks || []) {
171
+ const r = runCommandHook(h.command, input, {
172
+ ...opts,
173
+ timeout: h.timeout != null ? h.timeout * 1000 : opts.timeout,
174
+ });
175
+ results.push({ command: h.command, ...r });
176
+ if (r.decision === HOOK_DECISIONS.BLOCK || r.decision === HOOK_DECISIONS.ASK) {
177
+ return { decision: r.decision, reason: r.reason, hook: h.command, results };
178
+ }
179
+ }
180
+ return { decision: HOOK_DECISIONS.CONTINUE, reason: null, results };
181
+ }
182
+
183
+ module.exports = { runCommandHook, runHooks, tryParseDecision, HOOK_DECISIONS, _deps };