chainlesschain 0.162.37 → 0.162.39
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 +3 -2
- package/src/assets/web-panel/assets/{AIOps-_oxz4VHy.js → AIOps-DCjoAX_u.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-uaeqFuDj.js → ActionButton-XHoOmsbP.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BPVV0OUf.js → Analytics--xaFkDnL.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-ppCYKm3I.js → AppLayout-CSa3FBn8.js} +4 -4
- package/src/assets/web-panel/assets/{Audit-DFAY6umk.js → Audit-ONWXiAwG.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-pAPBFDyP.js → Backup-CKOPNdgy.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BbBl0uT2.js → BaseInput-PNj4uVqg.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Ct22JUnT.js → Chat-CZCulyXV.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-DPlsLl22.js → ChatBubbleRenderer-CjuJpfpV.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DEkCollc.js → Checkbox-jvy668lD.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Tor-de39.js → Codegen-DhUebOQD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-ojNrLQU7.js → Col-BiBvHfdT.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CLOGhqMF.js → Community-CmEdEti-.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CYKNlSZ4.js → Compact-CtxpF4R5.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-C5E6ABuA.js → Compliance-CvPTrTAJ.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CHeEsZ3W.js → Cowork-BMafGHjy.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-B4e1n2e7.js → Cron-mdg_4TR1.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DbNV8P9R.js → Crosschain--dGxsUvn.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C5_Tk3nC.js → DID-C9oKaCml.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-BhdV_c4N.js → Dashboard-CoGxKMvy.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CEi5AMtM.js → Dropdown-CDDu3ZZ3.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DOhPiYng.js → EmailListRenderer-Dy7_r9Ag.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-fu4NRP3X.js → FamilyGuardDashboard-CNg6vImJ.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B7BtIWKL.js → Federation-CT61bf3u.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BmPWZVLP.js → FormItemContext-CSLRnXhg.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-hsOPNJq8.js → GenericCardRenderer-CZ4NE5N3.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Bi_EFBUH.js → Git-DBuOma3L.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-emf2ubDK.js → Governance-BTU_SEef.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-B7KjKzkI.js → Inference-47SAmLC_.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-uAaBK0F3.js → KnowledgeGraph-DCrK5vP4.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-utK7hNpj.js → Logs-BqiDxdav.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-CzQe6n3z.js → Marketplace-CReUjsDt.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CuAaJr51.js → McpTools-agZBV3p8.js} +6 -6
- package/src/assets/web-panel/assets/{Memory-CRuZZJ75.js → Memory-C_YvUtyS.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Cp06wunh.js → MobileBridge-41fP1Tui.js} +3 -3
- package/src/assets/web-panel/assets/{MobileProjects-DJEdUwhr.js → MobileProjects-BkqLvGfL.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-8YY4dR7g.js → Mtc-JFJCXUnk.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BmPJYHar.js → MtcAudit-BHNpPZC9.js} +6 -6
- package/src/assets/web-panel/assets/{Multisig-d-ydyVdq.js → Multisig-DuCRumiz.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DA_ikw_n.js → NLProgramming-DK-g0fKY.js} +1 -1
- package/src/assets/web-panel/assets/Notes-BSMcjsPf.js +7 -0
- package/src/assets/web-panel/assets/{NotificationSettings-CzPZXEtK.js → NotificationSettings-9ouC118H.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-LG2nUO5y.js +1 -0
- package/src/assets/web-panel/assets/{Organization-DdDZ_Ap6.js → Organization-DSV7oRnR.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BnMBkttv.js → Overflow-DVkkORc3.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Es1050f-.js → P2P-BXXjkkQD.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CKkRmyn9.js → PdhVaultBrowser-O5hNnLTP.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-zU9n9cAD.js → Permissions-D_s0H5Av.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BZi5Xwas.js → PersonalDataHub-CzMDrwUi.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-CRfeGiFc.js → Pipeline-i9krLVTL.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CQA_IgLA.js → Privacy-cMQcj9I8.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-C9hmEvoT.js → ProjectInit-Ca_l7avo.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-yXA72ws4.js → ProjectSettings-BkaIhd6b.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BpWS-qam.js → Projects-Dy9yNmDg.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Cxe55dRD.js → Providers-D0nzYiqz.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Do0aUTQr.js → QuickAsk-Bzzr9d0f.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend--ysZHjyA.js → Recommend-C-UFbQnX.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-BOBU8JrH.js → Reputation-BKMIKO5F.js} +1 -1
- package/src/assets/web-panel/assets/{Row-C6X7bRKE.js → Row-Bs7htK1T.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-D8AwqlkQ.js → RssFeed-v6MdULUh.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Bi3rCZD4.js → Search-DlRWYzvz.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DxUDVrtY.js → Security-DXWO37xX.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BXXN7yC1.js → Services-C2tWA-O0.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-B3BR34tZ.js → Skeleton-Q8pIYY4a.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BjYu8OQ1.js → Skills-D7XBlErj.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DDkCtD8w.js → Sla-CiyMVPJ1.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CGhYzP7V.js → SpeechSettings-CadCeeiR.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CYNKVAHA.js → SyncSettings-DzNAUhQq.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-BjdHjZeb.js +1 -0
- package/src/assets/web-panel/assets/{Templates-CQuYFf2C.js → Templates-DfgEpUa4.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DdzZh8vE.js → Tenant-C8ajkuYi.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-B9rHwQQx.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-DKOARnc_.js → TimelineRenderer-D1ZVNezX.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-D7QRNG8y.js → Tokens-CAkED4mx.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BCsqLZl4.js → Trigger-CJSrm6X0.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BarGUa6p.js → Trust-B-TeorSk.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-pHrg5a8E.js → UkeySign-Di7Ymofy.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Dug3m1py.js → VideoEditing-DM1eYNZe.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BfK3Z_Ez.js → Wallet-DvRWkbmR.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CYRdl9td.js → WebAuthn-CeZ3Y622.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-DTW5AcqM.js → WorkflowEditor-Cq8c4h5j.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CCXz4j38.js → chat-7-WfML6Q.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BJBOhAqa.js → colors-D6FgCmB-.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-E9M6BQcM.js → compact-item-ClYV25qi.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Cg9CAws4.js → createContext-CDhtjdkV.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-O0FVFeZg.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DhVtqv5L.js → hasIn-DZSH5LQd.js} +1 -1
- package/src/assets/web-panel/assets/{index-_PNqQ5mE.js → index---azBCXl.js} +1 -1
- package/src/assets/web-panel/assets/index--ANIKvhL.js +1 -0
- package/src/assets/web-panel/assets/{index-kz1oXl1a.js → index-B13QnrnE.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-2dUIli.js → index-B4PMzmOx.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ca8BYV1g.js → index-B6VWGnwq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFZPRd0T.js → index-B78X5S22.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dwvewrul.js → index-BHeK8I5A.js} +1 -1
- package/src/assets/web-panel/assets/{index-MdXEhfdJ.js → index-BJ7mrOaB.js} +1 -1
- package/src/assets/web-panel/assets/{index--7o5YdL6.js → index-BUOPjAUM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFp-wdrQ.js → index-B_mMFQ4S.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdhnGez0.js → index-Bj8hZiyL.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUp_c8Le.js → index-BlBF_l8m.js} +1 -1
- package/src/assets/web-panel/assets/{index-6-04M2Nx.js → index-BpzOUiSb.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByazO4Q9.js → index-BqOIoEo6.js} +1 -1
- package/src/assets/web-panel/assets/{index-ComyTKz-.js → index-C7pQa2is.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cm1m7BJh.js → index-C7sC56w8.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4NBF4Sa.js → index-CDX4QU3k.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSQazU6J.js → index-CKgS8E_X.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAB0nGP7.js → index-CSjoWPxB.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8bjEHrQ.js → index-CWOkL-8O.js} +1 -1
- package/src/assets/web-panel/assets/{index-CznfPnOx.js → index-CmU631Je.js} +3 -3
- package/src/assets/web-panel/assets/{index-D7DXdf7x.js → index-CrTmxbL8.js} +1 -1
- package/src/assets/web-panel/assets/{index-wkt-o5q5.js → index-CxwfFZ1u.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxSzyly9.js → index-D0YzTJJO.js} +1 -1
- package/src/assets/web-panel/assets/{index-4N5lNXGP.js → index-DGJK8D0l.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaFe1aqY.js → index-DGj1orXm.js} +1 -1
- package/src/assets/web-panel/assets/{index-Di5LBXcE.js → index-DL6GFJAd.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_SMPD4L.js → index-DLizxxId.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSiyjCYi.js → index-DPEYvNvq.js} +1 -1
- package/src/assets/web-panel/assets/index-DUfp4rnQ.js +1 -0
- package/src/assets/web-panel/assets/{index-D5yC2Ps8.js → index-DWRoh3_3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDcJO27F.js → index-DZ4zuoCP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJ8nNT8h.js → index-DgaF1F0W.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChsSljaN.js → index-Di9pFrHV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFarAlXj.js → index-DjG82V0v.js} +1 -1
- package/src/assets/web-panel/assets/{index-B111fZ21.js → index-Or_McYjX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVR_s-pT.js → index-rCs9VJJp.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkTeBHI9.js → index-tU6pZ1TP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeRlLp3F.js → index-z-R0KaJS.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-iyBaePF-.js → initDefaultProps-CSdsIGy3.js} +1 -1
- package/src/assets/web-panel/assets/{motion-RWtj4rgu.js → motion-Do-AcZV4.js} +1 -1
- package/src/assets/web-panel/assets/{move-CqPRVzpH.js → move-BmgOoMsi.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DsvJze25.js → omit-D4Tm7-s9.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-B4tfZBhc.js → pickAttrs-CuWA8-lj.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-KvHUwXMA.js → placementArrow-BSbEF5op.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DGdJ-b7W.js → responsiveObserve-GIMJwB_9.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Cd6ebRmw.js → slide-DlZxpIBe.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Bg9GcIAn.js → statusUtils-BZ26LPlh.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-MQjKsG84.js → styleChecker-Yn_3FZ0l.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C241WujP.js → useFlexGapSupport-O_LOE1AB.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CMpy7RS4.js → useFs-VFMyQqtl.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BLHtapKb.js → usePersonalDataHub-B_hyrGB-.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DmcTV67c.js → vnode-D4LttGy7.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DHL8_0Y8.js → zoom-KnTK1fjj.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +31 -0
- package/src/commands/mcp.js +236 -6
- package/src/harness/mcp-client.js +70 -1
- package/src/lib/ide-context.js +271 -0
- package/src/lib/repl-completer.js +139 -0
- package/src/lib/settings-hooks.cjs +1 -0
- package/src/repl/agent-repl.js +88 -20
- package/src/repl/mcp-prompt.js +122 -0
- package/src/runtime/agent-core.js +156 -17
- package/src/runtime/headless-runner.js +53 -9
- package/src/runtime/headless-stream.js +19 -9
- package/src/runtime/mcp-config.js +118 -9
- package/src/assets/web-panel/assets/Notes-DIyF-fRe.js +0 -7
- package/src/assets/web-panel/assets/OrderTableRenderer-BiLtg-LY.js +0 -1
- package/src/assets/web-panel/assets/Tasks-DavmlJpd.js +0 -1
- package/src/assets/web-panel/assets/Terminal-D75WeG9d.js +0 -3
- package/src/assets/web-panel/assets/devWarning-BrsbTJUv.js +0 -1
- package/src/assets/web-panel/assets/index-DSTQDO-Y.js +0 -1
- package/src/assets/web-panel/assets/index-c2U6LV3Q.js +0 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP prompt + resource surfacing for the agent REPL (Claude-Code parity).
|
|
3
|
+
*
|
|
4
|
+
* MCP servers can expose "prompts" — server-defined, parameterized prompt
|
|
5
|
+
* templates — which Claude Code surfaces as slash commands of the form
|
|
6
|
+
* `/mcp__<server>__<prompt>`. This module is the pure, unit-testable core:
|
|
7
|
+
* it parses such a command, fetches the rendered prompt from the connected
|
|
8
|
+
* MCP client, and flattens it into plain text to use as the user's turn.
|
|
9
|
+
*
|
|
10
|
+
* It also renders a `/mcp` overview of every connected server's resources and
|
|
11
|
+
* prompts. The REPL (agent-repl.js) wires these in; all the logic lives here so
|
|
12
|
+
* it can be tested without spinning up a readline session.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parse a `/mcp__<server>__<prompt> [args]` line. Returns `{ server, name,
|
|
17
|
+
* args }` or `null` when the line is not an MCP prompt invocation.
|
|
18
|
+
*
|
|
19
|
+
* `args` is parsed from a trailing JSON object when present; a non-JSON tail is
|
|
20
|
+
* passed as `{ input: "<tail>" }` so simple one-arg prompts stay ergonomic.
|
|
21
|
+
*/
|
|
22
|
+
export function parseMcpPromptCommand(line) {
|
|
23
|
+
const trimmed = (line || "").trim();
|
|
24
|
+
if (!trimmed.startsWith("/mcp__")) return null;
|
|
25
|
+
|
|
26
|
+
const sp = trimmed.search(/\s/);
|
|
27
|
+
const token = sp === -1 ? trimmed : trimmed.slice(0, sp);
|
|
28
|
+
const rest = sp === -1 ? "" : trimmed.slice(sp + 1).trim();
|
|
29
|
+
|
|
30
|
+
const full = token.slice(1); // drop leading "/"
|
|
31
|
+
const parts = full.split("__"); // ["mcp", "<server>", "<prompt...>"]
|
|
32
|
+
if (parts.length < 3 || parts[0] !== "mcp") return null;
|
|
33
|
+
const server = parts[1];
|
|
34
|
+
const name = parts.slice(2).join("__");
|
|
35
|
+
if (!server || !name) return null;
|
|
36
|
+
|
|
37
|
+
let args = {};
|
|
38
|
+
if (rest) {
|
|
39
|
+
try {
|
|
40
|
+
const parsed = JSON.parse(rest);
|
|
41
|
+
args =
|
|
42
|
+
parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
43
|
+
? parsed
|
|
44
|
+
: { input: rest };
|
|
45
|
+
} catch {
|
|
46
|
+
args = { input: rest };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { server, name, args };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Flatten an MCP `prompts/get` result (`{ messages: [...] }`) into plain text.
|
|
54
|
+
* Handles text blocks and embedded text resources; ignores binary blocks.
|
|
55
|
+
*/
|
|
56
|
+
export function renderPromptMessages(result) {
|
|
57
|
+
const messages = Array.isArray(result?.messages) ? result.messages : [];
|
|
58
|
+
const out = [];
|
|
59
|
+
for (const msg of messages) {
|
|
60
|
+
const blocks = Array.isArray(msg?.content) ? msg.content : [msg?.content];
|
|
61
|
+
for (const b of blocks) {
|
|
62
|
+
if (!b) continue;
|
|
63
|
+
if (b.type === "text" && typeof b.text === "string") {
|
|
64
|
+
out.push(b.text);
|
|
65
|
+
} else if (
|
|
66
|
+
b.type === "resource" &&
|
|
67
|
+
b.resource &&
|
|
68
|
+
typeof b.resource.text === "string"
|
|
69
|
+
) {
|
|
70
|
+
out.push(b.resource.text);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return out.join("\n\n");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Expand a `/mcp__server__prompt` line into prompt text by calling the MCP
|
|
79
|
+
* client. Returns the rendered text, or `null` when the line is not an MCP
|
|
80
|
+
* prompt command. Throws if the underlying `getPrompt` fails (caller decides
|
|
81
|
+
* whether to surface or swallow).
|
|
82
|
+
*/
|
|
83
|
+
export async function expandMcpPrompt(line, mcpClient) {
|
|
84
|
+
const cmd = parseMcpPromptCommand(line);
|
|
85
|
+
if (!cmd) return null;
|
|
86
|
+
if (!mcpClient || typeof mcpClient.getPrompt !== "function") {
|
|
87
|
+
throw new Error("No MCP servers are connected this session.");
|
|
88
|
+
}
|
|
89
|
+
const result = await mcpClient.getPrompt(cmd.server, cmd.name, cmd.args);
|
|
90
|
+
return renderPromptMessages(result);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Render a human overview of all connected MCP resources + prompts for `/mcp`.
|
|
95
|
+
*/
|
|
96
|
+
export function renderMcpSurface(mcpClient) {
|
|
97
|
+
if (!mcpClient) return "No MCP servers are connected this session.";
|
|
98
|
+
const resources =
|
|
99
|
+
typeof mcpClient.listResources === "function"
|
|
100
|
+
? mcpClient.listResources()
|
|
101
|
+
: [];
|
|
102
|
+
const prompts =
|
|
103
|
+
typeof mcpClient.listPrompts === "function" ? mcpClient.listPrompts() : [];
|
|
104
|
+
|
|
105
|
+
const lines = [];
|
|
106
|
+
lines.push(`MCP resources (${resources.length}):`);
|
|
107
|
+
for (const r of resources) {
|
|
108
|
+
lines.push(` ${r.uri} [${r.server}]${r.name ? " — " + r.name : ""}`);
|
|
109
|
+
}
|
|
110
|
+
lines.push("");
|
|
111
|
+
lines.push(`MCP prompts (${prompts.length}):`);
|
|
112
|
+
for (const p of prompts) {
|
|
113
|
+
lines.push(
|
|
114
|
+
` /mcp__${p.server}__${p.name}${p.description ? " — " + p.description : ""}`,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (resources.length === 0 && prompts.length === 0) {
|
|
118
|
+
lines.push("");
|
|
119
|
+
lines.push("(connected servers expose no resources or prompts)");
|
|
120
|
+
}
|
|
121
|
+
return lines.join("\n");
|
|
122
|
+
}
|
|
@@ -222,7 +222,10 @@ async function runSettingsPreToolUseHooks(name, args, context, cwd) {
|
|
|
222
222
|
cwd,
|
|
223
223
|
session_id: context.sessionId || null,
|
|
224
224
|
};
|
|
225
|
-
const outcome = runCommandHooks(matched, payload, {
|
|
225
|
+
const outcome = runCommandHooks(matched, payload, {
|
|
226
|
+
cwd,
|
|
227
|
+
event: "PreToolUse",
|
|
228
|
+
});
|
|
226
229
|
if (outcome.decision === "block") {
|
|
227
230
|
return { blocked: true, reason: outcome.reason, hook: outcome.hook };
|
|
228
231
|
}
|
|
@@ -234,8 +237,7 @@ async function runSettingsPreToolUseHooks(name, args, context, cwd) {
|
|
|
234
237
|
tool: name,
|
|
235
238
|
args,
|
|
236
239
|
rule: `hook:${outcome.hook}`,
|
|
237
|
-
reason:
|
|
238
|
-
outcome.reason || "a PreToolUse hook requests confirmation",
|
|
240
|
+
reason: outcome.reason || "a PreToolUse hook requests confirmation",
|
|
239
241
|
})
|
|
240
242
|
: false;
|
|
241
243
|
return ok
|
|
@@ -730,7 +732,11 @@ export async function executeTool(name, args, context = {}) {
|
|
|
730
732
|
if (!ok) {
|
|
731
733
|
return {
|
|
732
734
|
error: `[Permission] Tool "${name}" requires confirmation (settings rule: ${settingsVerdict.rule}) — denied.`,
|
|
733
|
-
policy: {
|
|
735
|
+
policy: {
|
|
736
|
+
decision: "ask",
|
|
737
|
+
rule: settingsVerdict.rule,
|
|
738
|
+
via: "settings",
|
|
739
|
+
},
|
|
734
740
|
};
|
|
735
741
|
}
|
|
736
742
|
ruleAllowed = true; // confirmed → treat like allow downstream
|
|
@@ -889,6 +895,74 @@ export async function executeTool(name, args, context = {}) {
|
|
|
889
895
|
}
|
|
890
896
|
}
|
|
891
897
|
|
|
898
|
+
// settings.json SubagentStop hooks: fire when a `spawn_sub_agent` tool call
|
|
899
|
+
// finishes (Claude-Code SubagentStop parity). The subagent has already
|
|
900
|
+
// returned its summary, so this is observe + feedback rather than force-
|
|
901
|
+
// continue: a `block` reason is surfaced to the PARENT agent as hookFeedback
|
|
902
|
+
// so it can react (e.g. re-spawn or adjust), mirroring PostToolUse.
|
|
903
|
+
if (
|
|
904
|
+
name === "spawn_sub_agent" &&
|
|
905
|
+
context.settingsHooks &&
|
|
906
|
+
toolResult &&
|
|
907
|
+
typeof toolResult === "object"
|
|
908
|
+
) {
|
|
909
|
+
try {
|
|
910
|
+
const outcome = runObserveHooks(
|
|
911
|
+
context.settingsHooks,
|
|
912
|
+
"SubagentStop",
|
|
913
|
+
{
|
|
914
|
+
stop_hook_active: false,
|
|
915
|
+
session_id: context.sessionId || null,
|
|
916
|
+
subagent_response:
|
|
917
|
+
typeof toolResult === "object"
|
|
918
|
+
? JSON.stringify(toolResult).substring(0, 2000)
|
|
919
|
+
: String(toolResult).substring(0, 2000),
|
|
920
|
+
},
|
|
921
|
+
{ cwd },
|
|
922
|
+
);
|
|
923
|
+
if (outcome.decision === "block" && outcome.reason) {
|
|
924
|
+
toolResult.hookFeedback = toolResult.hookFeedback
|
|
925
|
+
? `${toolResult.hookFeedback}\n${outcome.reason}`
|
|
926
|
+
: outcome.reason;
|
|
927
|
+
}
|
|
928
|
+
} catch (_err) {
|
|
929
|
+
// SubagentStop hooks are best-effort
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// IDE post-edit diagnostics (Claude-Code parity): after a successful file
|
|
934
|
+
// mutation with an IDE bridge connected, pull the editor's fresh
|
|
935
|
+
// error/warning diagnostics for that file into the tool result so the model
|
|
936
|
+
// can fix what it just broke in the same loop. Best-effort, bounded;
|
|
937
|
+
// CC_IDE_CONTEXT=0 disables alongside prompt-time context.
|
|
938
|
+
if (
|
|
939
|
+
(name === "write_file" ||
|
|
940
|
+
name === "edit_file" ||
|
|
941
|
+
name === "edit_file_hashed") &&
|
|
942
|
+
toolResult &&
|
|
943
|
+
typeof toolResult === "object" &&
|
|
944
|
+
!toolResult.error &&
|
|
945
|
+
args?.path &&
|
|
946
|
+
context.mcpClient &&
|
|
947
|
+
context.externalToolExecutors
|
|
948
|
+
) {
|
|
949
|
+
try {
|
|
950
|
+
const { collectIdeDiagnostics, formatIdeDiagnostics } =
|
|
951
|
+
await import("../lib/ide-context.js");
|
|
952
|
+
const diags = await collectIdeDiagnostics(
|
|
953
|
+
{
|
|
954
|
+
mcpClient: context.mcpClient,
|
|
955
|
+
externalToolExecutors: context.externalToolExecutors,
|
|
956
|
+
},
|
|
957
|
+
path.resolve(cwd, args.path),
|
|
958
|
+
);
|
|
959
|
+
const feedback = formatIdeDiagnostics(diags);
|
|
960
|
+
if (feedback) toolResult.ideDiagnostics = feedback;
|
|
961
|
+
} catch (_err) {
|
|
962
|
+
// diagnostics feedback is optional polish — never fail the tool
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
892
966
|
return toolResult;
|
|
893
967
|
}
|
|
894
968
|
|
|
@@ -1240,12 +1314,8 @@ async function executeToolInner(
|
|
|
1240
1314
|
...(task.error ? { error: task.error } : {}),
|
|
1241
1315
|
stdout: out.text.substring(0, 30000),
|
|
1242
1316
|
stderr: err.text.substring(0, 30000),
|
|
1243
|
-
...(out.droppedGap
|
|
1244
|
-
|
|
1245
|
-
: {}),
|
|
1246
|
-
...(err.droppedGap
|
|
1247
|
-
? { stderr_dropped_bytes: err.droppedGap }
|
|
1248
|
-
: {}),
|
|
1317
|
+
...(out.droppedGap ? { stdout_dropped_bytes: out.droppedGap } : {}),
|
|
1318
|
+
...(err.droppedGap ? { stderr_dropped_bytes: err.droppedGap } : {}),
|
|
1249
1319
|
...(killed ? { killed: true } : {}),
|
|
1250
1320
|
startedAt: task.startedAt,
|
|
1251
1321
|
endedAt: task.endedAt,
|
|
@@ -1635,6 +1705,50 @@ async function executeToolInner(
|
|
|
1635
1705
|
}
|
|
1636
1706
|
|
|
1637
1707
|
default:
|
|
1708
|
+
if (localToolExecutor?.kind === "mcp-resource") {
|
|
1709
|
+
if (!mcpClient) {
|
|
1710
|
+
return attachDescriptor({
|
|
1711
|
+
error: `MCP client is unavailable for tool: ${name}`,
|
|
1712
|
+
});
|
|
1713
|
+
}
|
|
1714
|
+
try {
|
|
1715
|
+
if (localToolExecutor.op === "list") {
|
|
1716
|
+
const resources =
|
|
1717
|
+
typeof mcpClient.listResources === "function"
|
|
1718
|
+
? mcpClient.listResources(args?.server || undefined)
|
|
1719
|
+
: [];
|
|
1720
|
+
return attachDescriptor({ count: resources.length, resources });
|
|
1721
|
+
}
|
|
1722
|
+
// op === "read"
|
|
1723
|
+
const uri = args?.uri;
|
|
1724
|
+
if (!uri || typeof uri !== "string") {
|
|
1725
|
+
return attachDescriptor({
|
|
1726
|
+
error: "read_mcp_resource requires a string 'uri' argument.",
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
let server = args?.server;
|
|
1730
|
+
if (!server && typeof mcpClient.listResources === "function") {
|
|
1731
|
+
const match = mcpClient
|
|
1732
|
+
.listResources()
|
|
1733
|
+
.find((r) => r && r.uri === uri);
|
|
1734
|
+
server = match?.server;
|
|
1735
|
+
}
|
|
1736
|
+
if (!server) {
|
|
1737
|
+
return attachDescriptor({
|
|
1738
|
+
error: `Could not resolve which MCP server owns resource "${uri}". Pass 'server' explicitly.`,
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
const result = await mcpClient.readResource(server, uri);
|
|
1742
|
+
return attachDescriptor(
|
|
1743
|
+
result && typeof result === "object" ? result : { result },
|
|
1744
|
+
);
|
|
1745
|
+
} catch (err) {
|
|
1746
|
+
return attachDescriptor({
|
|
1747
|
+
error: `MCP resource access failed: ${err.message}`,
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1638
1752
|
if (localToolExecutor?.kind === "mcp") {
|
|
1639
1753
|
if (!mcpClient || typeof mcpClient.callTool !== "function") {
|
|
1640
1754
|
return attachDescriptor({
|
|
@@ -2601,7 +2715,13 @@ export function _accumulateAnthropicStream(lines, onToken) {
|
|
|
2601
2715
|
return _anthropicFinalize(state);
|
|
2602
2716
|
}
|
|
2603
2717
|
|
|
2604
|
-
async function _chatAnthropicStreaming(
|
|
2718
|
+
async function _chatAnthropicStreaming(
|
|
2719
|
+
apiUrl,
|
|
2720
|
+
body,
|
|
2721
|
+
extraHeaders,
|
|
2722
|
+
onToken,
|
|
2723
|
+
signal,
|
|
2724
|
+
) {
|
|
2605
2725
|
const response = await fetch(apiUrl, {
|
|
2606
2726
|
method: "POST",
|
|
2607
2727
|
headers: { "Content-Type": "application/json", ...extraHeaders },
|
|
@@ -2663,10 +2783,12 @@ function _openaiReduceLine(state, raw, onToken) {
|
|
|
2663
2783
|
if (Array.isArray(delta?.tool_calls)) {
|
|
2664
2784
|
for (const tc of delta.tool_calls) {
|
|
2665
2785
|
const idx = tc.index ?? 0;
|
|
2666
|
-
if (!state.tools[idx])
|
|
2786
|
+
if (!state.tools[idx])
|
|
2787
|
+
state.tools[idx] = { id: undefined, name: "", args: "" };
|
|
2667
2788
|
if (tc.id) state.tools[idx].id = tc.id;
|
|
2668
2789
|
if (tc.function?.name) state.tools[idx].name = tc.function.name;
|
|
2669
|
-
if (tc.function?.arguments)
|
|
2790
|
+
if (tc.function?.arguments)
|
|
2791
|
+
state.tools[idx].args += tc.function.arguments;
|
|
2670
2792
|
}
|
|
2671
2793
|
}
|
|
2672
2794
|
if (obj.usage) {
|
|
@@ -2702,7 +2824,14 @@ export function _accumulateOpenAIStream(lines, onToken) {
|
|
|
2702
2824
|
return _openaiFinalize(state);
|
|
2703
2825
|
}
|
|
2704
2826
|
|
|
2705
|
-
async function _chatOpenAIStreaming(
|
|
2827
|
+
async function _chatOpenAIStreaming(
|
|
2828
|
+
apiUrl,
|
|
2829
|
+
body,
|
|
2830
|
+
apiKey,
|
|
2831
|
+
onToken,
|
|
2832
|
+
signal,
|
|
2833
|
+
provider,
|
|
2834
|
+
) {
|
|
2706
2835
|
const response = await fetch(apiUrl, {
|
|
2707
2836
|
method: "POST",
|
|
2708
2837
|
headers: {
|
|
@@ -2843,7 +2972,11 @@ function _intensityToEffort(want) {
|
|
|
2843
2972
|
* RUNTIME-UNVERIFIED — no Anthropic key to validate the wire shape live.
|
|
2844
2973
|
* Exported for tests.
|
|
2845
2974
|
*/
|
|
2846
|
-
export function _anthropicThinkingParams(
|
|
2975
|
+
export function _anthropicThinkingParams(
|
|
2976
|
+
model,
|
|
2977
|
+
options = {},
|
|
2978
|
+
maxTokens = 8192,
|
|
2979
|
+
) {
|
|
2847
2980
|
const want = options?.thinking;
|
|
2848
2981
|
if (!want) return null; // off by default → request unchanged
|
|
2849
2982
|
const m = String(model || "").toLowerCase();
|
|
@@ -3181,7 +3314,11 @@ export async function* agentLoop(messages, options) {
|
|
|
3181
3314
|
}
|
|
3182
3315
|
}
|
|
3183
3316
|
if (preCompactBlocked) {
|
|
3184
|
-
yield {
|
|
3317
|
+
yield {
|
|
3318
|
+
type: "compaction-skipped",
|
|
3319
|
+
runId,
|
|
3320
|
+
reason: preCompactReason,
|
|
3321
|
+
};
|
|
3185
3322
|
}
|
|
3186
3323
|
const { messages: compacted, stats } = preCompactBlocked
|
|
3187
3324
|
? { messages, stats: { saved: 0 } }
|
|
@@ -3400,7 +3537,9 @@ export function formatToolArgs(name, args) {
|
|
|
3400
3537
|
case "edit_file_hashed":
|
|
3401
3538
|
return `${args.path} @${args.anchor_hash}`;
|
|
3402
3539
|
case "run_shell":
|
|
3403
|
-
return args.run_in_background
|
|
3540
|
+
return args.run_in_background
|
|
3541
|
+
? `${args.command} (background)`
|
|
3542
|
+
: args.command;
|
|
3404
3543
|
case "check_shell":
|
|
3405
3544
|
return args.task_id
|
|
3406
3545
|
? `${args.task_id}${args.kill ? " (kill)" : ""}`
|
|
@@ -176,6 +176,34 @@ export function resolveHeadlessSession(options = {}, store = {}, fallbackId) {
|
|
|
176
176
|
return { sessionId: id, resumeId, persist, wantLatest };
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Apply `--fork-session`: when a session has been resolved (resume/continue) and
|
|
181
|
+
* a fork is requested, branch its JSONL transcript into a NEW id so the original
|
|
182
|
+
* stays untouched (Claude-Code `--fork-session` parity). The copy carries the
|
|
183
|
+
* full prior history, so a later `--resume <newId>` replays the whole branch.
|
|
184
|
+
*
|
|
185
|
+
* Returns the id to use downstream + the source (`forkedFrom`), or the original
|
|
186
|
+
* id unchanged with `missing:true` when there is no transcript to fork. Pure
|
|
187
|
+
* apart from the injected store's side effect; both `sessionExists`/`forkSession`
|
|
188
|
+
* are injection seams so this is unit-testable without disk.
|
|
189
|
+
*
|
|
190
|
+
* @param {{forkSession?:boolean, sessionId?:string|null}} opts
|
|
191
|
+
* @param {{sessionExists?:Function, forkSession?:Function}} store
|
|
192
|
+
* @returns {{ sessionId:string|null, forkedFrom:string|null, missing:boolean }}
|
|
193
|
+
*/
|
|
194
|
+
export function applyForkSession(opts = {}, store = {}) {
|
|
195
|
+
const want = opts.forkSession === true;
|
|
196
|
+
const id = opts.sessionId || null;
|
|
197
|
+
if (!want || !id) return { sessionId: id, forkedFrom: null, missing: false };
|
|
198
|
+
if (typeof store.sessionExists === "function" && !store.sessionExists(id)) {
|
|
199
|
+
return { sessionId: id, forkedFrom: null, missing: true };
|
|
200
|
+
}
|
|
201
|
+
const newId =
|
|
202
|
+
typeof store.forkSession === "function" ? store.forkSession(id) : null;
|
|
203
|
+
if (!newId) return { sessionId: id, forkedFrom: null, missing: false };
|
|
204
|
+
return { sessionId: newId, forkedFrom: id, missing: false };
|
|
205
|
+
}
|
|
206
|
+
|
|
179
207
|
/**
|
|
180
208
|
* Run a single headless agentic turn.
|
|
181
209
|
*
|
|
@@ -404,9 +432,8 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
404
432
|
// settings.json UserPromptSubmit hooks. block → abort the run; context → inject.
|
|
405
433
|
if (settingsHooks) {
|
|
406
434
|
try {
|
|
407
|
-
const { runUserPromptSubmitHooks } =
|
|
408
|
-
"../lib/settings-hook-events.cjs"
|
|
409
|
-
);
|
|
435
|
+
const { runUserPromptSubmitHooks } =
|
|
436
|
+
await import("../lib/settings-hook-events.cjs");
|
|
410
437
|
const ups = runUserPromptSubmitHooks(settingsHooks, {
|
|
411
438
|
prompt: userContent,
|
|
412
439
|
cwd,
|
|
@@ -434,9 +461,8 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
434
461
|
let sessionStartContext = null;
|
|
435
462
|
if (settingsHooks) {
|
|
436
463
|
try {
|
|
437
|
-
const { runSessionStartHooks } =
|
|
438
|
-
"../lib/settings-hook-events.cjs"
|
|
439
|
-
);
|
|
464
|
+
const { runSessionStartHooks } =
|
|
465
|
+
await import("../lib/settings-hook-events.cjs");
|
|
440
466
|
sessionStartContext = runSessionStartHooks(settingsHooks, {
|
|
441
467
|
source: resumeId ? "resume" : "startup",
|
|
442
468
|
cwd,
|
|
@@ -520,6 +546,25 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
520
546
|
}
|
|
521
547
|
}
|
|
522
548
|
|
|
549
|
+
// IDE live context (Claude-Code parity): when an IDE bridge is connected,
|
|
550
|
+
// share the editor's selection/active file/open tabs with this turn. Appended
|
|
551
|
+
// to the in-flight user message only — AFTER persistence — so a resumed
|
|
552
|
+
// session replays the prompt, not a stale editor snapshot. Best-effort with
|
|
553
|
+
// a short timeout; CC_IDE_CONTEXT=0 disables.
|
|
554
|
+
try {
|
|
555
|
+
const { buildIdePromptContext, appendTextToContent } =
|
|
556
|
+
await import("../lib/ide-context.js");
|
|
557
|
+
const ideCtx = await (deps.buildIdePromptContext || buildIdePromptContext)(
|
|
558
|
+
mcp,
|
|
559
|
+
);
|
|
560
|
+
if (ideCtx) {
|
|
561
|
+
const last = messages[messages.length - 1];
|
|
562
|
+
last.content = appendTextToContent(last.content, ideCtx);
|
|
563
|
+
}
|
|
564
|
+
} catch {
|
|
565
|
+
// IDE context is optional polish — never fail the run over it.
|
|
566
|
+
}
|
|
567
|
+
|
|
523
568
|
// --permission-prompt-tool: route every CONFIRM-tier approval to an MCP tool
|
|
524
569
|
// (loaded via --mcp-config) instead of headless fail-closed. Overrides the
|
|
525
570
|
// permission-mode confirmer on the gate for this session.
|
|
@@ -766,9 +811,8 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
766
811
|
// settings.json SessionEnd hooks (observe-only) when the run finishes.
|
|
767
812
|
if (settingsHooks) {
|
|
768
813
|
try {
|
|
769
|
-
const { runObserveHooks } =
|
|
770
|
-
"../lib/settings-hook-events.cjs"
|
|
771
|
-
);
|
|
814
|
+
const { runObserveHooks } =
|
|
815
|
+
await import("../lib/settings-hook-events.cjs");
|
|
772
816
|
runObserveHooks(
|
|
773
817
|
settingsHooks,
|
|
774
818
|
"SessionEnd",
|
|
@@ -245,9 +245,8 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
245
245
|
// settings.json SessionStart hooks → inject session context once (observe-only).
|
|
246
246
|
if (settingsHooks) {
|
|
247
247
|
try {
|
|
248
|
-
const { runSessionStartHooks } =
|
|
249
|
-
"../lib/settings-hook-events.cjs"
|
|
250
|
-
);
|
|
248
|
+
const { runSessionStartHooks } =
|
|
249
|
+
await import("../lib/settings-hook-events.cjs");
|
|
251
250
|
const ctx = runSessionStartHooks(settingsHooks, {
|
|
252
251
|
source: "startup",
|
|
253
252
|
cwd,
|
|
@@ -428,9 +427,8 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
428
427
|
// settings.json UserPromptSubmit hooks. block → skip this turn; context → inject.
|
|
429
428
|
if (settingsHooks) {
|
|
430
429
|
try {
|
|
431
|
-
const { runUserPromptSubmitHooks } =
|
|
432
|
-
"../lib/settings-hook-events.cjs"
|
|
433
|
-
);
|
|
430
|
+
const { runUserPromptSubmitHooks } =
|
|
431
|
+
await import("../lib/settings-hook-events.cjs");
|
|
434
432
|
const ups = runUserPromptSubmitHooks(settingsHooks, {
|
|
435
433
|
prompt: userContent,
|
|
436
434
|
cwd,
|
|
@@ -454,6 +452,19 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
454
452
|
}
|
|
455
453
|
}
|
|
456
454
|
|
|
455
|
+
// IDE live context (Claude-Code parity): re-shared on every turn while an
|
|
456
|
+
// IDE bridge is connected — the user's selection moves between prompts.
|
|
457
|
+
// Best-effort; CC_IDE_CONTEXT=0 disables.
|
|
458
|
+
try {
|
|
459
|
+
const { buildIdePromptContext } = await import("../lib/ide-context.js");
|
|
460
|
+
const ideCtx = await (
|
|
461
|
+
deps.buildIdePromptContext || buildIdePromptContext
|
|
462
|
+
)(mcp);
|
|
463
|
+
if (ideCtx) userContent += `\n\n${ideCtx}`;
|
|
464
|
+
} catch {
|
|
465
|
+
// optional polish — never fail the turn over it
|
|
466
|
+
}
|
|
467
|
+
|
|
457
468
|
messages.push({ role: "user", content: userContent });
|
|
458
469
|
turns += 1;
|
|
459
470
|
|
|
@@ -508,9 +519,8 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
508
519
|
// settings.json SessionEnd hooks (observe-only) when stdin closes.
|
|
509
520
|
if (settingsHooks) {
|
|
510
521
|
try {
|
|
511
|
-
const { runObserveHooks } =
|
|
512
|
-
"../lib/settings-hook-events.cjs"
|
|
513
|
-
);
|
|
522
|
+
const { runObserveHooks } =
|
|
523
|
+
await import("../lib/settings-hook-events.cjs");
|
|
514
524
|
runObserveHooks(
|
|
515
525
|
settingsHooks,
|
|
516
526
|
"SessionEnd",
|