@cybedefend/vibedefend 1.5.0 → 1.7.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/README.md +71 -2
- package/dist/api/gateway-request.js +49 -0
- package/dist/api/gateway-request.js.map +1 -0
- package/dist/api/projects.js +67 -0
- package/dist/api/projects.js.map +1 -1
- package/dist/api/repository-link.js +157 -0
- package/dist/api/repository-link.js.map +1 -0
- package/dist/auth/auth-store.js +107 -25
- package/dist/auth/auth-store.js.map +1 -1
- package/dist/auth/auth.js +21 -0
- package/dist/auth/auth.js.map +1 -1
- package/dist/clients/cursor.js +5 -1
- package/dist/clients/cursor.js.map +1 -1
- package/dist/clients/vscode.js +38 -29
- package/dist/clients/vscode.js.map +1 -1
- package/dist/commands/mcp/allow.js +219 -0
- package/dist/commands/mcp/allow.js.map +1 -0
- package/dist/commands/mcp/connect.js +337 -0
- package/dist/commands/mcp/connect.js.map +1 -0
- package/dist/commands/mcp/index.js +170 -0
- package/dist/commands/mcp/index.js.map +1 -0
- package/dist/commands/mcp/proxy.js +320 -0
- package/dist/commands/mcp/proxy.js.map +1 -0
- package/dist/commands/mcp/scan.js +349 -0
- package/dist/commands/mcp/scan.js.map +1 -0
- package/dist/commands/mcp/sync.js +215 -0
- package/dist/commands/mcp/sync.js.map +1 -0
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/diagnostics.js +78 -12
- package/dist/diagnostics.js.map +1 -1
- package/dist/doctor.js +19 -0
- package/dist/doctor.js.map +1 -1
- package/dist/guards-evaluator/analysis-types.js +27 -0
- package/dist/guards-evaluator/analysis-types.js.map +1 -0
- package/dist/guards-evaluator/command-analysis.js +572 -0
- package/dist/guards-evaluator/command-analysis.js.map +1 -0
- package/dist/guards-evaluator/command-view.js +586 -0
- package/dist/guards-evaluator/command-view.js.map +1 -0
- package/dist/guards-evaluator/env.js +11 -0
- package/dist/guards-evaluator/env.js.map +1 -0
- package/dist/guards-evaluator/evaluate.js +91 -41
- package/dist/guards-evaluator/evaluate.js.map +1 -1
- package/dist/guards-evaluator/index.js +2 -1
- package/dist/guards-evaluator/index.js.map +1 -1
- package/dist/guards-evaluator/inline-code.js +259 -0
- package/dist/guards-evaluator/inline-code.js.map +1 -0
- package/dist/guards-evaluator/normalize.js +716 -0
- package/dist/guards-evaluator/normalize.js.map +1 -0
- package/dist/guards-evaluator/preprocess.js +13 -5
- package/dist/guards-evaluator/preprocess.js.map +1 -1
- package/dist/guards-evaluator/redact.js +19 -0
- package/dist/guards-evaluator/redact.js.map +1 -1
- package/dist/guards-evaluator/regex.js +25 -3
- package/dist/guards-evaluator/regex.js.map +1 -1
- package/dist/guards-evaluator/safe-commands.js +155 -0
- package/dist/guards-evaluator/safe-commands.js.map +1 -0
- package/dist/guards-evaluator/triage.js +315 -0
- package/dist/guards-evaluator/triage.js.map +1 -0
- package/dist/hook-runner.js +24679 -5079
- package/dist/hooks/install.js +38 -0
- package/dist/hooks/install.js.map +1 -1
- package/dist/hooks/runtime/config.js +38 -0
- package/dist/hooks/runtime/config.js.map +1 -1
- package/dist/hooks/runtime/emit.js +94 -61
- package/dist/hooks/runtime/emit.js.map +1 -1
- package/dist/hooks/runtime/fetch-rules.js +22 -7
- package/dist/hooks/runtime/fetch-rules.js.map +1 -1
- package/dist/hooks/runtime/gateway-http-error.js +34 -0
- package/dist/hooks/runtime/gateway-http-error.js.map +1 -0
- package/dist/hooks/runtime/guard-rules-cache.js +139 -17
- package/dist/hooks/runtime/guard-rules-cache.js.map +1 -1
- package/dist/hooks/runtime/guard-violations-buffer.js +321 -48
- package/dist/hooks/runtime/guard-violations-buffer.js.map +1 -1
- package/dist/hooks/runtime/judge-cache.js +6 -0
- package/dist/hooks/runtime/judge-cache.js.map +1 -1
- package/dist/hooks/runtime/judge-triage.js +193 -0
- package/dist/hooks/runtime/judge-triage.js.map +1 -0
- package/dist/hooks/runtime/judge.js +7 -1
- package/dist/hooks/runtime/judge.js.map +1 -1
- package/dist/hooks/runtime/pre-compact.js +12 -6
- package/dist/hooks/runtime/pre-compact.js.map +1 -1
- package/dist/hooks/runtime/resolve.js +90 -8
- package/dist/hooks/runtime/resolve.js.map +1 -1
- package/dist/hooks/runtime/retry-policy.js +57 -0
- package/dist/hooks/runtime/retry-policy.js.map +1 -0
- package/dist/hooks/runtime/review-sessions.js +74 -0
- package/dist/hooks/runtime/review-sessions.js.map +1 -0
- package/dist/hooks/runtime/script-resolve.js +695 -0
- package/dist/hooks/runtime/script-resolve.js.map +1 -0
- package/dist/hooks/runtime/session-activation.js +5 -1
- package/dist/hooks/runtime/session-activation.js.map +1 -1
- package/dist/hooks/runtime/session-review.js +163 -45
- package/dist/hooks/runtime/session-review.js.map +1 -1
- package/dist/hooks/runtime/session-start.js +2 -1
- package/dist/hooks/runtime/session-start.js.map +1 -1
- package/dist/hooks/runtime/session-writes.js +232 -0
- package/dist/hooks/runtime/session-writes.js.map +1 -0
- package/dist/hooks/runtime/sniff.js +26 -7
- package/dist/hooks/runtime/sniff.js.map +1 -1
- package/dist/hooks/runtime/target-resolve.js +336 -0
- package/dist/hooks/runtime/target-resolve.js.map +1 -0
- package/dist/hooks/runtime/unmapped-tools.js +93 -0
- package/dist/hooks/runtime/unmapped-tools.js.map +1 -0
- package/dist/hooks/runtime/usage-block.js +4 -0
- package/dist/hooks/runtime/usage-block.js.map +1 -1
- package/dist/hooks/runtime/user-prompt-submit.js +2 -1
- package/dist/hooks/runtime/user-prompt-submit.js.map +1 -1
- package/dist/hooks/runtime/wire-text.js +41 -0
- package/dist/hooks/runtime/wire-text.js.map +1 -0
- package/dist/hooks/runtime/work-dir.js +84 -0
- package/dist/hooks/runtime/work-dir.js.map +1 -0
- package/dist/index.js +45 -12
- package/dist/index.js.map +1 -1
- package/dist/install.js +174 -11
- package/dist/install.js.map +1 -1
- package/dist/link.js +74 -48
- package/dist/link.js.map +1 -1
- package/dist/login.js +77 -11
- package/dist/login.js.map +1 -1
- package/dist/mcp/auth/agent-sign-ins.js +174 -0
- package/dist/mcp/auth/agent-sign-ins.js.map +1 -0
- package/dist/mcp/auth/callback.js +200 -0
- package/dist/mcp/auth/callback.js.map +1 -0
- package/dist/mcp/auth/connect.js +392 -0
- package/dist/mcp/auth/connect.js.map +1 -0
- package/dist/mcp/auth/discovery.js +399 -0
- package/dist/mcp/auth/discovery.js.map +1 -0
- package/dist/mcp/auth/oauth.js +326 -0
- package/dist/mcp/auth/oauth.js.map +1 -0
- package/dist/mcp/auth/probe.js +128 -0
- package/dist/mcp/auth/probe.js.map +1 -0
- package/dist/mcp/auth/secrets.js +446 -0
- package/dist/mcp/auth/secrets.js.map +1 -0
- package/dist/mcp/auth/store.js +260 -0
- package/dist/mcp/auth/store.js.map +1 -0
- package/dist/mcp/auth/tokenSource.js +55 -0
- package/dist/mcp/auth/tokenSource.js.map +1 -0
- package/dist/mcp/config/atomicWrite.js +98 -0
- package/dist/mcp/config/atomicWrite.js.map +1 -0
- package/dist/mcp/config/clients.js +171 -0
- package/dist/mcp/config/clients.js.map +1 -0
- package/dist/mcp/config/cybedefend-servers.js +48 -0
- package/dist/mcp/config/cybedefend-servers.js.map +1 -0
- package/dist/mcp/config/discover.js +114 -0
- package/dist/mcp/config/discover.js.map +1 -0
- package/dist/mcp/config/hook.js +123 -0
- package/dist/mcp/config/hook.js.map +1 -0
- package/dist/mcp/config/index.js +11 -0
- package/dist/mcp/config/index.js.map +1 -0
- package/dist/mcp/config/install.js +132 -0
- package/dist/mcp/config/install.js.map +1 -0
- package/dist/mcp/config/installed.js +37 -0
- package/dist/mcp/config/installed.js.map +1 -0
- package/dist/mcp/config/jsonEdit.js +119 -0
- package/dist/mcp/config/jsonEdit.js.map +1 -0
- package/dist/mcp/config/lock.js +102 -0
- package/dist/mcp/config/lock.js.map +1 -0
- package/dist/mcp/config/proxyBinary.js +211 -0
- package/dist/mcp/config/proxyBinary.js.map +1 -0
- package/dist/mcp/config/rewrite.js +388 -0
- package/dist/mcp/config/rewrite.js.map +1 -0
- package/dist/mcp/config/types.js +34 -0
- package/dist/mcp/config/types.js.map +1 -0
- package/dist/mcp/proxy/audit.js +83 -0
- package/dist/mcp/proxy/audit.js.map +1 -0
- package/dist/mcp/proxy/authInterceptor.js +119 -0
- package/dist/mcp/proxy/authInterceptor.js.map +1 -0
- package/dist/mcp/proxy/expand.js +93 -0
- package/dist/mcp/proxy/expand.js.map +1 -0
- package/dist/mcp/proxy/inject.js +412 -0
- package/dist/mcp/proxy/inject.js.map +1 -0
- package/dist/mcp/proxy/intercept.js +63 -0
- package/dist/mcp/proxy/intercept.js.map +1 -0
- package/dist/mcp/proxy/jsonrpc.js +153 -0
- package/dist/mcp/proxy/jsonrpc.js.map +1 -0
- package/dist/mcp/proxy/log.js +109 -0
- package/dist/mcp/proxy/log.js.map +1 -0
- package/dist/mcp/proxy/paths.js +57 -0
- package/dist/mcp/proxy/paths.js.map +1 -0
- package/dist/mcp/proxy/proxy.js +520 -0
- package/dist/mcp/proxy/proxy.js.map +1 -0
- package/dist/mcp/proxy/serverCheckTimer.js +75 -0
- package/dist/mcp/proxy/serverCheckTimer.js.map +1 -0
- package/dist/mcp/proxy/sessionLifecycle.js +29 -0
- package/dist/mcp/proxy/sessionLifecycle.js.map +1 -0
- package/dist/mcp/proxy/spec.js +203 -0
- package/dist/mcp/proxy/spec.js.map +1 -0
- package/dist/mcp/proxy/sse.js +77 -0
- package/dist/mcp/proxy/sse.js.map +1 -0
- package/dist/mcp/proxy/upstream.js +2 -0
- package/dist/mcp/proxy/upstream.js.map +1 -0
- package/dist/mcp/proxy/upstreamHttp.js +499 -0
- package/dist/mcp/proxy/upstreamHttp.js.map +1 -0
- package/dist/mcp/proxy/upstreamStdio.js +188 -0
- package/dist/mcp/proxy/upstreamStdio.js.map +1 -0
- package/dist/mcp/proxy/upstreams.js +143 -0
- package/dist/mcp/proxy/upstreams.js.map +1 -0
- package/dist/mcp/proxy/verifyInterceptor.js +718 -0
- package/dist/mcp/proxy/verifyInterceptor.js.map +1 -0
- package/dist/mcp/proxy/windowsCommand.js +99 -0
- package/dist/mcp/proxy/windowsCommand.js.map +1 -0
- package/dist/mcp/report/buffer.js +351 -0
- package/dist/mcp/report/buffer.js.map +1 -0
- package/dist/mcp/report/coalesce.js +165 -0
- package/dist/mcp/report/coalesce.js.map +1 -0
- package/dist/mcp/report/constants.js +51 -0
- package/dist/mcp/report/constants.js.map +1 -0
- package/dist/mcp/report/project.js +83 -0
- package/dist/mcp/report/project.js.map +1 -0
- package/dist/mcp/report/reporter.js +443 -0
- package/dist/mcp/report/reporter.js.map +1 -0
- package/dist/mcp/report/types.js +3 -0
- package/dist/mcp/report/types.js.map +1 -0
- package/dist/mcp/report/validate.js +179 -0
- package/dist/mcp/report/validate.js.map +1 -0
- package/dist/mcp/scan/args.js +228 -0
- package/dist/mcp/scan/args.js.map +1 -0
- package/dist/mcp/scan/results.js +253 -0
- package/dist/mcp/scan/results.js.map +1 -0
- package/dist/mcp/scan/types.js +40 -0
- package/dist/mcp/scan/types.js.map +1 -0
- package/dist/mcp/verify/api.js +514 -0
- package/dist/mcp/verify/api.js.map +1 -0
- package/dist/mcp/verify/backend.js +143 -0
- package/dist/mcp/verify/backend.js.map +1 -0
- package/dist/mcp/verify/cache.js +200 -0
- package/dist/mcp/verify/cache.js.map +1 -0
- package/dist/mcp/verify/contract-errors.js +198 -0
- package/dist/mcp/verify/contract-errors.js.map +1 -0
- package/dist/mcp/verify/digest.js +91 -0
- package/dist/mcp/verify/digest.js.map +1 -0
- package/dist/mcp/verify/factory.js +56 -0
- package/dist/mcp/verify/factory.js.map +1 -0
- package/dist/mcp/verify/identity.js +286 -0
- package/dist/mcp/verify/identity.js.map +1 -0
- package/dist/mcp/verify/policy-store.js +63 -0
- package/dist/mcp/verify/policy-store.js.map +1 -0
- package/dist/mcp/verify/policy.js +160 -0
- package/dist/mcp/verify/policy.js.map +1 -0
- package/dist/mcp/verify/pool.js +27 -0
- package/dist/mcp/verify/pool.js.map +1 -0
- package/dist/mcp/verify/token-refresh.js +44 -0
- package/dist/mcp/verify/token-refresh.js.map +1 -0
- package/dist/mcp/verify/token.js +67 -0
- package/dist/mcp/verify/token.js.map +1 -0
- package/dist/mcp/verify/verifier.js +1166 -0
- package/dist/mcp/verify/verifier.js.map +1 -0
- package/dist/org-gate.js +1 -1
- package/dist/org-gate.js.map +1 -1
- package/dist/org.js +146 -0
- package/dist/org.js.map +1 -0
- package/dist/project-create.js +129 -0
- package/dist/project-create.js.map +1 -0
- package/dist/prompts.js +21 -0
- package/dist/prompts.js.map +1 -1
- package/dist/re2.wasm +0 -0
- package/dist/status.js +61 -0
- package/dist/status.js.map +1 -1
- package/dist/uninstall.js +49 -4
- package/dist/uninstall.js.map +1 -1
- package/dist/utils.js +62 -6
- package/dist/utils.js.map +1 -1
- package/package.json +10 -3
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
import { encodeMessage, errorResponse, idKey, isRequest, isResponse, JSON_RPC_INTERNAL_ERROR, LineFramer, methodOf, } from './jsonrpc.js';
|
|
2
|
+
import { FORWARD, passthrough, readClientInfo, } from './intercept.js';
|
|
3
|
+
import { describeUpstream } from './spec.js';
|
|
4
|
+
import { HttpUpstream } from './upstreamHttp.js';
|
|
5
|
+
import { StdioUpstream } from './upstreamStdio.js';
|
|
6
|
+
/**
|
|
7
|
+
* Protocol revisions the proxy knows how to name, newest first. Only used
|
|
8
|
+
* when the proxy has to answer `initialize` on its own; in the normal case
|
|
9
|
+
* the negotiated version is whatever the upstream picked.
|
|
10
|
+
*/
|
|
11
|
+
export const KNOWN_PROTOCOL_VERSIONS = [
|
|
12
|
+
'2025-11-25',
|
|
13
|
+
'2025-06-18',
|
|
14
|
+
'2025-03-26',
|
|
15
|
+
'2024-11-05',
|
|
16
|
+
];
|
|
17
|
+
/**
|
|
18
|
+
* Just under the one-second budget of the acceptance criterion: a timer fires
|
|
19
|
+
* at or after its delay, so a deadline set exactly on the budget answers a
|
|
20
|
+
* few milliseconds past it. Raise it with `VIBEDEFEND_MCP_INIT_DEADLINE_MS`
|
|
21
|
+
* if exact capabilities matter more than a fast handshake — an upstream
|
|
22
|
+
* launched through `npx` cold can need two or three seconds.
|
|
23
|
+
*/
|
|
24
|
+
export const DEFAULT_AGENT_INITIALIZE_DEADLINE_MS = 900;
|
|
25
|
+
export const DEFAULT_UPSTREAM_INITIALIZE_TIMEOUT_MS = 3000;
|
|
26
|
+
/**
|
|
27
|
+
* What the proxy claims when it has to answer before the upstream did.
|
|
28
|
+
*
|
|
29
|
+
* Claiming nothing would be honest and useless: the client would file the
|
|
30
|
+
* server as having no tools and never ask again. Claiming the common set
|
|
31
|
+
* costs an error on a list the upstream does not serve, and is repaired a
|
|
32
|
+
* moment later by the `list_changed` notifications sent from the real answer.
|
|
33
|
+
*/
|
|
34
|
+
const OPTIMISTIC_CAPABILITIES = {
|
|
35
|
+
tools: { listChanged: true },
|
|
36
|
+
prompts: { listChanged: true },
|
|
37
|
+
resources: { listChanged: true, subscribe: true },
|
|
38
|
+
logging: {},
|
|
39
|
+
completions: {},
|
|
40
|
+
};
|
|
41
|
+
/** A question with nobody answering is not a reason to keep the loop alive forever. */
|
|
42
|
+
const DEFAULT_ASK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
43
|
+
export class Proxy {
|
|
44
|
+
options;
|
|
45
|
+
logger;
|
|
46
|
+
interceptor;
|
|
47
|
+
framer = new LineFramer();
|
|
48
|
+
queue = [];
|
|
49
|
+
upstream;
|
|
50
|
+
phase = 'before-initialize';
|
|
51
|
+
initializeId;
|
|
52
|
+
initializeIdKey;
|
|
53
|
+
answeredInitialize = false;
|
|
54
|
+
/** Start of the acceptance budget: when the agent's `initialize` arrived. */
|
|
55
|
+
initializeReceivedAt = 0;
|
|
56
|
+
requestedProtocolVersion;
|
|
57
|
+
agentDeadline;
|
|
58
|
+
upstreamDeadline;
|
|
59
|
+
exit;
|
|
60
|
+
exitCode = 0;
|
|
61
|
+
/** What the agent said it can do, at `initialize`. */
|
|
62
|
+
agentCapabilities = {};
|
|
63
|
+
agentClient;
|
|
64
|
+
/** Requests the PROXY sent to the agent, waiting for their answer. */
|
|
65
|
+
asks = new Map();
|
|
66
|
+
askCounter = 0;
|
|
67
|
+
agentChannel = {
|
|
68
|
+
supports: (capability) => Boolean(this.agentCapabilities[capability]),
|
|
69
|
+
request: (method, params, timeoutMs) => this.askAgent(method, params, timeoutMs),
|
|
70
|
+
};
|
|
71
|
+
constructor(options) {
|
|
72
|
+
this.options = options;
|
|
73
|
+
this.logger = options.logger;
|
|
74
|
+
this.interceptor = options.interceptor ?? passthrough;
|
|
75
|
+
}
|
|
76
|
+
/** Resolves with the process exit code once both sides are done. */
|
|
77
|
+
run() {
|
|
78
|
+
const { stdin } = this.options;
|
|
79
|
+
return new Promise((resolve) => {
|
|
80
|
+
this.exit = (code) => {
|
|
81
|
+
if (this.phase === 'closed')
|
|
82
|
+
return;
|
|
83
|
+
this.phase = 'closed';
|
|
84
|
+
try {
|
|
85
|
+
this.options.onExit?.();
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
this.logger.warn('exit task failed', { error: describeError(error) });
|
|
89
|
+
}
|
|
90
|
+
this.clearTimers();
|
|
91
|
+
this.rejectOpenAsks('the session ended');
|
|
92
|
+
this.releaseStdin();
|
|
93
|
+
void this.upstream?.close().finally(() => resolve(code));
|
|
94
|
+
if (!this.upstream)
|
|
95
|
+
resolve(code);
|
|
96
|
+
};
|
|
97
|
+
stdin.on('data', (chunk) => this.onAgentChunk(chunk));
|
|
98
|
+
stdin.on('end', () => {
|
|
99
|
+
this.logger.info('agent closed the channel');
|
|
100
|
+
this.exit?.(this.exitCode);
|
|
101
|
+
});
|
|
102
|
+
stdin.on('error', (error) => {
|
|
103
|
+
this.logger.error('agent channel failed', { error: error.message });
|
|
104
|
+
this.exit?.(1);
|
|
105
|
+
});
|
|
106
|
+
this.logger.info('proxy started', {
|
|
107
|
+
upstream: describeUpstream(this.options.spec),
|
|
108
|
+
transport: this.options.spec.transport,
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/** Called by the command layer on SIGINT / SIGTERM. */
|
|
113
|
+
shutdown(code = 0) {
|
|
114
|
+
this.logger.info('shutting down', { code });
|
|
115
|
+
this.exit?.(code);
|
|
116
|
+
}
|
|
117
|
+
// ── Agent side ────────────────────────────────────────────────────────────
|
|
118
|
+
onAgentChunk(chunk) {
|
|
119
|
+
const { messages, errors } = this.framer.push(chunk);
|
|
120
|
+
for (const error of errors) {
|
|
121
|
+
this.logger.warn('undecodable line from the agent', { ...error });
|
|
122
|
+
}
|
|
123
|
+
for (const message of messages)
|
|
124
|
+
void this.onAgentMessage(message);
|
|
125
|
+
}
|
|
126
|
+
async onAgentMessage(message) {
|
|
127
|
+
const method = methodOf(message);
|
|
128
|
+
this.logger.debug('agent -> upstream', { method, id: message.id });
|
|
129
|
+
// An answer to a question the proxy asked. It is ours: the upstream never
|
|
130
|
+
// saw the request and must not see the reply.
|
|
131
|
+
if (isResponse(message) && this.settleAsk(message))
|
|
132
|
+
return;
|
|
133
|
+
const decision = this.interceptor.fromAgent
|
|
134
|
+
? await this.interceptor.fromAgent(message, {
|
|
135
|
+
logger: this.logger,
|
|
136
|
+
initialized: this.phase === 'ready',
|
|
137
|
+
agent: this.agentChannel,
|
|
138
|
+
client: this.agentClient,
|
|
139
|
+
})
|
|
140
|
+
: FORWARD;
|
|
141
|
+
if (decision.action === 'drop') {
|
|
142
|
+
this.logger.info('dropped a message from the agent', { method, reason: decision.reason });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (decision.action === 'respond') {
|
|
146
|
+
this.logger.info('answered the agent locally', { method, reason: decision.reason });
|
|
147
|
+
this.toAgent(decision.message);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const outgoing = decision.action === 'replace' ? decision.message : message;
|
|
151
|
+
if (isRequest(outgoing) && methodOf(outgoing) === 'initialize') {
|
|
152
|
+
await this.onAgentInitialize(outgoing);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
this.toUpstream(outgoing);
|
|
156
|
+
}
|
|
157
|
+
async onAgentInitialize(message) {
|
|
158
|
+
if (this.phase !== 'before-initialize') {
|
|
159
|
+
// A second `initialize` is a client bug, not something to fix silently:
|
|
160
|
+
// forward it and let the upstream answer.
|
|
161
|
+
this.logger.warn('a second initialize arrived, forwarding it as-is');
|
|
162
|
+
this.toUpstream(message);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.phase = 'initializing';
|
|
166
|
+
this.initializeReceivedAt = Date.now();
|
|
167
|
+
this.initializeId = message.id;
|
|
168
|
+
this.initializeIdKey = idKey(message.id);
|
|
169
|
+
const params = message.params;
|
|
170
|
+
this.agentClient = readClientInfo(params);
|
|
171
|
+
if (typeof params === 'object' && params !== null) {
|
|
172
|
+
const requested = params.protocolVersion;
|
|
173
|
+
if (typeof requested === 'string')
|
|
174
|
+
this.requestedProtocolVersion = requested;
|
|
175
|
+
const capabilities = params.capabilities;
|
|
176
|
+
if (typeof capabilities === 'object' && capabilities !== null) {
|
|
177
|
+
this.agentCapabilities = capabilities;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const started = Date.now();
|
|
181
|
+
try {
|
|
182
|
+
this.upstream = this.makeUpstream();
|
|
183
|
+
await this.upstream.start();
|
|
184
|
+
this.logger.info('upstream started', { ms: Date.now() - started });
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
const text = error instanceof Error ? error.message : String(error);
|
|
188
|
+
this.logger.error('upstream failed to start', { error: text });
|
|
189
|
+
this.toAgent(errorResponse(message.id, JSON_RPC_INTERNAL_ERROR, text));
|
|
190
|
+
this.answeredInitialize = true;
|
|
191
|
+
this.exitCode = 1;
|
|
192
|
+
this.exit?.(1);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
this.agentDeadline = setTimeout(() => {
|
|
196
|
+
if (this.answeredInitialize)
|
|
197
|
+
return;
|
|
198
|
+
this.logger.warn('upstream is slow to initialize, answering the agent first', {
|
|
199
|
+
deadlineMs: this.agentDeadlineMs,
|
|
200
|
+
});
|
|
201
|
+
this.answerInitializeOptimistically();
|
|
202
|
+
}, this.agentDeadlineMs);
|
|
203
|
+
this.upstreamDeadline = setTimeout(() => {
|
|
204
|
+
if (this.phase === 'ready' || this.phase === 'closed')
|
|
205
|
+
return;
|
|
206
|
+
this.logger.error('upstream never answered initialize, releasing the queued traffic', {
|
|
207
|
+
timeoutMs: this.upstreamDeadlineMs,
|
|
208
|
+
});
|
|
209
|
+
this.becomeReady();
|
|
210
|
+
}, this.upstreamDeadlineMs);
|
|
211
|
+
this.upstream.send(message);
|
|
212
|
+
}
|
|
213
|
+
get agentDeadlineMs() {
|
|
214
|
+
return this.options.agentInitializeDeadlineMs ?? DEFAULT_AGENT_INITIALIZE_DEADLINE_MS;
|
|
215
|
+
}
|
|
216
|
+
get upstreamDeadlineMs() {
|
|
217
|
+
return this.options.upstreamInitializeTimeoutMs ?? DEFAULT_UPSTREAM_INITIALIZE_TIMEOUT_MS;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* The number the acceptance criterion is about: how long the agent waited
|
|
221
|
+
* between sending `initialize` and being answered. The process boot that
|
|
222
|
+
* precedes it is paid for any stdio server, proxy or not, so it is not part
|
|
223
|
+
* of the measurement.
|
|
224
|
+
*/
|
|
225
|
+
noteInitializeAnswered(source) {
|
|
226
|
+
this.logger.info('initialize answered', {
|
|
227
|
+
ms: Date.now() - this.initializeReceivedAt,
|
|
228
|
+
source,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
answerInitializeOptimistically() {
|
|
232
|
+
this.answeredInitialize = true;
|
|
233
|
+
const protocolVersion = this.requestedProtocolVersion &&
|
|
234
|
+
KNOWN_PROTOCOL_VERSIONS.includes(this.requestedProtocolVersion)
|
|
235
|
+
? this.requestedProtocolVersion
|
|
236
|
+
: KNOWN_PROTOCOL_VERSIONS[0];
|
|
237
|
+
this.toAgent({
|
|
238
|
+
jsonrpc: '2.0',
|
|
239
|
+
id: this.initializeId,
|
|
240
|
+
result: {
|
|
241
|
+
protocolVersion,
|
|
242
|
+
capabilities: OPTIMISTIC_CAPABILITIES,
|
|
243
|
+
serverInfo: {
|
|
244
|
+
name: 'vibedefend-proxy',
|
|
245
|
+
version: this.options.proxyVersion ?? '0.0.0',
|
|
246
|
+
},
|
|
247
|
+
instructions: 'The upstream MCP server behind the VibeDefend proxy has not finished starting. ' +
|
|
248
|
+
'Its tools, prompts and resources appear as soon as it does.',
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
this.noteInitializeAnswered('proxy');
|
|
252
|
+
}
|
|
253
|
+
// ── Upstream side ─────────────────────────────────────────────────────────
|
|
254
|
+
makeUpstream() {
|
|
255
|
+
const events = {
|
|
256
|
+
onMessage: (message) => void this.onUpstreamMessage(message),
|
|
257
|
+
onError: (error) => this.logger.error('upstream error', { error: error.message }),
|
|
258
|
+
onClose: (info) => this.onUpstreamClose(info),
|
|
259
|
+
};
|
|
260
|
+
if (this.options.createUpstream) {
|
|
261
|
+
return this.options.createUpstream(this.options.spec, events, this.logger);
|
|
262
|
+
}
|
|
263
|
+
if (this.options.spec.transport === 'http') {
|
|
264
|
+
return new HttpUpstream({
|
|
265
|
+
spec: this.options.spec,
|
|
266
|
+
events,
|
|
267
|
+
logger: this.logger,
|
|
268
|
+
auth: this.options.auth,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
return new StdioUpstream({
|
|
272
|
+
spec: this.options.spec,
|
|
273
|
+
events,
|
|
274
|
+
logger: this.logger,
|
|
275
|
+
stderr: this.options.stderr,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
async onUpstreamMessage(message) {
|
|
279
|
+
const method = methodOf(message);
|
|
280
|
+
this.logger.debug('upstream -> agent', { method, id: message.id });
|
|
281
|
+
const decision = this.interceptor.fromUpstream
|
|
282
|
+
? await this.interceptor.fromUpstream(message, {
|
|
283
|
+
logger: this.logger,
|
|
284
|
+
initialized: this.phase === 'ready',
|
|
285
|
+
agent: this.agentChannel,
|
|
286
|
+
client: this.agentClient,
|
|
287
|
+
})
|
|
288
|
+
: FORWARD;
|
|
289
|
+
if (decision.action === 'drop') {
|
|
290
|
+
this.logger.info('dropped a message from the upstream', { method, reason: decision.reason });
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (decision.action === 'respond') {
|
|
294
|
+
this.logger.info('answered the upstream locally', { method, reason: decision.reason });
|
|
295
|
+
this.toUpstream(decision.message);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const incoming = decision.action === 'replace' ? decision.message : message;
|
|
299
|
+
if (this.phase === 'initializing' &&
|
|
300
|
+
isResponse(incoming) &&
|
|
301
|
+
idKey(incoming.id) === this.initializeIdKey) {
|
|
302
|
+
this.onUpstreamInitializeResult(incoming);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
this.toAgent(incoming);
|
|
306
|
+
}
|
|
307
|
+
onUpstreamInitializeResult(message) {
|
|
308
|
+
this.clearTimers();
|
|
309
|
+
if (!this.answeredInitialize) {
|
|
310
|
+
// The normal path: the upstream's own answer, forwarded untouched, so
|
|
311
|
+
// `serverInfo`, `instructions` and the negotiated version are exact.
|
|
312
|
+
this.answeredInitialize = true;
|
|
313
|
+
this.toAgent(message);
|
|
314
|
+
this.noteInitializeAnswered('upstream');
|
|
315
|
+
this.becomeReady();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
this.logger.warn('the upstream answered initialize after the deadline', {
|
|
319
|
+
hasError: 'error' in message,
|
|
320
|
+
});
|
|
321
|
+
this.becomeReady();
|
|
322
|
+
if ('error' in message)
|
|
323
|
+
return;
|
|
324
|
+
this.reconcileLateCapabilities(message);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Repairs an optimistic answer. The client skipped the lists it thought
|
|
328
|
+
* were empty, so it is told they changed; and anything the proxy claimed
|
|
329
|
+
* that the upstream does not have is logged, because that mismatch is the
|
|
330
|
+
* price of answering first.
|
|
331
|
+
*/
|
|
332
|
+
reconcileLateCapabilities(message) {
|
|
333
|
+
const result = message.result;
|
|
334
|
+
if (typeof result !== 'object' || result === null)
|
|
335
|
+
return;
|
|
336
|
+
const capabilities = result.capabilities;
|
|
337
|
+
const actual = typeof capabilities === 'object' && capabilities !== null
|
|
338
|
+
? capabilities
|
|
339
|
+
: {};
|
|
340
|
+
for (const area of ['tools', 'prompts', 'resources']) {
|
|
341
|
+
if (actual[area]) {
|
|
342
|
+
this.toAgent({ jsonrpc: '2.0', method: `notifications/${area}/list_changed` });
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const missing = Object.keys(OPTIMISTIC_CAPABILITIES).filter((area) => !actual[area]);
|
|
346
|
+
if (missing.length > 0) {
|
|
347
|
+
this.logger.warn('advertised capabilities the upstream does not have', { missing });
|
|
348
|
+
}
|
|
349
|
+
const negotiated = result.protocolVersion;
|
|
350
|
+
if (typeof negotiated === 'string' && negotiated !== this.announcedProtocolVersion()) {
|
|
351
|
+
this.logger.warn('protocol version announced to the agent differs from the negotiated one', {
|
|
352
|
+
announced: this.announcedProtocolVersion(),
|
|
353
|
+
negotiated,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
announcedProtocolVersion() {
|
|
358
|
+
return this.requestedProtocolVersion &&
|
|
359
|
+
KNOWN_PROTOCOL_VERSIONS.includes(this.requestedProtocolVersion)
|
|
360
|
+
? this.requestedProtocolVersion
|
|
361
|
+
: KNOWN_PROTOCOL_VERSIONS[0];
|
|
362
|
+
}
|
|
363
|
+
onUpstreamClose(info) {
|
|
364
|
+
if (this.phase === 'closed')
|
|
365
|
+
return;
|
|
366
|
+
this.logger.info('upstream closed', { ...info });
|
|
367
|
+
// A server that dies mid-session ends the session: the client respawns us
|
|
368
|
+
// when it wants to try again.
|
|
369
|
+
this.exitCode = typeof info.code === 'number' && info.code !== 0 ? info.code : 0;
|
|
370
|
+
this.exit?.(this.exitCode);
|
|
371
|
+
}
|
|
372
|
+
// ── Plumbing ──────────────────────────────────────────────────────────────
|
|
373
|
+
becomeReady() {
|
|
374
|
+
if (this.phase === 'ready' || this.phase === 'closed')
|
|
375
|
+
return;
|
|
376
|
+
this.phase = 'ready';
|
|
377
|
+
this.clearTimers();
|
|
378
|
+
this.runAfterInitialize();
|
|
379
|
+
if (this.queue.length > 0) {
|
|
380
|
+
this.logger.debug('releasing queued agent messages', { count: this.queue.length });
|
|
381
|
+
}
|
|
382
|
+
while (this.queue.length > 0) {
|
|
383
|
+
const message = this.queue.shift();
|
|
384
|
+
if (message)
|
|
385
|
+
this.upstream?.send(message);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Nothing may reach the upstream before its `initialize` has been answered:
|
|
390
|
+
* the spec forbids it, and a server that receives `notifications/initialized`
|
|
391
|
+
* too early drops it.
|
|
392
|
+
*/
|
|
393
|
+
toUpstream(message) {
|
|
394
|
+
if (this.phase === 'initializing') {
|
|
395
|
+
this.queue.push(message);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (!this.upstream) {
|
|
399
|
+
this.logger.warn('a message arrived before initialize, dropping it', {
|
|
400
|
+
method: methodOf(message),
|
|
401
|
+
});
|
|
402
|
+
if (isRequest(message)) {
|
|
403
|
+
this.toAgent(errorResponse(message.id, JSON_RPC_INTERNAL_ERROR, 'the upstream is not connected yet: send initialize first'));
|
|
404
|
+
}
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
this.upstream.send(message);
|
|
408
|
+
}
|
|
409
|
+
// ── Questions the proxy asks the agent ────────────────────────────────────
|
|
410
|
+
/**
|
|
411
|
+
* Sends a request of the proxy's own to the agent, and waits for the reply.
|
|
412
|
+
*
|
|
413
|
+
* The id carries a prefix no upstream uses, so the reply cannot be mistaken
|
|
414
|
+
* for one meant for the server, and an upstream request that happens to use
|
|
415
|
+
* the same number cannot be mistaken for ours.
|
|
416
|
+
*/
|
|
417
|
+
askAgent(method, params, timeoutMs = DEFAULT_ASK_TIMEOUT_MS) {
|
|
418
|
+
if (this.phase === 'closed')
|
|
419
|
+
return Promise.reject(new Error('the session ended'));
|
|
420
|
+
this.askCounter += 1;
|
|
421
|
+
const id = `vibedefend:${this.askCounter}`;
|
|
422
|
+
const key = idKey(id) ?? id;
|
|
423
|
+
return new Promise((resolve, reject) => {
|
|
424
|
+
const timer = setTimeout(() => {
|
|
425
|
+
this.asks.delete(key);
|
|
426
|
+
reject(new Error(`no answer from the agent to ${method} within ${timeoutMs} ms`));
|
|
427
|
+
}, timeoutMs);
|
|
428
|
+
timer.unref?.();
|
|
429
|
+
this.asks.set(key, { resolve, reject, timer });
|
|
430
|
+
const message = { jsonrpc: '2.0', id, method };
|
|
431
|
+
if (params !== undefined)
|
|
432
|
+
message.params = params;
|
|
433
|
+
this.logger.debug('proxy -> agent', { method, id });
|
|
434
|
+
this.toAgent(message);
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
/** `true` when the response answered one of our own questions. */
|
|
438
|
+
settleAsk(message) {
|
|
439
|
+
const key = idKey(message.id);
|
|
440
|
+
const ask = key ? this.asks.get(key) : undefined;
|
|
441
|
+
if (!ask || !key)
|
|
442
|
+
return false;
|
|
443
|
+
this.asks.delete(key);
|
|
444
|
+
clearTimeout(ask.timer);
|
|
445
|
+
ask.resolve(message);
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
rejectOpenAsks(reason) {
|
|
449
|
+
for (const [, ask] of this.asks) {
|
|
450
|
+
clearTimeout(ask.timer);
|
|
451
|
+
ask.reject(new Error(reason));
|
|
452
|
+
}
|
|
453
|
+
this.asks.clear();
|
|
454
|
+
}
|
|
455
|
+
toAgent(message) {
|
|
456
|
+
try {
|
|
457
|
+
this.options.stdout.write(encodeMessage(message));
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
this.logger.error('cannot write to the agent', {
|
|
461
|
+
error: error instanceof Error ? error.message : String(error),
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Fires the post-handshake work, on the next tick and never awaited.
|
|
467
|
+
*
|
|
468
|
+
* The queued agent traffic is released in this same turn; scheduling the
|
|
469
|
+
* work rather than running it keeps a slow filesystem from sitting between
|
|
470
|
+
* the agent's `initialize` and its first real request.
|
|
471
|
+
*/
|
|
472
|
+
runAfterInitialize() {
|
|
473
|
+
const task = this.options.afterInitialize;
|
|
474
|
+
if (!task)
|
|
475
|
+
return;
|
|
476
|
+
setTimeout(() => {
|
|
477
|
+
try {
|
|
478
|
+
void Promise.resolve(task(this.agentClient)).catch((error) => {
|
|
479
|
+
this.logger.warn('post-initialize task failed', { error: describeError(error) });
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
this.logger.warn('post-initialize task failed', { error: describeError(error) });
|
|
484
|
+
}
|
|
485
|
+
}, 0).unref?.();
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Lets the process end.
|
|
489
|
+
*
|
|
490
|
+
* When the upstream dies the proxy has nothing left to do, but a listener
|
|
491
|
+
* on `process.stdin` keeps the event loop alive on its own: without this
|
|
492
|
+
* the proxy would linger until the client closed the channel, which is
|
|
493
|
+
* exactly the hung server the client is trying to detect.
|
|
494
|
+
*/
|
|
495
|
+
releaseStdin() {
|
|
496
|
+
const stdin = this.options.stdin;
|
|
497
|
+
try {
|
|
498
|
+
stdin.pause();
|
|
499
|
+
stdin.unref?.();
|
|
500
|
+
}
|
|
501
|
+
catch {
|
|
502
|
+
/* nothing to release */
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
clearTimers() {
|
|
506
|
+
if (this.agentDeadline)
|
|
507
|
+
clearTimeout(this.agentDeadline);
|
|
508
|
+
if (this.upstreamDeadline)
|
|
509
|
+
clearTimeout(this.upstreamDeadline);
|
|
510
|
+
this.agentDeadline = undefined;
|
|
511
|
+
this.upstreamDeadline = undefined;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
export async function runProxy(options) {
|
|
515
|
+
return new Proxy(options).run();
|
|
516
|
+
}
|
|
517
|
+
function describeError(error) {
|
|
518
|
+
return error instanceof Error ? error.message : String(error);
|
|
519
|
+
}
|
|
520
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../../src/mcp/proxy/proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server check, for the whole life of the proxy.
|
|
3
|
+
*
|
|
4
|
+
* A block or an unblock decided by the organization must reach a session
|
|
5
|
+
* already open, not wait for the agent to list its tools again. So the
|
|
6
|
+
* proxy asks `servers/check` once at start, then every
|
|
7
|
+
* `SERVER_CHECK_INTERVAL_MS`, and tells `onChange` when the organization
|
|
8
|
+
* block appeared or went away.
|
|
9
|
+
*
|
|
10
|
+
* Off the hot path by construction: the timer never delays a message between
|
|
11
|
+
* the agent and the server, never keeps the process alive (`unref()`), runs
|
|
12
|
+
* one check at a time (a check still running skips the next tick), and never
|
|
13
|
+
* throws. A check that fails changes nothing: the verifier keeps a known
|
|
14
|
+
* block and never invents one.
|
|
15
|
+
*/
|
|
16
|
+
import { SERVER_CHECK_INTERVAL_MS } from '../report/constants.js';
|
|
17
|
+
export function startServerCheckTimer(opts) {
|
|
18
|
+
const { verifier, logger } = opts;
|
|
19
|
+
const setIntervalFn = opts.setIntervalFn ?? setInterval;
|
|
20
|
+
const clearIntervalFn = opts.clearIntervalFn ?? clearInterval;
|
|
21
|
+
let running;
|
|
22
|
+
let stopped = false;
|
|
23
|
+
async function check() {
|
|
24
|
+
let state;
|
|
25
|
+
try {
|
|
26
|
+
state = await verifier.checkServer();
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
logger.warn('verify: the periodic server check failed, nothing changed', { error: describe(error) });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (stopped || (state !== 'blocked' && state !== 'unblocked'))
|
|
33
|
+
return;
|
|
34
|
+
logger.info('verify: the organization block of this server changed', { state });
|
|
35
|
+
try {
|
|
36
|
+
const result = opts.onChange?.(state);
|
|
37
|
+
if (result instanceof Promise) {
|
|
38
|
+
result.catch((error) => {
|
|
39
|
+
logger.warn('verify: refreshing the server gate failed', { error: describe(error) });
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
logger.warn('verify: refreshing the server gate failed', { error: describe(error) });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function tick() {
|
|
48
|
+
if (running)
|
|
49
|
+
return running;
|
|
50
|
+
running = check().finally(() => {
|
|
51
|
+
running = undefined;
|
|
52
|
+
});
|
|
53
|
+
return running;
|
|
54
|
+
}
|
|
55
|
+
void tick();
|
|
56
|
+
const handle = setIntervalFn(() => {
|
|
57
|
+
if (running)
|
|
58
|
+
return;
|
|
59
|
+
void tick();
|
|
60
|
+
}, opts.intervalMs ?? SERVER_CHECK_INTERVAL_MS);
|
|
61
|
+
const unref = handle?.unref;
|
|
62
|
+
if (typeof unref === 'function')
|
|
63
|
+
unref.call(handle);
|
|
64
|
+
return {
|
|
65
|
+
stop() {
|
|
66
|
+
stopped = true;
|
|
67
|
+
clearIntervalFn(handle);
|
|
68
|
+
},
|
|
69
|
+
tick,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function describe(error) {
|
|
73
|
+
return error instanceof Error ? error.message : String(error);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=serverCheckTimer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverCheckTimer.js","sourceRoot":"","sources":["../../../src/mcp/proxy/serverCheckTimer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAWlE,MAAM,UAAU,qBAAqB,CAAC,IAOrC;IACC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,WAAW,CAAC;IACxD,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,aAAa,CAAC;IAC9D,IAAI,OAAkC,CAAC;IACvC,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,UAAU,KAAK;QAClB,IAAI,KAAmD,CAAC;QACxD,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;QACvC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,2DAA2D,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACrG,OAAO;QACT,CAAC;QACD,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,WAAW,CAAC;YAAE,OAAO;QACtE,MAAM,CAAC,IAAI,CAAC,uDAAuD,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAChF,IAAI,CAAC;YACH,MAAM,MAAM,GAAY,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC;YAC/C,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;gBAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;oBAC9B,MAAM,CAAC,IAAI,CAAC,2CAA2C,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACvF,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,2CAA2C,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,SAAS,IAAI;QACX,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAC5B,OAAO,GAAG,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;YAC7B,OAAO,GAAG,SAAS,CAAC;QACtB,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,IAAI,EAAE,CAAC;IACZ,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,EAAE;QAChC,IAAI,OAAO;YAAE,OAAO;QACpB,KAAK,IAAI,EAAE,CAAC;IACd,CAAC,EAAE,IAAI,CAAC,UAAU,IAAI,wBAAwB,CAAC,CAAC;IAChD,MAAM,KAAK,GAAI,MAAgD,EAAE,KAAK,CAAC;IACvE,IAAI,OAAO,KAAK,KAAK,UAAU;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEpD,OAAO;QACL,IAAI;YACF,OAAO,GAAG,IAAI,CAAC;YACf,eAAe,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI;KACL,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function createSessionLifecycle(deps) {
|
|
2
|
+
let timer;
|
|
3
|
+
let stopped = false;
|
|
4
|
+
function onChange() {
|
|
5
|
+
try {
|
|
6
|
+
void deps.refreshServerGate().catch(() => undefined);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
// The gate stays as it was; the next check tries again.
|
|
10
|
+
}
|
|
11
|
+
deps.reporter?.noteServerChanged();
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
start(client) {
|
|
15
|
+
if (stopped || timer)
|
|
16
|
+
return;
|
|
17
|
+
deps.reporter?.start(client);
|
|
18
|
+
timer = deps.startTimer(onChange);
|
|
19
|
+
},
|
|
20
|
+
stop() {
|
|
21
|
+
if (stopped)
|
|
22
|
+
return;
|
|
23
|
+
stopped = true;
|
|
24
|
+
timer?.stop();
|
|
25
|
+
deps.reporter?.stop();
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=sessionLifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionLifecycle.js","sourceRoot":"","sources":["../../../src/mcp/proxy/sessionLifecycle.ts"],"names":[],"mappings":"AA6BA,MAAM,UAAU,sBAAsB,CAAC,IAA0B;IAC/D,IAAI,KAAmC,CAAC;IACxC,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,SAAS,QAAQ;QACf,IAAI,CAAC;YACH,KAAK,IAAI,CAAC,iBAAiB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,wDAAwD;QAC1D,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IACrC,CAAC;IAED,OAAO;QACL,KAAK,CAAC,MAAM;YACV,IAAI,OAAO,IAAI,KAAK;gBAAE,OAAO;YAC7B,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAC7B,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC;QACD,IAAI;YACF,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,KAAK,EAAE,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC"}
|