@zhixuan92/multi-model-agent-mcp 2.7.5 → 2.8.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 +74 -0
- package/dist/cli.d.ts +23 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +105 -90
- package/dist/cli.js.map +1 -1
- package/dist/http/auth.d.ts +8 -0
- package/dist/http/auth.d.ts.map +1 -0
- package/dist/http/auth.js +43 -0
- package/dist/http/auth.js.map +1 -0
- package/dist/http/cwd-validator.d.ts +11 -0
- package/dist/http/cwd-validator.d.ts.map +1 -0
- package/dist/http/cwd-validator.js +31 -0
- package/dist/http/cwd-validator.js.map +1 -0
- package/dist/http/lifecycle-handlers.d.ts +12 -0
- package/dist/http/lifecycle-handlers.d.ts.map +1 -0
- package/dist/http/lifecycle-handlers.js +87 -0
- package/dist/http/lifecycle-handlers.js.map +1 -0
- package/dist/http/loopback.d.ts +10 -0
- package/dist/http/loopback.d.ts.map +1 -0
- package/dist/http/loopback.js +34 -0
- package/dist/http/loopback.js.map +1 -0
- package/dist/http/project-registry.d.ts +48 -0
- package/dist/http/project-registry.d.ts.map +1 -0
- package/dist/http/project-registry.js +119 -0
- package/dist/http/project-registry.js.map +1 -0
- package/dist/http/session-router.d.ts +33 -0
- package/dist/http/session-router.d.ts.map +1 -0
- package/dist/http/session-router.js +62 -0
- package/dist/http/session-router.js.map +1 -0
- package/dist/http/status-endpoint.d.ts +20 -0
- package/dist/http/status-endpoint.d.ts.map +1 -0
- package/dist/http/status-endpoint.js +85 -0
- package/dist/http/status-endpoint.js.map +1 -0
- package/dist/http/transport.d.ts +14 -0
- package/dist/http/transport.d.ts.map +1 -0
- package/dist/http/transport.js +209 -0
- package/dist/http/transport.js.map +1 -0
- package/dist/status-cli.d.ts +2 -0
- package/dist/status-cli.d.ts.map +1 -0
- package/dist/status-cli.js +68 -0
- package/dist/status-cli.js.map +1 -0
- package/package.json +4 -3
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
export function validateCwd(cwd) {
|
|
4
|
+
if (!cwd)
|
|
5
|
+
return { ok: false, error: 'missing_cwd', message: "required query param 'cwd' not provided" };
|
|
6
|
+
if (!path.isAbsolute(cwd))
|
|
7
|
+
return { ok: false, error: 'invalid_cwd', message: `cwd must be absolute: ${cwd}` };
|
|
8
|
+
let canonical;
|
|
9
|
+
try {
|
|
10
|
+
canonical = fs.realpathSync(cwd);
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
const code = err.code;
|
|
14
|
+
if (code === 'ENOENT')
|
|
15
|
+
return { ok: false, error: 'cwd_not_dir', message: `cwd does not exist: ${cwd}` };
|
|
16
|
+
if (code === 'EACCES' || code === 'EPERM')
|
|
17
|
+
return { ok: false, error: 'cwd_not_dir', message: `cwd is not accessible (permission denied): ${cwd}` };
|
|
18
|
+
return { ok: false, error: 'cwd_not_dir', message: `cwd cannot be resolved (${code ?? 'unknown error'}): ${cwd}` };
|
|
19
|
+
}
|
|
20
|
+
let stat;
|
|
21
|
+
try {
|
|
22
|
+
stat = fs.statSync(canonical);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return { ok: false, error: 'cwd_not_dir', message: `cwd realpath is not accessible: ${cwd} → ${canonical}` };
|
|
26
|
+
}
|
|
27
|
+
if (!stat.isDirectory())
|
|
28
|
+
return { ok: false, error: 'cwd_not_dir', message: `cwd is not a directory: ${cwd}` };
|
|
29
|
+
return { ok: true, canonicalCwd: canonical };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=cwd-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cwd-validator.js","sourceRoot":"","sources":["../../src/http/cwd-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAQlC,MAAM,UAAU,WAAW,CAAC,GAAuB;IACjD,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,yCAAyC,EAAE,CAAC;IACzG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,yBAAyB,GAAG,EAAE,EAAE,CAAC;IAC/G,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,IAAI,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,uBAAuB,GAAG,EAAE,EAAE,CAAC;QACzG,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,8CAA8C,GAAG,EAAE,EAAE,CAAC;QACpJ,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,2BAA2B,IAAI,IAAI,eAAe,MAAM,GAAG,EAAE,EAAE,CAAC;IACrH,CAAC;IACD,IAAI,IAAc,CAAC;IACnB,IAAI,CAAC;QACH,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,mCAAmC,GAAG,MAAM,SAAS,EAAE,EAAE,CAAC;IAC/G,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,2BAA2B,GAAG,EAAE,EAAE,CAAC;IAC/G,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Server as HttpServer } from 'node:http';
|
|
2
|
+
import type { DiagnosticLogger } from '@zhixuan92/multi-model-agent-core';
|
|
3
|
+
import type { ProjectRegistry } from './project-registry.js';
|
|
4
|
+
import type { SessionRouter } from './session-router.js';
|
|
5
|
+
export interface HttpLifecycleOptions {
|
|
6
|
+
shutdownDrainMs: number;
|
|
7
|
+
noExit?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function installHttpLifecycleHandlers(logger: DiagnosticLogger, httpServer: HttpServer, registry: ProjectRegistry, router: SessionRouter, options: HttpLifecycleOptions): void;
|
|
10
|
+
/** Test-only. */
|
|
11
|
+
export declare function __resetHttpLifecycleHandlersForTests(): void;
|
|
12
|
+
//# sourceMappingURL=lifecycle-handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-handlers.d.ts","sourceRoot":"","sources":["../../src/http/lifecycle-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAKD,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,oBAAoB,GAC5B,IAAI,CA4EN;AAED,iBAAiB;AACjB,wBAAgB,oCAAoC,IAAI,IAAI,CAI3D"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
let installed = false;
|
|
2
|
+
let cleanup = null;
|
|
3
|
+
export function installHttpLifecycleHandlers(logger, httpServer, registry, router, options) {
|
|
4
|
+
if (installed)
|
|
5
|
+
return;
|
|
6
|
+
installed = true;
|
|
7
|
+
let shuttingDown = false;
|
|
8
|
+
const hasInFlight = () => {
|
|
9
|
+
for (const [, pc] of registry.entries()) {
|
|
10
|
+
if (pc.activeRequests > 0)
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
return false;
|
|
14
|
+
};
|
|
15
|
+
const drainAndExit = async (cause) => {
|
|
16
|
+
if (shuttingDown)
|
|
17
|
+
return;
|
|
18
|
+
shuttingDown = true;
|
|
19
|
+
registry.stopEvictionTimer();
|
|
20
|
+
await new Promise((resolve) => httpServer.close(() => resolve()));
|
|
21
|
+
const deadline = Date.now() + options.shutdownDrainMs;
|
|
22
|
+
while (Date.now() < deadline && hasInFlight()) {
|
|
23
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
24
|
+
}
|
|
25
|
+
const timedOut = hasInFlight();
|
|
26
|
+
await router.closeAll();
|
|
27
|
+
registry.clear();
|
|
28
|
+
logger.shutdown(timedOut ? 'SIGTERM_drain_timeout' : cause);
|
|
29
|
+
if (!options.noExit)
|
|
30
|
+
process.exit(0);
|
|
31
|
+
};
|
|
32
|
+
const onSigterm = () => { void drainAndExit('SIGTERM'); };
|
|
33
|
+
const onSigint = () => { void drainAndExit('SIGINT'); };
|
|
34
|
+
const onSighup = () => { };
|
|
35
|
+
const onSigpipe = () => { };
|
|
36
|
+
const onStdinEnd = () => { };
|
|
37
|
+
const onStdoutError = () => { };
|
|
38
|
+
const onUncaught = (err) => {
|
|
39
|
+
logger.error('uncaughtException', err);
|
|
40
|
+
process.stderr.write(`[multi-model-agent] uncaughtException: ${err.stack ?? String(err)}\n`);
|
|
41
|
+
registry.stopEvictionTimer();
|
|
42
|
+
void router.closeAll().finally(() => {
|
|
43
|
+
registry.clear();
|
|
44
|
+
logger.shutdown('uncaughtException');
|
|
45
|
+
if (!options.noExit)
|
|
46
|
+
process.exit(1);
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
const onUnhandled = (reason) => {
|
|
50
|
+
logger.error('unhandledRejection', reason);
|
|
51
|
+
const stack = reason instanceof Error ? (reason.stack ?? reason.message) : String(reason);
|
|
52
|
+
process.stderr.write(`[multi-model-agent] unhandledRejection: ${stack}\n`);
|
|
53
|
+
registry.stopEvictionTimer();
|
|
54
|
+
void router.closeAll().finally(() => {
|
|
55
|
+
registry.clear();
|
|
56
|
+
logger.shutdown('unhandledRejection');
|
|
57
|
+
if (!options.noExit)
|
|
58
|
+
process.exit(1);
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
process.on('SIGTERM', onSigterm);
|
|
62
|
+
process.on('SIGINT', onSigint);
|
|
63
|
+
process.on('SIGHUP', onSighup);
|
|
64
|
+
process.on('SIGPIPE', onSigpipe);
|
|
65
|
+
process.stdin.on('end', onStdinEnd);
|
|
66
|
+
process.stdout.on('error', onStdoutError);
|
|
67
|
+
process.on('uncaughtException', onUncaught);
|
|
68
|
+
process.on('unhandledRejection', onUnhandled);
|
|
69
|
+
cleanup = () => {
|
|
70
|
+
process.off('SIGTERM', onSigterm);
|
|
71
|
+
process.off('SIGINT', onSigint);
|
|
72
|
+
process.off('SIGHUP', onSighup);
|
|
73
|
+
process.off('SIGPIPE', onSigpipe);
|
|
74
|
+
process.stdin.off('end', onStdinEnd);
|
|
75
|
+
process.stdout.off('error', onStdoutError);
|
|
76
|
+
process.off('uncaughtException', onUncaught);
|
|
77
|
+
process.off('unhandledRejection', onUnhandled);
|
|
78
|
+
installed = false;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** Test-only. */
|
|
82
|
+
export function __resetHttpLifecycleHandlersForTests() {
|
|
83
|
+
cleanup?.();
|
|
84
|
+
cleanup = null;
|
|
85
|
+
installed = false;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=lifecycle-handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-handlers.js","sourceRoot":"","sources":["../../src/http/lifecycle-handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns true iff the given address string refers to the loopback interface.
|
|
3
|
+
* Accepts all forms Node's socket layer surfaces:
|
|
4
|
+
* - IPv4 loopback (any 127.0.0.0/8 address): 127.0.0.1, 127.0.1.1, etc.
|
|
5
|
+
* - IPv6 loopback: ::1
|
|
6
|
+
* - IPv4-mapped IPv6 loopback: ::ffff:127.0.0.1 (and other 127/8 mapped forms)
|
|
7
|
+
* - Hostname: localhost
|
|
8
|
+
*/
|
|
9
|
+
export declare function isLoopbackAddress(addr: string | undefined): boolean;
|
|
10
|
+
//# sourceMappingURL=loopback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopback.d.ts","sourceRoot":"","sources":["../../src/http/loopback.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAoBnE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as net from 'node:net';
|
|
2
|
+
/**
|
|
3
|
+
* Returns true iff the given address string refers to the loopback interface.
|
|
4
|
+
* Accepts all forms Node's socket layer surfaces:
|
|
5
|
+
* - IPv4 loopback (any 127.0.0.0/8 address): 127.0.0.1, 127.0.1.1, etc.
|
|
6
|
+
* - IPv6 loopback: ::1
|
|
7
|
+
* - IPv4-mapped IPv6 loopback: ::ffff:127.0.0.1 (and other 127/8 mapped forms)
|
|
8
|
+
* - Hostname: localhost
|
|
9
|
+
*/
|
|
10
|
+
export function isLoopbackAddress(addr) {
|
|
11
|
+
if (!addr)
|
|
12
|
+
return false;
|
|
13
|
+
if (addr === 'localhost')
|
|
14
|
+
return true;
|
|
15
|
+
// Strip any scope ID (fe80::1%lo0 style) — rare for loopback but cheap to handle.
|
|
16
|
+
const clean = addr.split('%')[0];
|
|
17
|
+
const kind = net.isIP(clean);
|
|
18
|
+
if (kind === 4) {
|
|
19
|
+
return clean.startsWith('127.');
|
|
20
|
+
}
|
|
21
|
+
if (kind === 6) {
|
|
22
|
+
if (clean === '::1')
|
|
23
|
+
return true;
|
|
24
|
+
// IPv4-mapped IPv6: ::ffff:A.B.C.D
|
|
25
|
+
const mappedPrefix = '::ffff:';
|
|
26
|
+
if (clean.toLowerCase().startsWith(mappedPrefix)) {
|
|
27
|
+
const v4 = clean.slice(mappedPrefix.length);
|
|
28
|
+
return net.isIPv4(v4) && v4.startsWith('127.');
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=loopback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopback.js","sourceRoot":"","sources":["../../src/http/loopback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAwB;IACxD,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IACtC,kFAAkF;IAClF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QACf,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IACD,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QACf,IAAI,KAAK,KAAK,KAAK;YAAE,OAAO,IAAI,CAAC;QACjC,mCAAmC;QACnC,MAAM,YAAY,GAAG,SAAS,CAAC;QAC/B,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACjD,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAC5C,OAAO,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type ProjectContext } from '@zhixuan92/multi-model-agent-core';
|
|
2
|
+
export type ReserveError = 'project_cap' | 'invalid_cwd' | 'missing_cwd' | 'cwd_not_dir';
|
|
3
|
+
export type ReserveResult = {
|
|
4
|
+
ok: true;
|
|
5
|
+
projectContext: ProjectContext;
|
|
6
|
+
created: boolean;
|
|
7
|
+
} | {
|
|
8
|
+
ok: false;
|
|
9
|
+
error: ReserveError;
|
|
10
|
+
message: string;
|
|
11
|
+
};
|
|
12
|
+
export interface ProjectRegistryOptions {
|
|
13
|
+
cap: number;
|
|
14
|
+
idleEvictionMs: number;
|
|
15
|
+
evictionIntervalMs: number;
|
|
16
|
+
onProjectCreated?: (cwd: string) => void;
|
|
17
|
+
onProjectEvicted?: (cwd: string, idleMs: number) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare class ProjectRegistry {
|
|
20
|
+
private readonly map;
|
|
21
|
+
private readonly cap;
|
|
22
|
+
private readonly idleEvictionMs;
|
|
23
|
+
private readonly evictionIntervalMs;
|
|
24
|
+
private evictionTimer;
|
|
25
|
+
private readonly onProjectCreated?;
|
|
26
|
+
private readonly onProjectEvicted?;
|
|
27
|
+
constructor(options: ProjectRegistryOptions);
|
|
28
|
+
startEvictionTimer(): void;
|
|
29
|
+
stopEvictionTimer(): void;
|
|
30
|
+
/** Synchronous lookup-or-create with cap enforcement. Increments pendingReservations on success. */
|
|
31
|
+
reserveProject(cwd: string): ReserveResult;
|
|
32
|
+
/**
|
|
33
|
+
* Called from onsessioninitialized. Decrements pendingReservations and registers the session.
|
|
34
|
+
* `canonicalCwd` MUST be the `.cwd` value returned from a prior `reserveProject` call.
|
|
35
|
+
*/
|
|
36
|
+
attachSession(canonicalCwd: string, sessionId: string): void;
|
|
37
|
+
/** Detach a session. `canonicalCwd` must match `projectContext.cwd`. No-op if unknown. */
|
|
38
|
+
detachSession(canonicalCwd: string, sessionId: string): void;
|
|
39
|
+
/** Called if attachSession never fires. `canonicalCwd` must match `projectContext.cwd`. */
|
|
40
|
+
cancelReservation(canonicalCwd: string): void;
|
|
41
|
+
/** Look up a project by its canonical cwd. */
|
|
42
|
+
get(canonicalCwd: string): ProjectContext | undefined;
|
|
43
|
+
get size(): number;
|
|
44
|
+
entries(): IterableIterator<[string, ProjectContext]>;
|
|
45
|
+
evictIdle(): void;
|
|
46
|
+
clear(): void;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=project-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-registry.d.ts","sourceRoot":"","sources":["../../src/http/project-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAG9F,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,CAAC;AAEzF,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC9D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1D;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAqC;IACzD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAwB;IAC1D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAwC;gBAE9D,OAAO,EAAE,sBAAsB;IAQ3C,kBAAkB,IAAI,IAAI;IAM1B,iBAAiB,IAAI,IAAI;IAKzB,oGAAoG;IACpG,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa;IAoB1C;;;OAGG;IACH,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAQ5D,0FAA0F;IAC1F,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAO5D,2FAA2F;IAC3F,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAO7C,8CAA8C;IAC9C,GAAG,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIrD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAEA,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAItD,SAAS,IAAI,IAAI;IAuBjB,KAAK,IAAI,IAAI;CAQd"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { createProjectContext } from '@zhixuan92/multi-model-agent-core';
|
|
2
|
+
import { validateCwd } from './cwd-validator.js';
|
|
3
|
+
export class ProjectRegistry {
|
|
4
|
+
map = new Map();
|
|
5
|
+
cap;
|
|
6
|
+
idleEvictionMs;
|
|
7
|
+
evictionIntervalMs;
|
|
8
|
+
evictionTimer = null;
|
|
9
|
+
onProjectCreated;
|
|
10
|
+
onProjectEvicted;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.cap = options.cap;
|
|
13
|
+
this.idleEvictionMs = options.idleEvictionMs;
|
|
14
|
+
this.evictionIntervalMs = options.evictionIntervalMs;
|
|
15
|
+
this.onProjectCreated = options.onProjectCreated;
|
|
16
|
+
this.onProjectEvicted = options.onProjectEvicted;
|
|
17
|
+
}
|
|
18
|
+
startEvictionTimer() {
|
|
19
|
+
if (this.evictionTimer)
|
|
20
|
+
return;
|
|
21
|
+
this.evictionTimer = setInterval(() => this.evictIdle(), this.evictionIntervalMs);
|
|
22
|
+
this.evictionTimer.unref?.();
|
|
23
|
+
}
|
|
24
|
+
stopEvictionTimer() {
|
|
25
|
+
if (this.evictionTimer)
|
|
26
|
+
clearInterval(this.evictionTimer);
|
|
27
|
+
this.evictionTimer = null;
|
|
28
|
+
}
|
|
29
|
+
/** Synchronous lookup-or-create with cap enforcement. Increments pendingReservations on success. */
|
|
30
|
+
reserveProject(cwd) {
|
|
31
|
+
const v = validateCwd(cwd);
|
|
32
|
+
if (!v.ok)
|
|
33
|
+
return { ok: false, error: v.error, message: v.message };
|
|
34
|
+
const key = v.canonicalCwd;
|
|
35
|
+
const existing = this.map.get(key);
|
|
36
|
+
if (existing) {
|
|
37
|
+
existing.pendingReservations += 1;
|
|
38
|
+
existing.lastSeenAt = Date.now();
|
|
39
|
+
return { ok: true, projectContext: existing, created: false };
|
|
40
|
+
}
|
|
41
|
+
if (this.map.size >= this.cap) {
|
|
42
|
+
return { ok: false, error: 'project_cap', message: `server at ${this.cap} projects; close some connections and retry` };
|
|
43
|
+
}
|
|
44
|
+
const pc = createProjectContext(key);
|
|
45
|
+
pc.pendingReservations = 1;
|
|
46
|
+
this.map.set(key, pc);
|
|
47
|
+
this.onProjectCreated?.(key);
|
|
48
|
+
return { ok: true, projectContext: pc, created: true };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Called from onsessioninitialized. Decrements pendingReservations and registers the session.
|
|
52
|
+
* `canonicalCwd` MUST be the `.cwd` value returned from a prior `reserveProject` call.
|
|
53
|
+
*/
|
|
54
|
+
attachSession(canonicalCwd, sessionId) {
|
|
55
|
+
const pc = this.map.get(canonicalCwd);
|
|
56
|
+
if (!pc)
|
|
57
|
+
throw new Error(`attachSession: no project for ${canonicalCwd} (did you pass the raw cwd instead of projectContext.cwd?)`);
|
|
58
|
+
pc.activeSessions.add(sessionId);
|
|
59
|
+
if (pc.pendingReservations > 0)
|
|
60
|
+
pc.pendingReservations -= 1;
|
|
61
|
+
pc.lastSeenAt = Date.now();
|
|
62
|
+
}
|
|
63
|
+
/** Detach a session. `canonicalCwd` must match `projectContext.cwd`. No-op if unknown. */
|
|
64
|
+
detachSession(canonicalCwd, sessionId) {
|
|
65
|
+
const pc = this.map.get(canonicalCwd);
|
|
66
|
+
if (!pc)
|
|
67
|
+
return;
|
|
68
|
+
pc.activeSessions.delete(sessionId);
|
|
69
|
+
pc.lastSeenAt = Date.now();
|
|
70
|
+
}
|
|
71
|
+
/** Called if attachSession never fires. `canonicalCwd` must match `projectContext.cwd`. */
|
|
72
|
+
cancelReservation(canonicalCwd) {
|
|
73
|
+
const pc = this.map.get(canonicalCwd);
|
|
74
|
+
if (!pc)
|
|
75
|
+
return;
|
|
76
|
+
if (pc.pendingReservations > 0)
|
|
77
|
+
pc.pendingReservations -= 1;
|
|
78
|
+
pc.lastSeenAt = Date.now();
|
|
79
|
+
}
|
|
80
|
+
/** Look up a project by its canonical cwd. */
|
|
81
|
+
get(canonicalCwd) {
|
|
82
|
+
return this.map.get(canonicalCwd);
|
|
83
|
+
}
|
|
84
|
+
get size() {
|
|
85
|
+
return this.map.size;
|
|
86
|
+
}
|
|
87
|
+
*entries() {
|
|
88
|
+
yield* this.map.entries();
|
|
89
|
+
}
|
|
90
|
+
evictIdle() {
|
|
91
|
+
const now = Date.now();
|
|
92
|
+
const victims = [];
|
|
93
|
+
for (const [cwd, pc] of this.map.entries()) {
|
|
94
|
+
if (pc.activeSessions.size === 0 &&
|
|
95
|
+
pc.activeRequests === 0 &&
|
|
96
|
+
pc.pendingReservations === 0 &&
|
|
97
|
+
now - pc.lastSeenAt > this.idleEvictionMs) {
|
|
98
|
+
victims.push(cwd);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
for (const cwd of victims) {
|
|
102
|
+
const pc = this.map.get(cwd);
|
|
103
|
+
pc.contextBlocks.clear();
|
|
104
|
+
pc.batchCache.clear();
|
|
105
|
+
pc.clarifications.clear();
|
|
106
|
+
this.map.delete(cwd);
|
|
107
|
+
this.onProjectEvicted?.(cwd, now - pc.lastSeenAt);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
clear() {
|
|
111
|
+
for (const pc of this.map.values()) {
|
|
112
|
+
pc.contextBlocks.clear();
|
|
113
|
+
pc.batchCache.clear();
|
|
114
|
+
pc.clarifications.clear();
|
|
115
|
+
}
|
|
116
|
+
this.map.clear();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=project-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-registry.js","sourceRoot":"","sources":["../../src/http/project-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
3
|
+
import type { ProjectContext } from '@zhixuan92/multi-model-agent-core';
|
|
4
|
+
export interface SessionEntry {
|
|
5
|
+
transport: StreamableHTTPServerTransport;
|
|
6
|
+
server: McpServer;
|
|
7
|
+
projectContext: ProjectContext;
|
|
8
|
+
openedAt: number;
|
|
9
|
+
lastRequestAt: number;
|
|
10
|
+
}
|
|
11
|
+
export declare class SessionRouter {
|
|
12
|
+
private readonly map;
|
|
13
|
+
set(sessionId: string, entry: SessionEntry): void;
|
|
14
|
+
get(sessionId: string): SessionEntry | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Remove the entry from the map without calling transport.close() / server.close().
|
|
17
|
+
* Use this from inside transport.onclose to avoid reentrant close calls.
|
|
18
|
+
*/
|
|
19
|
+
delete(sessionId: string): void;
|
|
20
|
+
/**
|
|
21
|
+
* Remove the entry AND dispose its transport + server. Use from external shutdown paths
|
|
22
|
+
* where the transport is still live. Idempotent; safe to call when the entry is already gone.
|
|
23
|
+
*/
|
|
24
|
+
remove(sessionId: string): Promise<void>;
|
|
25
|
+
touchSession(sessionId: string): void;
|
|
26
|
+
evictIdleSessions(timeoutMs: number, options?: {
|
|
27
|
+
onEvict?: (sessionId: string, entry: SessionEntry) => void;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
closeAll(): Promise<void>;
|
|
30
|
+
entries(): IterableIterator<[string, SessionEntry]>;
|
|
31
|
+
get size(): number;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=session-router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-router.d.ts","sourceRoot":"","sources":["../../src/http/session-router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACxG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAExE,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,6BAA6B,CAAC;IACzC,MAAM,EAAE,SAAS,CAAC;IAClB,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAmC;IAEvD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IAIjD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIhD;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI/B;;;OAGG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9C,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAK/B,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QACnD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;KAC5D,GAAG,OAAO,CAAC,IAAI,CAAC;IAYX,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAIpD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export class SessionRouter {
|
|
2
|
+
map = new Map();
|
|
3
|
+
set(sessionId, entry) {
|
|
4
|
+
this.map.set(sessionId, entry);
|
|
5
|
+
}
|
|
6
|
+
get(sessionId) {
|
|
7
|
+
return this.map.get(sessionId);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Remove the entry from the map without calling transport.close() / server.close().
|
|
11
|
+
* Use this from inside transport.onclose to avoid reentrant close calls.
|
|
12
|
+
*/
|
|
13
|
+
delete(sessionId) {
|
|
14
|
+
this.map.delete(sessionId);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Remove the entry AND dispose its transport + server. Use from external shutdown paths
|
|
18
|
+
* where the transport is still live. Idempotent; safe to call when the entry is already gone.
|
|
19
|
+
*/
|
|
20
|
+
async remove(sessionId) {
|
|
21
|
+
const entry = this.map.get(sessionId);
|
|
22
|
+
if (!entry)
|
|
23
|
+
return;
|
|
24
|
+
this.map.delete(sessionId);
|
|
25
|
+
try {
|
|
26
|
+
await entry.transport.close();
|
|
27
|
+
}
|
|
28
|
+
catch { /* best-effort */ }
|
|
29
|
+
try {
|
|
30
|
+
await entry.server.close();
|
|
31
|
+
}
|
|
32
|
+
catch { /* best-effort */ }
|
|
33
|
+
}
|
|
34
|
+
touchSession(sessionId) {
|
|
35
|
+
const entry = this.map.get(sessionId);
|
|
36
|
+
if (entry)
|
|
37
|
+
entry.lastRequestAt = Date.now();
|
|
38
|
+
}
|
|
39
|
+
async evictIdleSessions(timeoutMs, options) {
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
const victims = [];
|
|
42
|
+
for (const [id, entry] of this.map.entries()) {
|
|
43
|
+
if (now - entry.lastRequestAt > timeoutMs)
|
|
44
|
+
victims.push({ id, entry });
|
|
45
|
+
}
|
|
46
|
+
for (const { id, entry } of victims) {
|
|
47
|
+
options?.onEvict?.(id, entry);
|
|
48
|
+
await this.remove(id);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async closeAll() {
|
|
52
|
+
const ids = Array.from(this.map.keys());
|
|
53
|
+
await Promise.all(ids.map(id => this.remove(id)));
|
|
54
|
+
}
|
|
55
|
+
*entries() {
|
|
56
|
+
yield* this.map.entries();
|
|
57
|
+
}
|
|
58
|
+
get size() {
|
|
59
|
+
return this.map.size;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=session-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-router.js","sourceRoot":"","sources":["../../src/http/session-router.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,aAAa;IACP,GAAG,GAAG,IAAI,GAAG,EAAwB,CAAC;IAEvD,GAAG,CAAC,SAAiB,EAAE,KAAmB;QACxC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,GAAG,CAAC,SAAiB;QACnB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,SAAiB;QACtB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3B,IAAI,CAAC;YAAC,MAAM,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QAClE,IAAI,CAAC;YAAC,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IACjE,CAAC;IAED,YAAY,CAAC,SAAiB;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,KAAK;YAAE,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,SAAiB,EAAE,OAE1C;QACC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAA+C,EAAE,CAAC;QAC/D,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;YAC7C,IAAI,GAAG,GAAG,KAAK,CAAC,aAAa,GAAG,SAAS;gBAAE,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,KAAK,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,OAAO,EAAE,CAAC;YACpC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC9B,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QACxC,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,CAAC,OAAO;QACN,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAC5B,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as http from 'node:http';
|
|
2
|
+
import type { ProjectRegistry } from './project-registry.js';
|
|
3
|
+
import type { SessionRouter } from './session-router.js';
|
|
4
|
+
import type { MultiModelConfig, DiagnosticLogger } from '@zhixuan92/multi-model-agent-core';
|
|
5
|
+
export interface StatusHandlerOptions {
|
|
6
|
+
registry: ProjectRegistry;
|
|
7
|
+
router: SessionRouter;
|
|
8
|
+
config: MultiModelConfig;
|
|
9
|
+
logger: DiagnosticLogger;
|
|
10
|
+
token: string;
|
|
11
|
+
}
|
|
12
|
+
export interface StatusHandler {
|
|
13
|
+
(req: http.IncomingMessage, res: http.ServerResponse): void;
|
|
14
|
+
updateBinding(host: string, port: number): void;
|
|
15
|
+
trackRequestStart(sessionId: string, cwd: string, tool: string): string;
|
|
16
|
+
trackRequestEnd(reqTrackId: string, status: 'ok' | 'error', durationMs: number): void;
|
|
17
|
+
trackHeadline(reqTrackId: string, headline: string): void;
|
|
18
|
+
}
|
|
19
|
+
export declare function buildStatusHandler(options: StatusHandlerOptions): StatusHandler;
|
|
20
|
+
//# sourceMappingURL=status-endpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-endpoint.d.ts","sourceRoot":"","sources":["../../src/http/status-endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAK5F,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IAC5D,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAChD,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACxE,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACtF,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAuG/E"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { SERVER_VERSION } from '../cli.js';
|
|
2
|
+
import { isLoopbackAddress } from './loopback.js';
|
|
3
|
+
import { validateAuthHeader } from './auth.js';
|
|
4
|
+
export function buildStatusHandler(options) {
|
|
5
|
+
const startedAtMs = Date.now();
|
|
6
|
+
let boundHost = options.config.transport.http.bind;
|
|
7
|
+
let boundPort = options.config.transport.http.port;
|
|
8
|
+
const active = new Map();
|
|
9
|
+
const recent = [];
|
|
10
|
+
const RECENT_MAX = 100;
|
|
11
|
+
const handler = ((req, res) => {
|
|
12
|
+
const peer = req.socket.remoteAddress;
|
|
13
|
+
if (!isLoopbackAddress(peer)) {
|
|
14
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
15
|
+
res.end(JSON.stringify({ error: 'forbidden', message: '/status is loopback-only' }));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (options.config.transport.http.auth.enabled) {
|
|
19
|
+
const auth = validateAuthHeader(Array.isArray(req.headers.authorization) ? req.headers.authorization[0] : req.headers.authorization, options.token);
|
|
20
|
+
if (!auth.ok) {
|
|
21
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
22
|
+
res.end(JSON.stringify({ error: 'unauthorized' }));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const projects = [];
|
|
27
|
+
for (const [cwd, pc] of options.registry.entries()) {
|
|
28
|
+
projects.push({
|
|
29
|
+
cwd,
|
|
30
|
+
createdAt: new Date(pc.createdAt).toISOString(),
|
|
31
|
+
lastSeenAt: new Date(pc.lastSeenAt).toISOString(),
|
|
32
|
+
activeSessions: pc.activeSessions.size,
|
|
33
|
+
batchCacheSize: pc.batchCache.size,
|
|
34
|
+
contextBlocksSize: pc.contextBlocks.size,
|
|
35
|
+
clarificationsSize: pc.clarifications.size,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const displayHost = boundHost.includes(':') ? `[${boundHost}]` : boundHost;
|
|
39
|
+
const body = {
|
|
40
|
+
version: SERVER_VERSION,
|
|
41
|
+
pid: process.pid,
|
|
42
|
+
transport: 'http',
|
|
43
|
+
bind: `${displayHost}:${boundPort}`,
|
|
44
|
+
uptimeMs: Date.now() - startedAtMs,
|
|
45
|
+
auth: { enabled: options.config.transport.http.auth.enabled },
|
|
46
|
+
projects,
|
|
47
|
+
activeRequests: Array.from(active.values()).map(r => ({
|
|
48
|
+
sessionId: r.sessionId,
|
|
49
|
+
cwd: r.cwd,
|
|
50
|
+
tool: r.tool,
|
|
51
|
+
startedAt: new Date(r.startedAt).toISOString(),
|
|
52
|
+
lastHeadline: r.lastHeadline,
|
|
53
|
+
})),
|
|
54
|
+
recent: recent.slice(-10),
|
|
55
|
+
};
|
|
56
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
57
|
+
res.end(JSON.stringify(body));
|
|
58
|
+
});
|
|
59
|
+
handler.updateBinding = (host, port) => {
|
|
60
|
+
boundHost = host;
|
|
61
|
+
boundPort = port;
|
|
62
|
+
};
|
|
63
|
+
handler.trackRequestStart = (sessionId, cwd, tool) => {
|
|
64
|
+
const id = `${sessionId}:${Date.now()}:${Math.random().toString(36).slice(2, 8)}`;
|
|
65
|
+
active.set(id, { sessionId, cwd, tool, startedAt: Date.now() });
|
|
66
|
+
return id;
|
|
67
|
+
};
|
|
68
|
+
handler.trackRequestEnd = (id, status, durationMs) => {
|
|
69
|
+
const entry = active.get(id);
|
|
70
|
+
if (!entry)
|
|
71
|
+
return;
|
|
72
|
+
active.delete(id);
|
|
73
|
+
recent.push({ sessionId: entry.sessionId, cwd: entry.cwd, tool: entry.tool, status, durationMs });
|
|
74
|
+
while (recent.length > RECENT_MAX)
|
|
75
|
+
recent.shift();
|
|
76
|
+
};
|
|
77
|
+
handler.trackHeadline = (id, headline) => {
|
|
78
|
+
const entry = active.get(id);
|
|
79
|
+
if (!entry)
|
|
80
|
+
return;
|
|
81
|
+
entry.lastHeadline = headline;
|
|
82
|
+
};
|
|
83
|
+
return handler;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=status-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-endpoint.js","sourceRoot":"","sources":["../../src/http/status-endpoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type DiagnosticLogger, type MultiModelConfig } from '@zhixuan92/multi-model-agent-core';
|
|
2
|
+
import { ProjectRegistry } from './project-registry.js';
|
|
3
|
+
import { SessionRouter } from './session-router.js';
|
|
4
|
+
export interface DaemonHandle {
|
|
5
|
+
url: string;
|
|
6
|
+
logger: DiagnosticLogger;
|
|
7
|
+
registry: ProjectRegistry;
|
|
8
|
+
router: SessionRouter;
|
|
9
|
+
stop: () => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export declare function startHttpDaemon(config: MultiModelConfig, options?: {
|
|
12
|
+
testMode?: boolean;
|
|
13
|
+
}): Promise<DaemonHandle>;
|
|
14
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/http/transport.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAqB,MAAM,qBAAqB,CAAC;AAQvE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,gBAAgB,EACxB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAC/B,OAAO,CAAC,YAAY,CAAC,CA2NvB"}
|