@cardor/agent-harness-kit 1.6.4 → 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 +1 -1
- package/dist/cli.js +37 -16
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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
|
|
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],
|
|
@@ -582,6 +588,12 @@ ${mcpLines}
|
|
|
582
588
|
`;
|
|
583
589
|
});
|
|
584
590
|
}
|
|
591
|
+
function translateFrontmatterForOpenCode(md) {
|
|
592
|
+
return md.replace(/(tools:\n(?: - [^\n]+\n)+)/, (match) => {
|
|
593
|
+
const tools = [...match.matchAll(/ - ([^\n]+)/g)].map((m) => m[1].trim());
|
|
594
|
+
return "tools:\n" + tools.map((t) => ` ${t.toLocaleLowerCase()}: true`).join("\n") + "\n";
|
|
595
|
+
});
|
|
596
|
+
}
|
|
585
597
|
var GITIGNORE_ENTRIES = `
|
|
586
598
|
# agent-harness-kit
|
|
587
599
|
.harness/harness.db
|
|
@@ -623,10 +635,15 @@ async function syncAgentPermissions(cwd2) {
|
|
|
623
635
|
continue;
|
|
624
636
|
}
|
|
625
637
|
const content = readFileSync3(filePath, "utf-8");
|
|
626
|
-
const
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
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
|
+
);
|
|
630
647
|
if (updated === content) {
|
|
631
648
|
console.log(` ${agent}.md already in sync`);
|
|
632
649
|
} else {
|
|
@@ -732,6 +749,7 @@ No tasks in progress.
|
|
|
732
749
|
const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
|
|
733
750
|
writeAgentFile(cwd2, ".codex/agents/lead.toml", agentLeadToml({ projectName }));
|
|
734
751
|
writeAgentFile(cwd2, ".codex/agents/explorer.toml", agentExplorerToml({ projectName, allowedPaths }));
|
|
752
|
+
writeAgentFile(cwd2, ".codex/agents/consultant.toml", agentConsultantToml({ projectName }));
|
|
735
753
|
writeAgentFile(cwd2, ".codex/agents/builder.toml", agentBuilderToml({ projectName, writablePaths }));
|
|
736
754
|
writeAgentFile(cwd2, ".codex/agents/reviewer.toml", agentReviewerToml({ projectName }));
|
|
737
755
|
writeAgentFile(cwd2, ".codex/agents/default.toml", agentLeadAsDefaultToml({ projectName }));
|
|
@@ -750,6 +768,7 @@ No tasks in progress.
|
|
|
750
768
|
const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
|
|
751
769
|
writeAgentFile(cwd2, ".codex/agents/lead.toml", agentLeadToml({ projectName }));
|
|
752
770
|
writeAgentFile(cwd2, ".codex/agents/explorer.toml", agentExplorerToml({ projectName, allowedPaths }));
|
|
771
|
+
writeAgentFile(cwd2, ".codex/agents/consultant.toml", agentConsultantToml({ projectName }));
|
|
753
772
|
writeAgentFile(cwd2, ".codex/agents/builder.toml", agentBuilderToml({ projectName, writablePaths }));
|
|
754
773
|
writeAgentFile(cwd2, ".codex/agents/reviewer.toml", agentReviewerToml({ projectName }));
|
|
755
774
|
writeAgentFile(cwd2, ".codex/agents/default.toml", agentLeadAsDefaultToml({ projectName }));
|
|
@@ -792,10 +811,11 @@ No tasks in progress.
|
|
|
792
811
|
const projectName = config.project.name;
|
|
793
812
|
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(", ");
|
|
794
813
|
const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
|
|
795
|
-
writeAgentFile(cwd2, ".opencode/agents/lead.md", agentLead({ projectName }));
|
|
796
|
-
writeAgentFile(cwd2, ".opencode/agents/explorer.md", agentExplorer({ projectName, allowedPaths }));
|
|
797
|
-
writeAgentFile(cwd2, ".opencode/agents/
|
|
798
|
-
writeAgentFile(cwd2, ".opencode/agents/
|
|
814
|
+
writeAgentFile(cwd2, ".opencode/agents/lead.md", translateFrontmatterForOpenCode(agentLead({ projectName })));
|
|
815
|
+
writeAgentFile(cwd2, ".opencode/agents/explorer.md", translateFrontmatterForOpenCode(agentExplorer({ projectName, allowedPaths })));
|
|
816
|
+
writeAgentFile(cwd2, ".opencode/agents/consultant.md", translateFrontmatterForOpenCode(agentConsultant({ projectName })));
|
|
817
|
+
writeAgentFile(cwd2, ".opencode/agents/builder.md", translateFrontmatterForOpenCode(agentBuilder({ projectName, writablePaths })));
|
|
818
|
+
writeAgentFile(cwd2, ".opencode/agents/reviewer.md", translateFrontmatterForOpenCode(agentReviewer({ projectName })));
|
|
799
819
|
mergeOpencodeJson(join6(cwd2, "opencode.json"), config.tools.mcp.port);
|
|
800
820
|
appendGitignore(cwd2);
|
|
801
821
|
}
|
|
@@ -809,10 +829,11 @@ No tasks in progress.
|
|
|
809
829
|
const projectName = config.project.name;
|
|
810
830
|
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(", ");
|
|
811
831
|
const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
|
|
812
|
-
writeAgentFile(cwd2, ".opencode/agents/lead.md", agentLead({ projectName }));
|
|
813
|
-
writeAgentFile(cwd2, ".opencode/agents/explorer.md", agentExplorer({ projectName, allowedPaths }));
|
|
814
|
-
writeAgentFile(cwd2, ".opencode/agents/
|
|
815
|
-
writeAgentFile(cwd2, ".opencode/agents/
|
|
832
|
+
writeAgentFile(cwd2, ".opencode/agents/lead.md", translateFrontmatterForOpenCode(agentLead({ projectName })));
|
|
833
|
+
writeAgentFile(cwd2, ".opencode/agents/explorer.md", translateFrontmatterForOpenCode(agentExplorer({ projectName, allowedPaths })));
|
|
834
|
+
writeAgentFile(cwd2, ".opencode/agents/consultant.md", translateFrontmatterForOpenCode(agentConsultant({ projectName })));
|
|
835
|
+
writeAgentFile(cwd2, ".opencode/agents/builder.md", translateFrontmatterForOpenCode(agentBuilder({ projectName, writablePaths })));
|
|
836
|
+
writeAgentFile(cwd2, ".opencode/agents/reviewer.md", translateFrontmatterForOpenCode(agentReviewer({ projectName })));
|
|
816
837
|
mergeOpencodeJson(join6(cwd2, "opencode.json"), config.tools.mcp.port);
|
|
817
838
|
}
|
|
818
839
|
async migrate(config, _to, _cwd) {
|
|
@@ -1786,7 +1807,7 @@ async function runHealth(cwd2) {
|
|
|
1786
1807
|
if (!dbOk) allOk = false;
|
|
1787
1808
|
const providerFiles = getProviderHealthFiles(config.provider);
|
|
1788
1809
|
const agentsDir = providerFiles.agentsDir;
|
|
1789
|
-
const agentNames = ["lead", "explorer", "builder", "reviewer"];
|
|
1810
|
+
const agentNames = ["lead", "explorer", "consultant", "builder", "reviewer"];
|
|
1790
1811
|
const agentsLabelWidth = "[checking agents] ".length;
|
|
1791
1812
|
for (let i = 0; i < agentNames.length; i++) {
|
|
1792
1813
|
const name = agentNames[i];
|
|
@@ -2244,7 +2265,7 @@ import { existsSync as existsSync9, readdirSync, rmSync } from "fs";
|
|
|
2244
2265
|
import { join as join13, resolve as resolve9 } from "path";
|
|
2245
2266
|
import * as p5 from "@clack/prompts";
|
|
2246
2267
|
import pc8 from "picocolors";
|
|
2247
|
-
var AGENT_MD_FILES = ["lead", "explorer", "builder", "reviewer"];
|
|
2268
|
+
var AGENT_MD_FILES = ["lead", "explorer", "consultant", "builder", "reviewer"];
|
|
2248
2269
|
async function resetAgentMds(cwd2, provider) {
|
|
2249
2270
|
const agentDir = provider === "claude-code" ? ".claude/agents" : ".opencode/agents";
|
|
2250
2271
|
const agentDirPath = resolve9(cwd2, agentDir);
|