@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/bin.js CHANGED
@@ -5460,10 +5460,20 @@ async function readTestability(projectRoot) {
5460
5460
  body: parsed.body
5461
5461
  };
5462
5462
  }
5463
+ async function writeTestability(projectRoot, input, body) {
5464
+ const p = testabilityPath(projectRoot);
5465
+ const isLocalDoc = "frontmatter" in input && typeof input.frontmatter === "object";
5466
+ const fm = isLocalDoc ? input.frontmatter : input;
5467
+ const effectiveBody = body !== void 0 ? body : isLocalDoc ? input.body : "";
5468
+ const validated = testabilityFrontmatterSchema.parse(fm);
5469
+ const serialized = serializeFrontmatter(validated, effectiveBody);
5470
+ await atomicWriteFile(p, serialized);
5471
+ }
5463
5472
  var init_testability2 = __esm({
5464
5473
  "../../packages/local-store/dist/testability.js"() {
5465
5474
  "use strict";
5466
5475
  init_dist();
5476
+ init_atomic();
5467
5477
  init_markdown();
5468
5478
  init_paths();
5469
5479
  }
@@ -8622,7 +8632,7 @@ function formatRefError(err) {
8622
8632
  const dir = ENTITY_DIRS[err.missing_ref];
8623
8633
  const hint = MISSING_REF_HINTS[err.missing_ref] ?? "";
8624
8634
  if (!err.missing_slug) {
8625
- 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`;
8635
+ 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`;
8626
8636
  return `${err.entity_type} ${err.entity_slug || err.entity_id}: ${err.missing_ref} slug is missing from frontmatter \u2014 ${fieldHint}`;
8627
8637
  }
8628
8638
  return `${err.entity_type} ${err.entity_slug || err.entity_id}: \`${err.missing_slug}\` not found in iamu/${dir}/${hint}`;
@@ -8636,7 +8646,7 @@ var init_refs = __esm({
8636
8646
  init_sync_tracking();
8637
8647
  init_walkthrough_mirror();
8638
8648
  MISSING_REF_HINTS = {
8639
- capability: " \u2014 create it with `iamu new capability` or check the slug in frontmatter",
8649
+ capability: " \u2014 create it with `iamu new capability` or set with `iamu set outline <slug> --capability <slug>`",
8640
8650
  outline: " \u2014 create it with `iamu new` or verify the slug matches a file in iamu/outlines/",
8641
8651
  persona: " \u2014 create it with `iamu new persona` or check the slug",
8642
8652
  scenario: " \u2014 verify the scenario exists locally with `iamu list scenarios`"
@@ -13636,8 +13646,8 @@ import { dirname as dirname3, join as join4, resolve as resolve2 } from "path";
13636
13646
  import { fileURLToPath as fileURLToPath2 } from "url";
13637
13647
  import chalk6 from "chalk";
13638
13648
  function getVersion() {
13639
- if ("0.3.0-beta.0") {
13640
- return "0.3.0-beta.0";
13649
+ if ("0.3.0-beta.1") {
13650
+ return "0.3.0-beta.1";
13641
13651
  }
13642
13652
  try {
13643
13653
  const thisDir = dirname3(fileURLToPath2(import.meta.url));
@@ -20873,6 +20883,15 @@ function validateFile(filePath, raw, projectRoot) {
20873
20883
  );
20874
20884
  }
20875
20885
  }
20886
+ if (type2 === "outline" && zodResult.success) {
20887
+ const fm = zodResult.data;
20888
+ if (!fm.primary_capability && !fm.capability) {
20889
+ result.warnings = result.warnings ?? [];
20890
+ result.warnings.push(
20891
+ `outline has no primary capability \u2014 sync will require one (run \`iamu set outline ${fm.slug ?? "<slug>"} --capability <slug>\`)`
20892
+ );
20893
+ }
20894
+ }
20876
20895
  return result;
20877
20896
  }
20878
20897
  async function buildRepairLookups(projectRoot) {
@@ -21441,6 +21460,15 @@ async function newEntity(type2, opts) {
21441
21460
  );
21442
21461
  return;
21443
21462
  }
21463
+ if (entityType === "outline" && !opts.capability) {
21464
+ try {
21465
+ const { entities } = await listEntities(projectRoot, "capability");
21466
+ if (entities.length === 1 && typeof entities[0].frontmatter.slug === "string") {
21467
+ opts.capability = entities[0].frontmatter.slug;
21468
+ }
21469
+ } catch {
21470
+ }
21471
+ }
21444
21472
  const id = randomUUID10();
21445
21473
  const frontmatter = defaultFrontmatter(entityType, id, slug, opts.name, opts);
21446
21474
  const body = opts.body ?? (entityType === "outline" ? "" : opts.narrative) ?? "";
@@ -21559,6 +21587,42 @@ function applyChanges(type2, fm, opts) {
21559
21587
  put("paths", paths);
21560
21588
  }
21561
21589
  if (opts.area !== void 0) put("area", opts.area || null);
21590
+ } else if (type2 === "outline") {
21591
+ if (opts.capability === false) {
21592
+ put("primary_capability", null);
21593
+ put("capability", null);
21594
+ } else if (opts.capability !== void 0) {
21595
+ put("primary_capability", opts.capability || null);
21596
+ put("capability", opts.capability || null);
21597
+ }
21598
+ if (opts.additionalCapabilities === false) {
21599
+ put("additional_capabilities", []);
21600
+ } else if (opts.additionalCapabilities !== void 0) {
21601
+ const caps = typeof opts.additionalCapabilities === "string" ? splitList(opts.additionalCapabilities) : Array.isArray(opts.additionalCapabilities) ? opts.additionalCapabilities : [];
21602
+ put("additional_capabilities", caps);
21603
+ }
21604
+ } else if (type2 === "testability") {
21605
+ if (opts.target !== void 0) put("target_url", opts.target || null);
21606
+ if (opts.devCommand !== void 0)
21607
+ put("dev_command", opts.devCommand || null);
21608
+ if (opts.authStrategy !== void 0)
21609
+ put("auth_strategy", opts.authStrategy || null);
21610
+ if (opts.access !== void 0) put("access", opts.access || null);
21611
+ if (opts.harnesses !== void 0) {
21612
+ put("harnesses", opts.harnesses ? splitList(opts.harnesses) : null);
21613
+ }
21614
+ if (opts.untestableBoundaries !== void 0) {
21615
+ put(
21616
+ "untestable_boundaries",
21617
+ opts.untestableBoundaries ? splitList(opts.untestableBoundaries) : null
21618
+ );
21619
+ }
21620
+ } else if (type2 === "context") {
21621
+ if (opts.domain !== void 0) put("domain", opts.domain || null);
21622
+ if (opts.industry !== void 0) put("industry", opts.industry || null);
21623
+ if (opts.jurisdiction !== void 0)
21624
+ put("jurisdiction", opts.jurisdiction || null);
21625
+ if (opts.notes !== void 0) put("notes", opts.notes || null);
21562
21626
  }
21563
21627
  return changed;
21564
21628
  }
@@ -21574,6 +21638,15 @@ async function setEntity(type2, slug, opts) {
21574
21638
  );
21575
21639
  return;
21576
21640
  }
21641
+ if (type2 !== "testability" && type2 !== "context" && !slug) {
21642
+ commandError(`A slug is required when setting a ${type2}.`, {
21643
+ ...opts,
21644
+ code: "missing_slug",
21645
+ fix: `iamu set ${type2} <slug>`
21646
+ });
21647
+ return;
21648
+ }
21649
+ const effectiveSlug = slug || type2;
21577
21650
  const foreign = Object.keys(FLAG_NAMES).filter(
21578
21651
  (k) => !allowed.includes(k) && given(opts, k)
21579
21652
  );
@@ -21583,7 +21656,7 @@ async function setEntity(type2, slug, opts) {
21583
21656
  {
21584
21657
  ...opts,
21585
21658
  code: "invalid_field_combination",
21586
- fix: `iamu set ${type2} ${slug} ${FLAG_NAMES[allowed[0]]} ...`
21659
+ fix: `iamu set ${type2} ${effectiveSlug} ${FLAG_NAMES[allowed[0]]} ...`
21587
21660
  }
21588
21661
  );
21589
21662
  return;
@@ -21624,7 +21697,38 @@ async function setEntity(type2, slug, opts) {
21624
21697
  const allowedPatchKeys = {
21625
21698
  scenario: ["entry", "entry_path", "target", "target_url", "state"],
21626
21699
  persona: ["access"],
21627
- capability: ["paths", "addPath", "removePath", "area"]
21700
+ capability: ["paths", "addPath", "removePath", "area"],
21701
+ outline: [
21702
+ "capability",
21703
+ "primary_capability",
21704
+ "additional_capabilities",
21705
+ "additionalCapabilities"
21706
+ ],
21707
+ testability: [
21708
+ "target",
21709
+ "target_url",
21710
+ "devCommand",
21711
+ "dev_command",
21712
+ "authStrategy",
21713
+ "auth_strategy",
21714
+ "access",
21715
+ "harnesses",
21716
+ "untestableBoundaries",
21717
+ "untestable_boundaries",
21718
+ "body"
21719
+ ],
21720
+ context: [
21721
+ "domain",
21722
+ "industry",
21723
+ "jurisdiction",
21724
+ "notes",
21725
+ "description",
21726
+ "name",
21727
+ "governed_by",
21728
+ "actors",
21729
+ "terminology",
21730
+ "body"
21731
+ ]
21628
21732
  };
21629
21733
  const foreignPatchKeys = Object.keys(parsed).filter(
21630
21734
  (k) => !allowedPatchKeys[type2]?.includes(k)
@@ -21683,6 +21787,65 @@ async function setEntity(type2, slug, opts) {
21683
21787
  if (effectiveOpts.area === void 0 && parsed.area !== void 0) {
21684
21788
  effectiveOpts.area = parsed.area === null || parsed.area === false ? false : String(parsed.area);
21685
21789
  }
21790
+ } else if (type2 === "outline") {
21791
+ if (effectiveOpts.capability === void 0 && (parsed.capability !== void 0 || parsed.primary_capability !== void 0)) {
21792
+ const v = parsed.capability ?? parsed.primary_capability;
21793
+ effectiveOpts.capability = v === null || v === false ? false : String(v);
21794
+ }
21795
+ if (effectiveOpts.additionalCapabilities === void 0 && (parsed.additionalCapabilities !== void 0 || parsed.additional_capabilities !== void 0)) {
21796
+ const v = parsed.additionalCapabilities ?? parsed.additional_capabilities;
21797
+ effectiveOpts.additionalCapabilities = v === null || v === false ? false : Array.isArray(v) ? v.join(",") : String(v);
21798
+ }
21799
+ } else if (type2 === "testability") {
21800
+ if (effectiveOpts.target === void 0 && (parsed.target !== void 0 || parsed.target_url !== void 0)) {
21801
+ const v = parsed.target ?? parsed.target_url;
21802
+ effectiveOpts.target = v === null || v === false ? false : String(v);
21803
+ }
21804
+ if (effectiveOpts.devCommand === void 0 && (parsed.devCommand !== void 0 || parsed.dev_command !== void 0)) {
21805
+ const v = parsed.devCommand ?? parsed.dev_command;
21806
+ effectiveOpts.devCommand = v === null || v === false ? false : String(v);
21807
+ }
21808
+ if (effectiveOpts.authStrategy === void 0 && (parsed.authStrategy !== void 0 || parsed.auth_strategy !== void 0)) {
21809
+ const v = parsed.authStrategy ?? parsed.auth_strategy;
21810
+ effectiveOpts.authStrategy = v === null || v === false ? false : String(v);
21811
+ }
21812
+ if (effectiveOpts.access === void 0 && parsed.access !== void 0) {
21813
+ effectiveOpts.access = parsed.access === null || parsed.access === false ? false : String(parsed.access);
21814
+ }
21815
+ if (effectiveOpts.harnesses === void 0 && parsed.harnesses !== void 0) {
21816
+ effectiveOpts.harnesses = parsed.harnesses === null || parsed.harnesses === false ? false : Array.isArray(parsed.harnesses) ? parsed.harnesses.join(",") : String(parsed.harnesses);
21817
+ }
21818
+ if (effectiveOpts.untestableBoundaries === void 0 && (parsed.untestableBoundaries !== void 0 || parsed.untestable_boundaries !== void 0)) {
21819
+ const b = parsed.untestableBoundaries ?? parsed.untestable_boundaries;
21820
+ effectiveOpts.untestableBoundaries = b === null || b === false ? false : Array.isArray(b) ? b.join(",") : String(b);
21821
+ }
21822
+ if (effectiveOpts.body === void 0 && parsed.body !== void 0) {
21823
+ effectiveOpts.body = String(parsed.body);
21824
+ }
21825
+ } else if (type2 === "context") {
21826
+ if (effectiveOpts.domain === void 0 && parsed.domain !== void 0) {
21827
+ effectiveOpts.domain = parsed.domain === null || parsed.domain === false ? false : String(parsed.domain);
21828
+ }
21829
+ if (effectiveOpts.industry === void 0 && parsed.industry !== void 0) {
21830
+ effectiveOpts.industry = parsed.industry === null || parsed.industry === false ? false : String(parsed.industry);
21831
+ }
21832
+ if (effectiveOpts.jurisdiction === void 0 && parsed.jurisdiction !== void 0) {
21833
+ effectiveOpts.jurisdiction = parsed.jurisdiction === null || parsed.jurisdiction === false ? false : String(parsed.jurisdiction);
21834
+ }
21835
+ if (effectiveOpts.notes === void 0 && parsed.notes !== void 0) {
21836
+ effectiveOpts.notes = parsed.notes === null || parsed.notes === false ? false : String(parsed.notes);
21837
+ }
21838
+ if (effectiveOpts.description === void 0 && parsed.description !== void 0) {
21839
+ effectiveOpts.description = parsed.description === null || parsed.description === false ? false : String(parsed.description);
21840
+ }
21841
+ if (effectiveOpts.name === void 0 && parsed.name !== void 0) {
21842
+ effectiveOpts.name = parsed.name === null || parsed.name === false ? false : String(parsed.name);
21843
+ }
21844
+ if (effectiveOpts.body === void 0 && parsed.body !== void 0) {
21845
+ effectiveOpts.body = String(parsed.body);
21846
+ } else if (effectiveOpts.body === void 0 && effectiveOpts.description !== void 0) {
21847
+ effectiveOpts.body = effectiveOpts.description ? String(effectiveOpts.description) : "";
21848
+ }
21686
21849
  }
21687
21850
  }
21688
21851
  if (!allowed.some((k) => given(effectiveOpts, k))) {
@@ -21691,11 +21854,112 @@ async function setEntity(type2, slug, opts) {
21691
21854
  {
21692
21855
  ...opts,
21693
21856
  code: "nothing_to_set",
21694
- fix: `iamu set ${type2} ${slug} ${FLAG_NAMES[allowed[0]]} ...`
21857
+ fix: `iamu set ${type2}${type2 === "testability" || type2 === "context" ? "" : ` ${effectiveSlug}`} ${FLAG_NAMES[allowed[0]]} ...`
21695
21858
  }
21696
21859
  );
21697
21860
  return;
21698
21861
  }
21862
+ if (type2 === "testability") {
21863
+ const doc = await readTestability(projectRoot) ?? {
21864
+ frontmatter: {
21865
+ schema_version: 1,
21866
+ status: "draft",
21867
+ target_url: "http://localhost:3000"
21868
+ },
21869
+ body: ""
21870
+ };
21871
+ const fm2 = { ...doc.frontmatter };
21872
+ const changed2 = applyChanges(type2, fm2, effectiveOpts);
21873
+ let body = doc.body;
21874
+ if (effectiveOpts.body !== void 0) {
21875
+ body = effectiveOpts.body;
21876
+ changed2.push("body");
21877
+ }
21878
+ const writtenPath2 = testabilityPath(projectRoot);
21879
+ try {
21880
+ await writeTestability(
21881
+ projectRoot,
21882
+ fm2,
21883
+ body
21884
+ );
21885
+ } catch (err) {
21886
+ const message = err instanceof ZodError2 ? err.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ") : err instanceof Error ? err.message : String(err);
21887
+ commandError(`Could not set testability: ${message}`, {
21888
+ ...opts,
21889
+ code: "testability_write_error",
21890
+ fix: "iamu set testability --target <url>"
21891
+ });
21892
+ return;
21893
+ }
21894
+ if (opts.json) {
21895
+ console.log(
21896
+ JSON.stringify({
21897
+ slug: "testability",
21898
+ type: "testability",
21899
+ path: writtenPath2,
21900
+ changed: changed2
21901
+ })
21902
+ );
21903
+ return;
21904
+ }
21905
+ console.log();
21906
+ console.log(
21907
+ ` ${symbols.success} Updated testability: ${changed2.join(", ")}`
21908
+ );
21909
+ console.log(` ${chalk28.dim("path:")} ${writtenPath2}`);
21910
+ console.log();
21911
+ return;
21912
+ }
21913
+ if (type2 === "context") {
21914
+ const doc = await readContext(projectRoot) ?? {
21915
+ frontmatter: {
21916
+ schema_version: SCHEMA_VERSION,
21917
+ status: "draft"
21918
+ },
21919
+ notes_body: ""
21920
+ };
21921
+ const fm2 = { ...doc.frontmatter };
21922
+ const changed2 = applyChanges(type2, fm2, effectiveOpts);
21923
+ let body = doc.notes_body;
21924
+ if (effectiveOpts.body !== void 0) {
21925
+ body = effectiveOpts.body;
21926
+ changed2.push("body");
21927
+ } else if (effectiveOpts.description !== void 0) {
21928
+ body = effectiveOpts.description ? String(effectiveOpts.description) : "";
21929
+ changed2.push("body");
21930
+ }
21931
+ const writtenPath2 = contextPath(projectRoot);
21932
+ try {
21933
+ await writeContext(projectRoot, {
21934
+ frontmatter: fm2,
21935
+ notes_body: body
21936
+ });
21937
+ } catch (err) {
21938
+ const message = err instanceof ZodError2 ? err.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ") : err instanceof Error ? err.message : String(err);
21939
+ commandError(`Could not set context: ${message}`, {
21940
+ ...opts,
21941
+ code: "context_write_error",
21942
+ fix: "iamu set context --domain <domain>"
21943
+ });
21944
+ return;
21945
+ }
21946
+ if (opts.json) {
21947
+ console.log(
21948
+ JSON.stringify({
21949
+ slug: "context",
21950
+ type: "context",
21951
+ path: writtenPath2,
21952
+ changed: changed2
21953
+ })
21954
+ );
21955
+ return;
21956
+ }
21957
+ console.log();
21958
+ console.log(` ${symbols.success} Updated context: ${changed2.join(", ")}`);
21959
+ console.log(` ${chalk28.dim("path:")} ${writtenPath2}`);
21960
+ console.log();
21961
+ return;
21962
+ }
21699
21963
  if (type2 === "capability") {
21700
21964
  const candidatePaths = [
21701
21965
  ...typeof effectiveOpts.paths === "string" ? splitList(effectiveOpts.paths) : [],
@@ -21708,7 +21972,7 @@ async function setEntity(type2, slug, opts) {
21708
21972
  {
21709
21973
  ...opts,
21710
21974
  code: "invalid_route_prefix",
21711
- fix: `iamu set ${type2} ${slug} --paths /${invalid[0]?.replace(/^\/+/, "") || ""}`
21975
+ fix: `iamu set ${type2} ${effectiveSlug} --paths /${invalid[0]?.replace(/^\/+/, "") || ""}`
21712
21976
  }
21713
21977
  );
21714
21978
  return;
@@ -21781,7 +22045,25 @@ var init_set_entity = __esm({
21781
22045
  "state"
21782
22046
  ],
21783
22047
  persona: ["access"],
21784
- capability: ["paths", "addPath", "removePath", "area"]
22048
+ capability: ["paths", "addPath", "removePath", "area"],
22049
+ outline: ["capability", "additionalCapabilities"],
22050
+ testability: [
22051
+ "target",
22052
+ "devCommand",
22053
+ "authStrategy",
22054
+ "access",
22055
+ "harnesses",
22056
+ "untestableBoundaries",
22057
+ "body"
22058
+ ],
22059
+ context: [
22060
+ "domain",
22061
+ "industry",
22062
+ "jurisdiction",
22063
+ "notes",
22064
+ "description",
22065
+ "body"
22066
+ ]
21785
22067
  };
21786
22068
  FLAG_NAMES = {
21787
22069
  entry: "--entry",
@@ -21793,7 +22075,20 @@ var init_set_entity = __esm({
21793
22075
  paths: "--paths",
21794
22076
  addPath: "--add-path",
21795
22077
  removePath: "--remove-path",
21796
- area: "--area"
22078
+ area: "--area",
22079
+ capability: "--capability",
22080
+ additionalCapabilities: "--additional-capabilities",
22081
+ devCommand: "--dev-command",
22082
+ authStrategy: "--auth-strategy",
22083
+ harnesses: "--harnesses",
22084
+ untestableBoundaries: "--untestable-boundaries",
22085
+ domain: "--domain",
22086
+ industry: "--industry",
22087
+ jurisdiction: "--jurisdiction",
22088
+ notes: "--notes",
22089
+ description: "--description",
22090
+ name: "--name",
22091
+ body: "--body"
21797
22092
  };
21798
22093
  }
21799
22094
  });
@@ -23054,7 +23349,7 @@ __export(instructions_walk_exports, {
23054
23349
  revisitSection: () => revisitSection,
23055
23350
  viewportLine: () => viewportLine
23056
23351
  });
23057
- import { existsSync as existsSync16, readFileSync as readFileSync9 } from "fs";
23352
+ import { existsSync as existsSync16, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
23058
23353
  import { join as join9 } from "path";
23059
23354
  import chalk31 from "chalk";
23060
23355
  function selfCommand() {
@@ -23441,8 +23736,17 @@ async function instructionsWalk(opts) {
23441
23736
  state: sfm.state ?? null,
23442
23737
  context: contextYml,
23443
23738
  untestableBoundaries
23444
- }) : null
23739
+ }) : null,
23740
+ walker_prompt_path: null
23445
23741
  };
23742
+ if (runDirPath && result.walker_prompt) {
23743
+ try {
23744
+ const promptPath = join9(runDirPath, "walker_prompt.txt");
23745
+ writeFileSync4(promptPath, result.walker_prompt, "utf-8");
23746
+ result.walker_prompt_path = promptPath;
23747
+ } catch {
23748
+ }
23749
+ }
23446
23750
  if (opts.json) {
23447
23751
  console.log(JSON.stringify(result, null, 2));
23448
23752
  return;
@@ -24463,13 +24767,25 @@ async function evaluateRecord(runId, opts) {
24463
24767
  });
24464
24768
  return;
24465
24769
  }
24770
+ const defaultVerdictsPath = path34.join(runDirPath, "verdicts.json");
24466
24771
  if (!opts.file && !opts.data) {
24467
- commandError("Either --file <path> or --data <json> is required", {
24468
- ...opts,
24469
- code: "missing_verdicts_input",
24470
- fix: "iamu evaluate-record --file verdicts.json"
24471
- });
24472
- return;
24772
+ let hasExisting = false;
24773
+ try {
24774
+ await fs32.access(defaultVerdictsPath);
24775
+ hasExisting = true;
24776
+ } catch {
24777
+ hasExisting = false;
24778
+ }
24779
+ if (hasExisting) {
24780
+ opts.file = defaultVerdictsPath;
24781
+ } else {
24782
+ commandError("Either --file <path> or --data <json> is required", {
24783
+ ...opts,
24784
+ code: "missing_verdicts_input",
24785
+ fix: `iamu evaluate-record ${runId} --data '<json>'`
24786
+ });
24787
+ return;
24788
+ }
24473
24789
  }
24474
24790
  let parsedFile;
24475
24791
  try {
@@ -25426,13 +25742,25 @@ async function matchRecord(runId, opts) {
25426
25742
  });
25427
25743
  const manifest = await completedManifest2(runDirPath, runId, opts);
25428
25744
  if (!manifest) return;
25745
+ const defaultMatchesPath = path36.join(runDirPath, "matches.json");
25429
25746
  if (!opts.file && !opts.data) {
25430
- commandError("Either --file <path> or --data <json> is required", {
25431
- ...opts,
25432
- code: "missing_matches_input",
25433
- fix: "iamu match-record --file matches.json"
25434
- });
25435
- return;
25747
+ let hasExisting = false;
25748
+ try {
25749
+ await fs34.access(defaultMatchesPath);
25750
+ hasExisting = true;
25751
+ } catch {
25752
+ hasExisting = false;
25753
+ }
25754
+ if (hasExisting) {
25755
+ opts.file = defaultMatchesPath;
25756
+ } else {
25757
+ commandError("Either --file <path> or --data <json> is required", {
25758
+ ...opts,
25759
+ code: "missing_matches_input",
25760
+ fix: `iamu match-record ${runId} --data '<json>'`
25761
+ });
25762
+ return;
25763
+ }
25436
25764
  }
25437
25765
  let answer;
25438
25766
  try {
@@ -25874,12 +26202,12 @@ function registerProjectCommands(program2) {
25874
26202
  await newEntity2(type2, opts);
25875
26203
  }
25876
26204
  );
25877
- program2.command("set <type> <slug>").helpGroup("Project:").description(
25878
- "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)"
26205
+ program2.command("set <type> [slug]").helpGroup("Project:").description(
26206
+ "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)"
25879
26207
  ).option(
25880
26208
  "--entry <path>",
25881
26209
  "Where the walk starts, as a path on the product (scenario)"
25882
- ).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(
26210
+ ).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(
25883
26211
  "--state-description <text>",
25884
26212
  "What the world must contain, in domain words (scenario)"
25885
26213
  ).option(
@@ -25887,8 +26215,8 @@ function registerProjectCommands(program2) {
25887
26215
  "How the walker picks the closest record when the exact one is missing (scenario)"
25888
26216
  ).option("--no-state", "Clear the starting state (scenario)").option(
25889
26217
  "--access <key>",
25890
- "Account, role or switcher key this persona uses (persona)"
25891
- ).option("--no-access", "Clear the access key (persona)").option(
26218
+ "Account, role or switcher key this persona uses (persona, testability)"
26219
+ ).option("--no-access", "Clear the access key (persona, testability)").option(
25892
26220
  "--paths <paths>",
25893
26221
  "Route prefixes, comma-separated; replaces the list (capability)"
25894
26222
  ).option("--no-paths", "Clear route prefixes (capability)").option(
@@ -25899,12 +26227,27 @@ function registerProjectCommands(program2) {
25899
26227
  "--remove-path <path>",
25900
26228
  "Remove a route prefix (capability, repeatable)",
25901
26229
  (val, prev = []) => [...prev, val]
25902
- ).option("--area <name>", "Visual grouping category (capability)").option("--no-area", "Clear the area (capability)").option(
26230
+ ).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(
26231
+ "--additional-capabilities <slugs>",
26232
+ "Secondary capability slugs, comma-separated (outline)"
26233
+ ).option(
26234
+ "--no-additional-capabilities",
26235
+ "Clear secondary capabilities (outline)"
26236
+ ).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(
26237
+ "--harnesses <list>",
26238
+ "Mock frameworks or seed scripts, comma-separated (testability)"
26239
+ ).option("--no-harnesses", "Clear harnesses (testability)").option(
26240
+ "--untestable-boundaries <list>",
26241
+ "Forbidden external endpoints, comma-separated (testability)"
26242
+ ).option(
26243
+ "--no-untestable-boundaries",
26244
+ "Clear untestable boundaries (testability)"
26245
+ ).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(
25903
26246
  "--file <path>",
25904
26247
  "JSON patch file to apply staging fields (or - for stdin)"
25905
26248
  ).option("--json", "Output as JSON").addHelpText(
25906
26249
  "after",
25907
- '\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'
26250
+ '\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'
25908
26251
  ).action(
25909
26252
  async (type2, slug, opts) => {
25910
26253
  const { setEntity: setEntity2 } = await Promise.resolve().then(() => (init_set_entity(), set_entity_exports));
@@ -26023,41 +26366,65 @@ function registerWalkthroughCommands(program2) {
26023
26366
  "--surface <text>",
26024
26367
  `"browse" (default) for iamu browse, or a description of your own browser tool \u2014 becomes the walker prompt's Driving surface section`
26025
26368
  ).option("--json", "Output as JSON").action(
26026
- async (phase, slug, opts) => {
26369
+ async (phase, slug, opts, cmd) => {
26370
+ const effectiveOpts = {
26371
+ ...cmd.optsWithGlobals(),
26372
+ ...opts
26373
+ };
26027
26374
  const { instructions: instructions2 } = await Promise.resolve().then(() => (init_instructions(), instructions_exports));
26028
- await instructions2(phase, slug, opts);
26375
+ await instructions2(phase, slug, effectiveOpts);
26029
26376
  }
26030
26377
  );
26031
26378
  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(
26032
26379
  "--surface <text>",
26033
26380
  `"browse" (default) for iamu browse, or a description of your own browser tool \u2014 becomes the walker prompt's Driving surface section`
26034
26381
  ).option("--json", "Output as JSON").action(
26035
- async (scenarioSlug, opts) => {
26382
+ async (scenarioSlug, opts, cmd) => {
26383
+ const effectiveOpts = {
26384
+ ...cmd.parent?.opts(),
26385
+ ...cmd.optsWithGlobals(),
26386
+ ...opts
26387
+ };
26036
26388
  const { instructionsWalk: instructionsWalk2 } = await Promise.resolve().then(() => (init_instructions_walk(), instructions_walk_exports));
26037
26389
  await instructionsWalk2({
26038
- ...opts,
26039
- scenario: scenarioSlug ?? opts.scenario
26390
+ ...effectiveOpts,
26391
+ scenario: scenarioSlug ?? effectiveOpts.scenario
26040
26392
  });
26041
26393
  }
26042
26394
  );
26043
26395
  instrCmd.command("stage [scenario-slug]").description(
26044
26396
  "Dynamic staging instructions: persona, outline, tension, boundaries"
26045
26397
  ).option("--json", "Output as JSON").action(
26046
- async (scenarioSlug, opts) => {
26398
+ async (scenarioSlug, opts, cmd) => {
26399
+ const effectiveOpts = {
26400
+ ...cmd.parent?.opts(),
26401
+ ...cmd.optsWithGlobals(),
26402
+ ...opts
26403
+ };
26047
26404
  const { instructionsStage: instructionsStage2 } = await Promise.resolve().then(() => (init_instructions(), instructions_exports));
26048
- await instructionsStage2(scenarioSlug, opts);
26405
+ await instructionsStage2(scenarioSlug, effectiveOpts);
26049
26406
  }
26050
26407
  );
26051
- instrCmd.command("setup").description("Dynamic project setup instructions & prerequisite checks").option("--json", "Output as JSON").action(async (opts) => {
26408
+ instrCmd.command("setup").description("Dynamic project setup instructions & prerequisite checks").option("--json", "Output as JSON").action(async (opts, cmd) => {
26409
+ const effectiveOpts = {
26410
+ ...cmd.parent?.opts(),
26411
+ ...cmd.optsWithGlobals(),
26412
+ ...opts
26413
+ };
26052
26414
  const { instructionsSetup: instructionsSetup2 } = await Promise.resolve().then(() => (init_instructions(), instructions_exports));
26053
- await instructionsSetup2(opts);
26415
+ await instructionsSetup2(effectiveOpts);
26054
26416
  });
26055
26417
  instrCmd.command("triage [run-or-scenario-slug]").description(
26056
26418
  "Dynamic triage instructions: finding triage, confirmation, dismissal guidance"
26057
26419
  ).option("--run <run-id>", "Run ID to triage findings for").option("--json", "Output as JSON").action(
26058
- async (slug, opts) => {
26420
+ async (slug, opts, cmd) => {
26421
+ const effectiveOpts = {
26422
+ ...cmd.parent?.opts(),
26423
+ ...cmd.optsWithGlobals(),
26424
+ ...opts
26425
+ };
26059
26426
  const { instructionsTriage: instructionsTriage2 } = await Promise.resolve().then(() => (init_instructions(), instructions_exports));
26060
- await instructionsTriage2(slug, opts);
26427
+ await instructionsTriage2(slug, effectiveOpts);
26061
26428
  }
26062
26429
  );
26063
26430
  program2.command("browse <command> [args...]").helpGroup("Walkthrough:").description(
@@ -26195,7 +26562,14 @@ function registerWalkthroughCommands(program2) {
26195
26562
  );
26196
26563
  program2.command("match-record <run-id>").helpGroup("Walkthrough:").description(
26197
26564
  "Record finding matches and re-derive the run's since-last-run delta"
26198
- ).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(
26565
+ ).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(
26566
+ "after",
26567
+ `
26568
+ Examples:
26569
+ $ iamu match-record <run-id> --data '{"matches":[]}'
26570
+ $ iamu match-record <run-id> --file matches.json
26571
+ $ iamu match-record <run-id> --json`
26572
+ ).action(
26199
26573
  async (runId, opts) => {
26200
26574
  const { matchRecord: matchRecord2 } = await Promise.resolve().then(() => (init_match(), match_exports));
26201
26575
  await matchRecord2(runId, opts);
@@ -26209,7 +26583,13 @@ function registerWalkthroughCommands(program2) {
26209
26583
  );
26210
26584
  program2.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(
26211
26585
  "after",
26212
- "\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"
26586
+ `
26587
+ Examples:
26588
+ $ iamu evaluate-record <run-id> --data '{"verdicts":[]}' --no-prompt --no-push
26589
+ $ iamu evaluate-record <run-id> --file verdicts.json
26590
+ $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt
26591
+ $ iamu evaluate-record <run-id> --file verdicts.json --no-push
26592
+ $ iamu evaluate-record <run-id> --file verdicts.json --json`
26213
26593
  ).action(
26214
26594
  async (runId, opts) => {
26215
26595
  const { evaluateRecord: evaluateRecord2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));