@zhixuan92/multi-model-agent 3.0.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/LICENSE +21 -0
- package/README.md +217 -0
- package/dist/cli/index.d.ts +61 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +252 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/install-skill.d.ts +158 -0
- package/dist/cli/install-skill.d.ts.map +1 -0
- package/dist/cli/install-skill.js +425 -0
- package/dist/cli/install-skill.js.map +1 -0
- package/dist/cli/print-token.d.ts +18 -0
- package/dist/cli/print-token.d.ts.map +1 -0
- package/dist/cli/print-token.js +60 -0
- package/dist/cli/print-token.js.map +1 -0
- package/dist/cli/serve.d.ts +44 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +61 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/status.d.ts +49 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +155 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/http/async-dispatch.d.ts +32 -0
- package/dist/http/async-dispatch.d.ts.map +1 -0
- package/dist/http/async-dispatch.js +53 -0
- package/dist/http/async-dispatch.js.map +1 -0
- package/dist/http/auth.d.ts +26 -0
- package/dist/http/auth.d.ts.map +1 -0
- package/dist/http/auth.js +64 -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 +115 -0
- package/dist/http/cwd-validator.js.map +1 -0
- package/dist/http/errors.d.ts +4 -0
- package/dist/http/errors.d.ts.map +1 -0
- package/dist/http/errors.js +9 -0
- package/dist/http/errors.js.map +1 -0
- package/dist/http/execution-context.d.ts +15 -0
- package/dist/http/execution-context.d.ts.map +1 -0
- package/dist/http/execution-context.js +35 -0
- package/dist/http/execution-context.js.map +1 -0
- package/dist/http/handler-deps.d.ts +16 -0
- package/dist/http/handler-deps.d.ts.map +1 -0
- package/dist/http/handler-deps.js +2 -0
- package/dist/http/handler-deps.js.map +1 -0
- package/dist/http/handlers/control/batch.d.ts +24 -0
- package/dist/http/handlers/control/batch.d.ts.map +1 -0
- package/dist/http/handlers/control/batch.js +81 -0
- package/dist/http/handlers/control/batch.js.map +1 -0
- package/dist/http/handlers/control/clarifications.d.ts +19 -0
- package/dist/http/handlers/control/clarifications.d.ts.map +1 -0
- package/dist/http/handlers/control/clarifications.js +58 -0
- package/dist/http/handlers/control/clarifications.js.map +1 -0
- package/dist/http/handlers/control/context-blocks.d.ts +22 -0
- package/dist/http/handlers/control/context-blocks.d.ts.map +1 -0
- package/dist/http/handlers/control/context-blocks.js +88 -0
- package/dist/http/handlers/control/context-blocks.js.map +1 -0
- package/dist/http/handlers/introspection/health.d.ts +13 -0
- package/dist/http/handlers/introspection/health.d.ts.map +1 -0
- package/dist/http/handlers/introspection/health.js +17 -0
- package/dist/http/handlers/introspection/health.js.map +1 -0
- package/dist/http/handlers/introspection/status.d.ts +26 -0
- package/dist/http/handlers/introspection/status.d.ts.map +1 -0
- package/dist/http/handlers/introspection/status.js +136 -0
- package/dist/http/handlers/introspection/status.js.map +1 -0
- package/dist/http/handlers/introspection/tools-list.d.ts +9 -0
- package/dist/http/handlers/introspection/tools-list.d.ts.map +1 -0
- package/dist/http/handlers/introspection/tools-list.js +28 -0
- package/dist/http/handlers/introspection/tools-list.js.map +1 -0
- package/dist/http/handlers/tools/audit.d.ts +4 -0
- package/dist/http/handlers/tools/audit.d.ts.map +1 -0
- package/dist/http/handlers/tools/audit.js +39 -0
- package/dist/http/handlers/tools/audit.js.map +1 -0
- package/dist/http/handlers/tools/debug.d.ts +4 -0
- package/dist/http/handlers/tools/debug.d.ts.map +1 -0
- package/dist/http/handlers/tools/debug.js +39 -0
- package/dist/http/handlers/tools/debug.js.map +1 -0
- package/dist/http/handlers/tools/delegate.d.ts +4 -0
- package/dist/http/handlers/tools/delegate.d.ts.map +1 -0
- package/dist/http/handlers/tools/delegate.js +57 -0
- package/dist/http/handlers/tools/delegate.js.map +1 -0
- package/dist/http/handlers/tools/execute-plan.d.ts +4 -0
- package/dist/http/handlers/tools/execute-plan.d.ts.map +1 -0
- package/dist/http/handlers/tools/execute-plan.js +39 -0
- package/dist/http/handlers/tools/execute-plan.js.map +1 -0
- package/dist/http/handlers/tools/retry.d.ts +4 -0
- package/dist/http/handlers/tools/retry.d.ts.map +1 -0
- package/dist/http/handlers/tools/retry.js +52 -0
- package/dist/http/handlers/tools/retry.js.map +1 -0
- package/dist/http/handlers/tools/review.d.ts +4 -0
- package/dist/http/handlers/tools/review.d.ts.map +1 -0
- package/dist/http/handlers/tools/review.js +39 -0
- package/dist/http/handlers/tools/review.js.map +1 -0
- package/dist/http/handlers/tools/verify.d.ts +4 -0
- package/dist/http/handlers/tools/verify.d.ts.map +1 -0
- package/dist/http/handlers/tools/verify.js +39 -0
- package/dist/http/handlers/tools/verify.js.map +1 -0
- package/dist/http/loopback.d.ts +17 -0
- package/dist/http/loopback.d.ts.map +1 -0
- package/dist/http/loopback.js +43 -0
- package/dist/http/loopback.js.map +1 -0
- package/dist/http/middleware/body-reader.d.ts +16 -0
- package/dist/http/middleware/body-reader.d.ts.map +1 -0
- package/dist/http/middleware/body-reader.js +44 -0
- package/dist/http/middleware/body-reader.js.map +1 -0
- package/dist/http/project-registry.d.ts +54 -0
- package/dist/http/project-registry.d.ts.map +1 -0
- package/dist/http/project-registry.js +132 -0
- package/dist/http/project-registry.js.map +1 -0
- package/dist/http/router.d.ts +14 -0
- package/dist/http/router.d.ts.map +1 -0
- package/dist/http/router.js +41 -0
- package/dist/http/router.js.map +1 -0
- package/dist/http/server.d.ts +16 -0
- package/dist/http/server.d.ts.map +1 -0
- package/dist/http/server.js +235 -0
- package/dist/http/server.js.map +1 -0
- package/dist/http/types.d.ts +9 -0
- package/dist/http/types.d.ts.map +1 -0
- package/dist/http/types.js +2 -0
- package/dist/http/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/install/claude-code.d.ts +43 -0
- package/dist/install/claude-code.d.ts.map +1 -0
- package/dist/install/claude-code.js +65 -0
- package/dist/install/claude-code.js.map +1 -0
- package/dist/install/codex-cli.d.ts +39 -0
- package/dist/install/codex-cli.d.ts.map +1 -0
- package/dist/install/codex-cli.js +318 -0
- package/dist/install/codex-cli.js.map +1 -0
- package/dist/install/cursor.d.ts +72 -0
- package/dist/install/cursor.d.ts.map +1 -0
- package/dist/install/cursor.js +81 -0
- package/dist/install/cursor.js.map +1 -0
- package/dist/install/gemini-cli.d.ts +66 -0
- package/dist/install/gemini-cli.d.ts.map +1 -0
- package/dist/install/gemini-cli.js +111 -0
- package/dist/install/gemini-cli.js.map +1 -0
- package/dist/install/include-utils.d.ts +27 -0
- package/dist/install/include-utils.d.ts.map +1 -0
- package/dist/install/include-utils.js +90 -0
- package/dist/install/include-utils.js.map +1 -0
- package/dist/install/manifest.d.ts +90 -0
- package/dist/install/manifest.d.ts.map +1 -0
- package/dist/install/manifest.js +200 -0
- package/dist/install/manifest.js.map +1 -0
- package/dist/openapi.d.ts +15 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +314 -0
- package/dist/openapi.js.map +1 -0
- package/dist/skills/_shared/auth.md +32 -0
- package/dist/skills/_shared/error-handling.md +31 -0
- package/dist/skills/_shared/polling.md +40 -0
- package/dist/skills/_shared/response-shape.md +46 -0
- package/dist/skills/mma-audit/SKILL.md +55 -0
- package/dist/skills/mma-clarifications/SKILL.md +68 -0
- package/dist/skills/mma-context-blocks/SKILL.md +69 -0
- package/dist/skills/mma-debug/SKILL.md +59 -0
- package/dist/skills/mma-delegate/SKILL.md +63 -0
- package/dist/skills/mma-execute-plan/SKILL.md +63 -0
- package/dist/skills/mma-retry/SKILL.md +54 -0
- package/dist/skills/mma-review/SKILL.md +55 -0
- package/dist/skills/mma-verify/SKILL.md +57 -0
- package/dist/skills/multi-model-agent/SKILL.md +55 -0
- package/package.json +60 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* print-token.ts — `mmagent print-token` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Reads the bearer auth token and prints it to stdout.
|
|
5
|
+
* Env override (MMAGENT_AUTH_TOKEN) wins over any file.
|
|
6
|
+
* Missing file → prints an error message to stderr and exits 1.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* mmagent print-token [--config <path>]
|
|
10
|
+
*/
|
|
11
|
+
import * as os from 'node:os';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import * as fs from 'node:fs';
|
|
14
|
+
/** Expand a leading '~/' to the home directory. */
|
|
15
|
+
function expandHome(p, homeDir) {
|
|
16
|
+
if (p.startsWith('~/'))
|
|
17
|
+
return path.join(homeDir, p.slice(2));
|
|
18
|
+
return p;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Read the bearer token and print it to stdout.
|
|
22
|
+
* Returns 0 on success, 1 on error.
|
|
23
|
+
*/
|
|
24
|
+
export function printToken(deps = {}) {
|
|
25
|
+
const homeDir = deps.homeDir ?? os.homedir();
|
|
26
|
+
const env = deps.env ?? process.env;
|
|
27
|
+
const stdout = deps.stdout ?? process.stdout.write.bind(process.stdout);
|
|
28
|
+
const stderr = deps.stderr ?? process.stderr.write.bind(process.stderr);
|
|
29
|
+
// Env override wins
|
|
30
|
+
const envToken = (env['MMAGENT_AUTH_TOKEN'] ?? '').trim();
|
|
31
|
+
if (envToken.length > 0) {
|
|
32
|
+
stdout(envToken + '\n');
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
// Fall back to token file
|
|
36
|
+
const rawTokenFile = deps.tokenFile ?? path.join(homeDir, '.multi-model', 'auth-token');
|
|
37
|
+
const tokenFile = expandHome(rawTokenFile, homeDir);
|
|
38
|
+
try {
|
|
39
|
+
const token = fs.readFileSync(tokenFile, 'utf-8').trim();
|
|
40
|
+
if (token.length === 0) {
|
|
41
|
+
stderr(`mmagent: token file is empty: ${tokenFile}\n`);
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
stdout(token + '\n');
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
const code = err.code;
|
|
49
|
+
if (code === 'ENOENT') {
|
|
50
|
+
stderr(`mmagent: token file not found: ${tokenFile}\n` +
|
|
51
|
+
`Run 'mmagent serve' once to generate a token, or set MMAGENT_AUTH_TOKEN.\n`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
55
|
+
stderr(`mmagent: cannot read token file ${tokenFile}: ${msg}\n`);
|
|
56
|
+
}
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=print-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"print-token.js","sourceRoot":"","sources":["../../src/cli/print-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAE9B,mDAAmD;AACnD,SAAS,UAAU,CAAC,CAAS,EAAE,OAAe;IAC5C,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,CAAC;AACX,CAAC;AAeD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,OAAuB,EAAE;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAExE,oBAAoB;IACpB,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;QACxB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,0BAA0B;IAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;IACxF,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAEpD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACzD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,iCAAiC,SAAS,IAAI,CAAC,CAAC;YACvD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;QACrB,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,CACJ,kCAAkC,SAAS,IAAI;gBAC/C,4EAA4E,CAC7E,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,MAAM,CAAC,mCAAmC,SAAS,KAAK,GAAG,IAAI,CAAC,CAAC;QACnE,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* serve.ts — starts the HTTP server and manages its signal lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* This module owns the complete serve lifecycle: starting the HTTP server,
|
|
5
|
+
* registering SIGTERM/SIGINT handlers, draining in-flight requests, and
|
|
6
|
+
* cleanly exiting the process. The CLI entry point (cli/index.ts) delegates
|
|
7
|
+
* to this module and does not manage signals directly.
|
|
8
|
+
*
|
|
9
|
+
* Usage (library):
|
|
10
|
+
* const handle = await startServe(config);
|
|
11
|
+
* // server is running on handle.port
|
|
12
|
+
* await handle.stop(); // graceful shutdown; no process.exit
|
|
13
|
+
*
|
|
14
|
+
* Usage (CLI):
|
|
15
|
+
* mmagent serve [--config <path>]
|
|
16
|
+
* // this module owns signal handling and process.exit
|
|
17
|
+
*/
|
|
18
|
+
import type { MultiModelConfig } from '@zhixuan92/multi-model-agent-core';
|
|
19
|
+
/** A running server handle returned by startServe(). */
|
|
20
|
+
export interface ServeHandle {
|
|
21
|
+
/** The port the server is listening on (useful when port=0 for ephemeral). */
|
|
22
|
+
port: number;
|
|
23
|
+
/**
|
|
24
|
+
* Gracefully shut down the server.
|
|
25
|
+
* Removes any registered SIGTERM/SIGINT handlers to prevent leaks.
|
|
26
|
+
* After this resolves, the process is no longer listening and may exit safely.
|
|
27
|
+
*/
|
|
28
|
+
stop(): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Start the HTTP server with the given config.
|
|
32
|
+
*
|
|
33
|
+
* Registers SIGTERM and SIGINT handlers that drain in-flight requests and
|
|
34
|
+
* exit the process cleanly. If config includes `server.limits.shutdownDrainMs`,
|
|
35
|
+
* the server will wait up to that duration for in-flight requests to finish.
|
|
36
|
+
*
|
|
37
|
+
* @param config Full MultiModelConfig (includes agents.*, defaults, diagnostics,
|
|
38
|
+
* and server block). startServer() inspects the agents.* field
|
|
39
|
+
* and enables real tool handlers when present.
|
|
40
|
+
* @param exit Process exit function — defaults to process.exit.
|
|
41
|
+
* Exposed so tests can suppress actual exits.
|
|
42
|
+
*/
|
|
43
|
+
export declare function startServe(config: MultiModelConfig, exit?: (code: number) => never): Promise<ServeHandle>;
|
|
44
|
+
//# sourceMappingURL=serve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/cli/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAG1E,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAYD;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,gBAAgB,EACxB,IAAI,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAkC,GACzD,OAAO,CAAC,WAAW,CAAC,CAuCtB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { startServer } from '../http/server.js';
|
|
2
|
+
/**
|
|
3
|
+
* Shared signal-state used to deduplicate shutdown if two signals arrive
|
|
4
|
+
* before stop() resolves.
|
|
5
|
+
*/
|
|
6
|
+
let stopInFlight = false;
|
|
7
|
+
// Stored so they can be removed when stop() is called programmatically
|
|
8
|
+
let onSigterm;
|
|
9
|
+
let onSigint;
|
|
10
|
+
/**
|
|
11
|
+
* Start the HTTP server with the given config.
|
|
12
|
+
*
|
|
13
|
+
* Registers SIGTERM and SIGINT handlers that drain in-flight requests and
|
|
14
|
+
* exit the process cleanly. If config includes `server.limits.shutdownDrainMs`,
|
|
15
|
+
* the server will wait up to that duration for in-flight requests to finish.
|
|
16
|
+
*
|
|
17
|
+
* @param config Full MultiModelConfig (includes agents.*, defaults, diagnostics,
|
|
18
|
+
* and server block). startServer() inspects the agents.* field
|
|
19
|
+
* and enables real tool handlers when present.
|
|
20
|
+
* @param exit Process exit function — defaults to process.exit.
|
|
21
|
+
* Exposed so tests can suppress actual exits.
|
|
22
|
+
*/
|
|
23
|
+
export async function startServe(config, exit = process.exit.bind(process)) {
|
|
24
|
+
const running = await startServer(config);
|
|
25
|
+
const stderr = process.stderr.write.bind(process.stderr);
|
|
26
|
+
const cleanupSignal = (sig) => {
|
|
27
|
+
if (stopInFlight)
|
|
28
|
+
return;
|
|
29
|
+
stopInFlight = true;
|
|
30
|
+
stderr(`[mmagent] received ${sig}, shutting down gracefully\u2026\n`);
|
|
31
|
+
running.stop().then(() => exit(0)).catch((err) => {
|
|
32
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
33
|
+
stderr(`[mmagent] shutdown failed: ${msg}\n`);
|
|
34
|
+
exit(1);
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
// Register handlers using named references so they can be removed correctly.
|
|
38
|
+
// Using anonymous wrappers (e.g. `process.once('SIGTERM', () => fn(sig))`)
|
|
39
|
+
// would make process.off(sig, fn) unable to find and remove the listener.
|
|
40
|
+
onSigterm = () => cleanupSignal('SIGTERM');
|
|
41
|
+
onSigint = () => cleanupSignal('SIGINT');
|
|
42
|
+
process.once('SIGTERM', onSigterm);
|
|
43
|
+
process.once('SIGINT', onSigint);
|
|
44
|
+
// Print the actual bound address so operators see what the kernel assigned
|
|
45
|
+
// (useful when port=0 selects an ephemeral port).
|
|
46
|
+
const host = running.serverAddress ?? config.server.bind;
|
|
47
|
+
stderr(`[mmagent] listening on ${host}:${running.port}\n`);
|
|
48
|
+
return {
|
|
49
|
+
port: running.port,
|
|
50
|
+
stop: async () => {
|
|
51
|
+
// Clean up signal listeners to prevent leaks when stop() is called
|
|
52
|
+
// programmatically (i.e. not via a signal).
|
|
53
|
+
if (onSigterm)
|
|
54
|
+
process.off('SIGTERM', onSigterm);
|
|
55
|
+
if (onSigint)
|
|
56
|
+
process.off('SIGINT', onSigint);
|
|
57
|
+
await running.stop();
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/cli/serve.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAchD;;;GAGG;AACH,IAAI,YAAY,GAAG,KAAK,CAAC;AAEzB,uEAAuE;AACvE,IAAI,SAAmC,CAAC;AACxC,IAAI,QAAkC,CAAC;AAEvC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAwB,EACxB,OAAgC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;IAE1D,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAA2C,CAAC,CAAC;IAE/E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzD,MAAM,aAAa,GAAG,CAAC,GAAyB,EAAE,EAAE;QAClD,IAAI,YAAY;YAAE,OAAO;QACzB,YAAY,GAAG,IAAI,CAAC;QACpB,MAAM,CAAC,sBAAsB,GAAG,oCAAoC,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACxD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,MAAM,CAAC,8BAA8B,GAAG,IAAI,CAAC,CAAC;YAC9C,IAAI,CAAC,CAAC,CAAC,CAAC;QACV,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,6EAA6E;IAC7E,2EAA2E;IAC3E,0EAA0E;IAC1E,SAAS,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAC3C,QAAQ,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACzC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEjC,2EAA2E;IAC3E,kDAAkD;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;IACzD,MAAM,CAAC,0BAA0B,IAAI,IAAI,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;IAE3D,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,KAAK,IAAI,EAAE;YACf,mEAAmE;YACnE,4CAA4C;YAC5C,IAAI,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACjD,IAAI,QAAQ;gBAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC9C,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface StatusDeps {
|
|
2
|
+
/** Server URL (e.g. 'http://127.0.0.1:7337'). */
|
|
3
|
+
serverUrl: string;
|
|
4
|
+
/** Bearer auth token. */
|
|
5
|
+
token: string;
|
|
6
|
+
/** Output as raw JSON instead of pretty-printed summary. */
|
|
7
|
+
json?: boolean;
|
|
8
|
+
/** Write to stdout. */
|
|
9
|
+
stdout?: (s: string) => boolean;
|
|
10
|
+
/** Write to stderr. */
|
|
11
|
+
stderr?: (s: string) => boolean;
|
|
12
|
+
/** Inject fetch for testability. Defaults to global fetch. */
|
|
13
|
+
fetch?: typeof fetch;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Fetch GET /status and print a summary (or raw JSON).
|
|
17
|
+
* Returns an exit code: 0 on success, 1 on error.
|
|
18
|
+
*/
|
|
19
|
+
export declare function fetchStatus(deps: StatusDeps): Promise<number>;
|
|
20
|
+
/**
|
|
21
|
+
* Build the server URL from a bind address and port.
|
|
22
|
+
* Handles '0.0.0.0' / '::' by converting to '127.0.0.1' since /status
|
|
23
|
+
* is loopback-only.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildServerUrl(bind: string, port: number): string;
|
|
26
|
+
export interface RunStatusDeps {
|
|
27
|
+
/** Config with server.bind + server.port. */
|
|
28
|
+
serverUrl: string;
|
|
29
|
+
/** Token file path (already resolved). */
|
|
30
|
+
tokenFile: string;
|
|
31
|
+
/** Whether to output raw JSON. */
|
|
32
|
+
json?: boolean;
|
|
33
|
+
/** Environment variable accessor (for MMAGENT_AUTH_TOKEN override). */
|
|
34
|
+
env?: Record<string, string | undefined>;
|
|
35
|
+
/** Write to stdout. */
|
|
36
|
+
stdout?: (s: string) => boolean;
|
|
37
|
+
/** Write to stderr. */
|
|
38
|
+
stderr?: (s: string) => boolean;
|
|
39
|
+
/** Inject fetch for testability. */
|
|
40
|
+
fetch?: typeof fetch;
|
|
41
|
+
/** Home directory (used to expand token file paths). */
|
|
42
|
+
homeDir?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Read the token and then call fetchStatus.
|
|
46
|
+
* Returns exit code.
|
|
47
|
+
*/
|
|
48
|
+
export declare function runStatus(deps: RunStatusDeps): Promise<number>;
|
|
49
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/cli/status.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,UAAU;IACzB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uBAAuB;IACvB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,uBAAuB;IACvB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAiBD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAuEnE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjE;AAED,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,uBAAuB;IACvB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,uBAAuB;IACvB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,oCAAoC;IACpC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAuCpE"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* status.ts — `mmagent status` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Fetches GET /status from a running server and pretty-prints a summary.
|
|
5
|
+
* Supports --json to dump the raw JSON response.
|
|
6
|
+
* Exits 1 if the server is unreachable or returns an error status.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* mmagent status [--config <path>] [--json]
|
|
10
|
+
*/
|
|
11
|
+
import * as os from 'node:os';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
/**
|
|
14
|
+
* Format uptime in ms as a human-readable string.
|
|
15
|
+
*/
|
|
16
|
+
function formatUptime(ms) {
|
|
17
|
+
const seconds = Math.floor(ms / 1000);
|
|
18
|
+
const minutes = Math.floor(seconds / 60);
|
|
19
|
+
const hours = Math.floor(minutes / 60);
|
|
20
|
+
const days = Math.floor(hours / 24);
|
|
21
|
+
if (days > 0)
|
|
22
|
+
return `${days}d ${hours % 24}h ${minutes % 60}m`;
|
|
23
|
+
if (hours > 0)
|
|
24
|
+
return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
25
|
+
if (minutes > 0)
|
|
26
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
27
|
+
return `${seconds}s`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Fetch GET /status and print a summary (or raw JSON).
|
|
31
|
+
* Returns an exit code: 0 on success, 1 on error.
|
|
32
|
+
*/
|
|
33
|
+
export async function fetchStatus(deps) {
|
|
34
|
+
const { serverUrl, token, json = false } = deps;
|
|
35
|
+
const stdout = deps.stdout ?? process.stdout.write.bind(process.stdout);
|
|
36
|
+
const stderr = deps.stderr ?? process.stderr.write.bind(process.stderr);
|
|
37
|
+
const fetcher = deps.fetch ?? fetch;
|
|
38
|
+
const url = `${serverUrl.replace(/\/$/, '')}/status`;
|
|
39
|
+
let res;
|
|
40
|
+
try {
|
|
41
|
+
res = await fetcher(url, {
|
|
42
|
+
method: 'GET',
|
|
43
|
+
headers: {
|
|
44
|
+
Authorization: `Bearer ${token}`,
|
|
45
|
+
Accept: 'application/json',
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
51
|
+
stderr(`mmagent status: cannot reach server at ${serverUrl}: ${msg}\n`);
|
|
52
|
+
stderr(`Is the server running? Start it with 'mmagent serve'.\n`);
|
|
53
|
+
return 1;
|
|
54
|
+
}
|
|
55
|
+
if (!res.ok) {
|
|
56
|
+
stderr(`mmagent status: server returned HTTP ${res.status} ${res.statusText}\n`);
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
let body;
|
|
60
|
+
try {
|
|
61
|
+
body = (await res.json());
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
stderr(`mmagent status: invalid JSON response from server\n`);
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
if (json) {
|
|
68
|
+
stdout(JSON.stringify(body, null, 2) + '\n');
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
// Pretty-print summary
|
|
72
|
+
const lines = [];
|
|
73
|
+
lines.push(`mmagent server status`);
|
|
74
|
+
lines.push(`─────────────────────────────`);
|
|
75
|
+
if (body.version)
|
|
76
|
+
lines.push(` version: ${body.version}`);
|
|
77
|
+
if (body.pid !== undefined)
|
|
78
|
+
lines.push(` pid: ${body.pid}`);
|
|
79
|
+
if (body.bind)
|
|
80
|
+
lines.push(` bind: ${body.bind}`);
|
|
81
|
+
if (body.uptimeMs !== undefined)
|
|
82
|
+
lines.push(` uptime: ${formatUptime(body.uptimeMs)}`);
|
|
83
|
+
const c = body.counters;
|
|
84
|
+
if (c) {
|
|
85
|
+
lines.push(` projects: ${c.projectCount ?? 0}`);
|
|
86
|
+
lines.push(` active batches: ${c.activeBatches ?? 0}`);
|
|
87
|
+
lines.push(` active reqs: ${c.activeRequests ?? 0}`);
|
|
88
|
+
}
|
|
89
|
+
const inflightCount = Array.isArray(body.inflight) ? body.inflight.length : 0;
|
|
90
|
+
lines.push(` in-flight: ${inflightCount}`);
|
|
91
|
+
if (body.skillVersion !== undefined) {
|
|
92
|
+
const sv = body.skillVersion ?? 'none';
|
|
93
|
+
const compat = body.skillCompatible === true ? ' (compatible)'
|
|
94
|
+
: body.skillCompatible === false ? ' (incompatible — run mmagent install-skill to update)'
|
|
95
|
+
: '';
|
|
96
|
+
lines.push(` skill version: ${sv}${compat}`);
|
|
97
|
+
}
|
|
98
|
+
stdout(lines.join('\n') + '\n');
|
|
99
|
+
return 0;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Build the server URL from a bind address and port.
|
|
103
|
+
* Handles '0.0.0.0' / '::' by converting to '127.0.0.1' since /status
|
|
104
|
+
* is loopback-only.
|
|
105
|
+
*/
|
|
106
|
+
export function buildServerUrl(bind, port) {
|
|
107
|
+
const host = (bind === '0.0.0.0' || bind === '::') ? '127.0.0.1' : bind;
|
|
108
|
+
return `http://${host}:${port}`;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Read the token and then call fetchStatus.
|
|
112
|
+
* Returns exit code.
|
|
113
|
+
*/
|
|
114
|
+
export async function runStatus(deps) {
|
|
115
|
+
const { serverUrl, tokenFile, json = false } = deps;
|
|
116
|
+
const env = deps.env ?? process.env;
|
|
117
|
+
const stderr = deps.stderr ?? process.stderr.write.bind(process.stderr);
|
|
118
|
+
const homeDir = deps.homeDir ?? os.homedir();
|
|
119
|
+
// Read the token (env wins)
|
|
120
|
+
let token;
|
|
121
|
+
const envToken = (env['MMAGENT_AUTH_TOKEN'] ?? '').trim();
|
|
122
|
+
if (envToken.length > 0) {
|
|
123
|
+
token = envToken;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const { readFileSync } = await import('node:fs');
|
|
127
|
+
const resolvedTokenFile = tokenFile.startsWith('~/')
|
|
128
|
+
? path.join(homeDir, tokenFile.slice(2))
|
|
129
|
+
: tokenFile;
|
|
130
|
+
try {
|
|
131
|
+
token = readFileSync(resolvedTokenFile, 'utf-8').trim();
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
const code = err.code;
|
|
135
|
+
if (code === 'ENOENT') {
|
|
136
|
+
stderr(`mmagent status: token file not found: ${resolvedTokenFile}\n`);
|
|
137
|
+
stderr(`Run 'mmagent print-token' or set MMAGENT_AUTH_TOKEN.\n`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
141
|
+
stderr(`mmagent status: cannot read token file: ${msg}\n`);
|
|
142
|
+
}
|
|
143
|
+
return 1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return fetchStatus({
|
|
147
|
+
serverUrl,
|
|
148
|
+
token,
|
|
149
|
+
json,
|
|
150
|
+
stdout: deps.stdout,
|
|
151
|
+
stderr: deps.stderr,
|
|
152
|
+
fetch: deps.fetch,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/cli/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { BatchRegistry, ProjectContext } from '@zhixuan92/multi-model-agent-core';
|
|
2
|
+
import type { ExecutionContext } from '@zhixuan92/multi-model-agent-core/executors/types';
|
|
3
|
+
import type { HandlerDeps } from './handler-deps.js';
|
|
4
|
+
export interface AsyncDispatchOptions<TResult> {
|
|
5
|
+
tool: string;
|
|
6
|
+
projectCwd: string;
|
|
7
|
+
blockIds: string[];
|
|
8
|
+
batchRegistry: BatchRegistry;
|
|
9
|
+
projectContext: ProjectContext;
|
|
10
|
+
deps: HandlerDeps;
|
|
11
|
+
/**
|
|
12
|
+
* The async function that does the real work. Receives the ExecutionContext
|
|
13
|
+
* and the pre-allocated batchId.
|
|
14
|
+
*/
|
|
15
|
+
executor: (ctx: ExecutionContext, batchId: string) => Promise<TResult>;
|
|
16
|
+
}
|
|
17
|
+
export interface AsyncDispatchResult {
|
|
18
|
+
batchId: string;
|
|
19
|
+
statusUrl: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Registers a new batch as 'pending', schedules the executor via setImmediate,
|
|
23
|
+
* and returns immediately with { batchId, statusUrl }.
|
|
24
|
+
*
|
|
25
|
+
* On success: calls batchRegistry.complete(batchId, result).
|
|
26
|
+
* On failure: calls batchRegistry.fail(batchId, { code, message, stack }).
|
|
27
|
+
*
|
|
28
|
+
* IMPORTANT: Does NOT maintain a manual activeBatches counter.
|
|
29
|
+
* Use BatchRegistry.countActiveForProject(cwd) as the truth source.
|
|
30
|
+
*/
|
|
31
|
+
export declare function asyncDispatch<TResult>(opts: AsyncDispatchOptions<TResult>): AsyncDispatchResult;
|
|
32
|
+
//# sourceMappingURL=async-dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-dispatch.d.ts","sourceRoot":"","sources":["../../src/http/async-dispatch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mDAAmD,CAAC;AAC1F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,MAAM,WAAW,oBAAoB,CAAC,OAAO;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,EAAE,cAAc,CAAC;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB;;;OAGG;IACH,QAAQ,EAAE,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxE;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,OAAO,EACnC,IAAI,EAAE,oBAAoB,CAAC,OAAO,CAAC,GAClC,mBAAmB,CAyCrB"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// packages/server/src/http/async-dispatch.ts
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { buildExecutionContext } from './execution-context.js';
|
|
4
|
+
/**
|
|
5
|
+
* Registers a new batch as 'pending', schedules the executor via setImmediate,
|
|
6
|
+
* and returns immediately with { batchId, statusUrl }.
|
|
7
|
+
*
|
|
8
|
+
* On success: calls batchRegistry.complete(batchId, result).
|
|
9
|
+
* On failure: calls batchRegistry.fail(batchId, { code, message, stack }).
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT: Does NOT maintain a manual activeBatches counter.
|
|
12
|
+
* Use BatchRegistry.countActiveForProject(cwd) as the truth source.
|
|
13
|
+
*/
|
|
14
|
+
export function asyncDispatch(opts) {
|
|
15
|
+
const batchId = randomUUID();
|
|
16
|
+
const { batchRegistry, projectContext, deps, tool, projectCwd, blockIds } = opts;
|
|
17
|
+
// Register entry as 'pending' before scheduling executor
|
|
18
|
+
batchRegistry.register({
|
|
19
|
+
batchId,
|
|
20
|
+
projectCwd,
|
|
21
|
+
tool,
|
|
22
|
+
state: 'pending',
|
|
23
|
+
startedAt: Date.now(),
|
|
24
|
+
stateChangedAt: Date.now(),
|
|
25
|
+
blockIds,
|
|
26
|
+
blocksReleased: false,
|
|
27
|
+
});
|
|
28
|
+
// Build execution context for this batch
|
|
29
|
+
const ctx = buildExecutionContext(deps, projectContext, batchId);
|
|
30
|
+
// Schedule executor asynchronously — do not await here
|
|
31
|
+
setImmediate(() => {
|
|
32
|
+
void (async () => {
|
|
33
|
+
try {
|
|
34
|
+
const result = await opts.executor(ctx, batchId);
|
|
35
|
+
batchRegistry.complete(batchId, result);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
39
|
+
const stack = err instanceof Error ? err.stack : undefined;
|
|
40
|
+
batchRegistry.fail(batchId, {
|
|
41
|
+
code: 'executor_error',
|
|
42
|
+
message,
|
|
43
|
+
...(stack !== undefined && { stack }),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
})();
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
batchId,
|
|
50
|
+
statusUrl: `/batch/${batchId}`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=async-dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-dispatch.js","sourceRoot":"","sources":["../../src/http/async-dispatch.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAqB/D;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAmC;IAEnC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAEjF,yDAAyD;IACzD,aAAa,CAAC,QAAQ,CAAC;QACrB,OAAO;QACP,UAAU;QACV,IAAI;QACJ,KAAK,EAAE,SAAS;QAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;QAC1B,QAAQ;QACR,cAAc,EAAE,KAAK;KACtB,CAAC,CAAC;IAEH,yCAAyC;IACzC,MAAM,GAAG,GAAG,qBAAqB,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IAEjE,uDAAuD;IACvD,YAAY,CAAC,GAAG,EAAE;QAChB,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;gBACjD,aAAa,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC1C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjE,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC3D,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE;oBAC1B,IAAI,EAAE,gBAAgB;oBACtB,OAAO;oBACP,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,CAAC;iBACtC,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,OAAO;QACP,SAAS,EAAE,UAAU,OAAO,EAAE;KAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load or generate the bearer token from a file path.
|
|
3
|
+
* Respects the MMAGENT_AUTH_TOKEN env override via coreLoadAuthToken when the
|
|
4
|
+
* file already exists. Falls back to generating a new token if the file does not exist.
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadToken(tokenPath: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Validate an Authorization header value (including "Bearer " prefix).
|
|
9
|
+
* Uses crypto.timingSafeEqual to prevent timing attacks.
|
|
10
|
+
*
|
|
11
|
+
* Returns { ok: true } on success.
|
|
12
|
+
* Returns { ok: false, reason } on failure without leaking which check failed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateAuthHeader(header: string | undefined, expected: string): {
|
|
15
|
+
ok: true;
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
reason: 'missing' | 'malformed' | 'mismatch';
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Convenience wrapper with boolean return — used by the server pipeline.
|
|
22
|
+
* Accepts the raw Authorization header value (e.g. "Bearer abc123") and
|
|
23
|
+
* the expected token string (without "Bearer " prefix).
|
|
24
|
+
*/
|
|
25
|
+
export declare function validateBearerHeader(header: string | undefined, expectedToken: string): boolean;
|
|
26
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/http/auth.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAkBnD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,EAAE,MAAM,GACf;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAA;CAAE,CAU5E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAE/F"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import { randomBytes, timingSafeEqual } from 'node:crypto';
|
|
5
|
+
import { loadAuthToken as coreLoadAuthToken } from '@zhixuan92/multi-model-agent-core';
|
|
6
|
+
function expandHome(p) {
|
|
7
|
+
if (p.startsWith('~/'))
|
|
8
|
+
return path.join(os.homedir(), p.slice(2));
|
|
9
|
+
return p;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Load or generate the bearer token from a file path.
|
|
13
|
+
* Respects the MMAGENT_AUTH_TOKEN env override via coreLoadAuthToken when the
|
|
14
|
+
* file already exists. Falls back to generating a new token if the file does not exist.
|
|
15
|
+
*/
|
|
16
|
+
export function loadToken(tokenPath) {
|
|
17
|
+
const resolved = expandHome(tokenPath);
|
|
18
|
+
if (fs.existsSync(resolved)) {
|
|
19
|
+
const stat = fs.statSync(resolved);
|
|
20
|
+
// Warn (do not fail) if the existing file has group/other read/write bits set.
|
|
21
|
+
if ((stat.mode & 0o077) !== 0) {
|
|
22
|
+
process.stderr.write(`[multi-model-agent] warning: token file ${resolved} has insecure permissions (mode ${(stat.mode & 0o777).toString(8)}); recommend 'chmod 0600 ${resolved}'\n`);
|
|
23
|
+
}
|
|
24
|
+
// Use core's loadAuthToken so the MMAGENT_AUTH_TOKEN env override is respected.
|
|
25
|
+
return coreLoadAuthToken({ tokenFile: resolved });
|
|
26
|
+
}
|
|
27
|
+
const dir = path.dirname(resolved);
|
|
28
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
29
|
+
const token = randomBytes(32).toString('base64url');
|
|
30
|
+
fs.writeFileSync(resolved, token + '\n', { mode: 0o600 });
|
|
31
|
+
return token;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate an Authorization header value (including "Bearer " prefix).
|
|
35
|
+
* Uses crypto.timingSafeEqual to prevent timing attacks.
|
|
36
|
+
*
|
|
37
|
+
* Returns { ok: true } on success.
|
|
38
|
+
* Returns { ok: false, reason } on failure without leaking which check failed.
|
|
39
|
+
*/
|
|
40
|
+
export function validateAuthHeader(header, expected) {
|
|
41
|
+
if (!header)
|
|
42
|
+
return { ok: false, reason: 'missing' };
|
|
43
|
+
const parts = header.split(/\s+/);
|
|
44
|
+
if (parts.length !== 2)
|
|
45
|
+
return { ok: false, reason: 'malformed' };
|
|
46
|
+
if (parts[0].toLowerCase() !== 'bearer')
|
|
47
|
+
return { ok: false, reason: 'malformed' };
|
|
48
|
+
const presented = Buffer.from(parts[1]);
|
|
49
|
+
const expectedBuf = Buffer.from(expected);
|
|
50
|
+
if (presented.length !== expectedBuf.length)
|
|
51
|
+
return { ok: false, reason: 'mismatch' };
|
|
52
|
+
if (!timingSafeEqual(presented, expectedBuf))
|
|
53
|
+
return { ok: false, reason: 'mismatch' };
|
|
54
|
+
return { ok: true };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Convenience wrapper with boolean return — used by the server pipeline.
|
|
58
|
+
* Accepts the raw Authorization header value (e.g. "Bearer abc123") and
|
|
59
|
+
* the expected token string (without "Bearer " prefix).
|
|
60
|
+
*/
|
|
61
|
+
export function validateBearerHeader(header, expectedToken) {
|
|
62
|
+
return validateAuthHeader(header, expectedToken).ok;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/http/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type CwdValidationError = 'missing_cwd' | 'invalid_cwd' | 'cwd_not_dir' | 'forbidden_cwd';
|
|
2
|
+
export type CwdValidationResult = {
|
|
3
|
+
ok: true;
|
|
4
|
+
canonicalCwd: string;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
error: CwdValidationError;
|
|
8
|
+
message: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function validateCwd(cwd: string | undefined): CwdValidationResult;
|
|
11
|
+
//# sourceMappingURL=cwd-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cwd-validator.d.ts","sourceRoot":"","sources":["../../src/http/cwd-validator.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,eAAe,CAAC;AAEjG,MAAM,MAAM,mBAAmB,GAC3B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAiF9D,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,CAiCxE"}
|