@cardor/agent-harness-kit 2.2.0 → 2.3.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
@@ -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 only, it also re-prompts for models.** Before regenerating, `ahk build --force` runs the same per-role model prompt as `ahk init` (see above) and injects the fresh choices into the regenerated frontmatter. Other providers are unaffected — no prompt appears for them.
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 p2 from "@clack/prompts";
23
+ import * as p3 from "@clack/prompts";
24
24
  import pc2 from "picocolors";
25
25
 
26
26
  // src/core/materializer/claude-code.ts
@@ -1387,20 +1387,69 @@ async function promptClaudeAgentModels(provider) {
1387
1387
  return claudeAgentModels;
1388
1388
  }
1389
1389
 
1390
+ // src/commands/codex-model-prompt.ts
1391
+ import * as p2 from "@clack/prompts";
1392
+ var AGENT_LABELS2 = [
1393
+ { key: "lead", label: "Lead" },
1394
+ { key: "explorer", label: "Explorer" },
1395
+ { key: "consultant", label: "Consultant" },
1396
+ { key: "builder", label: "Builder" },
1397
+ { key: "reviewer", label: "Reviewer" }
1398
+ ];
1399
+ var CODEX_MODEL_CHOICES = [
1400
+ "gpt-5.6-sol",
1401
+ "gpt-5.6-terra",
1402
+ "gpt-5.6-luna",
1403
+ "gpt-5.5",
1404
+ "gpt-5.4",
1405
+ "gpt-5.4-mini",
1406
+ "gpt-5.3-codex-spark"
1407
+ ];
1408
+ var CODEX_EFFORT_CHOICES = ["minimal", "low", "medium", "high", "xhigh"];
1409
+ async function promptCodexAgentModels(provider) {
1410
+ const codexAgentModels = {};
1411
+ if (provider !== "codex-cli") return codexAgentModels;
1412
+ for (const agent of AGENT_LABELS2) {
1413
+ const modelVal = await p2.select({
1414
+ message: `Model for ${agent.label}`,
1415
+ options: CODEX_MODEL_CHOICES.map((value) => ({ value, label: value })),
1416
+ initialValue: "gpt-5.6-terra"
1417
+ });
1418
+ if (p2.isCancel(modelVal)) {
1419
+ p2.cancel("Cancelled.");
1420
+ process.exit(0);
1421
+ }
1422
+ const effortVal = await p2.select({
1423
+ message: `Reasoning effort for ${agent.label}`,
1424
+ options: CODEX_EFFORT_CHOICES.map((value) => ({ value, label: value })),
1425
+ initialValue: "medium"
1426
+ });
1427
+ if (p2.isCancel(effortVal)) {
1428
+ p2.cancel("Cancelled.");
1429
+ process.exit(0);
1430
+ }
1431
+ codexAgentModels[agent.key] = {
1432
+ model: modelVal,
1433
+ effort: effortVal
1434
+ };
1435
+ }
1436
+ return codexAgentModels;
1437
+ }
1438
+
1390
1439
  // src/commands/build.ts
1391
1440
  async function runBuild(cwd2, opts) {
1392
1441
  await buildOnce(cwd2, opts.force);
1393
1442
  if (opts.sync) {
1394
- p2.log.step("Syncing agent permissions...");
1443
+ p3.log.step("Syncing agent permissions...");
1395
1444
  const config = await loadConfig(cwd2);
1396
1445
  const materializer = getMaterializer(config.provider);
1397
1446
  await materializer.syncPermissions(cwd2);
1398
1447
  }
1399
1448
  if (opts.watch) {
1400
- p2.log.info(`Watching agent-harness-kit.config.ts for changes...`);
1449
+ p3.log.info(`Watching agent-harness-kit.config.ts for changes...`);
1401
1450
  watch(cwd2, { recursive: false }, async (_, filename) => {
1402
1451
  if (filename?.startsWith("agent-harness-kit.config")) {
1403
- p2.log.step("Config changed \u2014 rebuilding...");
1452
+ p3.log.step("Config changed \u2014 rebuilding...");
1404
1453
  await buildOnce(cwd2, false);
1405
1454
  }
1406
1455
  });
@@ -1413,41 +1462,45 @@ async function buildOnce(cwd2, force) {
1413
1462
  try {
1414
1463
  config = await loadConfig(cwd2);
1415
1464
  } catch (err) {
1416
- p2.log.error(err instanceof Error ? err.message : String(err));
1465
+ p3.log.error(err instanceof Error ? err.message : String(err));
1417
1466
  process.exit(1);
1418
1467
  }
1419
1468
  let claudeAgentModels;
1420
1469
  if (force && config.provider === "claude-code") {
1421
1470
  claudeAgentModels = await promptClaudeAgentModels(config.provider);
1422
1471
  }
1423
- const spinner6 = p2.spinner();
1472
+ let codexAgentModels;
1473
+ if (force && config.provider === "codex-cli") {
1474
+ codexAgentModels = await promptCodexAgentModels(config.provider);
1475
+ }
1476
+ const spinner6 = p3.spinner();
1424
1477
  spinner6.start("Rebuilding files...");
1425
1478
  try {
1426
1479
  const materializer = getMaterializer(config.provider);
1427
- const report = await materializer.build(config, cwd2, { force, claudeAgentModels });
1480
+ const report = await materializer.build(config, cwd2, { force, claudeAgentModels, codexAgentModels });
1428
1481
  spinner6.stop(pc2.green("Build complete"));
1429
1482
  const d = report.derived;
1430
1483
  const upToDate = [...d.created, ...d.current, ...d.propagated];
1431
1484
  if (upToDate.length > 0) {
1432
- p2.log.success(upToDate.join(", "));
1485
+ p3.log.success(upToDate.join(", "));
1433
1486
  }
1434
1487
  if (d.propagated.length > 0) {
1435
- p2.log.info(`Propagated config changes to ${d.propagated.length} generated file(s):
1488
+ p3.log.info(`Propagated config changes to ${d.propagated.length} generated file(s):
1436
1489
  ${d.propagated.join("\n ")}`);
1437
1490
  }
1438
1491
  if (d.overwritten.length > 0) {
1439
- p2.log.warn(
1492
+ p3.log.warn(
1440
1493
  pc2.yellow(
1441
1494
  `--force REGENERATED ${d.overwritten.length} hand-edited generated file(s), discarding your edits:
1442
1495
  ` + d.overwritten.join("\n ")
1443
1496
  )
1444
1497
  );
1445
1498
  if (d.backupDir) {
1446
- p2.log.info(pc2.yellow(` Previous content backed up \u2192 ${d.backupDir}`));
1499
+ p3.log.info(pc2.yellow(` Previous content backed up \u2192 ${d.backupDir}`));
1447
1500
  }
1448
1501
  }
1449
1502
  if (d.preserved.length > 0) {
1450
- p2.log.warn(
1503
+ p3.log.warn(
1451
1504
  pc2.yellow(
1452
1505
  `Left ${d.preserved.length} hand-edited generated file(s) UNTOUCHED \u2014 your edits are safe:
1453
1506
  ` + d.preserved.join("\n ") + `
@@ -1456,26 +1509,26 @@ async function buildOnce(cwd2, force) {
1456
1509
  )
1457
1510
  );
1458
1511
  }
1459
- p2.log.success(`Agent definitions (${config.provider})`);
1460
- p2.log.success("MCP config");
1512
+ p3.log.success(`Agent definitions (${config.provider})`);
1513
+ p3.log.success("MCP config");
1461
1514
  const { created, overwritten, preserved, backupDir } = report.agents;
1462
1515
  if (created.length > 0) {
1463
- p2.log.info(`Created ${created.length} missing agent file(s):
1516
+ p3.log.info(`Created ${created.length} missing agent file(s):
1464
1517
  ${created.join("\n ")}`);
1465
1518
  }
1466
1519
  if (overwritten.length > 0) {
1467
- p2.log.warn(
1520
+ p3.log.warn(
1468
1521
  pc2.yellow(
1469
1522
  `--force REGENERATED ${overwritten.length} existing agent file(s), discarding any customizations:
1470
1523
  ` + overwritten.join("\n ")
1471
1524
  )
1472
1525
  );
1473
1526
  if (backupDir) {
1474
- p2.log.info(pc2.yellow(` Previous content backed up \u2192 ${backupDir}`));
1527
+ p3.log.info(pc2.yellow(` Previous content backed up \u2192 ${backupDir}`));
1475
1528
  }
1476
1529
  }
1477
1530
  if (preserved.length > 0) {
1478
- p2.log.info(
1531
+ p3.log.info(
1479
1532
  `Left ${preserved.length} existing agent file(s) untouched \u2014 agent files are yours to edit.
1480
1533
  Re-run with --force to regenerate them from the packaged templates (this DESTROYS your edits;
1481
1534
  a backup is written first).`
@@ -1483,7 +1536,7 @@ async function buildOnce(cwd2, force) {
1483
1536
  }
1484
1537
  } catch (err) {
1485
1538
  spinner6.stop(pc2.red("Build failed"));
1486
- p2.log.error(err instanceof Error ? err.message : String(err));
1539
+ p3.log.error(err instanceof Error ? err.message : String(err));
1487
1540
  process.exit(1);
1488
1541
  }
1489
1542
  }
@@ -2136,7 +2189,7 @@ var taskDescriptionSchema = v2.pipe(
2136
2189
  );
2137
2190
 
2138
2191
  // src/utils/form.ts
2139
- import * as p3 from "@clack/prompts";
2192
+ import * as p4 from "@clack/prompts";
2140
2193
  import * as v3 from "valibot";
2141
2194
  var cliFormWithRetry = async (formFn, schema) => {
2142
2195
  while (true) {
@@ -2144,60 +2197,11 @@ var cliFormWithRetry = async (formFn, schema) => {
2144
2197
  const result = v3.safeParse(schema, res);
2145
2198
  if (result.success) return result.output;
2146
2199
  const messages = result.issues.map((i) => i.message).join(", ");
2147
- p3.log.error(messages);
2148
- p3.log.info("Please try again.\n");
2200
+ p4.log.error(messages);
2201
+ p4.log.info("Please try again.\n");
2149
2202
  }
2150
2203
  };
2151
2204
 
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
2205
  // src/commands/init-helpers.ts
2202
2206
  import { randomUUID } from "crypto";
2203
2207
  import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
@@ -2609,11 +2613,13 @@ async function runMigrate(cwd2, opts) {
2609
2613
  console.log(pc9.dim(`Already on ${target} \u2014 nothing to migrate.`));
2610
2614
  return;
2611
2615
  }
2616
+ const claudeAgentModels = await promptClaudeAgentModels(target);
2617
+ const codexAgentModels = await promptCodexAgentModels(target);
2612
2618
  const spinner6 = p6.spinner();
2613
2619
  spinner6.start(`Migrating from ${config.provider} to ${target}...`);
2614
2620
  try {
2615
2621
  const targetMaterializer = getMaterializer(target);
2616
- await targetMaterializer.build(config, cwd2);
2622
+ await targetMaterializer.build(config, cwd2, { claudeAgentModels, codexAgentModels });
2617
2623
  spinner6.stop(pc9.green(`Migrated to ${target}`));
2618
2624
  p6.log.warn(`Update agent-harness-kit.config.ts: set provider: '${target}'`);
2619
2625
  p6.log.warn(`Then run: ahk build`);