@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,264 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
4
+ import { readdirSync, readFileSync, statSync } from 'node:fs';
5
+ import { join, resolve } from 'node:path';
6
+ import { openDB } from './db.js';
7
+ const VERSION = '0.1.0';
8
+ // ─── Tool schemas ─────────────────────────────────────────────────────────────
9
+ const TOOLS = [
10
+ {
11
+ name: 'actions.start',
12
+ description: 'Start a new action for a task. Returns an actionId (UUID).',
13
+ inputSchema: {
14
+ type: 'object',
15
+ properties: {
16
+ taskId: { type: 'number', description: 'The task ID from tasks.get' },
17
+ agent: {
18
+ type: 'string',
19
+ description: 'Agent name: lead | explorer | builder | reviewer | custom:<name>',
20
+ },
21
+ },
22
+ required: ['taskId', 'agent'],
23
+ },
24
+ },
25
+ {
26
+ name: 'actions.write',
27
+ description: 'Record a section in an action. Standard sections: result, tools_used, files_modified, blockers, next_steps.',
28
+ inputSchema: {
29
+ type: 'object',
30
+ properties: {
31
+ actionId: { type: 'string', description: 'UUID returned by actions.start' },
32
+ sectionType: {
33
+ type: 'string',
34
+ description: 'Section name: result | tools_used | files_modified | blockers | next_steps | <custom>',
35
+ },
36
+ content: { type: 'string', description: 'Content for this section' },
37
+ },
38
+ required: ['actionId', 'sectionType', 'content'],
39
+ },
40
+ },
41
+ {
42
+ name: 'actions.complete',
43
+ description: 'Close an action with a one-line summary.',
44
+ inputSchema: {
45
+ type: 'object',
46
+ properties: {
47
+ actionId: { type: 'string', description: 'UUID of the action to close' },
48
+ summary: { type: 'string', description: 'One-line summary of what was done' },
49
+ },
50
+ required: ['actionId', 'summary'],
51
+ },
52
+ },
53
+ {
54
+ name: 'actions.get',
55
+ description: 'Get the full action history for a task (all agents, all sections).',
56
+ inputSchema: {
57
+ type: 'object',
58
+ properties: {
59
+ taskId: { type: 'number', description: 'Task ID' },
60
+ },
61
+ required: ['taskId'],
62
+ },
63
+ },
64
+ {
65
+ name: 'tasks.get',
66
+ description: 'List tasks, optionally filtered by status.',
67
+ inputSchema: {
68
+ type: 'object',
69
+ properties: {
70
+ status: {
71
+ type: 'string',
72
+ enum: ['pending', 'in_progress', 'done', 'blocked'],
73
+ description: 'Filter by status (omit for all tasks)',
74
+ },
75
+ },
76
+ },
77
+ },
78
+ {
79
+ name: 'tasks.claim',
80
+ description: 'Atomically claim a pending task. Returns task_already_claimed if another agent got it first.',
81
+ inputSchema: {
82
+ type: 'object',
83
+ properties: {
84
+ id: { type: 'number', description: 'Task ID to claim' },
85
+ agent: { type: 'string', description: 'Your agent name' },
86
+ },
87
+ required: ['id', 'agent'],
88
+ },
89
+ },
90
+ {
91
+ name: 'tasks.update',
92
+ description: 'Change the status of a task.',
93
+ inputSchema: {
94
+ type: 'object',
95
+ properties: {
96
+ id: { type: 'number', description: 'Task ID' },
97
+ status: {
98
+ type: 'string',
99
+ enum: ['pending', 'in_progress', 'done', 'blocked'],
100
+ },
101
+ },
102
+ required: ['id', 'status'],
103
+ },
104
+ },
105
+ {
106
+ name: 'docs.search',
107
+ description: 'Search the project docs folder for content matching a query.',
108
+ inputSchema: {
109
+ type: 'object',
110
+ properties: {
111
+ query: { type: 'string', description: 'Search terms' },
112
+ },
113
+ required: ['query'],
114
+ },
115
+ },
116
+ ];
117
+ // ─── Server ───────────────────────────────────────────────────────────────────
118
+ export async function startMcpServer(config, cwd) {
119
+ const db = openDB(config, cwd);
120
+ const docsPath = resolve(cwd, config.project.docsPath);
121
+ const server = new Server({ name: 'agent-harness-kit', version: VERSION }, { capabilities: { tools: {} } });
122
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
123
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
124
+ const { name, arguments: args } = request.params;
125
+ const a = (args ?? {});
126
+ try {
127
+ const result = await dispatch(name, a, db, docsPath);
128
+ return result;
129
+ }
130
+ catch (err) {
131
+ return ok(`Error: ${err instanceof Error ? err.message : String(err)}`, true);
132
+ }
133
+ });
134
+ const transport = new StdioServerTransport();
135
+ await server.connect(transport);
136
+ }
137
+ // ─── Dispatch ─────────────────────────────────────────────────────────────────
138
+ async function dispatch(name, args, db, docsPath) {
139
+ switch (name) {
140
+ case 'actions.start': {
141
+ const taskId = num(args, 'taskId');
142
+ const agent = str(args, 'agent');
143
+ const action = db.startAction(taskId, agent);
144
+ return ok(JSON.stringify({ actionId: action.id, taskId, agent, status: 'in_progress' }));
145
+ }
146
+ case 'actions.write': {
147
+ const actionId = str(args, 'actionId');
148
+ const sectionType = str(args, 'sectionType');
149
+ const content = str(args, 'content');
150
+ db.writeSection(actionId, sectionType, content);
151
+ return ok(JSON.stringify({ actionId, sectionType, recorded: true }));
152
+ }
153
+ case 'actions.complete': {
154
+ const actionId = str(args, 'actionId');
155
+ const summary = str(args, 'summary');
156
+ const action = db.completeAction(actionId, summary);
157
+ return ok(JSON.stringify({ actionId, status: action.status, completedAt: action.completed_at }));
158
+ }
159
+ case 'actions.get': {
160
+ const taskId = num(args, 'taskId');
161
+ const actions = db.getActionsForTask(taskId);
162
+ const full = actions.map((a) => ({
163
+ ...a,
164
+ sections: db.getActionSections(a.id),
165
+ }));
166
+ return ok(JSON.stringify(full, null, 2));
167
+ }
168
+ case 'tasks.get': {
169
+ const status = args['status'];
170
+ const tasks = status
171
+ ? db.getTasks(status)
172
+ : db.getTasks();
173
+ return ok(JSON.stringify(tasks, null, 2));
174
+ }
175
+ case 'tasks.claim': {
176
+ const id = num(args, 'id');
177
+ const agent = str(args, 'agent');
178
+ const task = db.claimTask(id, agent);
179
+ if (!task) {
180
+ return ok(JSON.stringify({ error: 'task_already_claimed', taskId: id }));
181
+ }
182
+ return ok(JSON.stringify(task));
183
+ }
184
+ case 'tasks.update': {
185
+ const id = num(args, 'id');
186
+ const status = str(args, 'status');
187
+ const task = db.updateTaskStatus(id, status);
188
+ return ok(JSON.stringify(task));
189
+ }
190
+ case 'docs.search': {
191
+ const query = str(args, 'query');
192
+ const results = searchDocs(docsPath, query);
193
+ return ok(JSON.stringify(results, null, 2));
194
+ }
195
+ default:
196
+ return ok(`Unknown tool: ${name}`, true);
197
+ }
198
+ }
199
+ function searchDocs(docsPath, query, maxResults = 10) {
200
+ const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
201
+ const results = [];
202
+ try {
203
+ const files = collectMarkdownFiles(docsPath);
204
+ for (const file of files) {
205
+ if (results.length >= maxResults)
206
+ break;
207
+ try {
208
+ const content = readFileSync(file, 'utf8');
209
+ const lines = content.split('\n');
210
+ for (let i = 0; i < lines.length; i++) {
211
+ const lower = lines[i].toLowerCase();
212
+ if (terms.every((t) => lower.includes(t))) {
213
+ results.push({ file: file.replace(docsPath + '/', ''), line: i + 1, text: lines[i].trim() });
214
+ if (results.length >= maxResults)
215
+ break;
216
+ }
217
+ }
218
+ }
219
+ catch {
220
+ // skip unreadable files
221
+ }
222
+ }
223
+ }
224
+ catch {
225
+ return [{ file: '', line: 0, text: `docs path not found: ${docsPath}` }];
226
+ }
227
+ return results;
228
+ }
229
+ function collectMarkdownFiles(dir) {
230
+ const files = [];
231
+ try {
232
+ for (const entry of readdirSync(dir)) {
233
+ const full = join(dir, entry);
234
+ const stat = statSync(full);
235
+ if (stat.isDirectory()) {
236
+ files.push(...collectMarkdownFiles(full));
237
+ }
238
+ else if (entry.endsWith('.md') || entry.endsWith('.txt')) {
239
+ files.push(full);
240
+ }
241
+ }
242
+ }
243
+ catch {
244
+ // directory may not exist yet
245
+ }
246
+ return files;
247
+ }
248
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
249
+ function ok(text, isError = false) {
250
+ return { content: [{ type: 'text', text }], isError };
251
+ }
252
+ function str(args, key) {
253
+ const v = args[key];
254
+ if (typeof v !== 'string')
255
+ throw new Error(`${key} must be a string`);
256
+ return v;
257
+ }
258
+ function num(args, key) {
259
+ const v = args[key];
260
+ if (typeof v !== 'number')
261
+ throw new Error(`${key} must be a number`);
262
+ return v;
263
+ }
264
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../src/core/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GAEvB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEzC,OAAO,EAAE,MAAM,EAAkB,MAAM,SAAS,CAAA;AAEhD,MAAM,OAAO,GAAG,OAAO,CAAA;AAEvB,iFAAiF;AAEjF,MAAM,KAAK,GAAG;IACZ;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,4DAA4D;QACzE,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,4BAA4B,EAAE;gBACrE,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,kEAAkE;iBAChF;aACF;YACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;SAC9B;KACF;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EACT,6GAA6G;QAC/G,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gCAAgC,EAAE;gBAC3E,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,uFAAuF;iBACrG;gBACD,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0BAA0B,EAAE;aACrE;YACD,QAAQ,EAAE,CAAC,UAAU,EAAE,aAAa,EAAE,SAAS,CAAC;SACjD;KACF;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,0CAA0C;QACvD,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6BAA6B,EAAE;gBACxE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mCAAmC,EAAE;aAC9E;YACD,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC;SAClC;KACF;IACD;QACE,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,oEAAoE;QACjF,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE;aACnD;YACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACrB;KACF;IACD;QACE,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,4CAA4C;QACzD,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC;oBACnD,WAAW,EAAE,uCAAuC;iBACrD;aACF;SACF;KACF;IACD;QACE,IAAI,EAAE,aAAa;QACnB,WAAW,EACT,8FAA8F;QAChG,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kBAAkB,EAAE;gBACvD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE;aAC1D;YACD,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;SAC1B;KACF;IACD;QACE,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,8BAA8B;QAC3C,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE;gBAC9C,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC;iBACpD;aACF;YACD,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC;SAC3B;KACF;IACD;QACE,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,8DAA8D;QAC3E,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE;aACvD;YACD,QAAQ,EAAE,CAAC,OAAO,CAAC;SACpB;KACF;CACO,CAAA;AAEV,iFAAiF;AAEjF,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAqB,EAAE,GAAW;IACrE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAEtD,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,EAAE,EAC/C,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAA;IAED,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IAEhF,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAA;QAChD,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAA;QAEjD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAA;YACpD,OAAO,MAAM,CAAA;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;QAC/E,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;AACjC,CAAC;AAED,iFAAiF;AAEjF,KAAK,UAAU,QAAQ,CACrB,IAAY,EACZ,IAA6B,EAC7B,EAAa,EACb,QAAgB;IAEhB,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;YAClC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,OAAO,CAAc,CAAA;YAC7C,MAAM,MAAM,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;YAC5C,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC,CAAA;QAC1F,CAAC;QAED,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;YACtC,MAAM,WAAW,GAAG,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;YAC5C,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;YACpC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;YAC/C,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QACtE,CAAC;QAED,KAAK,kBAAkB,CAAC,CAAC,CAAC;YACxB,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;YACtC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;YACpC,MAAM,MAAM,GAAG,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;YACnD,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;QAClG,CAAC;QAED,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;YAClC,MAAM,OAAO,GAAG,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAA;YAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC/B,GAAG,CAAC;gBACJ,QAAQ,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;aACrC,CAAC,CAAC,CAAA;YACH,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAC1C,CAAC;QAED,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAuB,CAAA;YACnD,MAAM,KAAK,GAAG,MAAM;gBAClB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAA0C,CAAC;gBACzD,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAA;YACjB,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAC3C,CAAC;QAED,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YAC1B,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAChC,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;YACpC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;YAC1E,CAAC;YACD,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;QACjC,CAAC;QAED,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAqC,CAAA;YACtE,MAAM,IAAI,GAAG,EAAE,CAAC,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;YAC5C,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;QACjC,CAAC;QAED,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAChC,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;YAC3C,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAC7C,CAAC;QAED;YACE,OAAO,EAAE,CAAC,iBAAiB,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC;AAUD,SAAS,UAAU,CAAC,QAAgB,EAAE,KAAa,EAAE,UAAU,GAAG,EAAE;IAClE,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC9D,MAAM,OAAO,GAAiB,EAAE,CAAA;IAEhC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAA;QAC5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,OAAO,CAAC,MAAM,IAAI,UAAU;gBAAE,MAAK;YACvC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;gBAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;gBACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACtC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;oBACpC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC1C,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;wBAC5F,IAAI,OAAO,CAAC,MAAM,IAAI,UAAU;4BAAE,MAAK;oBACzC,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,wBAAwB,QAAQ,EAAE,EAAE,CAAC,CAAA;IAC1E,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAW;IACvC,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,CAAC;QACH,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YAC7B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;YAC3B,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACvB,KAAK,CAAC,IAAI,CAAC,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAA;YAC3C,CAAC;iBAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;IAChC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,iFAAiF;AAEjF,SAAS,EAAE,CAAC,IAAY,EAAE,OAAO,GAAG,KAAK;IACvC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAA;AAChE,CAAC;AAED,SAAS,GAAG,CAAC,IAA6B,EAAE,GAAW;IACrD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAA;IACnB,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,mBAAmB,CAAC,CAAA;IACrE,OAAO,CAAC,CAAA;AACV,CAAC;AAED,SAAS,GAAG,CAAC,IAA6B,EAAE,GAAW;IACrD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAA;IACnB,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,mBAAmB,CAAC,CAAA;IACrE,OAAO,CAAC,CAAA;AACV,CAAC"}
@@ -0,0 +1,14 @@
1
+ export type SQLRow = Record<string, unknown>;
2
+ export interface SQLStatement {
3
+ run(...args: unknown[]): unknown;
4
+ get(...args: unknown[]): SQLRow | undefined;
5
+ all(...args: unknown[]): SQLRow[];
6
+ }
7
+ export interface SQLiteDB {
8
+ exec(sql: string): void;
9
+ prepare(sql: string): SQLStatement;
10
+ close(): void;
11
+ }
12
+ export declare function openSQLite(path: string): SQLiteDB;
13
+ export declare function lastInsertId(db: SQLiteDB): number;
14
+ //# sourceMappingURL=sqlite-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-adapter.d.ts","sourceRoot":"","sources":["../../src/core/sqlite-adapter.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE5C,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAChC,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,SAAS,CAAA;IAC3C,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;IAClC,KAAK,IAAI,IAAI,CAAA;CACd;AAID,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAYjD;AAMD,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,CAGjD"}
@@ -0,0 +1,20 @@
1
+ import { createRequire } from 'node:module';
2
+ const _require = createRequire(import.meta.url);
3
+ const isBun = 'bun' in process.versions;
4
+ // ─── Factory ─────────────────────────────────────────────────────────────────
5
+ export function openSQLite(path) {
6
+ if (isBun) {
7
+ const { Database } = _require('bun:sqlite');
8
+ return new Database(path);
9
+ }
10
+ const { DatabaseSync } = _require('node:sqlite');
11
+ return new DatabaseSync(path);
12
+ }
13
+ // ─── last_insert_rowid() helper ───────────────────────────────────────────────
14
+ // Both bun:sqlite and node:sqlite have different return types for stmt.run().
15
+ // Reading last_insert_rowid() directly avoids the inconsistency.
16
+ export function lastInsertId(db) {
17
+ const row = db.prepare('SELECT last_insert_rowid() AS id').get();
18
+ return row.id;
19
+ }
20
+ //# sourceMappingURL=sqlite-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-adapter.js","sourceRoot":"","sources":["../../src/core/sqlite-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC/C,MAAM,KAAK,GAAG,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAA;AAmBvC,gFAAgF;AAEhF,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC,YAAY,CAEzC,CAAA;QACD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAwB,CAAA;IAClD,CAAC;IAED,MAAM,EAAE,YAAY,EAAE,GAAG,QAAQ,CAAC,aAAa,CAE9C,CAAA;IACD,OAAO,IAAI,YAAY,CAAC,IAAI,CAAwB,CAAA;AACtD,CAAC;AAED,iFAAiF;AACjF,8EAA8E;AAC9E,iEAAiE;AAEjE,MAAM,UAAU,YAAY,CAAC,EAAY;IACvC,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,EAAoB,CAAA;IAClF,OAAO,GAAG,CAAC,EAAE,CAAA;AACf,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { defineHarness } from './core/config.js';
2
+ export type { HarnessConfig, ProjectConfig, AgentsConfig, AgentConfig, CustomAgentConfig, StorageConfig, HealthConfig, ToolsConfig, ActionSections, TasksAdapter, Provider, TaskStatus, AgentName, ActionStatus, TaskRow, ActionRow, TaskSeed, } from './types.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,YAAY,EACV,aAAa,EACb,aAAa,EACb,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,cAAc,EACd,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,SAAS,EACT,YAAY,EACZ,OAAO,EACP,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { defineHarness } from './core/config.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=db.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.test.d.ts","sourceRoot":"","sources":["../../src/tests/db.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,106 @@
1
+ import { test, describe, beforeEach, afterEach } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { rmSync, mkdirSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { HarnessDB } from '../core/db.js';
6
+ const TMP = join(import.meta.dirname, '../../.tmp-test');
7
+ const config = {
8
+ project: { name: 'test', description: 'test project', docsPath: './docs' },
9
+ provider: 'claude-code',
10
+ agents: {
11
+ lead: { instructionsPath: null },
12
+ explorer: { instructionsPath: null, allowedPaths: [] },
13
+ builder: { instructionsPath: null, writablePaths: [] },
14
+ reviewer: { instructionsPath: null },
15
+ custom: [],
16
+ },
17
+ storage: {
18
+ dir: '.harness',
19
+ dbPath: join(TMP, 'test.db'),
20
+ tasks: { adapter: 'local' },
21
+ sections: { toolsUsed: true, filesModified: true, result: true, blockers: true, nextSteps: false },
22
+ markdownFallback: { enabled: false, path: join(TMP, 'current.md') },
23
+ },
24
+ health: { scriptPath: './health.sh', required: false },
25
+ tools: {
26
+ mcp: { enabled: false, port: 3456 },
27
+ scripts: { enabled: false, outputDir: '.harness/scripts' },
28
+ },
29
+ };
30
+ describe('HarnessDB', () => {
31
+ let db;
32
+ beforeEach(() => {
33
+ mkdirSync(TMP, { recursive: true });
34
+ db = new HarnessDB(config.storage.dbPath, config);
35
+ });
36
+ afterEach(() => {
37
+ db.close();
38
+ rmSync(TMP, { recursive: true, force: true });
39
+ });
40
+ test('addTask creates a task with pending status', () => {
41
+ const task = db.addTask({ slug: 'my-feature', title: 'My Feature' });
42
+ assert.equal(task.slug, 'my-feature');
43
+ assert.equal(task.title, 'My Feature');
44
+ assert.equal(task.status, 'pending');
45
+ assert.ok(task.id > 0);
46
+ });
47
+ test('getTasks returns all tasks', () => {
48
+ db.addTask({ slug: 'a', title: 'Task A' });
49
+ db.addTask({ slug: 'b', title: 'Task B' });
50
+ const tasks = db.getTasks();
51
+ assert.equal(tasks.length, 2);
52
+ });
53
+ test('getTasks filters by status', () => {
54
+ db.addTask({ slug: 'a', title: 'Task A' });
55
+ db.addTask({ slug: 'b', title: 'Task B' });
56
+ db.updateTaskStatus('a', 'in_progress');
57
+ const pending = db.getTasks('pending');
58
+ assert.equal(pending.length, 1);
59
+ assert.equal(pending[0].slug, 'b');
60
+ });
61
+ test('claimTask atomically claims a pending task', () => {
62
+ const task = db.addTask({ slug: 'work', title: 'Work' });
63
+ const claimed = db.claimTask(task.id, 'lead');
64
+ assert.ok(claimed);
65
+ assert.equal(claimed.status, 'in_progress');
66
+ assert.equal(claimed.assigned_to, 'lead');
67
+ });
68
+ test('claimTask returns null for already claimed task', () => {
69
+ const task = db.addTask({ slug: 'work2', title: 'Work2' });
70
+ db.claimTask(task.id, 'lead');
71
+ const second = db.claimTask(task.id, 'builder');
72
+ assert.equal(second, null);
73
+ });
74
+ test('startAction / writeSection / completeAction full lifecycle', () => {
75
+ const task = db.addTask({ slug: 'feat', title: 'Feature' });
76
+ const action = db.startAction(task.id, 'lead');
77
+ assert.equal(action.status, 'in_progress');
78
+ db.writeSection(action.id, 'result', 'Plan is done');
79
+ const sections = db.getActionSections(action.id);
80
+ assert.equal(sections.length, 1);
81
+ assert.equal(sections[0].content, 'Plan is done');
82
+ const completed = db.completeAction(action.id, 'Plan defined');
83
+ assert.equal(completed.status, 'completed');
84
+ assert.equal(completed.summary, 'Plan defined');
85
+ });
86
+ test('addTask with acceptance criteria', () => {
87
+ const task = db.addTask({
88
+ slug: 'with-ac',
89
+ title: 'With AC',
90
+ acceptance: ['Must pass tests', 'Must be reviewed'],
91
+ });
92
+ const ac = db.getTaskAcceptance(task.id);
93
+ assert.equal(ac.length, 2);
94
+ assert.equal(ac[0].criterion, 'Must pass tests');
95
+ });
96
+ test('syncFromFeatureList skips duplicates', () => {
97
+ db.addTask({ slug: 'exists', title: 'Exists' });
98
+ const result = db.syncFromFeatureList([
99
+ { slug: 'exists', title: 'Exists' },
100
+ { slug: 'new-one', title: 'New One' },
101
+ ]);
102
+ assert.equal(result.added, 1);
103
+ assert.equal(result.skipped, 1);
104
+ });
105
+ });
106
+ //# sourceMappingURL=db.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.test.js","sourceRoot":"","sources":["../../src/tests/db.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=slugify.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slugify.test.d.ts","sourceRoot":"","sources":["../../src/tests/slugify.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ import { test, describe } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ // Inline slugify — mirrors the logic in both materializers
4
+ function slugify(title) {
5
+ return title
6
+ .toLowerCase()
7
+ .replace(/[^a-z0-9]+/g, '-')
8
+ .replace(/^-+|-+$/g, '')
9
+ .slice(0, 64);
10
+ }
11
+ describe('slugify', () => {
12
+ test('lowercases and replaces spaces', () => {
13
+ assert.equal(slugify('My Feature'), 'my-feature');
14
+ });
15
+ test('strips leading and trailing dashes', () => {
16
+ assert.equal(slugify(' hello '), 'hello');
17
+ });
18
+ test('collapses multiple special chars', () => {
19
+ assert.equal(slugify('foo!!!bar'), 'foo-bar');
20
+ });
21
+ test('truncates at 64 chars', () => {
22
+ const long = 'a'.repeat(100);
23
+ assert.equal(slugify(long).length, 64);
24
+ });
25
+ });
26
+ //# sourceMappingURL=slugify.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slugify.test.js","sourceRoot":"","sources":["../../src/tests/slugify.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,MAAM,MAAM,oBAAoB,CAAA;AAEvC,2DAA2D;AAC3D,SAAS,OAAO,CAAC,KAAa;IAC5B,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;AAED,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,IAAI,CAAC,gCAAgC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,SAAS,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACjC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC5B,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=templates.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.test.d.ts","sourceRoot":"","sources":["../../src/tests/templates.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,64 @@
1
+ import { test, describe } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { mergeClaudeMcpJson, mergeOpencodeJson, featureListJson } from '../core/materializer/templates.js';
6
+ const TMP = join(import.meta.dirname, '../../.tmp-templates');
7
+ function setup() { mkdirSync(TMP, { recursive: true }); }
8
+ function teardown() { rmSync(TMP, { recursive: true, force: true }); }
9
+ describe('mergeClaudeMcpJson', () => {
10
+ test('creates file when it does not exist', () => {
11
+ setup();
12
+ const path = join(TMP, 'mcp.json');
13
+ mergeClaudeMcpJson(path, 3456);
14
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
15
+ assert.ok(parsed.mcpServers['agent-harness-kit']);
16
+ assert.equal(parsed.mcpServers['agent-harness-kit'].args[3], '3456');
17
+ teardown();
18
+ });
19
+ test('preserves existing mcpServers entries', () => {
20
+ setup();
21
+ const path = join(TMP, 'mcp2.json');
22
+ const initial = { mcpServers: { 'other-tool': { command: 'foo', args: [] } } };
23
+ writeFileSync(path, JSON.stringify(initial));
24
+ mergeClaudeMcpJson(path, 3456);
25
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
26
+ assert.ok(parsed.mcpServers['other-tool']);
27
+ assert.ok(parsed.mcpServers['agent-harness-kit']);
28
+ teardown();
29
+ });
30
+ });
31
+ describe('mergeOpencodeJson', () => {
32
+ test('creates file when it does not exist', () => {
33
+ setup();
34
+ const path = join(TMP, 'opencode.json');
35
+ mergeOpencodeJson(path, 3456);
36
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
37
+ assert.ok(parsed.mcp.servers['agent-harness-kit']);
38
+ teardown();
39
+ });
40
+ test('preserves existing mcp.servers entries', () => {
41
+ setup();
42
+ const path = join(TMP, 'opencode2.json');
43
+ const initial = { mcp: { servers: { 'other': { command: 'bar', args: [] } } } };
44
+ writeFileSync(path, JSON.stringify(initial));
45
+ mergeOpencodeJson(path, 3456);
46
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
47
+ assert.ok(parsed.mcp.servers['other']);
48
+ assert.ok(parsed.mcp.servers['agent-harness-kit']);
49
+ teardown();
50
+ });
51
+ });
52
+ describe('featureListJson', () => {
53
+ test('serializes empty list', () => {
54
+ const result = featureListJson([]);
55
+ assert.equal(result.trim(), '[]');
56
+ });
57
+ test('serializes tasks correctly', () => {
58
+ const result = featureListJson([{ slug: 'foo', title: 'Foo', acceptance: ['Must work'] }]);
59
+ const parsed = JSON.parse(result);
60
+ assert.equal(parsed[0].slug, 'foo');
61
+ assert.deepEqual(parsed[0].acceptance, ['Must work']);
62
+ });
63
+ });
64
+ //# sourceMappingURL=templates.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.test.js","sourceRoot":"","sources":["../../src/tests/templates.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AAE1G,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAA;AAE7D,SAAS,KAAK,KAAK,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA,CAAC,CAAC;AACxD,SAAS,QAAQ,KAAK,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA,CAAC,CAAC;AAErE,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC/C,KAAK,EAAE,CAAA;QACP,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;QAClC,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QACrD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAA;QACjD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;QACpE,QAAQ,EAAE,CAAA;IACZ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,uCAAuC,EAAE,GAAG,EAAE;QACjD,KAAK,EAAE,CAAA;QACP,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;QACnC,MAAM,OAAO,GAAG,EAAE,UAAU,EAAE,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,CAAA;QAC9E,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;QAC5C,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QACrD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAA;QAC1C,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAA;QACjD,QAAQ,EAAE,CAAA;IACZ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC/C,KAAK,EAAE,CAAA;QACP,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAA;QACvC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QACrD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAA;QAClD,QAAQ,EAAE,CAAA;IACZ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAClD,KAAK,EAAE,CAAA;QACP,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAA;QACxC,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAA;QAC/E,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;QAC5C,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QACrD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;QACtC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAA;QAClD,QAAQ,EAAE,CAAA;IACZ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACjC,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,CAAC,CAAA;QAClC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACtC,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAA;QAC1F,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACjC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACnC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}