@cardor/agent-harness-kit 0.16.10 → 0.18.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/cli.js CHANGED
@@ -149,14 +149,17 @@ If it exits non-zero, stop and report the issue. Do not proceed with tasks until
149
149
  The harness exposes tools via MCP server on port ${port}. Use these instead of reading files directly.
150
150
 
151
151
  \`\`\`
152
- actions.start taskId agent \u2192 start an action, returns actionId
153
- actions.write actionId section text \u2192 record a section (result, tools_used, ...)
154
- actions.complete actionId summary \u2192 close the action
155
- actions.get taskId \u2192 full action history for a task
156
- tasks.get [status] \u2192 list tasks (pending | in_progress | done | blocked)
157
- tasks.claim id \u2192 atomically claim a pending task
158
- tasks.update id status \u2192 change task status
159
- docs.search query \u2192 search ${docsPath} for relevant content
152
+ actions.start taskId agent \u2192 start an action, returns actionId
153
+ actions.write actionId section text \u2192 record a section (result, blockers, ...)
154
+ actions.record_tool actionId toolName [argsJson] [summary] \u2192 log a tool call to the Tools dashboard
155
+ actions.record_file actionId filePath operation [notes] \u2192 log a file touch to the Files dashboard
156
+ actions.complete actionId summary \u2192 close the action
157
+ actions.get taskId \u2192 full action history for a task
158
+ tasks.get [status] \u2192 list tasks (pending | in_progress | done | blocked)
159
+ tasks.claim id \u2192 atomically claim a pending task
160
+ tasks.update id status \u2192 change task status
161
+ tasks.acceptance.update criterionId \u2192 mark an acceptance criterion as met
162
+ docs.search query \u2192 search ${docsPath} for relevant content
160
163
  \`\`\`
161
164
 
162
165
  ## Workflow
@@ -169,7 +172,8 @@ docs.search query \u2192 search ${docsPath} for relevant c
169
172
 
170
173
  2. WORK (lead \u2192 explorer \u2192 builder \u2192 reviewer)
171
174
  - Each agent calls actions.start(taskId, agentName) \u2192 actionId
172
- - Records work with actions.write(actionId, section, content)
175
+ - After EVERY tool call: actions.record_tool(actionId, toolName, args, summary)
176
+ - After EVERY file change: actions.record_file(actionId, filePath, operation, notes)
173
177
  - Closes with actions.complete(actionId, summary)
174
178
 
175
179
  3. CLOSE
@@ -1161,12 +1165,27 @@ async function runHealth(cwd2) {
1161
1165
  // src/commands/init.ts
1162
1166
  import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
1163
1167
  import { homedir } from "os";
1164
- import { join as join9 } from "path";
1168
+ import { join as join10 } from "path";
1165
1169
  import * as p2 from "@clack/prompts";
1166
1170
  import pc6 from "picocolors";
1167
1171
 
1168
1172
  // src/commands/init-helpers.ts
1173
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
1174
+ import { join as join9 } from "path";
1169
1175
  import pc5 from "picocolors";
1176
+ function readProjectNameFromPackageJson(cwd2) {
1177
+ try {
1178
+ const pkgPath2 = join9(cwd2, "package.json");
1179
+ if (!existsSync7(pkgPath2)) return null;
1180
+ const content = readFileSync5(pkgPath2, "utf8");
1181
+ const pkg2 = JSON.parse(content);
1182
+ const name = pkg2?.name;
1183
+ if (typeof name === "string" && name.trim()) return name.trim();
1184
+ return null;
1185
+ } catch {
1186
+ return null;
1187
+ }
1188
+ }
1170
1189
  function applyConfigDefaults(params) {
1171
1190
  return {
1172
1191
  provider: params.provider,
@@ -1241,7 +1260,8 @@ function printWelcomeMessage(projectName) {
1241
1260
 
1242
1261
  // src/commands/init.ts
1243
1262
  async function runInit(cwd2, flags) {
1244
- const projectName = flags.name || "my-project";
1263
+ const detectedName = flags.name ?? readProjectNameFromPackageJson(cwd2);
1264
+ const projectName = detectedName || "my-project";
1245
1265
  printWelcomeMessage(projectName);
1246
1266
  let name;
1247
1267
  if (flags.name) {
@@ -1250,6 +1270,7 @@ async function runInit(cwd2, flags) {
1250
1270
  const val = await p2.text({
1251
1271
  message: "Project name",
1252
1272
  placeholder: "my-app",
1273
+ ...detectedName && { initialValue: detectedName },
1253
1274
  validate: (v) => v.trim() ? void 0 : "Project name is required"
1254
1275
  });
1255
1276
  if (p2.isCancel(val)) {
@@ -1373,9 +1394,9 @@ async function runInit(cwd2, flags) {
1373
1394
  let installDir = cwd2;
1374
1395
  if (globalInstallation) {
1375
1396
  if (provider === "claude-code") {
1376
- installDir = join9(homedir(), ".claude");
1397
+ installDir = join10(homedir(), ".claude");
1377
1398
  } else {
1378
- installDir = join9(homedir(), ".config", "opencode");
1399
+ installDir = join10(homedir(), ".config", "opencode");
1379
1400
  }
1380
1401
  }
1381
1402
  const configContent = configTs({
@@ -1386,8 +1407,8 @@ async function runInit(cwd2, flags) {
1386
1407
  tasksAdapter,
1387
1408
  port: config.tools.mcp.port
1388
1409
  });
1389
- writeFileSync7(join9(installDir, "agent-harness-kit.config.ts"), configContent, "utf8");
1390
- mkdirSync6(join9(installDir, config.storage.dir), { recursive: true });
1410
+ writeFileSync7(join10(installDir, "agent-harness-kit.config.ts"), configContent, "utf8");
1411
+ mkdirSync6(join10(installDir, config.storage.dir), { recursive: true });
1391
1412
  const db = openDB(config, installDir);
1392
1413
  await materializer.scaffold(config, { cwd: installDir, firstTask });
1393
1414
  if (firstTask) {
@@ -1468,9 +1489,137 @@ async function runMigrate(cwd2, opts) {
1468
1489
  }
1469
1490
  }
1470
1491
 
1492
+ // src/commands/reset.ts
1493
+ import { existsSync as existsSync8, readdirSync, rmSync } from "fs";
1494
+ import { join as join11, resolve as resolve7 } from "path";
1495
+ import * as p4 from "@clack/prompts";
1496
+ import pc8 from "picocolors";
1497
+ async function resetAgentMds(cwd2, provider) {
1498
+ const agentDir = provider === "claude-code" ? ".claude/agents" : ".opencode/agents";
1499
+ const agentDirPath = resolve7(cwd2, agentDir);
1500
+ if (!existsSync8(agentDirPath)) {
1501
+ console.log(pc8.yellow(` Skipping agent files \u2014 directory not found: ${agentDirPath}`));
1502
+ return;
1503
+ }
1504
+ const existingFiles = [];
1505
+ try {
1506
+ const files = readdirSync(agentDirPath);
1507
+ for (const f of files) {
1508
+ if (f.endsWith(".md")) {
1509
+ existingFiles.push(f);
1510
+ }
1511
+ }
1512
+ } catch {
1513
+ console.log(pc8.yellow(` Skipping agent files \u2014 ${agentDirPath} is not readable`));
1514
+ return;
1515
+ }
1516
+ if (existingFiles.length === 0) {
1517
+ console.log(pc8.yellow(` No agent MD files found in ${agentDir}/`));
1518
+ return;
1519
+ }
1520
+ for (const file of existingFiles) {
1521
+ const confirm3 = await p4.confirm({
1522
+ message: `Remove ${file}?`,
1523
+ initialValue: true
1524
+ });
1525
+ if (p4.isCancel(confirm3)) {
1526
+ console.log(pc8.red(" Cancelled by user."));
1527
+ return;
1528
+ }
1529
+ if (confirm3) {
1530
+ try {
1531
+ const filePath = join11(agentDirPath, file);
1532
+ rmSync(filePath, { force: true });
1533
+ console.log(pc8.green(` Removed ${file}`));
1534
+ } catch {
1535
+ console.error(pc8.red(` Failed to remove ${file}`));
1536
+ }
1537
+ } else {
1538
+ console.log(pc8.cyan(` Skipped ${file}`));
1539
+ }
1540
+ }
1541
+ }
1542
+ async function runReset(cwd2, opts) {
1543
+ let config;
1544
+ try {
1545
+ config = await loadConfig(cwd2);
1546
+ } catch {
1547
+ console.error(pc8.red("\u2717 No agent-harness-kit.config found. Run: ahk init"));
1548
+ process.exit(1);
1549
+ }
1550
+ const storageDir = config.storage.dir || ".harness";
1551
+ const dbPath = resolve7(cwd2, storageDir, "harness.db");
1552
+ const featureListPath = resolve7(cwd2, storageDir, "feature_list.json");
1553
+ let resetDb = false;
1554
+ let resetFeatureList = false;
1555
+ let resetAgentMdsFlag = false;
1556
+ if (existsSync8(dbPath)) {
1557
+ if (opts.force) {
1558
+ resetDb = true;
1559
+ } else {
1560
+ const confirm3 = await p4.confirm({
1561
+ message: `Delete database (${storageDir}/harness.db)?`,
1562
+ initialValue: true
1563
+ });
1564
+ if (p4.isCancel(confirm3)) {
1565
+ console.log(pc8.red(" Cancelled by user."));
1566
+ return;
1567
+ }
1568
+ resetDb = confirm3;
1569
+ }
1570
+ }
1571
+ if (existsSync8(featureListPath)) {
1572
+ if (opts.force) {
1573
+ resetFeatureList = true;
1574
+ } else {
1575
+ const confirm3 = await p4.confirm({
1576
+ message: `Delete feature list (${storageDir}/feature_list.json)?`,
1577
+ initialValue: true
1578
+ });
1579
+ if (p4.isCancel(confirm3)) {
1580
+ console.log(pc8.red(" Cancelled by user."));
1581
+ return;
1582
+ }
1583
+ resetFeatureList = confirm3;
1584
+ }
1585
+ }
1586
+ if (opts.provider) {
1587
+ resetAgentMdsFlag = true;
1588
+ }
1589
+ let changed = false;
1590
+ if (resetDb) {
1591
+ try {
1592
+ rmSync(dbPath, { force: true });
1593
+ console.log(pc8.green(` \u2713 Removed ${storageDir}/harness.db`));
1594
+ changed = true;
1595
+ } catch {
1596
+ console.error(pc8.red(` \u2717 Failed to remove ${dbPath}`));
1597
+ }
1598
+ }
1599
+ if (resetFeatureList) {
1600
+ try {
1601
+ rmSync(featureListPath, { force: true });
1602
+ console.log(pc8.green(` \u2713 Removed ${storageDir}/feature_list.json`));
1603
+ changed = true;
1604
+ } catch {
1605
+ console.error(pc8.red(` \u2717 Failed to remove ${featureListPath}`));
1606
+ }
1607
+ }
1608
+ if (resetAgentMdsFlag) {
1609
+ console.log("");
1610
+ await resetAgentMds(cwd2, opts.provider || "claude-code");
1611
+ }
1612
+ if (!resetDb && !resetFeatureList && !resetAgentMdsFlag) {
1613
+ console.log(pc8.yellow(" Nothing to reset (all items missing or skipped)."));
1614
+ return;
1615
+ }
1616
+ console.log("");
1617
+ console.log(pc8.green('\u2713 Reset complete. Run "ahk init" to scaffold a fresh harness.'));
1618
+ }
1619
+
1471
1620
  // src/core/mcp-server.ts
1472
- import { readdirSync, readFileSync as readFileSync5, statSync } from "fs";
1473
- import { join as join10, resolve as resolve7 } from "path";
1621
+ import { readdirSync as readdirSync2, readFileSync as readFileSync6, statSync } from "fs";
1622
+ import { join as join12, resolve as resolve8 } from "path";
1474
1623
  import { Server } from "@modelcontextprotocol/sdk/server";
1475
1624
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
1476
1625
  import {
@@ -1631,7 +1780,7 @@ var TOOLS = [
1631
1780
  ];
1632
1781
  async function startMcpServer(config, cwd2) {
1633
1782
  const db = openDB(config, cwd2);
1634
- const docsPath = resolve7(cwd2, config.project.docsPath);
1783
+ const docsPath = resolve8(cwd2, config.project.docsPath);
1635
1784
  const server = new Server(
1636
1785
  { name: "agent-harness-kit", version: VERSION },
1637
1786
  { capabilities: { tools: {} } }
@@ -1741,7 +1890,7 @@ function searchDocs(docsPath, query, maxResults = 10) {
1741
1890
  for (const file of files) {
1742
1891
  if (results.length >= maxResults) break;
1743
1892
  try {
1744
- const content = readFileSync5(file, "utf8");
1893
+ const content = readFileSync6(file, "utf8");
1745
1894
  const lines = content.split("\n");
1746
1895
  for (let i = 0; i < lines.length; i++) {
1747
1896
  const lower = lines[i].toLowerCase();
@@ -1761,8 +1910,8 @@ function searchDocs(docsPath, query, maxResults = 10) {
1761
1910
  function collectMarkdownFiles(dir) {
1762
1911
  const files = [];
1763
1912
  try {
1764
- for (const entry of readdirSync(dir)) {
1765
- const full = join10(dir, entry);
1913
+ for (const entry of readdirSync2(dir)) {
1914
+ const full = join12(dir, entry);
1766
1915
  const stat = statSync(full);
1767
1916
  if (stat.isDirectory()) {
1768
1917
  files.push(...collectMarkdownFiles(full));
@@ -1801,12 +1950,12 @@ async function runServe(cwd2, opts) {
1801
1950
 
1802
1951
  // src/commands/status.ts
1803
1952
  import Table from "cli-table3";
1804
- import pc8 from "picocolors";
1953
+ import pc9 from "picocolors";
1805
1954
  var STATUS_COLOR = {
1806
- pending: (s) => pc8.dim(s),
1807
- in_progress: (s) => pc8.cyan(s),
1808
- done: (s) => pc8.green(s),
1809
- blocked: (s) => pc8.red(s)
1955
+ pending: (s) => pc9.dim(s),
1956
+ in_progress: (s) => pc9.cyan(s),
1957
+ done: (s) => pc9.green(s),
1958
+ blocked: (s) => pc9.red(s)
1810
1959
  };
1811
1960
  async function runStatus(cwd2, opts) {
1812
1961
  const config = await loadConfig(cwd2);
@@ -1824,11 +1973,11 @@ async function runStatus(cwd2, opts) {
1824
1973
  return;
1825
1974
  }
1826
1975
  if (tasks.length === 0) {
1827
- console.log(pc8.dim("No tasks yet. Run: ahk task add"));
1976
+ console.log(pc9.dim("No tasks yet. Run: ahk task add"));
1828
1977
  return;
1829
1978
  }
1830
1979
  const table = new Table({
1831
- head: ["ID", "Slug", "Title", "Status", "Assigned", "Started"].map((h) => pc8.bold(h)),
1980
+ head: ["ID", "Slug", "Title", "Status", "Assigned", "Started"].map((h) => pc9.bold(h)),
1832
1981
  style: { head: [], border: [] }
1833
1982
  });
1834
1983
  for (const t of tasks) {
@@ -1846,12 +1995,12 @@ async function runStatus(cwd2, opts) {
1846
1995
  const inProgress = tasks.filter((t) => t.status === "in_progress");
1847
1996
  if (inProgress.length > 0) {
1848
1997
  console.log("");
1849
- console.log(pc8.bold("Active actions:"));
1998
+ console.log(pc9.bold("Active actions:"));
1850
1999
  for (const t of inProgress) {
1851
2000
  const actions = db.getActionsForTask(t.id);
1852
2001
  const active = actions.filter((a) => a.status === "in_progress");
1853
2002
  for (const a of active) {
1854
- console.log(` ${pc8.cyan(a.agent.padEnd(10))} \u2192 task #${t.id} ${t.slug}`);
2003
+ console.log(` ${pc9.cyan(a.agent.padEnd(10))} \u2192 task #${t.id} ${t.slug}`);
1855
2004
  }
1856
2005
  }
1857
2006
  }
@@ -1860,20 +2009,20 @@ async function runStatus(cwd2, opts) {
1860
2009
  const fn = STATUS_COLOR[s.status] ?? ((x) => x);
1861
2010
  return `${fn(s.status)}: ${s.total}`;
1862
2011
  });
1863
- console.log(pc8.dim("Tasks \u2014 ") + parts.join(pc8.dim(" | ")));
2012
+ console.log(pc9.dim("Tasks \u2014 ") + parts.join(pc9.dim(" | ")));
1864
2013
  } finally {
1865
2014
  db.close();
1866
2015
  }
1867
2016
  }
1868
2017
 
1869
2018
  // src/commands/sync.ts
1870
- import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
1871
- import { join as join11, resolve as resolve8 } from "path";
1872
- import pc9 from "picocolors";
2019
+ import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
2020
+ import { join as join13, resolve as resolve9 } from "path";
2021
+ import pc10 from "picocolors";
1873
2022
  async function runSync(cwd2, opts) {
1874
2023
  const config = await loadConfig(cwd2);
1875
2024
  const direction = opts.direction ?? "both";
1876
- const featureListPath = resolve8(join11(cwd2, config.storage.dir, "feature_list.json"));
2025
+ const featureListPath = resolve9(join13(cwd2, config.storage.dir, "feature_list.json"));
1877
2026
  const db = openDB(config, cwd2);
1878
2027
  try {
1879
2028
  if (direction === "in" || direction === "both") {
@@ -1887,70 +2036,70 @@ async function runSync(cwd2, opts) {
1887
2036
  }
1888
2037
  }
1889
2038
  async function syncIn(featureListPath, db, dryRun) {
1890
- if (!existsSync7(featureListPath)) {
1891
- console.log(pc9.dim(`feature_list.json not found at ${featureListPath} \u2014 skipping in-sync`));
2039
+ if (!existsSync9(featureListPath)) {
2040
+ console.log(pc10.dim(`feature_list.json not found at ${featureListPath} \u2014 skipping in-sync`));
1892
2041
  return;
1893
2042
  }
1894
2043
  let seeds;
1895
2044
  try {
1896
- seeds = JSON.parse(readFileSync6(featureListPath, "utf8"));
2045
+ seeds = JSON.parse(readFileSync7(featureListPath, "utf8"));
1897
2046
  } catch (err) {
1898
- console.error(pc9.red(`Failed to parse feature_list.json: ${err}`));
2047
+ console.error(pc10.red(`Failed to parse feature_list.json: ${err}`));
1899
2048
  process.exit(1);
1900
2049
  }
1901
2050
  if (dryRun) {
1902
- console.log(pc9.bold("Dry run \u2014 in-sync (feature_list.json \u2192 SQLite):"));
2051
+ console.log(pc10.bold("Dry run \u2014 in-sync (feature_list.json \u2192 SQLite):"));
1903
2052
  for (const t of seeds) {
1904
2053
  const existing = db.getTaskBySlug(t.slug);
1905
- console.log(` ${existing ? pc9.dim("skip") : pc9.green("add ")} ${t.slug}`);
2054
+ console.log(` ${existing ? pc10.dim("skip") : pc10.green("add ")} ${t.slug}`);
1906
2055
  }
1907
2056
  return;
1908
2057
  }
1909
2058
  const result = db.syncFromFeatureList(seeds);
1910
- console.log(pc9.green(`\u2713 In-sync: ${result.added} added, ${result.skipped} already existed`));
2059
+ console.log(pc10.green(`\u2713 In-sync: ${result.added} added, ${result.skipped} already existed`));
1911
2060
  }
1912
2061
  function syncOut(db, cwd2, dryRun) {
1913
2062
  if (dryRun) {
1914
2063
  const tasks = db.getTasks();
1915
- console.log(pc9.bold("Dry run \u2014 out-sync (SQLite \u2192 feature_list.json):"));
2064
+ console.log(pc10.bold("Dry run \u2014 out-sync (SQLite \u2192 feature_list.json):"));
1916
2065
  console.log(` ${tasks.length} tasks would be written`);
1917
2066
  return;
1918
2067
  }
1919
2068
  db.writeFeatureList(cwd2);
1920
- console.log(pc9.green("\u2713 Out-sync: feature_list.json updated"));
2069
+ console.log(pc10.green("\u2713 Out-sync: feature_list.json updated"));
1921
2070
  }
1922
2071
 
1923
2072
  // src/commands/task/add.ts
1924
- import * as p4 from "@clack/prompts";
1925
- import pc10 from "picocolors";
2073
+ import * as p5 from "@clack/prompts";
2074
+ import pc11 from "picocolors";
1926
2075
  async function runTaskAdd(cwd2) {
1927
- p4.intro(pc10.bold("agent-harness-kit \u2014 add task"));
1928
- const titleVal = await p4.text({
2076
+ p5.intro(pc11.bold("agent-harness-kit \u2014 add task"));
2077
+ const titleVal = await p5.text({
1929
2078
  message: "Task title",
1930
2079
  validate: (v) => v.trim() ? void 0 : "Title is required"
1931
2080
  });
1932
- if (p4.isCancel(titleVal)) {
1933
- p4.cancel("Cancelled.");
2081
+ if (p5.isCancel(titleVal)) {
2082
+ p5.cancel("Cancelled.");
1934
2083
  process.exit(0);
1935
2084
  }
1936
2085
  const title = titleVal.trim();
1937
- const descVal = await p4.text({
2086
+ const descVal = await p5.text({
1938
2087
  message: "Description (what and why)",
1939
2088
  placeholder: "Optional"
1940
2089
  });
1941
- if (p4.isCancel(descVal)) {
1942
- p4.cancel("Cancelled.");
2090
+ if (p5.isCancel(descVal)) {
2091
+ p5.cancel("Cancelled.");
1943
2092
  process.exit(0);
1944
2093
  }
1945
2094
  const description = descVal.trim();
1946
2095
  const acceptance = [];
1947
- p4.log.info("Acceptance criteria \u2014 one per line, empty line to finish");
2096
+ p5.log.info("Acceptance criteria \u2014 one per line, empty line to finish");
1948
2097
  while (true) {
1949
- const val = await p4.text({ message: ">", placeholder: "Criterion (or press Enter to finish)" });
1950
- if (p4.isCancel(val) || !val || !val.trim()) break;
2098
+ const val = await p5.text({ message: ">", placeholder: "Criterion (or press Enter to finish)" });
2099
+ if (p5.isCancel(val) || !val || !val.trim()) break;
1951
2100
  acceptance.push(val.trim());
1952
2101
  }
1953
- const spinner5 = p4.spinner();
2102
+ const spinner5 = p5.spinner();
1954
2103
  spinner5.start("Saving...");
1955
2104
  try {
1956
2105
  const config = await loadConfig(cwd2);
@@ -1960,28 +2109,28 @@ async function runTaskAdd(cwd2) {
1960
2109
  db.writeFeatureList(cwd2);
1961
2110
  db.close();
1962
2111
  spinner5.stop("");
1963
- console.log(pc10.green(`\u2713 Task #${task2.id} added \u2014 ${task2.slug} (pending)`));
1964
- console.log(pc10.cyan("\u2192") + " " + pc10.cyan("ahk status") + " to see all tasks");
2112
+ console.log(pc11.green(`\u2713 Task #${task2.id} added \u2014 ${task2.slug} (pending)`));
2113
+ console.log(pc11.cyan("\u2192") + " " + pc11.cyan("ahk status") + " to see all tasks");
1965
2114
  } catch (err) {
1966
- spinner5.stop(pc10.red("Failed"));
1967
- p4.log.error(err instanceof Error ? err.message : String(err));
2115
+ spinner5.stop(pc11.red("Failed"));
2116
+ p5.log.error(err instanceof Error ? err.message : String(err));
1968
2117
  process.exit(1);
1969
2118
  }
1970
2119
  }
1971
2120
 
1972
2121
  // src/commands/task/done.ts
1973
2122
  import { spawnSync as spawnSync2 } from "child_process";
1974
- import { existsSync as existsSync8 } from "fs";
1975
- import { resolve as resolve9 } from "path";
1976
- import pc11 from "picocolors";
2123
+ import { existsSync as existsSync10 } from "fs";
2124
+ import { resolve as resolve10 } from "path";
2125
+ import pc12 from "picocolors";
1977
2126
  async function runTaskDone(cwd2, idOrSlug) {
1978
2127
  const config = await loadConfig(cwd2);
1979
2128
  if (config.health.required) {
1980
- const scriptPath = resolve9(cwd2, config.health.scriptPath);
1981
- if (existsSync8(scriptPath)) {
2129
+ const scriptPath = resolve10(cwd2, config.health.scriptPath);
2130
+ if (existsSync10(scriptPath)) {
1982
2131
  const result = spawnSync2("bash", [scriptPath], { cwd: cwd2, stdio: "pipe", encoding: "utf8" });
1983
2132
  if (result.status !== 0) {
1984
- console.error(pc11.red("\u2717 Health check failed \u2014 cannot mark task as done."));
2133
+ console.error(pc12.red("\u2717 Health check failed \u2014 cannot mark task as done."));
1985
2134
  if (result.stdout) console.error(result.stdout);
1986
2135
  if (result.stderr) console.error(result.stderr);
1987
2136
  process.exit(1);
@@ -1994,16 +2143,16 @@ async function runTaskDone(cwd2, idOrSlug) {
1994
2143
  const isId = !isNaN(parsed);
1995
2144
  const task2 = isId ? db.getTaskById(parsed) : db.getTaskBySlug(idOrSlug);
1996
2145
  if (!task2) {
1997
- console.error(pc11.red(`Task not found: ${idOrSlug}`));
2146
+ console.error(pc12.red(`Task not found: ${idOrSlug}`));
1998
2147
  process.exit(1);
1999
2148
  }
2000
2149
  if (task2.status === "done") {
2001
- console.log(pc11.dim(`Task #${task2.id} is already done.`));
2150
+ console.log(pc12.dim(`Task #${task2.id} is already done.`));
2002
2151
  return;
2003
2152
  }
2004
2153
  db.updateTaskStatus(task2.id, "done");
2005
2154
  db.writeFeatureList(cwd2);
2006
- console.log(pc11.green(`\u2713 Task #${task2.id} \u2014 ${task2.slug} marked as done`));
2155
+ console.log(pc12.green(`\u2713 Task #${task2.id} \u2014 ${task2.slug} marked as done`));
2007
2156
  } finally {
2008
2157
  db.close();
2009
2158
  }
@@ -2011,12 +2160,12 @@ async function runTaskDone(cwd2, idOrSlug) {
2011
2160
 
2012
2161
  // src/commands/task/list.ts
2013
2162
  import Table2 from "cli-table3";
2014
- import pc12 from "picocolors";
2163
+ import pc13 from "picocolors";
2015
2164
  var STATUS_COLOR2 = {
2016
- pending: (s) => pc12.dim(s),
2017
- in_progress: (s) => pc12.cyan(s),
2018
- done: (s) => pc12.green(s),
2019
- blocked: (s) => pc12.red(s)
2165
+ pending: (s) => pc13.dim(s),
2166
+ in_progress: (s) => pc13.cyan(s),
2167
+ done: (s) => pc13.green(s),
2168
+ blocked: (s) => pc13.red(s)
2020
2169
  };
2021
2170
  async function runTaskList(cwd2, opts) {
2022
2171
  const config = await loadConfig(cwd2);
@@ -2030,11 +2179,11 @@ async function runTaskList(cwd2, opts) {
2030
2179
  return;
2031
2180
  }
2032
2181
  if (tasks.length === 0) {
2033
- console.log(pc12.dim("No tasks" + (filterStatus ? ` with status: ${filterStatus}` : "") + "."));
2182
+ console.log(pc13.dim("No tasks" + (filterStatus ? ` with status: ${filterStatus}` : "") + "."));
2034
2183
  return;
2035
2184
  }
2036
2185
  const table = new Table2({
2037
- head: ["ID", "Slug", "Title", "Status"].map((h) => pc12.bold(h)),
2186
+ head: ["ID", "Slug", "Title", "Status"].map((h) => pc13.bold(h)),
2038
2187
  style: { head: [], border: [] }
2039
2188
  });
2040
2189
  for (const t of tasks) {
@@ -2049,14 +2198,14 @@ async function runTaskList(cwd2, opts) {
2049
2198
 
2050
2199
  // src/core/package-data.ts
2051
2200
  import { createRequire as createRequire2 } from "module";
2052
- import { dirname as dirname5, join as join12 } from "path";
2201
+ import { dirname as dirname5, join as join14 } from "path";
2053
2202
  import { fileURLToPath as fileURLToPath3 } from "url";
2054
2203
  var require2 = createRequire2(import.meta.url);
2055
- var pkgPath = join12(dirname5(fileURLToPath3(import.meta.url)), "..", "package.json");
2204
+ var pkgPath = join14(dirname5(fileURLToPath3(import.meta.url)), "..", "package.json");
2056
2205
  var pkg = require2(pkgPath);
2057
2206
 
2058
2207
  // src/core/update-check.ts
2059
- import pc13 from "picocolors";
2208
+ import pc14 from "picocolors";
2060
2209
  var REGISTRY_URL = `https://registry.npmjs.org/${pkg.name}/latest`;
2061
2210
  var TIMEOUT_MS = 2500;
2062
2211
  function checkForUpdate(currentVersion) {
@@ -2074,18 +2223,18 @@ function checkForUpdate(currentVersion) {
2074
2223
  }
2075
2224
  function printUpdateMessage({ current, latest }) {
2076
2225
  const lines = [
2077
- ` Update available ${pc13.dim(current)} \u2192 ${pc13.green(latest)} `,
2078
- ` Run: ${pc13.cyan(`npm i ${pkg.name}@${latest}`)} `
2226
+ ` Update available ${pc14.dim(current)} \u2192 ${pc14.green(latest)} `,
2227
+ ` Run: ${pc14.cyan(`npm i ${pkg.name}@${latest}`)} `
2079
2228
  ];
2080
2229
  const width = Math.max(...lines.map((l) => stripAnsi2(l).length));
2081
2230
  const border = "\u2500".repeat(width);
2082
2231
  console.log();
2083
- console.log(pc13.yellow(`\u250C${border}\u2510`));
2232
+ console.log(pc14.yellow(`\u250C${border}\u2510`));
2084
2233
  for (const line of lines) {
2085
2234
  const pad = width - stripAnsi2(line).length;
2086
- console.log(pc13.yellow("\u2502") + line + " ".repeat(pad) + pc13.yellow("\u2502"));
2235
+ console.log(pc14.yellow("\u2502") + line + " ".repeat(pad) + pc14.yellow("\u2502"));
2087
2236
  }
2088
- console.log(pc13.yellow(`\u2514${border}\u2518`));
2237
+ console.log(pc14.yellow(`\u2514${border}\u2518`));
2089
2238
  console.log();
2090
2239
  }
2091
2240
  function isNewer(latest, current) {
@@ -2100,134 +2249,6 @@ function stripAnsi2(str2) {
2100
2249
  return str2.replace(/\x1B\[[0-9;]*m/g, "");
2101
2250
  }
2102
2251
 
2103
- // src/commands/reset.ts
2104
- import { existsSync as existsSync9, readdirSync as readdirSync2, rmSync } from "fs";
2105
- import { join as join13, resolve as resolve10 } from "path";
2106
- import * as p5 from "@clack/prompts";
2107
- import pc14 from "picocolors";
2108
- async function resetAgentMds(cwd2, provider) {
2109
- const agentDir = provider === "claude-code" ? ".claude/agents" : ".opencode/agents";
2110
- const agentDirPath = resolve10(cwd2, agentDir);
2111
- if (!existsSync9(agentDirPath)) {
2112
- console.log(pc14.yellow(` Skipping agent files \u2014 directory not found: ${agentDirPath}`));
2113
- return;
2114
- }
2115
- const existingFiles = [];
2116
- try {
2117
- const files = readdirSync2(agentDirPath);
2118
- for (const f of files) {
2119
- if (f.endsWith(".md")) {
2120
- existingFiles.push(f);
2121
- }
2122
- }
2123
- } catch {
2124
- console.log(pc14.yellow(` Skipping agent files \u2014 ${agentDirPath} is not readable`));
2125
- return;
2126
- }
2127
- if (existingFiles.length === 0) {
2128
- console.log(pc14.yellow(` No agent MD files found in ${agentDir}/`));
2129
- return;
2130
- }
2131
- for (const file of existingFiles) {
2132
- const confirm3 = await p5.confirm({
2133
- message: `Remove ${file}?`,
2134
- initialValue: true
2135
- });
2136
- if (p5.isCancel(confirm3)) {
2137
- console.log(pc14.red(" Cancelled by user."));
2138
- return;
2139
- }
2140
- if (confirm3) {
2141
- try {
2142
- const filePath = join13(agentDirPath, file);
2143
- rmSync(filePath, { force: true });
2144
- console.log(pc14.green(` Removed ${file}`));
2145
- } catch {
2146
- console.error(pc14.red(` Failed to remove ${file}`));
2147
- }
2148
- } else {
2149
- console.log(pc14.cyan(` Skipped ${file}`));
2150
- }
2151
- }
2152
- }
2153
- async function runReset(cwd2, opts) {
2154
- let config;
2155
- try {
2156
- config = await loadConfig(cwd2);
2157
- } catch {
2158
- console.error(pc14.red("\u2717 No agent-harness-kit.config found. Run: ahk init"));
2159
- process.exit(1);
2160
- }
2161
- const storageDir = config.storage.dir || ".harness";
2162
- const dbPath = resolve10(cwd2, storageDir, "harness.db");
2163
- const featureListPath = resolve10(cwd2, storageDir, "feature_list.json");
2164
- let resetDb = false;
2165
- let resetFeatureList = false;
2166
- let resetAgentMdsFlag = false;
2167
- if (existsSync9(dbPath)) {
2168
- if (opts.force) {
2169
- resetDb = true;
2170
- } else {
2171
- const confirm3 = await p5.confirm({
2172
- message: `Delete database (${storageDir}/harness.db)?`,
2173
- initialValue: true
2174
- });
2175
- if (p5.isCancel(confirm3)) {
2176
- console.log(pc14.red(" Cancelled by user."));
2177
- return;
2178
- }
2179
- resetDb = confirm3;
2180
- }
2181
- }
2182
- if (existsSync9(featureListPath)) {
2183
- if (opts.force) {
2184
- resetFeatureList = true;
2185
- } else {
2186
- const confirm3 = await p5.confirm({
2187
- message: `Delete feature list (${storageDir}/feature_list.json)?`,
2188
- initialValue: true
2189
- });
2190
- if (p5.isCancel(confirm3)) {
2191
- console.log(pc14.red(" Cancelled by user."));
2192
- return;
2193
- }
2194
- resetFeatureList = confirm3;
2195
- }
2196
- }
2197
- if (opts.provider) {
2198
- resetAgentMdsFlag = true;
2199
- }
2200
- let changed = false;
2201
- if (resetDb) {
2202
- try {
2203
- rmSync(dbPath, { force: true });
2204
- console.log(pc14.green(` \u2713 Removed ${storageDir}/harness.db`));
2205
- changed = true;
2206
- } catch {
2207
- console.error(pc14.red(` \u2717 Failed to remove ${dbPath}`));
2208
- }
2209
- }
2210
- if (resetFeatureList) {
2211
- try {
2212
- rmSync(featureListPath, { force: true });
2213
- console.log(pc14.green(` \u2713 Removed ${storageDir}/feature_list.json`));
2214
- changed = true;
2215
- } catch {
2216
- console.error(pc14.red(` \u2717 Failed to remove ${featureListPath}`));
2217
- }
2218
- }
2219
- if (resetAgentMdsFlag) {
2220
- console.log("");
2221
- await resetAgentMds(cwd2, opts.provider || "claude-code");
2222
- }
2223
- if (!resetDb && !resetFeatureList && !resetAgentMdsFlag) {
2224
- console.log(pc14.yellow(" Nothing to reset (all items missing or skipped)."));
2225
- return;
2226
- }
2227
- console.log("");
2228
- console.log(pc14.green('\u2713 Reset complete. Run "ahk init" to scaffold a fresh harness.'));
2229
- }
2230
-
2231
2252
  // src/cli.ts
2232
2253
  var cwd = process.cwd();
2233
2254
  var updateCheck = checkForUpdate(pkg.version);