@cardor/agent-harness-kit 0.17.0 → 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 +197 -196
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1270,6 +1270,7 @@ async function runInit(cwd2, flags) {
|
|
|
1270
1270
|
const val = await p2.text({
|
|
1271
1271
|
message: "Project name",
|
|
1272
1272
|
placeholder: "my-app",
|
|
1273
|
+
...detectedName && { initialValue: detectedName },
|
|
1273
1274
|
validate: (v) => v.trim() ? void 0 : "Project name is required"
|
|
1274
1275
|
});
|
|
1275
1276
|
if (p2.isCancel(val)) {
|
|
@@ -1488,9 +1489,137 @@ async function runMigrate(cwd2, opts) {
|
|
|
1488
1489
|
}
|
|
1489
1490
|
}
|
|
1490
1491
|
|
|
1491
|
-
// src/
|
|
1492
|
-
import {
|
|
1492
|
+
// src/commands/reset.ts
|
|
1493
|
+
import { existsSync as existsSync8, readdirSync, rmSync } from "fs";
|
|
1493
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
|
+
|
|
1620
|
+
// src/core/mcp-server.ts
|
|
1621
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync6, statSync } from "fs";
|
|
1622
|
+
import { join as join12, resolve as resolve8 } from "path";
|
|
1494
1623
|
import { Server } from "@modelcontextprotocol/sdk/server";
|
|
1495
1624
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1496
1625
|
import {
|
|
@@ -1651,7 +1780,7 @@ var TOOLS = [
|
|
|
1651
1780
|
];
|
|
1652
1781
|
async function startMcpServer(config, cwd2) {
|
|
1653
1782
|
const db = openDB(config, cwd2);
|
|
1654
|
-
const docsPath =
|
|
1783
|
+
const docsPath = resolve8(cwd2, config.project.docsPath);
|
|
1655
1784
|
const server = new Server(
|
|
1656
1785
|
{ name: "agent-harness-kit", version: VERSION },
|
|
1657
1786
|
{ capabilities: { tools: {} } }
|
|
@@ -1781,8 +1910,8 @@ function searchDocs(docsPath, query, maxResults = 10) {
|
|
|
1781
1910
|
function collectMarkdownFiles(dir) {
|
|
1782
1911
|
const files = [];
|
|
1783
1912
|
try {
|
|
1784
|
-
for (const entry of
|
|
1785
|
-
const full =
|
|
1913
|
+
for (const entry of readdirSync2(dir)) {
|
|
1914
|
+
const full = join12(dir, entry);
|
|
1786
1915
|
const stat = statSync(full);
|
|
1787
1916
|
if (stat.isDirectory()) {
|
|
1788
1917
|
files.push(...collectMarkdownFiles(full));
|
|
@@ -1821,12 +1950,12 @@ async function runServe(cwd2, opts) {
|
|
|
1821
1950
|
|
|
1822
1951
|
// src/commands/status.ts
|
|
1823
1952
|
import Table from "cli-table3";
|
|
1824
|
-
import
|
|
1953
|
+
import pc9 from "picocolors";
|
|
1825
1954
|
var STATUS_COLOR = {
|
|
1826
|
-
pending: (s) =>
|
|
1827
|
-
in_progress: (s) =>
|
|
1828
|
-
done: (s) =>
|
|
1829
|
-
blocked: (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)
|
|
1830
1959
|
};
|
|
1831
1960
|
async function runStatus(cwd2, opts) {
|
|
1832
1961
|
const config = await loadConfig(cwd2);
|
|
@@ -1844,11 +1973,11 @@ async function runStatus(cwd2, opts) {
|
|
|
1844
1973
|
return;
|
|
1845
1974
|
}
|
|
1846
1975
|
if (tasks.length === 0) {
|
|
1847
|
-
console.log(
|
|
1976
|
+
console.log(pc9.dim("No tasks yet. Run: ahk task add"));
|
|
1848
1977
|
return;
|
|
1849
1978
|
}
|
|
1850
1979
|
const table = new Table({
|
|
1851
|
-
head: ["ID", "Slug", "Title", "Status", "Assigned", "Started"].map((h) =>
|
|
1980
|
+
head: ["ID", "Slug", "Title", "Status", "Assigned", "Started"].map((h) => pc9.bold(h)),
|
|
1852
1981
|
style: { head: [], border: [] }
|
|
1853
1982
|
});
|
|
1854
1983
|
for (const t of tasks) {
|
|
@@ -1866,12 +1995,12 @@ async function runStatus(cwd2, opts) {
|
|
|
1866
1995
|
const inProgress = tasks.filter((t) => t.status === "in_progress");
|
|
1867
1996
|
if (inProgress.length > 0) {
|
|
1868
1997
|
console.log("");
|
|
1869
|
-
console.log(
|
|
1998
|
+
console.log(pc9.bold("Active actions:"));
|
|
1870
1999
|
for (const t of inProgress) {
|
|
1871
2000
|
const actions = db.getActionsForTask(t.id);
|
|
1872
2001
|
const active = actions.filter((a) => a.status === "in_progress");
|
|
1873
2002
|
for (const a of active) {
|
|
1874
|
-
console.log(` ${
|
|
2003
|
+
console.log(` ${pc9.cyan(a.agent.padEnd(10))} \u2192 task #${t.id} ${t.slug}`);
|
|
1875
2004
|
}
|
|
1876
2005
|
}
|
|
1877
2006
|
}
|
|
@@ -1880,20 +2009,20 @@ async function runStatus(cwd2, opts) {
|
|
|
1880
2009
|
const fn = STATUS_COLOR[s.status] ?? ((x) => x);
|
|
1881
2010
|
return `${fn(s.status)}: ${s.total}`;
|
|
1882
2011
|
});
|
|
1883
|
-
console.log(
|
|
2012
|
+
console.log(pc9.dim("Tasks \u2014 ") + parts.join(pc9.dim(" | ")));
|
|
1884
2013
|
} finally {
|
|
1885
2014
|
db.close();
|
|
1886
2015
|
}
|
|
1887
2016
|
}
|
|
1888
2017
|
|
|
1889
2018
|
// src/commands/sync.ts
|
|
1890
|
-
import { existsSync as
|
|
1891
|
-
import { join as
|
|
1892
|
-
import
|
|
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";
|
|
1893
2022
|
async function runSync(cwd2, opts) {
|
|
1894
2023
|
const config = await loadConfig(cwd2);
|
|
1895
2024
|
const direction = opts.direction ?? "both";
|
|
1896
|
-
const featureListPath =
|
|
2025
|
+
const featureListPath = resolve9(join13(cwd2, config.storage.dir, "feature_list.json"));
|
|
1897
2026
|
const db = openDB(config, cwd2);
|
|
1898
2027
|
try {
|
|
1899
2028
|
if (direction === "in" || direction === "both") {
|
|
@@ -1907,70 +2036,70 @@ async function runSync(cwd2, opts) {
|
|
|
1907
2036
|
}
|
|
1908
2037
|
}
|
|
1909
2038
|
async function syncIn(featureListPath, db, dryRun) {
|
|
1910
|
-
if (!
|
|
1911
|
-
console.log(
|
|
2039
|
+
if (!existsSync9(featureListPath)) {
|
|
2040
|
+
console.log(pc10.dim(`feature_list.json not found at ${featureListPath} \u2014 skipping in-sync`));
|
|
1912
2041
|
return;
|
|
1913
2042
|
}
|
|
1914
2043
|
let seeds;
|
|
1915
2044
|
try {
|
|
1916
2045
|
seeds = JSON.parse(readFileSync7(featureListPath, "utf8"));
|
|
1917
2046
|
} catch (err) {
|
|
1918
|
-
console.error(
|
|
2047
|
+
console.error(pc10.red(`Failed to parse feature_list.json: ${err}`));
|
|
1919
2048
|
process.exit(1);
|
|
1920
2049
|
}
|
|
1921
2050
|
if (dryRun) {
|
|
1922
|
-
console.log(
|
|
2051
|
+
console.log(pc10.bold("Dry run \u2014 in-sync (feature_list.json \u2192 SQLite):"));
|
|
1923
2052
|
for (const t of seeds) {
|
|
1924
2053
|
const existing = db.getTaskBySlug(t.slug);
|
|
1925
|
-
console.log(` ${existing ?
|
|
2054
|
+
console.log(` ${existing ? pc10.dim("skip") : pc10.green("add ")} ${t.slug}`);
|
|
1926
2055
|
}
|
|
1927
2056
|
return;
|
|
1928
2057
|
}
|
|
1929
2058
|
const result = db.syncFromFeatureList(seeds);
|
|
1930
|
-
console.log(
|
|
2059
|
+
console.log(pc10.green(`\u2713 In-sync: ${result.added} added, ${result.skipped} already existed`));
|
|
1931
2060
|
}
|
|
1932
2061
|
function syncOut(db, cwd2, dryRun) {
|
|
1933
2062
|
if (dryRun) {
|
|
1934
2063
|
const tasks = db.getTasks();
|
|
1935
|
-
console.log(
|
|
2064
|
+
console.log(pc10.bold("Dry run \u2014 out-sync (SQLite \u2192 feature_list.json):"));
|
|
1936
2065
|
console.log(` ${tasks.length} tasks would be written`);
|
|
1937
2066
|
return;
|
|
1938
2067
|
}
|
|
1939
2068
|
db.writeFeatureList(cwd2);
|
|
1940
|
-
console.log(
|
|
2069
|
+
console.log(pc10.green("\u2713 Out-sync: feature_list.json updated"));
|
|
1941
2070
|
}
|
|
1942
2071
|
|
|
1943
2072
|
// src/commands/task/add.ts
|
|
1944
|
-
import * as
|
|
1945
|
-
import
|
|
2073
|
+
import * as p5 from "@clack/prompts";
|
|
2074
|
+
import pc11 from "picocolors";
|
|
1946
2075
|
async function runTaskAdd(cwd2) {
|
|
1947
|
-
|
|
1948
|
-
const titleVal = await
|
|
2076
|
+
p5.intro(pc11.bold("agent-harness-kit \u2014 add task"));
|
|
2077
|
+
const titleVal = await p5.text({
|
|
1949
2078
|
message: "Task title",
|
|
1950
2079
|
validate: (v) => v.trim() ? void 0 : "Title is required"
|
|
1951
2080
|
});
|
|
1952
|
-
if (
|
|
1953
|
-
|
|
2081
|
+
if (p5.isCancel(titleVal)) {
|
|
2082
|
+
p5.cancel("Cancelled.");
|
|
1954
2083
|
process.exit(0);
|
|
1955
2084
|
}
|
|
1956
2085
|
const title = titleVal.trim();
|
|
1957
|
-
const descVal = await
|
|
2086
|
+
const descVal = await p5.text({
|
|
1958
2087
|
message: "Description (what and why)",
|
|
1959
2088
|
placeholder: "Optional"
|
|
1960
2089
|
});
|
|
1961
|
-
if (
|
|
1962
|
-
|
|
2090
|
+
if (p5.isCancel(descVal)) {
|
|
2091
|
+
p5.cancel("Cancelled.");
|
|
1963
2092
|
process.exit(0);
|
|
1964
2093
|
}
|
|
1965
2094
|
const description = descVal.trim();
|
|
1966
2095
|
const acceptance = [];
|
|
1967
|
-
|
|
2096
|
+
p5.log.info("Acceptance criteria \u2014 one per line, empty line to finish");
|
|
1968
2097
|
while (true) {
|
|
1969
|
-
const val = await
|
|
1970
|
-
if (
|
|
2098
|
+
const val = await p5.text({ message: ">", placeholder: "Criterion (or press Enter to finish)" });
|
|
2099
|
+
if (p5.isCancel(val) || !val || !val.trim()) break;
|
|
1971
2100
|
acceptance.push(val.trim());
|
|
1972
2101
|
}
|
|
1973
|
-
const spinner5 =
|
|
2102
|
+
const spinner5 = p5.spinner();
|
|
1974
2103
|
spinner5.start("Saving...");
|
|
1975
2104
|
try {
|
|
1976
2105
|
const config = await loadConfig(cwd2);
|
|
@@ -1980,28 +2109,28 @@ async function runTaskAdd(cwd2) {
|
|
|
1980
2109
|
db.writeFeatureList(cwd2);
|
|
1981
2110
|
db.close();
|
|
1982
2111
|
spinner5.stop("");
|
|
1983
|
-
console.log(
|
|
1984
|
-
console.log(
|
|
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");
|
|
1985
2114
|
} catch (err) {
|
|
1986
|
-
spinner5.stop(
|
|
1987
|
-
|
|
2115
|
+
spinner5.stop(pc11.red("Failed"));
|
|
2116
|
+
p5.log.error(err instanceof Error ? err.message : String(err));
|
|
1988
2117
|
process.exit(1);
|
|
1989
2118
|
}
|
|
1990
2119
|
}
|
|
1991
2120
|
|
|
1992
2121
|
// src/commands/task/done.ts
|
|
1993
2122
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1994
|
-
import { existsSync as
|
|
1995
|
-
import { resolve as
|
|
1996
|
-
import
|
|
2123
|
+
import { existsSync as existsSync10 } from "fs";
|
|
2124
|
+
import { resolve as resolve10 } from "path";
|
|
2125
|
+
import pc12 from "picocolors";
|
|
1997
2126
|
async function runTaskDone(cwd2, idOrSlug) {
|
|
1998
2127
|
const config = await loadConfig(cwd2);
|
|
1999
2128
|
if (config.health.required) {
|
|
2000
|
-
const scriptPath =
|
|
2001
|
-
if (
|
|
2129
|
+
const scriptPath = resolve10(cwd2, config.health.scriptPath);
|
|
2130
|
+
if (existsSync10(scriptPath)) {
|
|
2002
2131
|
const result = spawnSync2("bash", [scriptPath], { cwd: cwd2, stdio: "pipe", encoding: "utf8" });
|
|
2003
2132
|
if (result.status !== 0) {
|
|
2004
|
-
console.error(
|
|
2133
|
+
console.error(pc12.red("\u2717 Health check failed \u2014 cannot mark task as done."));
|
|
2005
2134
|
if (result.stdout) console.error(result.stdout);
|
|
2006
2135
|
if (result.stderr) console.error(result.stderr);
|
|
2007
2136
|
process.exit(1);
|
|
@@ -2014,16 +2143,16 @@ async function runTaskDone(cwd2, idOrSlug) {
|
|
|
2014
2143
|
const isId = !isNaN(parsed);
|
|
2015
2144
|
const task2 = isId ? db.getTaskById(parsed) : db.getTaskBySlug(idOrSlug);
|
|
2016
2145
|
if (!task2) {
|
|
2017
|
-
console.error(
|
|
2146
|
+
console.error(pc12.red(`Task not found: ${idOrSlug}`));
|
|
2018
2147
|
process.exit(1);
|
|
2019
2148
|
}
|
|
2020
2149
|
if (task2.status === "done") {
|
|
2021
|
-
console.log(
|
|
2150
|
+
console.log(pc12.dim(`Task #${task2.id} is already done.`));
|
|
2022
2151
|
return;
|
|
2023
2152
|
}
|
|
2024
2153
|
db.updateTaskStatus(task2.id, "done");
|
|
2025
2154
|
db.writeFeatureList(cwd2);
|
|
2026
|
-
console.log(
|
|
2155
|
+
console.log(pc12.green(`\u2713 Task #${task2.id} \u2014 ${task2.slug} marked as done`));
|
|
2027
2156
|
} finally {
|
|
2028
2157
|
db.close();
|
|
2029
2158
|
}
|
|
@@ -2031,12 +2160,12 @@ async function runTaskDone(cwd2, idOrSlug) {
|
|
|
2031
2160
|
|
|
2032
2161
|
// src/commands/task/list.ts
|
|
2033
2162
|
import Table2 from "cli-table3";
|
|
2034
|
-
import
|
|
2163
|
+
import pc13 from "picocolors";
|
|
2035
2164
|
var STATUS_COLOR2 = {
|
|
2036
|
-
pending: (s) =>
|
|
2037
|
-
in_progress: (s) =>
|
|
2038
|
-
done: (s) =>
|
|
2039
|
-
blocked: (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)
|
|
2040
2169
|
};
|
|
2041
2170
|
async function runTaskList(cwd2, opts) {
|
|
2042
2171
|
const config = await loadConfig(cwd2);
|
|
@@ -2050,11 +2179,11 @@ async function runTaskList(cwd2, opts) {
|
|
|
2050
2179
|
return;
|
|
2051
2180
|
}
|
|
2052
2181
|
if (tasks.length === 0) {
|
|
2053
|
-
console.log(
|
|
2182
|
+
console.log(pc13.dim("No tasks" + (filterStatus ? ` with status: ${filterStatus}` : "") + "."));
|
|
2054
2183
|
return;
|
|
2055
2184
|
}
|
|
2056
2185
|
const table = new Table2({
|
|
2057
|
-
head: ["ID", "Slug", "Title", "Status"].map((h) =>
|
|
2186
|
+
head: ["ID", "Slug", "Title", "Status"].map((h) => pc13.bold(h)),
|
|
2058
2187
|
style: { head: [], border: [] }
|
|
2059
2188
|
});
|
|
2060
2189
|
for (const t of tasks) {
|
|
@@ -2069,14 +2198,14 @@ async function runTaskList(cwd2, opts) {
|
|
|
2069
2198
|
|
|
2070
2199
|
// src/core/package-data.ts
|
|
2071
2200
|
import { createRequire as createRequire2 } from "module";
|
|
2072
|
-
import { dirname as dirname5, join as
|
|
2201
|
+
import { dirname as dirname5, join as join14 } from "path";
|
|
2073
2202
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2074
2203
|
var require2 = createRequire2(import.meta.url);
|
|
2075
|
-
var pkgPath =
|
|
2204
|
+
var pkgPath = join14(dirname5(fileURLToPath3(import.meta.url)), "..", "package.json");
|
|
2076
2205
|
var pkg = require2(pkgPath);
|
|
2077
2206
|
|
|
2078
2207
|
// src/core/update-check.ts
|
|
2079
|
-
import
|
|
2208
|
+
import pc14 from "picocolors";
|
|
2080
2209
|
var REGISTRY_URL = `https://registry.npmjs.org/${pkg.name}/latest`;
|
|
2081
2210
|
var TIMEOUT_MS = 2500;
|
|
2082
2211
|
function checkForUpdate(currentVersion) {
|
|
@@ -2094,18 +2223,18 @@ function checkForUpdate(currentVersion) {
|
|
|
2094
2223
|
}
|
|
2095
2224
|
function printUpdateMessage({ current, latest }) {
|
|
2096
2225
|
const lines = [
|
|
2097
|
-
` Update available ${
|
|
2098
|
-
` Run: ${
|
|
2226
|
+
` Update available ${pc14.dim(current)} \u2192 ${pc14.green(latest)} `,
|
|
2227
|
+
` Run: ${pc14.cyan(`npm i ${pkg.name}@${latest}`)} `
|
|
2099
2228
|
];
|
|
2100
2229
|
const width = Math.max(...lines.map((l) => stripAnsi2(l).length));
|
|
2101
2230
|
const border = "\u2500".repeat(width);
|
|
2102
2231
|
console.log();
|
|
2103
|
-
console.log(
|
|
2232
|
+
console.log(pc14.yellow(`\u250C${border}\u2510`));
|
|
2104
2233
|
for (const line of lines) {
|
|
2105
2234
|
const pad = width - stripAnsi2(line).length;
|
|
2106
|
-
console.log(
|
|
2235
|
+
console.log(pc14.yellow("\u2502") + line + " ".repeat(pad) + pc14.yellow("\u2502"));
|
|
2107
2236
|
}
|
|
2108
|
-
console.log(
|
|
2237
|
+
console.log(pc14.yellow(`\u2514${border}\u2518`));
|
|
2109
2238
|
console.log();
|
|
2110
2239
|
}
|
|
2111
2240
|
function isNewer(latest, current) {
|
|
@@ -2120,134 +2249,6 @@ function stripAnsi2(str2) {
|
|
|
2120
2249
|
return str2.replace(/\x1B\[[0-9;]*m/g, "");
|
|
2121
2250
|
}
|
|
2122
2251
|
|
|
2123
|
-
// src/commands/reset.ts
|
|
2124
|
-
import { existsSync as existsSync10, readdirSync as readdirSync2, rmSync } from "fs";
|
|
2125
|
-
import { join as join14, resolve as resolve10 } from "path";
|
|
2126
|
-
import * as p5 from "@clack/prompts";
|
|
2127
|
-
import pc14 from "picocolors";
|
|
2128
|
-
async function resetAgentMds(cwd2, provider) {
|
|
2129
|
-
const agentDir = provider === "claude-code" ? ".claude/agents" : ".opencode/agents";
|
|
2130
|
-
const agentDirPath = resolve10(cwd2, agentDir);
|
|
2131
|
-
if (!existsSync10(agentDirPath)) {
|
|
2132
|
-
console.log(pc14.yellow(` Skipping agent files \u2014 directory not found: ${agentDirPath}`));
|
|
2133
|
-
return;
|
|
2134
|
-
}
|
|
2135
|
-
const existingFiles = [];
|
|
2136
|
-
try {
|
|
2137
|
-
const files = readdirSync2(agentDirPath);
|
|
2138
|
-
for (const f of files) {
|
|
2139
|
-
if (f.endsWith(".md")) {
|
|
2140
|
-
existingFiles.push(f);
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
} catch {
|
|
2144
|
-
console.log(pc14.yellow(` Skipping agent files \u2014 ${agentDirPath} is not readable`));
|
|
2145
|
-
return;
|
|
2146
|
-
}
|
|
2147
|
-
if (existingFiles.length === 0) {
|
|
2148
|
-
console.log(pc14.yellow(` No agent MD files found in ${agentDir}/`));
|
|
2149
|
-
return;
|
|
2150
|
-
}
|
|
2151
|
-
for (const file of existingFiles) {
|
|
2152
|
-
const confirm3 = await p5.confirm({
|
|
2153
|
-
message: `Remove ${file}?`,
|
|
2154
|
-
initialValue: true
|
|
2155
|
-
});
|
|
2156
|
-
if (p5.isCancel(confirm3)) {
|
|
2157
|
-
console.log(pc14.red(" Cancelled by user."));
|
|
2158
|
-
return;
|
|
2159
|
-
}
|
|
2160
|
-
if (confirm3) {
|
|
2161
|
-
try {
|
|
2162
|
-
const filePath = join14(agentDirPath, file);
|
|
2163
|
-
rmSync(filePath, { force: true });
|
|
2164
|
-
console.log(pc14.green(` Removed ${file}`));
|
|
2165
|
-
} catch {
|
|
2166
|
-
console.error(pc14.red(` Failed to remove ${file}`));
|
|
2167
|
-
}
|
|
2168
|
-
} else {
|
|
2169
|
-
console.log(pc14.cyan(` Skipped ${file}`));
|
|
2170
|
-
}
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
async function runReset(cwd2, opts) {
|
|
2174
|
-
let config;
|
|
2175
|
-
try {
|
|
2176
|
-
config = await loadConfig(cwd2);
|
|
2177
|
-
} catch {
|
|
2178
|
-
console.error(pc14.red("\u2717 No agent-harness-kit.config found. Run: ahk init"));
|
|
2179
|
-
process.exit(1);
|
|
2180
|
-
}
|
|
2181
|
-
const storageDir = config.storage.dir || ".harness";
|
|
2182
|
-
const dbPath = resolve10(cwd2, storageDir, "harness.db");
|
|
2183
|
-
const featureListPath = resolve10(cwd2, storageDir, "feature_list.json");
|
|
2184
|
-
let resetDb = false;
|
|
2185
|
-
let resetFeatureList = false;
|
|
2186
|
-
let resetAgentMdsFlag = false;
|
|
2187
|
-
if (existsSync10(dbPath)) {
|
|
2188
|
-
if (opts.force) {
|
|
2189
|
-
resetDb = true;
|
|
2190
|
-
} else {
|
|
2191
|
-
const confirm3 = await p5.confirm({
|
|
2192
|
-
message: `Delete database (${storageDir}/harness.db)?`,
|
|
2193
|
-
initialValue: true
|
|
2194
|
-
});
|
|
2195
|
-
if (p5.isCancel(confirm3)) {
|
|
2196
|
-
console.log(pc14.red(" Cancelled by user."));
|
|
2197
|
-
return;
|
|
2198
|
-
}
|
|
2199
|
-
resetDb = confirm3;
|
|
2200
|
-
}
|
|
2201
|
-
}
|
|
2202
|
-
if (existsSync10(featureListPath)) {
|
|
2203
|
-
if (opts.force) {
|
|
2204
|
-
resetFeatureList = true;
|
|
2205
|
-
} else {
|
|
2206
|
-
const confirm3 = await p5.confirm({
|
|
2207
|
-
message: `Delete feature list (${storageDir}/feature_list.json)?`,
|
|
2208
|
-
initialValue: true
|
|
2209
|
-
});
|
|
2210
|
-
if (p5.isCancel(confirm3)) {
|
|
2211
|
-
console.log(pc14.red(" Cancelled by user."));
|
|
2212
|
-
return;
|
|
2213
|
-
}
|
|
2214
|
-
resetFeatureList = confirm3;
|
|
2215
|
-
}
|
|
2216
|
-
}
|
|
2217
|
-
if (opts.provider) {
|
|
2218
|
-
resetAgentMdsFlag = true;
|
|
2219
|
-
}
|
|
2220
|
-
let changed = false;
|
|
2221
|
-
if (resetDb) {
|
|
2222
|
-
try {
|
|
2223
|
-
rmSync(dbPath, { force: true });
|
|
2224
|
-
console.log(pc14.green(` \u2713 Removed ${storageDir}/harness.db`));
|
|
2225
|
-
changed = true;
|
|
2226
|
-
} catch {
|
|
2227
|
-
console.error(pc14.red(` \u2717 Failed to remove ${dbPath}`));
|
|
2228
|
-
}
|
|
2229
|
-
}
|
|
2230
|
-
if (resetFeatureList) {
|
|
2231
|
-
try {
|
|
2232
|
-
rmSync(featureListPath, { force: true });
|
|
2233
|
-
console.log(pc14.green(` \u2713 Removed ${storageDir}/feature_list.json`));
|
|
2234
|
-
changed = true;
|
|
2235
|
-
} catch {
|
|
2236
|
-
console.error(pc14.red(` \u2717 Failed to remove ${featureListPath}`));
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
if (resetAgentMdsFlag) {
|
|
2240
|
-
console.log("");
|
|
2241
|
-
await resetAgentMds(cwd2, opts.provider || "claude-code");
|
|
2242
|
-
}
|
|
2243
|
-
if (!resetDb && !resetFeatureList && !resetAgentMdsFlag) {
|
|
2244
|
-
console.log(pc14.yellow(" Nothing to reset (all items missing or skipped)."));
|
|
2245
|
-
return;
|
|
2246
|
-
}
|
|
2247
|
-
console.log("");
|
|
2248
|
-
console.log(pc14.green('\u2713 Reset complete. Run "ahk init" to scaffold a fresh harness.'));
|
|
2249
|
-
}
|
|
2250
|
-
|
|
2251
2252
|
// src/cli.ts
|
|
2252
2253
|
var cwd = process.cwd();
|
|
2253
2254
|
var updateCheck = checkForUpdate(pkg.version);
|