@cardor/agent-harness-kit 1.10.2 → 1.10.4
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/README.md +35 -15
- package/dist/{chunk-DNFFWQWR.js → chunk-6PEIJ2D5.js} +15 -2
- package/dist/chunk-6PEIJ2D5.js.map +1 -0
- package/dist/chunk-D64KK6UU.js +128 -0
- package/dist/chunk-D64KK6UU.js.map +1 -0
- package/dist/cli.js +90 -184
- package/dist/cli.js.map +1 -1
- package/dist/{db-QQ7BR5K7.js → db-3OXHRFAR.js} +10 -2
- package/dist/index.d.ts +36 -11
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-ADV7OPU2.js +0 -87
- package/dist/chunk-ADV7OPU2.js.map +0 -1
- package/dist/chunk-DNFFWQWR.js.map +0 -1
- /package/dist/{db-QQ7BR5K7.js.map → db-3OXHRFAR.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
findConfigFile,
|
|
3
3
|
loadConfig
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-D64KK6UU.js";
|
|
5
5
|
import {
|
|
6
|
+
DEFAULT_MARKDOWN_PATH,
|
|
7
|
+
DEFAULT_SQLITE_PATH,
|
|
6
8
|
getRowCounts,
|
|
7
9
|
isEmptyDatabase,
|
|
8
10
|
openDB,
|
|
9
11
|
readStorageStateFile,
|
|
10
12
|
resolveGlobalStorageDir,
|
|
13
|
+
resolveSqlitePath,
|
|
11
14
|
resolveSqlitePathForScope
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-6PEIJ2D5.js";
|
|
13
16
|
|
|
14
17
|
// src/cli.ts
|
|
15
18
|
import { Command } from "commander";
|
|
@@ -532,6 +535,8 @@ function modelField(model) {
|
|
|
532
535
|
}
|
|
533
536
|
function configObjectBody(params) {
|
|
534
537
|
const models = params.models ?? {};
|
|
538
|
+
const isGlobal = params.scope === "global";
|
|
539
|
+
const markdownFallbackLine = isGlobal ? `markdownFallback: { enabled: true },` : `markdownFallback: { enabled: true, path: '.harness/current.md' },`;
|
|
535
540
|
return ` project: {
|
|
536
541
|
name: ${JSON.stringify(params.name)},
|
|
537
542
|
description: ${JSON.stringify(params.description)},
|
|
@@ -552,7 +557,7 @@ function configObjectBody(params) {
|
|
|
552
557
|
// SQLite (default). Switch to postgres/mysql by changing database.type.
|
|
553
558
|
// database: { type: 'postgres', connectionString: process.env.DATABASE_URL },
|
|
554
559
|
// database: { type: 'mysql', connectionString: process.env.DATABASE_URL },
|
|
555
|
-
database: { type: 'sqlite'
|
|
560
|
+
database: { type: 'sqlite' },
|
|
556
561
|
|
|
557
562
|
storage: {
|
|
558
563
|
dir: '.harness',
|
|
@@ -564,7 +569,7 @@ function configObjectBody(params) {
|
|
|
564
569
|
blockers: true,
|
|
565
570
|
nextSteps: false,
|
|
566
571
|
},
|
|
567
|
-
|
|
572
|
+
${markdownFallbackLine}
|
|
568
573
|
// 'local' \u2014 DB lives in .harness/ (project-relative). 'global' \u2014 DB lives
|
|
569
574
|
// under ~/.harness/dbs/<projectId>/, outside the project tree.
|
|
570
575
|
scope: '${params.scope}',
|
|
@@ -751,14 +756,6 @@ function writeSkills(cwd2, skillsDir) {
|
|
|
751
756
|
writeFileSync3(dest, readFileSync4(src, "utf8"), "utf8");
|
|
752
757
|
}
|
|
753
758
|
}
|
|
754
|
-
function writeSkill(skillsRoot, skillName) {
|
|
755
|
-
const src = join4(__dirname2, "skills", skillName, "SKILL.md");
|
|
756
|
-
const destDir = join4(skillsRoot, skillName);
|
|
757
|
-
const dest = join4(destDir, "SKILL.md");
|
|
758
|
-
if (existsSync3(dest)) return;
|
|
759
|
-
mkdirSync3(destDir, { recursive: true });
|
|
760
|
-
writeFileSync3(dest, readFileSync4(src, "utf8"), "utf8");
|
|
761
|
-
}
|
|
762
759
|
|
|
763
760
|
// src/core/materializer/claude-code.ts
|
|
764
761
|
var ClaudeCodeMaterializer = class {
|
|
@@ -771,7 +768,7 @@ var ClaudeCodeMaterializer = class {
|
|
|
771
768
|
}
|
|
772
769
|
const tasks = opts.firstTask ? [{ slug: slugify(opts.firstTask.title), ...opts.firstTask }] : [];
|
|
773
770
|
write(cwd2, "feature_list.json", featureListJson(tasks));
|
|
774
|
-
if (!existsSync4(join5(cwd2, config.storage.markdownFallback.path))) {
|
|
771
|
+
if (config.storage.scope === "local" && !existsSync4(join5(cwd2, config.storage.markdownFallback.path))) {
|
|
775
772
|
write(
|
|
776
773
|
cwd2,
|
|
777
774
|
config.storage.markdownFallback.path,
|
|
@@ -883,7 +880,7 @@ var CodexCliMaterializer = class {
|
|
|
883
880
|
}
|
|
884
881
|
const tasks = opts.firstTask ? [{ slug: slugify(opts.firstTask.title), ...opts.firstTask }] : [];
|
|
885
882
|
write2(join6(config.storage.dir, "feature_list.json"), featureListJson(tasks));
|
|
886
|
-
if (!existsSync5(join6(cwd2, config.storage.markdownFallback.path))) {
|
|
883
|
+
if (config.storage.scope === "local" && !existsSync5(join6(cwd2, config.storage.markdownFallback.path))) {
|
|
887
884
|
write2(
|
|
888
885
|
config.storage.markdownFallback.path,
|
|
889
886
|
`<!-- AUTO-GENERATED by agent-harness-kit \u2014 DO NOT EDIT MANUALLY -->
|
|
@@ -962,7 +959,7 @@ var OpenCodeMaterializer = class {
|
|
|
962
959
|
}
|
|
963
960
|
const tasks = opts.firstTask ? [{ slug: slugify(opts.firstTask.title), ...opts.firstTask }] : [];
|
|
964
961
|
write2(join7(config.storage.dir, "feature_list.json"), featureListJson(tasks));
|
|
965
|
-
if (!existsSync6(join7(cwd2, config.storage.markdownFallback.path))) {
|
|
962
|
+
if (config.storage.scope === "local" && !existsSync6(join7(cwd2, config.storage.markdownFallback.path))) {
|
|
966
963
|
write2(
|
|
967
964
|
config.storage.markdownFallback.path,
|
|
968
965
|
`<!-- AUTO-GENERATED by agent-harness-kit \u2014 DO NOT EDIT MANUALLY -->
|
|
@@ -1067,7 +1064,8 @@ async function buildOnce(cwd2) {
|
|
|
1067
1064
|
}
|
|
1068
1065
|
|
|
1069
1066
|
// src/commands/dashboard.ts
|
|
1070
|
-
import {
|
|
1067
|
+
import { homedir } from "os";
|
|
1068
|
+
import { dirname as dirname4, join as join9 } from "path";
|
|
1071
1069
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1072
1070
|
import pc2 from "picocolors";
|
|
1073
1071
|
|
|
@@ -1082,11 +1080,11 @@ import { WebSocketServer } from "ws";
|
|
|
1082
1080
|
// src/core/port-utils.ts
|
|
1083
1081
|
import { createServer } from "net";
|
|
1084
1082
|
function isPortFree(port) {
|
|
1085
|
-
return new Promise((
|
|
1083
|
+
return new Promise((resolve12) => {
|
|
1086
1084
|
const server = createServer();
|
|
1087
|
-
server.once("error", () =>
|
|
1085
|
+
server.once("error", () => resolve12(false));
|
|
1088
1086
|
server.once("listening", () => {
|
|
1089
|
-
server.close(() =>
|
|
1087
|
+
server.close(() => resolve12(true));
|
|
1090
1088
|
});
|
|
1091
1089
|
server.listen(port, "127.0.0.1");
|
|
1092
1090
|
});
|
|
@@ -1280,7 +1278,7 @@ var __dirname3 = dirname4(fileURLToPath3(import.meta.url));
|
|
|
1280
1278
|
async function runDashboard(cwd2, opts) {
|
|
1281
1279
|
const config = await loadConfig(cwd2);
|
|
1282
1280
|
const db = await openDB(config, cwd2);
|
|
1283
|
-
const dbPath = config.database.type === "sqlite" ?
|
|
1281
|
+
const dbPath = config.database.type === "sqlite" ? resolveSqlitePath(config, cwd2, homedir()) : null;
|
|
1284
1282
|
const staticPath = join9(__dirname3, "dashboard-dist");
|
|
1285
1283
|
const { url } = await startDashboardServer(db, dbPath, staticPath, opts.port);
|
|
1286
1284
|
console.log(pc2.green(`\u2713`) + ` Dashboard running at ${pc2.bold(pc2.cyan(url))}`);
|
|
@@ -1302,7 +1300,6 @@ import pc3 from "picocolors";
|
|
|
1302
1300
|
|
|
1303
1301
|
// src/core/doctor.ts
|
|
1304
1302
|
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
1305
|
-
import { homedir } from "os";
|
|
1306
1303
|
import { dirname as dirname6, join as join11 } from "path";
|
|
1307
1304
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1308
1305
|
|
|
@@ -1465,55 +1462,6 @@ function checkSkills(cwd2, provider) {
|
|
|
1465
1462
|
const skillsDir = getProviderSkillsDir(provider);
|
|
1466
1463
|
return checkSkillsAtRoot(join11(cwd2, skillsDir));
|
|
1467
1464
|
}
|
|
1468
|
-
function getGlobalProviderAgentDir(provider, homeDir) {
|
|
1469
|
-
switch (provider) {
|
|
1470
|
-
case "claude-code":
|
|
1471
|
-
return { agentsDir: join11(homeDir, ".claude", "agents"), ext: ".md" };
|
|
1472
|
-
case "opencode":
|
|
1473
|
-
return { agentsDir: join11(homeDir, ".config", "opencode", "agents"), ext: ".md" };
|
|
1474
|
-
case "codex-cli":
|
|
1475
|
-
return { agentsDir: join11(homeDir, ".codex", "agents"), ext: ".toml" };
|
|
1476
|
-
default:
|
|
1477
|
-
return { agentsDir: join11(homeDir, ".claude", "agents"), ext: ".md" };
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
function getGlobalProviderSkillsDir(provider, homeDir) {
|
|
1481
|
-
switch (provider) {
|
|
1482
|
-
case "claude-code":
|
|
1483
|
-
return join11(homeDir, ".claude", "skills");
|
|
1484
|
-
case "opencode":
|
|
1485
|
-
return join11(homeDir, ".config", "opencode", "skills");
|
|
1486
|
-
case "codex-cli":
|
|
1487
|
-
return join11(homeDir, ".agents", "skills");
|
|
1488
|
-
default:
|
|
1489
|
-
return join11(homeDir, ".claude", "skills");
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
async function getGlobalDoctorStatus(provider, config, homeDir = homedir()) {
|
|
1493
|
-
const projectName = config.project.name;
|
|
1494
|
-
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(", ");
|
|
1495
|
-
const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
|
|
1496
|
-
const models = {
|
|
1497
|
-
lead: config.agents.lead.model,
|
|
1498
|
-
explorer: config.agents.explorer.model,
|
|
1499
|
-
consultant: config.agents.consultant?.model,
|
|
1500
|
-
builder: config.agents.builder.model,
|
|
1501
|
-
reviewer: config.agents.reviewer.model
|
|
1502
|
-
};
|
|
1503
|
-
const { agentsDir, ext } = getGlobalProviderAgentDir(provider, homeDir);
|
|
1504
|
-
const agents = checkAgentFilesAtRoot(
|
|
1505
|
-
agentsDir,
|
|
1506
|
-
ext,
|
|
1507
|
-
provider,
|
|
1508
|
-
projectName,
|
|
1509
|
-
allowedPaths,
|
|
1510
|
-
writablePaths,
|
|
1511
|
-
models
|
|
1512
|
-
);
|
|
1513
|
-
const skillsDir = getGlobalProviderSkillsDir(provider, homeDir);
|
|
1514
|
-
const skills = checkSkillsAtRoot(skillsDir);
|
|
1515
|
-
return { agents, skills };
|
|
1516
|
-
}
|
|
1517
1465
|
async function getDoctorStatus(cwd2) {
|
|
1518
1466
|
const lib = await checkLibVersion();
|
|
1519
1467
|
let config;
|
|
@@ -1659,7 +1607,8 @@ async function runExport(cwd2, opts) {
|
|
|
1659
1607
|
// src/commands/health.ts
|
|
1660
1608
|
import { spawnSync } from "child_process";
|
|
1661
1609
|
import { existsSync as existsSync10 } from "fs";
|
|
1662
|
-
import {
|
|
1610
|
+
import { homedir as homedir2 } from "os";
|
|
1611
|
+
import { join as join12, resolve as resolve6 } from "path";
|
|
1663
1612
|
import pc5 from "picocolors";
|
|
1664
1613
|
function checkLine(label, ok3, message, indent = 0) {
|
|
1665
1614
|
const prefix = label ? pc5.cyan(`[${label}] `) : " ".repeat(indent);
|
|
@@ -1677,9 +1626,9 @@ async function runHealth(cwd2) {
|
|
|
1677
1626
|
let allOk = true;
|
|
1678
1627
|
let dbOk;
|
|
1679
1628
|
if (config.database.type === "sqlite") {
|
|
1680
|
-
const dbPath =
|
|
1629
|
+
const dbPath = resolveSqlitePath(config, cwd2, homedir2());
|
|
1681
1630
|
dbOk = existsSync10(dbPath);
|
|
1682
|
-
checkLine("checking DB", dbOk, `${
|
|
1631
|
+
checkLine("checking DB", dbOk, `${dbPath} reachable`);
|
|
1683
1632
|
} else {
|
|
1684
1633
|
dbOk = true;
|
|
1685
1634
|
checkLine("checking DB", true, `${config.database.type}://${config.database.connectionString.replace(/:[^:@]*@/, ":***@")} configured`);
|
|
@@ -1703,7 +1652,7 @@ async function runHealth(cwd2) {
|
|
|
1703
1652
|
}
|
|
1704
1653
|
if (config.tools.mcp.enabled) {
|
|
1705
1654
|
const mcpFile = providerFiles.mcpFile;
|
|
1706
|
-
const mcpPath =
|
|
1655
|
+
const mcpPath = resolve6(cwd2, mcpFile);
|
|
1707
1656
|
const mcpOk = existsSync10(mcpPath);
|
|
1708
1657
|
checkLine("checking MCP", mcpOk, `${mcpFile} valid`);
|
|
1709
1658
|
if (!mcpOk) allOk = false;
|
|
@@ -1713,7 +1662,7 @@ async function runHealth(cwd2) {
|
|
|
1713
1662
|
console.error(pc5.red("\u2717 Harness checks failed \u2014 fix the above before running health.sh"));
|
|
1714
1663
|
process.exit(1);
|
|
1715
1664
|
}
|
|
1716
|
-
const scriptPath =
|
|
1665
|
+
const scriptPath = resolve6(cwd2, config.health.scriptPath);
|
|
1717
1666
|
if (!existsSync10(scriptPath)) {
|
|
1718
1667
|
console.error(pc5.red(`\u2717 health.sh not found: ${scriptPath}`));
|
|
1719
1668
|
console.error(" Run ahk init first.");
|
|
@@ -1755,51 +1704,6 @@ import { join as join14 } from "path";
|
|
|
1755
1704
|
import * as p3 from "@clack/prompts";
|
|
1756
1705
|
import pc7 from "picocolors";
|
|
1757
1706
|
|
|
1758
|
-
// src/core/materializer/global-sync.ts
|
|
1759
|
-
import { homedir as homedir2 } from "os";
|
|
1760
|
-
async function syncGlobalAgentsAndSkills(config, provider, homeDir = homedir2()) {
|
|
1761
|
-
const status = await getGlobalDoctorStatus(provider, config, homeDir);
|
|
1762
|
-
const missingAgents = status.agents.filter((a) => a.status === "missing");
|
|
1763
|
-
const missingSkills = status.skills.filter((s) => s.status === "missing");
|
|
1764
|
-
if (missingAgents.length === 0 && missingSkills.length === 0) {
|
|
1765
|
-
return { alreadySynced: true, createdAgents: [], createdSkills: [] };
|
|
1766
|
-
}
|
|
1767
|
-
const projectName = config.project.name;
|
|
1768
|
-
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(", ");
|
|
1769
|
-
const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
|
|
1770
|
-
const models = {
|
|
1771
|
-
lead: config.agents.lead.model,
|
|
1772
|
-
explorer: config.agents.explorer.model,
|
|
1773
|
-
consultant: config.agents.consultant?.model,
|
|
1774
|
-
builder: config.agents.builder.model,
|
|
1775
|
-
reviewer: config.agents.reviewer.model
|
|
1776
|
-
};
|
|
1777
|
-
const createdAgents = [];
|
|
1778
|
-
if (missingAgents.length > 0) {
|
|
1779
|
-
const { agentsDir, ext } = getGlobalProviderAgentDir(provider, homeDir);
|
|
1780
|
-
for (const agent of missingAgents) {
|
|
1781
|
-
const name = agent.name;
|
|
1782
|
-
const content = generateExpectedAgentContent(name, provider, {
|
|
1783
|
-
projectName,
|
|
1784
|
-
allowedPaths,
|
|
1785
|
-
writablePaths,
|
|
1786
|
-
model: models[name]
|
|
1787
|
-
});
|
|
1788
|
-
writeAgentFile(agentsDir, `${name}${ext}`, content);
|
|
1789
|
-
createdAgents.push(name);
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
const createdSkills = [];
|
|
1793
|
-
if (missingSkills.length > 0) {
|
|
1794
|
-
const skillsDir = getGlobalProviderSkillsDir(provider, homeDir);
|
|
1795
|
-
for (const skill of missingSkills) {
|
|
1796
|
-
writeSkill(skillsDir, skill.name);
|
|
1797
|
-
createdSkills.push(skill.name);
|
|
1798
|
-
}
|
|
1799
|
-
}
|
|
1800
|
-
return { alreadySynced: false, createdAgents, createdSkills };
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
1707
|
// src/schema/init.ts
|
|
1804
1708
|
import * as v from "valibot";
|
|
1805
1709
|
var initNameSchema = v.pipe(
|
|
@@ -1881,6 +1785,20 @@ function detectConfigExtension(cwd2) {
|
|
|
1881
1785
|
}
|
|
1882
1786
|
function applyConfigDefaults(params) {
|
|
1883
1787
|
const models = params.models ?? {};
|
|
1788
|
+
const scope = params.scope ?? "local";
|
|
1789
|
+
const projectId = params.projectId ?? randomUUID();
|
|
1790
|
+
const baseStorage = {
|
|
1791
|
+
dir: ".harness",
|
|
1792
|
+
tasks: { adapter: params.tasksAdapter },
|
|
1793
|
+
sections: {
|
|
1794
|
+
toolsUsed: true,
|
|
1795
|
+
filesModified: true,
|
|
1796
|
+
result: true,
|
|
1797
|
+
blockers: true,
|
|
1798
|
+
nextSteps: false
|
|
1799
|
+
}
|
|
1800
|
+
};
|
|
1801
|
+
const storage = scope === "global" ? { ...baseStorage, markdownFallback: { enabled: true }, scope: "global", projectId } : { ...baseStorage, markdownFallback: { enabled: true, path: ".harness/current.md" }, scope: "local", projectId };
|
|
1884
1802
|
return {
|
|
1885
1803
|
provider: params.provider,
|
|
1886
1804
|
project: {
|
|
@@ -1905,21 +1823,8 @@ function applyConfigDefaults(params) {
|
|
|
1905
1823
|
...models.consultant && { consultant: { instructionsPath: null, model: models.consultant } },
|
|
1906
1824
|
custom: []
|
|
1907
1825
|
},
|
|
1908
|
-
database: { type: "sqlite"
|
|
1909
|
-
storage
|
|
1910
|
-
dir: ".harness",
|
|
1911
|
-
tasks: { adapter: params.tasksAdapter },
|
|
1912
|
-
sections: {
|
|
1913
|
-
toolsUsed: true,
|
|
1914
|
-
filesModified: true,
|
|
1915
|
-
result: true,
|
|
1916
|
-
blockers: true,
|
|
1917
|
-
nextSteps: false
|
|
1918
|
-
},
|
|
1919
|
-
markdownFallback: { enabled: true, path: ".harness/current.md" },
|
|
1920
|
-
scope: params.scope ?? "local",
|
|
1921
|
-
projectId: params.projectId ?? randomUUID()
|
|
1922
|
-
},
|
|
1826
|
+
database: { type: "sqlite" },
|
|
1827
|
+
storage,
|
|
1923
1828
|
health: {
|
|
1924
1829
|
scriptPath: "./health.sh",
|
|
1925
1830
|
required: true
|
|
@@ -2041,7 +1946,7 @@ async function runInit(cwd2, flags) {
|
|
|
2041
1946
|
const modelOverrides = {};
|
|
2042
1947
|
if (provider === "claude-code" || provider === "codex-cli") {
|
|
2043
1948
|
const wantsModelCustomization = await p3.confirm({
|
|
2044
|
-
message: "
|
|
1949
|
+
message: "Customize the model per agent?",
|
|
2045
1950
|
initialValue: false
|
|
2046
1951
|
});
|
|
2047
1952
|
if (p3.isCancel(wantsModelCustomization)) {
|
|
@@ -2052,7 +1957,7 @@ async function runInit(cwd2, flags) {
|
|
|
2052
1957
|
if (provider === "claude-code") {
|
|
2053
1958
|
for (const agent of AGENT_LABELS) {
|
|
2054
1959
|
const val = await p3.select({
|
|
2055
|
-
message: `
|
|
1960
|
+
message: `Model for ${agent.label}`,
|
|
2056
1961
|
options: [
|
|
2057
1962
|
{ value: "inherit", label: "inherit (default)" },
|
|
2058
1963
|
{ value: "haiku", label: "haiku" },
|
|
@@ -2071,8 +1976,8 @@ async function runInit(cwd2, flags) {
|
|
|
2071
1976
|
} else {
|
|
2072
1977
|
for (const agent of AGENT_LABELS) {
|
|
2073
1978
|
const val = await p3.text({
|
|
2074
|
-
message: `
|
|
2075
|
-
placeholder: "
|
|
1979
|
+
message: `Model for ${agent.label} (Codex does not validate this value)`,
|
|
1980
|
+
placeholder: "e.g. gpt-5 (empty or <3 chars = no override)"
|
|
2076
1981
|
});
|
|
2077
1982
|
if (p3.isCancel(val)) {
|
|
2078
1983
|
p3.cancel("Cancelled.");
|
|
@@ -2110,7 +2015,10 @@ async function runInit(cwd2, flags) {
|
|
|
2110
2015
|
message: "Storage scope",
|
|
2111
2016
|
options: [
|
|
2112
2017
|
{ value: "local", label: "Local \u2014 .harness/harness.db lives in this project" },
|
|
2113
|
-
{
|
|
2018
|
+
{
|
|
2019
|
+
value: "global",
|
|
2020
|
+
label: "Global \u2014 DB lives under ~/.harness/dbs/<projectId>/, outside the project"
|
|
2021
|
+
}
|
|
2114
2022
|
],
|
|
2115
2023
|
initialValue: "local"
|
|
2116
2024
|
});
|
|
@@ -2174,7 +2082,6 @@ async function runInit(cwd2, flags) {
|
|
|
2174
2082
|
firstTask = { title: taskTitle, description: taskDesc, acceptance };
|
|
2175
2083
|
}
|
|
2176
2084
|
let configExt = "ts";
|
|
2177
|
-
let globalSyncResult = null;
|
|
2178
2085
|
const spinner6 = p3.spinner();
|
|
2179
2086
|
spinner6.start("Scaffolding...");
|
|
2180
2087
|
try {
|
|
@@ -2208,9 +2115,6 @@ async function runInit(cwd2, flags) {
|
|
|
2208
2115
|
const db = await openDB(config, installDir);
|
|
2209
2116
|
await db.writeStorageState(installDir);
|
|
2210
2117
|
await materializer.scaffold(config, { cwd: installDir, firstTask });
|
|
2211
|
-
if (config.storage.scope === "global") {
|
|
2212
|
-
globalSyncResult = await syncGlobalAgentsAndSkills(config, provider);
|
|
2213
|
-
}
|
|
2214
2118
|
if (firstTask) {
|
|
2215
2119
|
const slug = slugify(firstTask.title);
|
|
2216
2120
|
await db.addTask({
|
|
@@ -2234,8 +2138,16 @@ async function runInit(cwd2, flags) {
|
|
|
2234
2138
|
console.log(pc7.green(`\u2713 agent-harness-kit.config.${configExt}`));
|
|
2235
2139
|
console.log(pc7.green("\u2713 AGENTS.md"));
|
|
2236
2140
|
console.log(pc7.green("\u2713 health.sh"));
|
|
2237
|
-
console.log(
|
|
2238
|
-
|
|
2141
|
+
console.log(
|
|
2142
|
+
pc7.green(
|
|
2143
|
+
storageScope === "global" ? "\u2713 ~/.harness/dbs/<projectId>/harness.db" : "\u2713 .harness/harness.db"
|
|
2144
|
+
)
|
|
2145
|
+
);
|
|
2146
|
+
console.log(
|
|
2147
|
+
pc7.green(
|
|
2148
|
+
storageScope === "global" ? "\u2713 ~/.harness/dbs/<projectId>/current.md" : "\u2713 .harness/current.md"
|
|
2149
|
+
)
|
|
2150
|
+
);
|
|
2239
2151
|
console.log(pc7.green("\u2713 .harness/storage-state.json"));
|
|
2240
2152
|
console.log(pc7.green(`\u2713 ${agentsDir}lead.md`));
|
|
2241
2153
|
console.log(pc7.green(`\u2713 ${agentsDir}explorer.md`));
|
|
@@ -2243,19 +2155,6 @@ async function runInit(cwd2, flags) {
|
|
|
2243
2155
|
console.log(pc7.green(`\u2713 ${agentsDir}reviewer.md`));
|
|
2244
2156
|
console.log(pc7.green(`\u2713 ${mcpFile}`));
|
|
2245
2157
|
console.log(pc7.green("\u2713 .gitignore entries added"));
|
|
2246
|
-
if (globalSyncResult) {
|
|
2247
|
-
console.log("");
|
|
2248
|
-
if (globalSyncResult.alreadySynced) {
|
|
2249
|
-
console.log(pc7.dim("\u2713 Global agents/skills already synced \u2014 skipped"));
|
|
2250
|
-
} else {
|
|
2251
|
-
for (const name2 of globalSyncResult.createdAgents) {
|
|
2252
|
-
console.log(pc7.green(`\u2713 ~global agent added: ${name2}`));
|
|
2253
|
-
}
|
|
2254
|
-
for (const name2 of globalSyncResult.createdSkills) {
|
|
2255
|
-
console.log(pc7.green(`\u2713 ~global skill added: ${name2}`));
|
|
2256
|
-
}
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
2158
|
console.log("");
|
|
2260
2159
|
console.log(pc7.cyan("\u2192") + ` Edit ${pc7.cyan("health.sh")} with your project checks`);
|
|
2261
2160
|
console.log(pc7.cyan("\u2192") + ` ${pc7.cyan("ahk task add")} to queue work for agents`);
|
|
@@ -2315,7 +2214,7 @@ async function runMigrate(cwd2, opts) {
|
|
|
2315
2214
|
// src/commands/migrate-storage.ts
|
|
2316
2215
|
import { copyFileSync, existsSync as existsSync12, mkdirSync as mkdirSync8, rmSync, writeFileSync as writeFileSync9 } from "fs";
|
|
2317
2216
|
import { homedir as homedir3 } from "os";
|
|
2318
|
-
import { dirname as dirname7, join as join15, resolve as
|
|
2217
|
+
import { dirname as dirname7, join as join15, resolve as resolve7 } from "path";
|
|
2319
2218
|
import pc9 from "picocolors";
|
|
2320
2219
|
function log5(msg) {
|
|
2321
2220
|
console.log(msg);
|
|
@@ -2323,11 +2222,17 @@ function log5(msg) {
|
|
|
2323
2222
|
function fail(msg) {
|
|
2324
2223
|
throw new Error(msg);
|
|
2325
2224
|
}
|
|
2225
|
+
function defaultMarkdownPathForConfig(config) {
|
|
2226
|
+
return config.storage.scope === "local" ? config.storage.markdownFallback.path : DEFAULT_MARKDOWN_PATH;
|
|
2227
|
+
}
|
|
2326
2228
|
function currentMdPathForScope(scope, config, cwd2, homeDir) {
|
|
2327
|
-
return scope === "global" ? join15(resolveGlobalStorageDir(config, homeDir), "current.md") :
|
|
2229
|
+
return scope === "global" ? join15(resolveGlobalStorageDir(config, homeDir), "current.md") : resolve7(cwd2, defaultMarkdownPathForConfig(config));
|
|
2230
|
+
}
|
|
2231
|
+
function defaultSqlitePathForConfig(config) {
|
|
2232
|
+
return config.storage.scope === "local" && config.database.type === "sqlite" ? config.storage.sqlitePath ?? DEFAULT_SQLITE_PATH : DEFAULT_SQLITE_PATH;
|
|
2328
2233
|
}
|
|
2329
2234
|
async function backupDestination(cwd2, storageDir, data) {
|
|
2330
|
-
const backupsDir =
|
|
2235
|
+
const backupsDir = resolve7(cwd2, storageDir, "backups");
|
|
2331
2236
|
const path = join15(backupsDir, `pre-migrate-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`);
|
|
2332
2237
|
try {
|
|
2333
2238
|
mkdirSync8(backupsDir, { recursive: true });
|
|
@@ -2358,7 +2263,7 @@ async function runMigrateStorage(cwd2, opts, homeDir = homedir3()) {
|
|
|
2358
2263
|
let realScope;
|
|
2359
2264
|
let realDbType;
|
|
2360
2265
|
if (!state) {
|
|
2361
|
-
const defaultSqlitePath = config
|
|
2266
|
+
const defaultSqlitePath = defaultSqlitePathForConfig(config);
|
|
2362
2267
|
const localPath = resolveSqlitePathForScope("local", defaultSqlitePath, cwd2, config, homeDir);
|
|
2363
2268
|
const globalPath = resolveSqlitePathForScope("global", defaultSqlitePath, cwd2, config, homeDir);
|
|
2364
2269
|
const localCount = await probeTaskCount(localPath);
|
|
@@ -2418,7 +2323,7 @@ async function probeTaskCount(dbPath) {
|
|
|
2418
2323
|
}
|
|
2419
2324
|
}
|
|
2420
2325
|
async function migrateScopeOnly(cwd2, config, homeDir, fromScope, toScope, opts) {
|
|
2421
|
-
const sqlitePath = config
|
|
2326
|
+
const sqlitePath = defaultSqlitePathForConfig(config);
|
|
2422
2327
|
const srcDb = resolveSqlitePathForScope(fromScope, sqlitePath, cwd2, config, homeDir);
|
|
2423
2328
|
const destDb = resolveSqlitePathForScope(toScope, sqlitePath, cwd2, config, homeDir);
|
|
2424
2329
|
const srcMd = currentMdPathForScope(fromScope, config, cwd2, homeDir);
|
|
@@ -2448,8 +2353,8 @@ async function migrateScopeOnly(cwd2, config, homeDir, fromScope, toScope, opts)
|
|
|
2448
2353
|
let data;
|
|
2449
2354
|
try {
|
|
2450
2355
|
await backupDriver.ensureSchema();
|
|
2451
|
-
const { HarnessDB } = await import("./db-
|
|
2452
|
-
const tmpDb = new HarnessDB(backupDriver,
|
|
2356
|
+
const { HarnessDB } = await import("./db-3OXHRFAR.js");
|
|
2357
|
+
const tmpDb = new HarnessDB(backupDriver, config, homeDir);
|
|
2453
2358
|
data = await tmpDb.exportJson();
|
|
2454
2359
|
} finally {
|
|
2455
2360
|
await backupDriver.close();
|
|
@@ -2482,7 +2387,7 @@ async function migrateScopeOnly(cwd2, config, homeDir, fromScope, toScope, opts)
|
|
|
2482
2387
|
log5(pc9.green(`\u2713 Storage migrated: scope ${fromScope} \u2192 ${toScope}`));
|
|
2483
2388
|
}
|
|
2484
2389
|
async function migrateAcrossDbType(cwd2, config, homeDir, sourceScope, opts) {
|
|
2485
|
-
const sqlitePath = config
|
|
2390
|
+
const sqlitePath = defaultSqlitePathForConfig(config);
|
|
2486
2391
|
const srcPath = resolveSqlitePathForScope(sourceScope, sqlitePath, cwd2, config, homeDir);
|
|
2487
2392
|
if (!existsSync12(srcPath)) {
|
|
2488
2393
|
fail(`Source sqlite database not found at ${srcPath} (expected ${sourceScope} scope) \u2014 nothing to migrate.`);
|
|
@@ -2494,8 +2399,8 @@ async function migrateAcrossDbType(cwd2, config, homeDir, sourceScope, opts) {
|
|
|
2494
2399
|
try {
|
|
2495
2400
|
await srcDriver.ensureSchema();
|
|
2496
2401
|
sourceCounts = await getRowCounts(srcDriver);
|
|
2497
|
-
const { HarnessDB } = await import("./db-
|
|
2498
|
-
const srcDb = new HarnessDB(srcDriver,
|
|
2402
|
+
const { HarnessDB } = await import("./db-3OXHRFAR.js");
|
|
2403
|
+
const srcDb = new HarnessDB(srcDriver, config, homeDir);
|
|
2499
2404
|
sourceData = await srcDb.exportJson();
|
|
2500
2405
|
} finally {
|
|
2501
2406
|
await srcDriver.close();
|
|
@@ -2548,13 +2453,14 @@ async function migrateAcrossDbType(cwd2, config, homeDir, sourceScope, opts) {
|
|
|
2548
2453
|
|
|
2549
2454
|
// src/commands/reset.ts
|
|
2550
2455
|
import { existsSync as existsSync13, readdirSync, rmSync as rmSync2 } from "fs";
|
|
2551
|
-
import {
|
|
2456
|
+
import { homedir as homedir4 } from "os";
|
|
2457
|
+
import { join as join16, resolve as resolve8 } from "path";
|
|
2552
2458
|
import * as p5 from "@clack/prompts";
|
|
2553
2459
|
import pc10 from "picocolors";
|
|
2554
2460
|
var AGENT_MD_FILES = ["lead", "explorer", "consultant", "builder", "reviewer"];
|
|
2555
2461
|
async function resetAgentMds(cwd2, provider) {
|
|
2556
2462
|
const agentDir = provider === "claude-code" ? ".claude/agents" : ".opencode/agents";
|
|
2557
|
-
const agentDirPath =
|
|
2463
|
+
const agentDirPath = resolve8(cwd2, agentDir);
|
|
2558
2464
|
if (!existsSync13(agentDirPath)) {
|
|
2559
2465
|
console.log(pc10.yellow(` Skipping agent files \u2014 directory not found: ${agentDirPath}`));
|
|
2560
2466
|
return;
|
|
@@ -2606,8 +2512,8 @@ async function runReset(cwd2, opts) {
|
|
|
2606
2512
|
process.exit(1);
|
|
2607
2513
|
}
|
|
2608
2514
|
const storageDir = config.storage.dir || ".harness";
|
|
2609
|
-
const dbPath = config.database.type === "sqlite" ?
|
|
2610
|
-
const featureListPath =
|
|
2515
|
+
const dbPath = config.database.type === "sqlite" ? resolveSqlitePath(config, cwd2, homedir4()) : null;
|
|
2516
|
+
const featureListPath = resolve8(cwd2, storageDir, "feature_list.json");
|
|
2611
2517
|
let resetDb = false;
|
|
2612
2518
|
let resetFeatureList = false;
|
|
2613
2519
|
let resetAgentMdsFlag = false;
|
|
@@ -2620,7 +2526,7 @@ async function runReset(cwd2, opts) {
|
|
|
2620
2526
|
resetDb = false;
|
|
2621
2527
|
} else {
|
|
2622
2528
|
const confirm3 = await p5.confirm({
|
|
2623
|
-
message: `Delete database (${
|
|
2529
|
+
message: `Delete database (${dbPath})?`,
|
|
2624
2530
|
initialValue: true
|
|
2625
2531
|
});
|
|
2626
2532
|
if (p5.isCancel(confirm3)) {
|
|
@@ -2683,7 +2589,7 @@ async function runReset(cwd2, opts) {
|
|
|
2683
2589
|
|
|
2684
2590
|
// src/core/mcp-server.ts
|
|
2685
2591
|
import { existsSync as existsSync15, mkdirSync as mkdirSync9, readdirSync as readdirSync2, readFileSync as readFileSync10, statSync, writeFileSync as writeFileSync10 } from "fs";
|
|
2686
|
-
import { join as join18, resolve as
|
|
2592
|
+
import { join as join18, resolve as resolve9 } from "path";
|
|
2687
2593
|
import { Server } from "@modelcontextprotocol/sdk/server";
|
|
2688
2594
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2689
2595
|
import {
|
|
@@ -2995,7 +2901,7 @@ var TOOLS = [
|
|
|
2995
2901
|
];
|
|
2996
2902
|
async function startMcpServer(config, cwd2) {
|
|
2997
2903
|
const db = await openDB(config, cwd2);
|
|
2998
|
-
const docsPath =
|
|
2904
|
+
const docsPath = resolve9(cwd2, config.project.docsPath);
|
|
2999
2905
|
const server = new Server(
|
|
3000
2906
|
{ name: "agent-harness-kit", version: VERSION },
|
|
3001
2907
|
{ capabilities: { tools: {} } }
|
|
@@ -3395,12 +3301,12 @@ async function runStatus(cwd2, opts) {
|
|
|
3395
3301
|
|
|
3396
3302
|
// src/commands/sync.ts
|
|
3397
3303
|
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "fs";
|
|
3398
|
-
import { join as join19, resolve as
|
|
3304
|
+
import { join as join19, resolve as resolve10 } from "path";
|
|
3399
3305
|
import pc12 from "picocolors";
|
|
3400
3306
|
async function runSync(cwd2, opts) {
|
|
3401
3307
|
const config = await loadConfig(cwd2);
|
|
3402
3308
|
const direction = opts.direction ?? "both";
|
|
3403
|
-
const featureListPath =
|
|
3309
|
+
const featureListPath = resolve10(join19(cwd2, config.storage.dir, "feature_list.json"));
|
|
3404
3310
|
const db = await openDB(config, cwd2);
|
|
3405
3311
|
try {
|
|
3406
3312
|
if (direction === "in" || direction === "both") {
|
|
@@ -3506,12 +3412,12 @@ async function runTaskAdd(cwd2) {
|
|
|
3506
3412
|
// src/commands/task/done.ts
|
|
3507
3413
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
3508
3414
|
import { existsSync as existsSync17 } from "fs";
|
|
3509
|
-
import { resolve as
|
|
3415
|
+
import { resolve as resolve11 } from "path";
|
|
3510
3416
|
import pc14 from "picocolors";
|
|
3511
3417
|
async function runTaskDone(cwd2, idOrSlug) {
|
|
3512
3418
|
const config = await loadConfig(cwd2);
|
|
3513
3419
|
if (config.health.required) {
|
|
3514
|
-
const scriptPath =
|
|
3420
|
+
const scriptPath = resolve11(cwd2, config.health.scriptPath);
|
|
3515
3421
|
if (existsSync17(scriptPath)) {
|
|
3516
3422
|
const result = spawnSync2("bash", [scriptPath], { cwd: cwd2, stdio: "pipe", encoding: "utf8" });
|
|
3517
3423
|
if (result.status !== 0) {
|
|
@@ -3725,15 +3631,15 @@ import pc18 from "picocolors";
|
|
|
3725
3631
|
var REGISTRY_URL2 = `https://registry.npmjs.org/${pkg.name}/latest`;
|
|
3726
3632
|
var TIMEOUT_MS2 = 2500;
|
|
3727
3633
|
function checkForUpdate(currentVersion) {
|
|
3728
|
-
return new Promise((
|
|
3729
|
-
const timer = setTimeout(() =>
|
|
3634
|
+
return new Promise((resolve12) => {
|
|
3635
|
+
const timer = setTimeout(() => resolve12(null), TIMEOUT_MS2);
|
|
3730
3636
|
fetch(REGISTRY_URL2).then((res) => res.json()).then((data) => {
|
|
3731
3637
|
clearTimeout(timer);
|
|
3732
3638
|
const latest = data.version;
|
|
3733
|
-
|
|
3639
|
+
resolve12(isNewer2(latest, currentVersion) ? { current: currentVersion, latest } : null);
|
|
3734
3640
|
}).catch(() => {
|
|
3735
3641
|
clearTimeout(timer);
|
|
3736
|
-
|
|
3642
|
+
resolve12(null);
|
|
3737
3643
|
});
|
|
3738
3644
|
});
|
|
3739
3645
|
}
|