@cardor/agent-harness-kit 1.1.7 → 1.2.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
@@ -11,23 +11,25 @@ import * as p from "@clack/prompts";
11
11
  import pc from "picocolors";
12
12
 
13
13
  // src/core/materializer/claude-code.ts
14
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
15
- import { join as join3, resolve as resolve2 } from "path";
14
+ import { existsSync as existsSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
15
+ import { join as join4, resolve as resolve3 } from "path";
16
+
17
+ // src/utils/file.ts
18
+ import { mkdirSync, writeFileSync } from "fs";
19
+ import { join, resolve } from "path";
20
+ var write = (cwd2, relPath, content, mode) => {
21
+ const abs = join(cwd2, relPath);
22
+ mkdirSync(resolve(abs, ".."), { recursive: true });
23
+ writeFileSync(abs, content, { encoding: "utf8", mode });
24
+ };
16
25
 
17
26
  // src/core/materializer/mcp-merge.ts
18
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
27
+ import { existsSync, mkdirSync as mkdirSync2, readFileSync, writeFileSync as writeFileSync2 } from "fs";
19
28
  import { dirname } from "path";
20
- var compactionConfig = {
21
- compaction: {
22
- auto: true,
23
- prune: true,
24
- reserved: 1e4
25
- }
26
- };
27
29
  function mergeClaudeMcpJson(filePath, port) {
28
30
  const folderPath = dirname(filePath);
29
31
  if (!existsSync(folderPath)) {
30
- mkdirSync(folderPath, { recursive: true });
32
+ mkdirSync2(folderPath, { recursive: true });
31
33
  }
32
34
  let existing = {};
33
35
  if (existsSync(filePath)) {
@@ -36,27 +38,39 @@ function mergeClaudeMcpJson(filePath, port) {
36
38
  } catch {
37
39
  }
38
40
  }
39
- const agentHarnessKitConfig = {
40
- type: "stdio",
41
- command: "npx",
42
- args: ["ahk", "serve", "--port", String(port)]
43
- };
44
41
  const merged = {
45
42
  ...existing,
46
- compaction: existing.compaction ?? compactionConfig.compaction,
47
- default_agent: "lead",
48
43
  mcpServers: {
49
44
  ...existing.mcpServers ?? {},
50
- "agent-harness-kit": agentHarnessKitConfig
45
+ "agent-harness-kit": {
46
+ type: "stdio",
47
+ command: "npx",
48
+ args: ["ahk", "serve", "--port", String(port)]
49
+ }
50
+ }
51
+ };
52
+ mkdirSync2(dirname(filePath), { recursive: true });
53
+ writeFileSync2(filePath, JSON.stringify(merged, null, 2) + "\n", "utf8");
54
+ }
55
+ function mergeClaudeSettingsJson(filePath) {
56
+ mkdirSync2(dirname(filePath), { recursive: true });
57
+ let existing = {};
58
+ if (existsSync(filePath)) {
59
+ try {
60
+ existing = JSON.parse(readFileSync(filePath, "utf8"));
61
+ } catch {
51
62
  }
63
+ }
64
+ const merged = {
65
+ ...existing,
66
+ agent: "lead"
52
67
  };
53
- mkdirSync(dirname(filePath), { recursive: true });
54
- writeFileSync(filePath, JSON.stringify(merged, null, 2) + "\n", "utf8");
68
+ writeFileSync2(filePath, JSON.stringify(merged, null, 2) + "\n", "utf8");
55
69
  }
56
70
  function mergeOpencodeJson(filePath, port) {
57
71
  const folderPath = dirname(filePath);
58
72
  if (!existsSync(folderPath)) {
59
- mkdirSync(folderPath, { recursive: true });
73
+ mkdirSync2(folderPath, { recursive: true });
60
74
  }
61
75
  let existing = {};
62
76
  if (existsSync(filePath)) {
@@ -66,35 +80,73 @@ function mergeOpencodeJson(filePath, port) {
66
80
  }
67
81
  }
68
82
  const existingMcp = existing.mcp ?? {};
69
- const agentHarnessKitConfig = {
70
- enabled: true,
71
- type: "local",
72
- command: ["npx", "ahk", "serve", "--port", String(port)]
73
- };
74
83
  const merged = {
75
84
  ...existing,
76
- compaction: existing.compaction ?? compactionConfig.compaction,
77
85
  default_agent: "lead",
86
+ compaction: existing.compaction ?? { auto: true, prune: true, reserved: 1e4 },
87
+ permission: existing.permission ?? { write: "ask" },
78
88
  mcp: {
79
89
  ...existingMcp,
80
- "agent-harness-kit": agentHarnessKitConfig
90
+ "agent-harness-kit": {
91
+ enabled: true,
92
+ type: "local",
93
+ command: ["npx", "ahk", "serve", "--port", String(port)]
94
+ }
81
95
  }
82
96
  };
83
- writeFileSync(filePath, JSON.stringify(merged, null, 2) + "\n", "utf8");
97
+ writeFileSync2(filePath, JSON.stringify(merged, null, 2) + "\n", "utf8");
98
+ }
99
+ function mergeTomlSection(content, sectionName, sectionBody) {
100
+ const lines = content.split("\n");
101
+ const header = `[${sectionName}]`;
102
+ const startIdx = lines.findIndex((l) => l.trim() === header);
103
+ if (startIdx === -1) {
104
+ const trimmed = content.trimEnd();
105
+ return trimmed + (trimmed ? "\n\n" : "") + header + "\n" + sectionBody.trimEnd() + "\n";
106
+ }
107
+ let endIdx = lines.length;
108
+ for (let i = startIdx + 1; i < lines.length; i++) {
109
+ if (/^\[/.test(lines[i])) {
110
+ endIdx = i;
111
+ break;
112
+ }
113
+ }
114
+ const newLines = [
115
+ ...lines.slice(0, startIdx),
116
+ header,
117
+ ...sectionBody.trimEnd().split("\n"),
118
+ "",
119
+ ...lines.slice(endIdx)
120
+ ];
121
+ return newLines.join("\n");
122
+ }
123
+ function mergeCodexConfigToml(filePath, port) {
124
+ mkdirSync2(dirname(filePath), { recursive: true });
125
+ let content = "";
126
+ if (existsSync(filePath)) {
127
+ content = readFileSync(filePath, "utf8");
128
+ }
129
+ const sectionBody = [
130
+ 'command = "npx"',
131
+ `args = ["ahk", "serve", "--port", "${port}"]`,
132
+ 'default_tools_approval_mode = "auto"'
133
+ ].join("\n");
134
+ content = mergeTomlSection(content, "mcp_servers.agent-harness-kit", sectionBody);
135
+ writeFileSync2(filePath, content, "utf8");
84
136
  }
85
137
 
86
138
  // src/core/materializer/scaffold-utils.ts
87
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
88
- import { join as join2, resolve } from "path";
139
+ import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
140
+ import { join as join3, resolve as resolve2 } from "path";
89
141
 
90
142
  // src/core/materializer/templates.ts
91
143
  import { readFileSync as readFileSync2 } from "fs";
92
- import { dirname as dirname2, join } from "path";
144
+ import { dirname as dirname2, join as join2 } from "path";
93
145
  import { fileURLToPath } from "url";
94
146
  var __dirname = dirname2(fileURLToPath(import.meta.url));
95
- var TEMPLATES_DIR = join(__dirname, "agent-templates");
147
+ var TEMPLATES_DIR = join2(__dirname, "agent-templates");
96
148
  function loadAgentTemplate(name, vars = {}) {
97
- const raw = readFileSync2(join(TEMPLATES_DIR, `${name}.md`), "utf8");
149
+ const raw = readFileSync2(join2(TEMPLATES_DIR, `${name}.md`), "utf8");
98
150
  return raw.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
99
151
  }
100
152
  var HEALTH_SH = `#!/usr/bin/env bash
@@ -349,6 +401,55 @@ function agentReviewer(vars) {
349
401
  function featureListJson(tasks) {
350
402
  return JSON.stringify(tasks, null, 2) + "\n";
351
403
  }
404
+ function stripFrontmatter(md) {
405
+ const parts = md.split(/^---\s*$/m);
406
+ if (parts.length < 3) return { description: "", body: md };
407
+ const frontmatter = parts[1];
408
+ const body = parts.slice(2).join("---").replace(/^\n/, "");
409
+ let description = "";
410
+ const foldedMatch = frontmatter.match(/^description:\s*[>|]\s*\n((?:[ \t]+[^\n]*\n?)*)/m);
411
+ if (foldedMatch) {
412
+ description = foldedMatch[1].split("\n").map((l) => l.trim()).filter(Boolean).join(" ");
413
+ } else {
414
+ const inlineMatch = frontmatter.match(/^description:\s*(.+)$/m);
415
+ if (inlineMatch) description = inlineMatch[1].trim();
416
+ }
417
+ return { description, body };
418
+ }
419
+ function toCodexToml(name, description, body, sandboxMode) {
420
+ const safe = (s) => s.replace(/"""/g, '""\\u0022');
421
+ return `name = "${name}"
422
+ sandbox_mode = "${sandboxMode}"
423
+
424
+ description = """
425
+ ${safe(description)}
426
+ """
427
+
428
+ developer_instructions = """
429
+ ${safe(body.trimEnd())}
430
+ """
431
+ `;
432
+ }
433
+ function agentLeadToml(vars) {
434
+ const { description, body } = stripFrontmatter(loadAgentTemplate("lead", vars));
435
+ return toCodexToml("lead", description, body, "read-only");
436
+ }
437
+ function agentLeadAsDefaultToml(vars) {
438
+ const { description, body } = stripFrontmatter(loadAgentTemplate("lead", vars));
439
+ return toCodexToml("default", description, body, "read-only");
440
+ }
441
+ function agentExplorerToml(vars) {
442
+ const { description, body } = stripFrontmatter(loadAgentTemplate("explorer", vars));
443
+ return toCodexToml("explorer", description, body, "read-only");
444
+ }
445
+ function agentBuilderToml(vars) {
446
+ const { description, body } = stripFrontmatter(loadAgentTemplate("builder", vars));
447
+ return toCodexToml("builder", description, body, "workspace-write");
448
+ }
449
+ function agentReviewerToml(vars) {
450
+ const { description, body } = stripFrontmatter(loadAgentTemplate("reviewer", vars));
451
+ return toCodexToml("reviewer", description, body, "read-only");
452
+ }
352
453
  var GITIGNORE_ENTRIES = `
353
454
  # agent-harness-kit
354
455
  .harness/harness.db
@@ -359,17 +460,17 @@ var GITIGNORE_ENTRIES = `
359
460
 
360
461
  // src/core/materializer/scaffold-utils.ts
361
462
  function writeAgentFile(cwd2, relPath, content) {
362
- const abs = join2(cwd2, relPath);
463
+ const abs = join3(cwd2, relPath);
363
464
  if (existsSync2(abs)) return;
364
- mkdirSync2(resolve(abs, ".."), { recursive: true });
365
- writeFileSync2(abs, content, "utf8");
465
+ mkdirSync3(resolve2(abs, ".."), { recursive: true });
466
+ writeFileSync3(abs, content, "utf8");
366
467
  }
367
468
  function appendGitignore(cwd2) {
368
- const giPath = join2(cwd2, ".gitignore");
469
+ const giPath = join3(cwd2, ".gitignore");
369
470
  const existing = existsSync2(giPath) ? readFileSync3(giPath, "utf8") : "";
370
471
  const toAdd = GITIGNORE_ENTRIES.split("\n").filter((line) => line && !existing.includes(line)).join("\n");
371
472
  if (toAdd.trim()) {
372
- writeFileSync2(giPath, existing + (existing.endsWith("\n") ? "" : "\n") + toAdd + "\n", "utf8");
473
+ writeFileSync3(giPath, existing + (existing.endsWith("\n") ? "" : "\n") + toAdd + "\n", "utf8");
373
474
  }
374
475
  }
375
476
  function slugify(title) {
@@ -380,20 +481,16 @@ function slugify(title) {
380
481
  var ClaudeCodeMaterializer = class {
381
482
  async scaffold(config, opts) {
382
483
  const { cwd: cwd2 } = opts;
383
- const write = (relPath, content, mode) => {
384
- const abs = join3(cwd2, relPath);
385
- mkdirSync3(resolve2(abs, ".."), { recursive: true });
386
- writeFileSync3(abs, content, { encoding: "utf8", mode });
387
- };
388
- write("AGENTS.md", agentsMd(config));
389
- write("CLAUDE.md", claudeMd(config));
390
- if (!existsSync3(join3(cwd2, "health.sh"))) {
391
- write("health.sh", HEALTH_SH, 493);
484
+ write(cwd2, "AGENTS.md", agentsMd(config));
485
+ write(cwd2, "CLAUDE.md", claudeMd(config));
486
+ if (!existsSync3(join4(cwd2, "health.sh"))) {
487
+ write(cwd2, "health.sh", HEALTH_SH, 493);
392
488
  }
393
489
  const tasks = opts.firstTask ? [{ slug: slugify(opts.firstTask.title), ...opts.firstTask }] : [];
394
- write(join3(config.storage.dir, "feature_list.json"), featureListJson(tasks));
395
- if (!existsSync3(join3(cwd2, config.storage.markdownFallback.path))) {
490
+ write(cwd2, "feature_list.json", featureListJson(tasks));
491
+ if (!existsSync3(join4(cwd2, config.storage.markdownFallback.path))) {
396
492
  write(
493
+ cwd2,
397
494
  config.storage.markdownFallback.path,
398
495
  `<!-- AUTO-GENERATED by agent-harness-kit \u2014 DO NOT EDIT MANUALLY -->
399
496
  <!-- Run ahk status to refresh -->
@@ -411,17 +508,18 @@ No tasks in progress.
411
508
  writeAgentFile(cwd2, ".claude/agents/explorer.md", agentExplorer({ projectName, allowedPaths }));
412
509
  writeAgentFile(cwd2, ".claude/agents/builder.md", agentBuilder({ projectName, writablePaths }));
413
510
  writeAgentFile(cwd2, ".claude/agents/reviewer.md", agentReviewer({ projectName }));
414
- mergeClaudeMcpJson(join3(cwd2, ".claude/mcp.json"), config.tools.mcp.port);
511
+ mergeClaudeMcpJson(join4(cwd2, ".claude/mcp.json"), config.tools.mcp.port);
512
+ mergeClaudeSettingsJson(join4(cwd2, ".claude/settings.json"));
415
513
  appendGitignore(cwd2);
416
514
  }
417
515
  async build(config, cwd2) {
418
- const write = (relPath, content) => {
419
- const abs = join3(cwd2, relPath);
420
- mkdirSync3(resolve2(abs, ".."), { recursive: true });
421
- writeFileSync3(abs, content, "utf8");
516
+ const write2 = (relPath, content) => {
517
+ const abs = join4(cwd2, relPath);
518
+ mkdirSync4(resolve3(abs, ".."), { recursive: true });
519
+ writeFileSync4(abs, content, "utf8");
422
520
  };
423
- write("AGENTS.md", agentsMd(config));
424
- write("CLAUDE.md", claudeMd(config));
521
+ write2("AGENTS.md", agentsMd(config));
522
+ write2("CLAUDE.md", claudeMd(config));
425
523
  const projectName = config.project.name;
426
524
  const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(", ");
427
525
  const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
@@ -429,7 +527,70 @@ No tasks in progress.
429
527
  writeAgentFile(cwd2, ".claude/agents/explorer.md", agentExplorer({ projectName, allowedPaths }));
430
528
  writeAgentFile(cwd2, ".claude/agents/builder.md", agentBuilder({ projectName, writablePaths }));
431
529
  writeAgentFile(cwd2, ".claude/agents/reviewer.md", agentReviewer({ projectName }));
432
- mergeClaudeMcpJson(join3(cwd2, ".claude/mcp.json"), config.tools.mcp.port);
530
+ mergeClaudeMcpJson(join4(cwd2, ".claude/mcp.json"), config.tools.mcp.port);
531
+ mergeClaudeSettingsJson(join4(cwd2, ".claude/settings.json"));
532
+ }
533
+ async migrate(config, _to, _cwd) {
534
+ void config;
535
+ }
536
+ };
537
+
538
+ // src/core/materializer/codex-cli.ts
539
+ import { existsSync as existsSync4, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
540
+ import { join as join5, resolve as resolve4 } from "path";
541
+ var CodexCliMaterializer = class {
542
+ async scaffold(config, opts) {
543
+ const { cwd: cwd2 } = opts;
544
+ const write2 = (relPath, content, mode) => {
545
+ const abs = join5(cwd2, relPath);
546
+ mkdirSync5(resolve4(abs, ".."), { recursive: true });
547
+ writeFileSync5(abs, content, { encoding: "utf8", mode });
548
+ };
549
+ write2("AGENTS.md", agentsMd(config));
550
+ if (!existsSync4(join5(cwd2, "health.sh"))) {
551
+ write2("health.sh", HEALTH_SH, 493);
552
+ }
553
+ const tasks = opts.firstTask ? [{ slug: slugify(opts.firstTask.title), ...opts.firstTask }] : [];
554
+ write2(join5(config.storage.dir, "feature_list.json"), featureListJson(tasks));
555
+ if (!existsSync4(join5(cwd2, config.storage.markdownFallback.path))) {
556
+ write2(
557
+ config.storage.markdownFallback.path,
558
+ `<!-- AUTO-GENERATED by agent-harness-kit \u2014 DO NOT EDIT MANUALLY -->
559
+ <!-- Run ahk status to refresh -->
560
+
561
+ # Current Session
562
+
563
+ No tasks in progress.
564
+ `
565
+ );
566
+ }
567
+ const projectName = config.project.name;
568
+ const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(", ");
569
+ const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
570
+ writeAgentFile(cwd2, ".codex/agents/lead.toml", agentLeadToml({ projectName }));
571
+ writeAgentFile(cwd2, ".codex/agents/explorer.toml", agentExplorerToml({ projectName, allowedPaths }));
572
+ writeAgentFile(cwd2, ".codex/agents/builder.toml", agentBuilderToml({ projectName, writablePaths }));
573
+ writeAgentFile(cwd2, ".codex/agents/reviewer.toml", agentReviewerToml({ projectName }));
574
+ writeAgentFile(cwd2, ".codex/agents/default.toml", agentLeadAsDefaultToml({ projectName }));
575
+ mergeCodexConfigToml(join5(cwd2, ".codex/config.toml"), config.tools.mcp.port);
576
+ appendGitignore(cwd2);
577
+ }
578
+ async build(config, cwd2) {
579
+ const write2 = (relPath, content) => {
580
+ const abs = join5(cwd2, relPath);
581
+ mkdirSync5(resolve4(abs, ".."), { recursive: true });
582
+ writeFileSync5(abs, content, "utf8");
583
+ };
584
+ write2("AGENTS.md", agentsMd(config));
585
+ const projectName = config.project.name;
586
+ const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(", ");
587
+ const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
588
+ writeAgentFile(cwd2, ".codex/agents/lead.toml", agentLeadToml({ projectName }));
589
+ writeAgentFile(cwd2, ".codex/agents/explorer.toml", agentExplorerToml({ projectName, allowedPaths }));
590
+ writeAgentFile(cwd2, ".codex/agents/builder.toml", agentBuilderToml({ projectName, writablePaths }));
591
+ writeAgentFile(cwd2, ".codex/agents/reviewer.toml", agentReviewerToml({ projectName }));
592
+ writeAgentFile(cwd2, ".codex/agents/default.toml", agentLeadAsDefaultToml({ projectName }));
593
+ mergeCodexConfigToml(join5(cwd2, ".codex/config.toml"), config.tools.mcp.port);
433
594
  }
434
595
  async migrate(config, _to, _cwd) {
435
596
  void config;
@@ -437,24 +598,24 @@ No tasks in progress.
437
598
  };
438
599
 
439
600
  // src/core/materializer/opencode.ts
440
- import { existsSync as existsSync4, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
441
- import { join as join4, resolve as resolve3 } from "path";
601
+ import { existsSync as existsSync5, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
602
+ import { join as join6, resolve as resolve5 } from "path";
442
603
  var OpenCodeMaterializer = class {
443
604
  async scaffold(config, opts) {
444
605
  const { cwd: cwd2 } = opts;
445
- const write = (relPath, content, mode) => {
446
- const abs = join4(cwd2, relPath);
447
- mkdirSync4(resolve3(abs, ".."), { recursive: true });
448
- writeFileSync4(abs, content, { encoding: "utf8", mode });
606
+ const write2 = (relPath, content, mode) => {
607
+ const abs = join6(cwd2, relPath);
608
+ mkdirSync6(resolve5(abs, ".."), { recursive: true });
609
+ writeFileSync6(abs, content, { encoding: "utf8", mode });
449
610
  };
450
- write("AGENTS.md", agentsMd(config));
451
- if (!existsSync4(join4(cwd2, "health.sh"))) {
452
- write("health.sh", HEALTH_SH, 493);
611
+ write2("AGENTS.md", agentsMd(config));
612
+ if (!existsSync5(join6(cwd2, "health.sh"))) {
613
+ write2("health.sh", HEALTH_SH, 493);
453
614
  }
454
615
  const tasks = opts.firstTask ? [{ slug: slugify(opts.firstTask.title), ...opts.firstTask }] : [];
455
- write(join4(config.storage.dir, "feature_list.json"), featureListJson(tasks));
456
- if (!existsSync4(join4(cwd2, config.storage.markdownFallback.path))) {
457
- write(
616
+ write2(join6(config.storage.dir, "feature_list.json"), featureListJson(tasks));
617
+ if (!existsSync5(join6(cwd2, config.storage.markdownFallback.path))) {
618
+ write2(
458
619
  config.storage.markdownFallback.path,
459
620
  `<!-- AUTO-GENERATED by agent-harness-kit \u2014 DO NOT EDIT MANUALLY -->
460
621
  <!-- Run ahk status to refresh -->
@@ -472,16 +633,16 @@ No tasks in progress.
472
633
  writeAgentFile(cwd2, ".opencode/agents/explorer.md", agentExplorer({ projectName, allowedPaths }));
473
634
  writeAgentFile(cwd2, ".opencode/agents/builder.md", agentBuilder({ projectName, writablePaths }));
474
635
  writeAgentFile(cwd2, ".opencode/agents/reviewer.md", agentReviewer({ projectName }));
475
- mergeOpencodeJson(join4(cwd2, "opencode.json"), config.tools.mcp.port);
636
+ mergeOpencodeJson(join6(cwd2, "opencode.json"), config.tools.mcp.port);
476
637
  appendGitignore(cwd2);
477
638
  }
478
639
  async build(config, cwd2) {
479
- const write = (relPath, content) => {
480
- const abs = join4(cwd2, relPath);
481
- mkdirSync4(resolve3(abs, ".."), { recursive: true });
482
- writeFileSync4(abs, content, "utf8");
640
+ const write2 = (relPath, content) => {
641
+ const abs = join6(cwd2, relPath);
642
+ mkdirSync6(resolve5(abs, ".."), { recursive: true });
643
+ writeFileSync6(abs, content, "utf8");
483
644
  };
484
- write("AGENTS.md", agentsMd(config));
645
+ write2("AGENTS.md", agentsMd(config));
485
646
  const projectName = config.project.name;
486
647
  const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(", ");
487
648
  const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
@@ -489,7 +650,7 @@ No tasks in progress.
489
650
  writeAgentFile(cwd2, ".opencode/agents/explorer.md", agentExplorer({ projectName, allowedPaths }));
490
651
  writeAgentFile(cwd2, ".opencode/agents/builder.md", agentBuilder({ projectName, writablePaths }));
491
652
  writeAgentFile(cwd2, ".opencode/agents/reviewer.md", agentReviewer({ projectName }));
492
- mergeOpencodeJson(join4(cwd2, "opencode.json"), config.tools.mcp.port);
653
+ mergeOpencodeJson(join6(cwd2, "opencode.json"), config.tools.mcp.port);
493
654
  }
494
655
  async migrate(config, _to, _cwd) {
495
656
  void config;
@@ -503,6 +664,8 @@ function getMaterializer(provider) {
503
664
  return new ClaudeCodeMaterializer();
504
665
  case "opencode":
505
666
  return new OpenCodeMaterializer();
667
+ case "codex-cli":
668
+ return new CodexCliMaterializer();
506
669
  default:
507
670
  throw new Error(`Unknown provider: ${provider}`);
508
671
  }
@@ -543,14 +706,14 @@ async function buildOnce(cwd2) {
543
706
  }
544
707
 
545
708
  // src/commands/dashboard.ts
546
- import { dirname as dirname4, join as join7, resolve as resolve5 } from "path";
709
+ import { dirname as dirname4, join as join9, resolve as resolve7 } from "path";
547
710
  import { fileURLToPath as fileURLToPath2 } from "url";
548
711
  import pc2 from "picocolors";
549
712
 
550
713
  // src/core/dashboard-server.ts
551
714
  import { watch as watch2 } from "fs";
552
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
553
- import { extname, join as join5 } from "path";
715
+ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
716
+ import { extname, join as join7 } from "path";
554
717
  import { serve } from "@hono/node-server";
555
718
  import { Hono } from "hono";
556
719
  import { WebSocketServer } from "ws";
@@ -628,15 +791,15 @@ function startDashboardServer(db, dbPath, staticPath, port) {
628
791
  app.get("/*", (c) => {
629
792
  const urlPath = c.req.path;
630
793
  if (urlPath !== "/") {
631
- const candidate = join5(staticPath, urlPath);
632
- if (existsSync5(candidate)) {
794
+ const candidate = join7(staticPath, urlPath);
795
+ if (existsSync6(candidate)) {
633
796
  try {
634
797
  return fileResponse(candidate);
635
798
  } catch {
636
799
  }
637
800
  }
638
801
  }
639
- return fileResponse(join5(staticPath, "index.html"));
802
+ return fileResponse(join7(staticPath, "index.html"));
640
803
  });
641
804
  const httpServer = serve({ fetch: app.fetch, port });
642
805
  const wss = new WebSocketServer({ noServer: true });
@@ -663,7 +826,7 @@ function startDashboardServer(db, dbPath, staticPath, port) {
663
826
  let watcher = null;
664
827
  if (dbPath) {
665
828
  const walPath = `${dbPath}-wal`;
666
- const watchTarget = existsSync5(walPath) ? walPath : dbPath;
829
+ const watchTarget = existsSync6(walPath) ? walPath : dbPath;
667
830
  watcher = watch2(watchTarget, broadcast);
668
831
  }
669
832
  return {
@@ -679,8 +842,8 @@ function startDashboardServer(db, dbPath, staticPath, port) {
679
842
 
680
843
  // src/core/db.ts
681
844
  import { randomUUID } from "crypto";
682
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
683
- import { dirname as dirname3, join as join6, resolve as resolve4 } from "path";
845
+ import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
846
+ import { dirname as dirname3, join as join8, resolve as resolve6 } from "path";
684
847
 
685
848
  // src/core/repositories/ActionRepository.ts
686
849
  var ActionRepository = class {
@@ -1081,8 +1244,8 @@ var HarnessDB = class {
1081
1244
  // ─── current.md fallback ──────────────────────────────────────────────────
1082
1245
  async regenerateCurrentMd() {
1083
1246
  if (!this.config.storage.markdownFallback.enabled) return;
1084
- const mdPath = resolve4(this.config.storage.markdownFallback.path);
1085
- mkdirSync5(dirname3(mdPath), { recursive: true });
1247
+ const mdPath = resolve6(this.config.storage.markdownFallback.path);
1248
+ mkdirSync7(dirname3(mdPath), { recursive: true });
1086
1249
  const inProgress = await this.tasks.getAll("in_progress");
1087
1250
  const now = (/* @__PURE__ */ new Date()).toISOString();
1088
1251
  let md = `<!-- AUTO-GENERATED by agent-harness-kit \u2014 DO NOT EDIT MANUALLY -->
@@ -1149,7 +1312,7 @@ var HarnessDB = class {
1149
1312
  }
1150
1313
  }
1151
1314
  }
1152
- writeFileSync5(mdPath, md, "utf8");
1315
+ writeFileSync7(mdPath, md, "utf8");
1153
1316
  }
1154
1317
  // ─── Raw query escape hatch ───────────────────────────────────────────────
1155
1318
  async queryRaw(sql, ...params) {
@@ -1191,9 +1354,9 @@ var HarnessDB = class {
1191
1354
  status: t.status
1192
1355
  }))
1193
1356
  );
1194
- const path = join6(resolve4(cwd2), this.config.storage.dir, "feature_list.json");
1195
- mkdirSync5(dirname3(path), { recursive: true });
1196
- writeFileSync5(path, JSON.stringify(list, null, 2) + "\n", "utf8");
1357
+ const path = join8(resolve6(cwd2), this.config.storage.dir, "feature_list.json");
1358
+ mkdirSync7(dirname3(path), { recursive: true });
1359
+ writeFileSync7(path, JSON.stringify(list, null, 2) + "\n", "utf8");
1197
1360
  }
1198
1361
  };
1199
1362
  async function openDB(config, cwd2) {
@@ -1210,7 +1373,7 @@ async function openDB(config, cwd2) {
1210
1373
  if (dbConfig.type !== "sqlite") {
1211
1374
  throw new Error("Invalid database type");
1212
1375
  }
1213
- driver = new SQLiteDriver(resolve4(cwd2, dbConfig.path));
1376
+ driver = new SQLiteDriver(resolve6(cwd2, dbConfig.path));
1214
1377
  }
1215
1378
  await driver.ensureSchema();
1216
1379
  return new HarnessDB(driver, config);
@@ -1221,8 +1384,8 @@ var __dirname2 = dirname4(fileURLToPath2(import.meta.url));
1221
1384
  async function runDashboard(cwd2, opts) {
1222
1385
  const config = await loadConfig(cwd2);
1223
1386
  const db = await openDB(config, cwd2);
1224
- const dbPath = config.database.type === "sqlite" ? resolve5(cwd2, config.database.path) : null;
1225
- const staticPath = join7(__dirname2, "dashboard-dist");
1387
+ const dbPath = config.database.type === "sqlite" ? resolve7(cwd2, config.database.path) : null;
1388
+ const staticPath = join9(__dirname2, "dashboard-dist");
1226
1389
  const { url } = startDashboardServer(db, dbPath, staticPath, opts.port);
1227
1390
  console.log(pc2.green(`\u2713`) + ` Dashboard running at ${pc2.bold(pc2.cyan(url))}`);
1228
1391
  console.log(pc2.dim(` WebSocket live updates enabled`));
@@ -1239,7 +1402,7 @@ async function runDashboard(cwd2, opts) {
1239
1402
  }
1240
1403
 
1241
1404
  // src/commands/export.ts
1242
- import { writeFileSync as writeFileSync6 } from "fs";
1405
+ import { writeFileSync as writeFileSync8 } from "fs";
1243
1406
  import pc3 from "picocolors";
1244
1407
  async function runExport(cwd2, opts) {
1245
1408
  if (!opts.sql && !opts.json) {
@@ -1253,7 +1416,7 @@ async function runExport(cwd2, opts) {
1253
1416
  const data = await db.exportJson();
1254
1417
  const out = JSON.stringify(data, null, 2) + "\n";
1255
1418
  if (opts.output) {
1256
- writeFileSync6(opts.output, out, "utf8");
1419
+ writeFileSync8(opts.output, out, "utf8");
1257
1420
  console.log(pc3.green(`\u2713 Exported JSON \u2192 ${opts.output}`));
1258
1421
  } else {
1259
1422
  process.stdout.write(out);
@@ -1270,8 +1433,8 @@ async function runExport(cwd2, opts) {
1270
1433
 
1271
1434
  // src/commands/health.ts
1272
1435
  import { spawnSync } from "child_process";
1273
- import { existsSync as existsSync6 } from "fs";
1274
- import { join as join8, resolve as resolve6 } from "path";
1436
+ import { existsSync as existsSync7 } from "fs";
1437
+ import { join as join10, resolve as resolve8 } from "path";
1275
1438
  import pc4 from "picocolors";
1276
1439
  function checkLine(label, ok2, message, indent = 0) {
1277
1440
  const prefix = label ? pc4.cyan(`[${label}] `) : " ".repeat(indent);
@@ -1289,8 +1452,8 @@ async function runHealth(cwd2) {
1289
1452
  let allOk = true;
1290
1453
  let dbOk;
1291
1454
  if (config.database.type === "sqlite") {
1292
- const dbPath = resolve6(cwd2, config.database.path);
1293
- dbOk = existsSync6(dbPath);
1455
+ const dbPath = resolve8(cwd2, config.database.path);
1456
+ dbOk = existsSync7(dbPath);
1294
1457
  checkLine("checking DB", dbOk, `${config.database.path} reachable`);
1295
1458
  } else {
1296
1459
  dbOk = true;
@@ -1302,15 +1465,15 @@ async function runHealth(cwd2) {
1302
1465
  const agentsLabelWidth = "[checking agents] ".length;
1303
1466
  for (let i = 0; i < agentNames.length; i++) {
1304
1467
  const name = agentNames[i];
1305
- const agentPath = join8(cwd2, agentsDir, `${name}.md`);
1306
- const ok2 = existsSync6(agentPath);
1468
+ const agentPath = join10(cwd2, agentsDir, `${name}.md`);
1469
+ const ok2 = existsSync7(agentPath);
1307
1470
  checkLine(i === 0 ? "checking agents" : null, ok2, `${name}.md present`, agentsLabelWidth);
1308
1471
  if (!ok2) allOk = false;
1309
1472
  }
1310
1473
  if (config.tools.mcp.enabled) {
1311
1474
  const mcpFile = config.provider === "claude-code" ? ".claude/mcp.json" : "opencode.json";
1312
- const mcpPath = resolve6(cwd2, mcpFile);
1313
- const mcpOk = existsSync6(mcpPath);
1475
+ const mcpPath = resolve8(cwd2, mcpFile);
1476
+ const mcpOk = existsSync7(mcpPath);
1314
1477
  checkLine("checking MCP", mcpOk, `${mcpFile} valid`);
1315
1478
  if (!mcpOk) allOk = false;
1316
1479
  }
@@ -1319,8 +1482,8 @@ async function runHealth(cwd2) {
1319
1482
  console.error(pc4.red("\u2717 Harness checks failed \u2014 fix the above before running health.sh"));
1320
1483
  process.exit(1);
1321
1484
  }
1322
- const scriptPath = resolve6(cwd2, config.health.scriptPath);
1323
- if (!existsSync6(scriptPath)) {
1485
+ const scriptPath = resolve8(cwd2, config.health.scriptPath);
1486
+ if (!existsSync7(scriptPath)) {
1324
1487
  console.error(pc4.red(`\u2717 health.sh not found: ${scriptPath}`));
1325
1488
  console.error(" Run ahk init first.");
1326
1489
  process.exit(1);
@@ -1344,9 +1507,9 @@ async function runHealth(cwd2) {
1344
1507
  }
1345
1508
 
1346
1509
  // src/commands/init.ts
1347
- import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
1510
+ import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync9 } from "fs";
1348
1511
  import { homedir } from "os";
1349
- import { join as join10 } from "path";
1512
+ import { join as join12 } from "path";
1350
1513
  import * as p3 from "@clack/prompts";
1351
1514
  import pc6 from "picocolors";
1352
1515
 
@@ -1401,13 +1564,13 @@ var cliFormWithRetry = async (formFn, schema) => {
1401
1564
  };
1402
1565
 
1403
1566
  // src/commands/init-helpers.ts
1404
- import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
1405
- import { join as join9 } from "path";
1567
+ import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
1568
+ import { join as join11 } from "path";
1406
1569
  import pc5 from "picocolors";
1407
1570
  function readProjectNameFromPackageJson(cwd2) {
1408
1571
  try {
1409
- const pkgPath2 = join9(cwd2, "package.json");
1410
- if (!existsSync7(pkgPath2)) return null;
1572
+ const pkgPath2 = join11(cwd2, "package.json");
1573
+ if (!existsSync8(pkgPath2)) return null;
1411
1574
  const content = readFileSync5(pkgPath2, "utf8");
1412
1575
  const pkg2 = JSON.parse(content);
1413
1576
  const name = pkg2?.name;
@@ -1498,36 +1661,30 @@ async function runInit(cwd2, flags) {
1498
1661
  if (flags.name) {
1499
1662
  name = flags.name;
1500
1663
  } else {
1501
- name = await cliFormWithRetry(
1502
- async () => {
1503
- const val = await p3.text({
1504
- message: "Project name",
1505
- placeholder: "my-app",
1506
- ...detectedName && { initialValue: detectedName }
1507
- });
1508
- if (p3.isCancel(val)) {
1509
- p3.cancel("Cancelled.");
1510
- process.exit(0);
1511
- }
1512
- return val;
1513
- },
1514
- initNameSchema
1515
- );
1516
- }
1517
- const description = await cliFormWithRetry(
1518
- async () => {
1664
+ name = await cliFormWithRetry(async () => {
1519
1665
  const val = await p3.text({
1520
- message: "Short description (shown to agents as context)",
1521
- placeholder: "A REST API for managing notes"
1666
+ message: "Project name",
1667
+ placeholder: "my-app",
1668
+ ...detectedName && { initialValue: detectedName }
1522
1669
  });
1523
1670
  if (p3.isCancel(val)) {
1524
1671
  p3.cancel("Cancelled.");
1525
1672
  process.exit(0);
1526
1673
  }
1527
1674
  return val;
1528
- },
1529
- initDescriptionSchema
1530
- );
1675
+ }, initNameSchema);
1676
+ }
1677
+ const description = await cliFormWithRetry(async () => {
1678
+ const val = await p3.text({
1679
+ message: "Short description (shown to agents as context)",
1680
+ placeholder: "A REST API for managing notes"
1681
+ });
1682
+ if (p3.isCancel(val)) {
1683
+ p3.cancel("Cancelled.");
1684
+ process.exit(0);
1685
+ }
1686
+ return val;
1687
+ }, initDescriptionSchema);
1531
1688
  let provider;
1532
1689
  if (flags.provider && ["claude-code", "opencode"].includes(flags.provider)) {
1533
1690
  provider = flags.provider;
@@ -1535,8 +1692,9 @@ async function runInit(cwd2, flags) {
1535
1692
  const val = await p3.select({
1536
1693
  message: "AI provider",
1537
1694
  options: [
1695
+ { value: "opencode", label: "OpenCode" },
1538
1696
  { value: "claude-code", label: "Claude Code" },
1539
- { value: "opencode", label: "OpenCode" }
1697
+ { value: "codex-cli", label: "Codex CLI" }
1540
1698
  ]
1541
1699
  });
1542
1700
  if (p3.isCancel(val)) {
@@ -1561,20 +1719,17 @@ async function runInit(cwd2, flags) {
1561
1719
  if (flags.docs) {
1562
1720
  docsPath = flags.docs;
1563
1721
  } else {
1564
- docsPath = await cliFormWithRetry(
1565
- async () => {
1566
- const val = await p3.text({
1567
- message: "Docs folder path (agents will search here)",
1568
- initialValue: "./docs"
1569
- });
1570
- if (p3.isCancel(val)) {
1571
- p3.cancel("Cancelled.");
1572
- process.exit(0);
1573
- }
1574
- return val;
1575
- },
1576
- initDocsSchema
1577
- );
1722
+ docsPath = await cliFormWithRetry(async () => {
1723
+ const val = await p3.text({
1724
+ message: "Docs folder path (agents will search here)",
1725
+ initialValue: "./docs"
1726
+ });
1727
+ if (p3.isCancel(val)) {
1728
+ p3.cancel("Cancelled.");
1729
+ process.exit(0);
1730
+ }
1731
+ return val;
1732
+ }, initDocsSchema);
1578
1733
  }
1579
1734
  let tasksAdapter;
1580
1735
  if (flags.tasks && ["local", "jira", "linear"].includes(flags.tasks)) {
@@ -1594,35 +1749,29 @@ async function runInit(cwd2, flags) {
1594
1749
  }
1595
1750
  tasksAdapter = val;
1596
1751
  }
1597
- const addFirstTask = await p3.confirm({ message: "Add your first task now?", initialValue: true });
1752
+ const addFirstTask = await p3.confirm({ message: "Add your first task now?", initialValue: false });
1598
1753
  if (p3.isCancel(addFirstTask)) {
1599
1754
  p3.cancel("Cancelled");
1600
1755
  process.exit(0);
1601
1756
  }
1602
1757
  let firstTask;
1603
1758
  if (addFirstTask) {
1604
- const taskTitle = await cliFormWithRetry(
1605
- async () => {
1606
- const val = await p3.text({ message: "Task title" });
1607
- if (p3.isCancel(val)) {
1608
- p3.cancel("Cancelled");
1609
- process.exit(0);
1610
- }
1611
- return val.trim();
1612
- },
1613
- taskTitleSchema
1614
- );
1615
- const taskDesc = await cliFormWithRetry(
1616
- async () => {
1617
- const val = await p3.text({ message: "Task description", placeholder: "What and why" });
1618
- if (p3.isCancel(val)) {
1619
- p3.cancel("Cancelled");
1620
- process.exit(0);
1621
- }
1622
- return val.trim();
1623
- },
1624
- taskDescriptionSchema
1625
- );
1759
+ const taskTitle = await cliFormWithRetry(async () => {
1760
+ const val = await p3.text({ message: "Task title" });
1761
+ if (p3.isCancel(val)) {
1762
+ p3.cancel("Cancelled");
1763
+ process.exit(0);
1764
+ }
1765
+ return val.trim();
1766
+ }, taskTitleSchema);
1767
+ const taskDesc = await cliFormWithRetry(async () => {
1768
+ const val = await p3.text({ message: "Task description", placeholder: "What and why" });
1769
+ if (p3.isCancel(val)) {
1770
+ p3.cancel("Cancelled");
1771
+ process.exit(0);
1772
+ }
1773
+ return val.trim();
1774
+ }, taskDescriptionSchema);
1626
1775
  const acceptance = [];
1627
1776
  p3.log.info("Acceptance criteria \u2014 one per line, empty line to finish");
1628
1777
  while (true) {
@@ -1643,9 +1792,9 @@ async function runInit(cwd2, flags) {
1643
1792
  let installDir = cwd2;
1644
1793
  if (globalInstallation) {
1645
1794
  if (provider === "claude-code") {
1646
- installDir = join10(homedir(), ".claude");
1795
+ installDir = join12(homedir(), ".claude");
1647
1796
  } else {
1648
- installDir = join10(homedir(), ".config", "opencode");
1797
+ installDir = join12(homedir(), ".config", "opencode");
1649
1798
  }
1650
1799
  }
1651
1800
  const configContent = configTs({
@@ -1656,8 +1805,8 @@ async function runInit(cwd2, flags) {
1656
1805
  tasksAdapter,
1657
1806
  port: config.tools.mcp.port
1658
1807
  });
1659
- writeFileSync7(join10(installDir, "agent-harness-kit.config.ts"), configContent, "utf8");
1660
- mkdirSync6(join10(installDir, config.storage.dir), { recursive: true });
1808
+ writeFileSync9(join12(installDir, "agent-harness-kit.config.ts"), configContent, "utf8");
1809
+ mkdirSync8(join12(installDir, config.storage.dir), { recursive: true });
1661
1810
  const db = await openDB(config, installDir);
1662
1811
  await materializer.scaffold(config, { cwd: installDir, firstTask });
1663
1812
  if (firstTask) {
@@ -1695,7 +1844,9 @@ async function runInit(cwd2, flags) {
1695
1844
  console.log("");
1696
1845
  console.log(pc6.cyan("\u2192") + ` Edit ${pc6.cyan("health.sh")} with your project checks`);
1697
1846
  console.log(pc6.cyan("\u2192") + ` ${pc6.cyan("ahk task add")} to queue work for agents`);
1698
- console.log(pc6.cyan("\u2192") + ` Enrich your docs with knowledge graphs: ${pc6.cyan("https://github.com/safishamsi/graphify")}`);
1847
+ console.log(
1848
+ pc6.cyan("\u2192") + ` Enrich your docs with knowledge graphs: ${pc6.cyan("https://github.com/safishamsi/graphify")}`
1849
+ );
1699
1850
  const recommendations = [
1700
1851
  ` Give a try to Heimdall MCP: Transparent proxy that traces every MCP tool call with OpenTelemetry. `,
1701
1852
  ` Learn more: ${pc6.cyan("https://github.com/enmanuelmag/heimdall-mcp")} `
@@ -1746,15 +1897,15 @@ async function runMigrate(cwd2, opts) {
1746
1897
  }
1747
1898
 
1748
1899
  // src/commands/reset.ts
1749
- import { existsSync as existsSync8, readdirSync, rmSync } from "fs";
1750
- import { join as join11, resolve as resolve7 } from "path";
1900
+ import { existsSync as existsSync9, readdirSync, rmSync } from "fs";
1901
+ import { join as join13, resolve as resolve9 } from "path";
1751
1902
  import * as p5 from "@clack/prompts";
1752
1903
  import pc8 from "picocolors";
1753
1904
  var AGENT_MD_FILES = ["lead", "explorer", "builder", "reviewer"];
1754
1905
  async function resetAgentMds(cwd2, provider) {
1755
1906
  const agentDir = provider === "claude-code" ? ".claude/agents" : ".opencode/agents";
1756
- const agentDirPath = resolve7(cwd2, agentDir);
1757
- if (!existsSync8(agentDirPath)) {
1907
+ const agentDirPath = resolve9(cwd2, agentDir);
1908
+ if (!existsSync9(agentDirPath)) {
1758
1909
  console.log(pc8.yellow(` Skipping agent files \u2014 directory not found: ${agentDirPath}`));
1759
1910
  return;
1760
1911
  }
@@ -1785,7 +1936,7 @@ async function resetAgentMds(cwd2, provider) {
1785
1936
  }
1786
1937
  if (confirm3) {
1787
1938
  try {
1788
- const filePath = join11(agentDirPath, file);
1939
+ const filePath = join13(agentDirPath, file);
1789
1940
  rmSync(filePath, { force: true });
1790
1941
  console.log(pc8.green(` Removed ${file}`));
1791
1942
  } catch {
@@ -1805,12 +1956,12 @@ async function runReset(cwd2, opts) {
1805
1956
  process.exit(1);
1806
1957
  }
1807
1958
  const storageDir = config.storage.dir || ".harness";
1808
- const dbPath = config.database.type === "sqlite" ? resolve7(cwd2, config.database.path) : null;
1809
- const featureListPath = resolve7(cwd2, storageDir, "feature_list.json");
1959
+ const dbPath = config.database.type === "sqlite" ? resolve9(cwd2, config.database.path) : null;
1960
+ const featureListPath = resolve9(cwd2, storageDir, "feature_list.json");
1810
1961
  let resetDb = false;
1811
1962
  let resetFeatureList = false;
1812
1963
  let resetAgentMdsFlag = false;
1813
- if (dbPath && existsSync8(dbPath)) {
1964
+ if (dbPath && existsSync9(dbPath)) {
1814
1965
  if (opts.force) {
1815
1966
  resetDb = true;
1816
1967
  } else {
@@ -1832,7 +1983,7 @@ async function runReset(cwd2, opts) {
1832
1983
  } else if (!dbPath) {
1833
1984
  console.log(pc8.dim(` Skipping DB reset \u2014 remote ${config.database.type} database is not managed by this command.`));
1834
1985
  }
1835
- if (existsSync8(featureListPath)) {
1986
+ if (existsSync9(featureListPath)) {
1836
1987
  if (opts.force) {
1837
1988
  resetFeatureList = true;
1838
1989
  } else {
@@ -1882,7 +2033,7 @@ async function runReset(cwd2, opts) {
1882
2033
 
1883
2034
  // src/core/mcp-server.ts
1884
2035
  import { readdirSync as readdirSync2, readFileSync as readFileSync6, statSync } from "fs";
1885
- import { join as join12, resolve as resolve8 } from "path";
2036
+ import { join as join14, resolve as resolve10 } from "path";
1886
2037
  import { Server } from "@modelcontextprotocol/sdk/server";
1887
2038
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
1888
2039
  import {
@@ -2061,7 +2212,7 @@ var TOOLS = [
2061
2212
  ];
2062
2213
  async function startMcpServer(config, cwd2) {
2063
2214
  const db = await openDB(config, cwd2);
2064
- const docsPath = resolve8(cwd2, config.project.docsPath);
2215
+ const docsPath = resolve10(cwd2, config.project.docsPath);
2065
2216
  const server = new Server(
2066
2217
  { name: "agent-harness-kit", version: VERSION },
2067
2218
  { capabilities: { tools: {} } }
@@ -2202,7 +2353,7 @@ function collectMarkdownFiles(dir) {
2202
2353
  const files = [];
2203
2354
  try {
2204
2355
  for (const entry of readdirSync2(dir)) {
2205
- const full = join12(dir, entry);
2356
+ const full = join14(dir, entry);
2206
2357
  const stat = statSync(full);
2207
2358
  if (stat.isDirectory()) {
2208
2359
  files.push(...collectMarkdownFiles(full));
@@ -2309,13 +2460,13 @@ async function runStatus(cwd2, opts) {
2309
2460
  }
2310
2461
 
2311
2462
  // src/commands/sync.ts
2312
- import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
2313
- import { join as join13, resolve as resolve9 } from "path";
2463
+ import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
2464
+ import { join as join15, resolve as resolve11 } from "path";
2314
2465
  import pc10 from "picocolors";
2315
2466
  async function runSync(cwd2, opts) {
2316
2467
  const config = await loadConfig(cwd2);
2317
2468
  const direction = opts.direction ?? "both";
2318
- const featureListPath = resolve9(join13(cwd2, config.storage.dir, "feature_list.json"));
2469
+ const featureListPath = resolve11(join15(cwd2, config.storage.dir, "feature_list.json"));
2319
2470
  const db = await openDB(config, cwd2);
2320
2471
  try {
2321
2472
  if (direction === "in" || direction === "both") {
@@ -2329,7 +2480,7 @@ async function runSync(cwd2, opts) {
2329
2480
  }
2330
2481
  }
2331
2482
  async function syncIn(featureListPath, db, dryRun) {
2332
- if (!existsSync9(featureListPath)) {
2483
+ if (!existsSync10(featureListPath)) {
2333
2484
  console.log(pc10.dim(`feature_list.json not found at ${featureListPath} \u2014 skipping in-sync`));
2334
2485
  return;
2335
2486
  }
@@ -2420,14 +2571,14 @@ async function runTaskAdd(cwd2) {
2420
2571
 
2421
2572
  // src/commands/task/done.ts
2422
2573
  import { spawnSync as spawnSync2 } from "child_process";
2423
- import { existsSync as existsSync10 } from "fs";
2424
- import { resolve as resolve10 } from "path";
2574
+ import { existsSync as existsSync11 } from "fs";
2575
+ import { resolve as resolve12 } from "path";
2425
2576
  import pc12 from "picocolors";
2426
2577
  async function runTaskDone(cwd2, idOrSlug) {
2427
2578
  const config = await loadConfig(cwd2);
2428
2579
  if (config.health.required) {
2429
- const scriptPath = resolve10(cwd2, config.health.scriptPath);
2430
- if (existsSync10(scriptPath)) {
2580
+ const scriptPath = resolve12(cwd2, config.health.scriptPath);
2581
+ if (existsSync11(scriptPath)) {
2431
2582
  const result = spawnSync2("bash", [scriptPath], { cwd: cwd2, stdio: "pipe", encoding: "utf8" });
2432
2583
  if (result.status !== 0) {
2433
2584
  console.error(pc12.red("\u2717 Health check failed \u2014 cannot mark task as done."));
@@ -2498,10 +2649,10 @@ async function runTaskList(cwd2, opts) {
2498
2649
 
2499
2650
  // src/core/package-data.ts
2500
2651
  import { createRequire } from "module";
2501
- import { dirname as dirname5, join as join14 } from "path";
2652
+ import { dirname as dirname5, join as join16 } from "path";
2502
2653
  import { fileURLToPath as fileURLToPath3 } from "url";
2503
2654
  var require2 = createRequire(import.meta.url);
2504
- var pkgPath = join14(dirname5(fileURLToPath3(import.meta.url)), "..", "package.json");
2655
+ var pkgPath = join16(dirname5(fileURLToPath3(import.meta.url)), "..", "package.json");
2505
2656
  var pkg = require2(pkgPath);
2506
2657
 
2507
2658
  // src/core/update-check.ts
@@ -2509,15 +2660,15 @@ import pc14 from "picocolors";
2509
2660
  var REGISTRY_URL = `https://registry.npmjs.org/${pkg.name}/latest`;
2510
2661
  var TIMEOUT_MS = 2500;
2511
2662
  function checkForUpdate(currentVersion) {
2512
- return new Promise((resolve11) => {
2513
- const timer = setTimeout(() => resolve11(null), TIMEOUT_MS);
2663
+ return new Promise((resolve13) => {
2664
+ const timer = setTimeout(() => resolve13(null), TIMEOUT_MS);
2514
2665
  fetch(REGISTRY_URL).then((res) => res.json()).then((data) => {
2515
2666
  clearTimeout(timer);
2516
2667
  const latest = data.version;
2517
- resolve11(isNewer(latest, currentVersion) ? { current: currentVersion, latest } : null);
2668
+ resolve13(isNewer(latest, currentVersion) ? { current: currentVersion, latest } : null);
2518
2669
  }).catch(() => {
2519
2670
  clearTimeout(timer);
2520
- resolve11(null);
2671
+ resolve13(null);
2521
2672
  });
2522
2673
  });
2523
2674
  }