@cardor/agent-harness-kit 0.3.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +1 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/task/add.d.ts.map +1 -1
- package/dist/commands/task/add.js +1 -7
- package/dist/commands/task/add.js.map +1 -1
- package/dist/core/materializer/agent-templates/builder.md +110 -0
- package/dist/core/materializer/agent-templates/explorer.md +111 -0
- package/dist/core/materializer/agent-templates/lead.md +119 -0
- package/dist/core/materializer/agent-templates/reviewer.md +120 -0
- package/dist/core/materializer/agent-templates/test123.txt +0 -0
- package/dist/core/materializer/claude-code.d.ts.map +1 -1
- package/dist/core/materializer/claude-code.js +18 -35
- package/dist/core/materializer/claude-code.js.map +1 -1
- package/dist/core/materializer/mcp-merge.d.ts +3 -0
- package/dist/core/materializer/mcp-merge.d.ts.map +1 -0
- package/dist/core/materializer/mcp-merge.js +55 -0
- package/dist/core/materializer/mcp-merge.js.map +1 -0
- package/dist/core/materializer/opencode.d.ts.map +1 -1
- package/dist/core/materializer/opencode.js +18 -35
- package/dist/core/materializer/opencode.js.map +1 -1
- package/dist/core/materializer/scaffold-utils.d.ts +4 -0
- package/dist/core/materializer/scaffold-utils.d.ts.map +1 -0
- package/dist/core/materializer/scaffold-utils.js +28 -0
- package/dist/core/materializer/scaffold-utils.js.map +1 -0
- package/dist/core/materializer/templates.d.ts +14 -6
- package/dist/core/materializer/templates.d.ts.map +1 -1
- package/dist/core/materializer/templates.js +27 -160
- package/dist/core/materializer/templates.js.map +1 -1
- package/dist/tests/slugify.test.js +1 -8
- package/dist/tests/slugify.test.js.map +1 -1
- package/dist/tests/templates.test.js +2 -1
- package/dist/tests/templates.test.js.map +1 -1
- package/package.json +3 -2
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { existsSync, mkdirSync,
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { join, resolve } from 'node:path';
|
|
3
|
-
import { HEALTH_SH,
|
|
3
|
+
import { HEALTH_SH, agentsMd, featureListJson, agentLead, agentExplorer, agentBuilder, agentReviewer } from './templates.js';
|
|
4
|
+
import { mergeClaudeMcpJson } from './mcp-merge.js';
|
|
5
|
+
import { writeAgentFile, appendGitignore, slugify } from './scaffold-utils.js';
|
|
4
6
|
export class ClaudeCodeMaterializer {
|
|
5
7
|
async scaffold(config, opts) {
|
|
6
8
|
const { cwd } = opts;
|
|
@@ -25,10 +27,13 @@ export class ClaudeCodeMaterializer {
|
|
|
25
27
|
write(config.storage.markdownFallback.path, `<!-- AUTO-GENERATED by agent-harness-kit — DO NOT EDIT MANUALLY -->\n<!-- Run ahk status to refresh -->\n\n# Current Session\n\nNo tasks in progress.\n`);
|
|
26
28
|
}
|
|
27
29
|
// .claude/agents/ — skip files the dev may have customized
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
writeAgentFile(cwd, '.claude/agents/
|
|
30
|
+
const projectName = config.project.name;
|
|
31
|
+
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(', ');
|
|
32
|
+
const writablePaths = (config.agents.builder.writablePaths ?? []).join(', ');
|
|
33
|
+
writeAgentFile(cwd, '.claude/agents/lead.md', agentLead({ projectName }));
|
|
34
|
+
writeAgentFile(cwd, '.claude/agents/explorer.md', agentExplorer({ projectName, allowedPaths }));
|
|
35
|
+
writeAgentFile(cwd, '.claude/agents/builder.md', agentBuilder({ projectName, writablePaths }));
|
|
36
|
+
writeAgentFile(cwd, '.claude/agents/reviewer.md', agentReviewer({ projectName }));
|
|
32
37
|
// .claude/mcp.json — MERGE, never overwrite whole file
|
|
33
38
|
mergeClaudeMcpJson(join(cwd, '.claude', 'mcp.json'), config.tools.mcp.port);
|
|
34
39
|
// .gitignore additions
|
|
@@ -43,10 +48,13 @@ export class ClaudeCodeMaterializer {
|
|
|
43
48
|
// build always regenerates AGENTS.md (it's derived from config)
|
|
44
49
|
write('AGENTS.md', agentsMd(config));
|
|
45
50
|
// Agent files: skip if customized, write if missing
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
writeAgentFile(cwd, '.claude/agents/
|
|
51
|
+
const projectName = config.project.name;
|
|
52
|
+
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(', ');
|
|
53
|
+
const writablePaths = (config.agents.builder.writablePaths ?? []).join(', ');
|
|
54
|
+
writeAgentFile(cwd, '.claude/agents/lead.md', agentLead({ projectName }));
|
|
55
|
+
writeAgentFile(cwd, '.claude/agents/explorer.md', agentExplorer({ projectName, allowedPaths }));
|
|
56
|
+
writeAgentFile(cwd, '.claude/agents/builder.md', agentBuilder({ projectName, writablePaths }));
|
|
57
|
+
writeAgentFile(cwd, '.claude/agents/reviewer.md', agentReviewer({ projectName }));
|
|
50
58
|
// MCP config: always merge
|
|
51
59
|
mergeClaudeMcpJson(join(cwd, '.claude', 'mcp.json'), config.tools.mcp.port);
|
|
52
60
|
}
|
|
@@ -55,29 +63,4 @@ export class ClaudeCodeMaterializer {
|
|
|
55
63
|
// Migration from claude-code is handled by the target materializer
|
|
56
64
|
}
|
|
57
65
|
}
|
|
58
|
-
// ─── Shared helpers ───────────────────────────────────────────────────────────
|
|
59
|
-
function writeAgentFile(cwd, relPath, content) {
|
|
60
|
-
const abs = join(cwd, relPath);
|
|
61
|
-
if (existsSync(abs))
|
|
62
|
-
return; // preserve dev customizations
|
|
63
|
-
mkdirSync(resolve(abs, '..'), { recursive: true });
|
|
64
|
-
writeFileSync(abs, content, 'utf8');
|
|
65
|
-
}
|
|
66
|
-
function appendGitignore(cwd) {
|
|
67
|
-
const giPath = join(cwd, '.gitignore');
|
|
68
|
-
const existing = existsSync(giPath) ? readFileSync(giPath, 'utf8') : '';
|
|
69
|
-
const toAdd = GITIGNORE_ENTRIES.split('\n')
|
|
70
|
-
.filter((line) => line && !existing.includes(line))
|
|
71
|
-
.join('\n');
|
|
72
|
-
if (toAdd.trim()) {
|
|
73
|
-
writeFileSync(giPath, existing + (existing.endsWith('\n') ? '' : '\n') + toAdd + '\n', 'utf8');
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
function slugify(title) {
|
|
77
|
-
return title
|
|
78
|
-
.toLowerCase()
|
|
79
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
80
|
-
.replace(/^-+|-+$/g, '')
|
|
81
|
-
.slice(0, 64);
|
|
82
|
-
}
|
|
83
66
|
//# sourceMappingURL=claude-code.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/core/materializer/claude-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/core/materializer/claude-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-merge.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/mcp-merge.ts"],"names":[],"mappings":"AAGA,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAwBvE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CA6BtE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
export function mergeClaudeMcpJson(filePath, port) {
|
|
4
|
+
let existing = {};
|
|
5
|
+
if (existsSync(filePath)) {
|
|
6
|
+
try {
|
|
7
|
+
existing = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// Unreadable JSON — start fresh to avoid corrupt state
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const merged = {
|
|
14
|
+
...existing,
|
|
15
|
+
mcpServers: {
|
|
16
|
+
...(existing.mcpServers ?? {}),
|
|
17
|
+
'agent-harness-kit': {
|
|
18
|
+
command: 'npx',
|
|
19
|
+
args: ['ahk', 'serve', '--port', String(port)],
|
|
20
|
+
type: 'stdio',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
25
|
+
writeFileSync(filePath, JSON.stringify(merged, null, 2) + '\n', 'utf8');
|
|
26
|
+
}
|
|
27
|
+
export function mergeOpencodeJson(filePath, port) {
|
|
28
|
+
let existing = {};
|
|
29
|
+
if (existsSync(filePath)) {
|
|
30
|
+
try {
|
|
31
|
+
existing = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// start fresh
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const existingMcp = existing.mcp ?? {};
|
|
38
|
+
const existingServers = existingMcp.servers ?? {};
|
|
39
|
+
const merged = {
|
|
40
|
+
...existing,
|
|
41
|
+
mcp: {
|
|
42
|
+
...existingMcp,
|
|
43
|
+
servers: {
|
|
44
|
+
...existingServers,
|
|
45
|
+
'agent-harness-kit': {
|
|
46
|
+
command: 'npx',
|
|
47
|
+
args: ['ahk', 'serve', '--port', String(port)],
|
|
48
|
+
type: 'stdio',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
writeFileSync(filePath, JSON.stringify(merged, null, 2) + '\n', 'utf8');
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=mcp-merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-merge.js","sourceRoot":"","sources":["../../../src/core/materializer/mcp-merge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,IAAY;IAC/D,IAAI,QAAQ,GAA4B,EAAE,CAAA;IAC1C,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAA4B,CAAA;QAClF,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG;QACb,GAAG,QAAQ;QACX,UAAU,EAAE;YACV,GAAG,CAAE,QAAQ,CAAC,UAAsC,IAAI,EAAE,CAAC;YAC3D,mBAAmB,EAAE;gBACnB,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC9C,IAAI,EAAE,OAAO;aACd;SACF;KACF,CAAA;IAED,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACjD,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;AACzE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,IAAY;IAC9D,IAAI,QAAQ,GAA4B,EAAE,CAAA;IAC1C,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAA4B,CAAA;QAClF,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAI,QAAQ,CAAC,GAA+B,IAAI,EAAE,CAAA;IACnE,MAAM,eAAe,GAAI,WAAW,CAAC,OAAmC,IAAI,EAAE,CAAA;IAE9E,MAAM,MAAM,GAAG;QACb,GAAG,QAAQ;QACX,GAAG,EAAE;YACH,GAAG,WAAW;YACd,OAAO,EAAE;gBACP,GAAG,eAAe;gBAClB,mBAAmB,EAAE;oBACnB,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;oBAC9C,IAAI,EAAE,OAAO;iBACd;aACF;SACF;KACF,CAAA;IAED,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;AACzE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/opencode.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/opencode.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAK9C,qBAAa,oBAAqB,YAAW,YAAY;IACjD,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CrE,KAAK,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBxD,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGjF"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { existsSync, mkdirSync,
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { join, resolve } from 'node:path';
|
|
3
|
-
import { HEALTH_SH,
|
|
3
|
+
import { HEALTH_SH, agentsMd, featureListJson, agentLead, agentExplorer, agentBuilder, agentReviewer } from './templates.js';
|
|
4
|
+
import { mergeOpencodeJson } from './mcp-merge.js';
|
|
5
|
+
import { writeAgentFile, appendGitignore, slugify } from './scaffold-utils.js';
|
|
4
6
|
export class OpenCodeMaterializer {
|
|
5
7
|
async scaffold(config, opts) {
|
|
6
8
|
const { cwd } = opts;
|
|
@@ -23,10 +25,13 @@ export class OpenCodeMaterializer {
|
|
|
23
25
|
write(config.storage.markdownFallback.path, `<!-- AUTO-GENERATED by agent-harness-kit — DO NOT EDIT MANUALLY -->\n<!-- Run ahk status to refresh -->\n\n# Current Session\n\nNo tasks in progress.\n`);
|
|
24
26
|
}
|
|
25
27
|
// .opencode/agents/ — skip files the dev may have customized
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
writeAgentFile(cwd, '.opencode/agents/
|
|
28
|
+
const projectName = config.project.name;
|
|
29
|
+
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(', ');
|
|
30
|
+
const writablePaths = (config.agents.builder.writablePaths ?? []).join(', ');
|
|
31
|
+
writeAgentFile(cwd, '.opencode/agents/lead.md', agentLead({ projectName }));
|
|
32
|
+
writeAgentFile(cwd, '.opencode/agents/explorer.md', agentExplorer({ projectName, allowedPaths }));
|
|
33
|
+
writeAgentFile(cwd, '.opencode/agents/builder.md', agentBuilder({ projectName, writablePaths }));
|
|
34
|
+
writeAgentFile(cwd, '.opencode/agents/reviewer.md', agentReviewer({ projectName }));
|
|
30
35
|
// opencode.json — MERGE, never overwrite whole file
|
|
31
36
|
mergeOpencodeJson(join(cwd, 'opencode.json'), config.tools.mcp.port);
|
|
32
37
|
appendGitignore(cwd);
|
|
@@ -38,39 +43,17 @@ export class OpenCodeMaterializer {
|
|
|
38
43
|
writeFileSync(abs, content, 'utf8');
|
|
39
44
|
};
|
|
40
45
|
write('AGENTS.md', agentsMd(config));
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
writeAgentFile(cwd, '.opencode/agents/
|
|
46
|
+
const projectName = config.project.name;
|
|
47
|
+
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(', ');
|
|
48
|
+
const writablePaths = (config.agents.builder.writablePaths ?? []).join(', ');
|
|
49
|
+
writeAgentFile(cwd, '.opencode/agents/lead.md', agentLead({ projectName }));
|
|
50
|
+
writeAgentFile(cwd, '.opencode/agents/explorer.md', agentExplorer({ projectName, allowedPaths }));
|
|
51
|
+
writeAgentFile(cwd, '.opencode/agents/builder.md', agentBuilder({ projectName, writablePaths }));
|
|
52
|
+
writeAgentFile(cwd, '.opencode/agents/reviewer.md', agentReviewer({ projectName }));
|
|
45
53
|
mergeOpencodeJson(join(cwd, 'opencode.json'), config.tools.mcp.port);
|
|
46
54
|
}
|
|
47
55
|
async migrate(config, _to, _cwd) {
|
|
48
56
|
void config;
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
|
-
// ─── Shared helpers ───────────────────────────────────────────────────────────
|
|
52
|
-
function writeAgentFile(cwd, relPath, content) {
|
|
53
|
-
const abs = join(cwd, relPath);
|
|
54
|
-
if (existsSync(abs))
|
|
55
|
-
return; // preserve dev customizations
|
|
56
|
-
mkdirSync(resolve(abs, '..'), { recursive: true });
|
|
57
|
-
writeFileSync(abs, content, 'utf8');
|
|
58
|
-
}
|
|
59
|
-
function appendGitignore(cwd) {
|
|
60
|
-
const giPath = join(cwd, '.gitignore');
|
|
61
|
-
const existing = existsSync(giPath) ? readFileSync(giPath, 'utf8') : '';
|
|
62
|
-
const toAdd = GITIGNORE_ENTRIES.split('\n')
|
|
63
|
-
.filter((line) => line && !existing.includes(line))
|
|
64
|
-
.join('\n');
|
|
65
|
-
if (toAdd.trim()) {
|
|
66
|
-
writeFileSync(giPath, existing + (existing.endsWith('\n') ? '' : '\n') + toAdd + '\n', 'utf8');
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
function slugify(title) {
|
|
70
|
-
return title
|
|
71
|
-
.toLowerCase()
|
|
72
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
73
|
-
.replace(/^-+|-+$/g, '')
|
|
74
|
-
.slice(0, 64);
|
|
75
|
-
}
|
|
76
59
|
//# sourceMappingURL=opencode.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../src/core/materializer/opencode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../src/core/materializer/opencode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC9D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGzC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC5H,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAE9E,MAAM,OAAO,oBAAoB;IAC/B,KAAK,CAAC,QAAQ,CAAC,MAAqB,EAAE,IAAqB;QACzD,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QAEpB,MAAM,KAAK,GAAG,CAAC,OAAe,EAAE,OAAe,EAAE,IAAa,EAAE,EAAE;YAChE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;YAC9B,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAClD,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;QACzD,CAAC,CAAA;QAED,uDAAuD;QACvD,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;QAEpC,8CAA8C;QAC9C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;YACxC,KAAK,CAAC,WAAW,EAAE,SAAS,EAAE,KAAK,CAAC,CAAA;QACtC,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS;YAC1B,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YAC9D,CAAC,CAAC,EAAE,CAAA;QACN,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,mBAAmB,CAAC,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAAA;QAE5E,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACjE,KAAK,CACH,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,EACpC,yJAAyJ,CAC1J,CAAA;QACH,CAAC;QAED,6DAA6D;QAC7D,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAA;QACvC,MAAM,YAAY,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3E,MAAM,aAAa,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5E,cAAc,CAAC,GAAG,EAAE,0BAA0B,EAAE,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;QAC3E,cAAc,CAAC,GAAG,EAAE,8BAA8B,EAAE,aAAa,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC,CAAC,CAAA;QACjG,cAAc,CAAC,GAAG,EAAE,6BAA6B,EAAE,YAAY,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC,CAAC,CAAA;QAChG,cAAc,CAAC,GAAG,EAAE,8BAA8B,EAAE,aAAa,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;QAEnF,oDAAoD;QACpD,iBAAiB,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAEpE,eAAe,CAAC,GAAG,CAAC,CAAA;IACtB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAqB,EAAE,GAAW;QAC5C,MAAM,KAAK,GAAG,CAAC,OAAe,EAAE,OAAe,EAAE,EAAE;YACjD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;YAC9B,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAClD,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;QACrC,CAAC,CAAA;QAED,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;QAEpC,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAA;QACvC,MAAM,YAAY,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3E,MAAM,aAAa,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5E,cAAc,CAAC,GAAG,EAAE,0BAA0B,EAAE,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;QAC3E,cAAc,CAAC,GAAG,EAAE,8BAA8B,EAAE,aAAa,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC,CAAC,CAAA;QACjG,cAAc,CAAC,GAAG,EAAE,6BAA6B,EAAE,YAAY,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC,CAAC,CAAA;QAChG,cAAc,CAAC,GAAG,EAAE,8BAA8B,EAAE,aAAa,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;QAEnF,iBAAiB,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACtE,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAqB,EAAE,GAAa,EAAE,IAAY;QAC9D,KAAK,MAAM,CAAA;IACb,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold-utils.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/scaffold-utils.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAKlF;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAWjD;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM7C"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { GITIGNORE_ENTRIES } from './templates.js';
|
|
4
|
+
export function writeAgentFile(cwd, relPath, content) {
|
|
5
|
+
const abs = join(cwd, relPath);
|
|
6
|
+
if (existsSync(abs))
|
|
7
|
+
return; // preserve dev customizations
|
|
8
|
+
mkdirSync(resolve(abs, '..'), { recursive: true });
|
|
9
|
+
writeFileSync(abs, content, 'utf8');
|
|
10
|
+
}
|
|
11
|
+
export function appendGitignore(cwd) {
|
|
12
|
+
const giPath = join(cwd, '.gitignore');
|
|
13
|
+
const existing = existsSync(giPath) ? readFileSync(giPath, 'utf8') : '';
|
|
14
|
+
const toAdd = GITIGNORE_ENTRIES.split('\n')
|
|
15
|
+
.filter((line) => line && !existing.includes(line))
|
|
16
|
+
.join('\n');
|
|
17
|
+
if (toAdd.trim()) {
|
|
18
|
+
writeFileSync(giPath, existing + (existing.endsWith('\n') ? '' : '\n') + toAdd + '\n', 'utf8');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function slugify(title) {
|
|
22
|
+
return title
|
|
23
|
+
.toLowerCase()
|
|
24
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
25
|
+
.replace(/^-+|-+$/g, '')
|
|
26
|
+
.slice(0, 64);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=scaffold-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold-utils.js","sourceRoot":"","sources":["../../../src/core/materializer/scaffold-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,OAAe,EAAE,OAAe;IAC1E,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IAC9B,IAAI,UAAU,CAAC,GAAG,CAAC;QAAE,OAAM,CAAE,8BAA8B;IAC3D,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAClD,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;AACrC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;IACtC,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAEvE,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC;SACxC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;SAClD,IAAI,CAAC,IAAI,CAAC,CAAA;IAEb,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACjB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;IAChG,CAAC;AACH,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,KAAK;SACT,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AACjB,CAAC"}
|
|
@@ -9,17 +9,25 @@ export declare function configTs(params: {
|
|
|
9
9
|
tasksAdapter: string;
|
|
10
10
|
port: number;
|
|
11
11
|
}): string;
|
|
12
|
-
export declare
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export declare
|
|
12
|
+
export declare function agentLead(vars: {
|
|
13
|
+
projectName: string;
|
|
14
|
+
}): string;
|
|
15
|
+
export declare function agentExplorer(vars: {
|
|
16
|
+
projectName: string;
|
|
17
|
+
allowedPaths: string;
|
|
18
|
+
}): string;
|
|
19
|
+
export declare function agentBuilder(vars: {
|
|
20
|
+
projectName: string;
|
|
21
|
+
writablePaths: string;
|
|
22
|
+
}): string;
|
|
23
|
+
export declare function agentReviewer(vars: {
|
|
24
|
+
projectName: string;
|
|
25
|
+
}): string;
|
|
16
26
|
export declare function featureListJson(tasks: {
|
|
17
27
|
slug: string;
|
|
18
28
|
title: string;
|
|
19
29
|
description?: string;
|
|
20
30
|
acceptance?: string[];
|
|
21
31
|
}[]): string;
|
|
22
|
-
export declare function mergeClaudeMcpJson(filePath: string, port: number): void;
|
|
23
|
-
export declare function mergeOpencodeJson(filePath: string, port: number): void;
|
|
24
32
|
export declare const GITIGNORE_ENTRIES = "\n# agent-harness-kit\n.harness/harness.db\n.harness/harness.db-shm\n.harness/harness.db-wal\n.harness/current.md\n";
|
|
25
33
|
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/templates.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/templates.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAqBnD,eAAO,MAAM,SAAS,uoBAmBrB,CAAA;AAID,wBAAgB,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CA8EtD;AAID,wBAAgB,QAAQ,CAAC,MAAM,EAAE;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,MAAM,CA6CT;AAID,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE/D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAEzF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAEzF;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAEnE;AAID,wBAAgB,eAAe,CAC7B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,EAAE,GACpF,MAAM,CAER;AAID,eAAO,MAAM,iBAAiB,wHAM7B,CAAA"}
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
// ─── Agent template loader ────────────────────────────────────────────────────
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const TEMPLATES_DIR = join(__dirname, 'agent-templates');
|
|
7
|
+
/**
|
|
8
|
+
* Load an agent template file and interpolate {{variables}}.
|
|
9
|
+
* Variables are replaced using a simple {{key}} pattern.
|
|
10
|
+
*/
|
|
11
|
+
function loadAgentTemplate(name, vars = {}) {
|
|
12
|
+
const raw = readFileSync(join(TEMPLATES_DIR, `${name}.md`), 'utf8');
|
|
13
|
+
return raw.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
|
|
14
|
+
}
|
|
1
15
|
// ─── health.sh — exits 1 until the dev implements it ─────────────────────────
|
|
2
16
|
export const HEALTH_SH = `#!/usr/bin/env bash
|
|
3
17
|
# health.sh — project health check for agent-harness-kit
|
|
@@ -145,170 +159,23 @@ export default defineHarness({
|
|
|
145
159
|
})
|
|
146
160
|
`;
|
|
147
161
|
}
|
|
148
|
-
// ─── Agent definition templates
|
|
149
|
-
export
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
3. Decompose the task:
|
|
162
|
-
- What needs to be explored first?
|
|
163
|
-
- What needs to be built?
|
|
164
|
-
- What are the acceptance criteria?
|
|
165
|
-
4. Call \`actions.write(actionId, 'result', plan)\` with your decomposition.
|
|
166
|
-
5. Call \`actions.complete(actionId, 'Plan defined')\`.
|
|
167
|
-
6. Delegate to explorer, then builder, then reviewer — in that order.
|
|
168
|
-
|
|
169
|
-
## Rules
|
|
170
|
-
|
|
171
|
-
- Do NOT write code yourself. Delegate to builder.
|
|
172
|
-
- Do NOT read source files yourself. Delegate to explorer.
|
|
173
|
-
- One task at a time. Check \`tasks.get('in_progress')\` before picking a new one.
|
|
174
|
-
- If the reviewer blocks, coordinate a fix with builder and re-review.
|
|
175
|
-
`;
|
|
176
|
-
export const AGENT_EXPLORER = `---
|
|
177
|
-
description: Explorer agent — reads and maps the codebase, never writes files
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
# Explorer Agent
|
|
181
|
-
|
|
182
|
-
You are the **explorer agent** in the agent-harness-kit harness. Your job is to read and understand the relevant parts of the codebase for the current task. You never write or modify files.
|
|
183
|
-
|
|
184
|
-
## Your workflow
|
|
185
|
-
|
|
186
|
-
1. Call \`actions.start(taskId, 'explorer')\` to register your action.
|
|
187
|
-
2. Read only the files relevant to the current task. Use \`docs.search(query)\` first.
|
|
188
|
-
3. Record what you find:
|
|
189
|
-
- \`actions.write(actionId, 'tools_used', list_of_tools)\`
|
|
190
|
-
- \`actions.write(actionId, 'result', analysis)\`
|
|
191
|
-
4. Call \`actions.complete(actionId, 'Analysis done')\`.
|
|
192
|
-
|
|
193
|
-
## Rules
|
|
194
|
-
|
|
195
|
-
- Never modify files. You are read-only.
|
|
196
|
-
- Use progressive disclosure — read AGENTS.md, then navigate to specific files.
|
|
197
|
-
- Record every file you read via \`actions.write(actionId, 'tools_used', ...)\`.
|
|
198
|
-
`;
|
|
199
|
-
export const AGENT_BUILDER = `---
|
|
200
|
-
description: Builder agent — implements the plan produced by explorer and lead
|
|
201
|
-
---
|
|
202
|
-
|
|
203
|
-
# Builder Agent
|
|
204
|
-
|
|
205
|
-
You are the **builder agent** in the agent-harness-kit harness. Your job is to implement the plan from lead, using the analysis from explorer.
|
|
206
|
-
|
|
207
|
-
## Your workflow
|
|
208
|
-
|
|
209
|
-
1. Read the lead's plan from \`actions.get(taskId)\`.
|
|
210
|
-
2. Call \`actions.start(taskId, 'builder')\` to register your action.
|
|
211
|
-
3. Implement the task. Record every file you touch:
|
|
212
|
-
- \`actions.write(actionId, 'files_modified', list)\`
|
|
213
|
-
4. Record the result:
|
|
214
|
-
- \`actions.write(actionId, 'result', summary_of_changes)\`
|
|
215
|
-
5. If you hit a blocker: \`actions.write(actionId, 'blockers', description)\`
|
|
216
|
-
6. Call \`actions.complete(actionId, 'Implementation done')\`.
|
|
217
|
-
|
|
218
|
-
## Rules
|
|
219
|
-
|
|
220
|
-
- Only write to the paths allowed by your config (writablePaths).
|
|
221
|
-
- If something is unclear, record a blocker and surface it to lead — don't guess.
|
|
222
|
-
- Run tests after implementing if the project has a test suite.
|
|
223
|
-
`;
|
|
224
|
-
export const AGENT_REVIEWER = `---
|
|
225
|
-
description: Reviewer agent — verifies acceptance criteria before marking a task done
|
|
226
|
-
---
|
|
227
|
-
|
|
228
|
-
# Reviewer Agent
|
|
229
|
-
|
|
230
|
-
You are the **reviewer agent** in the agent-harness-kit harness. Your job is to verify that the builder's work meets all acceptance criteria before the task is marked done.
|
|
231
|
-
|
|
232
|
-
## Your workflow
|
|
233
|
-
|
|
234
|
-
1. Call \`actions.get(taskId)\` to read the full history (lead plan + explorer analysis + builder changes).
|
|
235
|
-
2. Call \`actions.start(taskId, 'reviewer')\` to register your action.
|
|
236
|
-
3. Verify each acceptance criterion:
|
|
237
|
-
- \`actions.write(actionId, 'result', 'APPROVED' or 'BLOCKED: reason')\`
|
|
238
|
-
4. If approved:
|
|
239
|
-
- \`actions.complete(actionId, 'Task approved')\`
|
|
240
|
-
- \`tasks.update(taskId, 'done')\`
|
|
241
|
-
5. If blocked:
|
|
242
|
-
- \`actions.write(actionId, 'blockers', what_is_missing)\`
|
|
243
|
-
- \`actions.complete(actionId, 'Task blocked: reason')\`
|
|
244
|
-
- Notify lead to re-assign to builder.
|
|
245
|
-
|
|
246
|
-
## Rules
|
|
247
|
-
|
|
248
|
-
- Never approve unless ALL acceptance criteria are met.
|
|
249
|
-
- Check that health.sh is green before approving.
|
|
250
|
-
- Be specific about what is missing when blocking.
|
|
251
|
-
`;
|
|
162
|
+
// ─── Agent definition templates (loaded from agent-templates/*.md) ─────────────
|
|
163
|
+
export function agentLead(vars) {
|
|
164
|
+
return loadAgentTemplate('lead', vars);
|
|
165
|
+
}
|
|
166
|
+
export function agentExplorer(vars) {
|
|
167
|
+
return loadAgentTemplate('explorer', vars);
|
|
168
|
+
}
|
|
169
|
+
export function agentBuilder(vars) {
|
|
170
|
+
return loadAgentTemplate('builder', vars);
|
|
171
|
+
}
|
|
172
|
+
export function agentReviewer(vars) {
|
|
173
|
+
return loadAgentTemplate('reviewer', vars);
|
|
174
|
+
}
|
|
252
175
|
// ─── feature_list.json initial seed ──────────────────────────────────────────
|
|
253
176
|
export function featureListJson(tasks) {
|
|
254
177
|
return JSON.stringify(tasks, null, 2) + '\n';
|
|
255
178
|
}
|
|
256
|
-
// ─── MCP JSON merge helpers ───────────────────────────────────────────────────
|
|
257
|
-
// These do a deep merge so existing provider config is preserved.
|
|
258
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
259
|
-
import { dirname } from 'node:path';
|
|
260
|
-
export function mergeClaudeMcpJson(filePath, port) {
|
|
261
|
-
let existing = {};
|
|
262
|
-
if (existsSync(filePath)) {
|
|
263
|
-
try {
|
|
264
|
-
existing = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
265
|
-
}
|
|
266
|
-
catch {
|
|
267
|
-
// Unreadable JSON — start fresh to avoid corrupt state
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
const merged = {
|
|
271
|
-
...existing,
|
|
272
|
-
mcpServers: {
|
|
273
|
-
...(existing.mcpServers ?? {}),
|
|
274
|
-
'agent-harness-kit': {
|
|
275
|
-
command: 'npx',
|
|
276
|
-
args: ['ahk', 'serve', '--port', String(port)],
|
|
277
|
-
type: 'stdio',
|
|
278
|
-
},
|
|
279
|
-
},
|
|
280
|
-
};
|
|
281
|
-
mkdirSync(dirname(filePath), { recursive: true });
|
|
282
|
-
writeFileSync(filePath, JSON.stringify(merged, null, 2) + '\n', 'utf8');
|
|
283
|
-
}
|
|
284
|
-
export function mergeOpencodeJson(filePath, port) {
|
|
285
|
-
let existing = {};
|
|
286
|
-
if (existsSync(filePath)) {
|
|
287
|
-
try {
|
|
288
|
-
existing = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
289
|
-
}
|
|
290
|
-
catch {
|
|
291
|
-
// start fresh
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
const existingMcp = existing.mcp ?? {};
|
|
295
|
-
const existingServers = existingMcp.servers ?? {};
|
|
296
|
-
const merged = {
|
|
297
|
-
...existing,
|
|
298
|
-
mcp: {
|
|
299
|
-
...existingMcp,
|
|
300
|
-
servers: {
|
|
301
|
-
...existingServers,
|
|
302
|
-
'agent-harness-kit': {
|
|
303
|
-
command: 'npx',
|
|
304
|
-
args: ['ahk', 'serve', '--port', String(port)],
|
|
305
|
-
type: 'stdio',
|
|
306
|
-
},
|
|
307
|
-
},
|
|
308
|
-
},
|
|
309
|
-
};
|
|
310
|
-
writeFileSync(filePath, JSON.stringify(merged, null, 2) + '\n', 'utf8');
|
|
311
|
-
}
|
|
312
179
|
// ─── .gitignore additions ─────────────────────────────────────────────────────
|
|
313
180
|
export const GITIGNORE_ENTRIES = `
|
|
314
181
|
# agent-harness-kit
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/core/materializer/templates.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/core/materializer/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAGxC,iFAAiF;AAEjF,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAA;AAExD;;;GAGG;AACH,SAAS,iBAAiB,CACxB,IAAkD,EAClD,OAA+B,EAAE;IAEjC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,IAAI,KAAK,CAAC,EAAE,MAAM,CAAC,CAAA;IACnE,OAAO,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,CAAA;AACrF,CAAC;AAED,gFAAgF;AAEhF,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;CAmBxB,CAAA;AAED,iFAAiF;AAEjF,MAAM,UAAU,QAAQ,CAAC,MAAqB;IAC5C,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,OAAO,CAAA;IACtD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAA;IAElC,OAAO,iBAAiB,IAAI;;;;;;IAM1B,IAAI,QAAQ,WAAW;;;;;;;;;;;;;;;;;;;;mDAoBwB,IAAI;;;;;;;;;;mDAUJ,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAkCxC,QAAQ;;;CAG1B,CAAA;AACD,CAAC;AAED,uFAAuF;AAEvF,MAAM,UAAU,QAAQ,CAAC,MAOxB;IACC,OAAO;;;;aAII,MAAM,CAAC,IAAI;oBACJ,MAAM,CAAC,WAAW;iBACrB,MAAM,CAAC,QAAQ;;;eAGjB,MAAM,CAAC,QAAQ;;;;0DAI4B,MAAM,CAAC,QAAQ;;;;;;;;;0BAS/C,MAAM,CAAC,YAAY;;;;;;;;;;;;;;;;;sCAiBP,MAAM,CAAC,IAAI;;;;CAIhD,CAAA;AACD,CAAC;AAED,kFAAkF;AAElF,MAAM,UAAU,SAAS,CAAC,IAA6B;IACrD,OAAO,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAmD;IAC/E,OAAO,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;AAC5C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAoD;IAC/E,OAAO,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;AAC3C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAA6B;IACzD,OAAO,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;AAC5C,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,eAAe,CAC7B,KAAqF;IAErF,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAA;AAC9C,CAAC;AAED,iFAAiF;AAEjF,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;CAMhC,CAAA"}
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { test, describe } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
|
|
4
|
-
function slugify(title) {
|
|
5
|
-
return title
|
|
6
|
-
.toLowerCase()
|
|
7
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
8
|
-
.replace(/^-+|-+$/g, '')
|
|
9
|
-
.slice(0, 64);
|
|
10
|
-
}
|
|
3
|
+
import { slugify } from '../core/materializer/scaffold-utils.js';
|
|
11
4
|
describe('slugify', () => {
|
|
12
5
|
test('lowercases and replaces spaces', () => {
|
|
13
6
|
assert.equal(slugify('My Feature'), 'my-feature');
|