chainlesschain 0.162.36 → 0.162.38

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 (160) hide show
  1. package/package.json +3 -2
  2. package/src/assets/web-panel/assets/{AIOps-vAVAFNJ4.js → AIOps-DV0Q9zKL.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BnRHFCKM.js → ActionButton-C6vH8rhL.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-BOjwqWqG.js → Analytics-BvPDc2ui.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-Dc0D1Txn.js → AppLayout-CWnyqTqY.js} +5 -5
  6. package/src/assets/web-panel/assets/{Audit-dd_2efaZ.js → Audit-BzenidV4.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-HF1jgm8G.js → Backup-CSl7bNwK.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-CCtzmoKe.js → BaseInput-DAY3iHIq.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-BNfH1c3p.js → Chat-Jyhm9fgk.js} +6 -6
  10. package/src/assets/web-panel/assets/{ChatBubbleRenderer-DCWFqmI4.js → ChatBubbleRenderer-CwlAnVjy.js} +1 -1
  11. package/src/assets/web-panel/assets/{Checkbox-BOr-NscK.js → Checkbox-D4rwURAi.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-DE058N7-.js → Codegen-DYdjTEfC.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-SOREo1XE.js → Col-DsVyZ_fS.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-sOvNZo9f.js → Community-CjCpl27Q.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-DnBe558D.js → Compact-kt18dsjm.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-o-r6CUbg.js → Compliance-BV5urquU.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-D6_k9mHP.js → Cowork-C4SovPWC.js} +3 -3
  18. package/src/assets/web-panel/assets/{Cron-CEV3Xkrm.js → Cron-uuNs_xzA.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-eJ1lQWKU.js → Crosschain-DR5a65tR.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-B-WqM9Hp.js → DID-B1KTf2-5.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-ZnKPcsHN.js → Dashboard-Dkj7XgED.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-B8uLWDIP.js → Dropdown-BhXCuJ19.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-Jmj2Y7aH.js → EmailListRenderer-DG8365Iv.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-Cb2xetG-.js → FamilyGuardDashboard-BdHGPu39.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-C_07GXoq.js → Federation-Dwvxl0zR.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-D3kbYrMU.js → FormItemContext-BVmhCVWU.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-9xgqvGPg.js → GenericCardRenderer-DDPjvF2s.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-BlwWlMMB.js → Git-foK6WTSr.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-DxN3wQZ_.js → Governance-CfqMdu6Y.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-ls7pSw_D.js → Inference-BKrLO4GO.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-_n9hYuPI.js → KnowledgeGraph-6o6Q-mmF.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-CvEVY5TK.js → Logs-L5ZIW0Dz.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-C3qvQJT7.js → Marketplace-BWkfEocP.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-DiwKpnKx.js → McpTools-BPebQbWU.js} +4 -4
  35. package/src/assets/web-panel/assets/{Memory-CIBPi_da.js → Memory-C0Dq-X3C.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-D-v0Se8y.js → MobileBridge-DRBoutTY.js} +2 -2
  37. package/src/assets/web-panel/assets/{MobileProjects-cP1apTQD.js → MobileProjects-BMP6eLp1.js} +1 -1
  38. package/src/assets/web-panel/assets/{Mtc-BMFWrI65.js → Mtc-Cj3QPM9p.js} +4 -4
  39. package/src/assets/web-panel/assets/{MtcAudit-2s8LaHtR.js → MtcAudit-rBQYbfQR.js} +2 -2
  40. package/src/assets/web-panel/assets/{Multisig-dL_nvj7d.js → Multisig-Dbuy4OY4.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-BbrJp06R.js → NLProgramming-CMnt1se-.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-jR9irwy3.js → Notes-BX9tSCiF.js} +4 -4
  43. package/src/assets/web-panel/assets/{NotificationSettings-Dk-STCIX.js → NotificationSettings-BFeirVRq.js} +1 -1
  44. package/src/assets/web-panel/assets/{OrderTableRenderer-CqqfY6zq.js → OrderTableRenderer-ybiMlKQW.js} +1 -1
  45. package/src/assets/web-panel/assets/{Organization-BCK5jylo.js → Organization-kTfRxKqk.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-BRAY7Smt.js → Overflow-CtuCAzwV.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-BltVRGjb.js → P2P-KfbciaP3.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-CV8UbXHe.js → PdhVaultBrowser-bqEUFhgC.js} +5 -5
  49. package/src/assets/web-panel/assets/{Permissions-_tNl47Qh.js → Permissions-BgMypz-z.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-Cgc4HjpX.js → PersonalDataHub-C3zUE-1z.js} +2 -2
  51. package/src/assets/web-panel/assets/{Pipeline-Bn_QU4mu.js → Pipeline-iX-pYHpC.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-jzJowp5P.js → Privacy-B01uzeFM.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-B_1pJ8qd.js → ProjectInit-TsfbzJp7.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-CPVZpXzs.js → ProjectSettings-iGvMp8sM.js} +2 -2
  55. package/src/assets/web-panel/assets/{Projects-CQsHOWnT.js → Projects-Be9k29iQ.js} +1 -1
  56. package/src/assets/web-panel/assets/{Providers-CzzMiLC0.js → Providers-C9Pc8dqo.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-MxBKIn9o.js → QuickAsk-DN_yFiVO.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-D8lN6Lis.js → Recommend-CvSNgl7H.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-CfYK-IrV.js → Reputation-S6BCz8xH.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-Bg7NZDP9.js → Row-CTRYCaqP.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-BOVNJhj0.js → RssFeed-Cu8_P5ll.js} +3 -3
  62. package/src/assets/web-panel/assets/{Search-B38qzmhY.js → Search-rZ1Xza_U.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-CjqleZpe.js → Security-CF43IJHX.js} +4 -4
  64. package/src/assets/web-panel/assets/{Services-Bu9JSJap.js → Services-BobNHzne.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-B2RvRkaX.js → Skeleton-DWJ2kfuI.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-_h42mxMN.js → Skills-AmEZgHYr.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-BssLs56D.js → Sla-DTS-fBiY.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-DCxFYHsd.js → SpeechSettings-DEr6MHRU.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-D2xQuNLE.js → SyncSettings-CVs9alv_.js} +2 -2
  70. package/src/assets/web-panel/assets/{Tasks-DhpOGOlo.js → Tasks-BcVDAxdi.js} +1 -1
  71. package/src/assets/web-panel/assets/{Templates-CYG-R-aS.js → Templates-CTNjZRKA.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-BQRYLsvP.js → Tenant-DPbXg0Pg.js} +1 -1
  73. package/src/assets/web-panel/assets/{Terminal-imKU7N5j.js → Terminal-DhKXcPw2.js} +2 -2
  74. package/src/assets/web-panel/assets/{TimelineRenderer-BIZzBftk.js → TimelineRenderer-B0DMZOpk.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-uMLH5p_a.js → Tokens-RvWuBXgg.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-BzS6XPqx.js → Trigger-2O-BaTQG.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-R4zhHufZ.js → Trust-6qY35L-C.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-DATQCoGe.js → UkeySign-DhV1wYtQ.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-ClUmKOtS.js → VideoEditing-DgqA5UZm.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-DzJTbQzD.js → Wallet-DJRYdUAK.js} +4 -4
  81. package/src/assets/web-panel/assets/{WebAuthn-CrXrLmzQ.js → WebAuthn-C2W-x0cg.js} +5 -5
  82. package/src/assets/web-panel/assets/{WorkflowEditor-CpvZ0Tma.js → WorkflowEditor-BP2tkDHe.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-a6wpYmVL.js → chat-CGVfeoTn.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-CXJADb1t.js → colors-BmjRolM1.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-CL2pohS_.js → compact-item-BvJJkjZE.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-xFi_1G5_.js → createContext-DyhlvRYs.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-CetO0WH0.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-Bchh1rAi.js → hasIn-BoBMR89s.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-C2eMYASq.js → index-39VDXdn6.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-CR3kFPuC.js → index-81tWFqfN.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-CTRd7vkq.js → index-BT1SQ9nj.js} +1 -1
  92. package/src/assets/web-panel/assets/index-BZVz-WfV.js +1 -0
  93. package/src/assets/web-panel/assets/{index-D-TT9Swq.js → index-Beh7jDbS.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-BrbJBnT-.js → index-Bm_MmdwP.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-dsLc7t6W.js → index-BqGNmoKy.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DEYcLAl7.js → index-BuQrONgf.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-KCib1PTw.js → index-BvvNnWXe.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DxahxRP7.js → index-ByWpNjTj.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-B6NehWty.js → index-BycpeGfj.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DTEu7TSF.js → index-C0xn6hOr.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BH9t10pe.js → index-C1t-r7yV.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-B7wT5VRi.js → index-CDPMHKQi.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-majCS3s2.js → index-CIaGw7vl.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-EPERz4Pu.js → index-CQJVedQ3.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-IkvkNxbc.js → index-CSgbOGaP.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DQ_hw_5P.js → index-Cbh-lCxq.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CMybtJY6.js → index-CzDVBBcg.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-B4zNisy9.js → index-Czsbrn75.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-M8SZI11a.js → index-D-93XwJd.js} +1 -1
  110. package/src/assets/web-panel/assets/index-D0-bvFy3.js +1 -0
  111. package/src/assets/web-panel/assets/{index-TxbHusq2.js → index-D0YToIi_.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-B7knYOpm.js → index-DIPZ6hbJ.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CGq4HQno.js → index-DeeLHcMY.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CdU8BwRW.js → index-DgbWSwr5.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-C4yBRKT4.js → index-DtKdCXHW.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-jMcv1u5o.js → index-DwTgvhOL.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-B3Tpv7-d.js → index-DyS4I4L-.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-u8K1y_lh.js → index-FKFT-QTk.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Cua_P8St.js → index-Te0ruvY_.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DVo1GJoj.js → index-VXVukhBA.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BPH5ESqs.js → index-Y1b8i0NV.js} +3 -3
  122. package/src/assets/web-panel/assets/{index-DsbMVBj1.js → index-ZNIms1nA.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BoaRB-4a.js → index-n-N19np-.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BmsIKzyu.js → index-vF1pR00A.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CuehgDOp.js → index-wLAjVpmJ.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DjdOL159.js → index-xPSzUoWT.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BF4xx1_b.js → index-xZdOioVg.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-DYn3Gc09.js → initDefaultProps-BLKSE8he.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-ZS3eolb9.js → motion-Bb59qqLK.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-CEw4uqr3.js → move-CB3pYCk6.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-DlHFZnPp.js → omit-iImQWuU7.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-eZQvV5fA.js → pickAttrs-DRP2Chqo.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-B31jQwa-.js → placementArrow-BrlfD4tF.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-DAsNmVto.js → responsiveObserve-Cqxkuh5H.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-gPQPrYZC.js → slide-nxKEuLMj.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-DwWKX5co.js → statusUtils-30E47KSk.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-B3VOtXuH.js → styleChecker-Dn2_-5bn.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-6ADctM2r.js → useFlexGapSupport-DkZ00X6F.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-6Zx1SSKs.js → useFs-ByrwSCOr.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-BzReowln.js → usePersonalDataHub-BDY6jtUD.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-C8IpEQbD.js → vnode-BL2q5BLv.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-ruc9vHr0.js → zoom-BSkPKE42.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/cli-anything.js +14 -6
  146. package/src/commands/loop.js +450 -0
  147. package/src/commands/mcp.js +236 -6
  148. package/src/harness/mcp-client.js +70 -1
  149. package/src/index.js +2 -0
  150. package/src/lib/loop.js +198 -0
  151. package/src/lib/settings-hooks.cjs +1 -0
  152. package/src/repl/agent-repl.js +57 -20
  153. package/src/repl/mcp-prompt.js +122 -0
  154. package/src/runtime/agent-core.js +123 -17
  155. package/src/runtime/headless-runner.js +34 -9
  156. package/src/runtime/mcp-config.js +118 -9
  157. package/src/runtime/policies/agent-policy.js +3 -0
  158. package/src/assets/web-panel/assets/devWarning-BtmELbtB.js +0 -1
  159. package/src/assets/web-panel/assets/index-B4l4vLTB.js +0 -1
  160. package/src/assets/web-panel/assets/index-B7Ek5iiY.js +0 -1
@@ -74,6 +74,7 @@ import { expandFileRefs } from "../runtime/file-ref-expander.js";
74
74
  import { composeSystemPrompt } from "../runtime/system-prompt.js";
75
75
  import { makeFallbackChatFn } from "../runtime/fallback-model.js";
76
76
  import { resolveSlashMacro } from "./slash-macro.js";
77
+ import { expandMcpPrompt, renderMcpSurface } from "./mcp-prompt.js";
77
78
 
78
79
  /**
79
80
  * Reference to the runtime DB for hook execution (set during startAgentRepl)
@@ -129,7 +130,8 @@ async function _persistAlwaysAllow(tool, args) {
129
130
  scope: "local",
130
131
  });
131
132
  if (!_permissionRules) _permissionRules = { allow: [], ask: [], deny: [] };
132
- if (!_permissionRules.allow.includes(rule)) _permissionRules.allow.push(rule);
133
+ if (!_permissionRules.allow.includes(rule))
134
+ _permissionRules.allow.push(rule);
133
135
  return { rule, file };
134
136
  } catch (err) {
135
137
  process.stderr.write(` always-allow persist failed: ${err.message}\n`);
@@ -504,9 +506,8 @@ export async function startAgentRepl(options = {}) {
504
506
  // settings.json SessionStart hooks → inject session context (observe-only).
505
507
  if (_settingsHooks) {
506
508
  try {
507
- const { runSessionStartHooks } = await import(
508
- "../lib/settings-hook-events.cjs"
509
- );
509
+ const { runSessionStartHooks } =
510
+ await import("../lib/settings-hook-events.cjs");
510
511
  const ctx = runSessionStartHooks(_settingsHooks, {
511
512
  source: "startup",
512
513
  cwd: process.cwd(),
@@ -630,6 +631,11 @@ export async function startAgentRepl(options = {}) {
630
631
  mcpConfigPath: options.mcpConfig || null,
631
632
  db: db?.getDatabase?.() || null,
632
633
  includeRegistered: options.useRegisteredMcp !== false,
634
+ // IDE bridge: auto-connect a running editor's MCP server when inside
635
+ // an IDE integrated terminal. --ide forces it, --no-ide disables it
636
+ // (parity with headless; auto-detect already works via process.env).
637
+ ide: options.ide,
638
+ cwd: process.cwd(),
633
639
  },
634
640
  { writeErr: (s) => process.stderr.write(s) },
635
641
  );
@@ -800,7 +806,8 @@ export async function startAgentRepl(options = {}) {
800
806
  if (_statusLineEnabled && _renderStatus) {
801
807
  const line = _renderStatus();
802
808
  // Built-in line is dimmed; a custom command may carry its own ANSI.
803
- if (line) process.stdout.write((_customStatus ? line : chalk.dim(line)) + "\n");
809
+ if (line)
810
+ process.stdout.write((_customStatus ? line : chalk.dim(line)) + "\n");
804
811
  }
805
812
  rl.setPrompt(getPrompt());
806
813
  rl.prompt();
@@ -1019,15 +1026,16 @@ export async function startAgentRepl(options = {}) {
1019
1026
  logger.info("Status line: on");
1020
1027
  } else {
1021
1028
  // bare / "show" → report state + a one-off render
1022
- const line = _statusLineEnabled && _renderStatus ? _renderStatus() : null;
1029
+ const line =
1030
+ _statusLineEnabled && _renderStatus ? _renderStatus() : null;
1023
1031
  if (line) {
1024
- logger.info(
1025
- `Status line: ${_customStatus ? line : chalk.dim(line)}`,
1026
- );
1032
+ logger.info(`Status line: ${_customStatus ? line : chalk.dim(line)}`);
1027
1033
  } else {
1028
1034
  logger.info(
1029
1035
  `Status line: ${_statusLineEnabled ? "on (no content yet)" : "off"}` +
1030
- (_statusLineEnabled ? "" : ` — enable with ${chalk.cyan("/statusline on")}`),
1036
+ (_statusLineEnabled
1037
+ ? ""
1038
+ : ` — enable with ${chalk.cyan("/statusline on")}`),
1031
1039
  );
1032
1040
  }
1033
1041
  if (_customStatus) {
@@ -1041,9 +1049,8 @@ export async function startAgentRepl(options = {}) {
1041
1049
  if (trimmed === "/output-style" || trimmed.startsWith("/output-style ")) {
1042
1050
  const arg = trimmed.slice("/output-style".length).trim();
1043
1051
  try {
1044
- const { discoverOutputStyles, getOutputStyle } = await import(
1045
- "../lib/output-styles.js"
1046
- );
1052
+ const { discoverOutputStyles, getOutputStyle } =
1053
+ await import("../lib/output-styles.js");
1047
1054
  if (!arg) {
1048
1055
  logger.log(chalk.bold("Output styles:"));
1049
1056
  for (const s of discoverOutputStyles(process.cwd())) {
@@ -1796,15 +1803,47 @@ export async function startAgentRepl(options = {}) {
1796
1803
  return;
1797
1804
  }
1798
1805
 
1806
+ // `/mcp` — overview of connected MCP servers' resources + prompts.
1807
+ if (trimmed === "/mcp" || trimmed === "/mcp ") {
1808
+ const mcpClient = _adhocMcp?.mcpClient || _bundleMcpClient;
1809
+ logger.log(renderMcpSurface(mcpClient));
1810
+ prompt();
1811
+ return;
1812
+ }
1813
+
1799
1814
  // User-defined slash-command macros (.claude/commands/*.md), Claude-Code
1800
1815
  // parity. resolveSlashMacro maps a leading /name to a command macro and
1801
1816
  // expands its template; a non-match returns the line unchanged so a literal
1802
1817
  // prompt like "/etc/hosts" still reaches the LLM. Wire is unit-tested.
1803
1818
  let promptText = trimmed;
1819
+
1820
+ // MCP server-provided prompts (Claude-Code parity): `/mcp__<server>__<name>
1821
+ // [json-args]` fetches a rendered prompt template from the connected MCP
1822
+ // server and uses its text as this turn's input. Falls through unchanged
1823
+ // when the line isn't an MCP prompt command.
1824
+ if (promptText.startsWith("/mcp__")) {
1825
+ try {
1826
+ const expanded = await expandMcpPrompt(
1827
+ promptText,
1828
+ _adhocMcp?.mcpClient || _bundleMcpClient,
1829
+ );
1830
+ if (expanded != null) {
1831
+ promptText = expanded;
1832
+ logger.log(chalk.gray(`[mcp] prompt expanded`));
1833
+ }
1834
+ } catch (err) {
1835
+ logger.info(
1836
+ chalk.yellow(`[mcp] prompt expansion failed: ${err.message}`),
1837
+ );
1838
+ prompt();
1839
+ return;
1840
+ }
1841
+ }
1804
1842
  try {
1805
1843
  const macro = await resolveSlashMacro(trimmed, { cwd: process.cwd() });
1806
1844
  if (macro.matched) {
1807
- for (const w of macro.warnings) logger.info(chalk.yellow(`[@ref] ${w}`));
1845
+ for (const w of macro.warnings)
1846
+ logger.info(chalk.yellow(`[@ref] ${w}`));
1808
1847
  promptText = macro.promptText;
1809
1848
  logger.log(
1810
1849
  chalk.gray(`[/${macro.name}] macro expanded (${macro.scope})`),
@@ -1859,9 +1898,8 @@ export async function startAgentRepl(options = {}) {
1859
1898
  // is observe-only). block → abort the turn; context → inject before the turn.
1860
1899
  if (_settingsHooks) {
1861
1900
  try {
1862
- const { runUserPromptSubmitHooks } = await import(
1863
- "../lib/settings-hook-events.cjs"
1864
- );
1901
+ const { runUserPromptSubmitHooks } =
1902
+ await import("../lib/settings-hook-events.cjs");
1865
1903
  const ups = runUserPromptSubmitHooks(_settingsHooks, {
1866
1904
  prompt: userContent,
1867
1905
  cwd: process.cwd(),
@@ -2131,9 +2169,8 @@ export async function startAgentRepl(options = {}) {
2131
2169
  // settings.json SessionEnd hooks (observe-only) when the REPL exits.
2132
2170
  if (_settingsHooks) {
2133
2171
  try {
2134
- const { runObserveHooks } = await import(
2135
- "../lib/settings-hook-events.cjs"
2136
- );
2172
+ const { runObserveHooks } =
2173
+ await import("../lib/settings-hook-events.cjs");
2137
2174
  runObserveHooks(
2138
2175
  _settingsHooks,
2139
2176
  "SessionEnd",
@@ -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,41 @@ 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
+
892
933
  return toolResult;
893
934
  }
894
935
 
@@ -1240,12 +1281,8 @@ async function executeToolInner(
1240
1281
  ...(task.error ? { error: task.error } : {}),
1241
1282
  stdout: out.text.substring(0, 30000),
1242
1283
  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
- : {}),
1284
+ ...(out.droppedGap ? { stdout_dropped_bytes: out.droppedGap } : {}),
1285
+ ...(err.droppedGap ? { stderr_dropped_bytes: err.droppedGap } : {}),
1249
1286
  ...(killed ? { killed: true } : {}),
1250
1287
  startedAt: task.startedAt,
1251
1288
  endedAt: task.endedAt,
@@ -1635,6 +1672,50 @@ async function executeToolInner(
1635
1672
  }
1636
1673
 
1637
1674
  default:
1675
+ if (localToolExecutor?.kind === "mcp-resource") {
1676
+ if (!mcpClient) {
1677
+ return attachDescriptor({
1678
+ error: `MCP client is unavailable for tool: ${name}`,
1679
+ });
1680
+ }
1681
+ try {
1682
+ if (localToolExecutor.op === "list") {
1683
+ const resources =
1684
+ typeof mcpClient.listResources === "function"
1685
+ ? mcpClient.listResources(args?.server || undefined)
1686
+ : [];
1687
+ return attachDescriptor({ count: resources.length, resources });
1688
+ }
1689
+ // op === "read"
1690
+ const uri = args?.uri;
1691
+ if (!uri || typeof uri !== "string") {
1692
+ return attachDescriptor({
1693
+ error: "read_mcp_resource requires a string 'uri' argument.",
1694
+ });
1695
+ }
1696
+ let server = args?.server;
1697
+ if (!server && typeof mcpClient.listResources === "function") {
1698
+ const match = mcpClient
1699
+ .listResources()
1700
+ .find((r) => r && r.uri === uri);
1701
+ server = match?.server;
1702
+ }
1703
+ if (!server) {
1704
+ return attachDescriptor({
1705
+ error: `Could not resolve which MCP server owns resource "${uri}". Pass 'server' explicitly.`,
1706
+ });
1707
+ }
1708
+ const result = await mcpClient.readResource(server, uri);
1709
+ return attachDescriptor(
1710
+ result && typeof result === "object" ? result : { result },
1711
+ );
1712
+ } catch (err) {
1713
+ return attachDescriptor({
1714
+ error: `MCP resource access failed: ${err.message}`,
1715
+ });
1716
+ }
1717
+ }
1718
+
1638
1719
  if (localToolExecutor?.kind === "mcp") {
1639
1720
  if (!mcpClient || typeof mcpClient.callTool !== "function") {
1640
1721
  return attachDescriptor({
@@ -2601,7 +2682,13 @@ export function _accumulateAnthropicStream(lines, onToken) {
2601
2682
  return _anthropicFinalize(state);
2602
2683
  }
2603
2684
 
2604
- async function _chatAnthropicStreaming(apiUrl, body, extraHeaders, onToken, signal) {
2685
+ async function _chatAnthropicStreaming(
2686
+ apiUrl,
2687
+ body,
2688
+ extraHeaders,
2689
+ onToken,
2690
+ signal,
2691
+ ) {
2605
2692
  const response = await fetch(apiUrl, {
2606
2693
  method: "POST",
2607
2694
  headers: { "Content-Type": "application/json", ...extraHeaders },
@@ -2663,10 +2750,12 @@ function _openaiReduceLine(state, raw, onToken) {
2663
2750
  if (Array.isArray(delta?.tool_calls)) {
2664
2751
  for (const tc of delta.tool_calls) {
2665
2752
  const idx = tc.index ?? 0;
2666
- if (!state.tools[idx]) state.tools[idx] = { id: undefined, name: "", args: "" };
2753
+ if (!state.tools[idx])
2754
+ state.tools[idx] = { id: undefined, name: "", args: "" };
2667
2755
  if (tc.id) state.tools[idx].id = tc.id;
2668
2756
  if (tc.function?.name) state.tools[idx].name = tc.function.name;
2669
- if (tc.function?.arguments) state.tools[idx].args += tc.function.arguments;
2757
+ if (tc.function?.arguments)
2758
+ state.tools[idx].args += tc.function.arguments;
2670
2759
  }
2671
2760
  }
2672
2761
  if (obj.usage) {
@@ -2702,7 +2791,14 @@ export function _accumulateOpenAIStream(lines, onToken) {
2702
2791
  return _openaiFinalize(state);
2703
2792
  }
2704
2793
 
2705
- async function _chatOpenAIStreaming(apiUrl, body, apiKey, onToken, signal, provider) {
2794
+ async function _chatOpenAIStreaming(
2795
+ apiUrl,
2796
+ body,
2797
+ apiKey,
2798
+ onToken,
2799
+ signal,
2800
+ provider,
2801
+ ) {
2706
2802
  const response = await fetch(apiUrl, {
2707
2803
  method: "POST",
2708
2804
  headers: {
@@ -2843,7 +2939,11 @@ function _intensityToEffort(want) {
2843
2939
  * RUNTIME-UNVERIFIED — no Anthropic key to validate the wire shape live.
2844
2940
  * Exported for tests.
2845
2941
  */
2846
- export function _anthropicThinkingParams(model, options = {}, maxTokens = 8192) {
2942
+ export function _anthropicThinkingParams(
2943
+ model,
2944
+ options = {},
2945
+ maxTokens = 8192,
2946
+ ) {
2847
2947
  const want = options?.thinking;
2848
2948
  if (!want) return null; // off by default → request unchanged
2849
2949
  const m = String(model || "").toLowerCase();
@@ -3181,7 +3281,11 @@ export async function* agentLoop(messages, options) {
3181
3281
  }
3182
3282
  }
3183
3283
  if (preCompactBlocked) {
3184
- yield { type: "compaction-skipped", runId, reason: preCompactReason };
3284
+ yield {
3285
+ type: "compaction-skipped",
3286
+ runId,
3287
+ reason: preCompactReason,
3288
+ };
3185
3289
  }
3186
3290
  const { messages: compacted, stats } = preCompactBlocked
3187
3291
  ? { messages, stats: { saved: 0 } }
@@ -3400,7 +3504,9 @@ export function formatToolArgs(name, args) {
3400
3504
  case "edit_file_hashed":
3401
3505
  return `${args.path} @${args.anchor_hash}`;
3402
3506
  case "run_shell":
3403
- return args.run_in_background ? `${args.command} (background)` : args.command;
3507
+ return args.run_in_background
3508
+ ? `${args.command} (background)`
3509
+ : args.command;
3404
3510
  case "check_shell":
3405
3511
  return args.task_id
3406
3512
  ? `${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,
@@ -766,9 +792,8 @@ export async function runAgentHeadless(options = {}, deps = {}) {
766
792
  // settings.json SessionEnd hooks (observe-only) when the run finishes.
767
793
  if (settingsHooks) {
768
794
  try {
769
- const { runObserveHooks } = await import(
770
- "../lib/settings-hook-events.cjs"
771
- );
795
+ const { runObserveHooks } =
796
+ await import("../lib/settings-hook-events.cjs");
772
797
  runObserveHooks(
773
798
  settingsHooks,
774
799
  "SessionEnd",