chainlesschain 0.162.35 → 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-CJn02U42.js → AIOps-vAVAFNJ4.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-ewURAAoy.js → ActionButton-BnRHFCKM.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BiSadESb.js → Analytics-BOjwqWqG.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BR0WOEug.js → AppLayout-Dc0D1Txn.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-CrqcYx0e.js → Audit-dd_2efaZ.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DtbSBn4e.js → Backup-HF1jgm8G.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BjSc9j0o.js → BaseInput-CCtzmoKe.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-ixzrlCJE.js → Chat-BNfH1c3p.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-B78nEq05.js → ChatBubbleRenderer-DCWFqmI4.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-UGYeSsgr.js → Checkbox-BOr-NscK.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B97OOAg4.js → Codegen-DE058N7-.js} +1 -1
- package/src/assets/web-panel/assets/{Col-D9aGkaZ6.js → Col-SOREo1XE.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Dc2v2RGS.js → Community-sOvNZo9f.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-B_FYlUQR.js → Compact-DnBe558D.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-C4FiTHyC.js → Compliance-o-r6CUbg.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CQ8j3LIg.js → Cowork-D6_k9mHP.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Dzjs9Z9Z.js → Cron-CEV3Xkrm.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BXI24uzI.js → Crosschain-eJ1lQWKU.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C-I4_d07.js → DID-B-WqM9Hp.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-BzzGh5mo.js → Dashboard-ZnKPcsHN.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Bh8H70De.js → Dropdown-B8uLWDIP.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DI_qybJP.js → EmailListRenderer-Jmj2Y7aH.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DkKTsfc4.js → FamilyGuardDashboard-Cb2xetG-.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DS7CmvVG.js → Federation-C_07GXoq.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CI97WsB5.js → FormItemContext-D3kbYrMU.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Da27EdR4.js → GenericCardRenderer-9xgqvGPg.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CEh0gR2W.js → Git-BlwWlMMB.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-kIr3tls2.js → Governance-DxN3wQZ_.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CC1GzyC1.js → Inference-ls7pSw_D.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BNgTiWOB.js → KnowledgeGraph-_n9hYuPI.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B2P10gB1.js → Logs-CvEVY5TK.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-HPfBvbFZ.js → Marketplace-C3qvQJT7.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-ByYotSKb.js → McpTools-DiwKpnKx.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-BGIAzFVS.js → Memory-CIBPi_da.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CroNYTAH.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-BqhyIwo9.js → Mtc-BMFWrI65.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-BpEKOvx9.js → MtcAudit-2s8LaHtR.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DST1d_Qo.js → Multisig-dL_nvj7d.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DlMsZcK_.js → NLProgramming-BbrJp06R.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-C734UJvD.js → Notes-jR9irwy3.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-C0-pPxvk.js → NotificationSettings-Dk-STCIX.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-C7zT9eFc.js → OrderTableRenderer-CqqfY6zq.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-C5iHC_yW.js → Organization-BCK5jylo.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CovuHHVR.js → Overflow-BRAY7Smt.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Dx9QL-Gy.js → P2P-BltVRGjb.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-IP1dEt6-.js → PdhVaultBrowser-CV8UbXHe.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-BrR1XZG5.js → Permissions-_tNl47Qh.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BgqxVE5m.js → PersonalDataHub-Cgc4HjpX.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-DzMk5HAz.js → Pipeline-Bn_QU4mu.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CDoLa6tk.js → Privacy-jzJowp5P.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Dy5gc6ve.js → ProjectInit-B_1pJ8qd.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DXy-k4hG.js → ProjectSettings-CPVZpXzs.js} +2 -2
- package/src/assets/web-panel/assets/Projects-CQsHOWnT.js +1 -0
- package/src/assets/web-panel/assets/Providers-CzzMiLC0.js +1 -0
- package/src/assets/web-panel/assets/{QuickAsk-B8KEHCnd.js → QuickAsk-MxBKIn9o.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DNVHGYYZ.js → Recommend-D8lN6Lis.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-CaDhWP03.js → Reputation-CfYK-IrV.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CrGLI02x.js → Row-Bg7NZDP9.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BX7P8I6i.js → RssFeed-BOVNJhj0.js} +3 -3
- package/src/assets/web-panel/assets/Search-B38qzmhY.js +1 -0
- package/src/assets/web-panel/assets/{Security-B6J7IFc1.js → Security-CjqleZpe.js} +4 -4
- package/src/assets/web-panel/assets/{Services-vvdcO3mM.js → Services-Bu9JSJap.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BoAoPTzZ.js → Skeleton-B2RvRkaX.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CyIQV5b3.js → Skills-_h42mxMN.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BAQVgdZV.js → Sla-BssLs56D.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Bxcn1Jkj.js → SpeechSettings-DCxFYHsd.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Dpaj3hDM.js → SyncSettings-D2xQuNLE.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Bwqo89En.js → Tasks-DhpOGOlo.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Bowcqifn.js → Templates-CYG-R-aS.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DOkf85uG.js → Tenant-BQRYLsvP.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-v4MM9dCj.js → Terminal-imKU7N5j.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-B9A3zDXA.js → TimelineRenderer-BIZzBftk.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-jtVVqKFr.js → Tokens-uMLH5p_a.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-26Iw-iIl.js → Trigger-BzS6XPqx.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DqY5ORrH.js → Trust-R4zhHufZ.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BFsbr3y7.js → UkeySign-DATQCoGe.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BtDbj3oa.js → VideoEditing-ClUmKOtS.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BAwmwHbk.js → Wallet-DzJTbQzD.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DINJTsfq.js → WebAuthn-CrXrLmzQ.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-BEorm8SK.js → WorkflowEditor-CpvZ0Tma.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CE39-Dxg.js → chat-a6wpYmVL.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C_cLZ93a.js → colors-CXJADb1t.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BSioWA2c.js → compact-item-CL2pohS_.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CGTk4mhN.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-Dl1fRwS_.js → hasIn-Bchh1rAi.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAhinBPR.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-BWpfxzVm.js → index-B4zNisy9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CA6K7lZB.js → index-B6NehWty.js} +1 -1
- package/src/assets/web-panel/assets/index-B7Ek5iiY.js +1 -0
- package/src/assets/web-panel/assets/{index-DJyeeygd.js → index-B7knYOpm.js} +1 -1
- package/src/assets/web-panel/assets/{index-hv4jUdG3.js → index-B7wT5VRi.js} +1 -1
- package/src/assets/web-panel/assets/{index-9_mmaR42.js → index-BF4xx1_b.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cxw3p73X.js → index-BH9t10pe.js} +1 -1
- package/src/assets/web-panel/assets/{index-B016Fsqr.js → index-BPH5ESqs.js} +3 -3
- package/src/assets/web-panel/assets/{index-BmbVyhk1.js → index-BmsIKzyu.js} +1 -1
- package/src/assets/web-panel/assets/{index-CST381Qf.js → index-BoaRB-4a.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9D4q-qI.js → index-BrbJBnT-.js} +1 -1
- package/src/assets/web-panel/assets/{index-pngH1and.js → index-C2eMYASq.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKEipmR8.js → index-C4yBRKT4.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2QiUEgK.js → index-CGq4HQno.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4JXchTG.js → index-CMybtJY6.js} +1 -1
- package/src/assets/web-panel/assets/{index-iiZfONfx.js → index-CR3kFPuC.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTKEXyaW.js → index-CTRd7vkq.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2ly7sCw.js → index-CdU8BwRW.js} +1 -1
- package/src/assets/web-panel/assets/{index-Di6nvW1N.js → index-Cua_P8St.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnEPB1Mz.js → index-CuehgDOp.js} +1 -1
- package/src/assets/web-panel/assets/{index-DrWERr8C.js → index-D-TT9Swq.js} +1 -1
- package/src/assets/web-panel/assets/{index-II3JhQu2.js → index-DEYcLAl7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbXnyoSO.js → index-DQ_hw_5P.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ceo9P9tQ.js → index-DTEu7TSF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDQx2YFc.js → index-DVo1GJoj.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-VVk1Jg.js → index-DjdOL159.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAwVwBOL.js → index-DsbMVBj1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bvi14vJ7.js → index-DxahxRP7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhqOTuMW.js → index-EPERz4Pu.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ds2RzRG0.js → index-IkvkNxbc.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChwpS1f0.js → index-KCib1PTw.js} +1 -1
- package/src/assets/web-panel/assets/{index-OCxo0X6J.js → index-M8SZI11a.js} +1 -1
- package/src/assets/web-panel/assets/{index-Qj2x55mz.js → index-TxbHusq2.js} +1 -1
- package/src/assets/web-panel/assets/{index-CisXVbSt.js → index-dsLc7t6W.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9tq8Da8.js → index-jMcv1u5o.js} +1 -1
- package/src/assets/web-panel/assets/{index--SWvw6yW.js → index-majCS3s2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTpCUi0m.js → index-u8K1y_lh.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-GOhLA2-f.js → initDefaultProps-DYn3Gc09.js} +1 -1
- package/src/assets/web-panel/assets/{motion-jqxFzHTx.js → motion-ZS3eolb9.js} +1 -1
- package/src/assets/web-panel/assets/{move-CSLsp6TA.js → move-CEw4uqr3.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Cnlrb25c.js → omit-DlHFZnPp.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CLqlxWWD.js → pickAttrs-eZQvV5fA.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BAWIWtul.js → placementArrow-B31jQwa-.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CSR1DayS.js → responsiveObserve-DAsNmVto.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CNhoPJOp.js → slide-gPQPrYZC.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BZiYHRHW.js → statusUtils-DwWKX5co.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BMoY-Fm5.js → styleChecker-B3VOtXuH.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DhtNdlaS.js → useFlexGapSupport-6ADctM2r.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DNPtDOZ4.js → useFs-6Zx1SSKs.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DTdjNvAI.js → usePersonalDataHub-BzReowln.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C9zW9IJ2.js → vnode-C8IpEQbD.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-D-6RYJJr.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 +8 -2
- 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 -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/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 +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-CH-qnGEV.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/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
|
@@ -145,7 +145,7 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
145
145
|
kind: "shell",
|
|
146
146
|
tier: "mvp",
|
|
147
147
|
description:
|
|
148
|
-
"Execute a shell command and return the output. Use for running tests, linting, builds, and other non-git workspace commands.",
|
|
148
|
+
"Execute a shell command and return the output. Use for running tests, linting, builds, and other non-git workspace commands. For long-running commands (builds, full test suites, dev servers) pass run_in_background:true to return a task_id immediately and poll with check_shell instead of blocking.",
|
|
149
149
|
inputSchema: {
|
|
150
150
|
type: "object",
|
|
151
151
|
properties: {
|
|
@@ -154,6 +154,16 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
154
154
|
type: "string",
|
|
155
155
|
description: "Working directory (optional)",
|
|
156
156
|
},
|
|
157
|
+
run_in_background: {
|
|
158
|
+
type: "boolean",
|
|
159
|
+
description:
|
|
160
|
+
"Run the command in the background and return a task_id immediately instead of blocking. Use for long-running commands (builds, test suites, dev servers). Poll output and completion with the check_shell tool.",
|
|
161
|
+
},
|
|
162
|
+
timeout: {
|
|
163
|
+
type: "number",
|
|
164
|
+
description:
|
|
165
|
+
"Foreground (synchronous) timeout in milliseconds. Default 60000, max 600000. Ignored when run_in_background is true.",
|
|
166
|
+
},
|
|
157
167
|
},
|
|
158
168
|
required: ["command"],
|
|
159
169
|
},
|
|
@@ -168,6 +178,40 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
168
178
|
tags: ["tool:run_shell", "contract:coding-agent", "tier:mvp"],
|
|
169
179
|
},
|
|
170
180
|
},
|
|
181
|
+
{
|
|
182
|
+
name: "check_shell",
|
|
183
|
+
title: "Check Shell",
|
|
184
|
+
kind: "shell",
|
|
185
|
+
tier: "mvp",
|
|
186
|
+
description:
|
|
187
|
+
"Poll a background run_shell task: returns its status, exit code, and any new stdout/stderr since the last check. Omit task_id to list all background tasks. Pass kill:true to terminate a still-running task.",
|
|
188
|
+
inputSchema: {
|
|
189
|
+
type: "object",
|
|
190
|
+
properties: {
|
|
191
|
+
task_id: {
|
|
192
|
+
type: "string",
|
|
193
|
+
description:
|
|
194
|
+
"The task_id returned by run_shell { run_in_background: true }. Omit to list all known background tasks.",
|
|
195
|
+
},
|
|
196
|
+
kill: {
|
|
197
|
+
type: "boolean",
|
|
198
|
+
description:
|
|
199
|
+
"Terminate the task if it is still running (e.g. a dev server you no longer need).",
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
required: [],
|
|
203
|
+
},
|
|
204
|
+
...TOOL_POLICY_METADATA.check_shell,
|
|
205
|
+
runtimeDescriptor: "shell",
|
|
206
|
+
permissions: {
|
|
207
|
+
level: "readonly",
|
|
208
|
+
scopes: ["process:read"],
|
|
209
|
+
},
|
|
210
|
+
telemetry: {
|
|
211
|
+
category: "shell",
|
|
212
|
+
tags: ["tool:check_shell", "contract:coding-agent", "tier:mvp"],
|
|
213
|
+
},
|
|
214
|
+
},
|
|
171
215
|
{
|
|
172
216
|
name: "git",
|
|
173
217
|
title: "Git",
|
|
@@ -366,14 +410,19 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
366
410
|
kind: "agent",
|
|
367
411
|
tier: "extension",
|
|
368
412
|
description:
|
|
369
|
-
"Spawn an isolated sub-agent to handle a subtask. The sub-agent has its own context and message history, and only returns a summary result. Use this for tasks that benefit from focused, independent execution (e.g. code review, summarization, translation).",
|
|
413
|
+
"Spawn an isolated sub-agent to handle a subtask. The sub-agent has its own context and message history, and only returns a summary result. Use this for tasks that benefit from focused, independent execution (e.g. code review, summarization, translation). Pass `agent` to delegate to a named, pre-defined subagent (its persona + tool scope come from its .md file); otherwise give an ad-hoc `role`.",
|
|
370
414
|
inputSchema: {
|
|
371
415
|
type: "object",
|
|
372
416
|
properties: {
|
|
417
|
+
agent: {
|
|
418
|
+
type: "string",
|
|
419
|
+
description:
|
|
420
|
+
'Optional name of a pre-defined subagent from .chainlesschain/agents/ or .claude/agents/ (e.g. "review:security"). Loads that file\'s system prompt + tool allow-list. Run `cc agents list` to see them. Explicit `role`/`tools` override the agent\'s values.',
|
|
421
|
+
},
|
|
373
422
|
role: {
|
|
374
423
|
type: "string",
|
|
375
424
|
description:
|
|
376
|
-
"Sub-agent role (e.g. code-review, summarizer, translator, debugger)",
|
|
425
|
+
"Sub-agent role (e.g. code-review, summarizer, translator, debugger). Required unless `agent` is given.",
|
|
377
426
|
},
|
|
378
427
|
task: {
|
|
379
428
|
type: "string",
|
|
@@ -397,7 +446,7 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
397
446
|
"Optional declarative profile (from sub-agent-profiles). When set, seeds systemPrompt / tool allowlist / iteration cap. Explicit `tools` overrides the profile allowlist.",
|
|
398
447
|
},
|
|
399
448
|
},
|
|
400
|
-
required: ["
|
|
449
|
+
required: ["task"],
|
|
401
450
|
},
|
|
402
451
|
...TOOL_POLICY_METADATA.spawn_sub_agent,
|
|
403
452
|
permissions: {
|
|
@@ -449,6 +498,47 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
449
498
|
tags: ["tool:web_fetch", "contract:coding-agent", "tier:extension"],
|
|
450
499
|
},
|
|
451
500
|
},
|
|
501
|
+
{
|
|
502
|
+
name: "web_search",
|
|
503
|
+
title: "Web Search",
|
|
504
|
+
kind: "network",
|
|
505
|
+
tier: "extension",
|
|
506
|
+
description:
|
|
507
|
+
"Search the web for a query and return ranked results (title, url, snippet) plus an optional synthesized answer. Use this to discover URLs, then web_fetch to read a page. Backend is configured via .chainlesschain/config.json:webSearch (default provider: auto — uses whichever API key is set, else keyless DuckDuckGo).",
|
|
508
|
+
inputSchema: {
|
|
509
|
+
type: "object",
|
|
510
|
+
properties: {
|
|
511
|
+
query: {
|
|
512
|
+
type: "string",
|
|
513
|
+
description: "Search query (natural-language keywords)",
|
|
514
|
+
},
|
|
515
|
+
provider: {
|
|
516
|
+
type: "string",
|
|
517
|
+
enum: ["auto", "tavily", "brave", "bocha", "qianfan", "duckduckgo", "searxng", "baidu"],
|
|
518
|
+
description:
|
|
519
|
+
"Override the configured search backend for this call (default: from config / auto)",
|
|
520
|
+
},
|
|
521
|
+
maxResults: {
|
|
522
|
+
type: "number",
|
|
523
|
+
description: "Maximum number of results to return (default: 8)",
|
|
524
|
+
},
|
|
525
|
+
timeout: {
|
|
526
|
+
type: "number",
|
|
527
|
+
description: "Request timeout in ms (default: 15000)",
|
|
528
|
+
},
|
|
529
|
+
},
|
|
530
|
+
required: ["query"],
|
|
531
|
+
},
|
|
532
|
+
...TOOL_POLICY_METADATA.web_search,
|
|
533
|
+
permissions: {
|
|
534
|
+
level: "readonly",
|
|
535
|
+
scopes: ["network:read"],
|
|
536
|
+
},
|
|
537
|
+
telemetry: {
|
|
538
|
+
category: "network",
|
|
539
|
+
tags: ["tool:web_search", "contract:coding-agent", "tier:extension"],
|
|
540
|
+
},
|
|
541
|
+
},
|
|
452
542
|
{
|
|
453
543
|
name: "todo_write",
|
|
454
544
|
title: "Todo Write",
|
|
@@ -115,6 +115,20 @@ const TOOL_POLICY_METADATA = Object.freeze({
|
|
|
115
115
|
isReadOnly: false,
|
|
116
116
|
readOnlySubcommands: READ_ONLY_GIT_SUBCOMMANDS,
|
|
117
117
|
},
|
|
118
|
+
// Polls a background run_shell task (output + completion). Read-only: it never
|
|
119
|
+
// starts new work — the spawn already happened, gated, under run_shell. The
|
|
120
|
+
// optional kill flag terminates a task the agent itself launched, so it stays
|
|
121
|
+
// low-risk and is allowed during plan mode.
|
|
122
|
+
check_shell: {
|
|
123
|
+
riskLevel: RISK_LEVELS.LOW,
|
|
124
|
+
category: TOOL_CATEGORIES.READ,
|
|
125
|
+
availableInPlanMode: true,
|
|
126
|
+
planModeBehavior: "allow",
|
|
127
|
+
requiresPlanApproval: false,
|
|
128
|
+
requiresConfirmation: false,
|
|
129
|
+
approvalFlow: "auto",
|
|
130
|
+
isReadOnly: true,
|
|
131
|
+
},
|
|
118
132
|
list_skills: {
|
|
119
133
|
riskLevel: RISK_LEVELS.LOW,
|
|
120
134
|
category: TOOL_CATEGORIES.SKILL,
|
|
@@ -175,6 +189,16 @@ const TOOL_POLICY_METADATA = Object.freeze({
|
|
|
175
189
|
approvalFlow: "auto",
|
|
176
190
|
isReadOnly: true,
|
|
177
191
|
},
|
|
192
|
+
web_search: {
|
|
193
|
+
riskLevel: RISK_LEVELS.MEDIUM,
|
|
194
|
+
category: TOOL_CATEGORIES.READ,
|
|
195
|
+
availableInPlanMode: true,
|
|
196
|
+
planModeBehavior: "allow",
|
|
197
|
+
requiresPlanApproval: false,
|
|
198
|
+
requiresConfirmation: false,
|
|
199
|
+
approvalFlow: "auto",
|
|
200
|
+
isReadOnly: true,
|
|
201
|
+
},
|
|
178
202
|
todo_write: {
|
|
179
203
|
riskLevel: RISK_LEVELS.LOW,
|
|
180
204
|
category: TOOL_CATEGORIES.WRITE,
|
|
@@ -25,9 +25,10 @@ import {
|
|
|
25
25
|
buildSystemPrompt,
|
|
26
26
|
agentLoop as coreAgentLoop,
|
|
27
27
|
formatToolArgs,
|
|
28
|
+
killAllBackgroundShellTasks,
|
|
28
29
|
} from "./agent-core.js";
|
|
29
30
|
import {
|
|
30
|
-
|
|
31
|
+
resolveAgentMcp,
|
|
31
32
|
resolvePermissionPromptTool,
|
|
32
33
|
makePermissionPromptConfirmer,
|
|
33
34
|
} from "./mcp-config.js";
|
|
@@ -44,6 +45,7 @@ import {
|
|
|
44
45
|
} from "../harness/jsonl-session-store.js";
|
|
45
46
|
import { expandFileRefs } from "./file-ref-expander.js";
|
|
46
47
|
import { composeSystemPrompt } from "./system-prompt.js";
|
|
48
|
+
import { buildUserContent } from "../lib/image-input.js";
|
|
47
49
|
import { withQuietStdout } from "./quiet-stdout.js";
|
|
48
50
|
|
|
49
51
|
/** Tools that cannot mutate the filesystem or run commands. */
|
|
@@ -229,6 +231,41 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
229
231
|
? options.additionalDirectories.filter(Boolean)
|
|
230
232
|
: [];
|
|
231
233
|
|
|
234
|
+
// .claude/settings.json permission rules (deny > ask > allow). A `deny` hard-
|
|
235
|
+
// blocks, an `allow` pre-authorizes (so a safe op isn't fail-closed headless),
|
|
236
|
+
// an `ask` falls closed (no human to confirm in headless). No file → null →
|
|
237
|
+
// every existing risk-tier / shell-policy layer runs unchanged.
|
|
238
|
+
let permissionRules = options.permissionRules || null;
|
|
239
|
+
if (!permissionRules) {
|
|
240
|
+
try {
|
|
241
|
+
const { loadSettings } = await import("../lib/settings-loader.cjs");
|
|
242
|
+
const loaded = loadSettings({ cwd, settingsFile: options.settingsFile });
|
|
243
|
+
const total =
|
|
244
|
+
loaded.rules.allow.length +
|
|
245
|
+
loaded.rules.ask.length +
|
|
246
|
+
loaded.rules.deny.length;
|
|
247
|
+
permissionRules = total > 0 ? loaded.rules : null;
|
|
248
|
+
} catch {
|
|
249
|
+
permissionRules = null; // fail-open
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// .claude/settings.json `hooks` block — decision-capable PreToolUse/
|
|
254
|
+
// PostToolUse hooks (see settings-hooks/hook-runner). null = no hooks.
|
|
255
|
+
let settingsHooks = options.settingsHooks || null;
|
|
256
|
+
if (!settingsHooks) {
|
|
257
|
+
try {
|
|
258
|
+
const { loadHooks } = await import("../lib/settings-hooks.cjs");
|
|
259
|
+
const loaded = loadHooks({ cwd, settingsFile: options.settingsFile });
|
|
260
|
+
settingsHooks =
|
|
261
|
+
loaded.hooks && Object.keys(loaded.hooks).length > 0
|
|
262
|
+
? loaded.hooks
|
|
263
|
+
: null;
|
|
264
|
+
} catch {
|
|
265
|
+
settingsHooks = null; // fail-open
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
232
269
|
const runLoop = deps.agentLoop || coreAgentLoop;
|
|
233
270
|
const doBootstrap = deps.bootstrap || bootstrap;
|
|
234
271
|
const getApprovalGate =
|
|
@@ -340,18 +377,89 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
340
377
|
|
|
341
378
|
// Effective system prompt: built-in base, optionally replaced by
|
|
342
379
|
// --system-prompt and/or extended by --append-system-prompt.
|
|
380
|
+
// --output-style (or settings.json `outputStyle`) → a persona appended to the
|
|
381
|
+
// system prompt. Resolved best-effort; a missing style is ignored with a warn.
|
|
382
|
+
let outputStyleBody = null;
|
|
383
|
+
try {
|
|
384
|
+
const { resolveOutputStyle } = await import("../lib/output-styles.js");
|
|
385
|
+
const st = resolveOutputStyle(options.outputStyle, cwd);
|
|
386
|
+
if (st && st.missing && options.outputStyle) {
|
|
387
|
+
writeErr(` output-style: unknown style "${options.outputStyle}"\n`);
|
|
388
|
+
} else if (st && st.body) {
|
|
389
|
+
outputStyleBody = st.body;
|
|
390
|
+
}
|
|
391
|
+
} catch {
|
|
392
|
+
outputStyleBody = null;
|
|
393
|
+
}
|
|
394
|
+
|
|
343
395
|
const systemContent = composeSystemPrompt(
|
|
344
396
|
buildSystemPrompt(cwd, { additionalDirectories }),
|
|
345
397
|
{
|
|
346
398
|
systemPrompt: options.systemPrompt,
|
|
347
399
|
appendSystemPrompt: options.appendSystemPrompt,
|
|
400
|
+
outputStyle: outputStyleBody,
|
|
348
401
|
},
|
|
349
402
|
);
|
|
350
403
|
|
|
404
|
+
// settings.json UserPromptSubmit hooks. block → abort the run; context → inject.
|
|
405
|
+
if (settingsHooks) {
|
|
406
|
+
try {
|
|
407
|
+
const { runUserPromptSubmitHooks } = await import(
|
|
408
|
+
"../lib/settings-hook-events.cjs"
|
|
409
|
+
);
|
|
410
|
+
const ups = runUserPromptSubmitHooks(settingsHooks, {
|
|
411
|
+
prompt: userContent,
|
|
412
|
+
cwd,
|
|
413
|
+
sessionId,
|
|
414
|
+
});
|
|
415
|
+
if (ups.blocked) {
|
|
416
|
+
writeErr(
|
|
417
|
+
`[hook] prompt blocked${ups.reason ? ": " + ups.reason : ""}\n`,
|
|
418
|
+
);
|
|
419
|
+
return {
|
|
420
|
+
exitCode: 2,
|
|
421
|
+
result: ups.reason || "blocked by UserPromptSubmit hook",
|
|
422
|
+
isError: true,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
if (ups.additionalContext) {
|
|
426
|
+
userContent += `\n\n[hook context]\n${ups.additionalContext}`;
|
|
427
|
+
}
|
|
428
|
+
} catch (_err) {
|
|
429
|
+
// settings hook dispatch is best-effort
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// settings.json SessionStart hooks → inject session context (observe-only).
|
|
434
|
+
let sessionStartContext = null;
|
|
435
|
+
if (settingsHooks) {
|
|
436
|
+
try {
|
|
437
|
+
const { runSessionStartHooks } = await import(
|
|
438
|
+
"../lib/settings-hook-events.cjs"
|
|
439
|
+
);
|
|
440
|
+
sessionStartContext = runSessionStartHooks(settingsHooks, {
|
|
441
|
+
source: resumeId ? "resume" : "startup",
|
|
442
|
+
cwd,
|
|
443
|
+
sessionId,
|
|
444
|
+
}).additionalContext;
|
|
445
|
+
} catch (_err) {
|
|
446
|
+
sessionStartContext = null;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// --image <path>: attach vision input to the user turn. buildUserContent
|
|
451
|
+
// returns the plain string when there are no images, so text-only runs are
|
|
452
|
+
// byte-for-byte unchanged; with images it builds an OpenAI-style multimodal
|
|
453
|
+
// content array (agent-core converts it per-provider for ollama/anthropic).
|
|
454
|
+
const userMessageContent = buildUserContent(userContent, options.images);
|
|
455
|
+
|
|
351
456
|
const messages = [
|
|
352
457
|
{ role: "system", content: systemContent },
|
|
458
|
+
...(sessionStartContext
|
|
459
|
+
? [{ role: "system", content: sessionStartContext }]
|
|
460
|
+
: []),
|
|
353
461
|
...history,
|
|
354
|
-
{ role: "user", content:
|
|
462
|
+
{ role: "user", content: userMessageContent },
|
|
355
463
|
];
|
|
356
464
|
|
|
357
465
|
// Persist the user turn up front (best-effort) so a session is recoverable
|
|
@@ -378,12 +486,30 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
378
486
|
// tools to the LLM (Claude-Code parity). Connection is best-effort — a server
|
|
379
487
|
// that fails to connect is logged to stderr and contributes no tools; a
|
|
380
488
|
// missing/empty config file fails fast (the user explicitly asked for MCP).
|
|
489
|
+
// Combine the ad-hoc --mcp-config file with the servers registered via
|
|
490
|
+
// `cc mcp add` (their --auto-connect ones) into ONE client, exposing every
|
|
491
|
+
// tool to the LLM. A bad --mcp-config file fails fast; registered connects
|
|
492
|
+
// are best-effort. --no-mcp disables the registered set (ad-hoc still loads).
|
|
381
493
|
let mcp = null;
|
|
382
|
-
|
|
383
|
-
const
|
|
494
|
+
{
|
|
495
|
+
const doResolve = deps.resolveAgentMcp || resolveAgentMcp;
|
|
384
496
|
try {
|
|
385
|
-
mcp = await
|
|
386
|
-
|
|
497
|
+
mcp = await doResolve(
|
|
498
|
+
{
|
|
499
|
+
mcpConfigPath: options.mcpConfig || null,
|
|
500
|
+
db: db?.getDatabase?.() || null,
|
|
501
|
+
includeRegistered: options.useRegisteredMcp !== false,
|
|
502
|
+
ide: options.ide,
|
|
503
|
+
cwd: options.cwd || process.cwd(),
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
writeErr,
|
|
507
|
+
loadMcpConfig: deps.loadMcpConfig,
|
|
508
|
+
loadRegisteredMcp: deps.loadRegisteredMcp,
|
|
509
|
+
loadIdeMcp: deps.loadIdeMcp,
|
|
510
|
+
},
|
|
511
|
+
);
|
|
512
|
+
if (mcp && isText) {
|
|
387
513
|
for (const c of mcp.connected) {
|
|
388
514
|
writeErr(` mcp: ${c.server} (${c.tools} tools)\n`);
|
|
389
515
|
}
|
|
@@ -422,6 +548,11 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
422
548
|
const loopOptions = {
|
|
423
549
|
model,
|
|
424
550
|
provider,
|
|
551
|
+
// Extended thinking (Anthropic; opt-in via --think/--ultrathink). null/off
|
|
552
|
+
// → chatWithTools sends no thinking field. thinkingBudget (--thinking-budget)
|
|
553
|
+
// is the legacy-model budget_tokens override; ignored when thinking is off.
|
|
554
|
+
thinking: options.thinking || null,
|
|
555
|
+
thinkingBudget: options.thinkingBudget || null,
|
|
425
556
|
baseUrl,
|
|
426
557
|
apiKey,
|
|
427
558
|
cwd,
|
|
@@ -431,6 +562,8 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
431
562
|
checkpointSession: options.checkpointSession || sessionId,
|
|
432
563
|
hookDb: db,
|
|
433
564
|
approvalGate,
|
|
565
|
+
permissionRules,
|
|
566
|
+
settingsHooks,
|
|
434
567
|
enabledToolNames,
|
|
435
568
|
disabledTools,
|
|
436
569
|
iterationBudget: budget,
|
|
@@ -623,6 +756,29 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
623
756
|
// ignore — disconnect is best-effort
|
|
624
757
|
}
|
|
625
758
|
}
|
|
759
|
+
// Kill any background run_shell tasks this run spawned so a backgrounded
|
|
760
|
+
// command (e.g. a dev server) doesn't outlive the headless invocation.
|
|
761
|
+
try {
|
|
762
|
+
killAllBackgroundShellTasks();
|
|
763
|
+
} catch {
|
|
764
|
+
// best-effort — never mask the run's own outcome
|
|
765
|
+
}
|
|
766
|
+
// settings.json SessionEnd hooks (observe-only) when the run finishes.
|
|
767
|
+
if (settingsHooks) {
|
|
768
|
+
try {
|
|
769
|
+
const { runObserveHooks } = await import(
|
|
770
|
+
"../lib/settings-hook-events.cjs"
|
|
771
|
+
);
|
|
772
|
+
runObserveHooks(
|
|
773
|
+
settingsHooks,
|
|
774
|
+
"SessionEnd",
|
|
775
|
+
{ reason: "completed", cwd, session_id: sessionId },
|
|
776
|
+
{ cwd },
|
|
777
|
+
);
|
|
778
|
+
} catch {
|
|
779
|
+
// observe-only
|
|
780
|
+
}
|
|
781
|
+
}
|
|
626
782
|
}
|
|
627
783
|
|
|
628
784
|
// coreAgentLoop emits run-ended reason "budget-exhausted" when the iteration
|
|
@@ -21,7 +21,7 @@ import { buildSystemPrompt, agentLoop as coreAgentLoop } from "./agent-core.js";
|
|
|
21
21
|
import { composeSystemPrompt } from "./system-prompt.js";
|
|
22
22
|
import { expandFileRefs } from "./file-ref-expander.js";
|
|
23
23
|
import {
|
|
24
|
-
|
|
24
|
+
resolveAgentMcp,
|
|
25
25
|
resolvePermissionPromptTool,
|
|
26
26
|
makePermissionPromptConfirmer,
|
|
27
27
|
} from "./mcp-config.js";
|
|
@@ -145,6 +145,38 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
145
145
|
? options.additionalDirectories.filter(Boolean)
|
|
146
146
|
: [];
|
|
147
147
|
|
|
148
|
+
// .claude/settings.json permission rules (deny > ask > allow); see
|
|
149
|
+
// runAgentHeadless for the full semantics. null = no file → unchanged.
|
|
150
|
+
let permissionRules = options.permissionRules || null;
|
|
151
|
+
if (!permissionRules) {
|
|
152
|
+
try {
|
|
153
|
+
const { loadSettings } = await import("../lib/settings-loader.cjs");
|
|
154
|
+
const loaded = loadSettings({ cwd, settingsFile: options.settingsFile });
|
|
155
|
+
const total =
|
|
156
|
+
loaded.rules.allow.length +
|
|
157
|
+
loaded.rules.ask.length +
|
|
158
|
+
loaded.rules.deny.length;
|
|
159
|
+
permissionRules = total > 0 ? loaded.rules : null;
|
|
160
|
+
} catch {
|
|
161
|
+
permissionRules = null; // fail-open
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// .claude/settings.json `hooks` block (decision-capable PreToolUse/PostToolUse).
|
|
166
|
+
let settingsHooks = options.settingsHooks || null;
|
|
167
|
+
if (!settingsHooks) {
|
|
168
|
+
try {
|
|
169
|
+
const { loadHooks } = await import("../lib/settings-hooks.cjs");
|
|
170
|
+
const loaded = loadHooks({ cwd, settingsFile: options.settingsFile });
|
|
171
|
+
settingsHooks =
|
|
172
|
+
loaded.hooks && Object.keys(loaded.hooks).length > 0
|
|
173
|
+
? loaded.hooks
|
|
174
|
+
: null;
|
|
175
|
+
} catch {
|
|
176
|
+
settingsHooks = null; // fail-open
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
148
180
|
const input = deps.input || process.stdin;
|
|
149
181
|
const runLoop = deps.agentLoop || coreAgentLoop;
|
|
150
182
|
const doBootstrap = deps.bootstrap || bootstrap;
|
|
@@ -191,15 +223,42 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
191
223
|
approvalGate = null;
|
|
192
224
|
}
|
|
193
225
|
|
|
226
|
+
// --output-style (or settings.json `outputStyle`) persona, appended.
|
|
227
|
+
let outputStyleBody = null;
|
|
228
|
+
try {
|
|
229
|
+
const { resolveOutputStyle } = await import("../lib/output-styles.js");
|
|
230
|
+
const st = resolveOutputStyle(options.outputStyle, cwd);
|
|
231
|
+
if (st && st.body) outputStyleBody = st.body;
|
|
232
|
+
} catch {
|
|
233
|
+
outputStyleBody = null;
|
|
234
|
+
}
|
|
194
235
|
const systemContent = composeSystemPrompt(
|
|
195
236
|
buildSystemPrompt(cwd, { additionalDirectories }),
|
|
196
237
|
{
|
|
197
238
|
systemPrompt: options.systemPrompt,
|
|
198
239
|
appendSystemPrompt: options.appendSystemPrompt,
|
|
240
|
+
outputStyle: outputStyleBody,
|
|
199
241
|
},
|
|
200
242
|
);
|
|
201
243
|
const messages = [{ role: "system", content: systemContent }];
|
|
202
244
|
|
|
245
|
+
// settings.json SessionStart hooks → inject session context once (observe-only).
|
|
246
|
+
if (settingsHooks) {
|
|
247
|
+
try {
|
|
248
|
+
const { runSessionStartHooks } = await import(
|
|
249
|
+
"../lib/settings-hook-events.cjs"
|
|
250
|
+
);
|
|
251
|
+
const ctx = runSessionStartHooks(settingsHooks, {
|
|
252
|
+
source: "startup",
|
|
253
|
+
cwd,
|
|
254
|
+
sessionId,
|
|
255
|
+
}).additionalContext;
|
|
256
|
+
if (ctx) messages.push({ role: "system", content: ctx });
|
|
257
|
+
} catch (_err) {
|
|
258
|
+
// best-effort
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
203
262
|
emit({
|
|
204
263
|
type: "system",
|
|
205
264
|
subtype: "init",
|
|
@@ -232,14 +291,29 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
232
291
|
}
|
|
233
292
|
}
|
|
234
293
|
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
//
|
|
294
|
+
// Combine the ad-hoc --mcp-config file with the registered (cc mcp add)
|
|
295
|
+
// auto-connect servers into one client for the whole stream session, exposing
|
|
296
|
+
// every tool to the LLM. A bad --mcp-config file fails up front; registered
|
|
297
|
+
// connects are best-effort. --no-mcp disables the registered set.
|
|
238
298
|
let mcp = null;
|
|
239
|
-
|
|
240
|
-
const
|
|
299
|
+
{
|
|
300
|
+
const doResolve = deps.resolveAgentMcp || resolveAgentMcp;
|
|
241
301
|
try {
|
|
242
|
-
mcp = await
|
|
302
|
+
mcp = await doResolve(
|
|
303
|
+
{
|
|
304
|
+
mcpConfigPath: options.mcpConfig || null,
|
|
305
|
+
db: db?.getDatabase?.() || null,
|
|
306
|
+
includeRegistered: options.useRegisteredMcp !== false,
|
|
307
|
+
ide: options.ide,
|
|
308
|
+
cwd: options.cwd || process.cwd(),
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
writeErr,
|
|
312
|
+
loadMcpConfig: deps.loadMcpConfig,
|
|
313
|
+
loadRegisteredMcp: deps.loadRegisteredMcp,
|
|
314
|
+
loadIdeMcp: deps.loadIdeMcp,
|
|
315
|
+
},
|
|
316
|
+
);
|
|
243
317
|
} catch (err) {
|
|
244
318
|
emit({
|
|
245
319
|
type: "result",
|
|
@@ -281,6 +355,10 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
281
355
|
const loopOptionsBase = {
|
|
282
356
|
model,
|
|
283
357
|
provider,
|
|
358
|
+
// Extended thinking (Anthropic; opt-in via --think/--ultrathink).
|
|
359
|
+
// thinkingBudget (--thinking-budget) = legacy-model budget_tokens override.
|
|
360
|
+
thinking: options.thinking || null,
|
|
361
|
+
thinkingBudget: options.thinkingBudget || null,
|
|
284
362
|
baseUrl,
|
|
285
363
|
apiKey,
|
|
286
364
|
cwd,
|
|
@@ -288,6 +366,8 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
288
366
|
sessionId,
|
|
289
367
|
hookDb: db,
|
|
290
368
|
approvalGate,
|
|
369
|
+
permissionRules,
|
|
370
|
+
settingsHooks,
|
|
291
371
|
enabledToolNames,
|
|
292
372
|
disabledTools,
|
|
293
373
|
prepareCall: goalPrepareCallFn,
|
|
@@ -345,6 +425,35 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
345
425
|
for (const w of expanded.warnings) writeErr(` @ref: ${w}\n`);
|
|
346
426
|
}
|
|
347
427
|
|
|
428
|
+
// settings.json UserPromptSubmit hooks. block → skip this turn; context → inject.
|
|
429
|
+
if (settingsHooks) {
|
|
430
|
+
try {
|
|
431
|
+
const { runUserPromptSubmitHooks } = await import(
|
|
432
|
+
"../lib/settings-hook-events.cjs"
|
|
433
|
+
);
|
|
434
|
+
const ups = runUserPromptSubmitHooks(settingsHooks, {
|
|
435
|
+
prompt: userContent,
|
|
436
|
+
cwd,
|
|
437
|
+
sessionId,
|
|
438
|
+
});
|
|
439
|
+
if (ups.blocked) {
|
|
440
|
+
emit({
|
|
441
|
+
type: "result",
|
|
442
|
+
subtype: "blocked",
|
|
443
|
+
is_error: true,
|
|
444
|
+
result: ups.reason || "blocked by UserPromptSubmit hook",
|
|
445
|
+
session_id: sessionId,
|
|
446
|
+
});
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
if (ups.additionalContext) {
|
|
450
|
+
userContent += `\n\n[hook context]\n${ups.additionalContext}`;
|
|
451
|
+
}
|
|
452
|
+
} catch (_err) {
|
|
453
|
+
// settings hook dispatch is best-effort
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
348
457
|
messages.push({ role: "user", content: userContent });
|
|
349
458
|
turns += 1;
|
|
350
459
|
|
|
@@ -396,6 +505,23 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
396
505
|
}
|
|
397
506
|
}
|
|
398
507
|
|
|
508
|
+
// settings.json SessionEnd hooks (observe-only) when stdin closes.
|
|
509
|
+
if (settingsHooks) {
|
|
510
|
+
try {
|
|
511
|
+
const { runObserveHooks } = await import(
|
|
512
|
+
"../lib/settings-hook-events.cjs"
|
|
513
|
+
);
|
|
514
|
+
runObserveHooks(
|
|
515
|
+
settingsHooks,
|
|
516
|
+
"SessionEnd",
|
|
517
|
+
{ reason: "stdin_closed", cwd, session_id: sessionId },
|
|
518
|
+
{ cwd },
|
|
519
|
+
);
|
|
520
|
+
} catch {
|
|
521
|
+
// observe-only
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
399
525
|
emit({ type: "system", subtype: "end", session_id: sessionId, turns });
|
|
400
526
|
return { exitCode: sawError ? 1 : 0, turns };
|
|
401
527
|
}
|