@cardor/agent-harness-kit 2.2.0 → 2.3.1
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 +3 -1
- package/dist/cli.js +83 -73
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -272,7 +272,7 @@ ahk build --force
|
|
|
272
272
|
- **It discards your customizations.** Every agent file is rewritten from the template. Prompt edits, `model:` lines, and restriction tweaks are all lost.
|
|
273
273
|
- **It backs up first.** Before overwriting anything, the current content of every affected file is copied under `.harness/backups/` — agent files to `agents-<timestamp>/`, hand-edited `AGENTS.md`/`CLAUDE.md` to `derived-<timestamp>/`. If that backup cannot be written, the command aborts and **no file is modified** — the same fail-safe as [`ahk migrate storage --force`](#storage-migration).
|
|
274
274
|
- **It names what it touched.** The command prints every file it overwrote and the backup location, so you can diff or restore.
|
|
275
|
-
- **Claude Code
|
|
275
|
+
- **Claude Code and Codex CLI also re-prompt for models.** Before regenerating, `ahk build --force` runs the same per-role prompt as `ahk init` for the current provider — the model prompt on Claude Code, or the model **and** reasoning-effort prompt on Codex CLI (see above) — and injects the fresh choices into the regenerated frontmatter/TOML. OpenCode and Grok Build are unaffected — no prompt appears for them, since neither has a closed model enum to prompt against.
|
|
276
276
|
|
|
277
277
|
`--force` also regenerates a hand-edited `AGENTS.md` or `CLAUDE.md` (backing it up first) — the only time you need it for those files, since an *unedited* one already re-generates on its own when config changes.
|
|
278
278
|
|
|
@@ -471,6 +471,8 @@ ahk migrate provider --to grok-cli
|
|
|
471
471
|
ahk migrate --to opencode
|
|
472
472
|
```
|
|
473
473
|
|
|
474
|
+
Migrating always regenerates the target provider's agent files from scratch, so — same as `ahk init` and `ahk build --force` — it also runs that target's per-role prompt first, before anything is written: the model prompt when migrating **to** Claude Code, or the model **and** reasoning-effort prompt when migrating **to** Codex CLI (see [`ahk init`](#ahk-init) above for what each prompt asks). Migrating to OpenCode or Grok CLI shows no prompt at all, since neither has a closed model enum to prompt against.
|
|
475
|
+
|
|
474
476
|
#### `ahk migrate storage` — ⚠️ sensitive, reads/writes real harness data
|
|
475
477
|
|
|
476
478
|
Migrates the harness database between storage backends: **local↔global scope** (moving `.harness/harness.db` in/out of `~/.harness/dbs/<projectId>/`) and **sqlite↔postgres/mysql** (dumping and reloading all 6 tables — tasks, task_acceptance, actions, action_sections, action_files, action_tools — inside a single transaction). It is **not interactive** — `agent-harness-kit.config.ts` (`storage.scope`, `storage.sqlitePath` (local scope only), `database.type`/`connectionString`) is the only source of truth for the desired target, compared against the real current state recorded in `.harness/storage-state.json`.
|
package/dist/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ import pc21 from "picocolors";
|
|
|
20
20
|
|
|
21
21
|
// src/commands/build.ts
|
|
22
22
|
import { watch } from "fs";
|
|
23
|
-
import * as
|
|
23
|
+
import * as p3 from "@clack/prompts";
|
|
24
24
|
import pc2 from "picocolors";
|
|
25
25
|
|
|
26
26
|
// src/core/materializer/claude-code.ts
|
|
@@ -398,6 +398,7 @@ function mergeCodexConfigToml(filePath, port, cwd2, pm = "npm") {
|
|
|
398
398
|
].join("\n");
|
|
399
399
|
content = ensureTomlTopLevelKey(content, "model", "gpt-5.6-terra");
|
|
400
400
|
content = ensureTomlTopLevelKey(content, "model_reasoning_effort", "medium");
|
|
401
|
+
content = ensureTomlTopLevelKey(content, "sandbox_mode", "danger-full-access");
|
|
401
402
|
content = mergeTomlSection(content, "mcp_servers.agent-harness-kit", sectionBody);
|
|
402
403
|
writeFileSync2(filePath, content, "utf8");
|
|
403
404
|
}
|
|
@@ -408,7 +409,10 @@ function mergeGrokConfigToml(filePath, port, cwd2, pm = "npm") {
|
|
|
408
409
|
content = readFileSync3(filePath, "utf8");
|
|
409
410
|
}
|
|
410
411
|
const [command, ...args] = getMcpCommandParts(pm, port, cwd2);
|
|
411
|
-
const sectionBody = [
|
|
412
|
+
const sectionBody = [
|
|
413
|
+
`command = ${JSON.stringify(command)}`,
|
|
414
|
+
`args = ${JSON.stringify(args)}`
|
|
415
|
+
].join("\n");
|
|
412
416
|
content = mergeTomlSection(content, "mcp_servers.agent-harness-kit", sectionBody);
|
|
413
417
|
writeFileSync2(filePath, content, "utf8");
|
|
414
418
|
}
|
|
@@ -1387,20 +1391,69 @@ async function promptClaudeAgentModels(provider) {
|
|
|
1387
1391
|
return claudeAgentModels;
|
|
1388
1392
|
}
|
|
1389
1393
|
|
|
1394
|
+
// src/commands/codex-model-prompt.ts
|
|
1395
|
+
import * as p2 from "@clack/prompts";
|
|
1396
|
+
var AGENT_LABELS2 = [
|
|
1397
|
+
{ key: "lead", label: "Lead" },
|
|
1398
|
+
{ key: "explorer", label: "Explorer" },
|
|
1399
|
+
{ key: "consultant", label: "Consultant" },
|
|
1400
|
+
{ key: "builder", label: "Builder" },
|
|
1401
|
+
{ key: "reviewer", label: "Reviewer" }
|
|
1402
|
+
];
|
|
1403
|
+
var CODEX_MODEL_CHOICES = [
|
|
1404
|
+
"gpt-5.6-sol",
|
|
1405
|
+
"gpt-5.6-terra",
|
|
1406
|
+
"gpt-5.6-luna",
|
|
1407
|
+
"gpt-5.5",
|
|
1408
|
+
"gpt-5.4",
|
|
1409
|
+
"gpt-5.4-mini",
|
|
1410
|
+
"gpt-5.3-codex-spark"
|
|
1411
|
+
];
|
|
1412
|
+
var CODEX_EFFORT_CHOICES = ["minimal", "low", "medium", "high", "xhigh"];
|
|
1413
|
+
async function promptCodexAgentModels(provider) {
|
|
1414
|
+
const codexAgentModels = {};
|
|
1415
|
+
if (provider !== "codex-cli") return codexAgentModels;
|
|
1416
|
+
for (const agent of AGENT_LABELS2) {
|
|
1417
|
+
const modelVal = await p2.select({
|
|
1418
|
+
message: `Model for ${agent.label}`,
|
|
1419
|
+
options: CODEX_MODEL_CHOICES.map((value) => ({ value, label: value })),
|
|
1420
|
+
initialValue: "gpt-5.6-terra"
|
|
1421
|
+
});
|
|
1422
|
+
if (p2.isCancel(modelVal)) {
|
|
1423
|
+
p2.cancel("Cancelled.");
|
|
1424
|
+
process.exit(0);
|
|
1425
|
+
}
|
|
1426
|
+
const effortVal = await p2.select({
|
|
1427
|
+
message: `Reasoning effort for ${agent.label}`,
|
|
1428
|
+
options: CODEX_EFFORT_CHOICES.map((value) => ({ value, label: value })),
|
|
1429
|
+
initialValue: "medium"
|
|
1430
|
+
});
|
|
1431
|
+
if (p2.isCancel(effortVal)) {
|
|
1432
|
+
p2.cancel("Cancelled.");
|
|
1433
|
+
process.exit(0);
|
|
1434
|
+
}
|
|
1435
|
+
codexAgentModels[agent.key] = {
|
|
1436
|
+
model: modelVal,
|
|
1437
|
+
effort: effortVal
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
return codexAgentModels;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1390
1443
|
// src/commands/build.ts
|
|
1391
1444
|
async function runBuild(cwd2, opts) {
|
|
1392
1445
|
await buildOnce(cwd2, opts.force);
|
|
1393
1446
|
if (opts.sync) {
|
|
1394
|
-
|
|
1447
|
+
p3.log.step("Syncing agent permissions...");
|
|
1395
1448
|
const config = await loadConfig(cwd2);
|
|
1396
1449
|
const materializer = getMaterializer(config.provider);
|
|
1397
1450
|
await materializer.syncPermissions(cwd2);
|
|
1398
1451
|
}
|
|
1399
1452
|
if (opts.watch) {
|
|
1400
|
-
|
|
1453
|
+
p3.log.info(`Watching agent-harness-kit.config.ts for changes...`);
|
|
1401
1454
|
watch(cwd2, { recursive: false }, async (_, filename) => {
|
|
1402
1455
|
if (filename?.startsWith("agent-harness-kit.config")) {
|
|
1403
|
-
|
|
1456
|
+
p3.log.step("Config changed \u2014 rebuilding...");
|
|
1404
1457
|
await buildOnce(cwd2, false);
|
|
1405
1458
|
}
|
|
1406
1459
|
});
|
|
@@ -1413,41 +1466,45 @@ async function buildOnce(cwd2, force) {
|
|
|
1413
1466
|
try {
|
|
1414
1467
|
config = await loadConfig(cwd2);
|
|
1415
1468
|
} catch (err) {
|
|
1416
|
-
|
|
1469
|
+
p3.log.error(err instanceof Error ? err.message : String(err));
|
|
1417
1470
|
process.exit(1);
|
|
1418
1471
|
}
|
|
1419
1472
|
let claudeAgentModels;
|
|
1420
1473
|
if (force && config.provider === "claude-code") {
|
|
1421
1474
|
claudeAgentModels = await promptClaudeAgentModels(config.provider);
|
|
1422
1475
|
}
|
|
1423
|
-
|
|
1476
|
+
let codexAgentModels;
|
|
1477
|
+
if (force && config.provider === "codex-cli") {
|
|
1478
|
+
codexAgentModels = await promptCodexAgentModels(config.provider);
|
|
1479
|
+
}
|
|
1480
|
+
const spinner6 = p3.spinner();
|
|
1424
1481
|
spinner6.start("Rebuilding files...");
|
|
1425
1482
|
try {
|
|
1426
1483
|
const materializer = getMaterializer(config.provider);
|
|
1427
|
-
const report = await materializer.build(config, cwd2, { force, claudeAgentModels });
|
|
1484
|
+
const report = await materializer.build(config, cwd2, { force, claudeAgentModels, codexAgentModels });
|
|
1428
1485
|
spinner6.stop(pc2.green("Build complete"));
|
|
1429
1486
|
const d = report.derived;
|
|
1430
1487
|
const upToDate = [...d.created, ...d.current, ...d.propagated];
|
|
1431
1488
|
if (upToDate.length > 0) {
|
|
1432
|
-
|
|
1489
|
+
p3.log.success(upToDate.join(", "));
|
|
1433
1490
|
}
|
|
1434
1491
|
if (d.propagated.length > 0) {
|
|
1435
|
-
|
|
1492
|
+
p3.log.info(`Propagated config changes to ${d.propagated.length} generated file(s):
|
|
1436
1493
|
${d.propagated.join("\n ")}`);
|
|
1437
1494
|
}
|
|
1438
1495
|
if (d.overwritten.length > 0) {
|
|
1439
|
-
|
|
1496
|
+
p3.log.warn(
|
|
1440
1497
|
pc2.yellow(
|
|
1441
1498
|
`--force REGENERATED ${d.overwritten.length} hand-edited generated file(s), discarding your edits:
|
|
1442
1499
|
` + d.overwritten.join("\n ")
|
|
1443
1500
|
)
|
|
1444
1501
|
);
|
|
1445
1502
|
if (d.backupDir) {
|
|
1446
|
-
|
|
1503
|
+
p3.log.info(pc2.yellow(` Previous content backed up \u2192 ${d.backupDir}`));
|
|
1447
1504
|
}
|
|
1448
1505
|
}
|
|
1449
1506
|
if (d.preserved.length > 0) {
|
|
1450
|
-
|
|
1507
|
+
p3.log.warn(
|
|
1451
1508
|
pc2.yellow(
|
|
1452
1509
|
`Left ${d.preserved.length} hand-edited generated file(s) UNTOUCHED \u2014 your edits are safe:
|
|
1453
1510
|
` + d.preserved.join("\n ") + `
|
|
@@ -1456,26 +1513,26 @@ async function buildOnce(cwd2, force) {
|
|
|
1456
1513
|
)
|
|
1457
1514
|
);
|
|
1458
1515
|
}
|
|
1459
|
-
|
|
1460
|
-
|
|
1516
|
+
p3.log.success(`Agent definitions (${config.provider})`);
|
|
1517
|
+
p3.log.success("MCP config");
|
|
1461
1518
|
const { created, overwritten, preserved, backupDir } = report.agents;
|
|
1462
1519
|
if (created.length > 0) {
|
|
1463
|
-
|
|
1520
|
+
p3.log.info(`Created ${created.length} missing agent file(s):
|
|
1464
1521
|
${created.join("\n ")}`);
|
|
1465
1522
|
}
|
|
1466
1523
|
if (overwritten.length > 0) {
|
|
1467
|
-
|
|
1524
|
+
p3.log.warn(
|
|
1468
1525
|
pc2.yellow(
|
|
1469
1526
|
`--force REGENERATED ${overwritten.length} existing agent file(s), discarding any customizations:
|
|
1470
1527
|
` + overwritten.join("\n ")
|
|
1471
1528
|
)
|
|
1472
1529
|
);
|
|
1473
1530
|
if (backupDir) {
|
|
1474
|
-
|
|
1531
|
+
p3.log.info(pc2.yellow(` Previous content backed up \u2192 ${backupDir}`));
|
|
1475
1532
|
}
|
|
1476
1533
|
}
|
|
1477
1534
|
if (preserved.length > 0) {
|
|
1478
|
-
|
|
1535
|
+
p3.log.info(
|
|
1479
1536
|
`Left ${preserved.length} existing agent file(s) untouched \u2014 agent files are yours to edit.
|
|
1480
1537
|
Re-run with --force to regenerate them from the packaged templates (this DESTROYS your edits;
|
|
1481
1538
|
a backup is written first).`
|
|
@@ -1483,7 +1540,7 @@ async function buildOnce(cwd2, force) {
|
|
|
1483
1540
|
}
|
|
1484
1541
|
} catch (err) {
|
|
1485
1542
|
spinner6.stop(pc2.red("Build failed"));
|
|
1486
|
-
|
|
1543
|
+
p3.log.error(err instanceof Error ? err.message : String(err));
|
|
1487
1544
|
process.exit(1);
|
|
1488
1545
|
}
|
|
1489
1546
|
}
|
|
@@ -2136,7 +2193,7 @@ var taskDescriptionSchema = v2.pipe(
|
|
|
2136
2193
|
);
|
|
2137
2194
|
|
|
2138
2195
|
// src/utils/form.ts
|
|
2139
|
-
import * as
|
|
2196
|
+
import * as p4 from "@clack/prompts";
|
|
2140
2197
|
import * as v3 from "valibot";
|
|
2141
2198
|
var cliFormWithRetry = async (formFn, schema) => {
|
|
2142
2199
|
while (true) {
|
|
@@ -2144,60 +2201,11 @@ var cliFormWithRetry = async (formFn, schema) => {
|
|
|
2144
2201
|
const result = v3.safeParse(schema, res);
|
|
2145
2202
|
if (result.success) return result.output;
|
|
2146
2203
|
const messages = result.issues.map((i) => i.message).join(", ");
|
|
2147
|
-
|
|
2148
|
-
|
|
2204
|
+
p4.log.error(messages);
|
|
2205
|
+
p4.log.info("Please try again.\n");
|
|
2149
2206
|
}
|
|
2150
2207
|
};
|
|
2151
2208
|
|
|
2152
|
-
// src/commands/codex-model-prompt.ts
|
|
2153
|
-
import * as p4 from "@clack/prompts";
|
|
2154
|
-
var AGENT_LABELS2 = [
|
|
2155
|
-
{ key: "lead", label: "Lead" },
|
|
2156
|
-
{ key: "explorer", label: "Explorer" },
|
|
2157
|
-
{ key: "consultant", label: "Consultant" },
|
|
2158
|
-
{ key: "builder", label: "Builder" },
|
|
2159
|
-
{ key: "reviewer", label: "Reviewer" }
|
|
2160
|
-
];
|
|
2161
|
-
var CODEX_MODEL_CHOICES = [
|
|
2162
|
-
"gpt-5.6-sol",
|
|
2163
|
-
"gpt-5.6-terra",
|
|
2164
|
-
"gpt-5.6-luna",
|
|
2165
|
-
"gpt-5.5",
|
|
2166
|
-
"gpt-5.4",
|
|
2167
|
-
"gpt-5.4-mini",
|
|
2168
|
-
"gpt-5.3-codex-spark"
|
|
2169
|
-
];
|
|
2170
|
-
var CODEX_EFFORT_CHOICES = ["minimal", "low", "medium", "high", "xhigh"];
|
|
2171
|
-
async function promptCodexAgentModels(provider) {
|
|
2172
|
-
const codexAgentModels = {};
|
|
2173
|
-
if (provider !== "codex-cli") return codexAgentModels;
|
|
2174
|
-
for (const agent of AGENT_LABELS2) {
|
|
2175
|
-
const modelVal = await p4.select({
|
|
2176
|
-
message: `Model for ${agent.label}`,
|
|
2177
|
-
options: CODEX_MODEL_CHOICES.map((value) => ({ value, label: value })),
|
|
2178
|
-
initialValue: "gpt-5.6-terra"
|
|
2179
|
-
});
|
|
2180
|
-
if (p4.isCancel(modelVal)) {
|
|
2181
|
-
p4.cancel("Cancelled.");
|
|
2182
|
-
process.exit(0);
|
|
2183
|
-
}
|
|
2184
|
-
const effortVal = await p4.select({
|
|
2185
|
-
message: `Reasoning effort for ${agent.label}`,
|
|
2186
|
-
options: CODEX_EFFORT_CHOICES.map((value) => ({ value, label: value })),
|
|
2187
|
-
initialValue: "medium"
|
|
2188
|
-
});
|
|
2189
|
-
if (p4.isCancel(effortVal)) {
|
|
2190
|
-
p4.cancel("Cancelled.");
|
|
2191
|
-
process.exit(0);
|
|
2192
|
-
}
|
|
2193
|
-
codexAgentModels[agent.key] = {
|
|
2194
|
-
model: modelVal,
|
|
2195
|
-
effort: effortVal
|
|
2196
|
-
};
|
|
2197
|
-
}
|
|
2198
|
-
return codexAgentModels;
|
|
2199
|
-
}
|
|
2200
|
-
|
|
2201
2209
|
// src/commands/init-helpers.ts
|
|
2202
2210
|
import { randomUUID } from "crypto";
|
|
2203
2211
|
import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
|
|
@@ -2609,11 +2617,13 @@ async function runMigrate(cwd2, opts) {
|
|
|
2609
2617
|
console.log(pc9.dim(`Already on ${target} \u2014 nothing to migrate.`));
|
|
2610
2618
|
return;
|
|
2611
2619
|
}
|
|
2620
|
+
const claudeAgentModels = await promptClaudeAgentModels(target);
|
|
2621
|
+
const codexAgentModels = await promptCodexAgentModels(target);
|
|
2612
2622
|
const spinner6 = p6.spinner();
|
|
2613
2623
|
spinner6.start(`Migrating from ${config.provider} to ${target}...`);
|
|
2614
2624
|
try {
|
|
2615
2625
|
const targetMaterializer = getMaterializer(target);
|
|
2616
|
-
await targetMaterializer.build(config, cwd2);
|
|
2626
|
+
await targetMaterializer.build(config, cwd2, { claudeAgentModels, codexAgentModels });
|
|
2617
2627
|
spinner6.stop(pc9.green(`Migrated to ${target}`));
|
|
2618
2628
|
p6.log.warn(`Update agent-harness-kit.config.ts: set provider: '${target}'`);
|
|
2619
2629
|
p6.log.warn(`Then run: ahk build`);
|