@cardor/agent-harness-kit 1.6.5 → 1.6.7

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
@@ -107,7 +107,7 @@ Everything is stored locally in a SQLite database (`.harness/harness.db`). No cl
107
107
  ## Features
108
108
 
109
109
  - **Provider-agnostic** — works with Claude Code, OpenCode, Codex CLI, or any MCP-compatible AI tool. Switch providers without losing your task history or reconfiguring your workflow.
110
- - **Structured 4-agent workflow** — Lead, Explorer, Builder, and Reviewer each have defined responsibilities and can only act within their role.
110
+ - **Structured 5-agent workflow** — Lead, Explorer, Consultant, Builder, and Reviewer each have defined responsibilities and can only act within their role.
111
111
  - **Atomic task claiming** — agents use `tasks.claim()` which uses a SQLite transaction to prevent two agents from picking up the same task at the same time.
112
112
  - **Full audit trail** — every action, file touched, tool used, and section written is stored in SQLite and queryable.
113
113
  - **Health gate** — agents must run `health.sh` and get a green exit before starting or closing any task. You define what "healthy" means.
package/dist/cli.js CHANGED
@@ -334,7 +334,7 @@ docs.search query \u2192 search ${docs
334
334
  - tasks.get('in_progress') \u2192 resume if something is in progress
335
335
  - tasks.get('pending') \u2192 pick lowest id
336
336
 
337
- 2. WORK (lead \u2192 explorer \u2192 builder \u2192 reviewer)
337
+ 2. WORK (lead \u2192 explorer \u2192 consultant \u2192 builder \u2192 reviewer)
338
338
  - Each agent calls actions.start(taskId, agentName) \u2192 actionId
339
339
  - After EVERY tool call: actions.record_tool(actionId, toolName, args, summary)
340
340
  - After EVERY file change: actions.record_file(actionId, filePath, operation, notes)
@@ -351,6 +351,7 @@ docs.search query \u2192 search ${docs
351
351
  |-------|---------------|
352
352
  | lead | Decomposes the task into a plan, assigns sub-agents |
353
353
  | explorer | Reads and maps relevant code, never writes |
354
+ | consultant | Technical advisor, runs after explorer, before builder. Never writes code. |
354
355
  | builder | Implements the plan, writes files |
355
356
  | reviewer | Verifies acceptance criteria, approves or blocks |
356
357
 
@@ -418,7 +419,7 @@ docs.search query \u2192 search ${docs
418
419
  - tasks.get('pending') \u2192 pick lowest id
419
420
  - No pending tasks? \u2192 ask user, infer fields, call tasks.add, then tasks.claim
420
421
 
421
- 2. WORK (lead \u2192 explorer \u2192 builder \u2192 reviewer)
422
+ 2. WORK (lead \u2192 explorer \u2192 consultant \u2192 builder \u2192 reviewer)
422
423
  - Each agent calls actions.start(taskId, agentName) \u2192 actionId
423
424
  - After EVERY tool call: actions.record_tool(actionId, toolName, args, summary)
424
425
  - After EVERY file change: actions.record_file(actionId, filePath, operation, notes)
@@ -435,6 +436,7 @@ docs.search query \u2192 search ${docs
435
436
  |-------|---------------|
436
437
  | lead | Decomposes the task into a plan, assigns sub-agents |
437
438
  | explorer | Reads and maps relevant code, never writes |
439
+ | consultant | Technical advisor, runs after explorer, before builder. Never writes code. |
438
440
  | builder | Implements the plan, writes files |
439
441
  | reviewer | Verifies acceptance criteria, approves or blocks |
440
442
 
@@ -564,6 +566,10 @@ function agentReviewerToml(vars) {
564
566
  const { description, body } = stripFrontmatter(loadAgentTemplate("reviewer", vars));
565
567
  return toCodexToml("reviewer", description, body, "read-only");
566
568
  }
569
+ function agentConsultantToml(vars) {
570
+ const { description, body } = stripFrontmatter(loadAgentTemplate("consultant", vars));
571
+ return toCodexToml("consultant", description, body, "read-only");
572
+ }
567
573
  function translateFrontmatterForClaudeCode(md, agentName) {
568
574
  const permissionsMap = {
569
575
  lead: [...MCP_CLAUDE_PERMISSIONS_LEAD],
@@ -629,10 +635,15 @@ async function syncAgentPermissions(cwd2) {
629
635
  continue;
630
636
  }
631
637
  const content = readFileSync3(filePath, "utf-8");
632
- const toolsBlock = `tools:
633
- ${tools.map((t) => ` - ${t}`).join("\n")}
634
- `;
635
- const updated = content.replace(/tools:\n(?: - [^\n]+\n)*/m, toolsBlock);
638
+ const updated = content.replace(
639
+ /(tools:\n)((?: - [^\n]+\n)*)/m,
640
+ (_match, header, toolsSection) => {
641
+ const nativeLines = toolsSection.split("\n").filter((line) => line.trim() && !line.includes("mcp__"));
642
+ const nativeSection = nativeLines.length ? nativeLines.join("\n") + "\n" : "";
643
+ const mcpSection = tools.map((t) => ` - ${t}`).join("\n") + "\n";
644
+ return header + nativeSection + mcpSection;
645
+ }
646
+ );
636
647
  if (updated === content) {
637
648
  console.log(` ${agent}.md already in sync`);
638
649
  } else {
@@ -738,6 +749,7 @@ No tasks in progress.
738
749
  const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
739
750
  writeAgentFile(cwd2, ".codex/agents/lead.toml", agentLeadToml({ projectName }));
740
751
  writeAgentFile(cwd2, ".codex/agents/explorer.toml", agentExplorerToml({ projectName, allowedPaths }));
752
+ writeAgentFile(cwd2, ".codex/agents/consultant.toml", agentConsultantToml({ projectName }));
741
753
  writeAgentFile(cwd2, ".codex/agents/builder.toml", agentBuilderToml({ projectName, writablePaths }));
742
754
  writeAgentFile(cwd2, ".codex/agents/reviewer.toml", agentReviewerToml({ projectName }));
743
755
  writeAgentFile(cwd2, ".codex/agents/default.toml", agentLeadAsDefaultToml({ projectName }));
@@ -756,6 +768,7 @@ No tasks in progress.
756
768
  const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
757
769
  writeAgentFile(cwd2, ".codex/agents/lead.toml", agentLeadToml({ projectName }));
758
770
  writeAgentFile(cwd2, ".codex/agents/explorer.toml", agentExplorerToml({ projectName, allowedPaths }));
771
+ writeAgentFile(cwd2, ".codex/agents/consultant.toml", agentConsultantToml({ projectName }));
759
772
  writeAgentFile(cwd2, ".codex/agents/builder.toml", agentBuilderToml({ projectName, writablePaths }));
760
773
  writeAgentFile(cwd2, ".codex/agents/reviewer.toml", agentReviewerToml({ projectName }));
761
774
  writeAgentFile(cwd2, ".codex/agents/default.toml", agentLeadAsDefaultToml({ projectName }));
@@ -800,6 +813,7 @@ No tasks in progress.
800
813
  const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
801
814
  writeAgentFile(cwd2, ".opencode/agents/lead.md", translateFrontmatterForOpenCode(agentLead({ projectName })));
802
815
  writeAgentFile(cwd2, ".opencode/agents/explorer.md", translateFrontmatterForOpenCode(agentExplorer({ projectName, allowedPaths })));
816
+ writeAgentFile(cwd2, ".opencode/agents/consultant.md", translateFrontmatterForOpenCode(agentConsultant({ projectName })));
803
817
  writeAgentFile(cwd2, ".opencode/agents/builder.md", translateFrontmatterForOpenCode(agentBuilder({ projectName, writablePaths })));
804
818
  writeAgentFile(cwd2, ".opencode/agents/reviewer.md", translateFrontmatterForOpenCode(agentReviewer({ projectName })));
805
819
  mergeOpencodeJson(join6(cwd2, "opencode.json"), config.tools.mcp.port);
@@ -817,6 +831,7 @@ No tasks in progress.
817
831
  const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
818
832
  writeAgentFile(cwd2, ".opencode/agents/lead.md", translateFrontmatterForOpenCode(agentLead({ projectName })));
819
833
  writeAgentFile(cwd2, ".opencode/agents/explorer.md", translateFrontmatterForOpenCode(agentExplorer({ projectName, allowedPaths })));
834
+ writeAgentFile(cwd2, ".opencode/agents/consultant.md", translateFrontmatterForOpenCode(agentConsultant({ projectName })));
820
835
  writeAgentFile(cwd2, ".opencode/agents/builder.md", translateFrontmatterForOpenCode(agentBuilder({ projectName, writablePaths })));
821
836
  writeAgentFile(cwd2, ".opencode/agents/reviewer.md", translateFrontmatterForOpenCode(agentReviewer({ projectName })));
822
837
  mergeOpencodeJson(join6(cwd2, "opencode.json"), config.tools.mcp.port);
@@ -1792,7 +1807,7 @@ async function runHealth(cwd2) {
1792
1807
  if (!dbOk) allOk = false;
1793
1808
  const providerFiles = getProviderHealthFiles(config.provider);
1794
1809
  const agentsDir = providerFiles.agentsDir;
1795
- const agentNames = ["lead", "explorer", "builder", "reviewer"];
1810
+ const agentNames = ["lead", "explorer", "consultant", "builder", "reviewer"];
1796
1811
  const agentsLabelWidth = "[checking agents] ".length;
1797
1812
  for (let i = 0; i < agentNames.length; i++) {
1798
1813
  const name = agentNames[i];
@@ -2250,7 +2265,7 @@ import { existsSync as existsSync9, readdirSync, rmSync } from "fs";
2250
2265
  import { join as join13, resolve as resolve9 } from "path";
2251
2266
  import * as p5 from "@clack/prompts";
2252
2267
  import pc8 from "picocolors";
2253
- var AGENT_MD_FILES = ["lead", "explorer", "builder", "reviewer"];
2268
+ var AGENT_MD_FILES = ["lead", "explorer", "consultant", "builder", "reviewer"];
2254
2269
  async function resetAgentMds(cwd2, provider) {
2255
2270
  const agentDir = provider === "claude-code" ? ".claude/agents" : ".opencode/agents";
2256
2271
  const agentDirPath = resolve9(cwd2, agentDir);