@code-yeongyu/senpi 2026.11.10-1 → 2026.11.10-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 +42 -0
- package/dist/bundle/chunks/{args-77GYOPEO.js → args-HFYB6URH.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-YFZ734T3.js → azure-openai-responses-MNN2TINI.js} +1 -1
- package/dist/bundle/chunks/{chunk-ZUQCYIRY.js → chunk-2ODGHBUD.js} +1 -1
- package/dist/bundle/chunks/{chunk-YPAQXRP3.js → chunk-47T6YMI2.js} +2 -2
- package/dist/bundle/chunks/{chunk-I5ASHSLZ.js → chunk-4JMGWVRH.js} +1 -1
- package/dist/bundle/chunks/{chunk-MSDBBOB2.js → chunk-5H43O4MA.js} +1 -1
- package/dist/bundle/chunks/{chunk-3IYWH6RO.js → chunk-6Q7Y2G5A.js} +1 -1
- package/dist/bundle/chunks/{chunk-X4XWAB3J.js → chunk-AC6MDRAE.js} +81 -81
- package/dist/bundle/chunks/{chunk-33MZJTQ3.js → chunk-B4WD5XHP.js} +1 -1
- package/dist/bundle/chunks/{chunk-V5FSENW6.js → chunk-COKX65TE.js} +1 -1
- package/dist/bundle/chunks/{chunk-LHEP3ACI.js → chunk-DEQLHN2J.js} +2 -2
- package/dist/bundle/chunks/{chunk-EJB5E2JK.js → chunk-DHAAWL2H.js} +1 -1
- package/dist/bundle/chunks/{chunk-2EJ4BGBM.js → chunk-DHORIIVQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-GPXZTSEX.js → chunk-DIHIEJFV.js} +3 -3
- package/dist/bundle/chunks/{chunk-NH7SYIGN.js → chunk-DLPV4B3R.js} +1 -1
- package/dist/bundle/chunks/{chunk-RCHIMH7N.js → chunk-DQY26AX3.js} +1 -1
- package/dist/bundle/chunks/{chunk-Y7Z7XPUF.js → chunk-DZQA5LVN.js} +1 -1
- package/dist/bundle/chunks/{chunk-2CNSCMYC.js → chunk-E5O4SP5I.js} +1 -1
- package/dist/bundle/chunks/{chunk-3Q5ZENSD.js → chunk-E6ZBTSC6.js} +1 -1
- package/dist/bundle/chunks/{chunk-HI5JSLG5.js → chunk-H3VJVKUK.js} +4 -4
- package/dist/bundle/chunks/{chunk-L6NRDUWJ.js → chunk-HZDKQOWB.js} +1 -1
- package/dist/bundle/chunks/chunk-IREUIMFE.js +11 -0
- package/dist/bundle/chunks/{chunk-FAFIGBUD.js → chunk-JSD6O3RJ.js} +2 -2
- package/dist/bundle/chunks/{chunk-BELNOPAI.js → chunk-L3KVP7VJ.js} +3 -3
- package/dist/bundle/chunks/{chunk-7MN7YNO5.js → chunk-L7DGTA3L.js} +1 -1
- package/dist/bundle/chunks/{chunk-J2NGJKXL.js → chunk-LXINMDMX.js} +1 -1
- package/dist/bundle/chunks/{chunk-H33A33M4.js → chunk-M2VJVJMK.js} +1 -1
- package/dist/bundle/chunks/{chunk-ARUV3US4.js → chunk-NN7NESW2.js} +1 -1
- package/dist/bundle/chunks/{chunk-2U6HXWXS.js → chunk-NNQ34ZDW.js} +1 -1
- package/dist/bundle/chunks/chunk-NQKCJQHB.js +2 -0
- package/dist/bundle/chunks/{chunk-TGW4R7SI.js → chunk-O5WJVIEU.js} +1 -1
- package/dist/bundle/chunks/{chunk-O3FG6HML.js → chunk-PJI5GT7U.js} +1 -1
- package/dist/bundle/chunks/{chunk-BPNSOZ2C.js → chunk-QUVSIW2R.js} +1 -1
- package/dist/bundle/chunks/{chunk-WXYMAUFX.js → chunk-QX7WD3IM.js} +1 -1
- package/dist/bundle/chunks/{chunk-Y4ONXQMR.js → chunk-RGHVPUUX.js} +1 -1
- package/dist/bundle/chunks/{chunk-RYPM5BZQ.js → chunk-S7NAJQB3.js} +1 -1
- package/dist/bundle/chunks/{chunk-LT353NSF.js → chunk-T4CUD7RF.js} +1 -1
- package/dist/bundle/chunks/{chunk-J7FW7MED.js → chunk-TCZORL3V.js} +1 -1
- package/dist/bundle/chunks/{chunk-KU72IKV5.js → chunk-VGSWOLIY.js} +1 -1
- package/dist/bundle/chunks/{chunk-DBQBJTMF.js → chunk-VUY4BZDI.js} +1 -1
- package/dist/bundle/chunks/chunk-XI6THO4F.js +2 -0
- package/dist/bundle/chunks/{chunk-THYEZBUG.js → chunk-Z2C5N2LM.js} +2 -2
- package/dist/bundle/chunks/{cli-main-VG3C2EXI.js → cli-main-ZTT3N4DO.js} +1 -1
- package/dist/bundle/chunks/{credential-accounts-LVVPKFEY.js → credential-accounts-5KHVGSCY.js} +1 -1
- package/dist/bundle/chunks/{dispatch-EP35KKJ3.js → dispatch-YUYZQXRP.js} +1 -1
- package/dist/bundle/chunks/{hand-entry-3LQKUTYS.js → hand-entry-UV5XPMBF.js} +3 -3
- package/dist/bundle/chunks/{headless-host-HKGNJGYT.js → headless-host-53UMJMM6.js} +1 -1
- package/dist/bundle/chunks/{health-write-FBF74QJ7.js → health-write-JLSF5EVV.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-5SCPY3OH.js → help-fast-path-552QLMWT.js} +1 -1
- package/dist/bundle/chunks/{host-command-CCASS7W4.js → host-command-BZN7WYYV.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-WWC7HXQ6.js → host-lifecycle-TNHASSFJ.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +1 -1
- package/dist/bundle/chunks/{host-session-command-YJB2FLKU.js → host-session-command-O5WYHZXH.js} +1 -1
- package/dist/bundle/chunks/{host-socket-request-DMYXC56U.js → host-socket-request-QN4Q2P5E.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-CUN3WMUF.js → interactive-mode-OCU4NDPC.js} +1 -1
- package/dist/bundle/chunks/{login-health-EVXVLHB2.js → login-health-TOSQT5RG.js} +1 -1
- package/dist/bundle/chunks/{main-P7XRC2OI.js → main-CNDP6HCF.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-244X3P6L.js → multi-session-host-ODGJAGJP.js} +11 -8
- package/dist/bundle/chunks/openai-codex-responses-VRGOAFEG.js +10 -0
- package/dist/bundle/chunks/{openai-responses-NIVBWE2H.js → openai-responses-I7PXRWCM.js} +2 -2
- package/dist/bundle/chunks/{package-manager-cli-UVWJOQA3.js → package-manager-cli-HSPUG4RJ.js} +1 -1
- package/dist/bundle/chunks/{role-HQUN4XXK.js → role-AEOLJRTP.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-F3BEMXBE.js → rotation-stream-E3FJFHXJ.js} +1 -1
- package/dist/bundle/chunks/rpc-mode-KOZPXU3U.js +2 -0
- package/dist/bundle/chunks/{rpc-monitor-source-C6VQ3BC4.js → rpc-monitor-source-PGTDSGWP.js} +1 -1
- package/dist/bundle/chunks/{run-attached-tui-R3RB5P7G.js → run-attached-tui-4AENRP7P.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-5FG2OKSR.js → schedule-command-SG44FE23.js} +1 -1
- package/dist/bundle/chunks/session-control-endpoint-5A24JYPE.js +3 -0
- package/dist/bundle/chunks/{session-picker-2FZSNFS7.js → session-picker-73YRS3GE.js} +1 -1
- package/dist/bundle/chunks/{session-slot-CZGQQCOC.js → session-slot-RH7JLO3F.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +199 -196
- package/dist/bundle/chunks/{state-store-S7QAESIF.js → state-store-IECVTYXC.js} +1 -1
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +1 -1
- 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/core/agent-session-runtime.d.ts +2 -0
- package/dist/core/agent-session-runtime.js +5 -0
- package/dist/core/agent-session.d.ts +13 -3
- package/dist/core/agent-session.js +89 -18
- package/dist/core/assistant-error-redaction.d.ts +9 -0
- package/dist/core/assistant-error-redaction.js +27 -0
- package/dist/core/config-reference-redaction.js +90 -10
- package/dist/core/context-files.d.ts +10 -0
- package/dist/core/context-files.js +58 -12
- package/dist/core/egress/wire.d.ts +13 -0
- package/dist/core/extensions/builtin/config-reload/change-groups.js +6 -2
- package/dist/core/extensions/builtin/mcp/auth/catalog-identity.js +32 -8
- package/dist/core/extensions/builtin/mcp/auth/oauth-grant.d.ts +43 -0
- package/dist/core/extensions/builtin/mcp/auth/oauth-grant.js +196 -0
- package/dist/core/extensions/builtin/mcp/auth/oauth-provider.d.ts +4 -17
- package/dist/core/extensions/builtin/mcp/auth/oauth-provider.js +64 -75
- package/dist/core/extensions/builtin/mcp/auth/oauth-refresh.d.ts +1 -1
- package/dist/core/extensions/builtin/mcp/auth/oauth-refresh.js +25 -4
- package/dist/core/extensions/builtin/mcp/auth/oauth.js +10 -7
- package/dist/core/extensions/builtin/mcp/auth/token-store.d.ts +18 -0
- package/dist/core/extensions/builtin/mcp/auth/token-store.js +3 -0
- package/dist/core/extensions/builtin/mcp/catalog-cache.js +7 -6
- package/dist/core/extensions/builtin/mcp/catalog.js +3 -2
- package/dist/core/extensions/builtin/mcp/invocation.js +6 -0
- package/dist/core/extensions/builtin/mcp/service-register.js +16 -2
- package/dist/core/extensions/builtin/mcp/service-tools-changed.js +61 -54
- package/dist/core/extensions/builtin/mcp/startup-race.d.ts +2 -0
- package/dist/core/extensions/builtin/mcp/startup-race.js +25 -7
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-2.js +6 -6
- package/dist/core/extensions/loader.js +24 -4
- package/dist/core/extensions/runner.d.ts +9 -1
- package/dist/core/extensions/runner.js +9 -4
- package/dist/core/extensions/types.d.ts +17 -3
- package/dist/core/hand/hook-advertise.d.ts +41 -0
- package/dist/core/hand/hook-advertise.js +98 -0
- package/dist/core/hand/hook-contract.d.ts +66 -0
- package/dist/core/hand/hook-contract.js +138 -0
- package/dist/core/open-timing.d.ts +2 -0
- package/dist/core/open-timing.js +7 -1
- package/dist/core/resource-loader.js +2 -0
- package/dist/core/retry-fallback/log.d.ts +7 -1
- package/dist/core/retry-fallback/log.js +82 -5
- package/dist/core/retry-fallback/model-config-error.js +2 -1
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.js +15 -1
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.js +8 -0
- package/dist/core/turn-origin.d.ts +19 -13
- package/dist/core/turn-origin.js +34 -30
- package/dist/core/ultrafast-lanes.d.ts +1 -0
- package/dist/core/ultrafast-lanes.js +4 -2
- package/dist/modes/interactive/components/footer.d.ts +23 -5
- package/dist/modes/interactive/components/footer.js +45 -16
- package/dist/modes/interactive/interactive-mode.js +9 -1
- package/dist/modes/interactive/session-control-rpc-commands.d.ts +1 -1
- package/dist/modes/interactive/session-control-rpc-commands.js +5 -0
- package/dist/modes/rpc/admit-external-message-command.d.ts +2 -2
- package/dist/modes/rpc/admit-external-message-command.js +2 -10
- package/dist/modes/rpc/compact-admission-validation.js +4 -1
- package/dist/modes/rpc/connection-handler.d.ts +2 -0
- package/dist/modes/rpc/connection-handler.js +20 -8
- package/dist/modes/rpc/connection-roles.d.ts +2 -0
- package/dist/modes/rpc/connection-roles.js +4 -0
- package/dist/modes/rpc/custom-capability.d.ts +4 -0
- package/dist/modes/rpc/custom-capability.js +4 -0
- package/dist/modes/rpc/delegated-drive-origin.d.ts +6 -6
- package/dist/modes/rpc/delegated-drive-origin.js +7 -8
- package/dist/modes/rpc/delegation-declaration.d.ts +2 -0
- package/dist/modes/rpc/delegation-declaration.js +5 -1
- package/dist/modes/rpc/effect-commands.d.ts +21 -0
- package/dist/modes/rpc/host-capabilities.d.ts +1 -0
- package/dist/modes/rpc/host-capabilities.js +5 -1
- package/dist/modes/rpc/host-observe-request.d.ts +2 -0
- package/dist/modes/rpc/host-observe-request.js +6 -1
- package/dist/modes/rpc/host-park-ledger.d.ts +19 -0
- package/dist/modes/rpc/host-park-ledger.js +110 -0
- package/dist/modes/rpc/lifecycle-delivery.js +4 -1
- package/dist/modes/rpc/loopless-tool-handlers.d.ts +6 -0
- package/dist/modes/rpc/loopless-tool-handlers.js +14 -1
- package/dist/modes/rpc/media-placeholders.js +1 -0
- package/dist/modes/rpc/method-classes-schema-host.d.ts +42 -1
- package/dist/modes/rpc/method-classes-schema-host.js +24 -21
- package/dist/modes/rpc/method-classes-schema.d.ts +42 -1
- package/dist/modes/rpc/method-classes-schema.js +5 -2
- package/dist/modes/rpc/method-classes.d.ts +2 -0
- package/dist/modes/rpc/method-classes.js +3 -0
- package/dist/modes/rpc/multi-session-host.js +1 -1
- package/dist/modes/rpc/rpc-host-command-types.d.ts +14 -1
- package/dist/modes/rpc/rpc-host-response-types.d.ts +21 -0
- package/dist/modes/rpc/session-attachment-gate.js +2 -0
- package/dist/modes/rpc/session-binding.d.ts +1 -0
- package/dist/modes/rpc/session-binding.js +6 -1
- package/dist/modes/rpc/session-connection-context.d.ts +2 -0
- package/dist/modes/rpc/session-connection-context.js +4 -0
- package/dist/modes/rpc/session-registry-attach.d.ts +2 -0
- package/dist/modes/rpc/session-registry-attach.js +15 -11
- package/dist/modes/rpc/session-registry-claims.js +2 -0
- package/dist/modes/rpc/session-registry-open.js +13 -7
- package/dist/modes/rpc/session-registry-opening.js +2 -1
- package/dist/modes/rpc/session-registry-types.d.ts +4 -0
- package/dist/modes/rpc/session-registry.d.ts +3 -0
- package/dist/modes/rpc/session-registry.js +27 -3
- package/dist/modes/rpc/session-router-close.js +1 -0
- package/dist/modes/rpc/session-router-context.d.ts +4 -2
- package/dist/modes/rpc/session-router-context.js +3 -0
- package/dist/modes/rpc/session-router-host-reads.js +1 -0
- package/dist/modes/rpc/session-router-occupancy.js +10 -1
- package/dist/modes/rpc/session-router-open-result.d.ts +12 -0
- package/dist/modes/rpc/session-router-open-result.js +63 -0
- package/dist/modes/rpc/session-router-open.d.ts +3 -0
- package/dist/modes/rpc/session-router-open.js +15 -63
- package/dist/modes/rpc/session-router-park.d.ts +15 -0
- package/dist/modes/rpc/session-router-park.js +176 -0
- package/dist/modes/rpc/session-router-routing.d.ts +1 -1
- package/dist/modes/rpc/session-router-routing.js +7 -0
- package/dist/modes/rpc/session-status-source.js +2 -2
- package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
- package/docs/engine-socket/fixtures/rpc-inbound-samples.json +22 -2
- package/docs/extensions.md +10 -0
- package/docs/rpc.md +50 -0
- package/docs/settings.md +1 -0
- package/docs/usage.md +1 -1
- package/native/socket-secret/prebuilds/win32-arm64/senpi_socket_secret.win32-arm64.node +0 -0
- package/native/socket-secret/prebuilds/win32-x64/senpi_socket_secret.win32-x64.node +0 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-436DNN4Z.js +0 -2
- package/dist/bundle/chunks/chunk-DLAY7CIU.js +0 -2
- package/dist/bundle/chunks/chunk-XH2MWTXA.js +0 -11
- package/dist/bundle/chunks/openai-codex-responses-ABB2J43U.js +0 -10
- package/dist/bundle/chunks/rpc-mode-G4I3HHPB.js +0 -2
- package/dist/bundle/chunks/session-control-endpoint-XWCFLJYC.js +0 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { OpenRpcSession } from "./session-registry.ts";
|
|
2
|
+
/** Owns both in-flight builds and ready parks, including the races with claim, expiry and shutdown. */
|
|
3
|
+
export declare class HostParkLedger {
|
|
4
|
+
private readonly parks;
|
|
5
|
+
private readonly replacements;
|
|
6
|
+
private stopped;
|
|
7
|
+
private readonly close;
|
|
8
|
+
constructor(close: (opened: OpenRpcSession) => Promise<void>);
|
|
9
|
+
get size(): number;
|
|
10
|
+
park(key: string, build: () => Promise<OpenRpcSession>): Promise<"parked" | "already_parked" | "full">;
|
|
11
|
+
/** A claim never waits for a build, and consumes the ready park synchronously. */
|
|
12
|
+
take(key: string): OpenRpcSession | undefined;
|
|
13
|
+
finish(key: string): void;
|
|
14
|
+
replace(key: string, build: () => Promise<OpenRpcSession>): void;
|
|
15
|
+
/** Fences new builds synchronously; every build already accepted is closed when it finishes. */
|
|
16
|
+
stop(): Promise<void>;
|
|
17
|
+
private retire;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=host-park-ledger.d.ts.map
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/** Speculation is bounded independently of the unlimited in-process session registry. */
|
|
2
|
+
const MAX_PARKS = 4;
|
|
3
|
+
const PARK_TTL_MS = 60_000;
|
|
4
|
+
/** Owns both in-flight builds and ready parks, including the races with claim, expiry and shutdown. */
|
|
5
|
+
export class HostParkLedger {
|
|
6
|
+
constructor(close) {
|
|
7
|
+
this.parks = new Map();
|
|
8
|
+
this.replacements = new Map();
|
|
9
|
+
this.stopped = false;
|
|
10
|
+
this.close = close;
|
|
11
|
+
}
|
|
12
|
+
get size() {
|
|
13
|
+
return this.parks.size;
|
|
14
|
+
}
|
|
15
|
+
async park(key, build) {
|
|
16
|
+
const existing = this.parks.get(key);
|
|
17
|
+
if (existing && !existing.claim && !existing.closing) {
|
|
18
|
+
await existing.ready;
|
|
19
|
+
return "already_parked";
|
|
20
|
+
}
|
|
21
|
+
// A park being claimed or closed is on its way out; the replacement scheduled after it builds the next.
|
|
22
|
+
if (existing)
|
|
23
|
+
return "full";
|
|
24
|
+
const replacement = this.replacements.get(key);
|
|
25
|
+
if (replacement !== undefined) {
|
|
26
|
+
clearTimeout(replacement);
|
|
27
|
+
this.replacements.delete(key);
|
|
28
|
+
}
|
|
29
|
+
if (this.stopped)
|
|
30
|
+
throw new Error("host_draining");
|
|
31
|
+
if (this.parks.size + this.replacements.size >= MAX_PARKS)
|
|
32
|
+
return "full";
|
|
33
|
+
const ready = Promise.withResolvers();
|
|
34
|
+
ready.promise.catch(() => { });
|
|
35
|
+
const park = { ready: ready.promise };
|
|
36
|
+
// Reserved before build's first await: a second request joins, never starts another runtime.
|
|
37
|
+
this.parks.set(key, park);
|
|
38
|
+
try {
|
|
39
|
+
park.opened = await build();
|
|
40
|
+
if (!this.stopped) {
|
|
41
|
+
park.expiry = setTimeout(() => void this.retire(key, park), PARK_TTL_MS);
|
|
42
|
+
park.expiry.unref?.();
|
|
43
|
+
}
|
|
44
|
+
ready.resolve();
|
|
45
|
+
if (this.stopped)
|
|
46
|
+
await this.retire(key, park);
|
|
47
|
+
return "parked";
|
|
48
|
+
}
|
|
49
|
+
catch (cause) {
|
|
50
|
+
this.parks.delete(key);
|
|
51
|
+
ready.reject(cause);
|
|
52
|
+
throw cause;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** A claim never waits for a build, and consumes the ready park synchronously. */
|
|
56
|
+
take(key) {
|
|
57
|
+
const park = this.parks.get(key);
|
|
58
|
+
if (this.stopped || !park?.opened || park.claim || park.closing)
|
|
59
|
+
return undefined;
|
|
60
|
+
clearTimeout(park.expiry);
|
|
61
|
+
park.claim = Promise.withResolvers();
|
|
62
|
+
return park.opened;
|
|
63
|
+
}
|
|
64
|
+
finish(key) {
|
|
65
|
+
const park = this.parks.get(key);
|
|
66
|
+
this.parks.delete(key);
|
|
67
|
+
park?.claim?.resolve();
|
|
68
|
+
}
|
|
69
|
+
replace(key, build) {
|
|
70
|
+
if (this.stopped || this.replacements.has(key))
|
|
71
|
+
return;
|
|
72
|
+
const timer = setTimeout(() => {
|
|
73
|
+
this.replacements.delete(key);
|
|
74
|
+
void this.park(key, build).catch((cause) => {
|
|
75
|
+
process.stderr.write(`senpi rpc replacement park failed: ${String(cause)}\n`);
|
|
76
|
+
});
|
|
77
|
+
}, 0);
|
|
78
|
+
timer.unref?.();
|
|
79
|
+
this.replacements.set(key, timer);
|
|
80
|
+
}
|
|
81
|
+
/** Fences new builds synchronously; every build already accepted is closed when it finishes. */
|
|
82
|
+
async stop() {
|
|
83
|
+
this.stopped = true;
|
|
84
|
+
for (const timer of this.replacements.values())
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
this.replacements.clear();
|
|
87
|
+
await Promise.all([...this.parks].map(async ([key, park]) => {
|
|
88
|
+
await park.ready.catch(() => { });
|
|
89
|
+
if (park.claim)
|
|
90
|
+
await park.claim.promise;
|
|
91
|
+
else
|
|
92
|
+
await this.retire(key, park);
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
retire(key, park) {
|
|
96
|
+
clearTimeout(park.expiry);
|
|
97
|
+
park.closing ??= (async () => {
|
|
98
|
+
try {
|
|
99
|
+
if (park.opened)
|
|
100
|
+
await this.close(park.opened);
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
if (this.parks.get(key) === park)
|
|
104
|
+
this.parks.delete(key);
|
|
105
|
+
}
|
|
106
|
+
})();
|
|
107
|
+
return park.closing;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=host-park-ledger.js.map
|
|
@@ -15,7 +15,10 @@ export function observeLifecycleDelivery(record) {
|
|
|
15
15
|
return record;
|
|
16
16
|
if (record.command === "get_state")
|
|
17
17
|
return { ...record, data: observeState(data) };
|
|
18
|
-
if (record.command === "open_session"
|
|
18
|
+
if ((record.command === "open_session" || record.command === "claim_session") &&
|
|
19
|
+
"state" in data &&
|
|
20
|
+
typeof data.state === "object" &&
|
|
21
|
+
data.state !== null)
|
|
19
22
|
return { ...record, data: { ...data, state: observeState(data.state) } };
|
|
20
23
|
return record;
|
|
21
24
|
}
|
|
@@ -25,6 +25,12 @@ export type LooplessLoopHooks = (event: string, payload: JsonValue) => Promise<J
|
|
|
25
25
|
* (`errors`).
|
|
26
26
|
*/
|
|
27
27
|
export declare function extensionLoopHooks(runner: ExtensionRunner, twoSidedHome: TwoSidedHome, cwd: string, call: LoopHookCall): LooplessLoopHooks;
|
|
28
|
+
/**
|
|
29
|
+
* The user's loop hooks, which a hand runs for a hosted loop: its non-builtin extensions (C7(c), K5) and the hooks
|
|
30
|
+
* builtin, which runs the user's shell hooks (C8). Every other builtin is the loop's own machinery (model, compaction,
|
|
31
|
+
* todo, search): each side loads its own builtins, so those run where the loop runs, as S29 never forwards builtins.
|
|
32
|
+
*/
|
|
33
|
+
export declare const isUserLoopHook: (extensionPath: string) => boolean;
|
|
28
34
|
/** A message a loop hook sent during its call, for the loop to send with the same options. */
|
|
29
35
|
export interface SentLoopMessage {
|
|
30
36
|
readonly message: Parameters<LoopHookCallFacts["sendMessage"]>[0];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import { forwardToolEvents } from "../../core/extensions/two-sided-forwarding.js";
|
|
3
|
+
import { hookModelOf, hookRequestOutputOf, parseHookRequestInput } from "../../core/hand/hook-contract.js";
|
|
3
4
|
/**
|
|
4
5
|
* A loopless runtime's own extensions' `tool_call`/`tool_result` handlers, emitted as a session emits them. On a hand
|
|
5
6
|
* (a call that carries its nested requests), a two-sided extension's handlers are forwarded to the loop that owns the
|
|
@@ -78,6 +79,18 @@ export function extensionLoopHooks(runner, twoSidedHome, cwd, call) {
|
|
|
78
79
|
...(preview === undefined ? {} : { preview }),
|
|
79
80
|
})));
|
|
80
81
|
}
|
|
82
|
+
if (event === "before_provider_request") {
|
|
83
|
+
// The hosted loop's request hooks (CK21): the user's hooks get the projected input (payload and effective model,
|
|
84
|
+
// no headers), and the reply's `output` carries the payload they produced.
|
|
85
|
+
const input = parseHookRequestInput(payload.input);
|
|
86
|
+
const model = hookModelOf(input);
|
|
87
|
+
return call.run(sessionId, cwd, idle, (effects) => dispatchLoopHook(runner, call, effects, async () => ({
|
|
88
|
+
output: hookRequestOutputOf(input, await runner.emitBeforeProviderRequest(structuredClone(input.payload), undefined, undefined, {
|
|
89
|
+
only: isUserLoopHook,
|
|
90
|
+
...(model === undefined ? {} : { model }),
|
|
91
|
+
})),
|
|
92
|
+
})));
|
|
93
|
+
}
|
|
81
94
|
throw new Error(`no loop hooks run on a hand for ${event}`);
|
|
82
95
|
};
|
|
83
96
|
}
|
|
@@ -86,7 +99,7 @@ export function extensionLoopHooks(runner, twoSidedHome, cwd, call) {
|
|
|
86
99
|
* builtin, which runs the user's shell hooks (C8). Every other builtin is the loop's own machinery (model, compaction,
|
|
87
100
|
* todo, search): each side loads its own builtins, so those run where the loop runs, as S29 never forwards builtins.
|
|
88
101
|
*/
|
|
89
|
-
const isUserLoopHook = (extensionPath) => !extensionPath.startsWith("<builtin:") || extensionPath === "<builtin:hooks>";
|
|
102
|
+
export const isUserLoopHook = (extensionPath) => !extensionPath.startsWith("<builtin:") || extensionPath === "<builtin:hooks>";
|
|
90
103
|
const INPUT_SOURCES = ["interactive", "rpc", "extension"];
|
|
91
104
|
const INPUT_ATTRIBUTIONS = ["user", "agent"];
|
|
92
105
|
const STREAMING_BEHAVIORS = ["steer", "followUp"];
|
|
@@ -15,6 +15,38 @@ export declare const HOST_RECORD_SCHEMAS: {
|
|
|
15
15
|
id: Type.TOptional<Type.TString>;
|
|
16
16
|
admissionId: Type.TOptional<Type.TString>;
|
|
17
17
|
type: Type.TLiteral<"open_session">;
|
|
18
|
+
} & {
|
|
19
|
+
retry: Type.TOptional<Type.TLiteral<true>>;
|
|
20
|
+
attended: Type.TOptional<Type.TLiteral<false>>;
|
|
21
|
+
spawnedBy: Type.TOptional<Type.TObject<{
|
|
22
|
+
parentSessionId: Type.TString;
|
|
23
|
+
rootSessionId: Type.TString;
|
|
24
|
+
taskId: Type.TString;
|
|
25
|
+
}>>;
|
|
26
|
+
expectedHostInstance: Type.TOptional<Type.TString>;
|
|
27
|
+
sessionPath: Type.TOptional<Type.TString>;
|
|
28
|
+
cwd: Type.TOptional<Type.TString>;
|
|
29
|
+
provider: Type.TOptional<Type.TString>;
|
|
30
|
+
modelId: Type.TOptional<Type.TString>;
|
|
31
|
+
thinkingLevel: Type.TOptional<Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>>;
|
|
32
|
+
permissionPreset: Type.TOptional<Type.TString>;
|
|
33
|
+
retain_on_disconnect: Type.TOptional<Type.TBoolean>;
|
|
34
|
+
kind: Type.TOptional<Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>>;
|
|
35
|
+
context: Type.TOptional<Type.TRecord<"^.*$", Type.TString>>;
|
|
36
|
+
auto_title: Type.TOptional<Type.TBoolean>;
|
|
37
|
+
durableSessionId: Type.TOptional<Type.TString>;
|
|
38
|
+
promptSurface: Type.TOptional<Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>>;
|
|
39
|
+
browserEngine: Type.TOptional<Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>>;
|
|
40
|
+
retryFallback: Type.TOptional<Type.TObject<{
|
|
41
|
+
modelFallback: Type.TBoolean;
|
|
42
|
+
fallbackChains: Type.TRecord<"^.*$", Type.TImmutable<Type.TArray<Type.TString>>>;
|
|
43
|
+
}>>;
|
|
44
|
+
env: Type.TOptional<Type.TRecord<"^.*$", Type.TString>>;
|
|
45
|
+
}>;
|
|
46
|
+
claim_session: Type.TObject<{
|
|
47
|
+
id: Type.TOptional<Type.TString>;
|
|
48
|
+
admissionId: Type.TOptional<Type.TString>;
|
|
49
|
+
type: Type.TLiteral<"claim_session">;
|
|
18
50
|
} & {
|
|
19
51
|
readonly retry: Type.TOptional<Type.TLiteral<true>>;
|
|
20
52
|
readonly attended: Type.TOptional<Type.TLiteral<false>>;
|
|
@@ -25,7 +57,6 @@ export declare const HOST_RECORD_SCHEMAS: {
|
|
|
25
57
|
}>>;
|
|
26
58
|
readonly expectedHostInstance: Type.TOptional<Type.TString>;
|
|
27
59
|
readonly sessionPath: Type.TOptional<Type.TString>;
|
|
28
|
-
readonly cwd: Type.TOptional<Type.TString>;
|
|
29
60
|
readonly provider: Type.TOptional<Type.TString>;
|
|
30
61
|
readonly modelId: Type.TOptional<Type.TString>;
|
|
31
62
|
readonly thinkingLevel: Type.TOptional<Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>>;
|
|
@@ -42,6 +73,16 @@ export declare const HOST_RECORD_SCHEMAS: {
|
|
|
42
73
|
fallbackChains: Type.TRecord<"^.*$", Type.TImmutable<Type.TArray<Type.TString>>>;
|
|
43
74
|
}>>;
|
|
44
75
|
readonly env: Type.TOptional<Type.TRecord<"^.*$", Type.TString>>;
|
|
76
|
+
readonly cwd: Type.TString;
|
|
77
|
+
}>;
|
|
78
|
+
park_session: Type.TObject<{
|
|
79
|
+
id: Type.TOptional<Type.TString>;
|
|
80
|
+
admissionId: Type.TOptional<Type.TString>;
|
|
81
|
+
type: Type.TLiteral<"park_session">;
|
|
82
|
+
} & {
|
|
83
|
+
readonly cwd: Type.TString;
|
|
84
|
+
readonly kind: Type.TOptional<Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>>;
|
|
85
|
+
readonly context: Type.TOptional<Type.TRecord<"^.*$", Type.TString>>;
|
|
45
86
|
}>;
|
|
46
87
|
close_session: Type.TObject<{
|
|
47
88
|
id: Type.TOptional<Type.TString>;
|
|
@@ -9,32 +9,35 @@ const uiResponseFrame = {
|
|
|
9
9
|
uiRequestId: OptId,
|
|
10
10
|
answerId: OptId,
|
|
11
11
|
};
|
|
12
|
+
const openProperties = {
|
|
13
|
+
retry: Opt(Type.Literal(true)),
|
|
14
|
+
attended: Opt(Type.Literal(false)),
|
|
15
|
+
spawnedBy: Opt(Type.Object({ parentSessionId: Id, rootSessionId: Id, taskId: Id })),
|
|
16
|
+
expectedHostInstance: OptId,
|
|
17
|
+
sessionPath: OptPath,
|
|
18
|
+
cwd: OptPath,
|
|
19
|
+
provider: OptId,
|
|
20
|
+
modelId: OptId,
|
|
21
|
+
thinkingLevel: Opt(ThinkingLevel),
|
|
22
|
+
permissionPreset: OptId,
|
|
23
|
+
retain_on_disconnect: OptBool,
|
|
24
|
+
kind: Opt(SessionKind),
|
|
25
|
+
context: Opt(SessionContext),
|
|
26
|
+
auto_title: OptBool,
|
|
27
|
+
durableSessionId: OptId,
|
|
28
|
+
promptSurface: Opt(literals("terminal", "app", "chat")),
|
|
29
|
+
browserEngine: Opt(literals("connected", "builtin", "none")),
|
|
30
|
+
retryFallback: Opt(RetryFallback),
|
|
31
|
+
env: Opt(SessionEnv),
|
|
32
|
+
};
|
|
12
33
|
export const HOST_RECORD_SCHEMAS = {
|
|
13
34
|
get_protocol_info: command("get_protocol_info", {
|
|
14
35
|
auth: Opt(Type.Object({ client_nonce: Id })),
|
|
15
36
|
observe: OptBool,
|
|
16
37
|
}),
|
|
17
|
-
open_session: command("open_session",
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
spawnedBy: Opt(Type.Object({ parentSessionId: Id, rootSessionId: Id, taskId: Id })),
|
|
21
|
-
expectedHostInstance: OptId,
|
|
22
|
-
sessionPath: OptPath,
|
|
23
|
-
cwd: OptPath,
|
|
24
|
-
provider: OptId,
|
|
25
|
-
modelId: OptId,
|
|
26
|
-
thinkingLevel: Opt(ThinkingLevel),
|
|
27
|
-
permissionPreset: OptId,
|
|
28
|
-
retain_on_disconnect: OptBool,
|
|
29
|
-
kind: Opt(SessionKind),
|
|
30
|
-
context: Opt(SessionContext),
|
|
31
|
-
auto_title: OptBool,
|
|
32
|
-
durableSessionId: OptId,
|
|
33
|
-
promptSurface: Opt(literals("terminal", "app", "chat")),
|
|
34
|
-
browserEngine: Opt(literals("connected", "builtin", "none")),
|
|
35
|
-
retryFallback: Opt(RetryFallback),
|
|
36
|
-
env: Opt(SessionEnv),
|
|
37
|
-
}),
|
|
38
|
+
open_session: command("open_session", openProperties),
|
|
39
|
+
claim_session: command("claim_session", { ...openProperties, cwd: PathStr }),
|
|
40
|
+
park_session: command("park_session", { cwd: PathStr, kind: Opt(SessionKind), context: Opt(SessionContext) }),
|
|
38
41
|
close_session: command("close_session", { sessionId: Id }),
|
|
39
42
|
move_session: Type.Union([
|
|
40
43
|
move({ op: Type.Literal("prepare"), moveId: Id }),
|
|
@@ -70,6 +70,38 @@ export declare const RPC_INBOUND_SCHEMAS: {
|
|
|
70
70
|
id: import("typebox").TOptional<import("typebox").TString>;
|
|
71
71
|
admissionId: import("typebox").TOptional<import("typebox").TString>;
|
|
72
72
|
type: import("typebox").TLiteral<"open_session">;
|
|
73
|
+
} & {
|
|
74
|
+
retry: import("typebox").TOptional<import("typebox").TLiteral<true>>;
|
|
75
|
+
attended: import("typebox").TOptional<import("typebox").TLiteral<false>>;
|
|
76
|
+
spawnedBy: import("typebox").TOptional<import("typebox").TObject<{
|
|
77
|
+
parentSessionId: import("typebox").TString;
|
|
78
|
+
rootSessionId: import("typebox").TString;
|
|
79
|
+
taskId: import("typebox").TString;
|
|
80
|
+
}>>;
|
|
81
|
+
expectedHostInstance: import("typebox").TOptional<import("typebox").TString>;
|
|
82
|
+
sessionPath: import("typebox").TOptional<import("typebox").TString>;
|
|
83
|
+
cwd: import("typebox").TOptional<import("typebox").TString>;
|
|
84
|
+
provider: import("typebox").TOptional<import("typebox").TString>;
|
|
85
|
+
modelId: import("typebox").TOptional<import("typebox").TString>;
|
|
86
|
+
thinkingLevel: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<string>, ...import("typebox").TLiteral<string>[]]>>;
|
|
87
|
+
permissionPreset: import("typebox").TOptional<import("typebox").TString>;
|
|
88
|
+
retain_on_disconnect: import("typebox").TOptional<import("typebox").TBoolean>;
|
|
89
|
+
kind: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<string>, ...import("typebox").TLiteral<string>[]]>>;
|
|
90
|
+
context: import("typebox").TOptional<import("typebox").TRecord<"^.*$", import("typebox").TString>>;
|
|
91
|
+
auto_title: import("typebox").TOptional<import("typebox").TBoolean>;
|
|
92
|
+
durableSessionId: import("typebox").TOptional<import("typebox").TString>;
|
|
93
|
+
promptSurface: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<string>, ...import("typebox").TLiteral<string>[]]>>;
|
|
94
|
+
browserEngine: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<string>, ...import("typebox").TLiteral<string>[]]>>;
|
|
95
|
+
retryFallback: import("typebox").TOptional<import("typebox").TObject<{
|
|
96
|
+
modelFallback: import("typebox").TBoolean;
|
|
97
|
+
fallbackChains: import("typebox").TRecord<"^.*$", import("typebox").TImmutable<import("typebox").TArray<import("typebox").TString>>>;
|
|
98
|
+
}>>;
|
|
99
|
+
env: import("typebox").TOptional<import("typebox").TRecord<"^.*$", import("typebox").TString>>;
|
|
100
|
+
}>;
|
|
101
|
+
readonly claim_session: import("typebox").TObject<{
|
|
102
|
+
id: import("typebox").TOptional<import("typebox").TString>;
|
|
103
|
+
admissionId: import("typebox").TOptional<import("typebox").TString>;
|
|
104
|
+
type: import("typebox").TLiteral<"claim_session">;
|
|
73
105
|
} & {
|
|
74
106
|
readonly retry: import("typebox").TOptional<import("typebox").TLiteral<true>>;
|
|
75
107
|
readonly attended: import("typebox").TOptional<import("typebox").TLiteral<false>>;
|
|
@@ -80,7 +112,6 @@ export declare const RPC_INBOUND_SCHEMAS: {
|
|
|
80
112
|
}>>;
|
|
81
113
|
readonly expectedHostInstance: import("typebox").TOptional<import("typebox").TString>;
|
|
82
114
|
readonly sessionPath: import("typebox").TOptional<import("typebox").TString>;
|
|
83
|
-
readonly cwd: import("typebox").TOptional<import("typebox").TString>;
|
|
84
115
|
readonly provider: import("typebox").TOptional<import("typebox").TString>;
|
|
85
116
|
readonly modelId: import("typebox").TOptional<import("typebox").TString>;
|
|
86
117
|
readonly thinkingLevel: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<string>, ...import("typebox").TLiteral<string>[]]>>;
|
|
@@ -97,6 +128,16 @@ export declare const RPC_INBOUND_SCHEMAS: {
|
|
|
97
128
|
fallbackChains: import("typebox").TRecord<"^.*$", import("typebox").TImmutable<import("typebox").TArray<import("typebox").TString>>>;
|
|
98
129
|
}>>;
|
|
99
130
|
readonly env: import("typebox").TOptional<import("typebox").TRecord<"^.*$", import("typebox").TString>>;
|
|
131
|
+
readonly cwd: import("typebox").TString;
|
|
132
|
+
}>;
|
|
133
|
+
readonly park_session: import("typebox").TObject<{
|
|
134
|
+
id: import("typebox").TOptional<import("typebox").TString>;
|
|
135
|
+
admissionId: import("typebox").TOptional<import("typebox").TString>;
|
|
136
|
+
type: import("typebox").TLiteral<"park_session">;
|
|
137
|
+
} & {
|
|
138
|
+
readonly cwd: import("typebox").TString;
|
|
139
|
+
readonly kind: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<string>, ...import("typebox").TLiteral<string>[]]>>;
|
|
140
|
+
readonly context: import("typebox").TOptional<import("typebox").TRecord<"^.*$", import("typebox").TString>>;
|
|
100
141
|
}>;
|
|
101
142
|
readonly close_session: import("typebox").TObject<{
|
|
102
143
|
id: import("typebox").TOptional<import("typebox").TString>;
|
|
@@ -37,12 +37,15 @@ function fieldBoundsError(record) {
|
|
|
37
37
|
const payload = rpcCommandPayloadError(record) ?? rpcMessageLengthError(record);
|
|
38
38
|
if (payload !== undefined)
|
|
39
39
|
return payload;
|
|
40
|
-
if (record.type === "open_session" ||
|
|
40
|
+
if (record.type === "open_session" ||
|
|
41
|
+
record.type === "warm" ||
|
|
42
|
+
record.type === "park_session" ||
|
|
43
|
+
record.type === "claim_session") {
|
|
41
44
|
const context = sessionContextError(record.context);
|
|
42
45
|
if (context !== undefined)
|
|
43
46
|
return context;
|
|
44
47
|
}
|
|
45
|
-
if (record.type === "open_session")
|
|
48
|
+
if (record.type === "open_session" || record.type === "claim_session")
|
|
46
49
|
return sessionRetryFallbackError(record.retryFallback) ?? sessionEnvShapeError(record.env);
|
|
47
50
|
if (record.type === "set_retry_fallback")
|
|
48
51
|
return sessionRetryFallbackError(record.retryFallback);
|
|
@@ -163,6 +163,8 @@ export declare const RPC_METHOD_CLASS: {
|
|
|
163
163
|
readonly classify: typeof openSessionClass;
|
|
164
164
|
readonly version: 2;
|
|
165
165
|
};
|
|
166
|
+
readonly claim_session: "device_admin";
|
|
167
|
+
readonly park_session: "device_admin";
|
|
166
168
|
readonly resume_session: "thread";
|
|
167
169
|
readonly fork: "thread";
|
|
168
170
|
readonly clone: "thread";
|
|
@@ -207,6 +207,9 @@ export const RPC_METHOD_CLASS = {
|
|
|
207
207
|
// thread by id; device_admin when the record names a host path, a permission preset or a tool environment
|
|
208
208
|
new_session: { classify: newSessionClass, version: 1 },
|
|
209
209
|
open_session: { classify: openSessionClass, version: 2 },
|
|
210
|
+
// Both commands require a cwd; claim has the same device authority as a cwd-naming open.
|
|
211
|
+
claim_session: "device_admin",
|
|
212
|
+
park_session: "device_admin",
|
|
210
213
|
resume_session: "thread",
|
|
211
214
|
fork: "thread",
|
|
212
215
|
clone: "thread",
|
|
@@ -177,7 +177,7 @@ export function createHostCore(options, writer, capabilities = parseClientCapabi
|
|
|
177
177
|
return;
|
|
178
178
|
}
|
|
179
179
|
const command = parsed;
|
|
180
|
-
const response = await gate.dispatch(command.type === "open_session" &&
|
|
180
|
+
const response = await gate.dispatch((command.type === "open_session" || command.type === "claim_session") &&
|
|
181
181
|
(delegated
|
|
182
182
|
? command.retain_on_disconnect !== true
|
|
183
183
|
: machineOwned && command.retain_on_disconnect === undefined)
|
|
@@ -255,7 +255,20 @@ type RpcCommandBody = RpcAttachmentCommand | (RpcSessionCommand & {
|
|
|
255
255
|
context?: Record<string, string>;
|
|
256
256
|
};
|
|
257
257
|
/** Compact callers may identify their own admission on any correlated session request. */
|
|
258
|
-
export type RpcCommand = RpcCommandBody
|
|
258
|
+
export type RpcCommand = (RpcCommandBody | {
|
|
259
|
+
id?: string;
|
|
260
|
+
/** Build one invisible session for later claim; never an attachment. Requires `park_claim`. */
|
|
261
|
+
type: "park_session";
|
|
262
|
+
cwd: string;
|
|
263
|
+
kind?: SessionKind;
|
|
264
|
+
context?: Record<string, string>;
|
|
265
|
+
} | (Omit<Extract<RpcCommandBody, {
|
|
266
|
+
type: "open_session";
|
|
267
|
+
}>, "type" | "cwd"> & {
|
|
268
|
+
/** Consume one ready park. A miss returns `claimed: false` and never builds a session. */
|
|
269
|
+
type: "claim_session";
|
|
270
|
+
cwd: string;
|
|
271
|
+
})) & {
|
|
259
272
|
readonly admissionId?: string;
|
|
260
273
|
};
|
|
261
274
|
/** Stdin records: session/host commands plus extension-UI replies and progress, and host-request answers. */
|
|
@@ -19,6 +19,27 @@ export interface RpcSessionPresence {
|
|
|
19
19
|
readonly held: number;
|
|
20
20
|
}
|
|
21
21
|
export type RpcHostCommandResponse = {
|
|
22
|
+
id?: string;
|
|
23
|
+
type: "response";
|
|
24
|
+
command: "park_session";
|
|
25
|
+
success: true;
|
|
26
|
+
data: {
|
|
27
|
+
state: "parked" | "already_parked" | "full";
|
|
28
|
+
};
|
|
29
|
+
} | {
|
|
30
|
+
id?: string;
|
|
31
|
+
type: "response";
|
|
32
|
+
command: "claim_session";
|
|
33
|
+
success: true;
|
|
34
|
+
data: {
|
|
35
|
+
claimed: false;
|
|
36
|
+
} | {
|
|
37
|
+
sessionId: string;
|
|
38
|
+
state: RpcSessionState;
|
|
39
|
+
attached?: boolean;
|
|
40
|
+
presence?: RpcSessionPresence;
|
|
41
|
+
};
|
|
42
|
+
} | {
|
|
22
43
|
id?: string;
|
|
23
44
|
type: "response";
|
|
24
45
|
command: "list_hands";
|
|
@@ -4,6 +4,7 @@ import type { RpcSessionEntry } from "./session-registry.ts";
|
|
|
4
4
|
/** A session-owned adapter around the classic command and extension-UI wiring. */
|
|
5
5
|
export interface RpcSessionBinding {
|
|
6
6
|
handle(command: object): Promise<void>;
|
|
7
|
+
setClientCapabilities?(capabilities: readonly string[]): void;
|
|
7
8
|
cancelPendingExtensionUiRequests?(): void;
|
|
8
9
|
/** A connection of the shared host left this session (`close_session`, a dropped or detached connection). */
|
|
9
10
|
connectionDetached?(connectionId: string): void;
|
|
@@ -40,6 +40,8 @@ export async function createRpcSessionBinding(sessionId, entry, writer, requestC
|
|
|
40
40
|
return carrier && record && firstOrdinal !== undefined ? { record, carrier, ordinal, firstOrdinal } : undefined;
|
|
41
41
|
};
|
|
42
42
|
const enqueueRecord = (record) => {
|
|
43
|
+
if (entry.speculative)
|
|
44
|
+
return;
|
|
43
45
|
toolSpans.observe(record);
|
|
44
46
|
const canonical = pairing?.take(record);
|
|
45
47
|
const refused = pairing?.refused(record) === true;
|
|
@@ -103,6 +105,8 @@ export async function createRpcSessionBinding(sessionId, entry, writer, requestC
|
|
|
103
105
|
writeInScope(record);
|
|
104
106
|
};
|
|
105
107
|
const writeStructuredInScope = bindToProviderScope((record) => {
|
|
108
|
+
if (entry.speculative)
|
|
109
|
+
return;
|
|
106
110
|
writer.structuredLanes.accept(sessionId, record);
|
|
107
111
|
const control = pairing?.structured(record);
|
|
108
112
|
if (control && lane)
|
|
@@ -151,7 +155,7 @@ export async function createRpcSessionBinding(sessionId, entry, writer, requestC
|
|
|
151
155
|
rpcOwnersByConnection.clear();
|
|
152
156
|
},
|
|
153
157
|
publishLoadedSurfacesChanged: (previous, digest) => {
|
|
154
|
-
if (entry.scope.state !== "closed")
|
|
158
|
+
if (!entry.speculative && entry.scope.state !== "closed")
|
|
155
159
|
writer.publishLoadedSurfacesChanged(sessionId, previous, digest);
|
|
156
160
|
},
|
|
157
161
|
...options,
|
|
@@ -171,6 +175,7 @@ export async function createRpcSessionBinding(sessionId, entry, writer, requestC
|
|
|
171
175
|
});
|
|
172
176
|
await handler.ready;
|
|
173
177
|
return {
|
|
178
|
+
setClientCapabilities: (capabilities) => runWithProviderScope(entry.scope, () => handler.setClientCapabilities(capabilities)),
|
|
174
179
|
handle: (command) => {
|
|
175
180
|
if (writer.handleMcpForm(command))
|
|
176
181
|
return Promise.resolve();
|
|
@@ -7,6 +7,8 @@ export declare class SessionConnectionContext {
|
|
|
7
7
|
private readonly delegationOf;
|
|
8
8
|
constructor(ownerOf: (id: string) => ExtensionTransportOwner | undefined, delegationOf?: (id: string) => DelegationDescriptor | undefined);
|
|
9
9
|
run<T>(id: string, task: () => T): T;
|
|
10
|
+
/** Host-owned background construction has no requesting transport or inherited delegation. */
|
|
11
|
+
outside<T>(task: () => T): T;
|
|
10
12
|
/** The delegation the running line captured at its start, or undefined for a connection that never declared. */
|
|
11
13
|
get delegation(): DelegationDescriptor | undefined;
|
|
12
14
|
/**
|
|
@@ -10,6 +10,10 @@ export class SessionConnectionContext {
|
|
|
10
10
|
const delegation = this.delegationOf(id);
|
|
11
11
|
return this.storage.run({ id, owner: this.ownerOf(id), ...(delegation === undefined ? {} : { delegation }) }, task);
|
|
12
12
|
}
|
|
13
|
+
/** Host-owned background construction has no requesting transport or inherited delegation. */
|
|
14
|
+
outside(task) {
|
|
15
|
+
return this.storage.exit(task);
|
|
16
|
+
}
|
|
13
17
|
/** The delegation the running line captured at its start, or undefined for a connection that never declared. */
|
|
14
18
|
get delegation() {
|
|
15
19
|
return this.storage.getStore()?.delegation;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { SessionPathReservations } from "./host-reservations.ts";
|
|
2
2
|
import { type OpenRpcSession, type RpcSessionEntry, type RpcSessionLaunchProfile, type RpcSessionOpenOptions } from "./session-registry-types.ts";
|
|
3
3
|
export declare function attachToOpenSession(entries: ReadonlyMap<string, RpcSessionEntry>, sessionPath: string, profile: RpcSessionLaunchProfile, options: RpcSessionOpenOptions | undefined, pathReservations: SessionPathReservations | undefined, now: number): Promise<OpenRpcSession>;
|
|
4
|
+
/** The live launch choices shared by attach-on-open and claiming an already-built session. */
|
|
5
|
+
export declare function applyAttachedProfile(entry: RpcSessionEntry, profile: RpcSessionLaunchProfile): void;
|
|
4
6
|
//# sourceMappingURL=session-registry-attach.d.ts.map
|
|
@@ -102,6 +102,21 @@ export async function attachToOpenSession(entries, sessionPath, profile, options
|
|
|
102
102
|
entry.retainOnDisconnect = true;
|
|
103
103
|
if (!entry.durableSessionId)
|
|
104
104
|
throw new RpcSessionRegistryError("session_path_in_use");
|
|
105
|
+
applyAttachedProfile(entry, profile);
|
|
106
|
+
entry.lastCommandAt = now;
|
|
107
|
+
if (wasParked) {
|
|
108
|
+
entry.lifecycleMutex = entry.lifecycleMutex.then(() => entry.runtime?.emitAttachmentEvent("session_resumed"));
|
|
109
|
+
await entry.lifecycleMutex;
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
sessionId: handle,
|
|
113
|
+
durableSessionId: entry.durableSessionId,
|
|
114
|
+
sessionPath: entry.sessionPath,
|
|
115
|
+
attached: true,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** The live launch choices shared by attach-on-open and claiming an already-built session. */
|
|
119
|
+
export function applyAttachedProfile(entry, profile) {
|
|
105
120
|
// The surface, browser engine and permission preset follow the client: an attach that names one
|
|
106
121
|
// moves the live session to it; an attach without one keeps what the session has.
|
|
107
122
|
if (profile.promptSurface !== undefined && profile.promptSurface !== entry.profile.promptSurface) {
|
|
@@ -121,16 +136,5 @@ export async function attachToOpenSession(entries, sessionPath, profile, options
|
|
|
121
136
|
entry.profile = frozenProfile(withClientPreset(entry.profile, namedPreset));
|
|
122
137
|
entry.runtime?.setPermissionPreset(namedPreset);
|
|
123
138
|
}
|
|
124
|
-
entry.lastCommandAt = now;
|
|
125
|
-
if (wasParked) {
|
|
126
|
-
entry.lifecycleMutex = entry.lifecycleMutex.then(() => entry.runtime?.emitAttachmentEvent("session_resumed"));
|
|
127
|
-
await entry.lifecycleMutex;
|
|
128
|
-
}
|
|
129
|
-
return {
|
|
130
|
-
sessionId: handle,
|
|
131
|
-
durableSessionId: entry.durableSessionId,
|
|
132
|
-
sessionPath: entry.sessionPath,
|
|
133
|
-
attached: true,
|
|
134
|
-
};
|
|
135
139
|
}
|
|
136
140
|
//# sourceMappingURL=session-registry-attach.js.map
|
|
@@ -70,6 +70,8 @@ export async function settlePendingClaim(pending, sessionPath, graceMs) {
|
|
|
70
70
|
/** Reconcile path and durable identity after runtime replacement. */
|
|
71
71
|
export function syncRuntimeMetadata(entries, reservations, pathReservations) {
|
|
72
72
|
for (const entry of entries) {
|
|
73
|
+
if (entry.speculative)
|
|
74
|
+
continue;
|
|
73
75
|
const manager = entry.runtime?.session.sessionManager;
|
|
74
76
|
if (!manager)
|
|
75
77
|
continue;
|