@cardor/agent-harness-kit 0.16.5 → 0.16.8
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/builder.md +37 -7
- package/dist/agent-templates/explorer.md +25 -6
- package/dist/agent-templates/lead.md +23 -0
- package/dist/agent-templates/reviewer.md +35 -6
- package/dist/cli.js +102 -68
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
|
@@ -30,6 +30,41 @@ You may only write to: `{{writablePaths}}`
|
|
|
30
30
|
|
|
31
31
|
Do not modify files outside these paths. If the task requires it, record a blocker and stop.
|
|
32
32
|
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## !! MANDATORY TRACKING — DO THIS FOR EVERY ACTION, NO EXCEPTIONS !!
|
|
36
|
+
|
|
37
|
+
These three calls are **not optional**. The dashboard cannot display what you do not report. Missing any of them is a failure of your role.
|
|
38
|
+
|
|
39
|
+
### 1. Log every tool call you make
|
|
40
|
+
|
|
41
|
+
After **each** tool invocation (Read, Edit, Write, Bash), immediately call:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
actions.write(actionId, 'tools_used', '<ToolName>: <args-summary> — why')
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
- `Read: src/auth/middleware.ts — understand existing JWT pattern`
|
|
49
|
+
- `Bash: npm test -- --testPathPattern=auth — verify auth tests pass`
|
|
50
|
+
- `Edit: src/auth/middleware.ts:45-78 — add refresh token validation`
|
|
51
|
+
|
|
52
|
+
### 2. Log every file you touch
|
|
53
|
+
|
|
54
|
+
After **each** file modification (Edit, Write), immediately call:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
actions.write(actionId, 'files_modified', '<file-path> — what changed and why')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Example: `src/auth/middleware.ts — added refresh token expiry check in validateToken()`
|
|
61
|
+
|
|
62
|
+
### 3. Do not complete your action without both logs being up to date
|
|
63
|
+
|
|
64
|
+
If you touched 5 files and made 12 tool calls, there must be 5 `files_modified` entries and 12 `tools_used` entries before you call `actions.complete`.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
33
68
|
## Workflow
|
|
34
69
|
|
|
35
70
|
### 1. Read the full action history
|
|
@@ -48,13 +83,7 @@ actions.start(taskId, 'builder') → save the returned actionId
|
|
|
48
83
|
|
|
49
84
|
### 3. Implement in small, verifiable steps
|
|
50
85
|
|
|
51
|
-
Work through the plan item by item.
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
actions.write(actionId, 'files_modified', '<file-path — what changed and why>')
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Log each file as you modify it. Be specific: "Added JWT validation to src/middleware/auth.ts — lines 45–78".
|
|
86
|
+
Work through the plan item by item. Log each tool call and each file touched as described in the **MANDATORY TRACKING** section above — do it as you go, not at the end.
|
|
58
87
|
|
|
59
88
|
### 4. Follow existing patterns
|
|
60
89
|
|
|
@@ -97,6 +126,7 @@ actions.complete(actionId, 'Implementation done — N files modified, tests pass
|
|
|
97
126
|
- **Read the plan and analysis first.** Never implement cold.
|
|
98
127
|
- **Only write to `{{writablePaths}}`.** No exceptions.
|
|
99
128
|
- **Log every file you touch.** No silent modifications.
|
|
129
|
+
- **Log every tool call.** Use `actions.write(actionId, 'tools_used', ...)` after each Read, Edit, Write, Bash invocation.
|
|
100
130
|
- **Leave tests green.** If tests fail after your changes, fix them before completing.
|
|
101
131
|
- **Do not refactor beyond the task scope.** Implement what was asked, nothing more.
|
|
102
132
|
- **If blocked, say so.** Do not invent workarounds for unclear requirements.
|
|
@@ -29,6 +29,29 @@ You may read files under: `{{allowedPaths}}`
|
|
|
29
29
|
|
|
30
30
|
If you need to read outside these paths, record that as a blocker — do not proceed.
|
|
31
31
|
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## !! MANDATORY TRACKING — DO THIS FOR EVERY ACTION, NO EXCEPTIONS !!
|
|
35
|
+
|
|
36
|
+
These calls are **not optional**. The dashboard cannot display what you do not report. Missing them is a failure of your role.
|
|
37
|
+
|
|
38
|
+
### Log every tool call you make
|
|
39
|
+
|
|
40
|
+
After **each** tool invocation (Read, Bash, grep, docs.search), immediately call:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
actions.write(actionId, 'tools_used', '<ToolName>: <args-summary> — why')
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Examples:
|
|
47
|
+
- `Read: src/auth/middleware.ts — find existing JWT pattern`
|
|
48
|
+
- `Bash: grep -r "refreshToken" src/ — locate all refresh token usages`
|
|
49
|
+
- `docs.search: "authentication middleware" — check project docs for auth guidance`
|
|
50
|
+
|
|
51
|
+
**Every single tool call must be logged.** No silent reads. The audit trail in the dashboard is built entirely from these entries.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
32
55
|
## Workflow
|
|
33
56
|
|
|
34
57
|
### 1. Read the lead's plan
|
|
@@ -59,13 +82,9 @@ Read `AGENTS.md` → follow its map → open only the specific files relevant to
|
|
|
59
82
|
|
|
60
83
|
Do NOT read the entire codebase. Be targeted.
|
|
61
84
|
|
|
62
|
-
### 5.
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
actions.write(actionId, 'tools_used', '<tool: file-path — why you read it>')
|
|
66
|
-
```
|
|
85
|
+
### 5. Log every tool call as you make it
|
|
67
86
|
|
|
68
|
-
Log each
|
|
87
|
+
Log each invocation as described in the **MANDATORY TRACKING** section above — do it immediately after each tool call, not at the end.
|
|
69
88
|
|
|
70
89
|
### 6. Produce a structured analysis
|
|
71
90
|
|
|
@@ -24,6 +24,29 @@ You are the **lead agent** for `{{projectName}}`. Your job is to orchestrate the
|
|
|
24
24
|
- Re-coordinate if the Reviewer blocks (send back to Builder with specific issues)
|
|
25
25
|
- Close the session cleanly when the task is done
|
|
26
26
|
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## !! MANDATORY TRACKING — DO THIS FOR EVERY ACTION, NO EXCEPTIONS !!
|
|
30
|
+
|
|
31
|
+
These calls are **not optional**. The dashboard cannot display what you do not report.
|
|
32
|
+
|
|
33
|
+
### Log every tool call you make
|
|
34
|
+
|
|
35
|
+
After **each** tool invocation (Bash, tasks.get, tasks.claim, actions.get), immediately call:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
actions.write(actionId, 'tools_used', '<ToolName>: <args-summary> — why')
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
- `Bash: bash health.sh — verify codebase health before starting`
|
|
43
|
+
- `tasks.get: pending — find next task to claim`
|
|
44
|
+
- `actions.get: taskId=abc123 — read action history to resume in-progress task`
|
|
45
|
+
|
|
46
|
+
**Log every call.** This applies from the moment you have an `actionId` (after step 3 below).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
27
50
|
## Workflow
|
|
28
51
|
|
|
29
52
|
### 1. Orient (always first)
|
|
@@ -24,6 +24,39 @@ You are the **reviewer agent** for `{{projectName}}`. Your job is to verify —
|
|
|
24
24
|
- Block clearly with specific, actionable issues when they are not
|
|
25
25
|
- Never approve to be helpful — only approve when the work is genuinely complete
|
|
26
26
|
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## !! MANDATORY TRACKING — DO THIS FOR EVERY ACTION, NO EXCEPTIONS !!
|
|
30
|
+
|
|
31
|
+
These calls are **not optional**. The dashboard cannot display what you do not report.
|
|
32
|
+
|
|
33
|
+
### 1. Log every tool call you make
|
|
34
|
+
|
|
35
|
+
After **each** tool invocation (Read, Bash), immediately call:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
actions.write(actionId, 'tools_used', '<ToolName>: <args-summary> — why')
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
- `Read: src/auth/middleware.ts — verify refresh token logic matches criterion 2`
|
|
43
|
+
- `Bash: npm test -- --testPathPattern=auth — confirm all auth tests pass`
|
|
44
|
+
|
|
45
|
+
### 2. Mark every acceptance criterion as you verify it
|
|
46
|
+
|
|
47
|
+
For **each** criterion (0-based index), call this immediately after you evaluate it:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
tasks.acceptance_update(taskId, criterionIndex, true|false)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- `true` = criterion is fully met
|
|
54
|
+
- `false` = criterion is not met
|
|
55
|
+
|
|
56
|
+
If the task has 3 criteria, you must make exactly 3 `tasks.acceptance_update` calls — one per criterion. Skipping any of them leaves the dashboard showing criteria as unverified.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
27
60
|
## Workflow
|
|
28
61
|
|
|
29
62
|
### 1. Read the full task history
|
|
@@ -47,12 +80,7 @@ actions.start(taskId, 'reviewer') → save the returned actionId
|
|
|
47
80
|
|
|
48
81
|
### 3. Verify each acceptance criterion
|
|
49
82
|
|
|
50
|
-
For each criterion in the
|
|
51
|
-
- Read the relevant files
|
|
52
|
-
- Run relevant commands if needed (tests, linting, type-checks)
|
|
53
|
-
- Mark it as met or unmet
|
|
54
|
-
|
|
55
|
-
Keep a running checklist as you go.
|
|
83
|
+
For each criterion: read the relevant files, run commands if needed, then immediately call `tasks.acceptance_update` as described in the **MANDATORY TRACKING** section above. Do this per-criterion as you go — not in batch at the end.
|
|
56
84
|
|
|
57
85
|
### 4. Run the health check
|
|
58
86
|
|
|
@@ -96,6 +124,7 @@ Then notify lead so the builder can be re-assigned.
|
|
|
96
124
|
|
|
97
125
|
- **Run health.sh before approving.** No exceptions.
|
|
98
126
|
- **Check every acceptance criterion.** Not just the obvious ones.
|
|
127
|
+
- **Call `tasks.acceptance_update()` for each criterion.** Both met and unmet — never skip this step.
|
|
99
128
|
- **Never self-approve partial work.** All criteria must be met, not most.
|
|
100
129
|
- **Be specific when blocking.** The builder must know exactly what to fix.
|
|
101
130
|
- **Do not fix issues yourself.** Your job is to verify, not to implement.
|
package/dist/cli.js
CHANGED
|
@@ -1155,9 +1155,10 @@ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
|
1155
1155
|
import { homedir } from "os";
|
|
1156
1156
|
import { join as join9 } from "path";
|
|
1157
1157
|
import * as p2 from "@clack/prompts";
|
|
1158
|
-
import
|
|
1158
|
+
import pc6 from "picocolors";
|
|
1159
1159
|
|
|
1160
1160
|
// src/commands/init-helpers.ts
|
|
1161
|
+
import pc5 from "picocolors";
|
|
1161
1162
|
function applyConfigDefaults(params) {
|
|
1162
1163
|
return {
|
|
1163
1164
|
provider: params.provider,
|
|
@@ -1197,10 +1198,43 @@ function applyConfigDefaults(params) {
|
|
|
1197
1198
|
}
|
|
1198
1199
|
};
|
|
1199
1200
|
}
|
|
1201
|
+
function stripAnsi(str2) {
|
|
1202
|
+
return str2.replace(/\x1B\[[0-9;]*m/g, "");
|
|
1203
|
+
}
|
|
1204
|
+
function drawBox(lines) {
|
|
1205
|
+
const width = Math.max(...lines.map((l) => stripAnsi(l).length));
|
|
1206
|
+
const border = "\u2500".repeat(width);
|
|
1207
|
+
console.log(pc5.yellow(`\u250C${border}\u2510`));
|
|
1208
|
+
for (const line of lines) {
|
|
1209
|
+
const pad = width - stripAnsi(line).length;
|
|
1210
|
+
const padStr = pad > 0 ? " ".repeat(pad) : "";
|
|
1211
|
+
console.log(pc5.yellow("\u2502") + line + padStr + pc5.yellow("\u2502"));
|
|
1212
|
+
}
|
|
1213
|
+
console.log(pc5.yellow(`\u2514${border}\u2518`));
|
|
1214
|
+
}
|
|
1215
|
+
function printWelcomeMessage(projectName) {
|
|
1216
|
+
const sep = "\u2500".repeat(38);
|
|
1217
|
+
const lines = [
|
|
1218
|
+
` ${pc5.bold(pc5.white("agent-harness-kit"))} `,
|
|
1219
|
+
` ${pc5.gray("\u2014")} harness scaffolding ${pc5.gray("\u2014")} `,
|
|
1220
|
+
` ${pc5.gray(sep)} `,
|
|
1221
|
+
` ${pc5.bold("Project:")} ${projectName || "\u2014"} `,
|
|
1222
|
+
` ${pc5.bold("Status:")} ${pc5.green("ready to configure")} `,
|
|
1223
|
+
` ${pc5.gray(sep)} `,
|
|
1224
|
+
` ${pc5.gray("Next steps:")} `,
|
|
1225
|
+
` ${pc5.gray("\u2192")} ${pc5.gray("Set up your AI provider config")} `,
|
|
1226
|
+
` ${pc5.gray("\u2192")} ${pc5.gray("Run your health check to verify")} `,
|
|
1227
|
+
` ${pc5.gray("\u2192")} ${pc5.gray("Start adding tasks for your agents")} `
|
|
1228
|
+
];
|
|
1229
|
+
console.log();
|
|
1230
|
+
drawBox(lines);
|
|
1231
|
+
console.log();
|
|
1232
|
+
}
|
|
1200
1233
|
|
|
1201
1234
|
// src/commands/init.ts
|
|
1202
1235
|
async function runInit(cwd2, flags) {
|
|
1203
|
-
|
|
1236
|
+
const projectName = flags.name || "my-project";
|
|
1237
|
+
printWelcomeMessage(projectName);
|
|
1204
1238
|
let name;
|
|
1205
1239
|
if (flags.name) {
|
|
1206
1240
|
name = flags.name;
|
|
@@ -1281,14 +1315,14 @@ async function runInit(cwd2, flags) {
|
|
|
1281
1315
|
]
|
|
1282
1316
|
});
|
|
1283
1317
|
if (p2.isCancel(val)) {
|
|
1284
|
-
p2.cancel("Cancelled
|
|
1318
|
+
p2.cancel("Cancelled");
|
|
1285
1319
|
process.exit(0);
|
|
1286
1320
|
}
|
|
1287
1321
|
tasksAdapter = val;
|
|
1288
1322
|
}
|
|
1289
1323
|
const addFirstTask = await p2.confirm({ message: "Add your first task now?", initialValue: true });
|
|
1290
1324
|
if (p2.isCancel(addFirstTask)) {
|
|
1291
|
-
p2.cancel("Cancelled
|
|
1325
|
+
p2.cancel("Cancelled");
|
|
1292
1326
|
process.exit(0);
|
|
1293
1327
|
}
|
|
1294
1328
|
let firstTask;
|
|
@@ -1298,7 +1332,7 @@ async function runInit(cwd2, flags) {
|
|
|
1298
1332
|
validate: (v) => v.trim() ? void 0 : "Title is required"
|
|
1299
1333
|
});
|
|
1300
1334
|
if (p2.isCancel(titleVal)) {
|
|
1301
|
-
p2.cancel("Cancelled
|
|
1335
|
+
p2.cancel("Cancelled");
|
|
1302
1336
|
process.exit(0);
|
|
1303
1337
|
}
|
|
1304
1338
|
const taskTitle = titleVal.trim();
|
|
@@ -1307,7 +1341,7 @@ async function runInit(cwd2, flags) {
|
|
|
1307
1341
|
placeholder: "What and why"
|
|
1308
1342
|
});
|
|
1309
1343
|
if (p2.isCancel(taskDescVal)) {
|
|
1310
|
-
p2.cancel("Cancelled
|
|
1344
|
+
p2.cancel("Cancelled");
|
|
1311
1345
|
process.exit(0);
|
|
1312
1346
|
}
|
|
1313
1347
|
const taskDesc = taskDescVal.trim();
|
|
@@ -1365,29 +1399,29 @@ async function runInit(cwd2, flags) {
|
|
|
1365
1399
|
process.exit(1);
|
|
1366
1400
|
}
|
|
1367
1401
|
const agentHarnessKitDir = globalInstallation ? "home directory" : "current directory";
|
|
1368
|
-
console.log(
|
|
1402
|
+
console.log(pc6.green(`\u2713 Scaffolded harness in ${agentHarnessKitDir}`));
|
|
1369
1403
|
const agentsDir = provider === "claude-code" ? ".claude/agents/" : ".opencode/agents/";
|
|
1370
1404
|
const mcpFile = provider === "claude-code" ? ".claude/mcp.json" : "./opencode.json";
|
|
1371
1405
|
console.log("");
|
|
1372
|
-
console.log(
|
|
1373
|
-
console.log(
|
|
1374
|
-
console.log(
|
|
1375
|
-
console.log(
|
|
1376
|
-
console.log(
|
|
1377
|
-
console.log(
|
|
1378
|
-
console.log(
|
|
1379
|
-
console.log(
|
|
1380
|
-
console.log(
|
|
1381
|
-
console.log(
|
|
1382
|
-
console.log(
|
|
1406
|
+
console.log(pc6.green("\u2713 agent-harness-kit.config.ts"));
|
|
1407
|
+
console.log(pc6.green("\u2713 AGENTS.md"));
|
|
1408
|
+
console.log(pc6.green("\u2713 health.sh"));
|
|
1409
|
+
console.log(pc6.green("\u2713 .harness/harness.db"));
|
|
1410
|
+
console.log(pc6.green("\u2713 .harness/current.md"));
|
|
1411
|
+
console.log(pc6.green(`\u2713 ${agentsDir}lead.md`));
|
|
1412
|
+
console.log(pc6.green(`\u2713 ${agentsDir}explorer.md`));
|
|
1413
|
+
console.log(pc6.green(`\u2713 ${agentsDir}builder.md`));
|
|
1414
|
+
console.log(pc6.green(`\u2713 ${agentsDir}reviewer.md`));
|
|
1415
|
+
console.log(pc6.green(`\u2713 ${mcpFile}`));
|
|
1416
|
+
console.log(pc6.green("\u2713 .gitignore entries added"));
|
|
1383
1417
|
console.log("");
|
|
1384
|
-
console.log(
|
|
1385
|
-
console.log(
|
|
1418
|
+
console.log(pc6.cyan("\u2192") + ` Edit ${pc6.cyan("health.sh")} with your project checks`);
|
|
1419
|
+
console.log(pc6.cyan("\u2192") + ` ${pc6.cyan("ahk task add")} to queue work for agents`);
|
|
1386
1420
|
}
|
|
1387
1421
|
|
|
1388
1422
|
// src/commands/migrate.ts
|
|
1389
1423
|
import * as p3 from "@clack/prompts";
|
|
1390
|
-
import
|
|
1424
|
+
import pc7 from "picocolors";
|
|
1391
1425
|
async function runMigrate(cwd2, opts) {
|
|
1392
1426
|
const config = await loadConfig(cwd2);
|
|
1393
1427
|
let target;
|
|
@@ -1408,7 +1442,7 @@ async function runMigrate(cwd2, opts) {
|
|
|
1408
1442
|
target = val;
|
|
1409
1443
|
}
|
|
1410
1444
|
if (target === config.provider) {
|
|
1411
|
-
console.log(
|
|
1445
|
+
console.log(pc7.dim(`Already on ${target} \u2014 nothing to migrate.`));
|
|
1412
1446
|
return;
|
|
1413
1447
|
}
|
|
1414
1448
|
const spinner5 = p3.spinner();
|
|
@@ -1416,11 +1450,11 @@ async function runMigrate(cwd2, opts) {
|
|
|
1416
1450
|
try {
|
|
1417
1451
|
const targetMaterializer = getMaterializer(target);
|
|
1418
1452
|
await targetMaterializer.build(config, cwd2);
|
|
1419
|
-
spinner5.stop(
|
|
1453
|
+
spinner5.stop(pc7.green(`Migrated to ${target}`));
|
|
1420
1454
|
p3.log.warn(`Update agent-harness-kit.config.ts: set provider: '${target}'`);
|
|
1421
1455
|
p3.log.warn(`Then run: ahk build`);
|
|
1422
1456
|
} catch (err) {
|
|
1423
|
-
spinner5.stop(
|
|
1457
|
+
spinner5.stop(pc7.red("Migration failed"));
|
|
1424
1458
|
p3.log.error(err instanceof Error ? err.message : String(err));
|
|
1425
1459
|
process.exit(1);
|
|
1426
1460
|
}
|
|
@@ -1734,12 +1768,12 @@ async function runServe(cwd2, opts) {
|
|
|
1734
1768
|
|
|
1735
1769
|
// src/commands/status.ts
|
|
1736
1770
|
import Table from "cli-table3";
|
|
1737
|
-
import
|
|
1771
|
+
import pc8 from "picocolors";
|
|
1738
1772
|
var STATUS_COLOR = {
|
|
1739
|
-
pending: (s) =>
|
|
1740
|
-
in_progress: (s) =>
|
|
1741
|
-
done: (s) =>
|
|
1742
|
-
blocked: (s) =>
|
|
1773
|
+
pending: (s) => pc8.dim(s),
|
|
1774
|
+
in_progress: (s) => pc8.cyan(s),
|
|
1775
|
+
done: (s) => pc8.green(s),
|
|
1776
|
+
blocked: (s) => pc8.red(s)
|
|
1743
1777
|
};
|
|
1744
1778
|
async function runStatus(cwd2, opts) {
|
|
1745
1779
|
const config = await loadConfig(cwd2);
|
|
@@ -1757,11 +1791,11 @@ async function runStatus(cwd2, opts) {
|
|
|
1757
1791
|
return;
|
|
1758
1792
|
}
|
|
1759
1793
|
if (tasks.length === 0) {
|
|
1760
|
-
console.log(
|
|
1794
|
+
console.log(pc8.dim("No tasks yet. Run: ahk task add"));
|
|
1761
1795
|
return;
|
|
1762
1796
|
}
|
|
1763
1797
|
const table = new Table({
|
|
1764
|
-
head: ["ID", "Slug", "Title", "Status", "Assigned", "Started"].map((h) =>
|
|
1798
|
+
head: ["ID", "Slug", "Title", "Status", "Assigned", "Started"].map((h) => pc8.bold(h)),
|
|
1765
1799
|
style: { head: [], border: [] }
|
|
1766
1800
|
});
|
|
1767
1801
|
for (const t of tasks) {
|
|
@@ -1779,12 +1813,12 @@ async function runStatus(cwd2, opts) {
|
|
|
1779
1813
|
const inProgress = tasks.filter((t) => t.status === "in_progress");
|
|
1780
1814
|
if (inProgress.length > 0) {
|
|
1781
1815
|
console.log("");
|
|
1782
|
-
console.log(
|
|
1816
|
+
console.log(pc8.bold("Active actions:"));
|
|
1783
1817
|
for (const t of inProgress) {
|
|
1784
1818
|
const actions = db.getActionsForTask(t.id);
|
|
1785
1819
|
const active = actions.filter((a) => a.status === "in_progress");
|
|
1786
1820
|
for (const a of active) {
|
|
1787
|
-
console.log(` ${
|
|
1821
|
+
console.log(` ${pc8.cyan(a.agent.padEnd(10))} \u2192 task #${t.id} ${t.slug}`);
|
|
1788
1822
|
}
|
|
1789
1823
|
}
|
|
1790
1824
|
}
|
|
@@ -1793,7 +1827,7 @@ async function runStatus(cwd2, opts) {
|
|
|
1793
1827
|
const fn = STATUS_COLOR[s.status] ?? ((x) => x);
|
|
1794
1828
|
return `${fn(s.status)}: ${s.total}`;
|
|
1795
1829
|
});
|
|
1796
|
-
console.log(
|
|
1830
|
+
console.log(pc8.dim("Tasks \u2014 ") + parts.join(pc8.dim(" | ")));
|
|
1797
1831
|
} finally {
|
|
1798
1832
|
db.close();
|
|
1799
1833
|
}
|
|
@@ -1802,7 +1836,7 @@ async function runStatus(cwd2, opts) {
|
|
|
1802
1836
|
// src/commands/sync.ts
|
|
1803
1837
|
import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
|
|
1804
1838
|
import { join as join11, resolve as resolve8 } from "path";
|
|
1805
|
-
import
|
|
1839
|
+
import pc9 from "picocolors";
|
|
1806
1840
|
async function runSync(cwd2, opts) {
|
|
1807
1841
|
const config = await loadConfig(cwd2);
|
|
1808
1842
|
const direction = opts.direction ?? "both";
|
|
@@ -1821,43 +1855,43 @@ async function runSync(cwd2, opts) {
|
|
|
1821
1855
|
}
|
|
1822
1856
|
async function syncIn(featureListPath, db, dryRun) {
|
|
1823
1857
|
if (!existsSync7(featureListPath)) {
|
|
1824
|
-
console.log(
|
|
1858
|
+
console.log(pc9.dim(`feature_list.json not found at ${featureListPath} \u2014 skipping in-sync`));
|
|
1825
1859
|
return;
|
|
1826
1860
|
}
|
|
1827
1861
|
let seeds;
|
|
1828
1862
|
try {
|
|
1829
1863
|
seeds = JSON.parse(readFileSync6(featureListPath, "utf8"));
|
|
1830
1864
|
} catch (err) {
|
|
1831
|
-
console.error(
|
|
1865
|
+
console.error(pc9.red(`Failed to parse feature_list.json: ${err}`));
|
|
1832
1866
|
process.exit(1);
|
|
1833
1867
|
}
|
|
1834
1868
|
if (dryRun) {
|
|
1835
|
-
console.log(
|
|
1869
|
+
console.log(pc9.bold("Dry run \u2014 in-sync (feature_list.json \u2192 SQLite):"));
|
|
1836
1870
|
for (const t of seeds) {
|
|
1837
1871
|
const existing = db.getTaskBySlug(t.slug);
|
|
1838
|
-
console.log(` ${existing ?
|
|
1872
|
+
console.log(` ${existing ? pc9.dim("skip") : pc9.green("add ")} ${t.slug}`);
|
|
1839
1873
|
}
|
|
1840
1874
|
return;
|
|
1841
1875
|
}
|
|
1842
1876
|
const result = db.syncFromFeatureList(seeds);
|
|
1843
|
-
console.log(
|
|
1877
|
+
console.log(pc9.green(`\u2713 In-sync: ${result.added} added, ${result.skipped} already existed`));
|
|
1844
1878
|
}
|
|
1845
1879
|
function syncOut(db, cwd2, dryRun) {
|
|
1846
1880
|
if (dryRun) {
|
|
1847
1881
|
const tasks = db.getTasks();
|
|
1848
|
-
console.log(
|
|
1882
|
+
console.log(pc9.bold("Dry run \u2014 out-sync (SQLite \u2192 feature_list.json):"));
|
|
1849
1883
|
console.log(` ${tasks.length} tasks would be written`);
|
|
1850
1884
|
return;
|
|
1851
1885
|
}
|
|
1852
1886
|
db.writeFeatureList(cwd2);
|
|
1853
|
-
console.log(
|
|
1887
|
+
console.log(pc9.green("\u2713 Out-sync: feature_list.json updated"));
|
|
1854
1888
|
}
|
|
1855
1889
|
|
|
1856
1890
|
// src/commands/task/add.ts
|
|
1857
1891
|
import * as p4 from "@clack/prompts";
|
|
1858
|
-
import
|
|
1892
|
+
import pc10 from "picocolors";
|
|
1859
1893
|
async function runTaskAdd(cwd2) {
|
|
1860
|
-
p4.intro(
|
|
1894
|
+
p4.intro(pc10.bold("agent-harness-kit \u2014 add task"));
|
|
1861
1895
|
const titleVal = await p4.text({
|
|
1862
1896
|
message: "Task title",
|
|
1863
1897
|
validate: (v) => v.trim() ? void 0 : "Title is required"
|
|
@@ -1893,10 +1927,10 @@ async function runTaskAdd(cwd2) {
|
|
|
1893
1927
|
db.writeFeatureList(cwd2);
|
|
1894
1928
|
db.close();
|
|
1895
1929
|
spinner5.stop("");
|
|
1896
|
-
console.log(
|
|
1897
|
-
console.log(
|
|
1930
|
+
console.log(pc10.green(`\u2713 Task #${task2.id} added \u2014 ${task2.slug} (pending)`));
|
|
1931
|
+
console.log(pc10.cyan("\u2192") + " " + pc10.cyan("ahk status") + " to see all tasks");
|
|
1898
1932
|
} catch (err) {
|
|
1899
|
-
spinner5.stop(
|
|
1933
|
+
spinner5.stop(pc10.red("Failed"));
|
|
1900
1934
|
p4.log.error(err instanceof Error ? err.message : String(err));
|
|
1901
1935
|
process.exit(1);
|
|
1902
1936
|
}
|
|
@@ -1906,7 +1940,7 @@ async function runTaskAdd(cwd2) {
|
|
|
1906
1940
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1907
1941
|
import { existsSync as existsSync8 } from "fs";
|
|
1908
1942
|
import { resolve as resolve9 } from "path";
|
|
1909
|
-
import
|
|
1943
|
+
import pc11 from "picocolors";
|
|
1910
1944
|
async function runTaskDone(cwd2, idOrSlug) {
|
|
1911
1945
|
const config = await loadConfig(cwd2);
|
|
1912
1946
|
if (config.health.required) {
|
|
@@ -1914,7 +1948,7 @@ async function runTaskDone(cwd2, idOrSlug) {
|
|
|
1914
1948
|
if (existsSync8(scriptPath)) {
|
|
1915
1949
|
const result = spawnSync2("bash", [scriptPath], { cwd: cwd2, stdio: "pipe", encoding: "utf8" });
|
|
1916
1950
|
if (result.status !== 0) {
|
|
1917
|
-
console.error(
|
|
1951
|
+
console.error(pc11.red("\u2717 Health check failed \u2014 cannot mark task as done."));
|
|
1918
1952
|
if (result.stdout) console.error(result.stdout);
|
|
1919
1953
|
if (result.stderr) console.error(result.stderr);
|
|
1920
1954
|
process.exit(1);
|
|
@@ -1927,16 +1961,16 @@ async function runTaskDone(cwd2, idOrSlug) {
|
|
|
1927
1961
|
const isId = !isNaN(parsed);
|
|
1928
1962
|
const task2 = isId ? db.getTaskById(parsed) : db.getTaskBySlug(idOrSlug);
|
|
1929
1963
|
if (!task2) {
|
|
1930
|
-
console.error(
|
|
1964
|
+
console.error(pc11.red(`Task not found: ${idOrSlug}`));
|
|
1931
1965
|
process.exit(1);
|
|
1932
1966
|
}
|
|
1933
1967
|
if (task2.status === "done") {
|
|
1934
|
-
console.log(
|
|
1968
|
+
console.log(pc11.dim(`Task #${task2.id} is already done.`));
|
|
1935
1969
|
return;
|
|
1936
1970
|
}
|
|
1937
1971
|
db.updateTaskStatus(task2.id, "done");
|
|
1938
1972
|
db.writeFeatureList(cwd2);
|
|
1939
|
-
console.log(
|
|
1973
|
+
console.log(pc11.green(`\u2713 Task #${task2.id} \u2014 ${task2.slug} marked as done`));
|
|
1940
1974
|
} finally {
|
|
1941
1975
|
db.close();
|
|
1942
1976
|
}
|
|
@@ -1944,12 +1978,12 @@ async function runTaskDone(cwd2, idOrSlug) {
|
|
|
1944
1978
|
|
|
1945
1979
|
// src/commands/task/list.ts
|
|
1946
1980
|
import Table2 from "cli-table3";
|
|
1947
|
-
import
|
|
1981
|
+
import pc12 from "picocolors";
|
|
1948
1982
|
var STATUS_COLOR2 = {
|
|
1949
|
-
pending: (s) =>
|
|
1950
|
-
in_progress: (s) =>
|
|
1951
|
-
done: (s) =>
|
|
1952
|
-
blocked: (s) =>
|
|
1983
|
+
pending: (s) => pc12.dim(s),
|
|
1984
|
+
in_progress: (s) => pc12.cyan(s),
|
|
1985
|
+
done: (s) => pc12.green(s),
|
|
1986
|
+
blocked: (s) => pc12.red(s)
|
|
1953
1987
|
};
|
|
1954
1988
|
async function runTaskList(cwd2, opts) {
|
|
1955
1989
|
const config = await loadConfig(cwd2);
|
|
@@ -1963,11 +1997,11 @@ async function runTaskList(cwd2, opts) {
|
|
|
1963
1997
|
return;
|
|
1964
1998
|
}
|
|
1965
1999
|
if (tasks.length === 0) {
|
|
1966
|
-
console.log(
|
|
2000
|
+
console.log(pc12.dim("No tasks" + (filterStatus ? ` with status: ${filterStatus}` : "") + "."));
|
|
1967
2001
|
return;
|
|
1968
2002
|
}
|
|
1969
2003
|
const table = new Table2({
|
|
1970
|
-
head: ["ID", "Slug", "Title", "Status"].map((h) =>
|
|
2004
|
+
head: ["ID", "Slug", "Title", "Status"].map((h) => pc12.bold(h)),
|
|
1971
2005
|
style: { head: [], border: [] }
|
|
1972
2006
|
});
|
|
1973
2007
|
for (const t of tasks) {
|
|
@@ -1989,7 +2023,7 @@ var pkgPath = join12(dirname5(fileURLToPath3(import.meta.url)), "..", "package.j
|
|
|
1989
2023
|
var pkg = require2(pkgPath);
|
|
1990
2024
|
|
|
1991
2025
|
// src/core/update-check.ts
|
|
1992
|
-
import
|
|
2026
|
+
import pc13 from "picocolors";
|
|
1993
2027
|
var REGISTRY_URL = `https://registry.npmjs.org/${pkg.name}/latest`;
|
|
1994
2028
|
var TIMEOUT_MS = 2500;
|
|
1995
2029
|
function checkForUpdate(currentVersion) {
|
|
@@ -2007,18 +2041,18 @@ function checkForUpdate(currentVersion) {
|
|
|
2007
2041
|
}
|
|
2008
2042
|
function printUpdateMessage({ current, latest }) {
|
|
2009
2043
|
const lines = [
|
|
2010
|
-
` Update available ${
|
|
2011
|
-
` Run: ${
|
|
2044
|
+
` Update available ${pc13.dim(current)} \u2192 ${pc13.green(latest)} `,
|
|
2045
|
+
` Run: ${pc13.cyan(`npm i ${pkg.name}@${latest}`)} `
|
|
2012
2046
|
];
|
|
2013
|
-
const width = Math.max(...lines.map((l) =>
|
|
2047
|
+
const width = Math.max(...lines.map((l) => stripAnsi2(l).length));
|
|
2014
2048
|
const border = "\u2500".repeat(width);
|
|
2015
2049
|
console.log();
|
|
2016
|
-
console.log(
|
|
2050
|
+
console.log(pc13.yellow(`\u250C${border}\u2510`));
|
|
2017
2051
|
for (const line of lines) {
|
|
2018
|
-
const pad = width -
|
|
2019
|
-
console.log(
|
|
2052
|
+
const pad = width - stripAnsi2(line).length;
|
|
2053
|
+
console.log(pc13.yellow("\u2502") + line + " ".repeat(pad) + pc13.yellow("\u2502"));
|
|
2020
2054
|
}
|
|
2021
|
-
console.log(
|
|
2055
|
+
console.log(pc13.yellow(`\u2514${border}\u2518`));
|
|
2022
2056
|
console.log();
|
|
2023
2057
|
}
|
|
2024
2058
|
function isNewer(latest, current) {
|
|
@@ -2029,7 +2063,7 @@ function isNewer(latest, current) {
|
|
|
2029
2063
|
if (lMin !== cMin) return lMin > cMin;
|
|
2030
2064
|
return lPat > cPat;
|
|
2031
2065
|
}
|
|
2032
|
-
function
|
|
2066
|
+
function stripAnsi2(str2) {
|
|
2033
2067
|
return str2.replace(/\x1B\[[0-9;]*m/g, "");
|
|
2034
2068
|
}
|
|
2035
2069
|
|