@cardor/agent-harness-kit 1.6.7 → 1.7.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/README.md +6 -6
- package/dist/{chunk-X7FOJOZB.js → chunk-OEPZRC7J.js} +4 -2
- package/dist/chunk-OEPZRC7J.js.map +1 -0
- package/dist/cli.js +90 -27
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -2
- package/dist/chunk-X7FOJOZB.js.map +0 -1
package/README.md
CHANGED
|
@@ -151,7 +151,7 @@ ahk init
|
|
|
151
151
|
|
|
152
152
|
### `ahk init`
|
|
153
153
|
|
|
154
|
-
Interactive scaffold. Asks for your project name, description, AI provider,
|
|
154
|
+
Interactive scaffold. Asks for your project name, description, AI provider, docs path, task adapter, and an optional first task. Creates all harness files in the current directory.
|
|
155
155
|
|
|
156
156
|
```bash
|
|
157
157
|
ahk init
|
|
@@ -161,9 +161,9 @@ ahk init --name "my-app" --provider claude-code --docs ./docs --tasks local
|
|
|
161
161
|
ahk init --name "my-app" --provider codex-cli --docs ./docs --tasks local
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
-
Run this once per project.
|
|
164
|
+
Run this once per project. If the project is already initialized, the command prints an 'already initialized' message with suggested next-step commands (`ahk build`, `ahk build --sync`, `ahk reset`, `ahk serve`) and exits without overwriting anything.
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
The config file extension is chosen automatically: `.ts` if a `tsconfig.json` is present, `.mjs` for ESM-only projects (`"type": "module"` in `package.json`), or `.cjs` otherwise.
|
|
167
167
|
|
|
168
168
|
---
|
|
169
169
|
|
|
@@ -341,7 +341,7 @@ ahk export --sql --output dump.sql # SQL dump to file
|
|
|
341
341
|
|
|
342
342
|
```
|
|
343
343
|
your-project/
|
|
344
|
-
├── agent-harness-kit.config.ts
|
|
344
|
+
├── agent-harness-kit.config.{ts|mjs|cjs}
|
|
345
345
|
├── AGENTS.md
|
|
346
346
|
├── CLAUDE.md
|
|
347
347
|
├── health.sh
|
|
@@ -363,7 +363,7 @@ your-project/
|
|
|
363
363
|
|
|
364
364
|
```
|
|
365
365
|
your-project/
|
|
366
|
-
├── agent-harness-kit.config.ts
|
|
366
|
+
├── agent-harness-kit.config.{ts|mjs|cjs}
|
|
367
367
|
├── AGENTS.md
|
|
368
368
|
├── health.sh
|
|
369
369
|
├── opencode.json ← MCP server + default_agent + compaction config
|
|
@@ -380,7 +380,7 @@ your-project/
|
|
|
380
380
|
|
|
381
381
|
```
|
|
382
382
|
your-project/
|
|
383
|
-
├── agent-harness-kit.config.ts
|
|
383
|
+
├── agent-harness-kit.config.{ts|mjs|cjs}
|
|
384
384
|
├── AGENTS.md
|
|
385
385
|
├── health.sh
|
|
386
386
|
├── .harness/
|
|
@@ -5,7 +5,8 @@ import { createJiti } from "jiti";
|
|
|
5
5
|
var CONFIG_NAMES = [
|
|
6
6
|
"agent-harness-kit.config.ts",
|
|
7
7
|
"agent-harness-kit.config",
|
|
8
|
-
"agent-harness-kit.config.mjs"
|
|
8
|
+
"agent-harness-kit.config.mjs",
|
|
9
|
+
"agent-harness-kit.config.cjs"
|
|
9
10
|
];
|
|
10
11
|
function findConfigFile(cwd) {
|
|
11
12
|
for (const name of CONFIG_NAMES) {
|
|
@@ -76,7 +77,8 @@ function applyDefaults(config) {
|
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
export {
|
|
80
|
+
findConfigFile,
|
|
79
81
|
loadConfig,
|
|
80
82
|
defineHarness
|
|
81
83
|
};
|
|
82
|
-
//# sourceMappingURL=chunk-
|
|
84
|
+
//# sourceMappingURL=chunk-OEPZRC7J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/config.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { createJiti } from 'jiti'\n\nimport type { HarnessConfig } from '@/types'\n\nconst CONFIG_NAMES = [\n 'agent-harness-kit.config.ts',\n 'agent-harness-kit.config',\n 'agent-harness-kit.config.mjs',\n 'agent-harness-kit.config.cjs',\n]\n\nexport function findConfigFile(cwd: string): string | null {\n for (const name of CONFIG_NAMES) {\n const candidate = join(cwd, name)\n if (existsSync(candidate)) return candidate\n }\n return null\n}\n\nexport async function loadConfig(cwd: string): Promise<HarnessConfig> {\n const configPath = findConfigFile(cwd)\n if (!configPath) {\n throw new Error('No agent-harness-kit.config found. Run: ahk init')\n }\n\n const jiti = createJiti(import.meta.url)\n const mod = await jiti.import(configPath) as { default?: HarnessConfig } | HarnessConfig\n const config = (mod as { default?: HarnessConfig }).default ?? (mod as HarnessConfig)\n\n if (!config || typeof config !== 'object') {\n throw new Error(`agent-harness-kit.config must export a default HarnessConfig object.`)\n }\n\n return applyDefaults(config as HarnessConfig)\n}\n\nexport function defineHarness(config: HarnessConfig): HarnessConfig {\n return config\n}\n\nfunction applyDefaults(config: HarnessConfig): HarnessConfig {\n const c = config as Partial<HarnessConfig>\n return {\n ...config,\n provider: c.provider ?? 'claude-code',\n project: {\n docsPath: './docs',\n agentsMd: './AGENTS.md',\n ...c.project,\n } as HarnessConfig['project'],\n agents: {\n lead: { instructionsPath: null },\n explorer: { instructionsPath: null },\n builder: { instructionsPath: null },\n reviewer: { instructionsPath: null },\n custom: [],\n ...c.agents,\n } as HarnessConfig['agents'],\n database: c.database ?? { type: 'sqlite' as const, path: '.harness/harness.db' },\n storage: {\n dir: '.harness',\n tasks: { adapter: 'local' as const },\n sections: {\n toolsUsed: true,\n filesModified: true,\n result: true,\n blockers: true,\n nextSteps: false,\n },\n markdownFallback: { enabled: true, path: '.harness/current.md' },\n ...c.storage,\n } as HarnessConfig['storage'],\n health: {\n scriptPath: './health.sh',\n required: true,\n ...c.health,\n },\n tools: {\n mcp: { enabled: true, port: 3742 },\n scripts: { enabled: true, outputDir: './.harness/scripts' },\n ...c.tools,\n } as HarnessConfig['tools'],\n }\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAC3B,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAI3B,IAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,eAAe,KAA4B;AACzD,aAAW,QAAQ,cAAc;AAC/B,UAAM,YAAY,KAAK,KAAK,IAAI;AAChC,QAAI,WAAW,SAAS,EAAG,QAAO;AAAA,EACpC;AACA,SAAO;AACT;AAEA,eAAsB,WAAW,KAAqC;AACpE,QAAM,aAAa,eAAe,GAAG;AACrC,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,QAAM,OAAO,WAAW,YAAY,GAAG;AACvC,QAAM,MAAM,MAAM,KAAK,OAAO,UAAU;AACxC,QAAM,SAAU,IAAoC,WAAY;AAEhE,MAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,UAAM,IAAI,MAAM,sEAAsE;AAAA,EACxF;AAEA,SAAO,cAAc,MAAuB;AAC9C;AAEO,SAAS,cAAc,QAAsC;AAClE,SAAO;AACT;AAEA,SAAS,cAAc,QAAsC;AAC3D,QAAM,IAAI;AACV,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU,EAAE,YAAY;AAAA,IACxB,SAAS;AAAA,MACP,UAAU;AAAA,MACV,UAAU;AAAA,MACV,GAAG,EAAE;AAAA,IACP;AAAA,IACA,QAAQ;AAAA,MACN,MAAM,EAAE,kBAAkB,KAAK;AAAA,MAC/B,UAAU,EAAE,kBAAkB,KAAK;AAAA,MACnC,SAAS,EAAE,kBAAkB,KAAK;AAAA,MAClC,UAAU,EAAE,kBAAkB,KAAK;AAAA,MACnC,QAAQ,CAAC;AAAA,MACT,GAAG,EAAE;AAAA,IACP;AAAA,IACA,UAAU,EAAE,YAAY,EAAE,MAAM,UAAmB,MAAM,sBAAsB;AAAA,IAC/E,SAAS;AAAA,MACP,KAAK;AAAA,MACL,OAAO,EAAE,SAAS,QAAiB;AAAA,MACnC,UAAU;AAAA,QACR,WAAW;AAAA,QACX,eAAe;AAAA,QACf,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,WAAW;AAAA,MACb;AAAA,MACA,kBAAkB,EAAE,SAAS,MAAM,MAAM,sBAAsB;AAAA,MAC/D,GAAG,EAAE;AAAA,IACP;AAAA,IACA,QAAQ;AAAA,MACN,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,GAAG,EAAE;AAAA,IACP;AAAA,IACA,OAAO;AAAA,MACL,KAAK,EAAE,SAAS,MAAM,MAAM,KAAK;AAAA,MACjC,SAAS,EAAE,SAAS,MAAM,WAAW,qBAAqB;AAAA,MAC1D,GAAG,EAAE;AAAA,IACP;AAAA,EACF;AACF;","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
findConfigFile,
|
|
2
3
|
loadConfig
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-OEPZRC7J.js";
|
|
4
5
|
|
|
5
6
|
// src/cli.ts
|
|
6
7
|
import { Command } from "commander";
|
|
@@ -499,6 +500,57 @@ export default defineHarness({
|
|
|
499
500
|
})
|
|
500
501
|
`;
|
|
501
502
|
}
|
|
503
|
+
var configMjs = configTs;
|
|
504
|
+
function configCjs(params) {
|
|
505
|
+
return `const { defineHarness } = require('@cardor/agent-harness-kit')
|
|
506
|
+
|
|
507
|
+
module.exports = defineHarness({
|
|
508
|
+
project: {
|
|
509
|
+
name: '${params.name}',
|
|
510
|
+
description: '${params.description}',
|
|
511
|
+
docsPath: '${params.docsPath}',
|
|
512
|
+
},
|
|
513
|
+
|
|
514
|
+
provider: '${params.provider}',
|
|
515
|
+
|
|
516
|
+
agents: {
|
|
517
|
+
lead: { instructionsPath: null },
|
|
518
|
+
explorer: { instructionsPath: null, allowedPaths: ['${params.docsPath}', './src'] },
|
|
519
|
+
builder: { instructionsPath: null, writablePaths: ['./src', './tests'] },
|
|
520
|
+
reviewer: { instructionsPath: null },
|
|
521
|
+
custom: [],
|
|
522
|
+
},
|
|
523
|
+
|
|
524
|
+
// SQLite (default). Switch to postgres/mysql by changing database.type.
|
|
525
|
+
// database: { type: 'postgres', connectionString: process.env.DATABASE_URL },
|
|
526
|
+
// database: { type: 'mysql', connectionString: process.env.DATABASE_URL },
|
|
527
|
+
database: { type: 'sqlite', path: '.harness/harness.db' },
|
|
528
|
+
|
|
529
|
+
storage: {
|
|
530
|
+
dir: '.harness',
|
|
531
|
+
tasks: { adapter: '${params.tasksAdapter}' },
|
|
532
|
+
sections: {
|
|
533
|
+
toolsUsed: true,
|
|
534
|
+
filesModified: true,
|
|
535
|
+
result: true,
|
|
536
|
+
blockers: true,
|
|
537
|
+
nextSteps: false,
|
|
538
|
+
},
|
|
539
|
+
markdownFallback: { enabled: true, path: '.harness/current.md' },
|
|
540
|
+
},
|
|
541
|
+
|
|
542
|
+
health: {
|
|
543
|
+
scriptPath: './health.sh',
|
|
544
|
+
required: true,
|
|
545
|
+
},
|
|
546
|
+
|
|
547
|
+
tools: {
|
|
548
|
+
mcp: { enabled: true, port: ${params.port} },
|
|
549
|
+
scripts: { enabled: true, outputDir: './.harness/scripts' },
|
|
550
|
+
},
|
|
551
|
+
})
|
|
552
|
+
`;
|
|
553
|
+
}
|
|
502
554
|
function agentLead(vars) {
|
|
503
555
|
return loadAgentTemplate("lead", vars);
|
|
504
556
|
}
|
|
@@ -1871,7 +1923,6 @@ function getProviderHealthFiles(provider) {
|
|
|
1871
1923
|
|
|
1872
1924
|
// src/commands/init.ts
|
|
1873
1925
|
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync9 } from "fs";
|
|
1874
|
-
import { homedir } from "os";
|
|
1875
1926
|
import { join as join12 } from "path";
|
|
1876
1927
|
import * as p3 from "@clack/prompts";
|
|
1877
1928
|
import pc6 from "picocolors";
|
|
@@ -1943,6 +1994,17 @@ function readProjectNameFromPackageJson(cwd2) {
|
|
|
1943
1994
|
return null;
|
|
1944
1995
|
}
|
|
1945
1996
|
}
|
|
1997
|
+
function detectConfigExtension(cwd2) {
|
|
1998
|
+
try {
|
|
1999
|
+
if (existsSync8(join11(cwd2, "tsconfig.json"))) return "ts";
|
|
2000
|
+
const pkgPath2 = join11(cwd2, "package.json");
|
|
2001
|
+
if (!existsSync8(pkgPath2)) return "cjs";
|
|
2002
|
+
const pkg2 = JSON.parse(readFileSync5(pkgPath2, "utf8"));
|
|
2003
|
+
if (pkg2?.type === "module") return "mjs";
|
|
2004
|
+
} catch {
|
|
2005
|
+
}
|
|
2006
|
+
return "cjs";
|
|
2007
|
+
}
|
|
1946
2008
|
function applyConfigDefaults(params) {
|
|
1947
2009
|
return {
|
|
1948
2010
|
provider: params.provider,
|
|
@@ -2017,6 +2079,23 @@ function printWelcomeMessage(projectName) {
|
|
|
2017
2079
|
|
|
2018
2080
|
// src/commands/init.ts
|
|
2019
2081
|
async function runInit(cwd2, flags) {
|
|
2082
|
+
const existingConfig = findConfigFile(cwd2);
|
|
2083
|
+
if (existingConfig) {
|
|
2084
|
+
console.log(
|
|
2085
|
+
pc6.yellow("\u26A0") + " " + pc6.bold("Project already initialized.") + pc6.dim(` (${existingConfig})`)
|
|
2086
|
+
);
|
|
2087
|
+
console.log();
|
|
2088
|
+
console.log(pc6.dim("Suggested next steps:"));
|
|
2089
|
+
console.log(
|
|
2090
|
+
" " + pc6.cyan("ahk build") + pc6.dim(" \u2014 re-sync agent files after updating the library")
|
|
2091
|
+
);
|
|
2092
|
+
console.log(" " + pc6.cyan("ahk build --sync") + pc6.dim(" \u2014 also sync agent permissions"));
|
|
2093
|
+
console.log(
|
|
2094
|
+
" " + pc6.cyan("ahk reset") + pc6.dim(" \u2014 wipe and re-initialize from scratch")
|
|
2095
|
+
);
|
|
2096
|
+
console.log(" " + pc6.cyan("ahk dashboard") + pc6.dim(" \u2014 open the harness dashboard"));
|
|
2097
|
+
process.exit(0);
|
|
2098
|
+
}
|
|
2020
2099
|
const detectedName = flags.name ?? readProjectNameFromPackageJson(cwd2);
|
|
2021
2100
|
const projectName = detectedName || "my-project";
|
|
2022
2101
|
printWelcomeMessage(projectName);
|
|
@@ -2066,18 +2145,6 @@ async function runInit(cwd2, flags) {
|
|
|
2066
2145
|
}
|
|
2067
2146
|
provider = val;
|
|
2068
2147
|
}
|
|
2069
|
-
let globalInstallation = false;
|
|
2070
|
-
const globalVal = await p3.confirm({
|
|
2071
|
-
message: "Install globally (to home directory)?",
|
|
2072
|
-
initialValue: false
|
|
2073
|
-
});
|
|
2074
|
-
if (p3.isCancel(globalVal)) {
|
|
2075
|
-
p3.cancel("Cancelled.");
|
|
2076
|
-
process.exit(0);
|
|
2077
|
-
}
|
|
2078
|
-
if (globalVal) {
|
|
2079
|
-
globalInstallation = true;
|
|
2080
|
-
}
|
|
2081
2148
|
let docsPath;
|
|
2082
2149
|
if (flags.docs) {
|
|
2083
2150
|
docsPath = flags.docs;
|
|
@@ -2147,20 +2214,17 @@ async function runInit(cwd2, flags) {
|
|
|
2147
2214
|
}
|
|
2148
2215
|
firstTask = { title: taskTitle, description: taskDesc, acceptance };
|
|
2149
2216
|
}
|
|
2217
|
+
let configExt = "ts";
|
|
2150
2218
|
const spinner6 = p3.spinner();
|
|
2151
2219
|
spinner6.start("Scaffolding...");
|
|
2152
2220
|
try {
|
|
2153
2221
|
const config = applyConfigDefaults({ name, description, provider, docsPath, tasksAdapter });
|
|
2154
2222
|
const materializer = getMaterializer(provider);
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
installDir = join12(homedir(), ".config", "opencode");
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
const configContent = configTs({
|
|
2223
|
+
const installDir = cwd2;
|
|
2224
|
+
configExt = detectConfigExtension(cwd2);
|
|
2225
|
+
const configFileName = `agent-harness-kit.config.${configExt}`;
|
|
2226
|
+
const templateFn = configExt === "ts" ? configTs : configExt === "mjs" ? configMjs : configCjs;
|
|
2227
|
+
const configContent = templateFn({
|
|
2164
2228
|
name,
|
|
2165
2229
|
description,
|
|
2166
2230
|
provider,
|
|
@@ -2168,7 +2232,7 @@ async function runInit(cwd2, flags) {
|
|
|
2168
2232
|
tasksAdapter,
|
|
2169
2233
|
port: config.tools.mcp.port
|
|
2170
2234
|
});
|
|
2171
|
-
writeFileSync9(join12(installDir,
|
|
2235
|
+
writeFileSync9(join12(installDir, configFileName), configContent, "utf8");
|
|
2172
2236
|
mkdirSync8(join12(installDir, config.storage.dir), { recursive: true });
|
|
2173
2237
|
const db = await openDB(config, installDir);
|
|
2174
2238
|
await materializer.scaffold(config, { cwd: installDir, firstTask });
|
|
@@ -2188,12 +2252,11 @@ async function runInit(cwd2, flags) {
|
|
|
2188
2252
|
p3.log.error(err instanceof Error ? err.message : String(err));
|
|
2189
2253
|
throw err;
|
|
2190
2254
|
}
|
|
2191
|
-
|
|
2192
|
-
console.log(pc6.green(`\u2713 Scaffolded harness in ${agentHarnessKitDir}`));
|
|
2255
|
+
console.log(pc6.green("\u2713 Scaffolded harness in current directory"));
|
|
2193
2256
|
const agentsDir = provider === "claude-code" ? ".claude/agents/" : ".opencode/agents/";
|
|
2194
2257
|
const mcpFile = provider === "claude-code" ? ".claude/mcp.json" : "./opencode.json";
|
|
2195
2258
|
console.log("");
|
|
2196
|
-
console.log(pc6.green(
|
|
2259
|
+
console.log(pc6.green(`\u2713 agent-harness-kit.config.${configExt}`));
|
|
2197
2260
|
console.log(pc6.green("\u2713 AGENTS.md"));
|
|
2198
2261
|
console.log(pc6.green("\u2713 health.sh"));
|
|
2199
2262
|
console.log(pc6.green("\u2713 .harness/harness.db"));
|