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
@@ -48,7 +48,10 @@ import {
48
48
  } from "../lib/task-model-selector.js";
49
49
  import { CLIPermanentMemory } from "../lib/permanent-memory.js";
50
50
  import { CLIAutonomousAgent, GoalStatus } from "../lib/autonomous-agent.js";
51
- import { PromptCompressor } from "../harness/prompt-compressor.js";
51
+ import {
52
+ PromptCompressor,
53
+ getContextWindow,
54
+ } from "../harness/prompt-compressor.js";
52
55
  import { feature } from "../lib/feature-flags.js";
53
56
  import { recordCompressionMetric } from "../lib/compression-telemetry.js";
54
57
  import {
@@ -58,17 +61,19 @@ import {
58
61
  } from "../lib/session-hooks.js";
59
62
  import { HookEvents } from "../lib/hook-manager.js";
60
63
  import { IterationBudget } from "../lib/iteration-budget.js";
61
- import { loadMcpConfig } from "../runtime/mcp-config.js";
64
+ import { resolveAgentMcp } from "../runtime/mcp-config.js";
62
65
  import {
63
66
  AGENT_TOOLS,
64
67
  buildSystemPrompt,
65
68
  executeTool as coreExecuteTool,
66
69
  agentLoop as coreAgentLoop,
67
70
  formatToolArgs,
71
+ killAllBackgroundShellTasks,
68
72
  } from "../runtime/agent-core.js";
69
73
  import { expandFileRefs } from "../runtime/file-ref-expander.js";
70
74
  import { composeSystemPrompt } from "../runtime/system-prompt.js";
71
75
  import { makeFallbackChatFn } from "../runtime/fallback-model.js";
76
+ import { resolveSlashMacro } from "./slash-macro.js";
72
77
 
73
78
  /**
74
79
  * Reference to the runtime DB for hook execution (set during startAgentRepl)
@@ -76,6 +81,61 @@ import { makeFallbackChatFn } from "../runtime/fallback-model.js";
76
81
  let _hookDb = null;
77
82
  let _compressor = null;
78
83
  let _approvalGate = null;
84
+ // .claude/settings.json permission rules (deny > ask > allow) + an interactive
85
+ // confirmer for `ask` matches. Loaded once at REPL startup; null = no file.
86
+ let _permissionRules = null;
87
+ let _permissionConfirm = null;
88
+ // .claude/settings.json `hooks` block (decision-capable PreToolUse/PostToolUse).
89
+ let _settingsHooks = null;
90
+
91
+ /**
92
+ * Fire settings.json Notification hooks (observe-only) — the agent needs the
93
+ * user's attention (e.g. waiting on a permission/risk confirmation). A hook can
94
+ * ring a bell / send a desktop notification. Best-effort, never blocks.
95
+ */
96
+ async function _fireNotification(message) {
97
+ if (!_settingsHooks) return;
98
+ try {
99
+ const { runObserveHooks } = await import("../lib/settings-hook-events.cjs");
100
+ runObserveHooks(
101
+ _settingsHooks,
102
+ "Notification",
103
+ { message, cwd: process.cwd(), session_id: null },
104
+ { cwd: process.cwd() },
105
+ );
106
+ } catch (_err) {
107
+ // observe-only — never affect the prompt
108
+ }
109
+ }
110
+
111
+ /**
112
+ * "Always allow" persistence: derive a sensible allow rule for a tool call,
113
+ * append it to .claude/settings.local.json (personal, gitignored), and reflect
114
+ * it in the in-memory ruleset so the rest of the session stops prompting. A
115
+ * persisted `allow` short-circuits the ApprovalGate via agent-core's
116
+ * `ruleAllowed` path (see permission-rules wiring). Returns {rule,file} or null.
117
+ */
118
+ async function _persistAlwaysAllow(tool, args) {
119
+ try {
120
+ const rulesMod = await import("../lib/permission-rules.cjs");
121
+ const { suggestAllowRule } = rulesMod.default || rulesMod;
122
+ const rule = suggestAllowRule(tool || "run_shell", args || {});
123
+ if (!rule) return null;
124
+ const { addRule } = await import("../lib/settings-loader.cjs");
125
+ const { file } = addRule({
126
+ cwd: process.cwd(),
127
+ kind: "allow",
128
+ rule,
129
+ scope: "local",
130
+ });
131
+ if (!_permissionRules) _permissionRules = { allow: [], ask: [], deny: [] };
132
+ if (!_permissionRules.allow.includes(rule)) _permissionRules.allow.push(rule);
133
+ return { rule, file };
134
+ } catch (err) {
135
+ process.stderr.write(` always-allow persist failed: ${err.message}\n`);
136
+ return null;
137
+ }
138
+ }
79
139
 
80
140
  /**
81
141
  * Execute a tool call — delegates to agent-core with REPL's hookDb and cwd.
@@ -85,6 +145,9 @@ async function executeTool(name, args) {
85
145
  hookDb: _hookDb,
86
146
  cwd: process.cwd(),
87
147
  approvalGate: _approvalGate,
148
+ permissionRules: _permissionRules,
149
+ permissionConfirm: _permissionConfirm,
150
+ settingsHooks: _settingsHooks,
88
151
  });
89
152
  }
90
153
 
@@ -162,6 +225,11 @@ async function agentLoop(messages, options) {
162
225
  export async function startAgentRepl(options = {}) {
163
226
  let model = options.model || "qwen2.5:7b";
164
227
  let provider = options.provider || "ollama";
228
+ // Extended thinking (Anthropic; opt-in via --think/--ultrathink). Carried from
229
+ // the runtime policy into the agent-loop options below. thinkingBudget
230
+ // (--thinking-budget) is the companion legacy-model budget_tokens override.
231
+ const thinking = options.thinking || null;
232
+ const thinkingBudget = options.thinkingBudget || null;
165
233
  const baseUrl = options.baseUrl || "http://localhost:11434";
166
234
  const apiKey = options.apiKey || null;
167
235
  // Extra workspace roots (--add-dir): advertised in the system prompt and
@@ -233,7 +301,10 @@ export async function startAgentRepl(options = {}) {
233
301
  await import("../lib/session-core-singletons.js");
234
302
  _approvalGate = await getApprovalGate();
235
303
  if (typeof _approvalGate.setConfirmer === "function") {
236
- _approvalGate.setConfirmer(async ({ args, riskLevel }) => {
304
+ _approvalGate.setConfirmer(async ({ tool, args, riskLevel }) => {
305
+ await _fireNotification(
306
+ `Permission needed: ${riskLevel || "medium"}-risk ${tool || "run_shell"}${args?.command ? " — " + args.command : ""}`,
307
+ );
237
308
  const rlConfirm = readline.createInterface({
238
309
  input: process.stdin,
239
310
  output: process.stdout,
@@ -243,13 +314,25 @@ export async function startAgentRepl(options = {}) {
243
314
  const ans = (
244
315
  await q(
245
316
  chalk.yellow(
246
- `\n[ApprovalGate] ${riskLevel || "medium"} risk command:${cmd}\n Proceed? (y/N) `,
317
+ `\n[ApprovalGate] ${riskLevel || "medium"} risk command:${cmd}\n` +
318
+ ` Proceed? [y]es once / [a]lways allow / [N]o: `,
247
319
  ),
248
320
  )
249
321
  )
250
322
  .trim()
251
323
  .toLowerCase();
252
324
  rlConfirm.close();
325
+ if (ans === "a" || ans === "always") {
326
+ const saved = await _persistAlwaysAllow(tool || "run_shell", args);
327
+ if (saved) {
328
+ process.stdout.write(
329
+ chalk.green(
330
+ ` ✓ always allow: added ${saved.rule} → ${saved.file}\n`,
331
+ ),
332
+ );
333
+ }
334
+ return true;
335
+ }
253
336
  return ans === "y" || ans === "yes";
254
337
  });
255
338
  }
@@ -257,6 +340,63 @@ export async function startAgentRepl(options = {}) {
257
340
  _approvalGate = null;
258
341
  }
259
342
 
343
+ // Load .claude/settings.json permission rules + wire an interactive confirmer
344
+ // so `ask` rules prompt (rather than fall closed like headless does).
345
+ try {
346
+ const { loadSettings } = await import("../lib/settings-loader.cjs");
347
+ const loaded = loadSettings({ cwd: process.cwd() });
348
+ const total =
349
+ loaded.rules.allow.length +
350
+ loaded.rules.ask.length +
351
+ loaded.rules.deny.length;
352
+ _permissionRules = total > 0 ? loaded.rules : null;
353
+ // Confirmer is shared by permission `ask` rules AND hook `ask` decisions,
354
+ // so define it unconditionally (a `hook:` rule label flows through too).
355
+ _permissionConfirm = async ({ tool, args, rule }) => {
356
+ await _fireNotification(
357
+ `Permission needed: ${tool}${rule ? " (" + rule + ")" : ""}`,
358
+ );
359
+ const rl = readline.createInterface({
360
+ input: process.stdin,
361
+ output: process.stdout,
362
+ });
363
+ const q = (p) => new Promise((res) => rl.question(p, res));
364
+ const detail = args?.command
365
+ ? ` ${args.command}`
366
+ : args?.path
367
+ ? ` ${args.path}`
368
+ : "";
369
+ const ans = (
370
+ await q(
371
+ chalk.yellow(
372
+ `\n[Permission] ${rule} asks before ${tool}:${detail}\n Proceed? (y/N) `,
373
+ ),
374
+ )
375
+ )
376
+ .trim()
377
+ .toLowerCase();
378
+ rl.close();
379
+ return ans === "y" || ans === "yes";
380
+ };
381
+ } catch (_err) {
382
+ _permissionRules = null;
383
+ _permissionConfirm = null;
384
+ }
385
+
386
+ // Load .claude/settings.json `hooks` block (decision-capable PreToolUse/
387
+ // PostToolUse). The interactive _permissionConfirm above doubles as the
388
+ // confirmer for a hook `ask` decision.
389
+ try {
390
+ const { loadHooks } = await import("../lib/settings-hooks.cjs");
391
+ const loaded = loadHooks({ cwd: process.cwd() });
392
+ _settingsHooks =
393
+ loaded.hooks && Object.keys(loaded.hooks).length > 0
394
+ ? loaded.hooks
395
+ : null;
396
+ } catch (_err) {
397
+ _settingsHooks = null;
398
+ }
399
+
260
400
  // Resume existing session or create new one
261
401
  const useJsonl = feature("JSONL_SESSION");
262
402
 
@@ -335,20 +475,47 @@ export async function startAgentRepl(options = {}) {
335
475
  // Non-critical — SessionManager integration must not block startup
336
476
  }
337
477
 
338
- const messages = [
478
+ // --system-prompt replaces the built-in prompt; --append-system-prompt
479
+ // extends it (parity with the headless runners). The base is kept so an
480
+ // output-style persona can be swapped in/out at runtime via /output-style.
481
+ const _replBaseSystem = composeSystemPrompt(
482
+ buildSystemPrompt(process.cwd(), { additionalDirectories }),
339
483
  {
340
- role: "system",
341
- // --system-prompt replaces the built-in prompt; --append-system-prompt
342
- // extends it (parity with the headless runners).
343
- content: composeSystemPrompt(
344
- buildSystemPrompt(process.cwd(), { additionalDirectories }),
345
- {
346
- systemPrompt: options.systemPrompt,
347
- appendSystemPrompt: options.appendSystemPrompt,
348
- },
349
- ),
484
+ systemPrompt: options.systemPrompt,
485
+ appendSystemPrompt: options.appendSystemPrompt,
350
486
  },
351
- ];
487
+ );
488
+ let _activeOutputStyle = null; // { name, body }
489
+ const messages = [{ role: "system", content: _replBaseSystem }];
490
+ // Apply --output-style or the settings.json `outputStyle` default at startup.
491
+ try {
492
+ const { resolveOutputStyle } = await import("../lib/output-styles.js");
493
+ const st = resolveOutputStyle(options.outputStyle, process.cwd());
494
+ if (st && st.body) {
495
+ _activeOutputStyle = { name: st.name, body: st.body };
496
+ messages[0].content = `${_replBaseSystem}\n\n${st.body}`;
497
+ } else if (st && st.name && !st.missing) {
498
+ _activeOutputStyle = { name: st.name, body: "" };
499
+ }
500
+ } catch (_err) {
501
+ // best-effort — no output style
502
+ }
503
+
504
+ // settings.json SessionStart hooks → inject session context (observe-only).
505
+ if (_settingsHooks) {
506
+ try {
507
+ const { runSessionStartHooks } = await import(
508
+ "../lib/settings-hook-events.cjs"
509
+ );
510
+ const ctx = runSessionStartHooks(_settingsHooks, {
511
+ source: "startup",
512
+ cwd: process.cwd(),
513
+ }).additionalContext;
514
+ if (ctx) messages.push({ role: "system", content: ctx });
515
+ } catch (_err) {
516
+ // best-effort
517
+ }
518
+ }
352
519
 
353
520
  // Deep Agents Deploy Phase 1 — load agent bundle if --bundle provided.
354
521
  // Injects AGENTS.md as system prompt, seeds USER.md into MemoryStore,
@@ -451,22 +618,35 @@ export async function startAgentRepl(options = {}) {
451
618
  }
452
619
  }
453
620
 
454
- // --mcp-config: connect ad-hoc MCP servers for this interactive session and
455
- // expose their tools to the LLM (Claude-Code parity with headless). Reuses the
456
- // shared engine, so tools surface as mcp__<server>__<tool>. Best-effort: a bad
457
- // config is reported but never aborts the REPL.
458
- if (options.mcpConfig) {
621
+ // MCP for this interactive session: the ad-hoc --mcp-config file PLUS the
622
+ // servers registered with `cc mcp add --auto-connect`, combined into one
623
+ // client so their tools surface to the LLM as mcp__<server>__<tool>. Reuses
624
+ // the shared engine. Best-effort: a bad --mcp-config is reported but never
625
+ // aborts the REPL; --no-mcp skips the registered set.
626
+ {
459
627
  try {
460
- _adhocMcp = await loadMcpConfig(options.mcpConfig, {
461
- writeErr: (s) => process.stderr.write(s),
462
- });
463
- const toolCount = _adhocMcp.extraToolDefinitions.length;
464
- logger.log(
465
- chalk.gray(
466
- `MCP: ${_adhocMcp.connected.length} server(s), ${toolCount} tool(s) ` +
467
- `(mcp__<server>__<tool>)`,
468
- ),
628
+ _adhocMcp = await resolveAgentMcp(
629
+ {
630
+ mcpConfigPath: options.mcpConfig || null,
631
+ db: db?.getDatabase?.() || null,
632
+ includeRegistered: options.useRegisteredMcp !== false,
633
+ // IDE bridge: auto-connect a running editor's MCP server when inside
634
+ // an IDE integrated terminal. --ide forces it, --no-ide disables it
635
+ // (parity with headless; auto-detect already works via process.env).
636
+ ide: options.ide,
637
+ cwd: process.cwd(),
638
+ },
639
+ { writeErr: (s) => process.stderr.write(s) },
469
640
  );
641
+ if (_adhocMcp) {
642
+ const toolCount = _adhocMcp.extraToolDefinitions.length;
643
+ logger.log(
644
+ chalk.gray(
645
+ `MCP: ${_adhocMcp.connected.length} server(s), ${toolCount} tool(s) ` +
646
+ `(mcp__<server>__<tool>)`,
647
+ ),
648
+ );
649
+ }
470
650
  } catch (mcpErr) {
471
651
  logger.log(chalk.yellow(`MCP: --mcp-config failed — ${mcpErr.message}`));
472
652
  _adhocMcp = null;
@@ -575,7 +755,58 @@ export async function startAgentRepl(options = {}) {
575
755
  );
576
756
  logger.log(chalk.gray("Type /exit to quit, /help for commands\n"));
577
757
 
758
+ // statusLine (Claude-Code parity): a line above the prompt each turn.
759
+ // - A user-configured `.claude/settings.json` `statusLine` command wins
760
+ // (model / branch / cost / … — first stdout line; best-effort, sync).
761
+ // - Otherwise a BUILT-IN context-usage line is shown: model · ⛁ used/window
762
+ // (pct%) · cwd · turn N — the "上下文用量显示" half. Default-on.
763
+ // - Suppressed entirely by `statusLine: false`, env CC_STATUSLINE=0, or
764
+ // `/statusline off`. Token usage is fed in from each turn's usage events.
765
+ let _statusLineEnabled = process.env.CC_STATUSLINE !== "0";
766
+ let _customStatus = false; // true when a settings.json command is configured
767
+ let _curModel = model; // tracks the per-turn active model for the readout
768
+ let _ctxUsedTokens = 0;
769
+ let _turnCount = 0;
770
+ let _renderStatus = null;
771
+ try {
772
+ const slm = await import("../lib/status-line.cjs");
773
+ const _sl = slm.default || slm;
774
+ const _slCfg = _sl.loadStatusLineConfig({ cwd: process.cwd() });
775
+ _customStatus = !!_slCfg;
776
+ const _slDisabled = _sl.isStatusLineDisabled({ cwd: process.cwd() });
777
+ if (_slDisabled) _statusLineEnabled = false;
778
+ _renderStatus = () => {
779
+ if (!_statusLineEnabled) return null;
780
+ try {
781
+ const context = _sl.buildContext({
782
+ sessionId,
783
+ model: _curModel,
784
+ provider,
785
+ cwd: process.cwd(),
786
+ usedTokens: _ctxUsedTokens,
787
+ contextWindow: getContextWindow(_curModel, provider),
788
+ turn: _turnCount,
789
+ });
790
+ // Custom command wins; otherwise the built-in context-usage render.
791
+ if (_slCfg) {
792
+ return _sl.renderStatusLine(_slCfg, context, { cwd: process.cwd() });
793
+ }
794
+ const line = _sl.renderDefaultStatusLine(context);
795
+ return line && line.trim() ? line : null;
796
+ } catch {
797
+ return null; // never let the status line break the REPL
798
+ }
799
+ };
800
+ } catch {
801
+ _renderStatus = null;
802
+ }
803
+
578
804
  const prompt = () => {
805
+ if (_statusLineEnabled && _renderStatus) {
806
+ const line = _renderStatus();
807
+ // Built-in line is dimmed; a custom command may carry its own ANSI.
808
+ if (line) process.stdout.write((_customStatus ? line : chalk.dim(line)) + "\n");
809
+ }
579
810
  rl.setPrompt(getPrompt());
580
811
  rl.prompt();
581
812
  };
@@ -612,6 +843,9 @@ export async function startAgentRepl(options = {}) {
612
843
  );
613
844
  logger.log(` ${chalk.cyan("/provider")} Show/change provider`);
614
845
  logger.log(` ${chalk.cyan("/clear")} Clear conversation`);
846
+ logger.log(
847
+ ` ${chalk.cyan("/statusline")} Context-usage line on/off (/statusline [on|off])`,
848
+ );
615
849
  logger.log(
616
850
  ` ${chalk.cyan("/compact")} Smart compact (importance-based)`,
617
851
  );
@@ -658,6 +892,29 @@ export async function startAgentRepl(options = {}) {
658
892
  logger.log(
659
893
  " Context engineering: instinct + memory + notes injection\n",
660
894
  );
895
+ // User-defined command macros (.claude/commands/*.md) become runnable
896
+ // slash commands here — list whatever is discovered so they're visible.
897
+ try {
898
+ const { discoverCommands } = await import("../lib/slash-commands.js");
899
+ const macros = discoverCommands(process.cwd());
900
+ if (macros.length > 0) {
901
+ logger.log(chalk.bold("Custom commands (.claude/commands):"));
902
+ for (const m of macros) {
903
+ const tag =
904
+ m.scope === "project"
905
+ ? chalk.cyan("[proj]")
906
+ : chalk.gray("[pers]");
907
+ logger.log(
908
+ ` ${chalk.cyan("/" + m.name)} ${tag}` +
909
+ (m.argumentHint ? chalk.dim(` ${m.argumentHint}`) : "") +
910
+ (m.description ? ` ${chalk.gray(m.description)}` : ""),
911
+ );
912
+ }
913
+ logger.log("");
914
+ }
915
+ } catch (_err) {
916
+ // Non-critical — macro discovery failure must not break /help
917
+ }
661
918
  prompt();
662
919
  return;
663
920
  }
@@ -708,6 +965,7 @@ export async function startAgentRepl(options = {}) {
708
965
  const arg = trimmed.slice(6).trim();
709
966
  if (arg) {
710
967
  model = arg;
968
+ _curModel = model; // keep the status-line readout in sync
711
969
  logger.info(`Model: ${chalk.cyan(model)}`);
712
970
  } else {
713
971
  logger.info(`Current model: ${chalk.cyan(model)}`);
@@ -756,6 +1014,76 @@ export async function startAgentRepl(options = {}) {
756
1014
  return;
757
1015
  }
758
1016
 
1017
+ if (trimmed === "/statusline" || trimmed.startsWith("/statusline ")) {
1018
+ const arg = trimmed.slice("/statusline".length).trim().toLowerCase();
1019
+ if (arg === "off") {
1020
+ _statusLineEnabled = false;
1021
+ logger.info("Status line: off");
1022
+ } else if (arg === "on") {
1023
+ _statusLineEnabled = true;
1024
+ logger.info("Status line: on");
1025
+ } else {
1026
+ // bare / "show" → report state + a one-off render
1027
+ const line = _statusLineEnabled && _renderStatus ? _renderStatus() : null;
1028
+ if (line) {
1029
+ logger.info(
1030
+ `Status line: ${_customStatus ? line : chalk.dim(line)}`,
1031
+ );
1032
+ } else {
1033
+ logger.info(
1034
+ `Status line: ${_statusLineEnabled ? "on (no content yet)" : "off"}` +
1035
+ (_statusLineEnabled ? "" : ` — enable with ${chalk.cyan("/statusline on")}`),
1036
+ );
1037
+ }
1038
+ if (_customStatus) {
1039
+ logger.info(chalk.gray(" source: settings.json statusLine command"));
1040
+ }
1041
+ }
1042
+ prompt();
1043
+ return;
1044
+ }
1045
+
1046
+ if (trimmed === "/output-style" || trimmed.startsWith("/output-style ")) {
1047
+ const arg = trimmed.slice("/output-style".length).trim();
1048
+ try {
1049
+ const { discoverOutputStyles, getOutputStyle } = await import(
1050
+ "../lib/output-styles.js"
1051
+ );
1052
+ if (!arg) {
1053
+ logger.log(chalk.bold("Output styles:"));
1054
+ for (const s of discoverOutputStyles(process.cwd())) {
1055
+ const cur =
1056
+ _activeOutputStyle?.name === s.name ? chalk.green(" *") : "";
1057
+ logger.log(
1058
+ ` ${s.name.padEnd(16)}${cur} ${chalk.gray(s.description || "")}`,
1059
+ );
1060
+ }
1061
+ logger.log(
1062
+ chalk.gray(`current: ${_activeOutputStyle?.name || "none"}`),
1063
+ );
1064
+ } else if (arg === "none" || arg === "default") {
1065
+ _activeOutputStyle = null;
1066
+ messages[0].content = _replBaseSystem;
1067
+ logger.info("output style cleared");
1068
+ } else {
1069
+ const s = getOutputStyle(arg, process.cwd());
1070
+ if (!s) {
1071
+ logger.error(chalk.red(`no such output style: ${arg}`));
1072
+ } else {
1073
+ _activeOutputStyle = { name: s.name, body: s.body || "" };
1074
+ messages[0].content = s.body
1075
+ ? `${_replBaseSystem}\n\n${s.body}`
1076
+ : _replBaseSystem;
1077
+ logger.info(chalk.green(`output style → ${s.name}`));
1078
+ }
1079
+ }
1080
+ } catch (err) {
1081
+ logger.error(chalk.red(`/output-style failed: ${err.message}`));
1082
+ }
1083
+ prompt();
1084
+ return;
1085
+ }
1086
+
759
1087
  if (trimmed === "/compact") {
760
1088
  if (_compressor && messages.length > 3) {
761
1089
  const { messages: compacted, stats } = await _compressor.compress(
@@ -1473,10 +1801,28 @@ export async function startAgentRepl(options = {}) {
1473
1801
  return;
1474
1802
  }
1475
1803
 
1804
+ // User-defined slash-command macros (.claude/commands/*.md), Claude-Code
1805
+ // parity. resolveSlashMacro maps a leading /name to a command macro and
1806
+ // expands its template; a non-match returns the line unchanged so a literal
1807
+ // prompt like "/etc/hosts" still reaches the LLM. Wire is unit-tested.
1808
+ let promptText = trimmed;
1809
+ try {
1810
+ const macro = await resolveSlashMacro(trimmed, { cwd: process.cwd() });
1811
+ if (macro.matched) {
1812
+ for (const w of macro.warnings) logger.info(chalk.yellow(`[@ref] ${w}`));
1813
+ promptText = macro.promptText;
1814
+ logger.log(
1815
+ chalk.gray(`[/${macro.name}] macro expanded (${macro.scope})`),
1816
+ );
1817
+ }
1818
+ } catch (err) {
1819
+ logger.verbose(`[slash-macro] expansion skipped: ${err.message}`);
1820
+ }
1821
+
1476
1822
  // Fire UserPromptSubmit hook with rewrite/abort support.
1477
1823
  // Hooks may emit {"rewrittenPrompt": "..."} or {"abort": true, "reason": "..."}
1478
1824
  // via stdout JSON. Failures fall through to the original prompt.
1479
- const promptDirective = await fireUserPromptSubmit(_hookDb, trimmed, {
1825
+ const promptDirective = await fireUserPromptSubmit(_hookDb, promptText, {
1480
1826
  sessionId,
1481
1827
  messageCount: messages.length,
1482
1828
  });
@@ -1490,7 +1836,7 @@ export async function startAgentRepl(options = {}) {
1490
1836
  return;
1491
1837
  }
1492
1838
  const effectivePrompt = promptDirective.prompt;
1493
- if (effectivePrompt !== trimmed) {
1839
+ if (effectivePrompt !== promptText) {
1494
1840
  logger.verbose(`[hook] prompt rewritten by UserPromptSubmit hook`);
1495
1841
  }
1496
1842
 
@@ -1514,13 +1860,42 @@ export async function startAgentRepl(options = {}) {
1514
1860
  logger.verbose(`[@ref] expansion skipped: ${err.message}`);
1515
1861
  }
1516
1862
 
1863
+ // settings.json UserPromptSubmit hooks (decision-capable; the DB hook above
1864
+ // is observe-only). block → abort the turn; context → inject before the turn.
1865
+ if (_settingsHooks) {
1866
+ try {
1867
+ const { runUserPromptSubmitHooks } = await import(
1868
+ "../lib/settings-hook-events.cjs"
1869
+ );
1870
+ const ups = runUserPromptSubmitHooks(_settingsHooks, {
1871
+ prompt: userContent,
1872
+ cwd: process.cwd(),
1873
+ sessionId,
1874
+ });
1875
+ if (ups.blocked) {
1876
+ logger.info(
1877
+ chalk.yellow(
1878
+ `[hook] prompt blocked${ups.reason ? ": " + ups.reason : ""}`,
1879
+ ),
1880
+ );
1881
+ prompt();
1882
+ return;
1883
+ }
1884
+ if (ups.additionalContext) {
1885
+ userContent += `\n\n[hook context]\n${ups.additionalContext}`;
1886
+ }
1887
+ } catch (_err) {
1888
+ // settings hook dispatch is best-effort
1889
+ }
1890
+ }
1891
+
1517
1892
  // Add user message
1518
1893
  messages.push({ role: "user", content: userContent });
1519
1894
 
1520
1895
  // Slot-filling: detect intent and fill missing parameters interactively
1521
1896
  try {
1522
1897
  const { CLISlotFiller } = await import("../lib/slot-filler.js");
1523
- const intent = CLISlotFiller.detectIntent(trimmed);
1898
+ const intent = CLISlotFiller.detectIntent(promptText);
1524
1899
  if (intent) {
1525
1900
  const defs = CLISlotFiller.getSlotDefinitions(intent.type);
1526
1901
  const missing = defs.required.filter((s) => !intent.entities[s]);
@@ -1549,7 +1924,7 @@ export async function startAgentRepl(options = {}) {
1549
1924
 
1550
1925
  // Auto-select best model based on task type
1551
1926
  let activeModel = model;
1552
- const taskDetection = detectTaskType(trimmed);
1927
+ const taskDetection = detectTaskType(promptText);
1553
1928
  if (taskDetection.confidence > 0.3) {
1554
1929
  const recommended = selectModelForTask(provider, taskDetection.taskType);
1555
1930
  if (recommended && recommended !== activeModel) {
@@ -1583,6 +1958,8 @@ export async function startAgentRepl(options = {}) {
1583
1958
  const { content: response, usageEvents } = await agentLoop(messages, {
1584
1959
  provider,
1585
1960
  model: activeModel,
1961
+ thinking,
1962
+ thinkingBudget,
1586
1963
  baseUrl,
1587
1964
  apiKey,
1588
1965
  contextEngine,
@@ -1594,6 +1971,9 @@ export async function startAgentRepl(options = {}) {
1594
1971
  checkpointSession: sessionId,
1595
1972
  prepareCall,
1596
1973
  approvalGate: _approvalGate,
1974
+ permissionRules: _permissionRules,
1975
+ permissionConfirm: _permissionConfirm,
1976
+ settingsHooks: _settingsHooks,
1597
1977
  // MCP: --mcp-config (ad-hoc) wins; bundle MCP is the fallback. The 3
1598
1978
  // tool channels expose --mcp-config servers' tools to the LLM directly.
1599
1979
  mcpClient: _adhocMcp?.mcpClient || _bundleMcpClient || undefined,
@@ -1617,6 +1997,17 @@ export async function startAgentRepl(options = {}) {
1617
1997
  }
1618
1998
  }
1619
1999
 
2000
+ // Feed the status line: the last usage event's input+output ≈ the tokens
2001
+ // now resident in the context window (what the next call resends). Track
2002
+ // the active model too, so the built-in readout reflects auto-switches.
2003
+ _curModel = activeModel;
2004
+ _turnCount += 1;
2005
+ if (usageEvents?.length) {
2006
+ const last = usageEvents[usageEvents.length - 1]?.usage || {};
2007
+ const used = (last.input_tokens || 0) + (last.output_tokens || 0);
2008
+ if (used > 0) _ctxUsedTokens = used;
2009
+ }
2010
+
1620
2011
  // Fire AssistantResponse hook with rewrite/suppress support
1621
2012
  const responseDirective = await fireAssistantResponse(
1622
2013
  _hookDb,
@@ -1710,7 +2101,7 @@ export async function startAgentRepl(options = {}) {
1710
2101
  // Store as episodic memory
1711
2102
  if (db) {
1712
2103
  try {
1713
- storeMemory(db, trimmed, { importance: 0.3, type: "episodic" });
2104
+ storeMemory(db, promptText, { importance: 0.3, type: "episodic" });
1714
2105
  } catch (_e) {
1715
2106
  // Non-critical
1716
2107
  }
@@ -1742,6 +2133,22 @@ export async function startAgentRepl(options = {}) {
1742
2133
  });
1743
2134
 
1744
2135
  rl.on("close", async () => {
2136
+ // settings.json SessionEnd hooks (observe-only) when the REPL exits.
2137
+ if (_settingsHooks) {
2138
+ try {
2139
+ const { runObserveHooks } = await import(
2140
+ "../lib/settings-hook-events.cjs"
2141
+ );
2142
+ runObserveHooks(
2143
+ _settingsHooks,
2144
+ "SessionEnd",
2145
+ { reason: "exit", cwd: process.cwd(), session_id: sessionId },
2146
+ { cwd: process.cwd() },
2147
+ );
2148
+ } catch (_err) {
2149
+ // observe-only
2150
+ }
2151
+ }
1745
2152
  // Save session on exit
1746
2153
  if (sessionId) {
1747
2154
  try {
@@ -1819,6 +2226,14 @@ export async function startAgentRepl(options = {}) {
1819
2226
  }
1820
2227
  }
1821
2228
 
2229
+ // Kill any background run_shell tasks so a backgrounded command (e.g. a
2230
+ // dev server) doesn't outlive the REPL session.
2231
+ try {
2232
+ killAllBackgroundShellTasks();
2233
+ } catch (_e) {
2234
+ // Non-critical
2235
+ }
2236
+
1822
2237
  // Shutdown runtime
1823
2238
  try {
1824
2239
  await shutdown();