@cardor/agent-harness-kit 0.1.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.
Files changed (111) hide show
  1. package/README.md +218 -0
  2. package/bin/ahk.js +2 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +113 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/build.d.ts +6 -0
  8. package/dist/commands/build.d.ts.map +1 -0
  9. package/dist/commands/build.js +39 -0
  10. package/dist/commands/build.js.map +1 -0
  11. package/dist/commands/export.d.ts +8 -0
  12. package/dist/commands/export.d.ts.map +1 -0
  13. package/dist/commands/export.js +33 -0
  14. package/dist/commands/export.js.map +1 -0
  15. package/dist/commands/health.d.ts +2 -0
  16. package/dist/commands/health.d.ts.map +1 -0
  17. package/dist/commands/health.js +38 -0
  18. package/dist/commands/health.js.map +1 -0
  19. package/dist/commands/init-helpers.d.ts +9 -0
  20. package/dist/commands/init-helpers.d.ts.map +1 -0
  21. package/dist/commands/init-helpers.js +40 -0
  22. package/dist/commands/init-helpers.js.map +1 -0
  23. package/dist/commands/init.d.ts +9 -0
  24. package/dist/commands/init.d.ts.map +1 -0
  25. package/dist/commands/init.js +202 -0
  26. package/dist/commands/init.js.map +1 -0
  27. package/dist/commands/migrate.d.ts +6 -0
  28. package/dist/commands/migrate.d.ts.map +1 -0
  29. package/dist/commands/migrate.js +45 -0
  30. package/dist/commands/migrate.js.map +1 -0
  31. package/dist/commands/serve.d.ts +6 -0
  32. package/dist/commands/serve.d.ts.map +1 -0
  33. package/dist/commands/serve.js +13 -0
  34. package/dist/commands/serve.js.map +1 -0
  35. package/dist/commands/status.d.ts +6 -0
  36. package/dist/commands/status.d.ts.map +1 -0
  37. package/dist/commands/status.js +71 -0
  38. package/dist/commands/status.js.map +1 -0
  39. package/dist/commands/sync.d.ts +7 -0
  40. package/dist/commands/sync.d.ts.map +1 -0
  41. package/dist/commands/sync.js +57 -0
  42. package/dist/commands/sync.js.map +1 -0
  43. package/dist/commands/task/add.d.ts +2 -0
  44. package/dist/commands/task/add.d.ts.map +1 -0
  45. package/dist/commands/task/add.js +59 -0
  46. package/dist/commands/task/add.js.map +1 -0
  47. package/dist/commands/task/done.d.ts +2 -0
  48. package/dist/commands/task/done.d.ts.map +1 -0
  49. package/dist/commands/task/done.js +45 -0
  50. package/dist/commands/task/done.js.map +1 -0
  51. package/dist/commands/task/index.d.ts +4 -0
  52. package/dist/commands/task/index.d.ts.map +1 -0
  53. package/dist/commands/task/index.js +4 -0
  54. package/dist/commands/task/index.js.map +1 -0
  55. package/dist/commands/task/list.d.ts +7 -0
  56. package/dist/commands/task/list.d.ts.map +1 -0
  57. package/dist/commands/task/list.js +42 -0
  58. package/dist/commands/task/list.js.map +1 -0
  59. package/dist/core/config.d.ts +5 -0
  60. package/dist/core/config.d.ts.map +1 -0
  61. package/dist/core/config.js +77 -0
  62. package/dist/core/config.js.map +1 -0
  63. package/dist/core/db.d.ts +56 -0
  64. package/dist/core/db.d.ts.map +1 -0
  65. package/dist/core/db.js +344 -0
  66. package/dist/core/db.js.map +1 -0
  67. package/dist/core/materializer/claude-code.d.ts +8 -0
  68. package/dist/core/materializer/claude-code.d.ts.map +1 -0
  69. package/dist/core/materializer/claude-code.js +83 -0
  70. package/dist/core/materializer/claude-code.js.map +1 -0
  71. package/dist/core/materializer/index.d.ts +8 -0
  72. package/dist/core/materializer/index.d.ts.map +1 -0
  73. package/dist/core/materializer/index.js +13 -0
  74. package/dist/core/materializer/index.js.map +1 -0
  75. package/dist/core/materializer/opencode.d.ts +8 -0
  76. package/dist/core/materializer/opencode.d.ts.map +1 -0
  77. package/dist/core/materializer/opencode.js +76 -0
  78. package/dist/core/materializer/opencode.js.map +1 -0
  79. package/dist/core/materializer/templates.d.ts +25 -0
  80. package/dist/core/materializer/templates.d.ts.map +1 -0
  81. package/dist/core/materializer/templates.js +319 -0
  82. package/dist/core/materializer/templates.js.map +1 -0
  83. package/dist/core/mcp-server.d.ts +3 -0
  84. package/dist/core/mcp-server.d.ts.map +1 -0
  85. package/dist/core/mcp-server.js +264 -0
  86. package/dist/core/mcp-server.js.map +1 -0
  87. package/dist/core/sqlite-adapter.d.ts +14 -0
  88. package/dist/core/sqlite-adapter.d.ts.map +1 -0
  89. package/dist/core/sqlite-adapter.js +20 -0
  90. package/dist/core/sqlite-adapter.js.map +1 -0
  91. package/dist/index.d.ts +3 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +2 -0
  94. package/dist/index.js.map +1 -0
  95. package/dist/tests/db.test.d.ts +2 -0
  96. package/dist/tests/db.test.d.ts.map +1 -0
  97. package/dist/tests/db.test.js +106 -0
  98. package/dist/tests/db.test.js.map +1 -0
  99. package/dist/tests/slugify.test.d.ts +2 -0
  100. package/dist/tests/slugify.test.d.ts.map +1 -0
  101. package/dist/tests/slugify.test.js +26 -0
  102. package/dist/tests/slugify.test.js.map +1 -0
  103. package/dist/tests/templates.test.d.ts +2 -0
  104. package/dist/tests/templates.test.d.ts.map +1 -0
  105. package/dist/tests/templates.test.js +64 -0
  106. package/dist/tests/templates.test.js.map +1 -0
  107. package/dist/types.d.ts +141 -0
  108. package/dist/types.d.ts.map +1 -0
  109. package/dist/types.js +3 -0
  110. package/dist/types.js.map +1 -0
  111. package/package.json +56 -0
@@ -0,0 +1,83 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { HEALTH_SH, GITIGNORE_ENTRIES, agentsMd, mergeClaudeMcpJson, featureListJson, AGENT_LEAD, AGENT_EXPLORER, AGENT_BUILDER, AGENT_REVIEWER, } from './templates.js';
4
+ export class ClaudeCodeMaterializer {
5
+ async scaffold(config, opts) {
6
+ const { cwd } = opts;
7
+ const write = (relPath, content, mode) => {
8
+ const abs = join(cwd, relPath);
9
+ mkdirSync(resolve(abs, '..'), { recursive: true });
10
+ writeFileSync(abs, content, { encoding: 'utf8', mode });
11
+ };
12
+ // AGENTS.md — always overwrite (generated from config)
13
+ write('AGENTS.md', agentsMd(config));
14
+ // health.sh — only create if it doesn't exist
15
+ if (!existsSync(join(cwd, 'health.sh'))) {
16
+ write('health.sh', HEALTH_SH, 0o755);
17
+ }
18
+ // .harness/feature_list.json
19
+ const tasks = opts.firstTask
20
+ ? [{ slug: slugify(opts.firstTask.title), ...opts.firstTask }]
21
+ : [];
22
+ write(join(config.storage.dir, 'feature_list.json'), featureListJson(tasks));
23
+ // .harness/current.md placeholder
24
+ if (!existsSync(join(cwd, config.storage.markdownFallback.path))) {
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`);
26
+ }
27
+ // .claude/agents/ — skip files the dev may have customized
28
+ writeAgentFile(cwd, '.claude/agents/lead.md', AGENT_LEAD);
29
+ writeAgentFile(cwd, '.claude/agents/explorer.md', AGENT_EXPLORER);
30
+ writeAgentFile(cwd, '.claude/agents/builder.md', AGENT_BUILDER);
31
+ writeAgentFile(cwd, '.claude/agents/reviewer.md', AGENT_REVIEWER);
32
+ // .claude/mcp.json — MERGE, never overwrite whole file
33
+ mergeClaudeMcpJson(join(cwd, '.claude', 'mcp.json'), config.tools.mcp.port);
34
+ // .gitignore additions
35
+ appendGitignore(cwd);
36
+ }
37
+ async build(config, cwd) {
38
+ const write = (relPath, content) => {
39
+ const abs = join(cwd, relPath);
40
+ mkdirSync(resolve(abs, '..'), { recursive: true });
41
+ writeFileSync(abs, content, 'utf8');
42
+ };
43
+ // build always regenerates AGENTS.md (it's derived from config)
44
+ write('AGENTS.md', agentsMd(config));
45
+ // Agent files: skip if customized, write if missing
46
+ writeAgentFile(cwd, '.claude/agents/lead.md', AGENT_LEAD);
47
+ writeAgentFile(cwd, '.claude/agents/explorer.md', AGENT_EXPLORER);
48
+ writeAgentFile(cwd, '.claude/agents/builder.md', AGENT_BUILDER);
49
+ writeAgentFile(cwd, '.claude/agents/reviewer.md', AGENT_REVIEWER);
50
+ // MCP config: always merge
51
+ mergeClaudeMcpJson(join(cwd, '.claude', 'mcp.json'), config.tools.mcp.port);
52
+ }
53
+ async migrate(config, _to, _cwd) {
54
+ void config;
55
+ // Migration from claude-code is handled by the target materializer
56
+ }
57
+ }
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
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/core/materializer/claude-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { HarnessConfig, Provider, ScaffoldOptions } from '../../types.js';
2
+ export interface Materializer {
3
+ scaffold(config: HarnessConfig, opts: ScaffoldOptions): Promise<void>;
4
+ build(config: HarnessConfig, cwd: string): Promise<void>;
5
+ migrate(config: HarnessConfig, to: Provider, cwd: string): Promise<void>;
6
+ }
7
+ export declare function getMaterializer(provider: Provider): Materializer;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAI9E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACrE,KAAK,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxD,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACzE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,YAAY,CAShE"}
@@ -0,0 +1,13 @@
1
+ import { ClaudeCodeMaterializer } from './claude-code.js';
2
+ import { OpenCodeMaterializer } from './opencode.js';
3
+ export function getMaterializer(provider) {
4
+ switch (provider) {
5
+ case 'claude-code':
6
+ return new ClaudeCodeMaterializer();
7
+ case 'opencode':
8
+ return new OpenCodeMaterializer();
9
+ default:
10
+ throw new Error(`Unknown provider: ${provider}`);
11
+ }
12
+ }
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/materializer/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAQpD,MAAM,UAAU,eAAe,CAAC,QAAkB;IAChD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,aAAa;YAChB,OAAO,IAAI,sBAAsB,EAAE,CAAA;QACrC,KAAK,UAAU;YACb,OAAO,IAAI,oBAAoB,EAAE,CAAA;QACnC;YACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAkB,EAAE,CAAC,CAAA;IAC9D,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { HarnessConfig, Provider, ScaffoldOptions } from '../../types.js';
2
+ import type { Materializer } from './index.js';
3
+ export declare class OpenCodeMaterializer implements Materializer {
4
+ scaffold(config: HarnessConfig, opts: ScaffoldOptions): Promise<void>;
5
+ build(config: HarnessConfig, cwd: string): Promise<void>;
6
+ migrate(config: HarnessConfig, _to: Provider, _cwd: string): Promise<void>;
7
+ }
8
+ //# sourceMappingURL=opencode.d.ts.map
@@ -0,0 +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;AAa9C,qBAAa,oBAAqB,YAAW,YAAY;IACjD,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCrE,KAAK,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBxD,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGjF"}
@@ -0,0 +1,76 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { HEALTH_SH, GITIGNORE_ENTRIES, agentsMd, mergeOpencodeJson, featureListJson, AGENT_LEAD, AGENT_EXPLORER, AGENT_BUILDER, AGENT_REVIEWER, } from './templates.js';
4
+ export class OpenCodeMaterializer {
5
+ async scaffold(config, opts) {
6
+ const { cwd } = opts;
7
+ const write = (relPath, content, mode) => {
8
+ const abs = join(cwd, relPath);
9
+ mkdirSync(resolve(abs, '..'), { recursive: true });
10
+ writeFileSync(abs, content, { encoding: 'utf8', mode });
11
+ };
12
+ // AGENTS.md — always overwrite (generated from config)
13
+ write('AGENTS.md', agentsMd(config));
14
+ // health.sh — only create if it doesn't exist
15
+ if (!existsSync(join(cwd, 'health.sh'))) {
16
+ write('health.sh', HEALTH_SH, 0o755);
17
+ }
18
+ const tasks = opts.firstTask
19
+ ? [{ slug: slugify(opts.firstTask.title), ...opts.firstTask }]
20
+ : [];
21
+ write(join(config.storage.dir, 'feature_list.json'), featureListJson(tasks));
22
+ if (!existsSync(join(cwd, config.storage.markdownFallback.path))) {
23
+ 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
+ }
25
+ // .opencode/agents/ — skip files the dev may have customized
26
+ writeAgentFile(cwd, '.opencode/agents/lead.md', AGENT_LEAD);
27
+ writeAgentFile(cwd, '.opencode/agents/explorer.md', AGENT_EXPLORER);
28
+ writeAgentFile(cwd, '.opencode/agents/builder.md', AGENT_BUILDER);
29
+ writeAgentFile(cwd, '.opencode/agents/reviewer.md', AGENT_REVIEWER);
30
+ // opencode.json — MERGE, never overwrite whole file
31
+ mergeOpencodeJson(join(cwd, 'opencode.json'), config.tools.mcp.port);
32
+ appendGitignore(cwd);
33
+ }
34
+ async build(config, cwd) {
35
+ const write = (relPath, content) => {
36
+ const abs = join(cwd, relPath);
37
+ mkdirSync(resolve(abs, '..'), { recursive: true });
38
+ writeFileSync(abs, content, 'utf8');
39
+ };
40
+ write('AGENTS.md', agentsMd(config));
41
+ writeAgentFile(cwd, '.opencode/agents/lead.md', AGENT_LEAD);
42
+ writeAgentFile(cwd, '.opencode/agents/explorer.md', AGENT_EXPLORER);
43
+ writeAgentFile(cwd, '.opencode/agents/builder.md', AGENT_BUILDER);
44
+ writeAgentFile(cwd, '.opencode/agents/reviewer.md', AGENT_REVIEWER);
45
+ mergeOpencodeJson(join(cwd, 'opencode.json'), config.tools.mcp.port);
46
+ }
47
+ async migrate(config, _to, _cwd) {
48
+ void config;
49
+ }
50
+ }
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
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../src/core/materializer/opencode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { HarnessConfig } from '../../types.js';
2
+ export declare const HEALTH_SH = "#!/usr/bin/env bash\n# health.sh \u2014 project health check for agent-harness-kit\n#\n# This script must exit 0 when the project is healthy.\n# Agents will run this before starting work.\n#\n# TODO: implement your project's health checks below.\n# Examples:\n# npm test\n# docker compose ps | grep -q \"running\"\n# psql -c \"SELECT 1\" > /dev/null 2>&1\n#\n# Until you implement it, this script intentionally exits 1\n# so agents know the environment is not verified.\n\necho \"health.sh not implemented yet.\"\necho \"Edit this file with your project's health checks.\"\necho \"It must exit 0 for agents to start working.\"\nexit 1\n";
3
+ export declare function agentsMd(config: HarnessConfig): string;
4
+ export declare function configTs(params: {
5
+ name: string;
6
+ description: string;
7
+ provider: string;
8
+ docsPath: string;
9
+ tasksAdapter: string;
10
+ port: number;
11
+ }): string;
12
+ export declare const AGENT_LEAD = "---\ndescription: Lead agent \u2014 orchestrates the harness workflow for a single task\n---\n\n# Lead Agent\n\nYou are the **lead agent** in the agent-harness-kit harness. Your job is to decompose a task into a plan and coordinate the other agents.\n\n## Your workflow\n\n1. Read `.harness/current.md` (or call `tasks.get('in_progress')`) to orient yourself.\n2. Call `actions.start(taskId, 'lead')` to register your action.\n3. Decompose the task:\n - What needs to be explored first?\n - What needs to be built?\n - What are the acceptance criteria?\n4. Call `actions.write(actionId, 'result', plan)` with your decomposition.\n5. Call `actions.complete(actionId, 'Plan defined')`.\n6. Delegate to explorer, then builder, then reviewer \u2014 in that order.\n\n## Rules\n\n- Do NOT write code yourself. Delegate to builder.\n- Do NOT read source files yourself. Delegate to explorer.\n- One task at a time. Check `tasks.get('in_progress')` before picking a new one.\n- If the reviewer blocks, coordinate a fix with builder and re-review.\n";
13
+ export declare const AGENT_EXPLORER = "---\ndescription: Explorer agent \u2014 reads and maps the codebase, never writes files\n---\n\n# Explorer Agent\n\nYou 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.\n\n## Your workflow\n\n1. Call `actions.start(taskId, 'explorer')` to register your action.\n2. Read only the files relevant to the current task. Use `docs.search(query)` first.\n3. Record what you find:\n - `actions.write(actionId, 'tools_used', list_of_tools)`\n - `actions.write(actionId, 'result', analysis)`\n4. Call `actions.complete(actionId, 'Analysis done')`.\n\n## Rules\n\n- Never modify files. You are read-only.\n- Use progressive disclosure \u2014 read AGENTS.md, then navigate to specific files.\n- Record every file you read via `actions.write(actionId, 'tools_used', ...)`.\n";
14
+ export declare const AGENT_BUILDER = "---\ndescription: Builder agent \u2014 implements the plan produced by explorer and lead\n---\n\n# Builder Agent\n\nYou are the **builder agent** in the agent-harness-kit harness. Your job is to implement the plan from lead, using the analysis from explorer.\n\n## Your workflow\n\n1. Read the lead's plan from `actions.get(taskId)`.\n2. Call `actions.start(taskId, 'builder')` to register your action.\n3. Implement the task. Record every file you touch:\n - `actions.write(actionId, 'files_modified', list)`\n4. Record the result:\n - `actions.write(actionId, 'result', summary_of_changes)`\n5. If you hit a blocker: `actions.write(actionId, 'blockers', description)`\n6. Call `actions.complete(actionId, 'Implementation done')`.\n\n## Rules\n\n- Only write to the paths allowed by your config (writablePaths).\n- If something is unclear, record a blocker and surface it to lead \u2014 don't guess.\n- Run tests after implementing if the project has a test suite.\n";
15
+ export declare const AGENT_REVIEWER = "---\ndescription: Reviewer agent \u2014 verifies acceptance criteria before marking a task done\n---\n\n# Reviewer Agent\n\nYou 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.\n\n## Your workflow\n\n1. Call `actions.get(taskId)` to read the full history (lead plan + explorer analysis + builder changes).\n2. Call `actions.start(taskId, 'reviewer')` to register your action.\n3. Verify each acceptance criterion:\n - `actions.write(actionId, 'result', 'APPROVED' or 'BLOCKED: reason')`\n4. If approved:\n - `actions.complete(actionId, 'Task approved')`\n - `tasks.update(taskId, 'done')`\n5. If blocked:\n - `actions.write(actionId, 'blockers', what_is_missing)`\n - `actions.complete(actionId, 'Task blocked: reason')`\n - Notify lead to re-assign to builder.\n\n## Rules\n\n- Never approve unless ALL acceptance criteria are met.\n- Check that health.sh is green before approving.\n- Be specific about what is missing when blocking.\n";
16
+ export declare function featureListJson(tasks: {
17
+ slug: string;
18
+ title: string;
19
+ description?: string;
20
+ acceptance?: string[];
21
+ }[]): string;
22
+ export declare function mergeClaudeMcpJson(filePath: string, port: number): void;
23
+ export declare function mergeOpencodeJson(filePath: string, port: number): void;
24
+ export declare const GITIGNORE_ENTRIES = "\n# agent-harness-kit\n.harness/harness.db\n.harness/harness.db-shm\n.harness/harness.db-wal\n";
25
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAInD,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,eAAO,MAAM,UAAU,4hCA0BtB,CAAA;AAED,eAAO,MAAM,cAAc,24BAsB1B,CAAA;AAED,eAAO,MAAM,aAAa,g9BAwBzB,CAAA;AAED,eAAO,MAAM,cAAc,kjCA2B1B,CAAA;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;AAQD,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;AAID,eAAO,MAAM,iBAAiB,mGAK7B,CAAA"}
@@ -0,0 +1,319 @@
1
+ // ─── health.sh — exits 1 until the dev implements it ─────────────────────────
2
+ export const HEALTH_SH = `#!/usr/bin/env bash
3
+ # health.sh — project health check for agent-harness-kit
4
+ #
5
+ # This script must exit 0 when the project is healthy.
6
+ # Agents will run this before starting work.
7
+ #
8
+ # TODO: implement your project's health checks below.
9
+ # Examples:
10
+ # npm test
11
+ # docker compose ps | grep -q "running"
12
+ # psql -c "SELECT 1" > /dev/null 2>&1
13
+ #
14
+ # Until you implement it, this script intentionally exits 1
15
+ # so agents know the environment is not verified.
16
+
17
+ echo "health.sh not implemented yet."
18
+ echo "Edit this file with your project's health checks."
19
+ echo "It must exit 0 for agents to start working."
20
+ exit 1
21
+ `;
22
+ // ─── AGENTS.md template ───────────────────────────────────────────────────────
23
+ export function agentsMd(config) {
24
+ const { name, description, docsPath } = config.project;
25
+ const port = config.tools.mcp.port;
26
+ return `# AGENTS.md — ${name}
27
+
28
+ > **Read this file first.** It is the navigation map for every AI agent working in this repository.
29
+
30
+ ## Project
31
+
32
+ **${name}** — ${description}
33
+
34
+ ## Health check (run before starting)
35
+
36
+ \`\`\`bash
37
+ bash health.sh
38
+ \`\`\`
39
+
40
+ If it exits non-zero, stop and report the issue. Do not proceed with tasks until health is green.
41
+
42
+ ## Harness data (source of truth)
43
+
44
+ | File | Purpose |
45
+ |------|---------|
46
+ | \`.harness/harness.db\` | SQLite: all tasks, actions, file changes, tool calls |
47
+ | \`.harness/current.md\` | Markdown fallback — read this if MCP server is unavailable |
48
+ | \`.harness/feature_list.json\` | Human-editable task seed list |
49
+
50
+ ## MCP tools (preferred)
51
+
52
+ The harness exposes tools via MCP server on port ${port}. Use these instead of reading files directly.
53
+
54
+ \`\`\`
55
+ actions.start taskId agent → start an action, returns actionId
56
+ actions.write actionId section text → record a section (result, tools_used, ...)
57
+ actions.complete actionId summary → close the action
58
+ actions.get taskId → full action history for a task
59
+ tasks.get [status] → list tasks (pending | in_progress | done | blocked)
60
+ tasks.claim id → atomically claim a pending task
61
+ tasks.update id status → change task status
62
+ docs.search query → search ${docsPath} for relevant content
63
+ \`\`\`
64
+
65
+ ## Workflow
66
+
67
+ \`\`\`
68
+ 1. INIT
69
+ - Run health.sh → exit 1 means stop
70
+ - tasks.get('in_progress') → resume if something is in progress
71
+ - tasks.get('pending') → pick lowest id
72
+
73
+ 2. WORK (lead → explorer → builder → reviewer)
74
+ - Each agent calls actions.start(taskId, agentName) → actionId
75
+ - Records work with actions.write(actionId, section, content)
76
+ - Closes with actions.complete(actionId, summary)
77
+
78
+ 3. CLOSE
79
+ - tasks.update(taskId, 'done')
80
+ - Run health.sh → must be green before closing
81
+ \`\`\`
82
+
83
+ ## Agent roles
84
+
85
+ | Agent | Responsibility |
86
+ |-------|---------------|
87
+ | lead | Decomposes the task into a plan, assigns sub-agents |
88
+ | explorer | Reads and maps relevant code, never writes |
89
+ | builder | Implements the plan, writes files |
90
+ | reviewer | Verifies acceptance criteria, approves or blocks |
91
+
92
+ ## What to read
93
+
94
+ \`\`\`
95
+ Always: .harness/current.md (or MCP tasks.get)
96
+ If implementing: ${docsPath}/
97
+ If orchestrating: Agent definition files in your provider's agents directory
98
+ \`\`\`
99
+ `;
100
+ }
101
+ // ─── agent-harness-kit.config.ts template ───────────────────────────────────────────
102
+ export function configTs(params) {
103
+ return `import { defineHarness } from 'agent-harness-kit'
104
+
105
+ export default defineHarness({
106
+ project: {
107
+ name: '${params.name}',
108
+ description: '${params.description}',
109
+ docsPath: '${params.docsPath}',
110
+ },
111
+
112
+ provider: '${params.provider}',
113
+
114
+ agents: {
115
+ lead: { instructionsPath: null },
116
+ explorer: { instructionsPath: null, allowedPaths: ['${params.docsPath}', './src'] },
117
+ builder: { instructionsPath: null, writablePaths: ['./src', './tests'] },
118
+ reviewer: { instructionsPath: null },
119
+ custom: [],
120
+ },
121
+
122
+ storage: {
123
+ dir: '.harness',
124
+ dbPath: '.harness/harness.db',
125
+ tasks: { adapter: '${params.tasksAdapter}' },
126
+ sections: {
127
+ toolsUsed: true,
128
+ filesModified: true,
129
+ result: true,
130
+ blockers: true,
131
+ nextSteps: false,
132
+ },
133
+ markdownFallback: { enabled: true, path: '.harness/current.md' },
134
+ },
135
+
136
+ health: {
137
+ scriptPath: './health.sh',
138
+ required: true,
139
+ },
140
+
141
+ tools: {
142
+ mcp: { enabled: true, port: ${params.port} },
143
+ scripts: { enabled: true, outputDir: './.harness/scripts' },
144
+ },
145
+ })
146
+ `;
147
+ }
148
+ // ─── Agent definition templates ───────────────────────────────────────────────
149
+ export const AGENT_LEAD = `---
150
+ description: Lead agent — orchestrates the harness workflow for a single task
151
+ ---
152
+
153
+ # Lead Agent
154
+
155
+ You are the **lead agent** in the agent-harness-kit harness. Your job is to decompose a task into a plan and coordinate the other agents.
156
+
157
+ ## Your workflow
158
+
159
+ 1. Read \`.harness/current.md\` (or call \`tasks.get('in_progress')\`) to orient yourself.
160
+ 2. Call \`actions.start(taskId, 'lead')\` to register your action.
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
+ `;
252
+ // ─── feature_list.json initial seed ──────────────────────────────────────────
253
+ export function featureListJson(tasks) {
254
+ return JSON.stringify(tasks, null, 2) + '\n';
255
+ }
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
+ // ─── .gitignore additions ─────────────────────────────────────────────────────
313
+ export const GITIGNORE_ENTRIES = `
314
+ # agent-harness-kit
315
+ .harness/harness.db
316
+ .harness/harness.db-shm
317
+ .harness/harness.db-wal
318
+ `;
319
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/core/materializer/templates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { HarnessConfig } from '../types.js';
2
+ export declare function startMcpServer(config: HarnessConfig, cwd: string): Promise<void>;
3
+ //# sourceMappingURL=mcp-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../src/core/mcp-server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,aAAa,CAAA;AAwH3D,wBAAsB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBtF"}