chainlesschain 0.162.34 → 0.162.36
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-BYfi9NYS.js → AIOps-vAVAFNJ4.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BiS_tAN7.js → ActionButton-BnRHFCKM.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-jiWl_p-B.js → Analytics-BOjwqWqG.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-m4sIzDot.js → AppLayout-Dc0D1Txn.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-CPla3Erm.js → Audit-dd_2efaZ.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BGeQzTaB.js → Backup-HF1jgm8G.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DTf7Z1iU.js → BaseInput-CCtzmoKe.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DPTlQlD-.js → Chat-BNfH1c3p.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BgRXce4e.js → ChatBubbleRenderer-DCWFqmI4.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DY-XuQMu.js → Checkbox-BOr-NscK.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B6oxPiZI.js → Codegen-DE058N7-.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Dqxb4wSE.js → Col-SOREo1XE.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DCIX514p.js → Community-sOvNZo9f.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BGtCzDoJ.js → Compact-DnBe558D.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-zcOYd55o.js → Compliance-o-r6CUbg.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DVTtdIdM.js → Cowork-D6_k9mHP.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-CPUaR69k.js → Cron-CEV3Xkrm.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DnjUS6QH.js → Crosschain-eJ1lQWKU.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Dnz8VDmx.js → DID-B-WqM9Hp.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CtWf27j7.js → Dashboard-ZnKPcsHN.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-B4GC1ZV4.js → Dropdown-B8uLWDIP.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-wjij3kzr.js → EmailListRenderer-Jmj2Y7aH.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-rS-2W4u5.js → FamilyGuardDashboard-Cb2xetG-.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-90p5Tnoz.js → Federation-C_07GXoq.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cnrw7gzq.js → FormItemContext-D3kbYrMU.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-C85NsWa3.js → GenericCardRenderer-9xgqvGPg.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BFAVM9F8.js → Git-BlwWlMMB.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DBoRonpq.js → Governance-DxN3wQZ_.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DHRyD66j.js → Inference-ls7pSw_D.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CTvUKecD.js → KnowledgeGraph-_n9hYuPI.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CB0dv_Ts.js → Logs-CvEVY5TK.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-CN7Hm5Uw.js → Marketplace-C3qvQJT7.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-q5H25_8L.js → McpTools-DiwKpnKx.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BCV3pZ1d.js → Memory-CIBPi_da.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-C04Mngt4.js → MobileBridge-D-v0Se8y.js} +2 -2
- package/src/assets/web-panel/assets/MobileProjects-cP1apTQD.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-ByAMz2DN.js → Mtc-BMFWrI65.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-B7V7byJq.js → MtcAudit-2s8LaHtR.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DtKmcVQV.js → Multisig-dL_nvj7d.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CaMbT5SC.js → NLProgramming-BbrJp06R.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DRjbSTCU.js → Notes-jR9irwy3.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-B9YbJID5.js → NotificationSettings-Dk-STCIX.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BcI_-vGS.js → OrderTableRenderer-CqqfY6zq.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-oTask4BE.js → Organization-BCK5jylo.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bab06ey7.js → Overflow-BRAY7Smt.js} +1 -1
- package/src/assets/web-panel/assets/{P2P--wlBeU0N.js → P2P-BltVRGjb.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-D4t77Pwc.js → PdhVaultBrowser-CV8UbXHe.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-B3sf6CJ3.js → Permissions-_tNl47Qh.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BXOojk63.js → PersonalDataHub-Cgc4HjpX.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-DReqtBFN.js → Pipeline-Bn_QU4mu.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-cT1GwKLx.js → Privacy-jzJowp5P.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BhTAzVhH.js → ProjectInit-B_1pJ8qd.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CK-D8Fyj.js → ProjectSettings-CPVZpXzs.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-CbHiwen6.js → Projects-CQsHOWnT.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-B-ftiXa8.js → Providers-CzzMiLC0.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CT5XPwTF.js → QuickAsk-MxBKIn9o.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CohhlBZ_.js → Recommend-D8lN6Lis.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-CrgbixFz.js → Reputation-CfYK-IrV.js} +1 -1
- package/src/assets/web-panel/assets/{Row-ClExmBn3.js → Row-Bg7NZDP9.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-VV0qizCJ.js → RssFeed-BOVNJhj0.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CqJapSiL.js → Search-B38qzmhY.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DY66Zie6.js → Security-CjqleZpe.js} +4 -4
- package/src/assets/web-panel/assets/{Services-RQwxat7-.js → Services-Bu9JSJap.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-0v37UTU_.js → Skeleton-B2RvRkaX.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-B4Vm4DxN.js → Skills-_h42mxMN.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CggphTlo.js → Sla-BssLs56D.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BAOU08C7.js → SpeechSettings-DCxFYHsd.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DmtC4J1w.js → SyncSettings-D2xQuNLE.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-DhpOGOlo.js +1 -0
- package/src/assets/web-panel/assets/{Templates-C1QK0YoU.js → Templates-CYG-R-aS.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CieOfmqp.js → Tenant-BQRYLsvP.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DWdhrxRq.js → Terminal-imKU7N5j.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CjFVUUDU.js → TimelineRenderer-BIZzBftk.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Bwbk3id9.js → Tokens-uMLH5p_a.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-uJle_yj4.js → Trigger-BzS6XPqx.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BcOuxAA5.js → Trust-R4zhHufZ.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DUu7Ufg6.js → UkeySign-DATQCoGe.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Ck8JtQ2n.js → VideoEditing-ClUmKOtS.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-B3jw43on.js → Wallet-DzJTbQzD.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-Baf9K0y7.js → WebAuthn-CrXrLmzQ.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-CTEDl_83.js → WorkflowEditor-CpvZ0Tma.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CKV51quV.js → chat-a6wpYmVL.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BO_RP_yz.js → colors-CXJADb1t.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BZsxw_ZG.js → compact-item-CL2pohS_.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CAbvtzVL.js → createContext-xFi_1G5_.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BtmELbtB.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-QmHT8zDz.js → hasIn-Bchh1rAi.js} +1 -1
- package/src/assets/web-panel/assets/{index-fnDgExTu.js → index-B3Tpv7-d.js} +1 -1
- package/src/assets/web-panel/assets/index-B4l4vLTB.js +1 -0
- package/src/assets/web-panel/assets/{index-BEJa1FiF.js → index-B4zNisy9.js} +1 -1
- package/src/assets/web-panel/assets/{index-jd2r-T4p.js → index-B6NehWty.js} +1 -1
- package/src/assets/web-panel/assets/index-B7Ek5iiY.js +1 -0
- package/src/assets/web-panel/assets/{index-BPZHeug4.js → index-B7knYOpm.js} +1 -1
- package/src/assets/web-panel/assets/{index-GPY0LjCu.js → index-B7wT5VRi.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKnngF_f.js → index-BF4xx1_b.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRNYA0BV.js → index-BH9t10pe.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKquNxL2.js → index-BPH5ESqs.js} +3 -3
- package/src/assets/web-panel/assets/{index-CEh2Ry_A.js → index-BmsIKzyu.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dob6B6qS.js → index-BoaRB-4a.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ha2_56mf.js → index-BrbJBnT-.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dln_vjSY.js → index-C2eMYASq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqiKnXtL.js → index-C4yBRKT4.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3fwyCjJ.js → index-CGq4HQno.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2aiE8jk.js → index-CMybtJY6.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5zhcul9.js → index-CR3kFPuC.js} +1 -1
- package/src/assets/web-panel/assets/{index-8BMLlHCv.js → index-CTRd7vkq.js} +1 -1
- package/src/assets/web-panel/assets/{index-C6i3reUS.js → index-CdU8BwRW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNvTNZ1V.js → index-Cua_P8St.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjrDGJP2.js → index-CuehgDOp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCsZiq4i.js → index-D-TT9Swq.js} +1 -1
- package/src/assets/web-panel/assets/{index-qPafbZmr.js → index-DEYcLAl7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeC7lehI.js → index-DQ_hw_5P.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnPBG3Tr.js → index-DTEu7TSF.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8CHQnPl.js → index-DVo1GJoj.js} +1 -1
- package/src/assets/web-panel/assets/{index-9IqJODII.js → index-DjdOL159.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBCYOypV.js → index-DsbMVBj1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BL7gQAuB.js → index-DxahxRP7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DC1CFfQU.js → index-EPERz4Pu.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVoYeZ5Q.js → index-IkvkNxbc.js} +1 -1
- package/src/assets/web-panel/assets/{index-CsBx0u5G.js → index-KCib1PTw.js} +1 -1
- package/src/assets/web-panel/assets/{index-5hlO2-JQ.js → index-M8SZI11a.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSaI8R_7.js → index-TxbHusq2.js} +1 -1
- package/src/assets/web-panel/assets/{index-C6AA-xB2.js → index-dsLc7t6W.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRK0oAV5.js → index-jMcv1u5o.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9Z83FTS.js → index-majCS3s2.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3K1eHDd.js → index-u8K1y_lh.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Bc2GWeWe.js → initDefaultProps-DYn3Gc09.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BI-Rxw6o.js → motion-ZS3eolb9.js} +1 -1
- package/src/assets/web-panel/assets/{move-DRPdwDQB.js → move-CEw4uqr3.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B4XTl3jW.js → omit-DlHFZnPp.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Do5d86Wr.js → pickAttrs-eZQvV5fA.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B8VGZ0ZF.js → placementArrow-B31jQwa-.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Cf0kI_vN.js → responsiveObserve-DAsNmVto.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Cb0psjSL.js → slide-gPQPrYZC.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Bjuo5Oal.js → statusUtils-DwWKX5co.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BLMhoHJ5.js → styleChecker-B3VOtXuH.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-BdCwAfNU.js → useFlexGapSupport-6ADctM2r.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-9Jhaz5gG.js → useFs-6Zx1SSKs.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-xYFyXKwD.js → usePersonalDataHub-BzReowln.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CVhepE6Z.js → vnode-C8IpEQbD.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-IbbtJ4Zr.js → zoom-ruc9vHr0.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +161 -6
- package/src/commands/agents.js +199 -0
- package/src/commands/command.js +7 -2
- package/src/commands/hook.js +136 -28
- package/src/commands/ide.js +168 -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 +8 -0
- package/src/lib/agent-core.js +7 -0
- package/src/lib/agents.js +147 -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/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 +21 -13
- 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 +445 -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 +1 -0
- package/src/runtime/system-prompt.js +6 -1
- package/src/assets/web-panel/assets/MobileProjects-CUxONYre.js +0 -1
- package/src/assets/web-panel/assets/Tasks-CExqxzL6.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DQYatsRR.js +0 -1
- package/src/assets/web-panel/assets/index-Bv_y1Ud7.js +0 -1
- package/src/assets/web-panel/assets/index-CZZnSJEX.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,30 @@ 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
|
-
`(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
|
+
},
|
|
634
|
+
{ writeErr: (s) => process.stderr.write(s) },
|
|
469
635
|
);
|
|
636
|
+
if (_adhocMcp) {
|
|
637
|
+
const toolCount = _adhocMcp.extraToolDefinitions.length;
|
|
638
|
+
logger.log(
|
|
639
|
+
chalk.gray(
|
|
640
|
+
`MCP: ${_adhocMcp.connected.length} server(s), ${toolCount} tool(s) ` +
|
|
641
|
+
`(mcp__<server>__<tool>)`,
|
|
642
|
+
),
|
|
643
|
+
);
|
|
644
|
+
}
|
|
470
645
|
} catch (mcpErr) {
|
|
471
646
|
logger.log(chalk.yellow(`MCP: --mcp-config failed — ${mcpErr.message}`));
|
|
472
647
|
_adhocMcp = null;
|
|
@@ -575,7 +750,58 @@ export async function startAgentRepl(options = {}) {
|
|
|
575
750
|
);
|
|
576
751
|
logger.log(chalk.gray("Type /exit to quit, /help for commands\n"));
|
|
577
752
|
|
|
753
|
+
// statusLine (Claude-Code parity): a line above the prompt each turn.
|
|
754
|
+
// - A user-configured `.claude/settings.json` `statusLine` command wins
|
|
755
|
+
// (model / branch / cost / … — first stdout line; best-effort, sync).
|
|
756
|
+
// - Otherwise a BUILT-IN context-usage line is shown: model · ⛁ used/window
|
|
757
|
+
// (pct%) · cwd · turn N — the "上下文用量显示" half. Default-on.
|
|
758
|
+
// - Suppressed entirely by `statusLine: false`, env CC_STATUSLINE=0, or
|
|
759
|
+
// `/statusline off`. Token usage is fed in from each turn's usage events.
|
|
760
|
+
let _statusLineEnabled = process.env.CC_STATUSLINE !== "0";
|
|
761
|
+
let _customStatus = false; // true when a settings.json command is configured
|
|
762
|
+
let _curModel = model; // tracks the per-turn active model for the readout
|
|
763
|
+
let _ctxUsedTokens = 0;
|
|
764
|
+
let _turnCount = 0;
|
|
765
|
+
let _renderStatus = null;
|
|
766
|
+
try {
|
|
767
|
+
const slm = await import("../lib/status-line.cjs");
|
|
768
|
+
const _sl = slm.default || slm;
|
|
769
|
+
const _slCfg = _sl.loadStatusLineConfig({ cwd: process.cwd() });
|
|
770
|
+
_customStatus = !!_slCfg;
|
|
771
|
+
const _slDisabled = _sl.isStatusLineDisabled({ cwd: process.cwd() });
|
|
772
|
+
if (_slDisabled) _statusLineEnabled = false;
|
|
773
|
+
_renderStatus = () => {
|
|
774
|
+
if (!_statusLineEnabled) return null;
|
|
775
|
+
try {
|
|
776
|
+
const context = _sl.buildContext({
|
|
777
|
+
sessionId,
|
|
778
|
+
model: _curModel,
|
|
779
|
+
provider,
|
|
780
|
+
cwd: process.cwd(),
|
|
781
|
+
usedTokens: _ctxUsedTokens,
|
|
782
|
+
contextWindow: getContextWindow(_curModel, provider),
|
|
783
|
+
turn: _turnCount,
|
|
784
|
+
});
|
|
785
|
+
// Custom command wins; otherwise the built-in context-usage render.
|
|
786
|
+
if (_slCfg) {
|
|
787
|
+
return _sl.renderStatusLine(_slCfg, context, { cwd: process.cwd() });
|
|
788
|
+
}
|
|
789
|
+
const line = _sl.renderDefaultStatusLine(context);
|
|
790
|
+
return line && line.trim() ? line : null;
|
|
791
|
+
} catch {
|
|
792
|
+
return null; // never let the status line break the REPL
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
} catch {
|
|
796
|
+
_renderStatus = null;
|
|
797
|
+
}
|
|
798
|
+
|
|
578
799
|
const prompt = () => {
|
|
800
|
+
if (_statusLineEnabled && _renderStatus) {
|
|
801
|
+
const line = _renderStatus();
|
|
802
|
+
// Built-in line is dimmed; a custom command may carry its own ANSI.
|
|
803
|
+
if (line) process.stdout.write((_customStatus ? line : chalk.dim(line)) + "\n");
|
|
804
|
+
}
|
|
579
805
|
rl.setPrompt(getPrompt());
|
|
580
806
|
rl.prompt();
|
|
581
807
|
};
|
|
@@ -612,6 +838,9 @@ export async function startAgentRepl(options = {}) {
|
|
|
612
838
|
);
|
|
613
839
|
logger.log(` ${chalk.cyan("/provider")} Show/change provider`);
|
|
614
840
|
logger.log(` ${chalk.cyan("/clear")} Clear conversation`);
|
|
841
|
+
logger.log(
|
|
842
|
+
` ${chalk.cyan("/statusline")} Context-usage line on/off (/statusline [on|off])`,
|
|
843
|
+
);
|
|
615
844
|
logger.log(
|
|
616
845
|
` ${chalk.cyan("/compact")} Smart compact (importance-based)`,
|
|
617
846
|
);
|
|
@@ -658,6 +887,29 @@ export async function startAgentRepl(options = {}) {
|
|
|
658
887
|
logger.log(
|
|
659
888
|
" Context engineering: instinct + memory + notes injection\n",
|
|
660
889
|
);
|
|
890
|
+
// User-defined command macros (.claude/commands/*.md) become runnable
|
|
891
|
+
// slash commands here — list whatever is discovered so they're visible.
|
|
892
|
+
try {
|
|
893
|
+
const { discoverCommands } = await import("../lib/slash-commands.js");
|
|
894
|
+
const macros = discoverCommands(process.cwd());
|
|
895
|
+
if (macros.length > 0) {
|
|
896
|
+
logger.log(chalk.bold("Custom commands (.claude/commands):"));
|
|
897
|
+
for (const m of macros) {
|
|
898
|
+
const tag =
|
|
899
|
+
m.scope === "project"
|
|
900
|
+
? chalk.cyan("[proj]")
|
|
901
|
+
: chalk.gray("[pers]");
|
|
902
|
+
logger.log(
|
|
903
|
+
` ${chalk.cyan("/" + m.name)} ${tag}` +
|
|
904
|
+
(m.argumentHint ? chalk.dim(` ${m.argumentHint}`) : "") +
|
|
905
|
+
(m.description ? ` ${chalk.gray(m.description)}` : ""),
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
logger.log("");
|
|
909
|
+
}
|
|
910
|
+
} catch (_err) {
|
|
911
|
+
// Non-critical — macro discovery failure must not break /help
|
|
912
|
+
}
|
|
661
913
|
prompt();
|
|
662
914
|
return;
|
|
663
915
|
}
|
|
@@ -708,6 +960,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
708
960
|
const arg = trimmed.slice(6).trim();
|
|
709
961
|
if (arg) {
|
|
710
962
|
model = arg;
|
|
963
|
+
_curModel = model; // keep the status-line readout in sync
|
|
711
964
|
logger.info(`Model: ${chalk.cyan(model)}`);
|
|
712
965
|
} else {
|
|
713
966
|
logger.info(`Current model: ${chalk.cyan(model)}`);
|
|
@@ -756,6 +1009,76 @@ export async function startAgentRepl(options = {}) {
|
|
|
756
1009
|
return;
|
|
757
1010
|
}
|
|
758
1011
|
|
|
1012
|
+
if (trimmed === "/statusline" || trimmed.startsWith("/statusline ")) {
|
|
1013
|
+
const arg = trimmed.slice("/statusline".length).trim().toLowerCase();
|
|
1014
|
+
if (arg === "off") {
|
|
1015
|
+
_statusLineEnabled = false;
|
|
1016
|
+
logger.info("Status line: off");
|
|
1017
|
+
} else if (arg === "on") {
|
|
1018
|
+
_statusLineEnabled = true;
|
|
1019
|
+
logger.info("Status line: on");
|
|
1020
|
+
} else {
|
|
1021
|
+
// bare / "show" → report state + a one-off render
|
|
1022
|
+
const line = _statusLineEnabled && _renderStatus ? _renderStatus() : null;
|
|
1023
|
+
if (line) {
|
|
1024
|
+
logger.info(
|
|
1025
|
+
`Status line: ${_customStatus ? line : chalk.dim(line)}`,
|
|
1026
|
+
);
|
|
1027
|
+
} else {
|
|
1028
|
+
logger.info(
|
|
1029
|
+
`Status line: ${_statusLineEnabled ? "on (no content yet)" : "off"}` +
|
|
1030
|
+
(_statusLineEnabled ? "" : ` — enable with ${chalk.cyan("/statusline on")}`),
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
if (_customStatus) {
|
|
1034
|
+
logger.info(chalk.gray(" source: settings.json statusLine command"));
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
prompt();
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
if (trimmed === "/output-style" || trimmed.startsWith("/output-style ")) {
|
|
1042
|
+
const arg = trimmed.slice("/output-style".length).trim();
|
|
1043
|
+
try {
|
|
1044
|
+
const { discoverOutputStyles, getOutputStyle } = await import(
|
|
1045
|
+
"../lib/output-styles.js"
|
|
1046
|
+
);
|
|
1047
|
+
if (!arg) {
|
|
1048
|
+
logger.log(chalk.bold("Output styles:"));
|
|
1049
|
+
for (const s of discoverOutputStyles(process.cwd())) {
|
|
1050
|
+
const cur =
|
|
1051
|
+
_activeOutputStyle?.name === s.name ? chalk.green(" *") : "";
|
|
1052
|
+
logger.log(
|
|
1053
|
+
` ${s.name.padEnd(16)}${cur} ${chalk.gray(s.description || "")}`,
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
logger.log(
|
|
1057
|
+
chalk.gray(`current: ${_activeOutputStyle?.name || "none"}`),
|
|
1058
|
+
);
|
|
1059
|
+
} else if (arg === "none" || arg === "default") {
|
|
1060
|
+
_activeOutputStyle = null;
|
|
1061
|
+
messages[0].content = _replBaseSystem;
|
|
1062
|
+
logger.info("output style cleared");
|
|
1063
|
+
} else {
|
|
1064
|
+
const s = getOutputStyle(arg, process.cwd());
|
|
1065
|
+
if (!s) {
|
|
1066
|
+
logger.error(chalk.red(`no such output style: ${arg}`));
|
|
1067
|
+
} else {
|
|
1068
|
+
_activeOutputStyle = { name: s.name, body: s.body || "" };
|
|
1069
|
+
messages[0].content = s.body
|
|
1070
|
+
? `${_replBaseSystem}\n\n${s.body}`
|
|
1071
|
+
: _replBaseSystem;
|
|
1072
|
+
logger.info(chalk.green(`output style → ${s.name}`));
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
} catch (err) {
|
|
1076
|
+
logger.error(chalk.red(`/output-style failed: ${err.message}`));
|
|
1077
|
+
}
|
|
1078
|
+
prompt();
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
759
1082
|
if (trimmed === "/compact") {
|
|
760
1083
|
if (_compressor && messages.length > 3) {
|
|
761
1084
|
const { messages: compacted, stats } = await _compressor.compress(
|
|
@@ -1473,10 +1796,28 @@ export async function startAgentRepl(options = {}) {
|
|
|
1473
1796
|
return;
|
|
1474
1797
|
}
|
|
1475
1798
|
|
|
1799
|
+
// User-defined slash-command macros (.claude/commands/*.md), Claude-Code
|
|
1800
|
+
// parity. resolveSlashMacro maps a leading /name to a command macro and
|
|
1801
|
+
// expands its template; a non-match returns the line unchanged so a literal
|
|
1802
|
+
// prompt like "/etc/hosts" still reaches the LLM. Wire is unit-tested.
|
|
1803
|
+
let promptText = trimmed;
|
|
1804
|
+
try {
|
|
1805
|
+
const macro = await resolveSlashMacro(trimmed, { cwd: process.cwd() });
|
|
1806
|
+
if (macro.matched) {
|
|
1807
|
+
for (const w of macro.warnings) logger.info(chalk.yellow(`[@ref] ${w}`));
|
|
1808
|
+
promptText = macro.promptText;
|
|
1809
|
+
logger.log(
|
|
1810
|
+
chalk.gray(`[/${macro.name}] macro expanded (${macro.scope})`),
|
|
1811
|
+
);
|
|
1812
|
+
}
|
|
1813
|
+
} catch (err) {
|
|
1814
|
+
logger.verbose(`[slash-macro] expansion skipped: ${err.message}`);
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1476
1817
|
// Fire UserPromptSubmit hook with rewrite/abort support.
|
|
1477
1818
|
// Hooks may emit {"rewrittenPrompt": "..."} or {"abort": true, "reason": "..."}
|
|
1478
1819
|
// via stdout JSON. Failures fall through to the original prompt.
|
|
1479
|
-
const promptDirective = await fireUserPromptSubmit(_hookDb,
|
|
1820
|
+
const promptDirective = await fireUserPromptSubmit(_hookDb, promptText, {
|
|
1480
1821
|
sessionId,
|
|
1481
1822
|
messageCount: messages.length,
|
|
1482
1823
|
});
|
|
@@ -1490,7 +1831,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
1490
1831
|
return;
|
|
1491
1832
|
}
|
|
1492
1833
|
const effectivePrompt = promptDirective.prompt;
|
|
1493
|
-
if (effectivePrompt !==
|
|
1834
|
+
if (effectivePrompt !== promptText) {
|
|
1494
1835
|
logger.verbose(`[hook] prompt rewritten by UserPromptSubmit hook`);
|
|
1495
1836
|
}
|
|
1496
1837
|
|
|
@@ -1514,13 +1855,42 @@ export async function startAgentRepl(options = {}) {
|
|
|
1514
1855
|
logger.verbose(`[@ref] expansion skipped: ${err.message}`);
|
|
1515
1856
|
}
|
|
1516
1857
|
|
|
1858
|
+
// settings.json UserPromptSubmit hooks (decision-capable; the DB hook above
|
|
1859
|
+
// is observe-only). block → abort the turn; context → inject before the turn.
|
|
1860
|
+
if (_settingsHooks) {
|
|
1861
|
+
try {
|
|
1862
|
+
const { runUserPromptSubmitHooks } = await import(
|
|
1863
|
+
"../lib/settings-hook-events.cjs"
|
|
1864
|
+
);
|
|
1865
|
+
const ups = runUserPromptSubmitHooks(_settingsHooks, {
|
|
1866
|
+
prompt: userContent,
|
|
1867
|
+
cwd: process.cwd(),
|
|
1868
|
+
sessionId,
|
|
1869
|
+
});
|
|
1870
|
+
if (ups.blocked) {
|
|
1871
|
+
logger.info(
|
|
1872
|
+
chalk.yellow(
|
|
1873
|
+
`[hook] prompt blocked${ups.reason ? ": " + ups.reason : ""}`,
|
|
1874
|
+
),
|
|
1875
|
+
);
|
|
1876
|
+
prompt();
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
if (ups.additionalContext) {
|
|
1880
|
+
userContent += `\n\n[hook context]\n${ups.additionalContext}`;
|
|
1881
|
+
}
|
|
1882
|
+
} catch (_err) {
|
|
1883
|
+
// settings hook dispatch is best-effort
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1517
1887
|
// Add user message
|
|
1518
1888
|
messages.push({ role: "user", content: userContent });
|
|
1519
1889
|
|
|
1520
1890
|
// Slot-filling: detect intent and fill missing parameters interactively
|
|
1521
1891
|
try {
|
|
1522
1892
|
const { CLISlotFiller } = await import("../lib/slot-filler.js");
|
|
1523
|
-
const intent = CLISlotFiller.detectIntent(
|
|
1893
|
+
const intent = CLISlotFiller.detectIntent(promptText);
|
|
1524
1894
|
if (intent) {
|
|
1525
1895
|
const defs = CLISlotFiller.getSlotDefinitions(intent.type);
|
|
1526
1896
|
const missing = defs.required.filter((s) => !intent.entities[s]);
|
|
@@ -1549,7 +1919,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
1549
1919
|
|
|
1550
1920
|
// Auto-select best model based on task type
|
|
1551
1921
|
let activeModel = model;
|
|
1552
|
-
const taskDetection = detectTaskType(
|
|
1922
|
+
const taskDetection = detectTaskType(promptText);
|
|
1553
1923
|
if (taskDetection.confidence > 0.3) {
|
|
1554
1924
|
const recommended = selectModelForTask(provider, taskDetection.taskType);
|
|
1555
1925
|
if (recommended && recommended !== activeModel) {
|
|
@@ -1583,6 +1953,8 @@ export async function startAgentRepl(options = {}) {
|
|
|
1583
1953
|
const { content: response, usageEvents } = await agentLoop(messages, {
|
|
1584
1954
|
provider,
|
|
1585
1955
|
model: activeModel,
|
|
1956
|
+
thinking,
|
|
1957
|
+
thinkingBudget,
|
|
1586
1958
|
baseUrl,
|
|
1587
1959
|
apiKey,
|
|
1588
1960
|
contextEngine,
|
|
@@ -1594,6 +1966,9 @@ export async function startAgentRepl(options = {}) {
|
|
|
1594
1966
|
checkpointSession: sessionId,
|
|
1595
1967
|
prepareCall,
|
|
1596
1968
|
approvalGate: _approvalGate,
|
|
1969
|
+
permissionRules: _permissionRules,
|
|
1970
|
+
permissionConfirm: _permissionConfirm,
|
|
1971
|
+
settingsHooks: _settingsHooks,
|
|
1597
1972
|
// MCP: --mcp-config (ad-hoc) wins; bundle MCP is the fallback. The 3
|
|
1598
1973
|
// tool channels expose --mcp-config servers' tools to the LLM directly.
|
|
1599
1974
|
mcpClient: _adhocMcp?.mcpClient || _bundleMcpClient || undefined,
|
|
@@ -1617,6 +1992,17 @@ export async function startAgentRepl(options = {}) {
|
|
|
1617
1992
|
}
|
|
1618
1993
|
}
|
|
1619
1994
|
|
|
1995
|
+
// Feed the status line: the last usage event's input+output ≈ the tokens
|
|
1996
|
+
// now resident in the context window (what the next call resends). Track
|
|
1997
|
+
// the active model too, so the built-in readout reflects auto-switches.
|
|
1998
|
+
_curModel = activeModel;
|
|
1999
|
+
_turnCount += 1;
|
|
2000
|
+
if (usageEvents?.length) {
|
|
2001
|
+
const last = usageEvents[usageEvents.length - 1]?.usage || {};
|
|
2002
|
+
const used = (last.input_tokens || 0) + (last.output_tokens || 0);
|
|
2003
|
+
if (used > 0) _ctxUsedTokens = used;
|
|
2004
|
+
}
|
|
2005
|
+
|
|
1620
2006
|
// Fire AssistantResponse hook with rewrite/suppress support
|
|
1621
2007
|
const responseDirective = await fireAssistantResponse(
|
|
1622
2008
|
_hookDb,
|
|
@@ -1710,7 +2096,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
1710
2096
|
// Store as episodic memory
|
|
1711
2097
|
if (db) {
|
|
1712
2098
|
try {
|
|
1713
|
-
storeMemory(db,
|
|
2099
|
+
storeMemory(db, promptText, { importance: 0.3, type: "episodic" });
|
|
1714
2100
|
} catch (_e) {
|
|
1715
2101
|
// Non-critical
|
|
1716
2102
|
}
|
|
@@ -1742,6 +2128,22 @@ export async function startAgentRepl(options = {}) {
|
|
|
1742
2128
|
});
|
|
1743
2129
|
|
|
1744
2130
|
rl.on("close", async () => {
|
|
2131
|
+
// settings.json SessionEnd hooks (observe-only) when the REPL exits.
|
|
2132
|
+
if (_settingsHooks) {
|
|
2133
|
+
try {
|
|
2134
|
+
const { runObserveHooks } = await import(
|
|
2135
|
+
"../lib/settings-hook-events.cjs"
|
|
2136
|
+
);
|
|
2137
|
+
runObserveHooks(
|
|
2138
|
+
_settingsHooks,
|
|
2139
|
+
"SessionEnd",
|
|
2140
|
+
{ reason: "exit", cwd: process.cwd(), session_id: sessionId },
|
|
2141
|
+
{ cwd: process.cwd() },
|
|
2142
|
+
);
|
|
2143
|
+
} catch (_err) {
|
|
2144
|
+
// observe-only
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
1745
2147
|
// Save session on exit
|
|
1746
2148
|
if (sessionId) {
|
|
1747
2149
|
try {
|
|
@@ -1819,6 +2221,14 @@ export async function startAgentRepl(options = {}) {
|
|
|
1819
2221
|
}
|
|
1820
2222
|
}
|
|
1821
2223
|
|
|
2224
|
+
// Kill any background run_shell tasks so a backgrounded command (e.g. a
|
|
2225
|
+
// dev server) doesn't outlive the REPL session.
|
|
2226
|
+
try {
|
|
2227
|
+
killAllBackgroundShellTasks();
|
|
2228
|
+
} catch (_e) {
|
|
2229
|
+
// Non-critical
|
|
2230
|
+
}
|
|
2231
|
+
|
|
1822
2232
|
// Shutdown runtime
|
|
1823
2233
|
try {
|
|
1824
2234
|
await shutdown();
|