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.
- package/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-CJn02U42.js → AIOps-_oxz4VHy.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-ewURAAoy.js → ActionButton-uaeqFuDj.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BiSadESb.js → Analytics-BPVV0OUf.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BR0WOEug.js → AppLayout-ppCYKm3I.js} +4 -4
- package/src/assets/web-panel/assets/{Audit-CrqcYx0e.js → Audit-DFAY6umk.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DtbSBn4e.js → Backup-pAPBFDyP.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BjSc9j0o.js → BaseInput-BbBl0uT2.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-ixzrlCJE.js → Chat-Ct22JUnT.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-B78nEq05.js → ChatBubbleRenderer-DPlsLl22.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-UGYeSsgr.js → Checkbox-DEkCollc.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B97OOAg4.js → Codegen-Tor-de39.js} +1 -1
- package/src/assets/web-panel/assets/{Col-D9aGkaZ6.js → Col-ojNrLQU7.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Dc2v2RGS.js → Community-CLOGhqMF.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-B_FYlUQR.js → Compact-CYKNlSZ4.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-C4FiTHyC.js → Compliance-C5E6ABuA.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CQ8j3LIg.js → Cowork-CHeEsZ3W.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-Dzjs9Z9Z.js → Cron-B4e1n2e7.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BXI24uzI.js → Crosschain-DbNV8P9R.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C-I4_d07.js → DID-C5_Tk3nC.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-BzzGh5mo.js → Dashboard-BhdV_c4N.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Bh8H70De.js → Dropdown-CEi5AMtM.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DI_qybJP.js → EmailListRenderer-DOhPiYng.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DkKTsfc4.js → FamilyGuardDashboard-fu4NRP3X.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DS7CmvVG.js → Federation-B7BtIWKL.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CI97WsB5.js → FormItemContext-BmPWZVLP.js} +1 -1
- package/src/assets/web-panel/assets/GenericCardRenderer-hsOPNJq8.js +1 -0
- package/src/assets/web-panel/assets/{Git-CEh0gR2W.js → Git-Bi_EFBUH.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-kIr3tls2.js → Governance-emf2ubDK.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CC1GzyC1.js → Inference-B7KjKzkI.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BNgTiWOB.js → KnowledgeGraph-uAaBK0F3.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B2P10gB1.js → Logs-utK7hNpj.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-HPfBvbFZ.js → Marketplace-CzQe6n3z.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-ByYotSKb.js → McpTools-CuAaJr51.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BGIAzFVS.js → Memory-CRuZZJ75.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CroNYTAH.js → MobileBridge-Cp06wunh.js} +2 -2
- package/src/assets/web-panel/assets/MobileProjects-DJEdUwhr.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-BqhyIwo9.js → Mtc-8YY4dR7g.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BpEKOvx9.js → MtcAudit-BmPJYHar.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DST1d_Qo.js → Multisig-d-ydyVdq.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DlMsZcK_.js → NLProgramming-DA_ikw_n.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-C734UJvD.js → Notes-DIyF-fRe.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-C0-pPxvk.js → NotificationSettings-CzPZXEtK.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BiLtg-LY.js +1 -0
- package/src/assets/web-panel/assets/{Organization-C5iHC_yW.js → Organization-DdDZ_Ap6.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CovuHHVR.js → Overflow-BnMBkttv.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Dx9QL-Gy.js → P2P-Es1050f-.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-IP1dEt6-.js → PdhVaultBrowser-CKkRmyn9.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-BrR1XZG5.js → Permissions-zU9n9cAD.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BgqxVE5m.js → PersonalDataHub-BZi5Xwas.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-DzMk5HAz.js → Pipeline-CRfeGiFc.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CDoLa6tk.js → Privacy-CQA_IgLA.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Dy5gc6ve.js → ProjectInit-C9hmEvoT.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DXy-k4hG.js → ProjectSettings-yXA72ws4.js} +2 -2
- package/src/assets/web-panel/assets/Projects-BpWS-qam.js +1 -0
- package/src/assets/web-panel/assets/Providers-Cxe55dRD.js +1 -0
- package/src/assets/web-panel/assets/{QuickAsk-B8KEHCnd.js → QuickAsk-Do0aUTQr.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DNVHGYYZ.js → Recommend--ysZHjyA.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-CaDhWP03.js → Reputation-BOBU8JrH.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CrGLI02x.js → Row-C6X7bRKE.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BX7P8I6i.js → RssFeed-D8AwqlkQ.js} +3 -3
- package/src/assets/web-panel/assets/Search-Bi3rCZD4.js +1 -0
- package/src/assets/web-panel/assets/{Security-B6J7IFc1.js → Security-DxUDVrtY.js} +4 -4
- package/src/assets/web-panel/assets/{Services-vvdcO3mM.js → Services-BXXN7yC1.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BoAoPTzZ.js → Skeleton-B3BR34tZ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CyIQV5b3.js → Skills-BjYu8OQ1.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BAQVgdZV.js → Sla-DDkCtD8w.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Bxcn1Jkj.js → SpeechSettings-CGhYzP7V.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Dpaj3hDM.js → SyncSettings-CYNKVAHA.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Bwqo89En.js → Tasks-DavmlJpd.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Bowcqifn.js → Templates-CQuYFf2C.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DOkf85uG.js → Tenant-DdzZh8vE.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-D75WeG9d.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-B9A3zDXA.js → TimelineRenderer-DKOARnc_.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-jtVVqKFr.js → Tokens-D7QRNG8y.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-26Iw-iIl.js → Trigger-BCsqLZl4.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DqY5ORrH.js → Trust-BarGUa6p.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BFsbr3y7.js → UkeySign-pHrg5a8E.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BtDbj3oa.js → VideoEditing-Dug3m1py.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BAwmwHbk.js → Wallet-BfK3Z_Ez.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DINJTsfq.js → WebAuthn-CYRdl9td.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-BEorm8SK.js → WorkflowEditor-DTW5AcqM.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CE39-Dxg.js → chat-CCXz4j38.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C_cLZ93a.js → colors-BJBOhAqa.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BSioWA2c.js → compact-item-E9M6BQcM.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CGTk4mhN.js → createContext-Cg9CAws4.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BrsbTJUv.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Dl1fRwS_.js → hasIn-DhVtqv5L.js} +1 -1
- package/src/assets/web-panel/assets/{index-pngH1and.js → index--7o5YdL6.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmbVyhk1.js → index-4N5lNXGP.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnEPB1Mz.js → index-6-04M2Nx.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cxw3p73X.js → index-B111fZ21.js} +1 -1
- package/src/assets/web-panel/assets/{index-CST381Qf.js → index-B4NBF4Sa.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChwpS1f0.js → index-B8bjEHrQ.js} +1 -1
- package/src/assets/web-panel/assets/{index--SWvw6yW.js → index-BAB0nGP7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAwVwBOL.js → index-BFZPRd0T.js} +1 -1
- package/src/assets/web-panel/assets/{index-hv4jUdG3.js → index-B_SMPD4L.js} +1 -1
- package/src/assets/web-panel/assets/{index-Qj2x55mz.js → index-BxSzyly9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWpfxzVm.js → index-ByazO4Q9.js} +1 -1
- package/src/assets/web-panel/assets/{index-Di6nvW1N.js → index-C-2dUIli.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhqOTuMW.js → index-CFarAlXj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CA6K7lZB.js → index-CFp-wdrQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTKEXyaW.js → index-CJ8nNT8h.js} +1 -1
- package/src/assets/web-panel/assets/{index-iiZfONfx.js → index-CSiyjCYi.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTpCUi0m.js → index-CUp_c8Le.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bvi14vJ7.js → index-CVR_s-pT.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKEipmR8.js → index-Ca8BYV1g.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJyeeygd.js → index-CeRlLp3F.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9tq8Da8.js → index-ChsSljaN.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2QiUEgK.js → index-CkTeBHI9.js} +1 -1
- package/src/assets/web-panel/assets/{index-OCxo0X6J.js → index-Cm1m7BJh.js} +1 -1
- package/src/assets/web-panel/assets/{index-DrWERr8C.js → index-ComyTKz-.js} +1 -1
- package/src/assets/web-panel/assets/{index-B016Fsqr.js → index-CznfPnOx.js} +3 -3
- package/src/assets/web-panel/assets/{index-CisXVbSt.js → index-D5yC2Ps8.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-VVk1Jg.js → index-D7DXdf7x.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDQx2YFc.js → index-DDcJO27F.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ds2RzRG0.js → index-DSQazU6J.js} +1 -1
- package/src/assets/web-panel/assets/index-DSTQDO-Y.js +1 -0
- package/src/assets/web-panel/assets/{index-C4JXchTG.js → index-DaFe1aqY.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAhinBPR.js → index-DdhnGez0.js} +1 -1
- package/src/assets/web-panel/assets/{index-9_mmaR42.js → index-Di5LBXcE.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9D4q-qI.js → index-Dwvewrul.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbXnyoSO.js → index-MdXEhfdJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-II3JhQu2.js → index-_PNqQ5mE.js} +1 -1
- package/src/assets/web-panel/assets/index-c2U6LV3Q.js +1 -0
- package/src/assets/web-panel/assets/{index-C2ly7sCw.js → index-kz1oXl1a.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ceo9P9tQ.js → index-wkt-o5q5.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-GOhLA2-f.js → initDefaultProps-iyBaePF-.js} +1 -1
- package/src/assets/web-panel/assets/{motion-jqxFzHTx.js → motion-RWtj4rgu.js} +1 -1
- package/src/assets/web-panel/assets/{move-CSLsp6TA.js → move-CqPRVzpH.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Cnlrb25c.js → omit-DsvJze25.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CLqlxWWD.js → pickAttrs-B4tfZBhc.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BAWIWtul.js → placementArrow-KvHUwXMA.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CSR1DayS.js → responsiveObserve-DGdJ-b7W.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CNhoPJOp.js → slide-Cd6ebRmw.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BZiYHRHW.js → statusUtils-Bg9GcIAn.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BMoY-Fm5.js → styleChecker-MQjKsG84.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DhtNdlaS.js → useFlexGapSupport-C241WujP.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DNPtDOZ4.js → useFs-CMpy7RS4.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DTdjNvAI.js → usePersonalDataHub-BLHtapKb.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C9zW9IJ2.js → vnode-DmcTV67c.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-D-6RYJJr.js → zoom-DHL8_0Y8.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +161 -6
- package/src/commands/agents.js +8 -2
- package/src/commands/cli-anything.js +14 -6
- package/src/commands/command.js +7 -2
- package/src/commands/hook.js +136 -28
- package/src/commands/ide.js +168 -0
- package/src/commands/loop.js +450 -0
- package/src/commands/mcp.js +92 -0
- package/src/commands/output-style.js +127 -0
- package/src/commands/permissions.js +211 -0
- package/src/commands/statusline.js +93 -0
- package/src/index.js +10 -2
- package/src/lib/agent-core.js +7 -0
- package/src/lib/agents.js +5 -0
- package/src/lib/hook-manager.js +1 -0
- package/src/lib/hook-runner.cjs +183 -0
- package/src/lib/ide-bridge.js +310 -0
- package/src/lib/image-input.js +156 -0
- package/src/lib/loop.js +198 -0
- package/src/lib/mcp-oauth.js +415 -0
- package/src/lib/output-styles.js +179 -0
- package/src/lib/permission-rules.cjs +325 -0
- package/src/lib/provider-options.js +11 -7
- package/src/lib/settings-hook-events.cjs +102 -0
- package/src/lib/settings-hooks.cjs +163 -0
- package/src/lib/settings-loader.cjs +244 -0
- package/src/lib/slash-commands.js +4 -0
- package/src/lib/status-line.cjs +204 -0
- package/src/lib/sub-agent-profiles.js +3 -0
- package/src/lib/web-search.js +487 -0
- package/src/repl/agent-repl.js +450 -35
- package/src/repl/slash-macro.js +45 -0
- package/src/runtime/agent-core.js +799 -21
- package/src/runtime/coding-agent-contract-shared.cjs +94 -4
- package/src/runtime/coding-agent-policy.cjs +24 -0
- package/src/runtime/headless-runner.js +162 -6
- package/src/runtime/headless-stream.js +133 -7
- package/src/runtime/mcp-config.js +161 -15
- package/src/runtime/policies/agent-policy.js +4 -0
- package/src/runtime/system-prompt.js +6 -1
- package/src/assets/web-panel/assets/GenericCardRenderer-Da27EdR4.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-CH-qnGEV.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-C7zT9eFc.js +0 -1
- package/src/assets/web-panel/assets/Projects-DvsaEbZR.js +0 -1
- package/src/assets/web-panel/assets/Providers-Demck9PO.js +0 -1
- package/src/assets/web-panel/assets/Search-laS6rz8M.js +0 -1
- package/src/assets/web-panel/assets/Terminal-v4MM9dCj.js +0 -3
- package/src/assets/web-panel/assets/devWarning-PObcVnJR.js +0 -1
- package/src/assets/web-panel/assets/index-BNwIzLyX.js +0 -1
- package/src/assets/web-panel/assets/index-Dh6FxR9B.js +0 -1
package/src/repl/agent-repl.js
CHANGED
|
@@ -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 {
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
341
|
-
|
|
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
|
-
//
|
|
455
|
-
//
|
|
456
|
-
//
|
|
457
|
-
// config is reported but never
|
|
458
|
-
|
|
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
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
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,
|
|
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 !==
|
|
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(
|
|
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(
|
|
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,
|
|
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();
|