@evomap/evolver-mcp 2.0.0-beta.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/dist/codexInstaller.d.ts +34 -0
- package/dist/codexInstaller.js +171 -0
- package/dist/cursorRulesInstaller.d.ts +76 -0
- package/dist/cursorRulesInstaller.js +196 -0
- package/dist/envFile.d.ts +10 -0
- package/dist/envFile.js +68 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -0
- package/dist/injection.d.ts +56 -0
- package/dist/injection.js +84 -0
- package/dist/installer.d.ts +106 -0
- package/dist/installer.js +513 -0
- package/dist/manualWiring.d.ts +14 -0
- package/dist/manualWiring.js +91 -0
- package/dist/primer.d.ts +12 -0
- package/dist/primer.js +32 -0
- package/dist/proxyClient.d.ts +72 -0
- package/dist/proxyClient.js +193 -0
- package/dist/server.d.ts +31 -0
- package/dist/server.js +38 -0
- package/dist/serviceGuidance.d.ts +15 -0
- package/dist/serviceGuidance.js +170 -0
- package/dist/stdio.d.ts +2 -0
- package/dist/stdio.js +107 -0
- package/dist/tools.d.ts +39 -0
- package/dist/tools.js +401 -0
- package/package.json +35 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** Every runtime in the setup matrix (#217), in a stable order — used for usage text and the unsupported reason. */
|
|
2
|
+
export const SETUP_RUNTIMES = [
|
|
3
|
+
'claude-code', 'codex', 'cursor', 'opencode', 'kiro', 'openclaw', 'mcp-generic', 'http-agent', 'server',
|
|
4
|
+
];
|
|
5
|
+
/** Runtimes v2 can write config/hooks for and verify. */
|
|
6
|
+
const INSTALLED_RUNTIMES = new Set(['claude-code', 'codex', 'cursor']);
|
|
7
|
+
/** Runtimes with no v2 auto-installer but a real manual path. The reason is the short, honest "do it by hand"
|
|
8
|
+
* line; the precise wiring text is a separate concern (#217 slice 2), not hard-coded here. */
|
|
9
|
+
const MANUAL_RUNTIMES = new Map([
|
|
10
|
+
['opencode', 'opencode is consumed passively today; register the evolver MCP server in its config by hand'],
|
|
11
|
+
['kiro', 'kiro is consumed passively today; register the evolver MCP server in its config by hand'],
|
|
12
|
+
['openclaw', 'no v2 auto-installer yet; wire the evolver MCP server (or PrivateHub HTTP/A2A) by hand'],
|
|
13
|
+
['mcp-generic', 'no config writer for a generic MCP client; register the evolver MCP server by hand'],
|
|
14
|
+
['http-agent', 'no config writer for an HTTP/API-only agent; wire it to PrivateHub HTTP/A2A by hand'],
|
|
15
|
+
['server', 'v2 does not manage service lifecycle; use the server/service startup guidance by hand'],
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Classify a runtime id into the setup matrix (#217). Takes a RAW string (not the SetupRuntime union) so the
|
|
19
|
+
* unsupported branch is reachable: an unrecognized id is the `unsupported` case, with a reason that lists the
|
|
20
|
+
* runtimes v2 does recognize. This is the single source of truth the CLI uses to decide install vs print vs refuse.
|
|
21
|
+
*/
|
|
22
|
+
export function runtimeSupport(runtime) {
|
|
23
|
+
if (INSTALLED_RUNTIMES.has(runtime))
|
|
24
|
+
return { runtime, outcome: 'installed' };
|
|
25
|
+
const reason = MANUAL_RUNTIMES.get(runtime);
|
|
26
|
+
if (reason !== undefined)
|
|
27
|
+
return { runtime, outcome: 'manual', reason };
|
|
28
|
+
return { runtime, outcome: 'unsupported', reason: `unknown runtime '${runtime}' (supported: ${SETUP_RUNTIMES.join(', ')})` };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 按 runtime 规划 MCP 工具注入(M5-5). MVP: CC(hooks)+codex(plugin) 做工具注入,
|
|
32
|
+
* 其余仅被动会话日志消费(待确认 a / 批注#39). 注入方式差异大, 故每 runtime 一策略.
|
|
33
|
+
*/
|
|
34
|
+
export function planInjection(runtime, server) {
|
|
35
|
+
switch (runtime) {
|
|
36
|
+
case 'claude-code':
|
|
37
|
+
return {
|
|
38
|
+
runtime, mode: 'mcp-hooks',
|
|
39
|
+
// CC 成熟: .mcp.json 注册 MCP server, agent 在 tool list 自然发现
|
|
40
|
+
config: { mcpServers: { evolver: { command: server.command, args: server.args ?? [], ...(server.env ? { env: server.env } : {}) } } },
|
|
41
|
+
note: 'CC: 写 .mcp.json + SessionStart hook; agent 经 MCP tool list 自然发现 evolver 能力',
|
|
42
|
+
};
|
|
43
|
+
case 'codex':
|
|
44
|
+
return {
|
|
45
|
+
runtime, mode: 'mcp-plugin',
|
|
46
|
+
// codex loads TOML (~/.codex or project .codex/config.toml). Real schema: an MCP stdio server under
|
|
47
|
+
// [mcp_servers.<id>] (command/args/env) — the installer also adds a [[hooks.SessionStart]] hook so
|
|
48
|
+
// codex gets the same hybrid as CC. Config mirrors the codex [mcp_servers.evolver] table shape.
|
|
49
|
+
config: { mcp_servers: { evolver: { command: server.command, args: server.args ?? [], ...(server.env ? { env: server.env } : {}) } } },
|
|
50
|
+
note: 'codex: 写 .codex/config.toml [mcp_servers.evolver] + [[hooks.SessionStart]]; agent 经 MCP tool list 发现 evolver 能力',
|
|
51
|
+
};
|
|
52
|
+
case 'cursor':
|
|
53
|
+
return {
|
|
54
|
+
runtime, mode: 'cursor-rules',
|
|
55
|
+
// cursor has no MCP-server-config + SessionStart-hook hybrid; its stable injection point is a project
|
|
56
|
+
// rules file. The active path renders quiet top-gene hints into .cursor/rules/evolver.mdc
|
|
57
|
+
// (alwaysApply:true) and a daemon rewrites it on gene-set change. This is gene-memory
|
|
58
|
+
// injection (NOT MCP tool discovery), so it carries no MCP server config here.
|
|
59
|
+
config: {},
|
|
60
|
+
note: 'cursor: 渲染静默 top-gene hints 进 .cursor/rules/evolver.mdc (alwaysApply:true); daemon 在 gene 集变化时重写',
|
|
61
|
+
};
|
|
62
|
+
case 'kiro':
|
|
63
|
+
case 'opencode':
|
|
64
|
+
return {
|
|
65
|
+
runtime, mode: 'passive',
|
|
66
|
+
config: {},
|
|
67
|
+
note: `${runtime}: MVP 仅被动消费会话日志(无工具注入); 接入方式待补`,
|
|
68
|
+
};
|
|
69
|
+
default: {
|
|
70
|
+
const _exhaustive = runtime;
|
|
71
|
+
throw new Error(`未知 runtime: ${String(_exhaustive)}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** 哪些 runtime 经 MCP server 注入工具发现(CC+codex). cursor 注入的是 gene 记忆(rules 文件)而非 MCP 工具,
|
|
76
|
+
* 故不计入此处;passive runtime 也为 false. */
|
|
77
|
+
export function injectsTools(runtime) {
|
|
78
|
+
const mode = planInjection(runtime, { command: 'x' }).mode;
|
|
79
|
+
return mode === 'mcp-hooks' || mode === 'mcp-plugin';
|
|
80
|
+
}
|
|
81
|
+
/** 是否为 active 注入(任何把 gene 价值推回 runtime 的方式:MCP 工具发现 或 cursor rules 记忆注入). */
|
|
82
|
+
export function isActiveInjection(runtime) {
|
|
83
|
+
return planInjection(runtime, { command: 'x' }).mode !== 'passive';
|
|
84
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { type RuntimeId, type McpServerCmd, type InjectionPlan } from './injection.js';
|
|
2
|
+
import { type CursorGene } from './cursorRulesInstaller.js';
|
|
3
|
+
/** Marks a config file as containing evolver-managed entries, so uninstall only removes what we added. */
|
|
4
|
+
export declare const MANAGED_MARKER = "_evolver_managed";
|
|
5
|
+
/** Default command the SessionStart hook runs to render + print the memory injection. The `--hook-stdin` flag opts
|
|
6
|
+
* the entrypoint into reading the runtime's SessionStart JSON from stdin (to capture session_id, #205); only the
|
|
7
|
+
* installed hook sets it, so a manual `evolver inject session-start` never reads stdin. */
|
|
8
|
+
export declare const DEFAULT_HOOK_COMMAND = "evolver inject session-start --hook-stdin";
|
|
9
|
+
/**
|
|
10
|
+
* Where a claude-code install registers the evolver MCP server. This is the fix for "global install doesn't
|
|
11
|
+
* actually globalize" (#290): Claude Code's MCP scopes are local / user / project, and a `.mcp.json` is the
|
|
12
|
+
* PROJECT-scoped file — it only loads when that directory is the launch cwd. So writing `~/.mcp.json` does NOT
|
|
13
|
+
* make evolver available from other projects. The real user (device-wide) scope is the top-level `mcpServers`
|
|
14
|
+
* in `~/.claude.json`.
|
|
15
|
+
* - 'project' (default): register in <configRoot>/.mcp.json (cwd-scoped) — unchanged legacy behavior.
|
|
16
|
+
* - 'user': register in ~/.claude.json's top-level mcpServers so EVERY project's sessions discover evolver.
|
|
17
|
+
* The SessionStart hook always lands in the matching .claude/settings.json (project: <configRoot>/.claude;
|
|
18
|
+
* user: ~/.claude — which is already user-level). codex/cursor ignore this (codex's ~/.codex/config.toml is a
|
|
19
|
+
* genuine global config, so its global path stays configRoot-driven).
|
|
20
|
+
*/
|
|
21
|
+
export type InstallScope = 'user' | 'project';
|
|
22
|
+
export interface InstallOptions {
|
|
23
|
+
/** Runtime config root — the CC adapter writes <configRoot>/.mcp.json and <configRoot>/.claude/settings.json
|
|
24
|
+
* for PROJECT scope. For USER scope the MCP registration goes to ~/.claude.json instead (see `scope`). */
|
|
25
|
+
configRoot: string;
|
|
26
|
+
/** claude-code only: 'project' (default) writes <configRoot>/.mcp.json; 'user' registers the MCP in
|
|
27
|
+
* ~/.claude.json so it loads in every project (Claude Code's real user scope). Ignored by codex/cursor. */
|
|
28
|
+
scope?: InstallScope;
|
|
29
|
+
/** The MCP server launch command registered in .mcp.json (how the runtime starts the evolver MCP server). */
|
|
30
|
+
server: McpServerCmd;
|
|
31
|
+
/** Command the SessionStart hook runs to inject memory. Default 'evolver inject session-start'. */
|
|
32
|
+
hookCommand?: string;
|
|
33
|
+
/** Reinstall even if an evolver install is already present. */
|
|
34
|
+
force?: boolean;
|
|
35
|
+
/** Cursor only: the top genes to render into .cursor/rules/evolver.mdc. The daemon refreshes these on change;
|
|
36
|
+
* a one-shot `setup-hooks --runtime=cursor` install seeds the file (empty ⇒ a placeholder the daemon fills). */
|
|
37
|
+
genes?: readonly CursorGene[];
|
|
38
|
+
/** Cursor only: cap on genes rendered into the always-on rules body (token-tax bound). */
|
|
39
|
+
maxGenes?: number;
|
|
40
|
+
}
|
|
41
|
+
export interface InstallResult {
|
|
42
|
+
ok: boolean;
|
|
43
|
+
runtime: RuntimeId;
|
|
44
|
+
mode: string;
|
|
45
|
+
/** Absolute paths written (install) or cleaned (uninstall). */
|
|
46
|
+
files: string[];
|
|
47
|
+
alreadyInstalled?: boolean;
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
50
|
+
export declare class SymlinkRefusedError extends Error {
|
|
51
|
+
constructor(label: string, path: string);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Thrown when a SHARED user config (~/.claude.json or ~/.claude/settings.json) exists but does not parse as JSON.
|
|
55
|
+
* These files are Claude Code's own state (projects/oauthAccount/userID/history/settings),
|
|
56
|
+
* and user-scope install merges into them via a full-file atomic replace. The lenient readJson() returns {} on
|
|
57
|
+
* a parse failure, which would make the merge emit ONLY evolver's entry and silently WIPE the whole file — a
|
|
58
|
+
* realistic data-loss path because Claude Code writes these files non-atomically (a concurrent session can leave
|
|
59
|
+
* one truncated). For the shared-config read we therefore refuse instead of clobbering. Project-scoped
|
|
60
|
+
* .mcp.json/.claude/settings.json are evolver-owned, so their lenient fresh-start behavior stays unchanged.
|
|
61
|
+
*/
|
|
62
|
+
export declare class UnparseableConfigError extends Error {
|
|
63
|
+
constructor(label: string, path: string);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Thrown when a SHARED user config exists but is empty or whitespace-only. Claude Code writes these files with a
|
|
67
|
+
* truncating write, so present-empty can be a concurrent-write window rather than a fresh config.
|
|
68
|
+
*/
|
|
69
|
+
export declare class EmptySharedConfigError extends Error {
|
|
70
|
+
constructor(label: string, path: string);
|
|
71
|
+
}
|
|
72
|
+
type SharedConfigRaceHook = (path: string, attempt: number) => void;
|
|
73
|
+
export declare function _setSharedConfigRaceHookForTest(hook?: SharedConfigRaceHook): void;
|
|
74
|
+
export declare function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
|
|
75
|
+
/**
|
|
76
|
+
* deepMerge, but for `hooks.<event>` arrays keep the user's existing entries and only replace evolver-owned
|
|
77
|
+
* ones — so reinstalling refreshes evolver's hook without clobbering a user's own SessionStart/Stop hooks.
|
|
78
|
+
*/
|
|
79
|
+
export declare function mergeHooksUnion(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
|
|
80
|
+
/** Strip evolver-owned hook entries + the marker from a parsed config (uninstall). Returns [changed, data]. */
|
|
81
|
+
export declare function stripManaged(data: Record<string, unknown>): {
|
|
82
|
+
changed: boolean;
|
|
83
|
+
data: Record<string, unknown>;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Execute an InjectionPlan against a runtime config root. Active runtimes:
|
|
87
|
+
* - claude-code (mcp-hooks): scope 'project' (default) writes/merges <root>/.mcp.json + <root>/.claude/settings.json;
|
|
88
|
+
* scope 'user' registers the MCP in ~/.claude.json (real user scope) + the SessionStart hook in ~/.claude/settings.json.
|
|
89
|
+
* - codex (mcp-plugin): writes/merges <root>/.codex/config.toml — [mcp_servers.evolver] + [[hooks.SessionStart]]
|
|
90
|
+
* (delegated to codexInstaller; TOML, not JSON). Same hybrid value (tool discovery + session-start injection).
|
|
91
|
+
* - cursor (cursor-rules): renders top genes into <root>/.cursor/rules/evolver.mdc (alwaysApply:true) — gene
|
|
92
|
+
* memory injection, not MCP tool discovery (delegated to cursorRulesInstaller). The daemon keeps it fresh.
|
|
93
|
+
* Idempotent + symlink-safe; passive runtimes (kiro/opencode) return ok:false (nothing to inject).
|
|
94
|
+
*/
|
|
95
|
+
export declare function installInjection(plan: InjectionPlan, opts: InstallOptions): InstallResult;
|
|
96
|
+
/** Remove evolver's MCP registration + SessionStart hook from a CC config root (leaves user content intact).
|
|
97
|
+
* Pass the SAME scope used at install: 'user' cleans ~/.claude.json + ~/.claude/settings.json; 'project'
|
|
98
|
+
* (default) cleans <configRoot>/.mcp.json + <configRoot>/.claude/settings.json. stripManaged only removes
|
|
99
|
+
* the mcpServers.evolver entry (and any evolver-owned hooks/marker), so it is safe on the shared ~/.claude.json. */
|
|
100
|
+
export declare function uninstallInjection(runtime: RuntimeId, opts: {
|
|
101
|
+
configRoot: string;
|
|
102
|
+
scope?: InstallScope;
|
|
103
|
+
}): InstallResult;
|
|
104
|
+
/** Convenience: plan + install in one call for a runtime. */
|
|
105
|
+
export declare function setupRuntime(runtime: RuntimeId, opts: InstallOptions): InstallResult;
|
|
106
|
+
export {};
|