metaharness 0.4.17 → 0.4.19
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/assets/generated-mcp.mjs +69 -0
- package/dist/bin.js +0 -0
- package/dist/generated-runtime.d.ts +4 -0
- package/dist/generated-runtime.d.ts.map +1 -0
- package/dist/generated-runtime.js +75 -0
- package/dist/generated-runtime.js.map +1 -0
- package/dist/harness-bin.js +0 -0
- package/dist/host-config.d.ts.map +1 -1
- package/dist/host-config.js +6 -5
- package/dist/host-config.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +168 -13
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +5 -0
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js.map +1 -1
- package/dist/plugin-init-cmd.d.ts.map +1 -1
- package/dist/plugin-init-cmd.js +1 -0
- package/dist/plugin-init-cmd.js.map +1 -1
- package/dist/subcommands.d.ts.map +1 -1
- package/dist/subcommands.js +8 -4
- package/dist/subcommands.js.map +1 -1
- package/dist/upgrade-cmd.d.ts.map +1 -1
- package/dist/upgrade-cmd.js +28 -18
- package/dist/upgrade-cmd.js.map +1 -1
- package/dist/upgrade.d.ts +2 -0
- package/dist/upgrade.d.ts.map +1 -1
- package/dist/upgrade.js +85 -10
- package/dist/upgrade.js.map +1 -1
- package/package.json +6 -5
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Read-only scaffold metadata over MCP stdio. No arbitrary paths, shell or network.
|
|
3
|
+
import { readFileSync, realpathSync } from 'node:fs';
|
|
4
|
+
const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
5
|
+
const protocols = ['2025-11-25', '2025-06-18', '2025-03-26', '2024-11-05'];
|
|
6
|
+
const tool = { name: 'harness_info', description: 'Read this generated harness name, version and description.',
|
|
7
|
+
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
|
|
8
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false } };
|
|
9
|
+
|
|
10
|
+
export function startMcp() {
|
|
11
|
+
let buffer = '';
|
|
12
|
+
let initialized = false;
|
|
13
|
+
const send = message => process.stdout.write(JSON.stringify(message) + '\n');
|
|
14
|
+
const error = (id, code, message) => send({jsonrpc: '2.0', id, error: {code, message}});
|
|
15
|
+
function handle(line) {
|
|
16
|
+
let request;
|
|
17
|
+
try { request = JSON.parse(line); } catch { error(null, -32700, 'Parse error'); return; }
|
|
18
|
+
if (!request || Array.isArray(request) || request.jsonrpc !== '2.0' || typeof request.method !== 'string' ||
|
|
19
|
+
('id' in request && typeof request.id !== 'string' && typeof request.id !== 'number')) {
|
|
20
|
+
error(null, -32600, 'Invalid request'); return;
|
|
21
|
+
}
|
|
22
|
+
// Notifications have no response, including notifications/initialized.
|
|
23
|
+
if (!('id' in request)) return;
|
|
24
|
+
const {id, method, params} = request;
|
|
25
|
+
let result;
|
|
26
|
+
if (method === 'initialize') {
|
|
27
|
+
if (!params || typeof params.protocolVersion !== 'string' || !params.clientInfo || !params.capabilities) {
|
|
28
|
+
error(id, -32602, 'Invalid initialize parameters'); return;
|
|
29
|
+
}
|
|
30
|
+
initialized = true;
|
|
31
|
+
result = {protocolVersion: protocols.includes(params.protocolVersion) ? params.protocolVersion : protocols[0],
|
|
32
|
+
capabilities: {tools: {}}, serverInfo: {name: pkg.name, version: pkg.version}};
|
|
33
|
+
} else if (method === 'ping') result = {};
|
|
34
|
+
else if (!initialized) { error(id, -32000, 'Initialize first'); return; }
|
|
35
|
+
else if (method === 'tools/list') result = {tools: [tool]};
|
|
36
|
+
else if (method === 'tools/call') {
|
|
37
|
+
const args = params?.arguments === undefined ? {} : params.arguments;
|
|
38
|
+
if (params?.name !== tool.name || !args || typeof args !== 'object' || Array.isArray(args) || Object.keys(args).length) {
|
|
39
|
+
error(id, -32602, 'Only harness_info with empty arguments is supported'); return;
|
|
40
|
+
}
|
|
41
|
+
result = {content: [{type: 'text', text: JSON.stringify({name: pkg.name, version: pkg.version, description: pkg.description})}], isError: false};
|
|
42
|
+
} else { error(id, -32601, 'Method not found'); return; }
|
|
43
|
+
send({jsonrpc: '2.0', id, result});
|
|
44
|
+
}
|
|
45
|
+
process.stdin.setEncoding('utf8');
|
|
46
|
+
process.stdin.on('data', chunk => {
|
|
47
|
+
buffer += chunk;
|
|
48
|
+
// Bound both incomplete and complete messages before JSON parsing.
|
|
49
|
+
while (buffer.includes('\n')) {
|
|
50
|
+
const index = buffer.indexOf('\n');
|
|
51
|
+
if (Buffer.byteLength(buffer.slice(0, index), 'utf8') > 65536) { process.stderr.write('MCP message exceeds 64 KiB\n'); process.exitCode = 1; process.stdin.destroy(); return; }
|
|
52
|
+
const line = buffer.slice(0, index); buffer = buffer.slice(index + 1);
|
|
53
|
+
if (line.trim()) handle(line);
|
|
54
|
+
}
|
|
55
|
+
if (Buffer.byteLength(buffer, 'utf8') > 65536) { process.stderr.write('MCP message exceeds 64 KiB\n'); process.exitCode = 1; process.stdin.destroy(); }
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Also launch directly from host configuration; importing from the CLI is inert.
|
|
60
|
+
import { fileURLToPath } from 'node:url';
|
|
61
|
+
const invokedDirectly = (() => {
|
|
62
|
+
if (!process.argv[1]) return false;
|
|
63
|
+
try {
|
|
64
|
+
// Node resolves module symlinks; argv may retain /var rather than
|
|
65
|
+
// /private/var on macOS, or an explicitly symlinked harness directory.
|
|
66
|
+
return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
|
|
67
|
+
} catch { return false; }
|
|
68
|
+
})();
|
|
69
|
+
if (invokedDirectly) startMcp();
|
package/dist/bin.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { RenderedFile } from './walker.js';
|
|
2
|
+
/** Shared creation/upgrade overlay. Preserve project files; also emit plugin-root files. */
|
|
3
|
+
export declare function integrateGeneratedRuntime(files: RenderedFile[], name: string, claude: boolean): void;
|
|
4
|
+
//# sourceMappingURL=generated-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generated-runtime.d.ts","sourceRoot":"","sources":["../src/generated-runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,4FAA4F;AAC5F,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAkEpG"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
/** Shared creation/upgrade overlay. Preserve project files; also emit plugin-root files. */
|
|
4
|
+
export function integrateGeneratedRuntime(files, name, claude) {
|
|
5
|
+
const put = (path, content) => {
|
|
6
|
+
const old = files.find(f => f.path === path);
|
|
7
|
+
if (old)
|
|
8
|
+
old.content = content;
|
|
9
|
+
else
|
|
10
|
+
files.push({ path, content, rendered: false, unresolved: [] });
|
|
11
|
+
};
|
|
12
|
+
const pkgFile = files.find(f => f.path === 'package.json');
|
|
13
|
+
const pkg = JSON.parse(pkgFile.content);
|
|
14
|
+
// All scaffolds get an executable metadata server, never an npm-name placeholder.
|
|
15
|
+
put('bin/mcp.js', readFileSync(new URL('../assets/generated-mcp.mjs', import.meta.url), 'utf8'));
|
|
16
|
+
const cli = files.find(f => f.path === 'bin/cli.js');
|
|
17
|
+
if (!cli || !cli.content.includes('switch (cmd) {')) {
|
|
18
|
+
throw new Error('Generated CLI is missing its command dispatcher');
|
|
19
|
+
}
|
|
20
|
+
cli.content = cli.content.replace("switch (cmd) {", `switch (cmd) {
|
|
21
|
+
case 'mcp': {
|
|
22
|
+
if (!['start', 'index'].includes(argv[1]) || argv.length !== 2) {
|
|
23
|
+
console.error('Usage: ${name} mcp start'); return 2;
|
|
24
|
+
}
|
|
25
|
+
const { startMcp } = await import('./mcp.js'); startMcp(); return undefined;
|
|
26
|
+
}`)
|
|
27
|
+
// An active stdio server must retain stdin; process.exit would close it immediately.
|
|
28
|
+
.replace('.then((code) => process.exit(code))', '.then((code) => { if (code !== undefined) process.exitCode = code; })')
|
|
29
|
+
.replace(' init boot', ' mcp start serve read-only harness metadata over stdio\\n init boot');
|
|
30
|
+
if (claude) {
|
|
31
|
+
const pluginFile = files.find(f => f.path === '.claude-plugin/plugin.json');
|
|
32
|
+
const plugin = JSON.parse(pluginFile.content);
|
|
33
|
+
plugin.author = { ...plugin.author, name: plugin.author?.name ?? plugin.author?.displayName ?? 'Generated by metaharness' };
|
|
34
|
+
plugin.mcpServers = { [name]: { command: 'node', args: ['${CLAUDE_PLUGIN_ROOT}/bin/mcp.js'] } };
|
|
35
|
+
put('.claude-plugin/plugin.json', JSON.stringify(plugin, null, 2) + '\n');
|
|
36
|
+
// Plugin discovery uses these root directories; .claude/* remains project context.
|
|
37
|
+
for (const file of [...files]) {
|
|
38
|
+
if (/^\.claude\/(commands|skills)\//.test(file.path))
|
|
39
|
+
put(file.path.slice('.claude/'.length), file.content);
|
|
40
|
+
const match = /^src\/agents\/([a-z0-9-]+)\.ts$/.exec(file.path);
|
|
41
|
+
const prompt = /export const SYSTEM_PROMPT = `([\s\S]*?)`/.exec(file.content)?.[1];
|
|
42
|
+
if (match && prompt)
|
|
43
|
+
put(`agents/${match[1]}.md`, `---\nname: ${match[1]}\ndescription: ${JSON.stringify(`Project ${match[1]} for ${name}`)}\n---\n\n${prompt}\n`);
|
|
44
|
+
}
|
|
45
|
+
// Resolve relative commands from the project working directory for project mode.
|
|
46
|
+
const settingsFile = files.find(f => f.path === '.claude/settings.json');
|
|
47
|
+
if (settingsFile) {
|
|
48
|
+
const settings = JSON.parse(settingsFile.content);
|
|
49
|
+
const removedAliases = [];
|
|
50
|
+
for (const [key, server] of Object.entries(settings.mcpServers ?? {})) {
|
|
51
|
+
const entry = server;
|
|
52
|
+
if (entry.command === 'npx' && entry.args?.includes(`${name}@latest`)) {
|
|
53
|
+
if (key === name)
|
|
54
|
+
settings.mcpServers[key] = { command: 'node', args: ['./bin/mcp.js'] };
|
|
55
|
+
else {
|
|
56
|
+
// Templates named nonexistent indexing/alerting services. Do not
|
|
57
|
+
// register the metadata server under names suggesting those tools.
|
|
58
|
+
delete settings.mcpServers[key];
|
|
59
|
+
removedAliases.push(key);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (Array.isArray(settings.permissions?.allow)) {
|
|
64
|
+
settings.permissions.allow = settings.permissions.allow.filter((rule) => !removedAliases.some(alias => rule.startsWith(`mcp__${alias}__`)));
|
|
65
|
+
}
|
|
66
|
+
put('.claude/settings.json', JSON.stringify(settings, null, 2) + '\n');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Package only generated metadata, never mutable claims, sessions or key material.
|
|
70
|
+
pkg.files = [...new Set([...(pkg.files ?? []), 'bin/**', '.claude-plugin/**',
|
|
71
|
+
'commands/**', 'skills/**', 'agents/**', '.harness/manifest.json',
|
|
72
|
+
'.harness/manifest.sha256', '.harness/mcp-policy.json'])];
|
|
73
|
+
pkgFile.content = JSON.stringify(pkg, null, 2) + '\n';
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=generated-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generated-runtime.js","sourceRoot":"","sources":["../src/generated-runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/harness-bin.js
CHANGED
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-config.d.ts","sourceRoot":"","sources":["../src/host-config.ts"],"names":[],"mappings":"AAkCA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,GAAG,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IAChC,4CAA4C;IAC5C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAyDD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"host-config.d.ts","sourceRoot":"","sources":["../src/host-config.ts"],"names":[],"mappings":"AAkCA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,GAAG,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IAChC,4CAA4C;IAC5C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAyDD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,QAAQ,EAAE,CA8J9E"}
|
package/dist/host-config.js
CHANGED
|
@@ -36,7 +36,7 @@ function mcpServerEntry(cfg) {
|
|
|
36
36
|
if (cfg.mcp === 'remote') {
|
|
37
37
|
return { type: 'http', url: 'https://localhost:8787/mcp', headers: { Authorization: 'Bearer ${HARNESS_MCP_TOKEN}' } };
|
|
38
38
|
}
|
|
39
|
-
return { command: '
|
|
39
|
+
return { command: 'node', args: ['./bin/mcp.js'] };
|
|
40
40
|
}
|
|
41
41
|
/** Derive a Claude-Code-style allow/deny posture (mirrors the web UI). */
|
|
42
42
|
function policyLists(cfg) {
|
|
@@ -97,7 +97,7 @@ export function hostConfigFiles(host, cfg) {
|
|
|
97
97
|
? `# ${cfg.name} — MCP disabled at scaffold time.\n`
|
|
98
98
|
: cfg.mcp === 'remote'
|
|
99
99
|
? `[mcp_servers.${cfg.name}]\ntype = "http"\nurl = "https://localhost:8787/mcp"\n`
|
|
100
|
-
: `[mcp_servers.${cfg.name}]\ncommand = "
|
|
100
|
+
: `[mcp_servers.${cfg.name}]\ncommand = "node"\nargs = ["./bin/mcp.js"]\n`;
|
|
101
101
|
return [
|
|
102
102
|
{ path: '.codex/config.toml', content: toml },
|
|
103
103
|
{ path: 'AGENTS.md', content: `# ${cfg.name}\n\n${cfg.description}\n\n## Behavioral rules\n\n- Use the harness's MCP tools (\`mcp__${cfg.name}__*\`) for orchestration.\n- Defer destructive operations to the user.\n` },
|
|
@@ -114,17 +114,18 @@ export function hostConfigFiles(host, cfg) {
|
|
|
114
114
|
// `model:` + `agent.personalities` schema; no name/description/scrub keys.
|
|
115
115
|
const persona = (cfg.description || `You are ${cfg.name}.`).replace(/[\r\n]+/g, ' ');
|
|
116
116
|
const files = [
|
|
117
|
-
{ path: 'cli-config.yaml', content: `# Hermes Agent config for ${cfg.name} — subset of cli-config.yaml.example.\nmodel:\n provider: "auto"\nagent:\n personalities:\n ${yamlKey(cfg.name)}: ${JSON.stringify(persona)}\n` },
|
|
117
|
+
{ path: 'cli-config.yaml', content: `# Hermes Agent config for ${cfg.name} — subset of cli-config.yaml.example.\nmodel:\n provider: "auto"\nagent:\n personalities:\n ${yamlKey(cfg.name)}: ${JSON.stringify(persona)}\n${server ? `mcp_servers:\n ${yamlKey(cfg.name)}: ${JSON.stringify(server)}\n` : ''}` },
|
|
118
118
|
];
|
|
119
119
|
if (server)
|
|
120
120
|
files.push({ path: `optional-mcps/${cfg.name}.json`, content: JSON.stringify({ [cfg.name]: server }, null, 2) + '\n' });
|
|
121
|
+
files.push({ path: 'install-hermes.md', content: `# Installing ${cfg.name} into Hermes\n\nHermes reads \`$HERMES_HOME/config.yaml\` (normally \`~/.hermes/config.yaml\`), not this folder automatically. Copy \`cli-config.yaml\` into a new isolated profile as \`config.yaml\`, or review and merge its personality and \`mcp_servers\` entries into your existing configuration. Preserve existing configuration and credentials. Start Hermes from this harness directory so relative stdio paths resolve; use an absolute server path when launching elsewhere. The optional-mcps export alone does not enable the server.\n` });
|
|
121
122
|
return files;
|
|
122
123
|
}
|
|
123
124
|
case 'openclaw': {
|
|
124
125
|
// ADR-046 — verified against real openclaw 2026.6.8: MCP nests under
|
|
125
126
|
// `mcp.servers` with an `enabled` flag (NOT top-level `mcp_servers`);
|
|
126
127
|
// no top-level allow/deny permissions concept.
|
|
127
|
-
const servers = server ? { [cfg.name]: { enabled: true,
|
|
128
|
+
const servers = server ? { [cfg.name]: { enabled: true, ...server } } : {};
|
|
128
129
|
return [{ path: '.openclaw/openclaw.json', content: JSON.stringify({ mcp: { servers } }, null, 2) + '\n' }];
|
|
129
130
|
}
|
|
130
131
|
case 'rvm': {
|
|
@@ -153,7 +154,7 @@ export function hostConfigFiles(host, cfg) {
|
|
|
153
154
|
return [
|
|
154
155
|
{ path: '.opencode/opencode.json', content: JSON.stringify({
|
|
155
156
|
$schema: 'https://opencode.ai/schema/opencode.json',
|
|
156
|
-
mcp: server ? { [cfg.name]: { type: 'local', command: ['
|
|
157
|
+
mcp: server ? { [cfg.name]: { type: 'local', command: ['node', './bin/mcp.js'], enabled: true } } : {},
|
|
157
158
|
permission: { edit: cfg.allowFileWrite ? 'allow' : 'ask', bash: { '*': cfg.allowShell ? 'allow' : 'ask', 'rm *': 'deny', 'git push *': 'deny' }, webfetch: 'ask' },
|
|
158
159
|
}, null, 2) + '\n' },
|
|
159
160
|
{ path: 'install.md', content: `# Installing ${cfg.name} into OpenCode\n\n1. \`opencode auth login\` to set a model provider.\n2. \`cd\` here and run \`opencode\` — the TUI reads \`.opencode/opencode.json\`.\n3. Inside the TUI run \`/mcp\` to verify \`${cfg.name}\` is registered.\n` },
|
package/dist/host-config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-config.js","sourceRoot":"","sources":["../src/host-config.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,+DAA+D;AAC/D,EAAE;AACF,yEAAyE;AACzE,kEAAkE;AAClE,6EAA6E;AAC7E,+EAA+E;AAC/E,0EAA0E;AAC1E,uEAAuE;AACvE,8DAA8D;AAC9D,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,6CAA6C;AAE7C,0EAA0E;AAC1E,2EAA2E;AAC3E,+BAA+B;AAC/B,MAAM,kBAAkB,GAAG,2DAA2D,CAAC;AAEvF;;;;;;;GAOG;AACH,SAAS,OAAO,CAAC,CAAS;IACxB,MAAM,gBAAgB,GAAG,+BAA+B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjE,OAAO,gBAAgB,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;AAC1G,CAAC;AAiBD,sEAAsE;AACtE,SAAS,cAAc,CAAC,GAAoB;IAC1C,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,GAAG,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QACzB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,4BAA4B,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,6BAA6B,EAAE,EAAE,CAAC;IACxH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"host-config.js","sourceRoot":"","sources":["../src/host-config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export declare const HOSTS: readonly ["claude-code", "codex", "pi-dev", "hermes", "openclaw", "rvm", "copilot", "opencode", "github-actions", "prime-agent"];
|
|
2
2
|
export type Host = (typeof HOSTS)[number];
|
|
3
|
+
export declare const METAHARNESS_VERBS: readonly ["analyze", "genome", "score", "weight-eft", "learn", "redblue", "flywheel", "turn-credit", "avo", "proxy"];
|
|
4
|
+
export declare const RESERVED_LOOKS_LIKE_A_COMMAND: Set<string>;
|
|
3
5
|
export declare const TEMPLATES: readonly ["minimal", "vertical:devops", "vertical:support", "vertical:trading", "vertical:legal", "vertical:research", "vertical:coding", "vertical:business", "vertical:crm", "vertical:marketing", "vertical:advertising", "vertical:ai", "vertical:agentics", "vertical:ruview", "vertical:health", "vertical:education", "vertical:sales", "vertical:gaming", "vertical:repo-maintainer", "vertical:exotic"];
|
|
4
6
|
export type TemplateId = (typeof TEMPLATES)[number];
|
|
5
7
|
export interface CatalogEntry {
|
|
@@ -85,6 +87,16 @@ export interface ScaffoldResult {
|
|
|
85
87
|
manifestPath: string;
|
|
86
88
|
unresolved: string[];
|
|
87
89
|
}
|
|
90
|
+
/** Render the same host and security overlays for creation and upgrade. */
|
|
91
|
+
export declare function renderScaffold(opts: ScaffoldOptions): Promise<{
|
|
92
|
+
rendered: import("./walker.js").RenderedFile[];
|
|
93
|
+
vars: {
|
|
94
|
+
name: string;
|
|
95
|
+
description: string;
|
|
96
|
+
host: "claude-code" | "codex" | "pi-dev" | "hermes" | "openclaw" | "rvm" | "copilot" | "opencode" | "github-actions" | "prime-agent";
|
|
97
|
+
};
|
|
98
|
+
hostSet: ("claude-code" | "codex" | "pi-dev" | "hermes" | "openclaw" | "rvm" | "copilot" | "opencode" | "github-actions" | "prime-agent")[];
|
|
99
|
+
}>;
|
|
88
100
|
export declare function scaffold(opts: ScaffoldOptions): Promise<ScaffoldResult>;
|
|
89
101
|
/** Try to detect an existing ruflo project at the given path. */
|
|
90
102
|
export declare function detectRufloProject(dir: string): {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { writeAtomic } from './writer.js';
|
|
|
7
7
|
import { emptyManifest, fingerprintFiles, sha256 } from './manifest.js';
|
|
8
8
|
import { validateHarnessName } from './renderer.js';
|
|
9
9
|
import { hostConfigFiles } from './host-config.js';
|
|
10
|
+
import { integrateGeneratedRuntime } from './generated-runtime.js';
|
|
10
11
|
import { FIELD_MEMORY_MODULE_PATH, fieldMemoryManifest, integrateFieldMemory, } from './field-memory-scaffold.js';
|
|
11
12
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
13
|
// Templates live at packages/create-agent-harness/templates/, one level above dist/.
|
|
@@ -61,6 +62,34 @@ const KERNEL_VERSION = resolveKernelVersion();
|
|
|
61
62
|
// prime-agent added per ADR-247 (skills-based, no MCP).
|
|
62
63
|
// HOSTS is the canonical 10-host catalog.
|
|
63
64
|
export const HOSTS = ['claude-code', 'codex', 'pi-dev', 'hermes', 'openclaw', 'rvm', 'copilot', 'opencode', 'github-actions', 'prime-agent'];
|
|
65
|
+
// Dream Cycle 2026-10-20 (generator-genome) — the real `metaharness`-level
|
|
66
|
+
// subcommand nouns, single-sourced so the "did you mean" guard below and the
|
|
67
|
+
// usage text can't drift independently of `runMetaHarnessSubcommand`'s switch
|
|
68
|
+
// (2026-08-27's gist found the usage text already missing 4 of these).
|
|
69
|
+
export const METAHARNESS_VERBS = [
|
|
70
|
+
'analyze', 'genome', 'score', 'weight-eft', 'learn', 'redblue', 'flywheel', 'turn-credit', 'avo', 'proxy',
|
|
71
|
+
];
|
|
72
|
+
// Words a CLI user reasonably expects to be a diagnostic/info subcommand,
|
|
73
|
+
// not a project name — reproduced live 2026-10-20: each one silently
|
|
74
|
+
// scaffolded a harness directory of that name and exited 0 instead of
|
|
75
|
+
// erroring, because `runMetaHarnessSubcommand` returns null for anything it
|
|
76
|
+
// doesn't recognize and `main()` falls through to the legacy bare-name
|
|
77
|
+
// scaffold path with no reserved-word check. Deferred from 2026-08-27's
|
|
78
|
+
// Dream Cycle ("doctor"/"diag" discovery) to this generator-genome slot.
|
|
79
|
+
// Round 2 (same night, independent critic): the first 12 covered the
|
|
80
|
+
// obvious diagnostic-sounding words, but left out 11 of the *generated
|
|
81
|
+
// harness's own* real `harness <verb>` subcommands (subcommands.ts's
|
|
82
|
+
// switch) — a user conflating `metaharness <verb>` with `harness <verb>`
|
|
83
|
+
// hits the identical bug for any of these too; critic live-verified all 11
|
|
84
|
+
// still silently scaffolded on the round-1 build. Folded in below rather
|
|
85
|
+
// than spun into a separate follow-up, since it's the same fix, same file,
|
|
86
|
+
// same guard, zero added risk.
|
|
87
|
+
export const RESERVED_LOOKS_LIKE_A_COMMAND = new Set([
|
|
88
|
+
'doctor', 'diag', 'audit', 'validate', 'compare', 'repo-scorecard',
|
|
89
|
+
'mcp-scan', 'threat-model', 'sbom', 'secrets', 'help', 'version',
|
|
90
|
+
'verify', 'sign', 'federate', 'mcp', 'publish', 'upgrade', 'completions',
|
|
91
|
+
'analyze-repo', 'export-config', 'oia-manifest', 'plugin-init',
|
|
92
|
+
]);
|
|
64
93
|
export const TEMPLATES = [
|
|
65
94
|
'minimal',
|
|
66
95
|
'vertical:devops',
|
|
@@ -227,6 +256,16 @@ Or directly:
|
|
|
227
256
|
npx metaharness-darwin evolve . --sandbox real --generations 3 --children 4
|
|
228
257
|
\`\`\`
|
|
229
258
|
|
|
259
|
+
## Fitness limits
|
|
260
|
+
|
|
261
|
+
The default \`--sandbox real\` command reruns repository tests. Those tests must
|
|
262
|
+
execute the changed policy for their outcomes to measure harness improvement.
|
|
263
|
+
An install smoke test can stay green for every variant and is regression evidence
|
|
264
|
+
only. Mock scores are simulated mechanism checks, not measured agent performance.
|
|
265
|
+
For adoption, use a surface-aware evaluator with frozen baseline/candidate code,
|
|
266
|
+
separate confirmation tasks, and per-task regression checks. A confirmation verdict
|
|
267
|
+
alone never grants deployment or promotion authority.
|
|
268
|
+
|
|
230
269
|
## Safety (secure by default)
|
|
231
270
|
|
|
232
271
|
- **Deterministic mutator** is the default — **no network, no API key, air-gapped**.
|
|
@@ -337,6 +376,11 @@ export class SessionLog {
|
|
|
337
376
|
private nextIndex = new Map<string, number>();
|
|
338
377
|
private branchParent = new Map<string, { branch: string; index: number }>();
|
|
339
378
|
private rootBranch: string;
|
|
379
|
+
// Shared (by reference, like the collections above) across fork()
|
|
380
|
+
// siblings — serializes append()/fork() per LOG, not per instance, so
|
|
381
|
+
// concurrent unawaited calls on this instance or a sibling can never
|
|
382
|
+
// read-check-write on the same stale nextIndex (ADR-246 §2.3 TOCTOU fix).
|
|
383
|
+
private queue: { p: Promise<unknown> } = { p: Promise.resolve() };
|
|
340
384
|
|
|
341
385
|
constructor(readonly path: string, readonly branch: string = 'main') {
|
|
342
386
|
this.rootBranch = branch;
|
|
@@ -406,10 +450,30 @@ export class SessionLog {
|
|
|
406
450
|
return errors;
|
|
407
451
|
}
|
|
408
452
|
|
|
453
|
+
/** Run \`op\` after every previously enqueued operation on this log's shared
|
|
454
|
+
* queue has settled (success or failure), and chain forward the same way —
|
|
455
|
+
* serializes append()/fork() per LOG (not per instance) in call order. */
|
|
456
|
+
private enqueue<T>(op: () => Promise<T>): Promise<T> {
|
|
457
|
+
const result = this.queue.p.then(op, op);
|
|
458
|
+
this.queue.p = result.then(() => undefined, () => undefined);
|
|
459
|
+
return result;
|
|
460
|
+
}
|
|
461
|
+
|
|
409
462
|
/** Append an event on the active branch (next monotonic index). The first
|
|
410
|
-
* event of a forked branch carries the fork's parent ref.
|
|
463
|
+
* event of a forked branch carries the fork's parent ref. Safe to call
|
|
464
|
+
* without awaiting the previous call: concurrent appends on this instance
|
|
465
|
+
* (or a fork() sibling sharing this queue) are serialized via enqueue()
|
|
466
|
+
* and assigned distinct, monotonic indices in call order. */
|
|
411
467
|
async append(kind: string, payload: unknown,
|
|
412
468
|
opts?: { parent?: { branch: string; index: number } }): Promise<SessionEvent> {
|
|
469
|
+
return this.enqueue(() => this.appendLocked(kind, payload, opts));
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/** The unserialized body of append() — only ever runs for one caller at a
|
|
473
|
+
* time per shared queue, via enqueue(). fork() also runs its synthetic
|
|
474
|
+
* first event through this. */
|
|
475
|
+
private async appendLocked(kind: string, payload: unknown,
|
|
476
|
+
opts?: { parent?: { branch: string; index: number } }): Promise<SessionEvent> {
|
|
413
477
|
const index = this.nextIndex.get(this.branch) ?? 0;
|
|
414
478
|
const parent = opts?.parent;
|
|
415
479
|
const isRoot = this.events.length === 0 || this.branch === this.rootBranch;
|
|
@@ -437,16 +501,22 @@ export class SessionLog {
|
|
|
437
501
|
* Immediately appends the new branch's synthetic first event: index 0,
|
|
438
502
|
* parent {branch: this.branch, index: atIndex}, kind 'fork', payload null. */
|
|
439
503
|
async fork(atIndex: number, newBranch: string): Promise<SessionLog> {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
504
|
+
// The "does newBranch already exist" check and the synthetic first event
|
|
505
|
+
// run inside ONE enqueue()'d operation: otherwise two concurrent fork()
|
|
506
|
+
// calls for the same new branch name could both pass the check before
|
|
507
|
+
// either's append() lands (the same TOCTOU shape as append(), one level up).
|
|
508
|
+
return this.enqueue(async () => {
|
|
509
|
+
const count = this.nextIndex.get(this.branch) ?? 0;
|
|
510
|
+
if (atIndex < 0 || atIndex >= count) throw new Error('session: cannot fork at index ' + atIndex);
|
|
511
|
+
if ((this.nextIndex.get(newBranch) ?? 0) > 0 || newBranch === this.branch) {
|
|
512
|
+
throw new Error('session: branch "' + newBranch + '" already exists');
|
|
513
|
+
}
|
|
514
|
+
const log = new SessionLog(this.path, newBranch);
|
|
515
|
+
log.events = this.events; log.nextIndex = this.nextIndex; log.branchParent = this.branchParent;
|
|
516
|
+
log.rootBranch = this.rootBranch; log.queue = this.queue;
|
|
517
|
+
await log.appendLocked('fork', null, { parent: { branch: this.branch, index: atIndex } });
|
|
518
|
+
return log;
|
|
519
|
+
});
|
|
450
520
|
}
|
|
451
521
|
|
|
452
522
|
private lineage(branch: string): SessionEvent[] {
|
|
@@ -489,6 +559,22 @@ export class SessionLog {
|
|
|
489
559
|
* Returns the list of paths written + the manifest path + any unresolved
|
|
490
560
|
* template variables (should be empty for a clean run).
|
|
491
561
|
*/
|
|
562
|
+
/**
|
|
563
|
+
* ADR-022's exact safe-default MCP policy object. Every capability starts at
|
|
564
|
+
* its safe value — the author opts INTO risk, never out of safety.
|
|
565
|
+
*/
|
|
566
|
+
function defaultMcpPolicy() {
|
|
567
|
+
return {
|
|
568
|
+
defaultDeny: true,
|
|
569
|
+
allowNetwork: false,
|
|
570
|
+
allowShell: false,
|
|
571
|
+
allowFileWrite: false,
|
|
572
|
+
requireApprovalForDangerous: true,
|
|
573
|
+
toolTimeoutMs: 30000,
|
|
574
|
+
maxToolCallsPerTurn: 8,
|
|
575
|
+
auditLog: true,
|
|
576
|
+
};
|
|
577
|
+
}
|
|
492
578
|
/** Standard MIT license text for a scaffolded harness (GH #23). */
|
|
493
579
|
function mitLicense(name) {
|
|
494
580
|
const year = new Date().getFullYear();
|
|
@@ -515,7 +601,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
515
601
|
SOFTWARE.
|
|
516
602
|
`;
|
|
517
603
|
}
|
|
518
|
-
|
|
604
|
+
/** Render the same host and security overlays for creation and upgrade. */
|
|
605
|
+
export async function renderScaffold(opts) {
|
|
519
606
|
const nameCheck = validateHarnessName(opts.name);
|
|
520
607
|
if (!nameCheck.valid) {
|
|
521
608
|
throw new Error(`invalid harness name: ${nameCheck.reason}`);
|
|
@@ -598,6 +685,54 @@ export async function scaffold(opts) {
|
|
|
598
685
|
if (!rendered.some(r => r.path === 'LICENSE')) {
|
|
599
686
|
rendered.push({ path: 'LICENSE', content: mitLicense(opts.name), rendered: false, unresolved: [] });
|
|
600
687
|
}
|
|
688
|
+
// Dream Cycle 2026-10-18 (security-adversarial, closes a gap disclosed-but-
|
|
689
|
+
// not-fixed on 2026-09-08, issue #297): ADR-022 is Accepted and specifies
|
|
690
|
+
// that `local`/`remote` MCP mode ships a default-deny `.harness/mcp-policy.json`
|
|
691
|
+
// alongside the MCP registration, and that `off` mode nulls the policy —
|
|
692
|
+
// "off" is a first-class mode (ADR-022 Consequences), so emission must stay
|
|
693
|
+
// keyed to whether this harness actually registers an MCP server, not
|
|
694
|
+
// unconditional. Every one of today's 20 templates' `.claude/settings.json.tmpl`
|
|
695
|
+
// happens to register one (`mcp: 'local'` is effectively hardcoded at the
|
|
696
|
+
// hostConfigFiles call above — there is no `--mcp off` flag yet), so this
|
|
697
|
+
// reads as "always emit" today, but keying it to the real rendered output
|
|
698
|
+
// keeps the invariant correct if/when a no-MCP template or `--mcp off` is
|
|
699
|
+
// added, rather than baking in today's accident as tomorrow's bug.
|
|
700
|
+
{
|
|
701
|
+
const settingsIdx = rendered.findIndex(r => r.path === '.claude/settings.json');
|
|
702
|
+
let mcpRegistered = rendered.some(r => r.path === '.mcp.json');
|
|
703
|
+
if (!mcpRegistered && settingsIdx !== -1) {
|
|
704
|
+
try {
|
|
705
|
+
const settings = JSON.parse(rendered[settingsIdx].content);
|
|
706
|
+
mcpRegistered = !!(settings.mcpServers && Object.keys(settings.mcpServers).length > 0);
|
|
707
|
+
}
|
|
708
|
+
catch { /* unparseable settings.json: treat as not registered, nothing to do */ }
|
|
709
|
+
}
|
|
710
|
+
// Native host formats also register MCP without a Claude settings file.
|
|
711
|
+
mcpRegistered ||= rendered.some(file => {
|
|
712
|
+
if (file.path === '.codex/config.toml')
|
|
713
|
+
return /^\[mcp_servers\./m.test(file.content);
|
|
714
|
+
if (file.path.startsWith('optional-mcps/') && file.path.endsWith('.json'))
|
|
715
|
+
return true;
|
|
716
|
+
if (!['.openclaw/openclaw.json', '.vscode/mcp.json', '.opencode/opencode.json'].includes(file.path))
|
|
717
|
+
return false;
|
|
718
|
+
try {
|
|
719
|
+
const config = JSON.parse(file.content);
|
|
720
|
+
const servers = config.mcp?.servers ?? config.mcpServers ?? config.servers ?? config.mcp;
|
|
721
|
+
return !!servers && Object.keys(servers).length > 0;
|
|
722
|
+
}
|
|
723
|
+
catch {
|
|
724
|
+
return false;
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
if (mcpRegistered && !rendered.some(r => r.path === '.harness/mcp-policy.json')) {
|
|
728
|
+
rendered.push({
|
|
729
|
+
path: '.harness/mcp-policy.json',
|
|
730
|
+
content: JSON.stringify(defaultMcpPolicy(), null, 2) + '\n',
|
|
731
|
+
rendered: false,
|
|
732
|
+
unresolved: [],
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
}
|
|
601
736
|
// ADR-147: deep-integrate Darwin Mode. Default ON (opt out with --no-darwin).
|
|
602
737
|
// Adds the @metaharness/darwin devDependency + `evolve`/`evolve:dry` scripts to
|
|
603
738
|
// the generated package.json, and emits a real `evolve` skill wired to the darwin
|
|
@@ -668,13 +803,20 @@ export async function scaffold(opts) {
|
|
|
668
803
|
// requires an explicit absolute path and authenticated principal evidence,
|
|
669
804
|
// avoiding the implicit database reopen and Sybil-prone caller-id patterns
|
|
670
805
|
// found during the discovery benchmark.
|
|
806
|
+
if (opts.fieldMemory === true) {
|
|
807
|
+
integrateFieldMemory(rendered);
|
|
808
|
+
}
|
|
809
|
+
integrateGeneratedRuntime(rendered, opts.name, hostSet.includes('claude-code'));
|
|
810
|
+
return { rendered, vars, hostSet };
|
|
811
|
+
}
|
|
812
|
+
export async function scaffold(opts) {
|
|
671
813
|
if (opts.fieldMemory === true) {
|
|
672
814
|
const existingModule = join(opts.targetDir, ...FIELD_MEMORY_MODULE_PATH.split('/'));
|
|
673
815
|
if (existsSync(existingModule)) {
|
|
674
816
|
throw new Error(`--field-memory refuses to overwrite existing ${FIELD_MEMORY_MODULE_PATH}`);
|
|
675
817
|
}
|
|
676
|
-
integrateFieldMemory(rendered);
|
|
677
818
|
}
|
|
819
|
+
const { rendered, vars, hostSet } = await renderScaffold(opts);
|
|
678
820
|
const fileMap = asFileMap(rendered);
|
|
679
821
|
// iter 58: stamp kernel_version at scaffold time (ADR-027 diagnostic).
|
|
680
822
|
// surface defaults to 'cli' inside emptyManifest; we override only
|
|
@@ -683,6 +825,7 @@ export async function scaffold(opts) {
|
|
|
683
825
|
meta: KERNEL_VERSION ? { kernel_version: KERNEL_VERSION } : {},
|
|
684
826
|
});
|
|
685
827
|
manifest.vars = vars;
|
|
828
|
+
manifest.features = { darwin: opts.darwin !== false, sessions: opts.sessions === true };
|
|
686
829
|
manifest.hosts = hostSet; // GH #10: full host set, not just the primary
|
|
687
830
|
if (opts.fieldMemory === true) {
|
|
688
831
|
manifest.field_memory = fieldMemoryManifest();
|
|
@@ -916,6 +1059,14 @@ export async function main(argv) {
|
|
|
916
1059
|
}
|
|
917
1060
|
}
|
|
918
1061
|
const args = parseArgs(argv);
|
|
1062
|
+
// See RESERVED_LOOKS_LIKE_A_COMMAND above. `--force` still lets someone
|
|
1063
|
+
// scaffold a project literally named e.g. "doctor" on purpose.
|
|
1064
|
+
if (first !== 'new' && args.name && !args.force && RESERVED_LOOKS_LIKE_A_COMMAND.has(args.name)) {
|
|
1065
|
+
console.error(`"${args.name}" looks like a command, not a project name — it is not a recognized metaharness subcommand.`);
|
|
1066
|
+
console.error(`Known subcommands: ${METAHARNESS_VERBS.join(', ')}`);
|
|
1067
|
+
console.error(`To scaffold a project literally named "${args.name}" anyway, re-run with --force.`);
|
|
1068
|
+
return 2;
|
|
1069
|
+
}
|
|
919
1070
|
if (args.list) {
|
|
920
1071
|
for (const line of formatCatalog(loadCatalog()))
|
|
921
1072
|
console.log(line);
|
|
@@ -978,6 +1129,10 @@ export async function main(argv) {
|
|
|
978
1129
|
console.log(' npx metaharness analyze <repo> (recommend a harness plan, no-exec)');
|
|
979
1130
|
console.log(' npx metaharness genome <repo> (7-section repo readiness)');
|
|
980
1131
|
console.log(' npx metaharness learn --host <h> --model <m> --slice <manifest> (ADR-228 GEPA learning run — $0 dry-run by default, --run to spend; needs a repo checkout)');
|
|
1132
|
+
console.log(' npx metaharness weight-eft <export|train|eval|status> (ADR-198 evolutionary fine-tuning; $0 export/dry-run, GPU-gated --train)');
|
|
1133
|
+
console.log(' npx metaharness redblue <init|run|attack|patch|retest|report> (adversarial red/blue eval of an agent/workflow you own; $0 with --mock-judge)');
|
|
1134
|
+
console.log(' npx metaharness flywheel <run|replay|graph> (promotion loop: run/measure/mutate/verify/promote; replay/graph are read-only)');
|
|
1135
|
+
console.log(' npx metaharness turn-credit <process|report> (ADR-248 offline recursive turn-level credit from recorded trajectories)');
|
|
981
1136
|
console.log(' npx metaharness avo <trusted-key|gate-build|gate-submit> (ADR-271 flywheel-gate receipts from an AVO run summary)');
|
|
982
1137
|
console.log(' npx metaharness proxy <install|status|start|stop|enable|disable|path|login|logout> (optional signed Cognitum Meta-Proxy sidecar)');
|
|
983
1138
|
console.log(' npx metaharness --from-existing [./path]');
|