@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 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, whether to install globally, docs path, task adapter, and an optional first task. Creates all harness files in the current directory (or home directory if global).
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. Safe to re-run it will not overwrite files you've customized.
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
- **Global installation** if you answer yes to "Install globally?", files go to `~/.claude` (Claude Code), `~/.config/opencode` (OpenCode), or `~/.codex` (Codex CLI). This lets you share one harness config across all your projects.
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-X7FOJOZB.js.map
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-X7FOJOZB.js";
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
- let installDir = cwd2;
2156
- if (globalInstallation) {
2157
- if (provider === "claude-code") {
2158
- installDir = join12(homedir(), ".claude");
2159
- } else {
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, "agent-harness-kit.config.ts"), configContent, "utf8");
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
- const agentHarnessKitDir = globalInstallation ? "home directory" : "current directory";
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("\u2713 agent-harness-kit.config.ts"));
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"));