@zhixuan92/multi-model-agent 5.0.1 → 5.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -9
- package/dist/cli/index.d.ts +62 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +345 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/info.d.ts +22 -0
- package/dist/cli/info.d.ts.map +1 -0
- package/dist/cli/info.js +100 -0
- package/dist/cli/info.js.map +1 -0
- package/dist/cli/logs.d.ts +15 -0
- package/dist/cli/logs.d.ts.map +1 -0
- package/dist/cli/logs.js +102 -0
- package/dist/cli/logs.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 +28 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +405 -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/cli/sync-skills.d.ts +58 -0
- package/dist/cli/sync-skills.d.ts.map +1 -0
- package/dist/cli/sync-skills.js +266 -0
- package/dist/cli/sync-skills.js.map +1 -0
- package/dist/cli/telemetry.d.ts +10 -0
- package/dist/cli/telemetry.d.ts.map +1 -0
- package/dist/cli/telemetry.js +161 -0
- package/dist/cli/telemetry.js.map +1 -0
- package/dist/cli/toggle.d.ts +26 -0
- package/dist/cli/toggle.d.ts.map +1 -0
- package/dist/cli/toggle.js +185 -0
- package/dist/cli/toggle.js.map +1 -0
- package/dist/http/async-dispatch.d.ts +44 -0
- package/dist/http/async-dispatch.d.ts.map +1 -0
- package/dist/http/async-dispatch.js +175 -0
- package/dist/http/async-dispatch.js.map +1 -0
- package/dist/http/auth.d.ts +20 -0
- package/dist/http/auth.d.ts.map +1 -0
- package/dist/http/auth.js +56 -0
- package/dist/http/auth.js.map +1 -0
- package/dist/http/canonicalize-file-paths.d.ts +8 -0
- package/dist/http/canonicalize-file-paths.d.ts.map +1 -0
- package/dist/http/canonicalize-file-paths.js +43 -0
- package/dist/http/canonicalize-file-paths.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 +130 -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 +18 -0
- package/dist/http/execution-context.d.ts.map +1 -0
- package/dist/http/execution-context.js +61 -0
- package/dist/http/execution-context.js.map +1 -0
- package/dist/http/handler-deps.d.ts +19 -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-slice.d.ts +4 -0
- package/dist/http/handlers/control/batch-slice.d.ts.map +1 -0
- package/dist/http/handlers/control/batch-slice.js +40 -0
- package/dist/http/handlers/control/batch-slice.js.map +1 -0
- package/dist/http/handlers/control/batch.d.ts +23 -0
- package/dist/http/handlers/control/batch.d.ts.map +1 -0
- package/dist/http/handlers/control/batch.js +332 -0
- package/dist/http/handlers/control/batch.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 +111 -0
- package/dist/http/handlers/control/context-blocks.js.map +1 -0
- package/dist/http/handlers/introspection/health.d.ts +20 -0
- package/dist/http/handlers/introspection/health.d.ts.map +1 -0
- package/dist/http/handlers/introspection/health.js +18 -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/tools/audit.d.ts +4 -0
- package/dist/http/handlers/tools/audit.d.ts.map +1 -0
- package/dist/http/handlers/tools/audit.js +43 -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 +43 -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 +43 -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 +45 -0
- package/dist/http/handlers/tools/execute-plan.js.map +1 -0
- package/dist/http/handlers/tools/investigate.d.ts +4 -0
- package/dist/http/handlers/tools/investigate.d.ts.map +1 -0
- package/dist/http/handlers/tools/investigate.js +64 -0
- package/dist/http/handlers/tools/investigate.js.map +1 -0
- package/dist/http/handlers/tools/journal-recall.d.ts +4 -0
- package/dist/http/handlers/tools/journal-recall.d.ts.map +1 -0
- package/dist/http/handlers/tools/journal-recall.js +40 -0
- package/dist/http/handlers/tools/journal-recall.js.map +1 -0
- package/dist/http/handlers/tools/journal-record.d.ts +8 -0
- package/dist/http/handlers/tools/journal-record.d.ts.map +1 -0
- package/dist/http/handlers/tools/journal-record.js +40 -0
- package/dist/http/handlers/tools/journal-record.js.map +1 -0
- package/dist/http/handlers/tools/research.d.ts +4 -0
- package/dist/http/handlers/tools/research.d.ts.map +1 -0
- package/dist/http/handlers/tools/research.js +64 -0
- package/dist/http/handlers/tools/research.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 +73 -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 +43 -0
- package/dist/http/handlers/tools/review.js.map +1 -0
- package/dist/http/journal-lock.d.ts +4 -0
- package/dist/http/journal-lock.d.ts.map +1 -0
- package/dist/http/journal-lock.js +34 -0
- package/dist/http/journal-lock.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/middleware/caller-identity.d.ts +16 -0
- package/dist/http/middleware/caller-identity.d.ts.map +1 -0
- package/dist/http/middleware/caller-identity.js +16 -0
- package/dist/http/middleware/caller-identity.js.map +1 -0
- package/dist/http/middleware/decompress.d.ts +14 -0
- package/dist/http/middleware/decompress.d.ts.map +1 -0
- package/dist/http/middleware/decompress.js +51 -0
- package/dist/http/middleware/decompress.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 +130 -0
- package/dist/http/project-registry.js.map +1 -0
- package/dist/http/request-observability.d.ts +8 -0
- package/dist/http/request-observability.d.ts.map +1 -0
- package/dist/http/request-observability.js +20 -0
- package/dist/http/request-observability.js.map +1 -0
- package/dist/http/request-pipeline.d.ts +16 -0
- package/dist/http/request-pipeline.d.ts.map +1 -0
- package/dist/http/request-pipeline.js +144 -0
- package/dist/http/request-pipeline.js.map +1 -0
- package/dist/http/server.d.ts +17 -0
- package/dist/http/server.d.ts.map +1 -0
- package/dist/http/server.js +300 -0
- package/dist/http/server.js.map +1 -0
- package/dist/http/types.d.ts +20 -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/skill-install/disabled-state.d.ts +35 -0
- package/dist/skill-install/disabled-state.d.ts.map +1 -0
- package/dist/skill-install/disabled-state.js +96 -0
- package/dist/skill-install/disabled-state.js.map +1 -0
- package/dist/skill-install/discover.d.ts +29 -0
- package/dist/skill-install/discover.d.ts.map +1 -0
- package/dist/skill-install/discover.js +104 -0
- package/dist/skill-install/discover.js.map +1 -0
- package/dist/skill-install/include-utils.d.ts +27 -0
- package/dist/skill-install/include-utils.d.ts.map +1 -0
- package/dist/skill-install/include-utils.js +90 -0
- package/dist/skill-install/include-utils.js.map +1 -0
- package/dist/skill-install/manifest.d.ts +82 -0
- package/dist/skill-install/manifest.d.ts.map +1 -0
- package/dist/skill-install/manifest.js +215 -0
- package/dist/skill-install/manifest.js.map +1 -0
- package/dist/skill-install/skill-installer-common.d.ts +26 -0
- package/dist/skill-install/skill-installer-common.d.ts.map +1 -0
- package/dist/skill-install/skill-installer-common.js +139 -0
- package/dist/skill-install/skill-installer-common.js.map +1 -0
- package/dist/skill-install/skill-installers/claude-code.d.ts +43 -0
- package/dist/skill-install/skill-installers/claude-code.d.ts.map +1 -0
- package/dist/skill-install/skill-installers/claude-code.js +65 -0
- package/dist/skill-install/skill-installers/claude-code.js.map +1 -0
- package/dist/skill-install/skill-installers/codex-cli.d.ts +27 -0
- package/dist/skill-install/skill-installers/codex-cli.d.ts.map +1 -0
- package/dist/skill-install/skill-installers/codex-cli.js +84 -0
- package/dist/skill-install/skill-installers/codex-cli.js.map +1 -0
- package/dist/skill-install/skill-installers/cursor.d.ts +72 -0
- package/dist/skill-install/skill-installers/cursor.d.ts.map +1 -0
- package/dist/skill-install/skill-installers/cursor.js +81 -0
- package/dist/skill-install/skill-installers/cursor.js.map +1 -0
- package/dist/skill-install/skill-installers/gemini-cli.d.ts +50 -0
- package/dist/skill-install/skill-installers/gemini-cli.d.ts.map +1 -0
- package/dist/skill-install/skill-installers/gemini-cli.js +72 -0
- package/dist/skill-install/skill-installers/gemini-cli.js.map +1 -0
- package/dist/skill-install/skill-manifest-sync.d.ts +11 -0
- package/dist/skill-install/skill-manifest-sync.d.ts.map +1 -0
- package/dist/skill-install/skill-manifest-sync.js +65 -0
- package/dist/skill-install/skill-manifest-sync.js.map +1 -0
- package/dist/skills/_shared/auth.md +41 -0
- package/dist/skills/_shared/error-handling.md +31 -0
- package/dist/skills/_shared/polling.md +88 -0
- package/dist/skills/_shared/response-shape.md +55 -0
- package/dist/skills/_shared/review-policy.md +15 -0
- package/dist/skills/mma-audit/SKILL.md +270 -0
- package/dist/skills/mma-context-blocks/SKILL.md +148 -0
- package/dist/skills/mma-debug/SKILL.md +208 -0
- package/dist/skills/mma-delegate/SKILL.md +216 -0
- package/dist/skills/mma-execute-plan/SKILL.md +214 -0
- package/dist/skills/mma-explore/SKILL.md +190 -0
- package/dist/skills/mma-investigate/SKILL.md +258 -0
- package/dist/skills/mma-journal-recall/SKILL.md +242 -0
- package/dist/skills/mma-journal-record/SKILL.md +202 -0
- package/dist/skills/mma-research/SKILL.md +223 -0
- package/dist/skills/mma-retry/SKILL.md +221 -0
- package/dist/skills/mma-review/SKILL.md +209 -0
- package/dist/skills/multi-model-agent/SKILL.md +206 -0
- package/dist/telemetry/consent.d.ts +4 -0
- package/dist/telemetry/consent.d.ts.map +1 -0
- package/dist/telemetry/consent.js +40 -0
- package/dist/telemetry/consent.js.map +1 -0
- package/dist/telemetry/flusher.d.ts +19 -0
- package/dist/telemetry/flusher.d.ts.map +1 -0
- package/dist/telemetry/flusher.js +277 -0
- package/dist/telemetry/flusher.js.map +1 -0
- package/dist/telemetry/generation.d.ts +9 -0
- package/dist/telemetry/generation.d.ts.map +1 -0
- package/dist/telemetry/generation.js +33 -0
- package/dist/telemetry/generation.js.map +1 -0
- package/dist/telemetry/identity.d.ts +9 -0
- package/dist/telemetry/identity.d.ts.map +1 -0
- package/dist/telemetry/identity.js +35 -0
- package/dist/telemetry/identity.js.map +1 -0
- package/dist/telemetry/install-id.d.ts +13 -0
- package/dist/telemetry/install-id.d.ts.map +1 -0
- package/dist/telemetry/install-id.js +49 -0
- package/dist/telemetry/install-id.js.map +1 -0
- package/dist/telemetry/install-meta.d.ts +10 -0
- package/dist/telemetry/install-meta.d.ts.map +1 -0
- package/dist/telemetry/install-meta.js +15 -0
- package/dist/telemetry/install-meta.js.map +1 -0
- package/dist/telemetry/queue.d.ts +35 -0
- package/dist/telemetry/queue.d.ts.map +1 -0
- package/dist/telemetry/queue.js +287 -0
- package/dist/telemetry/queue.js.map +1 -0
- package/dist/telemetry/recorder.d.ts +39 -0
- package/dist/telemetry/recorder.d.ts.map +1 -0
- package/dist/telemetry/recorder.js +173 -0
- package/dist/telemetry/recorder.js.map +1 -0
- package/package.json +43 -24
- package/scripts/postinstall.js +36 -0
- package/bin/mmagent.mjs +0 -47
- package/postinstall.mjs +0 -8
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { HTTPListener } from '@zhixuan92/multi-model-agent-core';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { join, dirname } from 'node:path';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { RouteDispatcher } from '@zhixuan92/multi-model-agent-core';
|
|
7
|
+
import { EnvelopeBus } from '@zhixuan92/multi-model-agent-core/events/envelope-bus';
|
|
8
|
+
import { LogWriter } from '@zhixuan92/multi-model-agent-core/events/log-writer';
|
|
9
|
+
import { TelemetryUploader } from '@zhixuan92/multi-model-agent-core/events/telemetry-uploader';
|
|
10
|
+
import { StderrLogSubscriber } from '@zhixuan92/multi-model-agent-core/events/stderr-log-subscriber';
|
|
11
|
+
import { decideConsent } from '@zhixuan92/multi-model-agent-core/events/consent-rules';
|
|
12
|
+
import { sendError, sendJson } from './errors.js';
|
|
13
|
+
import { loadToken } from './auth.js';
|
|
14
|
+
import { handleRequest } from './request-pipeline.js';
|
|
15
|
+
import { getRecorder } from '../telemetry/recorder.js';
|
|
16
|
+
/** Server package version — read once at module load time from package.json. */
|
|
17
|
+
function readServerVersion() {
|
|
18
|
+
try {
|
|
19
|
+
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
// Walk up from src/http/ to packages/server/
|
|
21
|
+
const pkgPath = join(thisDir, '..', '..', 'package.json');
|
|
22
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
23
|
+
return pkg.version ?? '0.0.0';
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return '0.0.0';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export const SERVER_VERSION = readServerVersion();
|
|
30
|
+
/** Routes where the loopback guard is enforced. */
|
|
31
|
+
const LOOPBACK_ONLY_PATHS = new Set(['/health', '/status']);
|
|
32
|
+
/** Routes that do NOT require bearer auth. */
|
|
33
|
+
const AUTH_EXEMPT_PATHS = new Set(['/health']);
|
|
34
|
+
/** Routes that require a `cwd` query parameter (validated by cwd-validator middleware). */
|
|
35
|
+
const CWD_REQUIRED_PATHS = new Set([
|
|
36
|
+
'/delegate', '/audit', '/review', '/debug', '/execute-plan', '/retry', '/investigate', '/research', '/journal-record', '/journal-recall',
|
|
37
|
+
'/control/batch-slice', '/context-blocks',
|
|
38
|
+
]);
|
|
39
|
+
/** Routes that require the X-MMA-Main-Model header. Enforced at request boundary
|
|
40
|
+
* so wire telemetry's main_model column is never null for billed runs. The
|
|
41
|
+
* tool routes need it; the introspection / batch-polling / context-block
|
|
42
|
+
* utility routes do not. */
|
|
43
|
+
const MAIN_MODEL_REQUIRED_PATHS = new Set([
|
|
44
|
+
'/delegate', '/audit', '/review', '/debug', '/execute-plan', '/retry', '/investigate', '/research', '/journal-record', '/journal-recall',
|
|
45
|
+
]);
|
|
46
|
+
/**
|
|
47
|
+
* Registers tool handlers (POST /delegate, /audit, /review, /debug, /execute-plan, /retry).
|
|
48
|
+
* Builds a ToolSurfaceRegistry by calling each tool-config's registerXxx, then
|
|
49
|
+
* iterates `registry.list()` filtered to `surface: 'tool'` entries to drive
|
|
50
|
+
* route registration. The registry is the canonical source for tool surface
|
|
51
|
+
* metadata (httpMethod, httpPath, schema, toolCategory).
|
|
52
|
+
*/
|
|
53
|
+
async function registerToolHandlers(router, config, batchRegistry, projectRegistry) {
|
|
54
|
+
const { buildToolSurfaceRegistry } = await import('@zhixuan92/multi-model-agent-core');
|
|
55
|
+
const surface = buildToolSurfaceRegistry();
|
|
56
|
+
// For tool handlers, we need MultiModelConfig which is part of ServerConfig only
|
|
57
|
+
// when the full mmagent.config.json is loaded. In test/minimal configs that only
|
|
58
|
+
// have `server:`, we create a stub config. Real CLI startup will load full config.
|
|
59
|
+
const multiModelConfig = config.agents
|
|
60
|
+
? config
|
|
61
|
+
: undefined;
|
|
62
|
+
if (!multiModelConfig) {
|
|
63
|
+
// Server started with server-only config (e.g. tests): register stubs that return 503.
|
|
64
|
+
// Drive registration from the registry so adding a tool only requires a tool-config edit.
|
|
65
|
+
for (const entry of surface.list()) {
|
|
66
|
+
if (entry.surface !== 'tool')
|
|
67
|
+
continue;
|
|
68
|
+
router.register(entry.httpMethod, entry.httpPath, (_req, res, _params, _ctx) => {
|
|
69
|
+
sendError(res, 503, 'no_agent_config', 'Server started without agent configuration; provide a full mmagent.config.json');
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const bus = new EnvelopeBus();
|
|
75
|
+
const logWriter = new LogWriter({ diagnosticsLog: multiModelConfig.diagnostics?.log ?? false, logDir: multiModelConfig.diagnostics?.logDir });
|
|
76
|
+
bus.subscribe(logWriter);
|
|
77
|
+
// Always-on stderr log stream — no quiet mode and no --verbose flag (4.7.3+).
|
|
78
|
+
bus.subscribe(new StderrLogSubscriber());
|
|
79
|
+
let recorderForBus = null;
|
|
80
|
+
try {
|
|
81
|
+
recorderForBus = getRecorder();
|
|
82
|
+
}
|
|
83
|
+
catch { /* not initialized */ }
|
|
84
|
+
// decideConsent signature: read from packages/server/src/telemetry/consent.ts. Today it reads
|
|
85
|
+
// process.env.MMAGENT_TELEMETRY + a config.json. Replicate that call here:
|
|
86
|
+
const decideConsentForUploader = () => {
|
|
87
|
+
const envVal = process.env.MMAGENT_TELEMETRY;
|
|
88
|
+
let configState = undefined;
|
|
89
|
+
try {
|
|
90
|
+
const cfgPath = join(homedir(), '.multi-model', 'config.json');
|
|
91
|
+
const cfg = JSON.parse(readFileSync(cfgPath, 'utf8'));
|
|
92
|
+
if (cfg && typeof cfg === 'object' && cfg.telemetry && typeof cfg.telemetry === 'object' && typeof cfg.telemetry.enabled === 'boolean') {
|
|
93
|
+
configState = { enabled: cfg.telemetry.enabled };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
if (e.code !== 'ENOENT') {
|
|
98
|
+
configState = { kind: 'unreadable' };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return decideConsent({ env: envVal, config: configState });
|
|
102
|
+
};
|
|
103
|
+
const uploader = new TelemetryUploader({
|
|
104
|
+
recorder: recorderForBus,
|
|
105
|
+
consent: { decide: decideConsentForUploader },
|
|
106
|
+
buildOpts: (env) => ({
|
|
107
|
+
toolMode: 'full', // default
|
|
108
|
+
implementerModel: env.stages[0]?.model ?? env.mainModel,
|
|
109
|
+
implementerTier: env.stages[0]?.tier ?? env.agentType,
|
|
110
|
+
mainModelFamily: env.mainModel.split('-')[0] ?? 'unknown',
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
bus.subscribe(uploader);
|
|
114
|
+
const deps = { config: multiModelConfig, bus, logWriter, projectRegistry, batchRegistry };
|
|
115
|
+
// Per-tool handler builders, keyed by registry routeName. The registry tells
|
|
116
|
+
// us WHICH route to register and at WHICH path/method; this map answers HOW
|
|
117
|
+
// to build the per-tool handler.
|
|
118
|
+
const { buildDelegateHandler } = await import('./handlers/tools/delegate.js');
|
|
119
|
+
const { buildAuditHandler } = await import('./handlers/tools/audit.js');
|
|
120
|
+
const { buildReviewHandler } = await import('./handlers/tools/review.js');
|
|
121
|
+
const { buildDebugHandler } = await import('./handlers/tools/debug.js');
|
|
122
|
+
const { buildExecutePlanHandler } = await import('./handlers/tools/execute-plan.js');
|
|
123
|
+
const { buildRetryHandler } = await import('./handlers/tools/retry.js');
|
|
124
|
+
const { buildInvestigateHandler } = await import('./handlers/tools/investigate.js');
|
|
125
|
+
const { buildResearchHandler } = await import('./handlers/tools/research.js');
|
|
126
|
+
const { buildJournalRecordHandler } = await import('./handlers/tools/journal-record.js');
|
|
127
|
+
const { buildJournalRecallHandler } = await import('./handlers/tools/journal-recall.js');
|
|
128
|
+
const builders = {
|
|
129
|
+
delegate: buildDelegateHandler,
|
|
130
|
+
audit: buildAuditHandler,
|
|
131
|
+
review: buildReviewHandler,
|
|
132
|
+
debug: buildDebugHandler,
|
|
133
|
+
execute_plan: buildExecutePlanHandler,
|
|
134
|
+
retry_tasks: buildRetryHandler,
|
|
135
|
+
investigate: buildInvestigateHandler,
|
|
136
|
+
research: buildResearchHandler,
|
|
137
|
+
'journal-record': buildJournalRecordHandler,
|
|
138
|
+
'journal-recall': buildJournalRecallHandler,
|
|
139
|
+
};
|
|
140
|
+
for (const entry of surface.list()) {
|
|
141
|
+
if (entry.surface !== 'tool')
|
|
142
|
+
continue;
|
|
143
|
+
const builder = builders[entry.routeName];
|
|
144
|
+
if (!builder) {
|
|
145
|
+
// Route is in the registry but its handler hasn't been wired yet
|
|
146
|
+
// (e.g. /research added in a prior task, handler lands in a later one).
|
|
147
|
+
// Skip silently — the next task wires the handler and enables the route.
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
router.register(entry.httpMethod, entry.httpPath, builder(deps));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Registers control handlers (GET /batch/:batchId, POST/DELETE /context-blocks).
|
|
155
|
+
*/
|
|
156
|
+
async function registerControlHandlers(router, config, batchRegistry, projectRegistry) {
|
|
157
|
+
const { buildBatchHandler } = await import('./handlers/control/batch.js');
|
|
158
|
+
const { buildBatchSliceHandler } = await import('./handlers/control/batch-slice.js');
|
|
159
|
+
const { buildCreateContextBlockHandler, buildDeleteContextBlockHandler } = await import('./handlers/control/context-blocks.js');
|
|
160
|
+
const multiModelConfig = config.agents
|
|
161
|
+
? config
|
|
162
|
+
: undefined;
|
|
163
|
+
router.register('GET', '/batch/:batchId', buildBatchHandler({ batchRegistry }));
|
|
164
|
+
if (multiModelConfig) {
|
|
165
|
+
const bus = new EnvelopeBus();
|
|
166
|
+
const logWriter = new LogWriter({ diagnosticsLog: multiModelConfig.diagnostics?.log ?? false, logDir: multiModelConfig.diagnostics?.logDir });
|
|
167
|
+
bus.subscribe(logWriter);
|
|
168
|
+
bus.subscribe(new StderrLogSubscriber());
|
|
169
|
+
let recorderForBus = null;
|
|
170
|
+
try {
|
|
171
|
+
recorderForBus = getRecorder();
|
|
172
|
+
}
|
|
173
|
+
catch { /* not initialized */ }
|
|
174
|
+
const decideConsentForUploader = () => {
|
|
175
|
+
const envVal = process.env.MMAGENT_TELEMETRY;
|
|
176
|
+
let configState = undefined;
|
|
177
|
+
try {
|
|
178
|
+
const cfgPath = join(homedir(), '.multi-model', 'config.json');
|
|
179
|
+
const cfg = JSON.parse(readFileSync(cfgPath, 'utf8'));
|
|
180
|
+
if (cfg && typeof cfg === 'object' && cfg.telemetry && typeof cfg.telemetry === 'object' && typeof cfg.telemetry.enabled === 'boolean') {
|
|
181
|
+
configState = { enabled: cfg.telemetry.enabled };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
if (e.code !== 'ENOENT') {
|
|
186
|
+
configState = { kind: 'unreadable' };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return decideConsent({ env: envVal, config: configState });
|
|
190
|
+
};
|
|
191
|
+
const uploader = new TelemetryUploader({
|
|
192
|
+
recorder: recorderForBus,
|
|
193
|
+
consent: { decide: decideConsentForUploader },
|
|
194
|
+
buildOpts: (env) => ({
|
|
195
|
+
toolMode: 'full', // default
|
|
196
|
+
implementerModel: env.stages[0]?.model ?? env.mainModel,
|
|
197
|
+
implementerTier: env.stages[0]?.tier ?? env.agentType,
|
|
198
|
+
mainModelFamily: env.mainModel.split('-')[0] ?? 'unknown',
|
|
199
|
+
}),
|
|
200
|
+
});
|
|
201
|
+
bus.subscribe(uploader);
|
|
202
|
+
const deps = { config: multiModelConfig, bus, logWriter, projectRegistry, batchRegistry };
|
|
203
|
+
router.register('POST', '/control/batch-slice', buildBatchSliceHandler(deps));
|
|
204
|
+
router.register('POST', '/context-blocks', buildCreateContextBlockHandler({
|
|
205
|
+
projectRegistry,
|
|
206
|
+
maxContextBlockBytes: multiModelConfig.server.limits.maxContextBlockBytes,
|
|
207
|
+
maxContextBlocksPerProject: multiModelConfig.server.limits.maxContextBlocksPerProject,
|
|
208
|
+
}));
|
|
209
|
+
router.register('DELETE', '/context-blocks/:blockId', buildDeleteContextBlockHandler({ projectRegistry }));
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
router.register('POST', '/control/batch-slice', (_req, res) => {
|
|
213
|
+
sendError(res, 503, 'no_agent_config', 'Server started without agent configuration; provide a full mmagent.config.json');
|
|
214
|
+
});
|
|
215
|
+
router.register('POST', '/context-blocks', (_req, res) => {
|
|
216
|
+
sendError(res, 503, 'no_agent_config', 'Server started without agent configuration; provide a full mmagent.config.json');
|
|
217
|
+
});
|
|
218
|
+
router.register('DELETE', '/context-blocks/:blockId', buildDeleteContextBlockHandler({ projectRegistry }));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
export async function startServer(config, injectedManifestSync) {
|
|
222
|
+
const token = loadToken(config.server.auth.tokenFile);
|
|
223
|
+
const router = new RouteDispatcher();
|
|
224
|
+
// ── Create shared registries ───────────────────────────────────────────────
|
|
225
|
+
const { BatchRegistry } = await import('@zhixuan92/multi-model-agent-core');
|
|
226
|
+
const { ProjectRegistry } = await import('./project-registry.js');
|
|
227
|
+
const batchRegistry = new BatchRegistry({
|
|
228
|
+
batchTtlMs: config.server.limits.batchTtlMs,
|
|
229
|
+
});
|
|
230
|
+
const projectRegistry = new ProjectRegistry({
|
|
231
|
+
cap: config.server.limits.projectCap,
|
|
232
|
+
idleEvictionMs: config.server.limits.idleProjectTimeoutMs,
|
|
233
|
+
evictionIntervalMs: Math.min(config.server.limits.idleProjectTimeoutMs, 60_000),
|
|
234
|
+
});
|
|
235
|
+
// Capture serverStartedAt before health registration so /health can expose it.
|
|
236
|
+
const serverStartedAt = Date.now();
|
|
237
|
+
// GET /health — unauthenticated liveness + skill manifest drift check
|
|
238
|
+
const { buildHealthHandler } = await import('./handlers/introspection/health.js');
|
|
239
|
+
let skillManifestSync;
|
|
240
|
+
if (injectedManifestSync) {
|
|
241
|
+
skillManifestSync = injectedManifestSync;
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
try {
|
|
245
|
+
const { makeSkillManifestSync } = await import('../skill-install/skill-manifest-sync.js');
|
|
246
|
+
const { discoverPerClientInstallDirs } = await import('../skill-install/discover.js');
|
|
247
|
+
skillManifestSync = makeSkillManifestSync(discoverPerClientInstallDirs());
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
skillManifestSync = { driftReport: () => [] };
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
router.register('GET', '/health', buildHealthHandler({ manifestSync: skillManifestSync }));
|
|
254
|
+
// Register tool handlers (Phase 6)
|
|
255
|
+
await registerToolHandlers(router, config, batchRegistry, projectRegistry);
|
|
256
|
+
// Register control handlers (Phase 7)
|
|
257
|
+
await registerControlHandlers(router, config, batchRegistry, projectRegistry);
|
|
258
|
+
// GET /status — operator introspection (registered after registries are ready)
|
|
259
|
+
const { buildStatusHandler } = await import('./handlers/introspection/status.js');
|
|
260
|
+
router.register('GET', '/status', buildStatusHandler({
|
|
261
|
+
batchRegistry,
|
|
262
|
+
projectRegistry,
|
|
263
|
+
serverStartedAt,
|
|
264
|
+
bind: config.server.bind,
|
|
265
|
+
version: SERVER_VERSION,
|
|
266
|
+
}));
|
|
267
|
+
// Test-only: enumerates registered routes. Guarded by env; zero impact on production.
|
|
268
|
+
if (process.env.MMAGENT_TEST_INTROSPECTION === '1') {
|
|
269
|
+
router.register('GET', '/__routes', (_req, res) => {
|
|
270
|
+
sendJson(res, 200, router.listRoutes().map((route) => ({
|
|
271
|
+
method: route.method.toUpperCase(),
|
|
272
|
+
path: route.path,
|
|
273
|
+
})));
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
const listener = new HTTPListener({
|
|
277
|
+
bind: config.server.bind,
|
|
278
|
+
port: config.server.port,
|
|
279
|
+
handler: (req, res) => handleRequest(router, token, req, res, config, PIPELINE_CFG),
|
|
280
|
+
});
|
|
281
|
+
const { port, address: serverAddress } = await listener.start();
|
|
282
|
+
return {
|
|
283
|
+
port,
|
|
284
|
+
serverAddress,
|
|
285
|
+
stop: () => listener.stop(),
|
|
286
|
+
batchRegistry,
|
|
287
|
+
projectRegistry,
|
|
288
|
+
serverStartedAt,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
// Per-request pipeline lives in request-pipeline.ts. server.ts owns routing
|
|
292
|
+
// table + bootstrap; the pipeline owns body-cap → route → loopback → auth →
|
|
293
|
+
// JSON parse → cwd → dispatch.
|
|
294
|
+
const PIPELINE_CFG = {
|
|
295
|
+
loopbackOnlyPaths: LOOPBACK_ONLY_PATHS,
|
|
296
|
+
authExemptPaths: AUTH_EXEMPT_PATHS,
|
|
297
|
+
cwdRequiredPaths: CWD_REQUIRED_PATHS,
|
|
298
|
+
mainModelRequiredPaths: MAIN_MODEL_REQUIRED_PATHS,
|
|
299
|
+
};
|
|
300
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/http/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { CallerClient } from './middleware/caller-identity.js';
|
|
3
|
+
export interface RequestContext {
|
|
4
|
+
url: URL;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
body?: unknown;
|
|
7
|
+
authed: boolean;
|
|
8
|
+
callerClient: CallerClient;
|
|
9
|
+
/** Calling agent's model id from x-mma-main-model header (null if absent). */
|
|
10
|
+
mainModel: string | null;
|
|
11
|
+
}
|
|
12
|
+
export type Handler = (ctx: RequestContext, res: ServerResponse, params: Record<string, string>) => Promise<void> | void;
|
|
13
|
+
/**
|
|
14
|
+
* Raw handler shape used by the C1 RouteDispatcher inside the server.
|
|
15
|
+
* Server-specific because it carries RequestContext (caller identity, cwd, body).
|
|
16
|
+
* The core RouteDispatcher is generic; this is the concrete H instantiation
|
|
17
|
+
* the server registers.
|
|
18
|
+
*/
|
|
19
|
+
export type RawHandler = (req: IncomingMessage, res: ServerResponse, params: Record<string, string>, ctx: RequestContext) => Promise<void> | void;
|
|
20
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/http/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,GAAG,CAAC;IACT,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,YAAY,CAAC;IAC3B,8EAA8E;IAC9E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEzH;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,CACvB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,GAAG,EAAE,cAAc,KAChB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/http/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type Client } from './manifest.js';
|
|
3
|
+
declare const disabledStateSchema: z.ZodObject<{
|
|
4
|
+
version: z.ZodLiteral<1>;
|
|
5
|
+
disabledAt: z.ZodNumber;
|
|
6
|
+
cliVersion: z.ZodString;
|
|
7
|
+
targets: z.ZodArray<z.ZodEnum<{
|
|
8
|
+
gemini: "gemini";
|
|
9
|
+
"claude-code": "claude-code";
|
|
10
|
+
cursor: "cursor";
|
|
11
|
+
codex: "codex";
|
|
12
|
+
}>>;
|
|
13
|
+
}, z.core.$strip>;
|
|
14
|
+
export type DisabledState = z.infer<typeof disabledStateSchema>;
|
|
15
|
+
/** Full path to the sentinel file. */
|
|
16
|
+
export declare function disabledStatePath(homeDir?: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Read and validate the sentinel. Returns null when absent, unreadable, or
|
|
19
|
+
* structurally invalid — a malformed sentinel must never wedge sync-skills.
|
|
20
|
+
*/
|
|
21
|
+
export declare function readDisabledState(homeDir?: string): DisabledState | null;
|
|
22
|
+
/** The set of currently-disabled clients (empty when the sentinel is absent). */
|
|
23
|
+
export declare function disabledTargets(homeDir?: string): Client[];
|
|
24
|
+
/**
|
|
25
|
+
* Mark `targets` as disabled, unioned with any already-disabled clients.
|
|
26
|
+
* Returns the resulting disabled set (stable ALL_CLIENTS order).
|
|
27
|
+
*/
|
|
28
|
+
export declare function addDisabledTargets(homeDir: string | undefined, targets: Client[], cliVersion: string): Client[];
|
|
29
|
+
/**
|
|
30
|
+
* Clear `targets` from the disabled set. Deletes the sentinel file entirely
|
|
31
|
+
* once nothing remains disabled. Returns the still-disabled set.
|
|
32
|
+
*/
|
|
33
|
+
export declare function clearDisabledTargets(homeDir: string | undefined, targets: Client[]): Client[];
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=disabled-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disabled-state.d.ts","sourceRoot":"","sources":["../../src/skill-install/disabled-state.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAA4B,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAQtE,QAAA,MAAM,mBAAmB;;;;;;;;;;iBAKvB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,sCAAsC;AACtC,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAQxE;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAE1D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,EAAE,MAAM,EAAE,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAWV;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAgB7F"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* disabled-state.ts — the persistent "skills disabled" sentinel.
|
|
3
|
+
*
|
|
4
|
+
* `mmagent disable` writes this file; `sync-skills` (and the npm postinstall
|
|
5
|
+
* hook that shells out to it) consults it so an upgrade never silently
|
|
6
|
+
* reinstalls skills the user deliberately turned off. `mmagent enable` clears
|
|
7
|
+
* the relevant targets and, when none remain, deletes the file.
|
|
8
|
+
*
|
|
9
|
+
* Stored at ~/.multi-model/skills-disabled.json — the same directory as the
|
|
10
|
+
* install manifest and auth token, with matching 0o700/0o600 permissions.
|
|
11
|
+
*
|
|
12
|
+
* The sentinel is target-aware: it records *which* clients are disabled so a
|
|
13
|
+
* `disable --target=cursor` does not block syncing claude-code.
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'node:fs';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
import { ALL_CLIENTS, manifestDir } from './manifest.js';
|
|
19
|
+
const DISABLED_NAME = 'skills-disabled.json';
|
|
20
|
+
// Derive the client enum from ALL_CLIENTS so a new client never silently
|
|
21
|
+
// fails sentinel validation. z.enum needs a non-empty literal tuple.
|
|
22
|
+
const clientEnum = z.enum(ALL_CLIENTS);
|
|
23
|
+
const disabledStateSchema = z.object({
|
|
24
|
+
version: z.literal(1),
|
|
25
|
+
disabledAt: z.number().int().nonnegative(),
|
|
26
|
+
cliVersion: z.string(),
|
|
27
|
+
targets: z.array(clientEnum),
|
|
28
|
+
});
|
|
29
|
+
/** Full path to the sentinel file. */
|
|
30
|
+
export function disabledStatePath(homeDir) {
|
|
31
|
+
return path.join(manifestDir(homeDir), DISABLED_NAME);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Read and validate the sentinel. Returns null when absent, unreadable, or
|
|
35
|
+
* structurally invalid — a malformed sentinel must never wedge sync-skills.
|
|
36
|
+
*/
|
|
37
|
+
export function readDisabledState(homeDir) {
|
|
38
|
+
try {
|
|
39
|
+
const raw = fs.readFileSync(disabledStatePath(homeDir), 'utf-8');
|
|
40
|
+
const parsed = disabledStateSchema.safeParse(JSON.parse(raw));
|
|
41
|
+
return parsed.success ? parsed.data : null;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** The set of currently-disabled clients (empty when the sentinel is absent). */
|
|
48
|
+
export function disabledTargets(homeDir) {
|
|
49
|
+
return readDisabledState(homeDir)?.targets ?? [];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Mark `targets` as disabled, unioned with any already-disabled clients.
|
|
53
|
+
* Returns the resulting disabled set (stable ALL_CLIENTS order).
|
|
54
|
+
*/
|
|
55
|
+
export function addDisabledTargets(homeDir, targets, cliVersion) {
|
|
56
|
+
const current = new Set(disabledTargets(homeDir));
|
|
57
|
+
for (const t of targets)
|
|
58
|
+
current.add(t);
|
|
59
|
+
const merged = ALL_CLIENTS.filter((c) => current.has(c));
|
|
60
|
+
writeDisabledState(homeDir, {
|
|
61
|
+
version: 1,
|
|
62
|
+
disabledAt: Date.now(),
|
|
63
|
+
cliVersion,
|
|
64
|
+
targets: merged,
|
|
65
|
+
});
|
|
66
|
+
return merged;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Clear `targets` from the disabled set. Deletes the sentinel file entirely
|
|
70
|
+
* once nothing remains disabled. Returns the still-disabled set.
|
|
71
|
+
*/
|
|
72
|
+
export function clearDisabledTargets(homeDir, targets) {
|
|
73
|
+
const existing = readDisabledState(homeDir);
|
|
74
|
+
if (existing === null)
|
|
75
|
+
return [];
|
|
76
|
+
const remaining = existing.targets.filter((t) => !targets.includes(t));
|
|
77
|
+
if (remaining.length === 0) {
|
|
78
|
+
try {
|
|
79
|
+
fs.rmSync(disabledStatePath(homeDir), { force: true });
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
/* best effort — an absent file is the desired end state anyway */
|
|
83
|
+
}
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
writeDisabledState(homeDir, { ...existing, targets: remaining });
|
|
87
|
+
return remaining;
|
|
88
|
+
}
|
|
89
|
+
function writeDisabledState(homeDir, state) {
|
|
90
|
+
fs.mkdirSync(manifestDir(homeDir), { recursive: true, mode: 0o700 });
|
|
91
|
+
fs.writeFileSync(disabledStatePath(homeDir), JSON.stringify(state, null, 2) + '\n', {
|
|
92
|
+
encoding: 'utf-8',
|
|
93
|
+
mode: 0o600,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=disabled-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disabled-state.js","sourceRoot":"","sources":["../../src/skill-install/disabled-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Client } from './manifest.js';
|
|
2
|
+
export declare const SUPPORTED_SKILLS: readonly ["multi-model-agent", "mma-delegate", "mma-audit", "mma-review", "mma-debug", "mma-execute-plan", "mma-retry", "mma-context-blocks", "mma-investigate", "mma-research", "mma-explore", "mma-journal-record", "mma-journal-recall"];
|
|
3
|
+
/** Thrown when a skill's SKILL.md cannot be read from the bundled skills directory. */
|
|
4
|
+
export declare class SkillNotFoundError extends Error {
|
|
5
|
+
readonly code: "skill_not_found";
|
|
6
|
+
constructor(skillName: string, checkedPath: string);
|
|
7
|
+
}
|
|
8
|
+
export declare function skillsRootCandidates(here: string): string[];
|
|
9
|
+
export declare function pickSkillsRoot(here: string, exists?: (p: string) => boolean): string;
|
|
10
|
+
/**
|
|
11
|
+
* Return the absolute path to the skills root directory. Production: the
|
|
12
|
+
* bundled `packages/server/src/skills/` (or its dist mirror). Tests pass
|
|
13
|
+
* a fixture path explicitly.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getSkillsRoot(skillsRoot?: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Read the content of a skill's SKILL.md file. Returns null if the file
|
|
18
|
+
* does not exist; propagates other I/O errors so callers can distinguish
|
|
19
|
+
* "skill not found" from "can't access skill".
|
|
20
|
+
*/
|
|
21
|
+
export declare function readSkillContent(skillName: string, skillsRoot?: string): string | null;
|
|
22
|
+
/**
|
|
23
|
+
* Return the per-client install directories where skills are written as
|
|
24
|
+
* subdirectories. Only includes clients that use the per-skill directory
|
|
25
|
+
* model (claude-code and codex). Gemini and Cursor bundle skills into a
|
|
26
|
+
* single file/extension and are not included.
|
|
27
|
+
*/
|
|
28
|
+
export declare function discoverPerClientInstallDirs(homeDir?: string): Partial<Record<Client, string>>;
|
|
29
|
+
//# sourceMappingURL=discover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../src/skill-install/discover.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,eAAO,MAAM,gBAAgB,6OAcnB,CAAC;AAEX,uFAAuF;AACvF,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAG,iBAAiB,CAAU;gBAC/B,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAOnD;AAYD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAgB3D;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAuB,GAC7C,MAAM,CAMR;AAID;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQtF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAM9F"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Skill discovery — locates packaged SKILL.md files on disk and reads them.
|
|
2
|
+
// Extracted from cli/install-skill.ts as part of Ch 7 Task 39.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
export const SUPPORTED_SKILLS = [
|
|
8
|
+
'multi-model-agent',
|
|
9
|
+
'mma-delegate',
|
|
10
|
+
'mma-audit',
|
|
11
|
+
'mma-review',
|
|
12
|
+
'mma-debug',
|
|
13
|
+
'mma-execute-plan',
|
|
14
|
+
'mma-retry',
|
|
15
|
+
'mma-context-blocks',
|
|
16
|
+
'mma-investigate',
|
|
17
|
+
'mma-research',
|
|
18
|
+
'mma-explore',
|
|
19
|
+
'mma-journal-record',
|
|
20
|
+
'mma-journal-recall',
|
|
21
|
+
];
|
|
22
|
+
/** Thrown when a skill's SKILL.md cannot be read from the bundled skills directory. */
|
|
23
|
+
export class SkillNotFoundError extends Error {
|
|
24
|
+
code = 'skill_not_found';
|
|
25
|
+
constructor(skillName, checkedPath) {
|
|
26
|
+
super(`Skill '${skillName}' not found. ` +
|
|
27
|
+
`Checked: ${checkedPath}. ` +
|
|
28
|
+
`Available skills: ${SUPPORTED_SKILLS.join(', ')}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Discover.ts lives in `packages/core/src/tool-surface/` (or its dist mirror).
|
|
32
|
+
// Skills are bundled by the server package at `packages/server/src/skills/`
|
|
33
|
+
// (copied to `packages/server/dist/skills/` at build time, then shipped on
|
|
34
|
+
// the `@zhixuan92/multi-model-agent` npm package as `dist/skills/`).
|
|
35
|
+
// Probe candidates for both monorepo dev layouts and the two npm-installed
|
|
36
|
+
// layouts (hoisted siblings, or core nested under server).
|
|
37
|
+
//
|
|
38
|
+
// Exported (and parameterized on `here` + `exists`) so the candidate logic
|
|
39
|
+
// can be unit-tested against fixtures that mimic each layout — the v4.0.1
|
|
40
|
+
// regression was a missing prod candidate.
|
|
41
|
+
export function skillsRootCandidates(here) {
|
|
42
|
+
return [
|
|
43
|
+
// Dev source: packages/core/src/tool-surface -> packages/server/src/skills
|
|
44
|
+
path.resolve(here, '..', '..', '..', 'server', 'src', 'skills'),
|
|
45
|
+
// Dev built: packages/core/dist/tool-surface -> packages/server/dist/skills
|
|
46
|
+
path.resolve(here, '..', '..', '..', 'server', 'dist', 'skills'),
|
|
47
|
+
// npm install (hoisted): node_modules/@zhixuan92/multi-model-agent-core/dist/tool-surface
|
|
48
|
+
// -> node_modules/@zhixuan92/multi-model-agent/dist/skills
|
|
49
|
+
path.resolve(here, '..', '..', '..', 'multi-model-agent', 'dist', 'skills'),
|
|
50
|
+
// npm install (core nested under server):
|
|
51
|
+
// .../multi-model-agent/node_modules/@zhixuan92/multi-model-agent-core/dist/tool-surface
|
|
52
|
+
// -> .../multi-model-agent/dist/skills
|
|
53
|
+
path.resolve(here, '..', '..', '..', '..', '..', 'dist', 'skills'),
|
|
54
|
+
// Last-resort fallback for any caller that bundles skills inside core.
|
|
55
|
+
path.resolve(here, '..', 'skills'),
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
export function pickSkillsRoot(here, exists = fs.existsSync) {
|
|
59
|
+
const candidates = skillsRootCandidates(here);
|
|
60
|
+
for (const c of candidates) {
|
|
61
|
+
if (exists(c))
|
|
62
|
+
return c;
|
|
63
|
+
}
|
|
64
|
+
return candidates[0];
|
|
65
|
+
}
|
|
66
|
+
const DEFAULT_SKILLS_ROOT = pickSkillsRoot(path.dirname(fileURLToPath(import.meta.url)));
|
|
67
|
+
/**
|
|
68
|
+
* Return the absolute path to the skills root directory. Production: the
|
|
69
|
+
* bundled `packages/server/src/skills/` (or its dist mirror). Tests pass
|
|
70
|
+
* a fixture path explicitly.
|
|
71
|
+
*/
|
|
72
|
+
export function getSkillsRoot(skillsRoot) {
|
|
73
|
+
return skillsRoot ?? DEFAULT_SKILLS_ROOT;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Read the content of a skill's SKILL.md file. Returns null if the file
|
|
77
|
+
* does not exist; propagates other I/O errors so callers can distinguish
|
|
78
|
+
* "skill not found" from "can't access skill".
|
|
79
|
+
*/
|
|
80
|
+
export function readSkillContent(skillName, skillsRoot) {
|
|
81
|
+
const skillFile = path.join(getSkillsRoot(skillsRoot), skillName, 'SKILL.md');
|
|
82
|
+
try {
|
|
83
|
+
return fs.readFileSync(skillFile, 'utf-8');
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
if (err.code === 'ENOENT')
|
|
87
|
+
return null;
|
|
88
|
+
throw err;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Return the per-client install directories where skills are written as
|
|
93
|
+
* subdirectories. Only includes clients that use the per-skill directory
|
|
94
|
+
* model (claude-code and codex). Gemini and Cursor bundle skills into a
|
|
95
|
+
* single file/extension and are not included.
|
|
96
|
+
*/
|
|
97
|
+
export function discoverPerClientInstallDirs(homeDir) {
|
|
98
|
+
const h = homeDir ?? os.homedir();
|
|
99
|
+
return {
|
|
100
|
+
'claude-code': path.join(h, '.claude', 'skills'),
|
|
101
|
+
'codex': path.join(h, '.codex', 'skills'),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/skill-install/discover.ts"],"names":[],"mappings":"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"}
|