@code-yeongyu/senpi 2026.10.25-2 → 2026.10.25-3
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/CHANGELOG.md +20 -0
- package/dist/bundle/chunks/{args-JXULI4EH.js → args-B444OQBK.js} +1 -1
- package/dist/bundle/chunks/{auth-4NUNUSTF.js → auth-C77UQA55.js} +1 -1
- package/dist/bundle/chunks/chunk-6O4SEW2W.js +5 -0
- package/dist/bundle/chunks/{chunk-Y5OTHMXO.js → chunk-7CNOCJCN.js} +1 -1
- package/dist/bundle/chunks/{chunk-JRXKLIEQ.js → chunk-7W7OJDIY.js} +4 -4
- package/dist/bundle/chunks/chunk-AX72VNRS.js +27 -0
- package/dist/bundle/chunks/{chunk-LYGAV6KU.js → chunk-C5UFJ7B3.js} +1 -1
- package/dist/bundle/chunks/{chunk-G2UETS2R.js → chunk-CNL6QSUB.js} +4 -4
- package/dist/bundle/chunks/{chunk-2EFVQWXZ.js → chunk-FFQOEC76.js} +3 -3
- package/dist/bundle/chunks/chunk-H3HNMY2W.js +13 -0
- package/dist/bundle/chunks/{chunk-W2BKZBYJ.js → chunk-HVJI5T75.js} +1 -1
- package/dist/bundle/chunks/{chunk-YN7ELQ43.js → chunk-JA2R2ZSE.js} +1 -1
- package/dist/bundle/chunks/chunk-JPGT64RV.js +2 -0
- package/dist/bundle/chunks/chunk-KXB5WIS5.js +4 -0
- package/dist/bundle/chunks/chunk-L73UYAH5.js +3 -0
- package/dist/bundle/chunks/chunk-LTU6UFEX.js +2 -0
- package/dist/bundle/chunks/{chunk-KUE4AQN6.js → chunk-MJ5NNWX4.js} +1 -1
- package/dist/bundle/chunks/{chunk-WFXUCVIR.js → chunk-O3Q2ET6W.js} +2 -5
- package/dist/bundle/chunks/{chunk-MXZPAUFB.js → chunk-ODTGC6YU.js} +1 -1
- package/dist/bundle/chunks/chunk-P3M2PF6K.js +27 -0
- package/dist/bundle/chunks/{chunk-VNN2V74Y.js → chunk-SWJXRC2I.js} +1 -1
- package/dist/bundle/chunks/{chunk-RXKNOEQQ.js → chunk-UQNRW3VU.js} +1 -1
- package/dist/bundle/chunks/{chunk-U67ML6CQ.js → chunk-WD6WBYC5.js} +1 -1
- package/dist/bundle/chunks/chunk-WJOT3DFL.js +2 -0
- package/dist/bundle/chunks/{chunk-XBUSVKWC.js → chunk-WLHNEUGD.js} +1 -1
- package/dist/bundle/chunks/chunk-YI7SPFDN.js +5 -0
- package/dist/bundle/chunks/{chunk-J2U5VDG7.js → chunk-YRF4I43T.js} +28 -28
- package/dist/bundle/chunks/chunk-Z3UYNSVR.js +3 -0
- package/dist/bundle/chunks/cli-main-HEKFFB5S.js +3 -0
- package/dist/bundle/chunks/{client-KWTLTKVV.js → client-WTYEICLH.js} +3 -3
- package/dist/bundle/chunks/dispatch-NYAULNVW.js +9 -0
- package/dist/bundle/chunks/{help-fast-path-ZHZGXAUG.js → help-fast-path-3Z26DQSV.js} +1 -1
- package/dist/bundle/chunks/host-command-Z3WPHJOW.js +2 -0
- package/dist/bundle/chunks/host-lifecycle-ONQIMWMX.js +3 -0
- package/dist/bundle/chunks/host-lifecycle.js +7 -5
- package/dist/bundle/chunks/host-session-command-J65ENSV5.js +20 -0
- package/dist/bundle/chunks/{host-socket-request-AS2OCRLP.js → host-socket-request-3CWE4265.js} +1 -1
- package/dist/bundle/chunks/interactive-mode-DEPQC6TX.js +2 -0
- package/dist/bundle/chunks/mcp-presenter-bootstrap-XUSCQVRC.js +2 -0
- package/dist/bundle/chunks/{multi-session-host-VTTY5MFT.js → multi-session-host-YI2WZOET.js} +12 -9
- package/dist/bundle/chunks/{package-manager-cli-DZFOC3MF.js → package-manager-cli-GHZPJMRF.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-U7YQMC7H.js → rotation-stream-ZPVCFOVD.js} +1 -1
- package/dist/bundle/chunks/rpc-mode-ORHBGBBV.js +2 -0
- package/dist/bundle/chunks/{rpc-monitor-source-B5NQ4ZVH.js → rpc-monitor-source-FFEQS744.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-SLISTG4V.js → schedule-command-YWG6D6ZF.js} +1 -1
- package/dist/bundle/chunks/session-control-endpoint-36HAQSQO.js +3 -0
- package/dist/bundle/chunks/{session-picker-465FVXQG.js → session-picker-25H5KNYP.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +278 -264
- package/dist/bundle/chunks/{stdio-IEC635SY.js → stdio-YXDKKKQZ.js} +1 -1
- package/dist/bundle/chunks/{streamableHttp-KJI5KE4K.js → streamableHttp-DKIBUWVY.js} +1 -1
- package/dist/bundle/chunks/{types-LLNV23LW.js → types-BJUEQ4II.js} +1 -1
- package/dist/bundle/chunks/zod-compat-RJDXCU7S.js +2 -0
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +7 -5
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.js +9 -0
- package/dist/cli/host-command-args.d.ts +1 -0
- package/dist/cli/host-command-args.js +7 -1
- package/dist/cli/host-command.js +3 -1
- package/dist/core/agent-session.js +22 -7
- package/dist/core/extensions/builtin/goal/index.js +1 -0
- package/dist/core/extensions/builtin/goal/lifecycle-facts.d.ts +3 -0
- package/dist/core/extensions/builtin/mcp/catalog.d.ts +3 -1
- package/dist/core/extensions/builtin/mcp/catalog.js +2 -0
- package/dist/core/extensions/builtin/mcp/connection.d.ts +1 -0
- package/dist/core/extensions/builtin/mcp/connection.js +46 -1
- package/dist/core/extensions/builtin/mcp/elicitation.d.ts +6 -1
- package/dist/core/extensions/builtin/mcp/elicitation.js +56 -2
- package/dist/core/extensions/builtin/mcp/expose/call.js +6 -2
- package/dist/core/extensions/builtin/mcp/expose/session.d.ts +4 -1
- package/dist/core/extensions/builtin/mcp/expose/session.js +7 -0
- package/dist/core/extensions/builtin/mcp/health.js +5 -0
- package/dist/core/extensions/builtin/mcp/host-registry.js +7 -1
- package/dist/core/extensions/builtin/mcp/index.js +2 -0
- package/dist/core/extensions/builtin/mcp/modern/client.d.ts +5 -0
- package/dist/core/extensions/builtin/mcp/modern/client.js +15 -0
- package/dist/core/extensions/builtin/mcp/modern/consent-queue.d.ts +2 -0
- package/dist/core/extensions/builtin/mcp/modern/consent-queue.js +59 -0
- package/dist/core/extensions/builtin/mcp/modern/diagnostics.d.ts +4 -0
- package/dist/core/extensions/builtin/mcp/modern/diagnostics.js +39 -0
- package/dist/core/extensions/builtin/mcp/modern/dispatch.js +21 -11
- package/dist/core/extensions/builtin/mcp/modern/elicitation.d.ts +14 -0
- package/dist/core/extensions/builtin/mcp/modern/elicitation.js +145 -0
- package/dist/core/extensions/builtin/mcp/modern/errors.d.ts +21 -0
- package/dist/core/extensions/builtin/mcp/modern/errors.js +23 -0
- package/dist/core/extensions/builtin/mcp/modern/form-schema.d.ts +20 -0
- package/dist/core/extensions/builtin/mcp/modern/form-schema.js +153 -0
- package/dist/core/extensions/builtin/mcp/modern/http-fetch.d.ts +3 -1
- package/dist/core/extensions/builtin/mcp/modern/http-fetch.js +8 -2
- package/dist/core/extensions/builtin/mcp/modern/inputs.d.ts +11 -0
- package/dist/core/extensions/builtin/mcp/modern/inputs.js +65 -0
- package/dist/core/extensions/builtin/mcp/modern/parameter-headers.d.ts +11 -0
- package/dist/core/extensions/builtin/mcp/modern/parameter-headers.js +109 -0
- package/dist/core/extensions/builtin/mcp/modern/request.d.ts +20 -0
- package/dist/core/extensions/builtin/mcp/modern/request.js +292 -0
- package/dist/core/extensions/builtin/mcp/modern/stdio-probe.d.ts +1 -1
- package/dist/core/extensions/builtin/mcp/modern/stdio-probe.js +54 -6
- package/dist/core/extensions/builtin/mcp/modern/transport.js +80 -14
- package/dist/core/extensions/builtin/mcp/modern/wire.js +11 -7
- package/dist/core/extensions/builtin/mcp/prompts.d.ts +5 -1
- package/dist/core/extensions/builtin/mcp/prompts.js +6 -1
- package/dist/core/extensions/builtin/mcp/request-origin.d.ts +47 -0
- package/dist/core/extensions/builtin/mcp/request-origin.js +59 -0
- package/dist/core/extensions/builtin/mcp/resources.d.ts +4 -1
- package/dist/core/extensions/builtin/mcp/resources.js +19 -4
- package/dist/core/extensions/builtin/mcp/sdk.lazy.d.ts +3 -1
- package/dist/core/extensions/builtin/mcp/sdk.lazy.js +3 -1
- package/dist/core/extensions/builtin/mcp/service-register.d.ts +4 -1
- package/dist/core/extensions/builtin/mcp/service-register.js +3 -0
- package/dist/core/extensions/builtin/mcp/service-types.d.ts +2 -1
- package/dist/core/extensions/builtin/mcp/service.d.ts +1 -0
- package/dist/core/extensions/builtin/mcp/service.js +79 -4
- package/dist/core/extensions/builtin/mcp/shared-connection.js +36 -2
- package/dist/core/extensions/builtin/mcp/shared-lease.d.ts +1 -0
- package/dist/core/extensions/builtin/mcp/shared-lease.js +9 -0
- package/dist/core/extensions/builtin/mcp/transport-sdk.d.ts +3 -2
- package/dist/core/extensions/builtin/mcp/transport-sdk.js +56 -25
- package/dist/core/extensions/builtin/mcp/wrap.d.ts +7 -0
- package/dist/core/extensions/builtin/mcp/wrap.js +6 -0
- package/dist/core/extensions/runner.js +3 -2
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/lifecycle-ledger.d.ts +1 -0
- package/dist/core/lifecycle-ledger.js +7 -2
- package/dist/core/lifecycle-record.js +3 -0
- package/dist/core/lifecycle-session-binding.d.ts +11 -1
- package/dist/core/lifecycle-session-binding.js +29 -2
- package/dist/core/lifecycle-stop.d.ts +41 -0
- package/dist/core/lifecycle-stop.js +92 -0
- package/dist/core/mcp-form-types.d.ts +89 -0
- package/dist/core/mcp-form-types.js +23 -0
- package/dist/core/mcp-mrtr-presentations.d.ts +15 -0
- package/dist/core/mcp-mrtr-presentations.js +17 -0
- package/dist/core/session-lifecycle-types.d.ts +15 -0
- package/dist/core/session-lifecycle.d.ts +17 -1
- package/dist/core/session-lifecycle.js +40 -2
- package/dist/main.js +5 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +1 -0
- package/dist/modes/interactive/components/extension-selector.js +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.js +34 -8
- package/dist/modes/interactive/mcp-local-presenter.d.ts +5 -0
- package/dist/modes/interactive/mcp-local-presenter.js +109 -0
- package/dist/modes/rpc/connection-handler.d.ts +1 -0
- package/dist/modes/rpc/connection-handler.js +7 -1
- package/dist/modes/rpc/host-capabilities.d.ts +1 -0
- package/dist/modes/rpc/host-capabilities.js +2 -1
- package/dist/modes/rpc/host-ensure-start.js +13 -2
- package/dist/modes/rpc/host-ensure-types.d.ts +2 -0
- package/dist/modes/rpc/host-ensure.js +1 -0
- package/dist/modes/rpc/host-handoff.d.ts +2 -0
- package/dist/modes/rpc/host-handover-wire.d.ts +2 -0
- package/dist/modes/rpc/host-handover-wire.js +1 -0
- package/dist/modes/rpc/host-lifecycle-launch.d.ts +1 -0
- package/dist/modes/rpc/host-lifecycle-launch.js +43 -2
- package/dist/modes/rpc/host-runner.d.ts +2 -0
- package/dist/modes/rpc/host-runner.js +8 -6
- package/dist/modes/rpc/host-successor.js +11 -1
- package/dist/modes/rpc/mcp-form-dialog.d.ts +45 -0
- package/dist/modes/rpc/mcp-form-dialog.js +159 -0
- package/dist/modes/rpc/mcp-form-worker.d.ts +14 -0
- package/dist/modes/rpc/mcp-form-worker.js +167 -0
- package/dist/modes/rpc/mcp-presenter-authority.d.ts +53 -0
- package/dist/modes/rpc/mcp-presenter-authority.js +309 -0
- package/dist/modes/rpc/mcp-presenter-bootstrap.d.ts +8 -0
- package/dist/modes/rpc/mcp-presenter-bootstrap.js +111 -0
- package/dist/modes/rpc/mcp-presenter-control.d.ts +24 -0
- package/dist/modes/rpc/mcp-presenter-control.js +330 -0
- package/dist/modes/rpc/multi-session-host.d.ts +3 -0
- package/dist/modes/rpc/multi-session-host.js +36 -1
- package/dist/modes/rpc/session-binding.js +6 -1
- package/dist/modes/rpc/session-event-writer.d.ts +14 -0
- package/dist/modes/rpc/session-event-writer.js +128 -1
- package/dist/modes/rpc/session-router-routing.js +1 -0
- package/dist/modes/rpc/session-worker-client.d.ts +3 -0
- package/dist/modes/rpc/session-worker-client.js +89 -0
- package/dist/modes/rpc/session-worker-protocol.d.ts +41 -0
- package/dist/modes/rpc/session-worker.js +9 -0
- package/docs/extensions.md +5 -0
- package/docs/mcp.md +20 -3
- package/docs/rpc.md +111 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-B6TPQDBW.js +0 -5
- package/dist/bundle/chunks/chunk-CDRFFHLL.js +0 -4
- package/dist/bundle/chunks/chunk-HPCS4HM4.js +0 -27
- package/dist/bundle/chunks/chunk-KJZAY5YH.js +0 -27
- package/dist/bundle/chunks/chunk-OI4NMCKP.js +0 -3
- package/dist/bundle/chunks/chunk-SCVRKIFK.js +0 -2
- package/dist/bundle/chunks/cli-main-SWKFMTZQ.js +0 -3
- package/dist/bundle/chunks/dispatch-DEP4PEDZ.js +0 -10
- package/dist/bundle/chunks/host-command-BC6UWP33.js +0 -2
- package/dist/bundle/chunks/host-lifecycle-TN5NEGNF.js +0 -3
- package/dist/bundle/chunks/host-session-command-MGVBLBRV.js +0 -20
- package/dist/bundle/chunks/interactive-mode-SCSROHD5.js +0 -2
- package/dist/bundle/chunks/rpc-mode-TOXYD4XA.js +0 -2
- package/dist/bundle/chunks/session-control-endpoint-HFFMBALG.js +0 -3
package/dist/bundle/rpc-entry.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
3
|
-
import"./chunks/chunk-UFJ2K7Q7.js";import{main}from"./chunks/chunk-
|
|
3
|
+
import"./chunks/chunk-UFJ2K7Q7.js";import{main}from"./chunks/chunk-YRF4I43T.js";import"./chunks/chunk-ODTGC6YU.js";import"./chunks/chunk-FHXR4ZAC.js";import"./chunks/chunk-7CNOCJCN.js";import{configureHttpDispatcher}from"./chunks/chunk-FFQOEC76.js";import"./chunks/chunk-DXJJP6RP.js";import"./chunks/chunk-GXY5JEI5.js";import"./chunks/chunk-7W7OJDIY.js";import"./chunks/chunk-GY5MR5KR.js";import"./chunks/chunk-EHQXLHRB.js";import"./chunks/chunk-XF3LJC3O.js";import"./chunks/chunk-CNPDUC4D.js";import"./chunks/chunk-MLVIYDHK.js";import"./chunks/chunk-H3HNMY2W.js";import"./chunks/chunk-JPGT64RV.js";import"./chunks/chunk-UQNRW3VU.js";import"./chunks/chunk-P3M2PF6K.js";import"./chunks/chunk-HVJI5T75.js";import"./chunks/chunk-QMRJYMNH.js";import"./chunks/chunk-C5UFJ7B3.js";import"./chunks/chunk-TIVW4P37.js";import"./chunks/chunk-H4QOEVS5.js";import"./chunks/chunk-3LNSLJ7N.js";import"./chunks/chunk-MSQCTH6V.js";import"./chunks/chunk-4AOMNOGY.js";import"./chunks/chunk-KLAX467B.js";import"./chunks/chunk-JFFS72FL.js";import"./chunks/chunk-ORXZXUMC.js";import"./chunks/chunk-GZVCRV7I.js";import"./chunks/chunk-KUPQO7MC.js";import"./chunks/chunk-SOMFLLPD.js";import"./chunks/chunk-WD6WBYC5.js";import"./chunks/chunk-26UBFF6N.js";import"./chunks/chunk-MTQQ2VQH.js";import"./chunks/chunk-JA2R2ZSE.js";import"./chunks/chunk-Z3UYNSVR.js";import"./chunks/chunk-KXB5WIS5.js";import"./chunks/chunk-CNL6QSUB.js";import"./chunks/chunk-SWJXRC2I.js";import"./chunks/chunk-4WZRVZNX.js";import"./chunks/chunk-U3VOXCGP.js";import"./chunks/chunk-O3Q2ET6W.js";import"./chunks/chunk-YI7SPFDN.js";import"./chunks/chunk-HB35RBP4.js";import"./chunks/chunk-Z6WGAK7W.js";import"./chunks/chunk-DLAY7CIU.js";import"./chunks/chunk-3BTN337S.js";import"./chunks/chunk-QXREUA5F.js";import"./chunks/chunk-RUGYFYH7.js";import"./chunks/chunk-OEFCY46F.js";import"./chunks/chunk-KRNXUTZJ.js";import"./chunks/chunk-TAV6QZFM.js";import"./chunks/chunk-PELNNWGO.js";import"./chunks/chunk-TTU2RNVX.js";import"./chunks/chunk-FDL4CF6F.js";import"./chunks/chunk-BWA4FVFW.js";import"./chunks/chunk-YU4AYH4C.js";import"./chunks/chunk-E6WYH3ZL.js";import"./chunks/chunk-COH5F7QV.js";import"./chunks/chunk-RFB5CBW7.js";import"./chunks/chunk-2VZJTDUX.js";import"./chunks/chunk-E4LBKOZG.js";import"./chunks/chunk-GVSBCJFI.js";import"./chunks/chunk-WASCMT6Y.js";import"./chunks/chunk-T36LJ6MW.js";import"./chunks/chunk-QGJLZ6BI.js";import"./chunks/chunk-WHPDEDCC.js";import"./chunks/chunk-AA2L2RHH.js";import"./chunks/chunk-HK46JMSC.js";import"./chunks/chunk-4P7WARQZ.js";import"./chunks/chunk-WDTJ6JKE.js";import"./chunks/chunk-5ROMKDLK.js";import"./chunks/chunk-3W47LTXQ.js";import"./chunks/chunk-6AOVUTUR.js";import"./chunks/chunk-45SZOLCU.js";import"./chunks/chunk-DMI55M2N.js";import"./chunks/chunk-PJ34QVL5.js";import"./chunks/chunk-BMX2U22F.js";import"./chunks/chunk-YU2P3CAR.js";import"./chunks/chunk-WLHNEUGD.js";import"./chunks/chunk-ZOFZRJSL.js";import"./chunks/chunk-2SOVDETB.js";import"./chunks/chunk-V3CK2AVC.js";import"./chunks/chunk-VRDU425E.js";import"./chunks/chunk-ZGAB7WQA.js";import{APP_NAME,scrubBrandFromEnvironment}from"./chunks/chunk-7YO7VQZW.js";import"./chunks/chunk-ATQFN5HI.js";import"./chunks/chunk-MIENF2YK.js";import"./chunks/chunk-OXNWERO4.js";import"./chunks/chunk-QN2BHP3M.js";import"./chunks/chunk-NTK2MHJ5.js";import"./chunks/chunk-O5RYI3IW.js";import"./chunks/chunk-IKOFCODM.js";process.title=`${APP_NAME}-rpc`;scrubBrandFromEnvironment();process.env.PI_CODING_AGENT="true";process.env.AI_AGENT=APP_NAME;process.emitWarning=(()=>{});configureHttpDispatcher();main(["--mode","rpc",...process.argv.slice(2)]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"buildId":"
|
|
1
|
+
{"buildId":"c1ee656ad995c37e","externals":["@earendil-works/chord","@earendil-works/pi-pty","@silvia-odwyer/photon-node","bufferutil","canvas","kerberos","supports-color","utf-8-validate"]}
|
package/dist/cli/args.d.ts
CHANGED
|
@@ -55,6 +55,8 @@ export interface Args {
|
|
|
55
55
|
grokNeo?: boolean;
|
|
56
56
|
/** Serve independently routed plain-RPC sessions over one host. */
|
|
57
57
|
multiSession?: boolean;
|
|
58
|
+
presenterBootstrapFd?: number;
|
|
59
|
+
mcpPresenterEnforcement?: boolean;
|
|
58
60
|
/**
|
|
59
61
|
* Opt non-interactive app modes (notably RPC) into engine-side session auto-titling.
|
|
60
62
|
* Deprecated for shared hosts: prefer per-session `open_session.auto_title`.
|
package/dist/cli/args.js
CHANGED
|
@@ -297,6 +297,15 @@ export function parseArgs(args, options = {}) {
|
|
|
297
297
|
else if (arg === "--multi-session") {
|
|
298
298
|
result.multiSession = true;
|
|
299
299
|
}
|
|
300
|
+
else if (arg === "--mcp-presenter-fd") {
|
|
301
|
+
if (args[++i] === "4")
|
|
302
|
+
result.presenterBootstrapFd = 4;
|
|
303
|
+
else
|
|
304
|
+
result.diagnostics.push({ type: "error", message: "Invalid presenter bootstrap descriptor" });
|
|
305
|
+
}
|
|
306
|
+
else if (arg === "--mcp-presenter-enforcement") {
|
|
307
|
+
result.mcpPresenterEnforcement = true;
|
|
308
|
+
}
|
|
300
309
|
else if (arg === "--auto-title-sessions") {
|
|
301
310
|
result.autoTitleSessions = true;
|
|
302
311
|
}
|
|
@@ -5,6 +5,7 @@ import { type HostStopGeneration } from "../modes/rpc/host-stop-generation.ts";
|
|
|
5
5
|
declare const SUBCOMMANDS: readonly ["ensure", "status", "stop", "handoff", "shard-path", "gc"];
|
|
6
6
|
type HostSubcommand = (typeof SUBCOMMANDS)[number];
|
|
7
7
|
export interface ParsedHostArgs {
|
|
8
|
+
readonly presenterBootstrapFd?: number;
|
|
8
9
|
readonly subcommand: HostSubcommand;
|
|
9
10
|
readonly specPath?: string;
|
|
10
11
|
readonly policy: HostDecisionPolicy;
|
|
@@ -26,11 +26,16 @@ export function parseHostArgs(args) {
|
|
|
26
26
|
let root;
|
|
27
27
|
let agentDir;
|
|
28
28
|
let keyRoot;
|
|
29
|
+
let presenterBootstrapFd;
|
|
29
30
|
const handover = {};
|
|
30
31
|
for (let index = 0; index < rest.length; index++) {
|
|
31
32
|
const flag = rest[index];
|
|
32
33
|
const value = rest[index + 1];
|
|
33
|
-
if (flag === "--
|
|
34
|
+
if (flag === "--mcp-presenter-fd" && value === "4" && (subcommand === "ensure" || subcommand === "handoff")) {
|
|
35
|
+
presenterBootstrapFd = 4;
|
|
36
|
+
index++;
|
|
37
|
+
}
|
|
38
|
+
else if (flag === "--rpc-key-root" && value !== undefined && !value.startsWith("--")) {
|
|
34
39
|
keyRoot = resolve(value);
|
|
35
40
|
index++;
|
|
36
41
|
}
|
|
@@ -115,6 +120,7 @@ export function parseHostArgs(args) {
|
|
|
115
120
|
if (typeof terms === "string")
|
|
116
121
|
return terms;
|
|
117
122
|
return {
|
|
123
|
+
...(presenterBootstrapFd === undefined ? {} : { presenterBootstrapFd }),
|
|
118
124
|
subcommand,
|
|
119
125
|
...(specPath !== undefined && { specPath }),
|
|
120
126
|
policy,
|
package/dist/cli/host-command.js
CHANGED
|
@@ -28,6 +28,7 @@ import { DEFAULT_HOST_LAUNCH_SPEC, HostLaunchSpecError, loadHostLaunchSpec, } fr
|
|
|
28
28
|
import { HOST_EXIT_ERROR, HOST_EXIT_USAGE, runHostRequest, } from "../modes/rpc/host-runner.js";
|
|
29
29
|
import { parseHostArgs } from "./host-command-args.js";
|
|
30
30
|
import { emit } from "./host-emit.js";
|
|
31
|
+
import { presenterBootstrapStream } from "../modes/rpc/mcp-presenter-bootstrap.js";
|
|
31
32
|
export { parseHostArgs } from "./host-command-args.js";
|
|
32
33
|
const USAGE = `usage: ${APP_NAME} host <ensure|status|stop|handoff|shard-path|gc> [options]
|
|
33
34
|
|
|
@@ -55,7 +56,8 @@ export async function runHostCommand(args) {
|
|
|
55
56
|
}
|
|
56
57
|
try {
|
|
57
58
|
const request = await hostRequest(parsed);
|
|
58
|
-
const
|
|
59
|
+
const presenterBootstrap = parsed.presenterBootstrapFd === undefined ? undefined : presenterBootstrapStream(parsed.presenterBootstrapFd);
|
|
60
|
+
const outcome = await runHostRequest(request, { keyRoot: parsed.keyRoot, presenterBootstrap }).finally(() => presenterBootstrap?.destroy());
|
|
59
61
|
if (parsed.subcommand === "shard-path" && !parsed.json)
|
|
60
62
|
writeSync(1, `${String(outcome.payload.socket)}\n`);
|
|
61
63
|
else
|
|
@@ -609,6 +609,9 @@ export class AgentSession {
|
|
|
609
609
|
this._handleAgentEvent = (event, signal) => {
|
|
610
610
|
if (event.type === "agent_start")
|
|
611
611
|
this._lifecycleBinding.startRun();
|
|
612
|
+
// Bound at emission: the core can start the next run before the queue reaches this end (senpi#3864).
|
|
613
|
+
if (event.type === "agent_end")
|
|
614
|
+
this._lifecycleBinding.bindTurnEnd(event);
|
|
612
615
|
if (event.type === "message_start") {
|
|
613
616
|
try {
|
|
614
617
|
const entryId = this._lifecycleBinding.consume(event.message);
|
|
@@ -3113,8 +3116,9 @@ export class AgentSession {
|
|
|
3113
3116
|
else if (event.type === "agent_end") {
|
|
3114
3117
|
const extensionEvent = this._abortProvenance.beginAgentEnd(event.messages, agentEndWillRetry, this._findLastAssistantInMessages(event.messages)?.stopReason === "aborted");
|
|
3115
3118
|
try {
|
|
3119
|
+
const guardStartLeafId = this.sessionManager.getLeafId();
|
|
3116
3120
|
await this._extensionRunner.emit(extensionEvent);
|
|
3117
|
-
await this._lifecycleBinding.turnEnded(extensionEvent);
|
|
3121
|
+
await this._lifecycleBinding.turnEnded(extensionEvent, event, guardStartLeafId);
|
|
3118
3122
|
}
|
|
3119
3123
|
finally {
|
|
3120
3124
|
this._abortProvenance.endAgentEnd(extensionEvent);
|
|
@@ -3538,12 +3542,23 @@ export class AgentSession {
|
|
|
3538
3542
|
}
|
|
3539
3543
|
/** Record a deadline stop durably so the goal engine holds off until admitted user input. */
|
|
3540
3544
|
_recordDeadlineStop(deadline) {
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3545
|
+
const at = Date.now();
|
|
3546
|
+
// The lifecycle stop is captured before the write, so a refused write keeps it for this run (senpi#3864).
|
|
3547
|
+
this._lifecycleBinding.deadlineStopped(deadline.kind, at);
|
|
3548
|
+
let entryId;
|
|
3549
|
+
try {
|
|
3550
|
+
entryId = this.sessionManager.appendCustomEntry(TURN_DEADLINE_ENTRY_TYPE, {
|
|
3551
|
+
kind: deadline.kind,
|
|
3552
|
+
limitMs: deadline.limitMs,
|
|
3553
|
+
elapsedMs: deadline.elapsedMs,
|
|
3554
|
+
at,
|
|
3555
|
+
});
|
|
3556
|
+
}
|
|
3557
|
+
catch (error) {
|
|
3558
|
+
this._lifecycleBinding.deadlineStopWriteFailed();
|
|
3559
|
+
throw error;
|
|
3560
|
+
}
|
|
3561
|
+
this._emitEntryAppended(entryId);
|
|
3547
3562
|
}
|
|
3548
3563
|
/**
|
|
3549
3564
|
* Get the names of currently active tools.
|
|
@@ -137,6 +137,7 @@ export default function goalExtension(pi) {
|
|
|
137
137
|
const end = lastAgentEnd ?? restoredEnd;
|
|
138
138
|
return {
|
|
139
139
|
goal,
|
|
140
|
+
...(lastTodoOutcome === undefined ? {} : { todoOutcome: lastTodoOutcome }),
|
|
140
141
|
...(end
|
|
141
142
|
? {
|
|
142
143
|
input: collectTurnEndLivenessInput(ctx, end, {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { AgentEndEvent } from "../../types.ts";
|
|
2
|
+
import type { TodoOwedOutcome } from "./todo-owed-backstop.ts";
|
|
2
3
|
import type { TurnEndLivenessInput } from "./turn-end-liveness.ts";
|
|
3
4
|
import type { Goal } from "./types.ts";
|
|
4
5
|
export interface GoalLifecycleFacts {
|
|
5
6
|
readonly goal: Goal | null;
|
|
6
7
|
readonly input?: TurnEndLivenessInput;
|
|
8
|
+
/** What the todo backstop returned at the last turn end; a repeated `cap` emits no event. */
|
|
9
|
+
readonly todoOutcome?: TodoOwedOutcome;
|
|
7
10
|
}
|
|
8
11
|
type Collector = (restoredEnd?: AgentEndEvent, goal?: Goal | null) => Promise<GoalLifecycleFacts>;
|
|
9
12
|
export declare function onGoalLifecycleChange(owner: object, listener: (goal: Goal | null) => void): () => void;
|
|
@@ -5,8 +5,10 @@ import type { ServerConnection } from "./connection.ts";
|
|
|
5
5
|
import type { McpOutputArtifacts } from "./guard/output-guard.ts";
|
|
6
6
|
import type { McpEnsureFreshAuth } from "./health.ts";
|
|
7
7
|
import type { McpInvocationResolver } from "./invocation.ts";
|
|
8
|
+
import type { McpRequestOrigin } from "./request-origin.ts";
|
|
8
9
|
type ListedTool = Awaited<ReturnType<Client["listTools"]>>["tools"][number];
|
|
9
10
|
export interface McpToolCatalogEntry {
|
|
11
|
+
requestOrigin?: () => McpRequestOrigin | undefined;
|
|
10
12
|
server: string;
|
|
11
13
|
tool: string;
|
|
12
14
|
schema: ListedTool["inputSchema"];
|
|
@@ -21,7 +23,7 @@ export interface McpToolCatalogEntry {
|
|
|
21
23
|
outputGuard?: McpSettings["outputGuard"];
|
|
22
24
|
invocation?: McpInvocationResolver;
|
|
23
25
|
}
|
|
24
|
-
type McpToolCatalogOptions = Pick<McpToolCatalogEntry, "agentDir" | "artifacts" | "ensureFresh" | "outputGuard" | "invocation">;
|
|
26
|
+
type McpToolCatalogOptions = Pick<McpToolCatalogEntry, "agentDir" | "artifacts" | "ensureFresh" | "outputGuard" | "invocation" | "requestOrigin">;
|
|
25
27
|
export declare function collectToolCatalog(server: string, connection: ServerConnection, config: McpServerDeclaredConfig, options?: McpToolCatalogOptions): Promise<McpToolCatalogEntry[]>;
|
|
26
28
|
/** What registering these tools with this catalog's resources and prompts exposes;
|
|
27
29
|
* equal identities register identical definitions. */
|
|
@@ -2,6 +2,7 @@ import { collectAllPages } from "./expose/pagination.js";
|
|
|
2
2
|
export async function collectToolCatalog(server, connection, config, options = {}) {
|
|
3
3
|
const result = await collectAllPages((cursor) => connection.client.listTools(cursor === undefined ? {} : { cursor }, { timeout: config.requestTimeoutMs }));
|
|
4
4
|
return result.items.map((tool) => ({
|
|
5
|
+
requestOrigin: options.requestOrigin,
|
|
5
6
|
annotations: tool.annotations,
|
|
6
7
|
agentDir: options.agentDir,
|
|
7
8
|
artifacts: options.artifacts,
|
|
@@ -27,6 +28,7 @@ export function mcpRegistrationIdentity(tools, catalog) {
|
|
|
27
28
|
}
|
|
28
29
|
export function cachedToolsToCatalogEntries(server, catalog, connection, requestTimeoutMs, ensureConnected, options = {}) {
|
|
29
30
|
return catalog.tools.map((tool) => ({
|
|
31
|
+
requestOrigin: options.requestOrigin,
|
|
30
32
|
annotations: tool.annotations,
|
|
31
33
|
agentDir: options.agentDir,
|
|
32
34
|
artifacts: options.artifacts,
|
|
@@ -4,6 +4,7 @@ export type { ServerConnectionOptions, ServerConnectionState, ServerConnectionSt
|
|
|
4
4
|
export declare class ServerConnection {
|
|
5
5
|
#private;
|
|
6
6
|
readonly serverName: string;
|
|
7
|
+
get requestLifetimeSignal(): AbortSignal;
|
|
7
8
|
constructor(options: ServerConnectionOptions);
|
|
8
9
|
get state(): ServerConnectionState;
|
|
9
10
|
get declarationIdentity(): string | undefined;
|
|
@@ -2,6 +2,8 @@ import { dirname } from "node:path";
|
|
|
2
2
|
import { resolveServerAuth } from "./auth/context.js";
|
|
3
3
|
import { diagnoseCapturedMcpConnectFailure, diagnoseMcpConnectFailure } from "./diagnose.js";
|
|
4
4
|
import { ConnectError } from "./errors.js";
|
|
5
|
+
import { legacyMcpFormEligible } from "./elicitation.js";
|
|
6
|
+
import { isModernMcpClient, legacyMcpFormsAdvertised } from "./modern/request.js";
|
|
5
7
|
import { subscribeMcpServerLogging } from "./logging.js";
|
|
6
8
|
import { isMcpNeedsAuthError } from "./needs-auth.js";
|
|
7
9
|
import { subscribeMcpListChanged } from "./notifications.js";
|
|
@@ -18,12 +20,18 @@ export class ServerConnection {
|
|
|
18
20
|
#resolveConfig;
|
|
19
21
|
#projectPolicy;
|
|
20
22
|
#policyAbort;
|
|
23
|
+
#requestLifetime = new AbortController();
|
|
24
|
+
get requestLifetimeSignal() {
|
|
25
|
+
return this.#requestLifetime.signal;
|
|
26
|
+
}
|
|
21
27
|
#startedGrantNames = [];
|
|
22
28
|
#state;
|
|
23
29
|
#generation = 0;
|
|
24
30
|
#connection;
|
|
25
31
|
#pendingConnection;
|
|
26
32
|
#pendingConnect;
|
|
33
|
+
#renegotiatingForms;
|
|
34
|
+
#stopFormReadiness;
|
|
27
35
|
#lastError;
|
|
28
36
|
#stateListeners = new Set();
|
|
29
37
|
#toolsListeners = new Set();
|
|
@@ -87,9 +95,33 @@ export class ServerConnection {
|
|
|
87
95
|
return this.#connection?.getRootPid() ?? null;
|
|
88
96
|
}
|
|
89
97
|
connect() {
|
|
98
|
+
return this.#renegotiatingForms ?? this.#connect();
|
|
99
|
+
}
|
|
100
|
+
#legacyFormsChanged(client) {
|
|
101
|
+
return (this.#elicitationUiProvider?.enforced?.() === true &&
|
|
102
|
+
!isModernMcpClient(client) &&
|
|
103
|
+
legacyMcpFormsAdvertised(client) !==
|
|
104
|
+
legacyMcpFormEligible(this.#elicitationUiProvider, this.#elicitationEnabled !== false));
|
|
105
|
+
}
|
|
106
|
+
#refreshLegacyForms() {
|
|
107
|
+
if (this.#state !== "connected" || this.#renegotiatingForms || !this.#legacyFormsChanged(this.client))
|
|
108
|
+
return;
|
|
109
|
+
// Publish the single flight before renewing: connect callers join it while the old transport closes.
|
|
110
|
+
this.#renegotiatingForms = Promise.resolve()
|
|
111
|
+
.then(() => this.renew())
|
|
112
|
+
.finally(() => {
|
|
113
|
+
this.#renegotiatingForms = undefined;
|
|
114
|
+
});
|
|
115
|
+
void this.#renegotiatingForms.catch((error) => {
|
|
116
|
+
this.markDegraded(error instanceof Error ? error : new Error(String(error)));
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
#connect() {
|
|
90
120
|
if (this.#state === "disabled") {
|
|
91
121
|
return Promise.reject(this.#connectError(`MCP server ${this.serverName} is disabled`, "connect"));
|
|
92
122
|
}
|
|
123
|
+
if (this.#elicitationUiProvider?.enforced?.())
|
|
124
|
+
this.#stopFormReadiness ??= this.#elicitationUiProvider.subscribe?.(() => this.#refreshLegacyForms());
|
|
93
125
|
if (this.#state === "connected")
|
|
94
126
|
return Promise.resolve(this.client);
|
|
95
127
|
if (this.#pendingConnect)
|
|
@@ -153,13 +185,17 @@ export class ServerConnection {
|
|
|
153
185
|
throw this.#connectError(`MCP server ${this.serverName} is disabled`, "renew");
|
|
154
186
|
}
|
|
155
187
|
this.#policyAbort?.abort();
|
|
188
|
+
this.#requestLifetime.abort();
|
|
189
|
+
this.#requestLifetime = new AbortController();
|
|
156
190
|
this.#generation++;
|
|
157
191
|
this.#pendingConnect = undefined;
|
|
158
192
|
this.#setState("idle");
|
|
159
193
|
await this.#disposeOwnedConnections();
|
|
160
|
-
return this
|
|
194
|
+
return this.#connect();
|
|
161
195
|
}
|
|
162
196
|
bumpGeneration() {
|
|
197
|
+
this.#requestLifetime.abort();
|
|
198
|
+
this.#requestLifetime = new AbortController();
|
|
163
199
|
this.#policyAbort?.abort();
|
|
164
200
|
this.#generation++;
|
|
165
201
|
this.#pendingConnect = undefined;
|
|
@@ -169,6 +205,9 @@ export class ServerConnection {
|
|
|
169
205
|
return this.#disposeOwnedConnections();
|
|
170
206
|
}
|
|
171
207
|
disable() {
|
|
208
|
+
this.#stopFormReadiness?.();
|
|
209
|
+
this.#stopFormReadiness = undefined;
|
|
210
|
+
this.#requestLifetime.abort();
|
|
172
211
|
this.#policyAbort?.abort();
|
|
173
212
|
this.#generation++;
|
|
174
213
|
this.#pendingConnect = undefined;
|
|
@@ -177,6 +216,9 @@ export class ServerConnection {
|
|
|
177
216
|
return this.#disposeOwnedConnections();
|
|
178
217
|
}
|
|
179
218
|
async dispose() {
|
|
219
|
+
this.#stopFormReadiness?.();
|
|
220
|
+
this.#stopFormReadiness = undefined;
|
|
221
|
+
this.#requestLifetime.abort();
|
|
180
222
|
this.#policyAbort?.abort();
|
|
181
223
|
this.#generation++;
|
|
182
224
|
this.#pendingConnect = undefined;
|
|
@@ -320,6 +362,9 @@ export class ServerConnection {
|
|
|
320
362
|
// Server logging notifications (todo 42): RFC-5424 → the per-server
|
|
321
363
|
// logger, filtered by config.logLevel, burst-capped.
|
|
322
364
|
subscribeMcpServerLogging(connection.client, { logLevel: this.#config.logLevel, logger: this.#logger });
|
|
365
|
+
// Readiness can change while initialize is in flight; never publish that stale negotiation as connected.
|
|
366
|
+
if (this.#legacyFormsChanged(connection.client))
|
|
367
|
+
return this.renew();
|
|
323
368
|
this.#setState("connected");
|
|
324
369
|
this.markToolsChanged("connect");
|
|
325
370
|
return connection.client;
|
|
@@ -9,7 +9,11 @@ export declare function mcpClientCapabilities(elicitationEnabled?: boolean): {
|
|
|
9
9
|
};
|
|
10
10
|
export declare const MCP_ELICITATION_TIMEOUT_MS: number;
|
|
11
11
|
type ElicitationUi = Pick<ExtensionUIContext, "input" | "select">;
|
|
12
|
-
export type McpElicitationUiProvider = () => ElicitationUi | undefined
|
|
12
|
+
export type McpElicitationUiProvider = (() => ElicitationUi | undefined) & {
|
|
13
|
+
readonly eligible?: () => boolean;
|
|
14
|
+
readonly enforced?: () => boolean;
|
|
15
|
+
readonly subscribe?: (listener: () => void) => () => void;
|
|
16
|
+
};
|
|
13
17
|
export interface McpElicitationUiOwner {
|
|
14
18
|
getMcpElicitationUi(): ElicitationUi | undefined;
|
|
15
19
|
}
|
|
@@ -26,6 +30,7 @@ interface ElicitProperty {
|
|
|
26
30
|
}
|
|
27
31
|
/** Legacy classic-session seam. Session-owned services pass themselves directly. */
|
|
28
32
|
export declare function setMcpElicitationUiProvider(provider: McpElicitationUiProvider | undefined): void;
|
|
33
|
+
export declare function legacyMcpFormEligible(provider: McpElicitationUiProvider | undefined, enabled: boolean): boolean;
|
|
29
34
|
/**
|
|
30
35
|
* Wire the elicitation/create handler onto a fresh client. Async because the
|
|
31
36
|
* request schema comes from the lazily loaded SDK; the caller (`buildMcpClient`
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
// The whole form is bounded by a timeout that resolves to cancel so a wedged
|
|
10
10
|
// dialog can never wedge the tool-call pipeline. URL mode is deliberately not
|
|
11
11
|
// implemented in v1.
|
|
12
|
+
import { privateMcpForms } from "../../../mcp-form-types.js";
|
|
13
|
+
import { legacyMcpOperation } from "./request-origin.js";
|
|
14
|
+
import { isRecord, validateMrtrForm } from "./modern/form-schema.js";
|
|
12
15
|
import { createMcpLogger } from "./log.js";
|
|
13
16
|
import { loadMcpSdkTypes } from "./sdk.lazy.js";
|
|
14
17
|
import { safeTimer } from "./wrap.js";
|
|
@@ -27,6 +30,48 @@ async function rejectElicitation() {
|
|
|
27
30
|
const { ErrorCode, McpError } = await loadMcpSdkTypes();
|
|
28
31
|
throw new McpError(ErrorCode.InternalError, "Elicitation cannot be processed");
|
|
29
32
|
}
|
|
33
|
+
export function legacyMcpFormEligible(provider, enabled) {
|
|
34
|
+
if (!enabled)
|
|
35
|
+
return false;
|
|
36
|
+
if (provider?.eligible)
|
|
37
|
+
return provider.eligible();
|
|
38
|
+
const ui = provider?.();
|
|
39
|
+
const binding = ui === undefined ? undefined : privateMcpForms(ui);
|
|
40
|
+
return binding === undefined || binding.capture()?.ready() === true;
|
|
41
|
+
}
|
|
42
|
+
async function rejectPrivateElicitation() {
|
|
43
|
+
const { ErrorCode, McpError } = await loadMcpSdkTypes();
|
|
44
|
+
throw new McpError(ErrorCode.InternalError, "Elicitation processing unavailable");
|
|
45
|
+
}
|
|
46
|
+
async function privateElicitation(client, params, signal, requestId, timeoutMs) {
|
|
47
|
+
const operation = legacyMcpOperation(client);
|
|
48
|
+
if (operation === "ambiguous") {
|
|
49
|
+
const { ErrorCode, McpError } = await loadMcpSdkTypes();
|
|
50
|
+
throw new McpError(ErrorCode.InternalError, "Elicitation cannot be processed: ambiguous origin from concurrent legacy tools/call requests. Run these calls sequentially or use an MRTR server.", { reason: "ambiguous_legacy_origin" });
|
|
51
|
+
}
|
|
52
|
+
const presenter = operation?.origin.privateForm;
|
|
53
|
+
if (!isRecord(params) ||
|
|
54
|
+
typeof params.message !== "string" ||
|
|
55
|
+
(params.mode !== undefined && params.mode !== "form") ||
|
|
56
|
+
!operation ||
|
|
57
|
+
!presenter?.ready() ||
|
|
58
|
+
!validateMrtrForm(params.requestedSchema))
|
|
59
|
+
return rejectPrivateElicitation();
|
|
60
|
+
const outcome = await presenter.present({
|
|
61
|
+
operationId: String(requestId),
|
|
62
|
+
inputId: String(requestId),
|
|
63
|
+
round: 0,
|
|
64
|
+
server: { label: operation.origin.serverLabel, source: operation.origin.serverSource ?? "user" },
|
|
65
|
+
message: params.message,
|
|
66
|
+
schema: params.requestedSchema,
|
|
67
|
+
operationSignal: AbortSignal.any([operation.signal, signal]),
|
|
68
|
+
presentationSignal: presenter.signal,
|
|
69
|
+
deadlineMs: timeoutMs,
|
|
70
|
+
});
|
|
71
|
+
if (outcome.kind !== "result" || operation.signal.aborted || !operation.origin.isCurrent())
|
|
72
|
+
return rejectPrivateElicitation();
|
|
73
|
+
return outcome.result;
|
|
74
|
+
}
|
|
30
75
|
/**
|
|
31
76
|
* Wire the elicitation/create handler onto a fresh client. Async because the
|
|
32
77
|
* request schema comes from the lazily loaded SDK; the caller (`buildMcpClient`
|
|
@@ -40,18 +85,27 @@ export async function configureMcpElicitation(client, owner = legacyUiProvider,
|
|
|
40
85
|
const { ErrorCode, McpError } = await loadMcpSdkTypes();
|
|
41
86
|
client.fallbackRequestHandler = async (request) => {
|
|
42
87
|
if (request.method === "elicitation/create")
|
|
43
|
-
return rejectElicitation();
|
|
88
|
+
return typeof owner === "function" && owner.enforced?.() ? rejectPrivateElicitation() : rejectElicitation();
|
|
44
89
|
throw new McpError(ErrorCode.MethodNotFound, "Method not found");
|
|
45
90
|
};
|
|
46
91
|
return;
|
|
47
92
|
}
|
|
48
93
|
const { ElicitRequestSchema } = await loadMcpSdkTypes();
|
|
49
|
-
|
|
94
|
+
if (typeof owner === "function" && owner.enforced?.()) {
|
|
95
|
+
// Private validation prevents SDK error.data from echoing malformed form bodies.
|
|
96
|
+
client.setRequestHandler(ElicitRequestSchema.omit({ params: true }).passthrough(), (request, extra) => privateElicitation(client, request.params, extra.signal, extra.requestId, timeoutMs));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
client.setRequestHandler(ElicitRequestSchema, async (request, extra) => {
|
|
50
100
|
const params = request.params;
|
|
51
101
|
// URL mode is deliberately unsupported in v1 (form mode only).
|
|
52
102
|
if (!("requestedSchema" in params))
|
|
53
103
|
return rejectElicitation();
|
|
54
104
|
const ui = typeof owner === "function" ? owner() : owner?.getMcpElicitationUi();
|
|
105
|
+
const enforced = (typeof owner === "function" && owner.enforced?.()) || (ui !== undefined && privateMcpForms(ui) !== undefined);
|
|
106
|
+
if (enforced) {
|
|
107
|
+
return privateElicitation(client, params, extra.signal, extra.requestId, timeoutMs);
|
|
108
|
+
}
|
|
55
109
|
if (ui === undefined)
|
|
56
110
|
return rejectElicitation();
|
|
57
111
|
return await runElicitationForm(ui, params.message, params.requestedSchema, timeoutMs);
|
|
@@ -2,6 +2,8 @@ import { redactResolvedReferenceData, redactResolvedReferenceValues } from "../.
|
|
|
2
2
|
import { ToolExecError } from "../errors.js";
|
|
3
3
|
import { ensureMcpToolCallConnection, withMcpRetriableFailedSendRetry, withMcpSessionExpiryRetry } from "../health.js";
|
|
4
4
|
import { runMcpConnectionLifecycleCall } from "../idle.js";
|
|
5
|
+
import { mcpRequestOptions } from "../request-origin.js";
|
|
6
|
+
import { McpMrtrError } from "../modern/errors.js";
|
|
5
7
|
export async function callMcpTool(entry, args, signal, onUpdate, label, invocation) {
|
|
6
8
|
try {
|
|
7
9
|
return await runMcpConnectionLifecycleCall(entry.connection, () => withMcpSessionExpiryRetry(entry.connection, async () => {
|
|
@@ -29,7 +31,7 @@ export async function callMcpTool(entry, args, signal, onUpdate, label, invocati
|
|
|
29
31
|
if (prepared !== undefined && !prepared.isCurrent())
|
|
30
32
|
continue;
|
|
31
33
|
const current = prepared?.entry ?? entry;
|
|
32
|
-
const result = await current.connection.client.callTool({ name: current.tool, arguments: args }, undefined, {
|
|
34
|
+
const result = await current.connection.client.callTool({ name: current.tool, arguments: args }, undefined, mcpRequestOptions(current.requestOrigin?.(), {
|
|
33
35
|
onprogress: (progress) => {
|
|
34
36
|
onUpdate?.(redactResolvedReferenceData({
|
|
35
37
|
content: [{ type: "text", text: formatProgress(label, progress) }],
|
|
@@ -38,13 +40,15 @@ export async function callMcpTool(entry, args, signal, onUpdate, label, invocati
|
|
|
38
40
|
},
|
|
39
41
|
signal,
|
|
40
42
|
timeout: current.requestTimeoutMs,
|
|
41
|
-
});
|
|
43
|
+
}));
|
|
42
44
|
return { kind: "called", entry: current, result };
|
|
43
45
|
}
|
|
44
46
|
});
|
|
45
47
|
}));
|
|
46
48
|
}
|
|
47
49
|
catch (error) {
|
|
50
|
+
if (error instanceof McpMrtrError)
|
|
51
|
+
throw error;
|
|
48
52
|
const label = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
49
53
|
throw new ToolExecError(redactResolvedReferenceValues(`ToolExecError: ${label}`), {
|
|
50
54
|
cause: error,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "../../../types.ts";
|
|
1
|
+
import type { ExtensionAPI, ExtensionUIContext } from "../../../types.ts";
|
|
2
2
|
import type { ToolSearchService } from "../../tool-search/service.ts";
|
|
3
3
|
import type { McpCachedServerCatalog } from "../catalog-cache.ts";
|
|
4
4
|
import type { ResolvedMcpConfig } from "../config-schema.ts";
|
|
@@ -7,6 +7,7 @@ import type { McpOutputArtifacts } from "../guard/output-guard.ts";
|
|
|
7
7
|
import type { McpInvocationResolver } from "../invocation.ts";
|
|
8
8
|
import { type McpLogger } from "../log.ts";
|
|
9
9
|
import type { McpPromptServer } from "../prompts.ts";
|
|
10
|
+
import type { McpRequestOrigin } from "../request-origin.ts";
|
|
10
11
|
import { type McpResourceServer } from "../resources.ts";
|
|
11
12
|
import type { McpCatalogRegistrationOptions } from "./register.ts";
|
|
12
13
|
import { type McpTierBRegistration } from "./tier-b.ts";
|
|
@@ -15,6 +16,8 @@ export type McpSessionRegistration = McpTierBRegistration & {
|
|
|
15
16
|
promptServers: McpPromptServer[];
|
|
16
17
|
};
|
|
17
18
|
export interface McpDirectRegistrationEntry {
|
|
19
|
+
readonly requestOrigin?: () => McpRequestOrigin | undefined;
|
|
20
|
+
readonly bindPresentation?: (ui: ExtensionUIContext) => void;
|
|
18
21
|
readonly name: string;
|
|
19
22
|
readonly connection: ServerConnection;
|
|
20
23
|
readonly logger: McpLogger;
|
|
@@ -24,6 +24,7 @@ export async function registerDirectMcpTools(pi, config, entries, toolSearchServ
|
|
|
24
24
|
artifacts: entry.artifacts,
|
|
25
25
|
ensureFresh: entry.ensureFresh,
|
|
26
26
|
invocation: entry.invocation,
|
|
27
|
+
requestOrigin: entry.requestOrigin,
|
|
27
28
|
outputGuard: config.settings.outputGuard,
|
|
28
29
|
})
|
|
29
30
|
: []
|
|
@@ -32,6 +33,7 @@ export async function registerDirectMcpTools(pi, config, entries, toolSearchServ
|
|
|
32
33
|
artifacts: entry.artifacts,
|
|
33
34
|
ensureFresh: entry.ensureFresh,
|
|
34
35
|
invocation: entry.invocation,
|
|
36
|
+
requestOrigin: entry.requestOrigin,
|
|
35
37
|
outputGuard: config.settings.outputGuard,
|
|
36
38
|
});
|
|
37
39
|
const identity = mcpRegistrationIdentity(catalog, entry.cachedCatalog);
|
|
@@ -39,6 +41,9 @@ export async function registerDirectMcpTools(pi, config, entries, toolSearchServ
|
|
|
39
41
|
const cachedPrompts = entry.cachedCatalog?.prompts ?? [];
|
|
40
42
|
if (cachedPrompts.length > 0) {
|
|
41
43
|
promptServers.push({
|
|
44
|
+
ensureFresh: entry.ensureFresh,
|
|
45
|
+
bindPresentation: entry.bindPresentation,
|
|
46
|
+
requestOrigin: entry.requestOrigin,
|
|
42
47
|
connection: entry.connection,
|
|
43
48
|
prompts: cachedPrompts,
|
|
44
49
|
requestTimeoutMs: server.config.requestTimeoutMs,
|
|
@@ -48,6 +53,8 @@ export async function registerDirectMcpTools(pi, config, entries, toolSearchServ
|
|
|
48
53
|
const cachedResources = entry.cachedCatalog?.resources ?? [];
|
|
49
54
|
if (cachedResources.length > 0) {
|
|
50
55
|
resourceServers.push({
|
|
56
|
+
ensureFresh: entry.ensureFresh,
|
|
57
|
+
requestOrigin: entry.requestOrigin,
|
|
51
58
|
agentDir: entry.agentDir,
|
|
52
59
|
artifacts: entry.artifacts,
|
|
53
60
|
connection: entry.connection,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AuthError, ConnectError, isMcpSessionExpiredError, isRetriableMcpError, SessionExpiredError, } from "./errors.js";
|
|
2
2
|
import { isMcpNeedsAuthError } from "./needs-auth.js";
|
|
3
3
|
import { reconnectMcpNow } from "./reconnect.js";
|
|
4
|
+
import { McpMrtrError } from "./modern/errors.js";
|
|
4
5
|
export const MCP_PING_STALE_MS = 30_000;
|
|
5
6
|
export const MCP_PING_TIMEOUT_MS = 2_000;
|
|
6
7
|
const healthByConnection = new WeakMap();
|
|
@@ -46,6 +47,8 @@ export async function withMcpSessionExpiryRetry(connection, operation) {
|
|
|
46
47
|
return await operation();
|
|
47
48
|
}
|
|
48
49
|
catch (error) {
|
|
50
|
+
if (error instanceof McpMrtrError)
|
|
51
|
+
throw error;
|
|
49
52
|
if (!isMcpSessionExpiredError(error))
|
|
50
53
|
throw error;
|
|
51
54
|
connection.markDegraded(sessionExpiredError(connection, error, true));
|
|
@@ -67,6 +70,8 @@ export async function withMcpRetriableFailedSendRetry(connection, operation) {
|
|
|
67
70
|
return await operation();
|
|
68
71
|
}
|
|
69
72
|
catch (error) {
|
|
73
|
+
if (error instanceof McpMrtrError)
|
|
74
|
+
throw error;
|
|
70
75
|
if (!isRetriableFailedSendError(error))
|
|
71
76
|
throw error;
|
|
72
77
|
connection.markDegraded(failedSendError(connection, error, true));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { legacyMcpFormEligible } from "./elicitation.js";
|
|
1
2
|
import { observe } from "./env-grants-store.js";
|
|
2
3
|
import { effectiveGrantNames } from "./project-skill-policy.js";
|
|
3
4
|
import { SharedMcpConnection } from "./shared-connection.js";
|
|
@@ -17,7 +18,12 @@ export class HostMcpRegistry {
|
|
|
17
18
|
#shared = new Map();
|
|
18
19
|
#grantObservers = new Map();
|
|
19
20
|
attachShared(key, owner, options) {
|
|
20
|
-
const
|
|
21
|
+
const eligible = legacyMcpFormEligible(options.elicitationUiProvider, options.elicitationEnabled !== false);
|
|
22
|
+
// Enforced pools observe live readiness; it must not remain frozen in a creation-time key.
|
|
23
|
+
const formPolicy = options.elicitationUiProvider?.enforced?.() === true
|
|
24
|
+
? `private:${options.elicitationEnabled !== false}`
|
|
25
|
+
: `${eligible}:false`;
|
|
26
|
+
const identity = `${sharedMcpKey(options, options.agentDir)}\0legacy-form:${formPolicy}`;
|
|
21
27
|
let shared = this.#shared.get(identity);
|
|
22
28
|
if (shared === undefined) {
|
|
23
29
|
shared = new SharedMcpConnection(options, () => this.#shared.delete(identity));
|
|
@@ -61,6 +61,7 @@ export function createMcpExtension(service, sessionOwned = true) {
|
|
|
61
61
|
service.activateSkillMcpTools(targets, pi);
|
|
62
62
|
};
|
|
63
63
|
pi.on("input", async (event, ctx) => {
|
|
64
|
+
service.bindMcpMrtrPresentation(pi, ctx.ui);
|
|
64
65
|
const match = /^\s*\/skill:([A-Za-z0-9._-]+)/.exec(event.text);
|
|
65
66
|
if (match)
|
|
66
67
|
revealSkill(match[1]);
|
|
@@ -125,6 +126,7 @@ export function createMcpExtension(service, sessionOwned = true) {
|
|
|
125
126
|
// Elicitation (todo 41): point mid-call forms at this session's UI.
|
|
126
127
|
service.setMcpElicitationUiProvider(() => (ctx.hasUI ? ctx.ui : undefined));
|
|
127
128
|
await (attachPromise ?? attach({ type: "session_start", reason: "startup" }, ctx));
|
|
129
|
+
service.bindMcpMrtrPresentation(pi, ctx.ui);
|
|
128
130
|
}
|
|
129
131
|
const skills = preview ? [] : (event.systemPromptOptions.skills ?? []);
|
|
130
132
|
if (skills.length > 0) {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { type McpElicitationUiProvider } from "../elicitation.ts";
|
|
3
|
+
import { type ModernProtocolState } from "./request.ts";
|
|
4
|
+
export declare function createMcpRequestClient(protocol: ModernProtocolState, uiProvider: McpElicitationUiProvider | undefined, readCredential?: () => string | undefined, elicitationEnabled?: boolean): Promise<Client>;
|
|
5
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { configureMcpElicitation, legacyMcpFormEligible, mcpClientCapabilities, } from "../elicitation.js";
|
|
2
|
+
import { loadMcpSdkClient } from "../sdk.lazy.js";
|
|
3
|
+
import { mcpElapsedClock } from "../wrap.js";
|
|
4
|
+
import { installModernRequestAdapter } from "./request.js";
|
|
5
|
+
export async function createMcpRequestClient(protocol, uiProvider, readCredential = () => undefined, elicitationEnabled = true) {
|
|
6
|
+
const { Client } = await loadMcpSdkClient();
|
|
7
|
+
protocol.privateForms = uiProvider?.enforced?.() === true;
|
|
8
|
+
const legacyEligible = legacyMcpFormEligible(uiProvider, elicitationEnabled);
|
|
9
|
+
protocol.legacyFormEligible = legacyEligible;
|
|
10
|
+
const client = new Client({ name: "senpi-mcp-client", version: "0.0.0" }, { capabilities: mcpClientCapabilities(legacyEligible) });
|
|
11
|
+
await configureMcpElicitation(client, uiProvider, undefined, legacyEligible);
|
|
12
|
+
installModernRequestAdapter(client, protocol, mcpElapsedClock, readCredential);
|
|
13
|
+
return client;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=client.js.map
|