@iamu-dev/iamu 0.3.0-beta.0 → 0.3.0-beta.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/dist/index.js CHANGED
@@ -5459,10 +5459,20 @@ async function readTestability(projectRoot) {
5459
5459
  body: parsed.body
5460
5460
  };
5461
5461
  }
5462
+ async function writeTestability(projectRoot, input, body) {
5463
+ const p = testabilityPath(projectRoot);
5464
+ const isLocalDoc = "frontmatter" in input && typeof input.frontmatter === "object";
5465
+ const fm = isLocalDoc ? input.frontmatter : input;
5466
+ const effectiveBody = body !== void 0 ? body : isLocalDoc ? input.body : "";
5467
+ const validated = testabilityFrontmatterSchema.parse(fm);
5468
+ const serialized = serializeFrontmatter(validated, effectiveBody);
5469
+ await atomicWriteFile(p, serialized);
5470
+ }
5462
5471
  var init_testability2 = __esm({
5463
5472
  "../../packages/local-store/dist/testability.js"() {
5464
5473
  "use strict";
5465
5474
  init_dist();
5475
+ init_atomic();
5466
5476
  init_markdown();
5467
5477
  init_paths();
5468
5478
  }
@@ -8621,7 +8631,7 @@ function formatRefError(err) {
8621
8631
  const dir = ENTITY_DIRS[err.missing_ref];
8622
8632
  const hint = MISSING_REF_HINTS[err.missing_ref] ?? "";
8623
8633
  if (!err.missing_slug) {
8624
- const fieldHint = err.missing_ref === "capability" && err.entity_type === "outline" ? "add `primary_capability:` to the outline frontmatter" : `add a \`${err.missing_ref}:\` field to the file`;
8634
+ const fieldHint = err.missing_ref === "capability" && err.entity_type === "outline" ? `run \`iamu set outline ${err.entity_slug ?? "<slug>"} --capability <slug>\`` : `add a \`${err.missing_ref}:\` field to the file`;
8625
8635
  return `${err.entity_type} ${err.entity_slug || err.entity_id}: ${err.missing_ref} slug is missing from frontmatter \u2014 ${fieldHint}`;
8626
8636
  }
8627
8637
  return `${err.entity_type} ${err.entity_slug || err.entity_id}: \`${err.missing_slug}\` not found in iamu/${dir}/${hint}`;
@@ -8635,7 +8645,7 @@ var init_refs = __esm({
8635
8645
  init_sync_tracking();
8636
8646
  init_walkthrough_mirror();
8637
8647
  MISSING_REF_HINTS = {
8638
- capability: " \u2014 create it with `iamu new capability` or check the slug in frontmatter",
8648
+ capability: " \u2014 create it with `iamu new capability` or set with `iamu set outline <slug> --capability <slug>`",
8639
8649
  outline: " \u2014 create it with `iamu new` or verify the slug matches a file in iamu/outlines/",
8640
8650
  persona: " \u2014 create it with `iamu new persona` or check the slug",
8641
8651
  scenario: " \u2014 verify the scenario exists locally with `iamu list scenarios`"
@@ -13581,8 +13591,8 @@ import { dirname as dirname3, join as join4, resolve as resolve2 } from "path";
13581
13591
  import { fileURLToPath as fileURLToPath2 } from "url";
13582
13592
  import chalk6 from "chalk";
13583
13593
  function getVersion() {
13584
- if ("0.3.0-beta.0") {
13585
- return "0.3.0-beta.0";
13594
+ if ("0.3.0-beta.1") {
13595
+ return "0.3.0-beta.1";
13586
13596
  }
13587
13597
  try {
13588
13598
  const thisDir = dirname3(fileURLToPath2(import.meta.url));
@@ -20818,6 +20828,15 @@ function validateFile(filePath, raw, projectRoot) {
20818
20828
  );
20819
20829
  }
20820
20830
  }
20831
+ if (type2 === "outline" && zodResult.success) {
20832
+ const fm = zodResult.data;
20833
+ if (!fm.primary_capability && !fm.capability) {
20834
+ result.warnings = result.warnings ?? [];
20835
+ result.warnings.push(
20836
+ `outline has no primary capability \u2014 sync will require one (run \`iamu set outline ${fm.slug ?? "<slug>"} --capability <slug>\`)`
20837
+ );
20838
+ }
20839
+ }
20821
20840
  return result;
20822
20841
  }
20823
20842
  async function buildRepairLookups(projectRoot) {
@@ -21386,6 +21405,15 @@ async function newEntity(type2, opts) {
21386
21405
  );
21387
21406
  return;
21388
21407
  }
21408
+ if (entityType === "outline" && !opts.capability) {
21409
+ try {
21410
+ const { entities } = await listEntities(projectRoot, "capability");
21411
+ if (entities.length === 1 && typeof entities[0].frontmatter.slug === "string") {
21412
+ opts.capability = entities[0].frontmatter.slug;
21413
+ }
21414
+ } catch {
21415
+ }
21416
+ }
21389
21417
  const id = randomUUID10();
21390
21418
  const frontmatter = defaultFrontmatter(entityType, id, slug, opts.name, opts);
21391
21419
  const body = opts.body ?? (entityType === "outline" ? "" : opts.narrative) ?? "";
@@ -21504,6 +21532,42 @@ function applyChanges(type2, fm, opts) {
21504
21532
  put("paths", paths);
21505
21533
  }
21506
21534
  if (opts.area !== void 0) put("area", opts.area || null);
21535
+ } else if (type2 === "outline") {
21536
+ if (opts.capability === false) {
21537
+ put("primary_capability", null);
21538
+ put("capability", null);
21539
+ } else if (opts.capability !== void 0) {
21540
+ put("primary_capability", opts.capability || null);
21541
+ put("capability", opts.capability || null);
21542
+ }
21543
+ if (opts.additionalCapabilities === false) {
21544
+ put("additional_capabilities", []);
21545
+ } else if (opts.additionalCapabilities !== void 0) {
21546
+ const caps = typeof opts.additionalCapabilities === "string" ? splitList(opts.additionalCapabilities) : Array.isArray(opts.additionalCapabilities) ? opts.additionalCapabilities : [];
21547
+ put("additional_capabilities", caps);
21548
+ }
21549
+ } else if (type2 === "testability") {
21550
+ if (opts.target !== void 0) put("target_url", opts.target || null);
21551
+ if (opts.devCommand !== void 0)
21552
+ put("dev_command", opts.devCommand || null);
21553
+ if (opts.authStrategy !== void 0)
21554
+ put("auth_strategy", opts.authStrategy || null);
21555
+ if (opts.access !== void 0) put("access", opts.access || null);
21556
+ if (opts.harnesses !== void 0) {
21557
+ put("harnesses", opts.harnesses ? splitList(opts.harnesses) : null);
21558
+ }
21559
+ if (opts.untestableBoundaries !== void 0) {
21560
+ put(
21561
+ "untestable_boundaries",
21562
+ opts.untestableBoundaries ? splitList(opts.untestableBoundaries) : null
21563
+ );
21564
+ }
21565
+ } else if (type2 === "context") {
21566
+ if (opts.domain !== void 0) put("domain", opts.domain || null);
21567
+ if (opts.industry !== void 0) put("industry", opts.industry || null);
21568
+ if (opts.jurisdiction !== void 0)
21569
+ put("jurisdiction", opts.jurisdiction || null);
21570
+ if (opts.notes !== void 0) put("notes", opts.notes || null);
21507
21571
  }
21508
21572
  return changed;
21509
21573
  }
@@ -21519,6 +21583,15 @@ async function setEntity(type2, slug, opts) {
21519
21583
  );
21520
21584
  return;
21521
21585
  }
21586
+ if (type2 !== "testability" && type2 !== "context" && !slug) {
21587
+ commandError(`A slug is required when setting a ${type2}.`, {
21588
+ ...opts,
21589
+ code: "missing_slug",
21590
+ fix: `iamu set ${type2} <slug>`
21591
+ });
21592
+ return;
21593
+ }
21594
+ const effectiveSlug = slug || type2;
21522
21595
  const foreign = Object.keys(FLAG_NAMES).filter(
21523
21596
  (k) => !allowed.includes(k) && given(opts, k)
21524
21597
  );
@@ -21528,7 +21601,7 @@ async function setEntity(type2, slug, opts) {
21528
21601
  {
21529
21602
  ...opts,
21530
21603
  code: "invalid_field_combination",
21531
- fix: `iamu set ${type2} ${slug} ${FLAG_NAMES[allowed[0]]} ...`
21604
+ fix: `iamu set ${type2} ${effectiveSlug} ${FLAG_NAMES[allowed[0]]} ...`
21532
21605
  }
21533
21606
  );
21534
21607
  return;
@@ -21569,7 +21642,38 @@ async function setEntity(type2, slug, opts) {
21569
21642
  const allowedPatchKeys = {
21570
21643
  scenario: ["entry", "entry_path", "target", "target_url", "state"],
21571
21644
  persona: ["access"],
21572
- capability: ["paths", "addPath", "removePath", "area"]
21645
+ capability: ["paths", "addPath", "removePath", "area"],
21646
+ outline: [
21647
+ "capability",
21648
+ "primary_capability",
21649
+ "additional_capabilities",
21650
+ "additionalCapabilities"
21651
+ ],
21652
+ testability: [
21653
+ "target",
21654
+ "target_url",
21655
+ "devCommand",
21656
+ "dev_command",
21657
+ "authStrategy",
21658
+ "auth_strategy",
21659
+ "access",
21660
+ "harnesses",
21661
+ "untestableBoundaries",
21662
+ "untestable_boundaries",
21663
+ "body"
21664
+ ],
21665
+ context: [
21666
+ "domain",
21667
+ "industry",
21668
+ "jurisdiction",
21669
+ "notes",
21670
+ "description",
21671
+ "name",
21672
+ "governed_by",
21673
+ "actors",
21674
+ "terminology",
21675
+ "body"
21676
+ ]
21573
21677
  };
21574
21678
  const foreignPatchKeys = Object.keys(parsed).filter(
21575
21679
  (k) => !allowedPatchKeys[type2]?.includes(k)
@@ -21628,6 +21732,65 @@ async function setEntity(type2, slug, opts) {
21628
21732
  if (effectiveOpts.area === void 0 && parsed.area !== void 0) {
21629
21733
  effectiveOpts.area = parsed.area === null || parsed.area === false ? false : String(parsed.area);
21630
21734
  }
21735
+ } else if (type2 === "outline") {
21736
+ if (effectiveOpts.capability === void 0 && (parsed.capability !== void 0 || parsed.primary_capability !== void 0)) {
21737
+ const v = parsed.capability ?? parsed.primary_capability;
21738
+ effectiveOpts.capability = v === null || v === false ? false : String(v);
21739
+ }
21740
+ if (effectiveOpts.additionalCapabilities === void 0 && (parsed.additionalCapabilities !== void 0 || parsed.additional_capabilities !== void 0)) {
21741
+ const v = parsed.additionalCapabilities ?? parsed.additional_capabilities;
21742
+ effectiveOpts.additionalCapabilities = v === null || v === false ? false : Array.isArray(v) ? v.join(",") : String(v);
21743
+ }
21744
+ } else if (type2 === "testability") {
21745
+ if (effectiveOpts.target === void 0 && (parsed.target !== void 0 || parsed.target_url !== void 0)) {
21746
+ const v = parsed.target ?? parsed.target_url;
21747
+ effectiveOpts.target = v === null || v === false ? false : String(v);
21748
+ }
21749
+ if (effectiveOpts.devCommand === void 0 && (parsed.devCommand !== void 0 || parsed.dev_command !== void 0)) {
21750
+ const v = parsed.devCommand ?? parsed.dev_command;
21751
+ effectiveOpts.devCommand = v === null || v === false ? false : String(v);
21752
+ }
21753
+ if (effectiveOpts.authStrategy === void 0 && (parsed.authStrategy !== void 0 || parsed.auth_strategy !== void 0)) {
21754
+ const v = parsed.authStrategy ?? parsed.auth_strategy;
21755
+ effectiveOpts.authStrategy = v === null || v === false ? false : String(v);
21756
+ }
21757
+ if (effectiveOpts.access === void 0 && parsed.access !== void 0) {
21758
+ effectiveOpts.access = parsed.access === null || parsed.access === false ? false : String(parsed.access);
21759
+ }
21760
+ if (effectiveOpts.harnesses === void 0 && parsed.harnesses !== void 0) {
21761
+ effectiveOpts.harnesses = parsed.harnesses === null || parsed.harnesses === false ? false : Array.isArray(parsed.harnesses) ? parsed.harnesses.join(",") : String(parsed.harnesses);
21762
+ }
21763
+ if (effectiveOpts.untestableBoundaries === void 0 && (parsed.untestableBoundaries !== void 0 || parsed.untestable_boundaries !== void 0)) {
21764
+ const b = parsed.untestableBoundaries ?? parsed.untestable_boundaries;
21765
+ effectiveOpts.untestableBoundaries = b === null || b === false ? false : Array.isArray(b) ? b.join(",") : String(b);
21766
+ }
21767
+ if (effectiveOpts.body === void 0 && parsed.body !== void 0) {
21768
+ effectiveOpts.body = String(parsed.body);
21769
+ }
21770
+ } else if (type2 === "context") {
21771
+ if (effectiveOpts.domain === void 0 && parsed.domain !== void 0) {
21772
+ effectiveOpts.domain = parsed.domain === null || parsed.domain === false ? false : String(parsed.domain);
21773
+ }
21774
+ if (effectiveOpts.industry === void 0 && parsed.industry !== void 0) {
21775
+ effectiveOpts.industry = parsed.industry === null || parsed.industry === false ? false : String(parsed.industry);
21776
+ }
21777
+ if (effectiveOpts.jurisdiction === void 0 && parsed.jurisdiction !== void 0) {
21778
+ effectiveOpts.jurisdiction = parsed.jurisdiction === null || parsed.jurisdiction === false ? false : String(parsed.jurisdiction);
21779
+ }
21780
+ if (effectiveOpts.notes === void 0 && parsed.notes !== void 0) {
21781
+ effectiveOpts.notes = parsed.notes === null || parsed.notes === false ? false : String(parsed.notes);
21782
+ }
21783
+ if (effectiveOpts.description === void 0 && parsed.description !== void 0) {
21784
+ effectiveOpts.description = parsed.description === null || parsed.description === false ? false : String(parsed.description);
21785
+ }
21786
+ if (effectiveOpts.name === void 0 && parsed.name !== void 0) {
21787
+ effectiveOpts.name = parsed.name === null || parsed.name === false ? false : String(parsed.name);
21788
+ }
21789
+ if (effectiveOpts.body === void 0 && parsed.body !== void 0) {
21790
+ effectiveOpts.body = String(parsed.body);
21791
+ } else if (effectiveOpts.body === void 0 && effectiveOpts.description !== void 0) {
21792
+ effectiveOpts.body = effectiveOpts.description ? String(effectiveOpts.description) : "";
21793
+ }
21631
21794
  }
21632
21795
  }
21633
21796
  if (!allowed.some((k) => given(effectiveOpts, k))) {
@@ -21636,11 +21799,112 @@ async function setEntity(type2, slug, opts) {
21636
21799
  {
21637
21800
  ...opts,
21638
21801
  code: "nothing_to_set",
21639
- fix: `iamu set ${type2} ${slug} ${FLAG_NAMES[allowed[0]]} ...`
21802
+ fix: `iamu set ${type2}${type2 === "testability" || type2 === "context" ? "" : ` ${effectiveSlug}`} ${FLAG_NAMES[allowed[0]]} ...`
21640
21803
  }
21641
21804
  );
21642
21805
  return;
21643
21806
  }
21807
+ if (type2 === "testability") {
21808
+ const doc = await readTestability(projectRoot) ?? {
21809
+ frontmatter: {
21810
+ schema_version: 1,
21811
+ status: "draft",
21812
+ target_url: "http://localhost:3000"
21813
+ },
21814
+ body: ""
21815
+ };
21816
+ const fm2 = { ...doc.frontmatter };
21817
+ const changed2 = applyChanges(type2, fm2, effectiveOpts);
21818
+ let body = doc.body;
21819
+ if (effectiveOpts.body !== void 0) {
21820
+ body = effectiveOpts.body;
21821
+ changed2.push("body");
21822
+ }
21823
+ const writtenPath2 = testabilityPath(projectRoot);
21824
+ try {
21825
+ await writeTestability(
21826
+ projectRoot,
21827
+ fm2,
21828
+ body
21829
+ );
21830
+ } catch (err) {
21831
+ const message = err instanceof ZodError2 ? err.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ") : err instanceof Error ? err.message : String(err);
21832
+ commandError(`Could not set testability: ${message}`, {
21833
+ ...opts,
21834
+ code: "testability_write_error",
21835
+ fix: "iamu set testability --target <url>"
21836
+ });
21837
+ return;
21838
+ }
21839
+ if (opts.json) {
21840
+ console.log(
21841
+ JSON.stringify({
21842
+ slug: "testability",
21843
+ type: "testability",
21844
+ path: writtenPath2,
21845
+ changed: changed2
21846
+ })
21847
+ );
21848
+ return;
21849
+ }
21850
+ console.log();
21851
+ console.log(
21852
+ ` ${symbols.success} Updated testability: ${changed2.join(", ")}`
21853
+ );
21854
+ console.log(` ${chalk28.dim("path:")} ${writtenPath2}`);
21855
+ console.log();
21856
+ return;
21857
+ }
21858
+ if (type2 === "context") {
21859
+ const doc = await readContext(projectRoot) ?? {
21860
+ frontmatter: {
21861
+ schema_version: SCHEMA_VERSION,
21862
+ status: "draft"
21863
+ },
21864
+ notes_body: ""
21865
+ };
21866
+ const fm2 = { ...doc.frontmatter };
21867
+ const changed2 = applyChanges(type2, fm2, effectiveOpts);
21868
+ let body = doc.notes_body;
21869
+ if (effectiveOpts.body !== void 0) {
21870
+ body = effectiveOpts.body;
21871
+ changed2.push("body");
21872
+ } else if (effectiveOpts.description !== void 0) {
21873
+ body = effectiveOpts.description ? String(effectiveOpts.description) : "";
21874
+ changed2.push("body");
21875
+ }
21876
+ const writtenPath2 = contextPath(projectRoot);
21877
+ try {
21878
+ await writeContext(projectRoot, {
21879
+ frontmatter: fm2,
21880
+ notes_body: body
21881
+ });
21882
+ } catch (err) {
21883
+ const message = err instanceof ZodError2 ? err.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ") : err instanceof Error ? err.message : String(err);
21884
+ commandError(`Could not set context: ${message}`, {
21885
+ ...opts,
21886
+ code: "context_write_error",
21887
+ fix: "iamu set context --domain <domain>"
21888
+ });
21889
+ return;
21890
+ }
21891
+ if (opts.json) {
21892
+ console.log(
21893
+ JSON.stringify({
21894
+ slug: "context",
21895
+ type: "context",
21896
+ path: writtenPath2,
21897
+ changed: changed2
21898
+ })
21899
+ );
21900
+ return;
21901
+ }
21902
+ console.log();
21903
+ console.log(` ${symbols.success} Updated context: ${changed2.join(", ")}`);
21904
+ console.log(` ${chalk28.dim("path:")} ${writtenPath2}`);
21905
+ console.log();
21906
+ return;
21907
+ }
21644
21908
  if (type2 === "capability") {
21645
21909
  const candidatePaths = [
21646
21910
  ...typeof effectiveOpts.paths === "string" ? splitList(effectiveOpts.paths) : [],
@@ -21653,7 +21917,7 @@ async function setEntity(type2, slug, opts) {
21653
21917
  {
21654
21918
  ...opts,
21655
21919
  code: "invalid_route_prefix",
21656
- fix: `iamu set ${type2} ${slug} --paths /${invalid[0]?.replace(/^\/+/, "") || ""}`
21920
+ fix: `iamu set ${type2} ${effectiveSlug} --paths /${invalid[0]?.replace(/^\/+/, "") || ""}`
21657
21921
  }
21658
21922
  );
21659
21923
  return;
@@ -21726,7 +21990,25 @@ var init_set_entity = __esm({
21726
21990
  "state"
21727
21991
  ],
21728
21992
  persona: ["access"],
21729
- capability: ["paths", "addPath", "removePath", "area"]
21993
+ capability: ["paths", "addPath", "removePath", "area"],
21994
+ outline: ["capability", "additionalCapabilities"],
21995
+ testability: [
21996
+ "target",
21997
+ "devCommand",
21998
+ "authStrategy",
21999
+ "access",
22000
+ "harnesses",
22001
+ "untestableBoundaries",
22002
+ "body"
22003
+ ],
22004
+ context: [
22005
+ "domain",
22006
+ "industry",
22007
+ "jurisdiction",
22008
+ "notes",
22009
+ "description",
22010
+ "body"
22011
+ ]
21730
22012
  };
21731
22013
  FLAG_NAMES = {
21732
22014
  entry: "--entry",
@@ -21738,7 +22020,20 @@ var init_set_entity = __esm({
21738
22020
  paths: "--paths",
21739
22021
  addPath: "--add-path",
21740
22022
  removePath: "--remove-path",
21741
- area: "--area"
22023
+ area: "--area",
22024
+ capability: "--capability",
22025
+ additionalCapabilities: "--additional-capabilities",
22026
+ devCommand: "--dev-command",
22027
+ authStrategy: "--auth-strategy",
22028
+ harnesses: "--harnesses",
22029
+ untestableBoundaries: "--untestable-boundaries",
22030
+ domain: "--domain",
22031
+ industry: "--industry",
22032
+ jurisdiction: "--jurisdiction",
22033
+ notes: "--notes",
22034
+ description: "--description",
22035
+ name: "--name",
22036
+ body: "--body"
21742
22037
  };
21743
22038
  }
21744
22039
  });
@@ -22999,7 +23294,7 @@ __export(instructions_walk_exports, {
22999
23294
  revisitSection: () => revisitSection,
23000
23295
  viewportLine: () => viewportLine
23001
23296
  });
23002
- import { existsSync as existsSync16, readFileSync as readFileSync9 } from "fs";
23297
+ import { existsSync as existsSync16, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
23003
23298
  import { join as join9 } from "path";
23004
23299
  import chalk31 from "chalk";
23005
23300
  function selfCommand() {
@@ -23386,8 +23681,17 @@ async function instructionsWalk(opts) {
23386
23681
  state: sfm.state ?? null,
23387
23682
  context: contextYml,
23388
23683
  untestableBoundaries
23389
- }) : null
23684
+ }) : null,
23685
+ walker_prompt_path: null
23390
23686
  };
23687
+ if (runDirPath && result.walker_prompt) {
23688
+ try {
23689
+ const promptPath = join9(runDirPath, "walker_prompt.txt");
23690
+ writeFileSync4(promptPath, result.walker_prompt, "utf-8");
23691
+ result.walker_prompt_path = promptPath;
23692
+ } catch {
23693
+ }
23694
+ }
23391
23695
  if (opts.json) {
23392
23696
  console.log(JSON.stringify(result, null, 2));
23393
23697
  return;
@@ -24408,13 +24712,25 @@ async function evaluateRecord(runId, opts) {
24408
24712
  });
24409
24713
  return;
24410
24714
  }
24715
+ const defaultVerdictsPath = path34.join(runDirPath, "verdicts.json");
24411
24716
  if (!opts.file && !opts.data) {
24412
- commandError("Either --file <path> or --data <json> is required", {
24413
- ...opts,
24414
- code: "missing_verdicts_input",
24415
- fix: "iamu evaluate-record --file verdicts.json"
24416
- });
24417
- return;
24717
+ let hasExisting = false;
24718
+ try {
24719
+ await fs32.access(defaultVerdictsPath);
24720
+ hasExisting = true;
24721
+ } catch {
24722
+ hasExisting = false;
24723
+ }
24724
+ if (hasExisting) {
24725
+ opts.file = defaultVerdictsPath;
24726
+ } else {
24727
+ commandError("Either --file <path> or --data <json> is required", {
24728
+ ...opts,
24729
+ code: "missing_verdicts_input",
24730
+ fix: `iamu evaluate-record ${runId} --data '<json>'`
24731
+ });
24732
+ return;
24733
+ }
24418
24734
  }
24419
24735
  let parsedFile;
24420
24736
  try {
@@ -25371,13 +25687,25 @@ async function matchRecord(runId, opts) {
25371
25687
  });
25372
25688
  const manifest = await completedManifest2(runDirPath, runId, opts);
25373
25689
  if (!manifest) return;
25690
+ const defaultMatchesPath = path36.join(runDirPath, "matches.json");
25374
25691
  if (!opts.file && !opts.data) {
25375
- commandError("Either --file <path> or --data <json> is required", {
25376
- ...opts,
25377
- code: "missing_matches_input",
25378
- fix: "iamu match-record --file matches.json"
25379
- });
25380
- return;
25692
+ let hasExisting = false;
25693
+ try {
25694
+ await fs34.access(defaultMatchesPath);
25695
+ hasExisting = true;
25696
+ } catch {
25697
+ hasExisting = false;
25698
+ }
25699
+ if (hasExisting) {
25700
+ opts.file = defaultMatchesPath;
25701
+ } else {
25702
+ commandError("Either --file <path> or --data <json> is required", {
25703
+ ...opts,
25704
+ code: "missing_matches_input",
25705
+ fix: `iamu match-record ${runId} --data '<json>'`
25706
+ });
25707
+ return;
25708
+ }
25381
25709
  }
25382
25710
  let answer;
25383
25711
  try {
@@ -25811,12 +26139,12 @@ function registerProjectCommands(program) {
25811
26139
  await newEntity2(type2, opts);
25812
26140
  }
25813
26141
  );
25814
- program.command("set <type> <slug>").helpGroup("Project:").description(
25815
- "Change how an entity is staged: a scenario's start path, target and starting state, a persona's access key, a capability's routes (scenario, persona, capability)"
26142
+ program.command("set <type> [slug]").helpGroup("Project:").description(
26143
+ "Change how an entity is staged: a scenario's start path, target and starting state, a persona's access key, a capability's routes, or project testability / context (scenario, persona, capability, testability, context)"
25816
26144
  ).option(
25817
26145
  "--entry <path>",
25818
26146
  "Where the walk starts, as a path on the product (scenario)"
25819
- ).option("--no-entry", "Clear the start path (scenario)").option("--target <url>", "Default target URL (scenario)").option("--no-target", "Clear the default target URL (scenario)").option(
26147
+ ).option("--no-entry", "Clear the start path (scenario)").option("--target <url>", "Default target URL (scenario, testability)").option("--no-target", "Clear the default target URL (scenario)").option(
25820
26148
  "--state-description <text>",
25821
26149
  "What the world must contain, in domain words (scenario)"
25822
26150
  ).option(
@@ -25824,8 +26152,8 @@ function registerProjectCommands(program) {
25824
26152
  "How the walker picks the closest record when the exact one is missing (scenario)"
25825
26153
  ).option("--no-state", "Clear the starting state (scenario)").option(
25826
26154
  "--access <key>",
25827
- "Account, role or switcher key this persona uses (persona)"
25828
- ).option("--no-access", "Clear the access key (persona)").option(
26155
+ "Account, role or switcher key this persona uses (persona, testability)"
26156
+ ).option("--no-access", "Clear the access key (persona, testability)").option(
25829
26157
  "--paths <paths>",
25830
26158
  "Route prefixes, comma-separated; replaces the list (capability)"
25831
26159
  ).option("--no-paths", "Clear route prefixes (capability)").option(
@@ -25836,12 +26164,27 @@ function registerProjectCommands(program) {
25836
26164
  "--remove-path <path>",
25837
26165
  "Remove a route prefix (capability, repeatable)",
25838
26166
  (val, prev = []) => [...prev, val]
25839
- ).option("--area <name>", "Visual grouping category (capability)").option("--no-area", "Clear the area (capability)").option(
26167
+ ).option("--area <name>", "Visual grouping category (capability)").option("--no-area", "Clear the area (capability)").option("--capability <slug>", "Primary capability slug (outline)").option("--no-capability", "Clear primary capability (outline)").option(
26168
+ "--additional-capabilities <slugs>",
26169
+ "Secondary capability slugs, comma-separated (outline)"
26170
+ ).option(
26171
+ "--no-additional-capabilities",
26172
+ "Clear secondary capabilities (outline)"
26173
+ ).option("--dev-command <cmd>", "Dev startup command (testability)").option("--no-dev-command", "Clear dev startup command (testability)").option("--auth-strategy <strategy>", "Auth strategy (testability)").option("--no-auth-strategy", "Clear auth strategy (testability)").option(
26174
+ "--harnesses <list>",
26175
+ "Mock frameworks or seed scripts, comma-separated (testability)"
26176
+ ).option("--no-harnesses", "Clear harnesses (testability)").option(
26177
+ "--untestable-boundaries <list>",
26178
+ "Forbidden external endpoints, comma-separated (testability)"
26179
+ ).option(
26180
+ "--no-untestable-boundaries",
26181
+ "Clear untestable boundaries (testability)"
26182
+ ).option("--domain <text>", "Domain name (context)").option("--industry <text>", "Industry category (context)").option("--jurisdiction <text>", "Jurisdiction or region (context)").option("--notes <text>", "Orientation notes (context)").option("--description <text>", "Project description (context)").option("--name <text>", "Project name (context)").option("--body <text>", "Markdown narrative body (testability, context)").option(
25840
26183
  "--file <path>",
25841
26184
  "JSON patch file to apply staging fields (or - for stdin)"
25842
26185
  ).option("--json", "Output as JSON").addHelpText(
25843
26186
  "after",
25844
- '\nWhat a scenario is about (narrative, tension, human tests, brief) is not set here.\n\nExamples:\n $ iamu set scenario maria--handoff --entry /incidents --state-description "Five open incidents at one site"\n $ iamu set persona maria --access coordinator@site-a.test\n $ iamu set capability team-access --add-path /team\n $ iamu set scenario maria--handoff --file patch.json'
26187
+ '\nWhat a scenario is about (narrative, tension, human tests, brief) is not set here.\n\nExamples:\n $ iamu set scenario maria--handoff --entry /incidents --state-description "Five open incidents at one site"\n $ iamu set persona maria --access coordinator@site-a.test\n $ iamu set outline shift-handoff --capability incident-reporting\n $ iamu set capability team-access --add-path /team\n $ iamu set testability --target http://localhost:5173 --dev-command "./dev" --auth-strategy dev_switcher\n $ iamu set context --domain "Workplace safety" --industry "Manufacturing" --description "..."\n $ iamu set scenario maria--handoff --file patch.json'
25845
26188
  ).action(
25846
26189
  async (type2, slug, opts) => {
25847
26190
  const { setEntity: setEntity2 } = await Promise.resolve().then(() => (init_set_entity(), set_entity_exports));
@@ -25960,41 +26303,65 @@ function registerWalkthroughCommands(program) {
25960
26303
  "--surface <text>",
25961
26304
  `"browse" (default) for iamu browse, or a description of your own browser tool \u2014 becomes the walker prompt's Driving surface section`
25962
26305
  ).option("--json", "Output as JSON").action(
25963
- async (phase, slug, opts) => {
26306
+ async (phase, slug, opts, cmd) => {
26307
+ const effectiveOpts = {
26308
+ ...cmd.optsWithGlobals(),
26309
+ ...opts
26310
+ };
25964
26311
  const { instructions: instructions2 } = await Promise.resolve().then(() => (init_instructions(), instructions_exports));
25965
- await instructions2(phase, slug, opts);
26312
+ await instructions2(phase, slug, effectiveOpts);
25966
26313
  }
25967
26314
  );
25968
26315
  instrCmd.command("walk [scenario-slug]").description("Compose walking prompt from scenario + persona + outline").option("--scenario <slug>", "Scenario slug (default: active scenario)").option("--run <run-id>", "Run ID (resolves target URL from manifest)").option(
25969
26316
  "--surface <text>",
25970
26317
  `"browse" (default) for iamu browse, or a description of your own browser tool \u2014 becomes the walker prompt's Driving surface section`
25971
26318
  ).option("--json", "Output as JSON").action(
25972
- async (scenarioSlug, opts) => {
26319
+ async (scenarioSlug, opts, cmd) => {
26320
+ const effectiveOpts = {
26321
+ ...cmd.parent?.opts(),
26322
+ ...cmd.optsWithGlobals(),
26323
+ ...opts
26324
+ };
25973
26325
  const { instructionsWalk: instructionsWalk2 } = await Promise.resolve().then(() => (init_instructions_walk(), instructions_walk_exports));
25974
26326
  await instructionsWalk2({
25975
- ...opts,
25976
- scenario: scenarioSlug ?? opts.scenario
26327
+ ...effectiveOpts,
26328
+ scenario: scenarioSlug ?? effectiveOpts.scenario
25977
26329
  });
25978
26330
  }
25979
26331
  );
25980
26332
  instrCmd.command("stage [scenario-slug]").description(
25981
26333
  "Dynamic staging instructions: persona, outline, tension, boundaries"
25982
26334
  ).option("--json", "Output as JSON").action(
25983
- async (scenarioSlug, opts) => {
26335
+ async (scenarioSlug, opts, cmd) => {
26336
+ const effectiveOpts = {
26337
+ ...cmd.parent?.opts(),
26338
+ ...cmd.optsWithGlobals(),
26339
+ ...opts
26340
+ };
25984
26341
  const { instructionsStage: instructionsStage2 } = await Promise.resolve().then(() => (init_instructions(), instructions_exports));
25985
- await instructionsStage2(scenarioSlug, opts);
26342
+ await instructionsStage2(scenarioSlug, effectiveOpts);
25986
26343
  }
25987
26344
  );
25988
- instrCmd.command("setup").description("Dynamic project setup instructions & prerequisite checks").option("--json", "Output as JSON").action(async (opts) => {
26345
+ instrCmd.command("setup").description("Dynamic project setup instructions & prerequisite checks").option("--json", "Output as JSON").action(async (opts, cmd) => {
26346
+ const effectiveOpts = {
26347
+ ...cmd.parent?.opts(),
26348
+ ...cmd.optsWithGlobals(),
26349
+ ...opts
26350
+ };
25989
26351
  const { instructionsSetup: instructionsSetup2 } = await Promise.resolve().then(() => (init_instructions(), instructions_exports));
25990
- await instructionsSetup2(opts);
26352
+ await instructionsSetup2(effectiveOpts);
25991
26353
  });
25992
26354
  instrCmd.command("triage [run-or-scenario-slug]").description(
25993
26355
  "Dynamic triage instructions: finding triage, confirmation, dismissal guidance"
25994
26356
  ).option("--run <run-id>", "Run ID to triage findings for").option("--json", "Output as JSON").action(
25995
- async (slug, opts) => {
26357
+ async (slug, opts, cmd) => {
26358
+ const effectiveOpts = {
26359
+ ...cmd.parent?.opts(),
26360
+ ...cmd.optsWithGlobals(),
26361
+ ...opts
26362
+ };
25996
26363
  const { instructionsTriage: instructionsTriage2 } = await Promise.resolve().then(() => (init_instructions(), instructions_exports));
25997
- await instructionsTriage2(slug, opts);
26364
+ await instructionsTriage2(slug, effectiveOpts);
25998
26365
  }
25999
26366
  );
26000
26367
  program.command("browse <command> [args...]").helpGroup("Walkthrough:").description(
@@ -26132,7 +26499,14 @@ function registerWalkthroughCommands(program) {
26132
26499
  );
26133
26500
  program.command("match-record <run-id>").helpGroup("Walkthrough:").description(
26134
26501
  "Record finding matches and re-derive the run's since-last-run delta"
26135
- ).option("--file <path>", "Path to matches JSON file (or - for stdin)").option("--data <json>", "Inline matches JSON string").option("--json", "Output match results as JSON").action(
26502
+ ).option("--file <path>", "Path to matches JSON file (or - for stdin)").option("--data <json>", "Inline matches JSON string").option("--json", "Output match results as JSON").addHelpText(
26503
+ "after",
26504
+ `
26505
+ Examples:
26506
+ $ iamu match-record <run-id> --data '{"matches":[]}'
26507
+ $ iamu match-record <run-id> --file matches.json
26508
+ $ iamu match-record <run-id> --json`
26509
+ ).action(
26136
26510
  async (runId, opts) => {
26137
26511
  const { matchRecord: matchRecord2 } = await Promise.resolve().then(() => (init_match(), match_exports));
26138
26512
  await matchRecord2(runId, opts);
@@ -26146,7 +26520,13 @@ function registerWalkthroughCommands(program) {
26146
26520
  );
26147
26521
  program.command("evaluate-record <run-id>").helpGroup("Walkthrough:").description("Record evaluation verdicts into the run's verdicts.json").option("--file <path>", "Path to verdicts JSON file (or - for stdin)").option("--data <json>", "Inline verdicts JSON string").option("--json", "Output summary as JSON").option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--no-push", "Skip pushing the updated run to Iamu Cloud").option("--view", "Open results in browser immediately without prompt").addHelpText(
26148
26522
  "after",
26149
- "\nExamples:\n $ iamu evaluate-record <run-id> --file verdicts.json\n $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt\n $ iamu evaluate-record <run-id> --file verdicts.json --no-push\n $ iamu evaluate-record <run-id> --file verdicts.json --json"
26523
+ `
26524
+ Examples:
26525
+ $ iamu evaluate-record <run-id> --data '{"verdicts":[]}' --no-prompt --no-push
26526
+ $ iamu evaluate-record <run-id> --file verdicts.json
26527
+ $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt
26528
+ $ iamu evaluate-record <run-id> --file verdicts.json --no-push
26529
+ $ iamu evaluate-record <run-id> --file verdicts.json --json`
26150
26530
  ).action(
26151
26531
  async (runId, opts) => {
26152
26532
  const { evaluateRecord: evaluateRecord2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));