@adhisang/minecraft-modding-mcp 6.2.0 → 7.0.0-rc.0
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 +71 -0
- package/README.md +21 -5
- package/dist/cache-policy.d.ts +71 -0
- package/dist/cache-policy.js +83 -0
- package/dist/cache-registry.js +6 -6
- package/dist/cli.js +74 -3
- package/dist/compat-stdio-transport.d.ts +1 -1
- package/dist/compat-stdio-transport.js +13 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.js +8 -2
- package/dist/decompiler/vineflower.d.ts +1 -0
- package/dist/decompiler/vineflower.js +8 -5
- package/dist/entry-tools/analyze-mod-service.d.ts +70 -136
- package/dist/entry-tools/analyze-symbol-service.d.ts +112 -150
- package/dist/entry-tools/compare-minecraft-service.d.ts +59 -145
- package/dist/entry-tools/entry-tool-schema.d.ts +38 -4
- package/dist/entry-tools/entry-tool-schema.js +4 -1
- package/dist/entry-tools/inspect-minecraft/internal.d.ts +235 -799
- package/dist/entry-tools/inspect-minecraft/internal.js +65 -28
- package/dist/entry-tools/inspect-minecraft-service.d.ts +372 -1736
- package/dist/entry-tools/inspect-minecraft-service.js +1 -1
- package/dist/entry-tools/manage-cache-service.d.ts +81 -91
- package/dist/entry-tools/validate-project/cases/project-summary.d.ts +7 -7
- package/dist/entry-tools/validate-project-service.d.ts +164 -592
- package/dist/entry-tools/verify-mixin-target-service.d.ts +3 -19
- package/dist/era-classifier.d.ts +161 -0
- package/dist/era-classifier.js +292 -0
- package/dist/error-mapping.js +9 -2
- package/dist/index.d.ts +42 -4
- package/dist/index.js +637 -475
- package/dist/java-process.d.ts +2 -0
- package/dist/java-process.js +22 -2
- package/dist/json-rpc-framing.d.ts +77 -1
- package/dist/json-rpc-framing.js +249 -13
- package/dist/mapping/loaders/tiny-loom-selection.d.ts +88 -0
- package/dist/mapping/loaders/tiny-loom-selection.js +223 -0
- package/dist/mapping/loaders/tiny-loom.js +45 -33
- package/dist/mapping/loaders/tiny-maven.js +6 -11
- package/dist/mapping/parsers/tiny.d.ts +57 -0
- package/dist/mapping/parsers/tiny.js +99 -22
- package/dist/mapping-service.d.ts +19 -0
- package/dist/mapping-service.js +93 -9
- package/dist/mcp-helpers.d.ts +19 -2
- package/dist/mcp-helpers.js +48 -6
- package/dist/minecraft-explorer-service.d.ts +1 -1
- package/dist/mixin/types.d.ts +8 -0
- package/dist/mod-analyzer.js +7 -7
- package/dist/mod-decompile-service.js +1 -0
- package/dist/nbt/java-nbt-codec.js +12 -2
- package/dist/nbt/json-patch.js +14 -3
- package/dist/nbt/pipeline.js +40 -3
- package/dist/nbt/typed-json.js +26 -1
- package/dist/registration-adapter.d.ts +32 -0
- package/dist/registration-adapter.js +52 -0
- package/dist/request-context.d.ts +7 -0
- package/dist/request-context.js +9 -0
- package/dist/resources.d.ts +1 -1
- package/dist/resources.js +25 -19
- package/dist/server-identity.d.ts +27 -0
- package/dist/server-identity.js +26 -0
- package/dist/source/access-validate.js +53 -0
- package/dist/source/artifact-resolver.d.ts +69 -1
- package/dist/source/artifact-resolver.js +215 -14
- package/dist/source/class-source.d.ts +22 -0
- package/dist/source/class-source.js +162 -29
- package/dist/source/did-you-mean.d.ts +12 -1
- package/dist/source/did-you-mean.js +6 -2
- package/dist/source/file-access.js +150 -46
- package/dist/source/indexer.js +1 -0
- package/dist/source/nested-jars.d.ts +19 -0
- package/dist/source/nested-jars.js +90 -21
- package/dist/source/shared-utils.d.ts +21 -0
- package/dist/source/shared-utils.js +23 -0
- package/dist/source-service.d.ts +12 -0
- package/dist/source-service.js +3 -0
- package/dist/stdio-supervisor.d.ts +357 -2
- package/dist/stdio-supervisor.js +1031 -80
- package/dist/storage/db.d.ts +2 -1
- package/dist/storage/db.js +15 -8
- package/dist/synthetic-decorator.d.ts +24 -0
- package/dist/synthetic-decorator.js +48 -0
- package/dist/tool-contract-manifest.js +1 -1
- package/dist/tool-guidance.d.ts +17 -1
- package/dist/tool-guidance.js +417 -13
- package/dist/tool-schema-registry.d.ts +2 -0
- package/dist/tool-schema-registry.js +4 -0
- package/dist/tool-schemas.d.ts +2214 -3915
- package/dist/tool-schemas.js +34 -7
- package/dist/types.d.ts +35 -0
- package/dist/v1-parity-schemas.d.ts +7 -0
- package/dist/v1-parity-schemas.js +5584 -0
- package/dist/version-diff-service.d.ts +33 -0
- package/dist/version-diff-service.js +148 -3
- package/dist/version-service.js +36 -14
- package/dist/warning-details.js +18 -1
- package/docs/README-ja.md +9 -3
- package/docs/tool-reference.md +267 -22
- package/package.json +12 -9
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
import { type ChildProcessWithoutNullStreams } from "node:child_process";
|
|
2
|
-
import type { JSONRPCMessage, JSONRPCResponse } from "@modelcontextprotocol/
|
|
2
|
+
import type { JSONRPCMessage, JSONRPCResponse } from "@modelcontextprotocol/server";
|
|
3
|
+
import { type ConcreteFramingMode } from "./json-rpc-framing.js";
|
|
4
|
+
import { type Era } from "./era-classifier.js";
|
|
3
5
|
export declare function loadValidateProjectTimeoutMs(value?: string | undefined): number;
|
|
4
6
|
export declare function computeWorkerStartupWatchdogMs(validateProjectTimeoutMs: number): number;
|
|
5
7
|
export declare function computeRestartBackoffMs(retryIndex: number): number;
|
|
8
|
+
/**
|
|
9
|
+
* How long an adopted worker must stay ready before a CLEAN voluntary
|
|
10
|
+
* stand-down counts as the end of a generation that actually served.
|
|
11
|
+
*
|
|
12
|
+
* A worker stands down on stdin EOF. On a host that hands every spawned child
|
|
13
|
+
* a stdin which closes immediately, that EOF arrives while the worker is still
|
|
14
|
+
* starting: it writes its ready marker, is adopted (which clears the restart
|
|
15
|
+
* backoff), and exits 0 in the same breath. Answering that with the 100 ms
|
|
16
|
+
* restart floor respawns a ~125 MB process ten times a second forever, so a
|
|
17
|
+
* stand-down inside this window escalates the backoff instead.
|
|
18
|
+
*
|
|
19
|
+
* A CRASH is deliberately not covered: it may be transient and keeps the
|
|
20
|
+
* prompt replacement the restart suites pin, whereas a clean stand-down means
|
|
21
|
+
* the host closed the pipe and will close the replacement's stdin the same way.
|
|
22
|
+
*/
|
|
23
|
+
export declare const MIN_HEALTHY_WORKER_READY_MS = 1000;
|
|
6
24
|
export declare function terminatePosixProcessGroup(pid: number, kill?: (pid: number, signal: NodeJS.Signals) => void): boolean;
|
|
7
25
|
export declare function buildWindowsTreeKillArgs(pid: number): string[];
|
|
8
26
|
export declare function shouldRetainUnavailableNotification(method: string): boolean;
|
|
@@ -16,6 +34,16 @@ export declare class RestartBackoffState {
|
|
|
16
34
|
private epoch;
|
|
17
35
|
reserve(now: number): RestartReservation;
|
|
18
36
|
reset(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Raise the escalation level without reserving a restart.
|
|
39
|
+
*
|
|
40
|
+
* Adoption resets the index, so a generation that was adopted and then died
|
|
41
|
+
* without ever serving arrives here with the level already cleared. This
|
|
42
|
+
* restores the level that the repeated failure has earned, which is what
|
|
43
|
+
* stops a self-cancelling adopt/reset cycle from pinning every restart to
|
|
44
|
+
* the 100 ms floor.
|
|
45
|
+
*/
|
|
46
|
+
escalateTo(level: number): void;
|
|
19
47
|
}
|
|
20
48
|
export declare function retryPosixTreeToken(pid: number, kill?: (pid: number, signal: NodeJS.Signals) => void): boolean;
|
|
21
49
|
export declare function settleTreeCleanupWithin(operation: Promise<boolean>, timeoutMs: number, onTimeout?: () => void): Promise<boolean>;
|
|
@@ -25,6 +53,8 @@ export type SupervisorOptions = {
|
|
|
25
53
|
clientWriter?: (message: JSONRPCMessage) => void;
|
|
26
54
|
treeTokenRetrier?: (pid: number) => boolean | Promise<boolean>;
|
|
27
55
|
treeCleanupTimeoutMs?: number;
|
|
56
|
+
cleanupTokenRetryBaseMs?: number;
|
|
57
|
+
cleanupTokenRetryCapMs?: number;
|
|
28
58
|
eventWriter?: (level: "warn" | "error" | "info", event: string, details?: Record<string, unknown>) => void;
|
|
29
59
|
monotonicNow?: () => number;
|
|
30
60
|
timerScheduler?: (callback: () => void, delayMs: number) => NodeJS.Timeout;
|
|
@@ -58,10 +88,58 @@ export type PendingRequestSnapshot = {
|
|
|
58
88
|
/** `true` when toolArgsRedacted contains sentinel placeholders (truncate/redact/overflow). */
|
|
59
89
|
toolArgsRedactedModified?: boolean;
|
|
60
90
|
startedAt: number;
|
|
91
|
+
/**
|
|
92
|
+
* Framing mode of the inbound frame that carried this request, captured at
|
|
93
|
+
* admission. Every terminal client-bound write for this request (forwarded
|
|
94
|
+
* worker response, timeout/queue-limit/restart synthesis) uses THIS mode —
|
|
95
|
+
* never the connection's latest inbound mode. Retained for the pending
|
|
96
|
+
* entry's whole lifetime (including client-cancelled tombstones) until the
|
|
97
|
+
* entry is discarded.
|
|
98
|
+
*/
|
|
99
|
+
mode?: ConcreteFramingMode;
|
|
100
|
+
/**
|
|
101
|
+
* The supervisor's era at this request's admission ("unselected" occurs
|
|
102
|
+
* only for era-neutral server/discover admitted before any lock). Always
|
|
103
|
+
* set at runtime by createPendingRequest, the sole constructor; optional at
|
|
104
|
+
* the type level for tolerant synthetic-builder inputs and exported-type
|
|
105
|
+
* compatibility — no reply BUILDER may read it. Carve-out: the terminal
|
|
106
|
+
* synthetic-decoration step (writeSyntheticReply → decorateSyntheticReply)
|
|
107
|
+
* reads `era` — and ONLY `era` — to gate modern-era decoration; the three
|
|
108
|
+
* captured context fields below remain unread everywhere.
|
|
109
|
+
*/
|
|
110
|
+
era?: Era;
|
|
111
|
+
/**
|
|
112
|
+
* Per-request modern protocol context, captured SHALLOW (values aliased
|
|
113
|
+
* as-is from params._meta — nothing may mutate an inbound params graph
|
|
114
|
+
* after admission, or captured snapshots would change retroactively) for
|
|
115
|
+
* shallow-valid modern-signal requests only; undefined for claim-less
|
|
116
|
+
* legacy traffic and for every initialize (initialize envelopes are
|
|
117
|
+
* ignored). Captured for downstream consumers; the supervisor itself must
|
|
118
|
+
* never read these three fields — no reply, synthesis, decoration, or
|
|
119
|
+
* forwarded frame may depend on them (the no-leak tests pin that).
|
|
120
|
+
* Synthetic decoration reads the snapshot's `era` alone, and the identity
|
|
121
|
+
* it stamps comes from src/server-identity.ts, never from request context.
|
|
122
|
+
*/
|
|
123
|
+
protocolVersion?: string;
|
|
124
|
+
clientCapabilities?: Record<string, unknown>;
|
|
125
|
+
clientInfo?: unknown;
|
|
61
126
|
lastStage?: string;
|
|
62
127
|
lastStageStartedAt?: number;
|
|
63
128
|
lastStageMeta?: unknown;
|
|
64
129
|
};
|
|
130
|
+
/**
|
|
131
|
+
* Frozen premigration reply for a tools/call whose name is not registered
|
|
132
|
+
* (typo OR flag-disabled tool — indistinguishable, exactly as the v1 SDK
|
|
133
|
+
* answered): a SUCCESSFUL CallToolResult with isError:true and one text
|
|
134
|
+
* content entry embedding the v1 error string. The v2 SDK throws a raw
|
|
135
|
+
* -32602 instead, so the supervisor synthesizes this envelope for
|
|
136
|
+
* LEGACY-era registry misses (see handleClientMessage) to keep the legacy
|
|
137
|
+
* wire byte-identical to the premigration baseline
|
|
138
|
+
* (tests/fixtures/premigration/error-code-inventory.json, disabled-tool
|
|
139
|
+
* row). The modern era keeps the raw -32602 (sanctioned: tool absence is a
|
|
140
|
+
* params problem on 2026-07-28, mirroring the SDK's own not-found mapping).
|
|
141
|
+
*/
|
|
142
|
+
export declare function buildUnknownToolNotFoundReply(id: RequestId, toolName: string): JSONRPCResponse;
|
|
65
143
|
export declare function buildLegacyJsonRpcError(id: RequestId): JSONRPCResponse;
|
|
66
144
|
export type RedactedToolArgs = {
|
|
67
145
|
args: Record<string, unknown>;
|
|
@@ -106,6 +184,8 @@ export declare class StdioSupervisor {
|
|
|
106
184
|
private readonly clientWriter;
|
|
107
185
|
private readonly treeTokenRetrier;
|
|
108
186
|
private readonly treeCleanupTimeoutMs;
|
|
187
|
+
private readonly cleanupTokenRetryBaseMs;
|
|
188
|
+
private readonly cleanupTokenRetryCapMs;
|
|
109
189
|
private readonly eventWriter;
|
|
110
190
|
private readonly monotonicNow;
|
|
111
191
|
private readonly timerScheduler;
|
|
@@ -124,10 +204,59 @@ export declare class StdioSupervisor {
|
|
|
124
204
|
private readonly unresolvedTreeTokens;
|
|
125
205
|
private readonly restartBackoff;
|
|
126
206
|
private readonly terminalChildren;
|
|
207
|
+
/**
|
|
208
|
+
* Monotonic worker-generation counter (incremented per successful spawn).
|
|
209
|
+
* Recorded into finality tombstones so retention can be bounded per
|
|
210
|
+
* generation; hand-injected children in tests that bypass spawnWorker run
|
|
211
|
+
* as generation 0.
|
|
212
|
+
*/
|
|
213
|
+
private workerGeneration;
|
|
214
|
+
/**
|
|
215
|
+
* Response-finality tombstones: request key → {originating worker
|
|
216
|
+
* generation, originating framing mode}, recorded by writeSyntheticReply
|
|
217
|
+
* the moment a synthetic response is written. While a tombstone exists, any
|
|
218
|
+
* worker RESPONSE for that id is discarded (with a logged
|
|
219
|
+
* `supervisor.late_response_discarded` event) instead of being forwarded —
|
|
220
|
+
* the synthesized response was terminal, and exactly one response per id
|
|
221
|
+
* must reach the client. A tombstone is cleared when its id is re-forwarded
|
|
222
|
+
* to a worker (forwardRequest), because a client may legally retry with the
|
|
223
|
+
* same id; finality is per request INSTANCE, not per id forever.
|
|
224
|
+
*
|
|
225
|
+
* `mode` is retained deliberately even though discard writes nothing today:
|
|
226
|
+
* a tombstoned id keeps its originating framing mode until discard, so any
|
|
227
|
+
* future terminal write for that id — should the discard policy ever gain
|
|
228
|
+
* one — answers in the originating framing.
|
|
229
|
+
*
|
|
230
|
+
* Retention bound: entries with generation ≤ G are dropped when the
|
|
231
|
+
* generation-G child emits "close" (process ended AND its stdio streams
|
|
232
|
+
* closed — Node's guarantee for that event). This is safe: worker frames
|
|
233
|
+
* only enter handleWorkerMessage from the CURRENT child, the supervisor
|
|
234
|
+
* only forwards ids with live pending entries, and forwarding clears the
|
|
235
|
+
* id's tombstone — so once every generation that could have seen a
|
|
236
|
+
* tombstoned id is gone with streams closed, no current child can ever
|
|
237
|
+
* deliver a frame for it. Also cleared wholesale on shutdown.
|
|
238
|
+
*/
|
|
239
|
+
private readonly syntheticTombstones;
|
|
127
240
|
private child;
|
|
128
241
|
private childReady;
|
|
242
|
+
/**
|
|
243
|
+
* Monotonic timestamp of the current generation's adoption, or undefined
|
|
244
|
+
* while no generation is adopted. Read once at exit to tell a generation
|
|
245
|
+
* that served from one that stood down the moment it came up.
|
|
246
|
+
*/
|
|
247
|
+
private childReadyAt;
|
|
248
|
+
/**
|
|
249
|
+
* Consecutive adopted generations that stood down CLEANLY before they had
|
|
250
|
+
* been ready for MIN_HEALTHY_WORKER_READY_MS. Any other outcome — a crash, a
|
|
251
|
+
* signal, a generation that served — clears it.
|
|
252
|
+
*/
|
|
253
|
+
private consecutiveImmediateStandDowns;
|
|
129
254
|
private shuttingDown;
|
|
130
255
|
private restartTimer;
|
|
256
|
+
private cleanupRetryTimer;
|
|
257
|
+
private cleanupRetryIndex;
|
|
258
|
+
private readonly cleanupRetryAttempts;
|
|
259
|
+
private readonly cleanupRetriesInFlight;
|
|
131
260
|
private startupWatchdog;
|
|
132
261
|
private validateBarrierKey;
|
|
133
262
|
private runningValidateKey;
|
|
@@ -136,24 +265,173 @@ export declare class StdioSupervisor {
|
|
|
136
265
|
private currentRetryReservation;
|
|
137
266
|
private retryPaused;
|
|
138
267
|
private workerStderrBuffer;
|
|
139
|
-
|
|
268
|
+
/**
|
|
269
|
+
* Framing mode of the most recently detected inbound client frame. NOT used
|
|
270
|
+
* for request-correlated writes (those use the originating request's
|
|
271
|
+
* captured mode); this is only the documented fallback for client-bound
|
|
272
|
+
* writes that correlate to no request id (worker-originated notifications
|
|
273
|
+
* and server->client requests forwarded at handleWorkerMessage, and
|
|
274
|
+
* untracked-id responses with no finality tombstone — tombstoned ids are
|
|
275
|
+
* discarded, never forwarded).
|
|
276
|
+
*/
|
|
277
|
+
private lastInboundClientMode;
|
|
278
|
+
/**
|
|
279
|
+
* Per-frame framing mode of every inbound client message, keyed by message
|
|
280
|
+
* object identity. Lets admission (createPendingRequest), queued-message
|
|
281
|
+
* flushes, and initialize replay recover the ORIGINATING frame's mode long
|
|
282
|
+
* after the frame was parsed.
|
|
283
|
+
*/
|
|
284
|
+
private readonly inboundFrameModes;
|
|
140
285
|
private initializeRequest;
|
|
141
286
|
private initializedNotification;
|
|
287
|
+
/**
|
|
288
|
+
* Number of queued requests that arrived before an initial initialize while
|
|
289
|
+
* the worker was unavailable. Only era-neutral modern discovers can occupy
|
|
290
|
+
* this prefix; readiness forwards it before initialize, then keeps the queue
|
|
291
|
+
* suffix gated until the initialization response.
|
|
292
|
+
*/
|
|
293
|
+
private initializePredecessorCount;
|
|
142
294
|
private clientInitialized;
|
|
143
295
|
private replayingInitialization;
|
|
144
296
|
private initializeSentToWorker;
|
|
297
|
+
/**
|
|
298
|
+
* Process-lifetime era state. The supervisor is the SOLE era gatekeeper:
|
|
299
|
+
* classification happens at admission (handleClientMessage), in stdin
|
|
300
|
+
* order. The first valid NON-discover era signal locks the era (initialize
|
|
301
|
+
* → legacy; shallow-valid modern `_meta` request → modern); the lock is
|
|
302
|
+
* one-way and survives worker restarts.
|
|
303
|
+
*/
|
|
304
|
+
private era;
|
|
305
|
+
/**
|
|
306
|
+
* Whether `start()` attached this instance to the real process stdio. Only
|
|
307
|
+
* then may a teardown touch process-wide state (the framing-fatal exit
|
|
308
|
+
* code); white-box suites construct supervisors without starting them and
|
|
309
|
+
* must never have their own runner's exit status rewritten.
|
|
310
|
+
*/
|
|
311
|
+
private ownsProcessStdio;
|
|
312
|
+
/**
|
|
313
|
+
* Whether a fatal fault has already armed the explicit process exit. A
|
|
314
|
+
* second fault must not stack another watchdog or cut the first teardown
|
|
315
|
+
* short.
|
|
316
|
+
*/
|
|
317
|
+
private fatalExitScheduled;
|
|
318
|
+
/** Memoized teardown; see shutdown(). */
|
|
319
|
+
private shutdownRun;
|
|
145
320
|
constructor(options: SupervisorOptions);
|
|
146
321
|
start(): Promise<void>;
|
|
147
322
|
private readonly handleClientData;
|
|
323
|
+
/** The captured per-frame mode of an inbound client message, if known. */
|
|
324
|
+
private modeForMessage;
|
|
148
325
|
private readonly handleClientError;
|
|
149
326
|
private readonly handleClientClosed;
|
|
150
327
|
private readonly handleTerminateSignal;
|
|
328
|
+
/**
|
|
329
|
+
* Terminal fault in the supervisor process. Reported through the injected
|
|
330
|
+
* event writer, then routed into the ordinary shutdown so the detached
|
|
331
|
+
* worker group is reaped rather than orphaned by a crash.
|
|
332
|
+
*/
|
|
333
|
+
private readonly handleFatalError;
|
|
151
334
|
private handleClientMessage;
|
|
335
|
+
/**
|
|
336
|
+
* Era-aware notification dispatch. notifications/cancelled stays
|
|
337
|
+
* supervisor-side in ALL eras/states; notifications/initialized is captured
|
|
338
|
+
* and forwarded only within a legacy flow; every other notification is
|
|
339
|
+
* gated by the era rules before reaching the original forwarding path.
|
|
340
|
+
* Dropped variants emit NO response and never affect subsequent traffic.
|
|
341
|
+
*/
|
|
342
|
+
private handleClientNotification;
|
|
343
|
+
/**
|
|
344
|
+
* Era rules for non-initialize requests, applied at admission in stdin
|
|
345
|
+
* order. Returns undefined when the request was terminally rejected here (a
|
|
346
|
+
* supervisor-produced response was written; nothing may be forwarded or
|
|
347
|
+
* queued). On admission it returns the admission-time era signal, which the
|
|
348
|
+
* caller hands to createPendingRequest so snapshot capture uses the same
|
|
349
|
+
* result as the gating decision (extractModernRequestContext re-checks the
|
|
350
|
+
* same immutable params graph defensively — a pure re-evaluation, not a
|
|
351
|
+
* second authority); the caller then proceeds through the original era-less
|
|
352
|
+
* admission path unchanged.
|
|
353
|
+
*/
|
|
354
|
+
private admitEraRequest;
|
|
355
|
+
/**
|
|
356
|
+
* Deep validation of a shallow-valid modern claim's protocolVersion VALUE,
|
|
357
|
+
* applied to EVERY modern request at admission. Returns whether the request
|
|
358
|
+
* was terminally answered here.
|
|
359
|
+
*
|
|
360
|
+
* The version check used to be delegated entirely to the worker, and the SDK
|
|
361
|
+
* only performs it while the connection is still OPENING: once an instance
|
|
362
|
+
* is pinned, `processMessage` delivers straight to it without re-reading the
|
|
363
|
+
* envelope. So the contract ("any unsupported version string answers -32022
|
|
364
|
+
* with data.supported/data.requested") held for exactly one request per
|
|
365
|
+
* process — and whether it held at all depended on which method the client
|
|
366
|
+
* happened to send first, since the era-neutral `server/discover` does not
|
|
367
|
+
* pin. Every later request with `"1999-12-31"` was SERVED, tool handlers
|
|
368
|
+
* included.
|
|
369
|
+
*
|
|
370
|
+
* Ordering is deliberate and matches the SDK's own listen path: the envelope
|
|
371
|
+
* shape is checked first (era gating above), the era lock is committed
|
|
372
|
+
* BEFORE this check — an unsupported version still locks modern, exactly as
|
|
373
|
+
* documented — and only then is the value judged, ahead of any method-level
|
|
374
|
+
* rejection. The reply is built from the SDK's own
|
|
375
|
+
* UnsupportedProtocolVersionError, so it stays byte-identical to the answer
|
|
376
|
+
* the worker gives on the still-opening path.
|
|
377
|
+
*/
|
|
378
|
+
private rejectUnsupportedProtocolVersion;
|
|
379
|
+
/**
|
|
380
|
+
* One-way modern lock. Purges the cached legacy lifecycle state so no
|
|
381
|
+
* initialize/notifications/initialized can ever reach a worker in a
|
|
382
|
+
* modern-locked process — across ALL later worker generations.
|
|
383
|
+
*/
|
|
384
|
+
private lockModernEra;
|
|
385
|
+
/**
|
|
386
|
+
* `eraSignal` is the ADMISSION-time classification handed back by
|
|
387
|
+
* admitEraRequest — the initialize/replay/flush call sites omit it (an
|
|
388
|
+
* initialize snapshot is always era "legacy" with no modern context, even
|
|
389
|
+
* when the initialize carries a _meta envelope). Context is captured only
|
|
390
|
+
* for shallow-valid modern signals; this.era already reflects any lock
|
|
391
|
+
* admitEraRequest applied, so it IS the era at admission on every path.
|
|
392
|
+
*/
|
|
152
393
|
private createPendingRequest;
|
|
153
394
|
private canDispatchImmediately;
|
|
154
395
|
private forwardRequest;
|
|
155
396
|
private writeToWorker;
|
|
156
397
|
private handleCancellation;
|
|
398
|
+
/**
|
|
399
|
+
* Terminal release of a FORWARDED request the client cancelled.
|
|
400
|
+
*
|
|
401
|
+
* MCP cancellation semantics forbid a response for a cancelled id, so the
|
|
402
|
+
* supervisor stops waiting on the worker the moment the cancellation is
|
|
403
|
+
* admitted — and a worker is under no obligation to ever answer a cancelled
|
|
404
|
+
* request. Keeping the entry in `pendingRequests` as a suppression marker
|
|
405
|
+
* (the pre-repair behavior) therefore stranded EVERY dispatch barrier the
|
|
406
|
+
* map gates — canDispatchImmediately's empty-map requirement, drainQueue's
|
|
407
|
+
* validate release — for the life of the process whenever the worker never
|
|
408
|
+
* answered, and let a client grow the map without bound by pairing fresh
|
|
409
|
+
* ids with cancellations.
|
|
410
|
+
*
|
|
411
|
+
* Suppression is instead recorded as an ordinary response-finality
|
|
412
|
+
* tombstone, which already carries exactly the needed semantics: a late
|
|
413
|
+
* worker answer for the id is discarded with a logged event, and
|
|
414
|
+
* re-forwarding the id (a legal retry) clears it. The result is one
|
|
415
|
+
* mechanism for "this request instance is over" rather than two.
|
|
416
|
+
*
|
|
417
|
+
* Carve-out: an in-flight `initialize` is NOT released. Its pending entry is
|
|
418
|
+
* owned by the legacy handshake lifecycle (replay correlation,
|
|
419
|
+
* isInitializationResponse, the preserved-key rule in
|
|
420
|
+
* failPendingRequestsOnWorkerExit), which has its own recovery paths
|
|
421
|
+
* (startup watchdog, worker exit, clearInitialInitializationState) and never
|
|
422
|
+
* consulted the cancellation marker anyway — so handshake behavior is
|
|
423
|
+
* unchanged, byte for byte.
|
|
424
|
+
*
|
|
425
|
+
* Returns whether an entry was actually released.
|
|
426
|
+
*/
|
|
427
|
+
private releaseCancelledRequest;
|
|
428
|
+
/**
|
|
429
|
+
* Era gating for a cancellation notification. Extracted from
|
|
430
|
+
* handleCancellation so supervisor-side bookkeeping (releasing the cancelled
|
|
431
|
+
* request) stays independent of whether the frame may reach the worker — a
|
|
432
|
+
* DROPPED cancellation still cancels, exactly as documented.
|
|
433
|
+
*/
|
|
434
|
+
private shouldForwardCancellation;
|
|
157
435
|
private handleValidateProjectDeadline;
|
|
158
436
|
private drainQueue;
|
|
159
437
|
private spawnWorker;
|
|
@@ -162,15 +440,81 @@ export declare class StdioSupervisor {
|
|
|
162
440
|
private handleWorkerStderr;
|
|
163
441
|
private handleWorkerProcessError;
|
|
164
442
|
private handleWorkerExit;
|
|
443
|
+
/**
|
|
444
|
+
* Decide whether the generation that just ended counts as a start that
|
|
445
|
+
* succeeded.
|
|
446
|
+
*
|
|
447
|
+
* A worker stands down on stdin EOF, and it replays an EOF that arrived
|
|
448
|
+
* while it was still starting. On a host that closes a spawned child's stdin
|
|
449
|
+
* immediately, every generation therefore signals ready, is adopted — which
|
|
450
|
+
* clears the restart backoff — and exits 0 in the same breath. Left at the
|
|
451
|
+
* 100 ms floor that is an unbounded hot respawn loop, so a clean stand-down
|
|
452
|
+
* inside the healthy window re-escalates the backoff the adoption cleared.
|
|
453
|
+
*
|
|
454
|
+
* Only a CLEAN exit qualifies: a non-zero code or a signal is a crash, which
|
|
455
|
+
* may be transient and keeps its prompt replacement.
|
|
456
|
+
*/
|
|
457
|
+
private accountForReadyGenerationExit;
|
|
165
458
|
private handleWorkerMessage;
|
|
166
459
|
private applyStageUpdate;
|
|
167
460
|
private handleWorkerReady;
|
|
168
461
|
private isInitializationResponse;
|
|
169
462
|
private flushQueue;
|
|
170
463
|
private failPendingRequestsOnWorkerExit;
|
|
464
|
+
/**
|
|
465
|
+
* The single terminal-synthesis writer: EVERY supervisor-synthesized
|
|
466
|
+
* response (queue-limit, validate-project timeout, worker-restart in all
|
|
467
|
+
* variants incl. the structured-restart toggle, startup-failure
|
|
468
|
+
* terminalization, initialize-failure -32603) routes through here.
|
|
469
|
+
* Responsibilities, in order:
|
|
470
|
+
* 1. settle the pending entry,
|
|
471
|
+
* 2. record the finality tombstone (id + originating worker generation +
|
|
472
|
+
* framing mode) so a late worker response for the id is discarded —
|
|
473
|
+
* ONLY when the id was actually FORWARDED to a worker (i.e. the entry
|
|
474
|
+
* in pendingRequests at the id IS the snapshot instance being
|
|
475
|
+
* answered; an id-colliding DIFFERENT live entry is left untouched).
|
|
476
|
+
* Never-forwarded
|
|
477
|
+
* rejections (queue-limit at admission and at the forward fallback,
|
|
478
|
+
* queue-phase validate timeout, cap-blocked replies, startup-failure
|
|
479
|
+
* terminalization of queued work, the retained-initialize error) record
|
|
480
|
+
* NO tombstone: no worker ever saw those ids, so no worker can answer
|
|
481
|
+
* them, and tombstoning them would let a client grow the map without
|
|
482
|
+
* bound inside a healthy generation,
|
|
483
|
+
* 3. apply modern-era decoration — `snapshot.era` is the ONLY
|
|
484
|
+
* captured-context field read; raw error envelopes and non-modern eras
|
|
485
|
+
* pass through byte-identical — and
|
|
486
|
+
* 4. write in the ORIGINATING request's framing.
|
|
487
|
+
* Admission-time era rejections (era_conflict/missing_meta/-32601) do NOT
|
|
488
|
+
* route through here: they reject before any forwarding could happen, so
|
|
489
|
+
* no worker can ever answer those ids. The initialize-error synthesis also
|
|
490
|
+
* records no tombstone: isInitializationResponse settles its pending entry
|
|
491
|
+
* before synthesizing, the answering generation is terminated, and the
|
|
492
|
+
* replay cache is cleared — no late-response channel remains.
|
|
493
|
+
*/
|
|
494
|
+
private writeSyntheticReply;
|
|
495
|
+
/**
|
|
496
|
+
* Records a response-finality tombstone for a request instance the
|
|
497
|
+
* supervisor has terminally settled (synthesized reply or client
|
|
498
|
+
* cancellation). Insertion-order eviction at MAX_SYNTHETIC_TOMBSTONES keeps
|
|
499
|
+
* the map bounded even inside one healthy worker generation, where the
|
|
500
|
+
* per-generation purge cannot fire.
|
|
501
|
+
*/
|
|
502
|
+
private recordFinalityTombstone;
|
|
503
|
+
/**
|
|
504
|
+
* Retention bound for finality tombstones: generation `generation` is gone
|
|
505
|
+
* with streams closed, so every tombstone recorded at or before it is
|
|
506
|
+
* unreachable (see syntheticTombstones doc) and may be dropped.
|
|
507
|
+
*/
|
|
508
|
+
private purgeTombstonesThroughGeneration;
|
|
509
|
+
/**
|
|
510
|
+
* Writes one client-bound message. `mode` is the ORIGINATING REQUEST's
|
|
511
|
+
* captured framing; callers omit it only for writes that correlate to no
|
|
512
|
+
* request id, which fall back to the last-detected inbound mode.
|
|
513
|
+
*/
|
|
171
514
|
private writeToClient;
|
|
172
515
|
private clearInitialInitializationState;
|
|
173
516
|
private liveCapOccupancy;
|
|
517
|
+
get unresolvedTreeTokenCount(): number;
|
|
174
518
|
private clearStartupWatchdog;
|
|
175
519
|
private adoptActiveChild;
|
|
176
520
|
private invalidateCurrentChild;
|
|
@@ -178,13 +522,24 @@ export declare class StdioSupervisor {
|
|
|
178
522
|
private recoverTimedOutWorker;
|
|
179
523
|
private beginTreeTermination;
|
|
180
524
|
private finishTreeTermination;
|
|
525
|
+
private scheduleCleanupTokenRetry;
|
|
526
|
+
private runCleanupTokenRetries;
|
|
527
|
+
private stopCleanupTokenRetryIfIdle;
|
|
181
528
|
private retryUnresolvedTreeToken;
|
|
529
|
+
private performUnresolvedTreeTokenRetry;
|
|
182
530
|
private handleStartupFailure;
|
|
183
531
|
private failQueuedRequestsOnStartupFailure;
|
|
184
532
|
private scheduleRestart;
|
|
185
533
|
private armRestartReservation;
|
|
186
534
|
private resumePausedRestart;
|
|
535
|
+
/**
|
|
536
|
+
* Idempotent teardown. Every caller receives the SAME promise, so a caller
|
|
537
|
+
* that needs to know when cleanup is really finished — the fatal handler,
|
|
538
|
+
* which then ends the process — cannot be handed an already-resolved promise
|
|
539
|
+
* while another teardown is still collecting the worker's process group.
|
|
540
|
+
*/
|
|
187
541
|
private shutdown;
|
|
542
|
+
private runShutdown;
|
|
188
543
|
}
|
|
189
544
|
export declare const STDIO_WORKER_MODE_ENV = "MCP_STDIO_WORKER_MODE";
|
|
190
545
|
export {};
|