@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 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
@@ -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 = [`command = ${JSON.stringify(command)}`, `args = ${JSON.stringify(args)}`].join("\n");
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
- p2.log.step("Syncing agent permissions...");
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
- p2.log.info(`Watching agent-harness-kit.config.ts for changes...`);
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
- p2.log.step("Config changed \u2014 rebuilding...");
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
- p2.log.error(err instanceof Error ? err.message : String(err));
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
- const spinner6 = p2.spinner();
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
- p2.log.success(upToDate.join(", "));
1489
+ p3.log.success(upToDate.join(", "));
1433
1490
  }
1434
1491
  if (d.propagated.length > 0) {
1435
- p2.log.info(`Propagated config changes to ${d.propagated.length} generated file(s):
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
- p2.log.warn(
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
- p2.log.info(pc2.yellow(` Previous content backed up \u2192 ${d.backupDir}`));
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
- p2.log.warn(
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
- p2.log.success(`Agent definitions (${config.provider})`);
1460
- p2.log.success("MCP config");
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
- p2.log.info(`Created ${created.length} missing agent file(s):
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
- p2.log.warn(
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
- p2.log.info(pc2.yellow(` Previous content backed up \u2192 ${backupDir}`));
1531
+ p3.log.info(pc2.yellow(` Previous content backed up \u2192 ${backupDir}`));
1475
1532
  }
1476
1533
  }
1477
1534
  if (preserved.length > 0) {
1478
- p2.log.info(
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
- p2.log.error(err instanceof Error ? err.message : String(err));
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 p3 from "@clack/prompts";
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
- p3.log.error(messages);
2148
- p3.log.info("Please try again.\n");
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`);