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.
Files changed (162) hide show
  1. package/package.json +3 -2
  2. package/src/assets/web-panel/assets/{AIOps-_oxz4VHy.js → AIOps-DCjoAX_u.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-uaeqFuDj.js → ActionButton-XHoOmsbP.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-BPVV0OUf.js → Analytics--xaFkDnL.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-ppCYKm3I.js → AppLayout-CSa3FBn8.js} +4 -4
  6. package/src/assets/web-panel/assets/{Audit-DFAY6umk.js → Audit-ONWXiAwG.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-pAPBFDyP.js → Backup-CKOPNdgy.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-BbBl0uT2.js → BaseInput-PNj4uVqg.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-Ct22JUnT.js → Chat-CZCulyXV.js} +6 -6
  10. package/src/assets/web-panel/assets/{ChatBubbleRenderer-DPlsLl22.js → ChatBubbleRenderer-CjuJpfpV.js} +1 -1
  11. package/src/assets/web-panel/assets/{Checkbox-DEkCollc.js → Checkbox-jvy668lD.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-Tor-de39.js → Codegen-DhUebOQD.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-ojNrLQU7.js → Col-BiBvHfdT.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-CLOGhqMF.js → Community-CmEdEti-.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-CYKNlSZ4.js → Compact-CtxpF4R5.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-C5E6ABuA.js → Compliance-CvPTrTAJ.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-CHeEsZ3W.js → Cowork-BMafGHjy.js} +2 -2
  18. package/src/assets/web-panel/assets/{Cron-B4e1n2e7.js → Cron-mdg_4TR1.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-DbNV8P9R.js → Crosschain--dGxsUvn.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-C5_Tk3nC.js → DID-C9oKaCml.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-BhdV_c4N.js → Dashboard-CoGxKMvy.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-CEi5AMtM.js → Dropdown-CDDu3ZZ3.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-DOhPiYng.js → EmailListRenderer-Dy7_r9Ag.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-fu4NRP3X.js → FamilyGuardDashboard-CNg6vImJ.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-B7BtIWKL.js → Federation-CT61bf3u.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-BmPWZVLP.js → FormItemContext-CSLRnXhg.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-hsOPNJq8.js → GenericCardRenderer-CZ4NE5N3.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-Bi_EFBUH.js → Git-DBuOma3L.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-emf2ubDK.js → Governance-BTU_SEef.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-B7KjKzkI.js → Inference-47SAmLC_.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-uAaBK0F3.js → KnowledgeGraph-DCrK5vP4.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-utK7hNpj.js → Logs-BqiDxdav.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-CzQe6n3z.js → Marketplace-CReUjsDt.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-CuAaJr51.js → McpTools-agZBV3p8.js} +6 -6
  35. package/src/assets/web-panel/assets/{Memory-CRuZZJ75.js → Memory-C_YvUtyS.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-Cp06wunh.js → MobileBridge-41fP1Tui.js} +3 -3
  37. package/src/assets/web-panel/assets/{MobileProjects-DJEdUwhr.js → MobileProjects-BkqLvGfL.js} +1 -1
  38. package/src/assets/web-panel/assets/{Mtc-8YY4dR7g.js → Mtc-JFJCXUnk.js} +5 -5
  39. package/src/assets/web-panel/assets/{MtcAudit-BmPJYHar.js → MtcAudit-BHNpPZC9.js} +6 -6
  40. package/src/assets/web-panel/assets/{Multisig-d-ydyVdq.js → Multisig-DuCRumiz.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-DA_ikw_n.js → NLProgramming-DK-g0fKY.js} +1 -1
  42. package/src/assets/web-panel/assets/Notes-BSMcjsPf.js +7 -0
  43. package/src/assets/web-panel/assets/{NotificationSettings-CzPZXEtK.js → NotificationSettings-9ouC118H.js} +1 -1
  44. package/src/assets/web-panel/assets/OrderTableRenderer-LG2nUO5y.js +1 -0
  45. package/src/assets/web-panel/assets/{Organization-DdDZ_Ap6.js → Organization-DSV7oRnR.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-BnMBkttv.js → Overflow-DVkkORc3.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-Es1050f-.js → P2P-BXXjkkQD.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-CKkRmyn9.js → PdhVaultBrowser-O5hNnLTP.js} +3 -3
  49. package/src/assets/web-panel/assets/{Permissions-zU9n9cAD.js → Permissions-D_s0H5Av.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-BZi5Xwas.js → PersonalDataHub-CzMDrwUi.js} +3 -3
  51. package/src/assets/web-panel/assets/{Pipeline-CRfeGiFc.js → Pipeline-i9krLVTL.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-CQA_IgLA.js → Privacy-cMQcj9I8.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-C9hmEvoT.js → ProjectInit-Ca_l7avo.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-yXA72ws4.js → ProjectSettings-BkaIhd6b.js} +2 -2
  55. package/src/assets/web-panel/assets/{Projects-BpWS-qam.js → Projects-Dy9yNmDg.js} +1 -1
  56. package/src/assets/web-panel/assets/{Providers-Cxe55dRD.js → Providers-D0nzYiqz.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-Do0aUTQr.js → QuickAsk-Bzzr9d0f.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend--ysZHjyA.js → Recommend-C-UFbQnX.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-BOBU8JrH.js → Reputation-BKMIKO5F.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-C6X7bRKE.js → Row-Bs7htK1T.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-D8AwqlkQ.js → RssFeed-v6MdULUh.js} +3 -3
  62. package/src/assets/web-panel/assets/{Search-Bi3rCZD4.js → Search-DlRWYzvz.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-DxUDVrtY.js → Security-DXWO37xX.js} +4 -4
  64. package/src/assets/web-panel/assets/{Services-BXXN7yC1.js → Services-C2tWA-O0.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-B3BR34tZ.js → Skeleton-Q8pIYY4a.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-BjYu8OQ1.js → Skills-D7XBlErj.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-DDkCtD8w.js → Sla-CiyMVPJ1.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-CGhYzP7V.js → SpeechSettings-CadCeeiR.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-CYNKVAHA.js → SyncSettings-DzNAUhQq.js} +2 -2
  70. package/src/assets/web-panel/assets/Tasks-BjdHjZeb.js +1 -0
  71. package/src/assets/web-panel/assets/{Templates-CQuYFf2C.js → Templates-DfgEpUa4.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-DdzZh8vE.js → Tenant-C8ajkuYi.js} +1 -1
  73. package/src/assets/web-panel/assets/Terminal-B9rHwQQx.js +3 -0
  74. package/src/assets/web-panel/assets/{TimelineRenderer-DKOARnc_.js → TimelineRenderer-D1ZVNezX.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-D7QRNG8y.js → Tokens-CAkED4mx.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-BCsqLZl4.js → Trigger-CJSrm6X0.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-BarGUa6p.js → Trust-B-TeorSk.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-pHrg5a8E.js → UkeySign-Di7Ymofy.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-Dug3m1py.js → VideoEditing-DM1eYNZe.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-BfK3Z_Ez.js → Wallet-DvRWkbmR.js} +4 -4
  81. package/src/assets/web-panel/assets/{WebAuthn-CYRdl9td.js → WebAuthn-CeZ3Y622.js} +5 -5
  82. package/src/assets/web-panel/assets/{WorkflowEditor-DTW5AcqM.js → WorkflowEditor-Cq8c4h5j.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-CCXz4j38.js → chat-7-WfML6Q.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-BJBOhAqa.js → colors-D6FgCmB-.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-E9M6BQcM.js → compact-item-ClYV25qi.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-Cg9CAws4.js → createContext-CDhtjdkV.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-O0FVFeZg.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-DhVtqv5L.js → hasIn-DZSH5LQd.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-_PNqQ5mE.js → index---azBCXl.js} +1 -1
  90. package/src/assets/web-panel/assets/index--ANIKvhL.js +1 -0
  91. package/src/assets/web-panel/assets/{index-kz1oXl1a.js → index-B13QnrnE.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-C-2dUIli.js → index-B4PMzmOx.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-Ca8BYV1g.js → index-B6VWGnwq.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-BFZPRd0T.js → index-B78X5S22.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Dwvewrul.js → index-BHeK8I5A.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-MdXEhfdJ.js → index-BJ7mrOaB.js} +1 -1
  97. package/src/assets/web-panel/assets/{index--7o5YdL6.js → index-BUOPjAUM.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CFp-wdrQ.js → index-B_mMFQ4S.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DdhnGez0.js → index-Bj8hZiyL.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CUp_c8Le.js → index-BlBF_l8m.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-6-04M2Nx.js → index-BpzOUiSb.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-ByazO4Q9.js → index-BqOIoEo6.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-ComyTKz-.js → index-C7pQa2is.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Cm1m7BJh.js → index-C7sC56w8.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B4NBF4Sa.js → index-CDX4QU3k.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DSQazU6J.js → index-CKgS8E_X.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BAB0nGP7.js → index-CSjoWPxB.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-B8bjEHrQ.js → index-CWOkL-8O.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CznfPnOx.js → index-CmU631Je.js} +3 -3
  110. package/src/assets/web-panel/assets/{index-D7DXdf7x.js → index-CrTmxbL8.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-wkt-o5q5.js → index-CxwfFZ1u.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BxSzyly9.js → index-D0YzTJJO.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-4N5lNXGP.js → index-DGJK8D0l.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DaFe1aqY.js → index-DGj1orXm.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Di5LBXcE.js → index-DL6GFJAd.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B_SMPD4L.js → index-DLizxxId.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CSiyjCYi.js → index-DPEYvNvq.js} +1 -1
  118. package/src/assets/web-panel/assets/index-DUfp4rnQ.js +1 -0
  119. package/src/assets/web-panel/assets/{index-D5yC2Ps8.js → index-DWRoh3_3.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DDcJO27F.js → index-DZ4zuoCP.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CJ8nNT8h.js → index-DgaF1F0W.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-ChsSljaN.js → index-Di9pFrHV.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CFarAlXj.js → index-DjG82V0v.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-B111fZ21.js → index-Or_McYjX.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CVR_s-pT.js → index-rCs9VJJp.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CkTeBHI9.js → index-tU6pZ1TP.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CeRlLp3F.js → index-z-R0KaJS.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-iyBaePF-.js → initDefaultProps-CSdsIGy3.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-RWtj4rgu.js → motion-Do-AcZV4.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-CqPRVzpH.js → move-BmgOoMsi.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-DsvJze25.js → omit-D4Tm7-s9.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-B4tfZBhc.js → pickAttrs-CuWA8-lj.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-KvHUwXMA.js → placementArrow-BSbEF5op.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-DGdJ-b7W.js → responsiveObserve-GIMJwB_9.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-Cd6ebRmw.js → slide-DlZxpIBe.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-Bg9GcIAn.js → statusUtils-BZ26LPlh.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-MQjKsG84.js → styleChecker-Yn_3FZ0l.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-C241WujP.js → useFlexGapSupport-O_LOE1AB.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-CMpy7RS4.js → useFs-VFMyQqtl.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-BLHtapKb.js → usePersonalDataHub-B_hyrGB-.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-DmcTV67c.js → vnode-D4LttGy7.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-DHL8_0Y8.js → zoom-KnTK1fjj.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/agent.js +31 -0
  145. package/src/commands/mcp.js +236 -6
  146. package/src/harness/mcp-client.js +70 -1
  147. package/src/lib/ide-context.js +271 -0
  148. package/src/lib/repl-completer.js +139 -0
  149. package/src/lib/settings-hooks.cjs +1 -0
  150. package/src/repl/agent-repl.js +88 -20
  151. package/src/repl/mcp-prompt.js +122 -0
  152. package/src/runtime/agent-core.js +156 -17
  153. package/src/runtime/headless-runner.js +53 -9
  154. package/src/runtime/headless-stream.js +19 -9
  155. package/src/runtime/mcp-config.js +118 -9
  156. package/src/assets/web-panel/assets/Notes-DIyF-fRe.js +0 -7
  157. package/src/assets/web-panel/assets/OrderTableRenderer-BiLtg-LY.js +0 -1
  158. package/src/assets/web-panel/assets/Tasks-DavmlJpd.js +0 -1
  159. package/src/assets/web-panel/assets/Terminal-D75WeG9d.js +0 -3
  160. package/src/assets/web-panel/assets/devWarning-BrsbTJUv.js +0 -1
  161. package/src/assets/web-panel/assets/index-DSTQDO-Y.js +0 -1
  162. 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, { cwd, event: "PreToolUse" });
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: { decision: "ask", rule: settingsVerdict.rule, via: "settings" },
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
- ? { stdout_dropped_bytes: out.droppedGap }
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(apiUrl, body, extraHeaders, onToken, signal) {
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]) state.tools[idx] = { id: undefined, name: "", args: "" };
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) state.tools[idx].args += 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(apiUrl, body, apiKey, onToken, signal, provider) {
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(model, options = {}, maxTokens = 8192) {
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 { type: "compaction-skipped", runId, reason: preCompactReason };
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 ? `${args.command} (background)` : args.command;
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 } = await import(
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 } = await import(
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 } = await import(
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 } = await import(
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 } = await import(
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 } = await import(
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",