@cardor/agent-harness-kit 1.5.1 → 1.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/dist/agent-templates/reviewer.md +1 -0
- package/dist/cli.js +139 -64
- package/dist/cli.js.map +1 -1
- package/dist/dashboard-dist/assets/index-6UCLKb-M.css +1 -0
- package/dist/dashboard-dist/assets/{index-Bxz3ZqFc.js → index-CoqlHfTu.js} +4 -4
- package/dist/dashboard-dist/index.html +10 -7
- package/dist/dashboard-dist/logo-512.png +0 -0
- package/dist/dashboard-dist/logo.png +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/{mysql-NXLYFD2H.js → mysql-THKQOXIS.js} +8 -2
- package/dist/mysql-THKQOXIS.js.map +1 -0
- package/dist/{postgres-6BXN7ZH4.js → postgres-IOQE32DM.js} +8 -2
- package/dist/postgres-IOQE32DM.js.map +1 -0
- package/dist/{sqlite-M65L55DA.js → sqlite-XBEJJ5T2.js} +8 -2
- package/dist/sqlite-XBEJJ5T2.js.map +1 -0
- package/package.json +1 -1
- package/dist/dashboard-dist/assets/index-EE0Trm7c.css +0 -1
- package/dist/mysql-NXLYFD2H.js.map +0 -1
- package/dist/postgres-6BXN7ZH4.js.map +0 -1
- package/dist/sqlite-M65L55DA.js.map +0 -1
|
@@ -119,6 +119,7 @@ Then notify lead so the builder can be re-assigned.
|
|
|
119
119
|
|
|
120
120
|
- **Run health.sh before approving.** No exceptions.
|
|
121
121
|
- **Check every acceptance criterion.** Not just the obvious ones.
|
|
122
|
+
- **Use `tasks.acceptance.get(taskId)` to retrieve criterion ids.** Call this before `tasks.acceptance.update()` when you do not already have criterion ids from `tasks.get`.
|
|
122
123
|
- **Call `tasks.acceptance.update()` for each criterion.** Never skip this step.
|
|
123
124
|
- **Never self-approve partial work.** All criteria must be met, not most.
|
|
124
125
|
- **Be specific when blocking.** The builder must know exactly what to fix.
|
package/dist/cli.js
CHANGED
|
@@ -67,7 +67,7 @@ function mergeClaudeSettingsJson(filePath) {
|
|
|
67
67
|
};
|
|
68
68
|
writeFileSync2(filePath, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
69
69
|
}
|
|
70
|
-
var
|
|
70
|
+
var MCP_CLAUDE_PERMISSIONS_LEAD = [
|
|
71
71
|
"mcp__agent-harness-kit__actions_start",
|
|
72
72
|
"mcp__agent-harness-kit__actions_write",
|
|
73
73
|
"mcp__agent-harness-kit__actions_complete",
|
|
@@ -76,14 +76,69 @@ var MCP_PERMISSIONS = [
|
|
|
76
76
|
"mcp__agent-harness-kit__actions_record_tool",
|
|
77
77
|
"mcp__agent-harness-kit__tasks_get",
|
|
78
78
|
"mcp__agent-harness-kit__tasks_claim",
|
|
79
|
+
"mcp__agent-harness-kit__tasks_add",
|
|
79
80
|
"mcp__agent-harness-kit__tasks_update",
|
|
81
|
+
"mcp__agent-harness-kit__tasks_edit",
|
|
82
|
+
"mcp__agent-harness-kit__tasks_archive",
|
|
83
|
+
"mcp__agent-harness-kit__tasks_unarchive",
|
|
84
|
+
"mcp__agent-harness-kit__tasks_acceptance_get",
|
|
85
|
+
"mcp__agent-harness-kit__docs_search"
|
|
86
|
+
];
|
|
87
|
+
var MCP_CLAUDE_PERMISSIONS_EXPLORER = [
|
|
88
|
+
"mcp__agent-harness-kit__actions_start",
|
|
89
|
+
"mcp__agent-harness-kit__actions_write",
|
|
90
|
+
"mcp__agent-harness-kit__actions_complete",
|
|
91
|
+
"mcp__agent-harness-kit__actions_get",
|
|
92
|
+
"mcp__agent-harness-kit__actions_record_file",
|
|
93
|
+
"mcp__agent-harness-kit__actions_record_tool",
|
|
94
|
+
"mcp__agent-harness-kit__tasks_get",
|
|
95
|
+
"mcp__agent-harness-kit__tasks_claim",
|
|
96
|
+
"mcp__agent-harness-kit__tasks_acceptance_get",
|
|
97
|
+
"mcp__agent-harness-kit__docs_search"
|
|
98
|
+
];
|
|
99
|
+
var MCP_CLAUDE_PERMISSIONS_BUILDER = [
|
|
100
|
+
"mcp__agent-harness-kit__actions_start",
|
|
101
|
+
"mcp__agent-harness-kit__actions_write",
|
|
102
|
+
"mcp__agent-harness-kit__actions_complete",
|
|
103
|
+
"mcp__agent-harness-kit__actions_get",
|
|
104
|
+
"mcp__agent-harness-kit__actions_record_file",
|
|
105
|
+
"mcp__agent-harness-kit__actions_record_tool",
|
|
106
|
+
"mcp__agent-harness-kit__tasks_get",
|
|
107
|
+
"mcp__agent-harness-kit__tasks_claim",
|
|
80
108
|
"mcp__agent-harness-kit__tasks_add",
|
|
81
|
-
"mcp__agent-harness-
|
|
109
|
+
"mcp__agent-harness-kit__tasks_update",
|
|
82
110
|
"mcp__agent-harness-kit__tasks_edit",
|
|
83
111
|
"mcp__agent-harness-kit__tasks_archive",
|
|
84
112
|
"mcp__agent-harness-kit__tasks_unarchive",
|
|
113
|
+
"mcp__agent-harness-kit__tasks_acceptance_get",
|
|
85
114
|
"mcp__agent-harness-kit__docs_search"
|
|
86
115
|
];
|
|
116
|
+
var MCP_CLAUDE_PERMISSIONS_REVIEWER = [
|
|
117
|
+
"mcp__agent-harness-kit__actions_start",
|
|
118
|
+
"mcp__agent-harness-kit__actions_write",
|
|
119
|
+
"mcp__agent-harness-kit__actions_complete",
|
|
120
|
+
"mcp__agent-harness-kit__actions_get",
|
|
121
|
+
"mcp__agent-harness-kit__actions_record_file",
|
|
122
|
+
"mcp__agent-harness-kit__actions_record_tool",
|
|
123
|
+
"mcp__agent-harness-kit__tasks_get",
|
|
124
|
+
"mcp__agent-harness-kit__tasks_claim",
|
|
125
|
+
"mcp__agent-harness-kit__tasks_add",
|
|
126
|
+
"mcp__agent-harness-kit__tasks_update",
|
|
127
|
+
"mcp__agent-harness-kit__tasks_edit",
|
|
128
|
+
"mcp__agent-harness-kit__tasks_archive",
|
|
129
|
+
"mcp__agent-harness-kit__tasks_unarchive",
|
|
130
|
+
"mcp__agent-harness-kit__tasks_acceptance_update",
|
|
131
|
+
"mcp__agent-harness-kit__tasks_acceptance_get",
|
|
132
|
+
"mcp__agent-harness-kit__docs_search"
|
|
133
|
+
];
|
|
134
|
+
var MCP_CLAUDE_PERMISSIONS = [
|
|
135
|
+
.../* @__PURE__ */ new Set([
|
|
136
|
+
...MCP_CLAUDE_PERMISSIONS_LEAD,
|
|
137
|
+
...MCP_CLAUDE_PERMISSIONS_EXPLORER,
|
|
138
|
+
...MCP_CLAUDE_PERMISSIONS_BUILDER,
|
|
139
|
+
...MCP_CLAUDE_PERMISSIONS_REVIEWER
|
|
140
|
+
])
|
|
141
|
+
];
|
|
87
142
|
function mergeClaudeSettingsLocalJson(filePath) {
|
|
88
143
|
mkdirSync2(dirname(filePath), { recursive: true });
|
|
89
144
|
let existing = {};
|
|
@@ -96,7 +151,7 @@ function mergeClaudeSettingsLocalJson(filePath) {
|
|
|
96
151
|
const existingPermissions = existing.permissions ?? {};
|
|
97
152
|
const existingAllow = existingPermissions.allow ?? [];
|
|
98
153
|
const existingServers = existing.enabledMcpjsonServers ?? [];
|
|
99
|
-
const mergedAllow = Array.from(/* @__PURE__ */ new Set([...existingAllow, ...
|
|
154
|
+
const mergedAllow = Array.from(/* @__PURE__ */ new Set([...existingAllow, ...MCP_CLAUDE_PERMISSIONS]));
|
|
100
155
|
const mergedServers = Array.from(/* @__PURE__ */ new Set([...existingServers, "agent-harness-kit"]));
|
|
101
156
|
const merged = {
|
|
102
157
|
...existing,
|
|
@@ -491,47 +546,15 @@ function agentReviewerToml(vars) {
|
|
|
491
546
|
const { description, body } = stripFrontmatter(loadAgentTemplate("reviewer", vars));
|
|
492
547
|
return toCodexToml("reviewer", description, body, "read-only");
|
|
493
548
|
}
|
|
494
|
-
var CLAUDE_CODE_MCP_TOOLS = {
|
|
495
|
-
lead: [
|
|
496
|
-
// 'mcp__agent-harness-kit__actions.start',
|
|
497
|
-
// 'mcp__agent-harness-kit__actions.write',
|
|
498
|
-
// 'mcp__agent-harness-kit__actions.complete',
|
|
499
|
-
// 'mcp__agent-harness-kit__actions.get',
|
|
500
|
-
// 'mcp__agent-harness-kit__actions.record_tool',
|
|
501
|
-
// 'mcp__agent-harness-kit__tasks.get',
|
|
502
|
-
// 'mcp__agent-harness-kit__tasks.claim',
|
|
503
|
-
// 'mcp__agent-harness-kit__tasks.update',
|
|
504
|
-
// 'mcp__agent-harness-kit__tasks.add',
|
|
505
|
-
],
|
|
506
|
-
explorer: [
|
|
507
|
-
// 'mcp__agent-harness-kit__actions.start',
|
|
508
|
-
// 'mcp__agent-harness-kit__actions.write',
|
|
509
|
-
// 'mcp__agent-harness-kit__actions.complete',
|
|
510
|
-
// 'mcp__agent-harness-kit__actions.get',
|
|
511
|
-
// 'mcp__agent-harness-kit__actions.record_tool',
|
|
512
|
-
// 'mcp__agent-harness-kit__docs.search',
|
|
513
|
-
],
|
|
514
|
-
builder: [
|
|
515
|
-
// 'mcp__agent-harness-kit__actions.start',
|
|
516
|
-
// 'mcp__agent-harness-kit__actions.write',
|
|
517
|
-
// 'mcp__agent-harness-kit__actions.complete',
|
|
518
|
-
// 'mcp__agent-harness-kit__actions.get',
|
|
519
|
-
// 'mcp__agent-harness-kit__actions.record_tool',
|
|
520
|
-
// 'mcp__agent-harness-kit__actions.record_file',
|
|
521
|
-
],
|
|
522
|
-
reviewer: [
|
|
523
|
-
// 'mcp__agent-harness-kit__actions.start',
|
|
524
|
-
// 'mcp__agent-harness-kit__actions.write',
|
|
525
|
-
// 'mcp__agent-harness-kit__actions.complete',
|
|
526
|
-
// 'mcp__agent-harness-kit__actions.get',
|
|
527
|
-
// 'mcp__agent-harness-kit__actions.record_tool',
|
|
528
|
-
// 'mcp__agent-harness-kit__tasks.acceptance.update',
|
|
529
|
-
// 'mcp__agent-harness-kit__tasks.update',
|
|
530
|
-
]
|
|
531
|
-
};
|
|
532
549
|
function translateFrontmatterForClaudeCode(md, agentName) {
|
|
533
|
-
const
|
|
534
|
-
|
|
550
|
+
const permissionsMap = {
|
|
551
|
+
lead: MCP_CLAUDE_PERMISSIONS_LEAD,
|
|
552
|
+
explorer: MCP_CLAUDE_PERMISSIONS_EXPLORER,
|
|
553
|
+
builder: MCP_CLAUDE_PERMISSIONS_BUILDER,
|
|
554
|
+
reviewer: MCP_CLAUDE_PERMISSIONS_REVIEWER
|
|
555
|
+
};
|
|
556
|
+
const permissions = permissionsMap[agentName] ?? MCP_CLAUDE_PERMISSIONS;
|
|
557
|
+
const mcpLines = permissions.map((t) => ` - ${t}`).join("\n");
|
|
535
558
|
return md.replace(/(tools:\n(?: - (?!mcp__)[^\n]+\n)+)/, (match) => {
|
|
536
559
|
const trimmed = match.trimEnd();
|
|
537
560
|
return `${trimmed}
|
|
@@ -809,6 +832,30 @@ import { extname, join as join7 } from "path";
|
|
|
809
832
|
import { serve } from "@hono/node-server";
|
|
810
833
|
import { Hono } from "hono";
|
|
811
834
|
import { WebSocketServer } from "ws";
|
|
835
|
+
|
|
836
|
+
// src/core/port-utils.ts
|
|
837
|
+
import { createServer } from "net";
|
|
838
|
+
function isPortFree(port) {
|
|
839
|
+
return new Promise((resolve13) => {
|
|
840
|
+
const server = createServer();
|
|
841
|
+
server.once("error", () => resolve13(false));
|
|
842
|
+
server.once("listening", () => {
|
|
843
|
+
server.close(() => resolve13(true));
|
|
844
|
+
});
|
|
845
|
+
server.listen(port, "127.0.0.1");
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
async function findFreePort(start, maxAttempts = 10) {
|
|
849
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
850
|
+
const port = start + i;
|
|
851
|
+
if (await isPortFree(port)) return port;
|
|
852
|
+
}
|
|
853
|
+
throw new Error(
|
|
854
|
+
`Could not find a free port after ${maxAttempts} attempts (tried ${start}-${start + maxAttempts - 1}). Please free a port and try again.`
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// src/core/dashboard-server.ts
|
|
812
859
|
var MIME = {
|
|
813
860
|
".html": "text/html; charset=utf-8",
|
|
814
861
|
".js": "application/javascript; charset=utf-8",
|
|
@@ -829,7 +876,7 @@ function fileResponse(filePath) {
|
|
|
829
876
|
headers: { "Content-Type": mime, "Cache-Control": "no-cache" }
|
|
830
877
|
});
|
|
831
878
|
}
|
|
832
|
-
function startDashboardServer(db, dbPath, staticPath, port) {
|
|
879
|
+
async function startDashboardServer(db, dbPath, staticPath, port) {
|
|
833
880
|
const app = new Hono();
|
|
834
881
|
const { tasks, actions, stats } = db;
|
|
835
882
|
app.use("/api/*", async (c, next) => {
|
|
@@ -871,7 +918,10 @@ function startDashboardServer(db, dbPath, staticPath, port) {
|
|
|
871
918
|
if (body.description !== void 0) updateParams.description = body.description;
|
|
872
919
|
await db.updateTask(id, updateParams);
|
|
873
920
|
if (body.acceptance !== void 0 && Array.isArray(body.acceptance)) {
|
|
874
|
-
await db.updateTaskAcceptance(
|
|
921
|
+
await db.updateTaskAcceptance(
|
|
922
|
+
id,
|
|
923
|
+
body.acceptance.map((a) => a.trim()).filter(Boolean)
|
|
924
|
+
);
|
|
875
925
|
}
|
|
876
926
|
const updated = await tasks.getById(id);
|
|
877
927
|
const acceptance = await tasks.getAcceptance(id);
|
|
@@ -936,7 +986,11 @@ function startDashboardServer(db, dbPath, staticPath, port) {
|
|
|
936
986
|
}
|
|
937
987
|
return fileResponse(join7(staticPath, "index.html"));
|
|
938
988
|
});
|
|
939
|
-
const
|
|
989
|
+
const resolvedPort = await findFreePort(port);
|
|
990
|
+
if (resolvedPort !== port) {
|
|
991
|
+
console.log(`Port ${port} in use, using ${resolvedPort}`);
|
|
992
|
+
}
|
|
993
|
+
const httpServer = serve({ fetch: app.fetch, port: resolvedPort });
|
|
940
994
|
const wss = new WebSocketServer({ noServer: true });
|
|
941
995
|
httpServer.on("upgrade", (req, socket, head) => {
|
|
942
996
|
if (req.url === "/ws") {
|
|
@@ -965,7 +1019,7 @@ function startDashboardServer(db, dbPath, staticPath, port) {
|
|
|
965
1019
|
watcher = watch2(watchTarget, broadcast);
|
|
966
1020
|
}
|
|
967
1021
|
return {
|
|
968
|
-
url: `http://localhost:${
|
|
1022
|
+
url: `http://localhost:${resolvedPort}`,
|
|
969
1023
|
close: () => {
|
|
970
1024
|
clearTimeout(debounce);
|
|
971
1025
|
watcher?.close();
|
|
@@ -1188,8 +1242,8 @@ var TaskRepository = class {
|
|
|
1188
1242
|
async add(params) {
|
|
1189
1243
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1190
1244
|
return this.driver.insert(
|
|
1191
|
-
`INSERT INTO tasks (slug, title, description, status, created_at) VALUES (?, ?, ?, ?, ?)`,
|
|
1192
|
-
[params.slug, params.title, params.description ?? null, params.status ?? "pending", now]
|
|
1245
|
+
`INSERT INTO tasks (slug, title, description, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
1246
|
+
[params.slug, params.title, params.description ?? null, params.status ?? "pending", now, now]
|
|
1193
1247
|
);
|
|
1194
1248
|
}
|
|
1195
1249
|
async addAcceptance(taskId, criteria) {
|
|
@@ -1214,7 +1268,7 @@ var TaskRepository = class {
|
|
|
1214
1268
|
if (conditions.length > 0) {
|
|
1215
1269
|
sql += ` WHERE ${conditions.join(" AND ")}`;
|
|
1216
1270
|
}
|
|
1217
|
-
sql += ` ORDER BY
|
|
1271
|
+
sql += ` ORDER BY CASE status WHEN 'pending' THEN 1 WHEN 'in_progress' THEN 2 WHEN 'blocked' THEN 3 WHEN 'done' THEN 4 ELSE 5 END, updated_at DESC`;
|
|
1218
1272
|
return this.driver.query(sql, params);
|
|
1219
1273
|
}
|
|
1220
1274
|
async getAllWithAcceptanceCounts(includeArchived = false) {
|
|
@@ -1228,7 +1282,7 @@ var TaskRepository = class {
|
|
|
1228
1282
|
if (!includeArchived) {
|
|
1229
1283
|
sql += ` WHERE t.archived_at IS NULL`;
|
|
1230
1284
|
}
|
|
1231
|
-
sql += ` GROUP BY t.id ORDER BY t.
|
|
1285
|
+
sql += ` GROUP BY t.id ORDER BY CASE t.status WHEN 'pending' THEN 1 WHEN 'in_progress' THEN 2 WHEN 'blocked' THEN 3 WHEN 'done' THEN 4 ELSE 5 END, t.updated_at DESC`;
|
|
1232
1286
|
return this.driver.query(sql);
|
|
1233
1287
|
}
|
|
1234
1288
|
async getById(id) {
|
|
@@ -1244,23 +1298,25 @@ var TaskRepository = class {
|
|
|
1244
1298
|
);
|
|
1245
1299
|
}
|
|
1246
1300
|
async setStatus(id, status, extra) {
|
|
1301
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1247
1302
|
if (extra?.started_at) {
|
|
1248
1303
|
await this.driver.exec(
|
|
1249
|
-
`UPDATE tasks SET status = ?, started_at = ? WHERE id = ?`,
|
|
1250
|
-
[status, extra.started_at, id]
|
|
1304
|
+
`UPDATE tasks SET status = ?, started_at = ?, updated_at = ? WHERE id = ?`,
|
|
1305
|
+
[status, extra.started_at, now, id]
|
|
1251
1306
|
);
|
|
1252
1307
|
} else if (extra?.completed_at) {
|
|
1253
1308
|
await this.driver.exec(
|
|
1254
|
-
`UPDATE tasks SET status = ?, completed_at = ? WHERE id = ?`,
|
|
1255
|
-
[status, extra.completed_at, id]
|
|
1309
|
+
`UPDATE tasks SET status = ?, completed_at = ?, updated_at = ? WHERE id = ?`,
|
|
1310
|
+
[status, extra.completed_at, now, id]
|
|
1256
1311
|
);
|
|
1257
1312
|
} else {
|
|
1258
|
-
await this.driver.exec(`UPDATE tasks SET status = ? WHERE id = ?`, [status, id]);
|
|
1313
|
+
await this.driver.exec(`UPDATE tasks SET status = ?, updated_at = ? WHERE id = ?`, [status, now, id]);
|
|
1259
1314
|
}
|
|
1260
1315
|
}
|
|
1261
1316
|
async update(id, params) {
|
|
1262
1317
|
const sets = [];
|
|
1263
1318
|
const vals = [];
|
|
1319
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1264
1320
|
if (params.title !== void 0) {
|
|
1265
1321
|
sets.push("title = ?");
|
|
1266
1322
|
vals.push(params.title);
|
|
@@ -1274,6 +1330,8 @@ var TaskRepository = class {
|
|
|
1274
1330
|
vals.push(params.slug);
|
|
1275
1331
|
}
|
|
1276
1332
|
if (sets.length === 0) return;
|
|
1333
|
+
sets.push("updated_at = ?");
|
|
1334
|
+
vals.push(now);
|
|
1277
1335
|
vals.push(id);
|
|
1278
1336
|
await this.driver.exec(`UPDATE tasks SET ${sets.join(", ")} WHERE id = ?`, vals);
|
|
1279
1337
|
}
|
|
@@ -1288,10 +1346,11 @@ var TaskRepository = class {
|
|
|
1288
1346
|
}
|
|
1289
1347
|
async archive(id) {
|
|
1290
1348
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1291
|
-
await this.driver.exec(`UPDATE tasks SET archived_at = ? WHERE id = ?`, [now, id]);
|
|
1349
|
+
await this.driver.exec(`UPDATE tasks SET archived_at = ?, updated_at = ? WHERE id = ?`, [now, now, id]);
|
|
1292
1350
|
}
|
|
1293
1351
|
async unarchive(id) {
|
|
1294
|
-
|
|
1352
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1353
|
+
await this.driver.exec(`UPDATE tasks SET archived_at = NULL, updated_at = ? WHERE id = ?`, [now, id]);
|
|
1295
1354
|
}
|
|
1296
1355
|
async getArchived() {
|
|
1297
1356
|
return this.driver.query(
|
|
@@ -1300,8 +1359,8 @@ var TaskRepository = class {
|
|
|
1300
1359
|
}
|
|
1301
1360
|
async claim(id, agent, now) {
|
|
1302
1361
|
return this.driver.exec(
|
|
1303
|
-
`UPDATE tasks SET status = 'in_progress', assigned_to = ?, started_at = ? WHERE id = ? AND status = 'pending'`,
|
|
1304
|
-
[agent, now, id]
|
|
1362
|
+
`UPDATE tasks SET status = 'in_progress', assigned_to = ?, started_at = ?, updated_at = ? WHERE id = ? AND status = 'pending'`,
|
|
1363
|
+
[agent, now, now, id]
|
|
1305
1364
|
);
|
|
1306
1365
|
}
|
|
1307
1366
|
async markAcceptanceMet(criterionId) {
|
|
@@ -1577,13 +1636,13 @@ async function openDB(config, cwd2) {
|
|
|
1577
1636
|
const dbConfig = config.database;
|
|
1578
1637
|
let driver;
|
|
1579
1638
|
if (dbConfig.type === "postgres") {
|
|
1580
|
-
const { PostgresDriver } = await import("./postgres-
|
|
1639
|
+
const { PostgresDriver } = await import("./postgres-IOQE32DM.js");
|
|
1581
1640
|
driver = new PostgresDriver(dbConfig);
|
|
1582
1641
|
} else if (dbConfig.type === "mysql") {
|
|
1583
|
-
const { MySQLDriver } = await import("./mysql-
|
|
1642
|
+
const { MySQLDriver } = await import("./mysql-THKQOXIS.js");
|
|
1584
1643
|
driver = new MySQLDriver(dbConfig);
|
|
1585
1644
|
} else {
|
|
1586
|
-
const { SQLiteDriver } = await import("./sqlite-
|
|
1645
|
+
const { SQLiteDriver } = await import("./sqlite-XBEJJ5T2.js");
|
|
1587
1646
|
if (dbConfig.type !== "sqlite") {
|
|
1588
1647
|
throw new Error("Invalid database type");
|
|
1589
1648
|
}
|
|
@@ -1600,7 +1659,7 @@ async function runDashboard(cwd2, opts) {
|
|
|
1600
1659
|
const db = await openDB(config, cwd2);
|
|
1601
1660
|
const dbPath = config.database.type === "sqlite" ? resolve7(cwd2, config.database.path) : null;
|
|
1602
1661
|
const staticPath = join9(__dirname2, "dashboard-dist");
|
|
1603
|
-
const { url } = startDashboardServer(db, dbPath, staticPath, opts.port);
|
|
1662
|
+
const { url } = await startDashboardServer(db, dbPath, staticPath, opts.port);
|
|
1604
1663
|
console.log(pc2.green(`\u2713`) + ` Dashboard running at ${pc2.bold(pc2.cyan(url))}`);
|
|
1605
1664
|
console.log(pc2.dim(` WebSocket live updates enabled`));
|
|
1606
1665
|
console.log(pc2.dim(` Press Ctrl+C to stop`));
|
|
@@ -2414,6 +2473,17 @@ var TOOLS = [
|
|
|
2414
2473
|
required: ["criterionId"]
|
|
2415
2474
|
}
|
|
2416
2475
|
},
|
|
2476
|
+
{
|
|
2477
|
+
name: "tasks.acceptance.get",
|
|
2478
|
+
description: "Given a taskId, returns all acceptance criteria for that task with their id, task_id, criterion text, and met status. Use the returned id values to call tasks.acceptance_update(criterionId).",
|
|
2479
|
+
inputSchema: {
|
|
2480
|
+
type: "object",
|
|
2481
|
+
properties: {
|
|
2482
|
+
taskId: { type: "number", description: "Task ID" }
|
|
2483
|
+
},
|
|
2484
|
+
required: ["taskId"]
|
|
2485
|
+
}
|
|
2486
|
+
},
|
|
2417
2487
|
{
|
|
2418
2488
|
name: "tasks.add",
|
|
2419
2489
|
description: "Create a new task in the harness. Use this when the user describes work in natural language. Infer slug, title, description, and acceptance criteria from the conversation. Ask for missing critical info before calling.",
|
|
@@ -2590,6 +2660,11 @@ async function dispatch(name, args, db, docsPath) {
|
|
|
2590
2660
|
await db.markAcceptanceMet(criterionId);
|
|
2591
2661
|
return ok(JSON.stringify({ criterionId, met: true }));
|
|
2592
2662
|
}
|
|
2663
|
+
case "tasks.acceptance.get": {
|
|
2664
|
+
const taskId = num(args, "taskId");
|
|
2665
|
+
const criteria = await db.getTaskAcceptance(taskId);
|
|
2666
|
+
return ok(JSON.stringify(criteria, null, 2));
|
|
2667
|
+
}
|
|
2593
2668
|
case "actions.record_tool": {
|
|
2594
2669
|
const actionId = str(args, "actionId");
|
|
2595
2670
|
const toolName = str(args, "toolName");
|