@iamu-dev/iamu 0.8.0-beta.5 → 0.8.0-beta.6

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
@@ -6688,7 +6688,7 @@ var init_wire_compat = __esm({
6688
6688
  function cloudSupportsGuidance(capabilities) {
6689
6689
  return Boolean(capabilities?.includes(GUIDANCE_CAPABILITY) || capabilities?.includes(DESIGNER_FINDINGS_CAPABILITY));
6690
6690
  }
6691
- async function fetchServerCapabilities(apiUrl, apiKey, fetchFn, timeoutMs, onFailure) {
6691
+ async function fetchServerCapabilities(apiUrl, apiKey, fetchFn, timeoutMs, onFailure, onServerClock) {
6692
6692
  const controller = new AbortController();
6693
6693
  const timer = setTimeout(() => controller.abort(), timeoutMs);
6694
6694
  try {
@@ -6698,6 +6698,9 @@ async function fetchServerCapabilities(apiUrl, apiKey, fetchFn, timeoutMs, onFai
6698
6698
  signal: controller.signal
6699
6699
  };
6700
6700
  const res = await fetchFn(`${apiUrl.replace(/\/+$/, "")}/api/meta`, init2);
6701
+ const offset = serverClockOffset(res);
6702
+ if (offset !== null)
6703
+ onServerClock?.(offset);
6701
6704
  if (res.status === 404)
6702
6705
  return [];
6703
6706
  if (!res.ok) {
@@ -6719,6 +6722,16 @@ async function fetchServerCapabilities(apiUrl, apiKey, fetchFn, timeoutMs, onFai
6719
6722
  clearTimeout(timer);
6720
6723
  }
6721
6724
  }
6725
+ function serverClockOffset(res) {
6726
+ const headers = res?.headers;
6727
+ if (!headers || typeof headers.get !== "function")
6728
+ return null;
6729
+ const raw = headers.get.call(headers, "date");
6730
+ if (typeof raw !== "string")
6731
+ return null;
6732
+ const at = Date.parse(raw);
6733
+ return Number.isNaN(at) ? null : at - Date.now();
6734
+ }
6722
6735
  function shapeForServer(pending, capabilities) {
6723
6736
  const knows = capabilities.includes(DESIGNER_FINDINGS_CAPABILITY);
6724
6737
  const knowsProvenance = capabilities.includes(FINDING_PROVENANCE_CAPABILITY);
@@ -10688,7 +10701,7 @@ function compareIso(a, b) {
10688
10701
  return ta - tb;
10689
10702
  return String(a ?? "").localeCompare(String(b ?? ""));
10690
10703
  }
10691
- async function designerFindingsOn(projectRoot, screens, before, targetUrl = null) {
10704
+ async function designerFindingsOn(projectRoot, screens, before, targetUrl = null, settled = /* @__PURE__ */ new Set()) {
10692
10705
  const latest = /* @__PURE__ */ new Map();
10693
10706
  const cache = /* @__PURE__ */ new Map();
10694
10707
  const wanted = new Set([...screens].map((k) => normalizeScreenKey(k, targetUrl)));
@@ -10712,7 +10725,7 @@ async function designerFindingsOn(projectRoot, screens, before, targetUrl = null
10712
10725
  }
10713
10726
  const all = [...latest.values()].sort((a, b) => compareIso(a.created_at, b.created_at));
10714
10727
  return {
10715
- open: all.filter(unsettled).map((fm, n) => ({
10728
+ open: all.filter((fm) => unsettled(fm) && !settled.has(fm.id)).map((fm, n) => ({
10716
10729
  ref: `P${n + 1}`,
10717
10730
  id: fm.id,
10718
10731
  title: fm.title ?? fm.slug,
@@ -11205,6 +11218,26 @@ async function readReviewEvidence(projectRoot) {
11205
11218
  }
11206
11219
  return out2;
11207
11220
  }
11221
+ async function verifiedDesignerFixes(projectRoot, before) {
11222
+ const addressed = (await listDesignerFindings(projectRoot)).map((f) => f.frontmatter).filter((fm) => fm.triage_status === "addressed" && !fm.design_cause_of);
11223
+ const out2 = /* @__PURE__ */ new Set();
11224
+ if (addressed.length === 0)
11225
+ return out2;
11226
+ const cutoff = toMillis(before);
11227
+ const runs = (await readRunEvidence(projectRoot)).filter((r) => {
11228
+ if (cutoff === null)
11229
+ return true;
11230
+ const start2 = toMillis(r.started_at);
11231
+ return start2 !== null && start2 < cutoff;
11232
+ });
11233
+ const states = deriveFixStates(addressed, runs);
11234
+ for (const fm of addressed) {
11235
+ if (fm.fix_status === "verified_resolved" || states.get(fm.slug)?.fix_state === "verified") {
11236
+ out2.add(fm.id);
11237
+ }
11238
+ }
11239
+ return out2;
11240
+ }
11208
11241
  async function computeFixStates(projectRoot) {
11209
11242
  const { entities } = await listEntities(projectRoot, "finding");
11210
11243
  const findings2 = entities.map((e) => e.frontmatter);
@@ -12266,6 +12299,7 @@ async function canonicalFindingFiles(projectRoot, scenarioSlug, canonicalId) {
12266
12299
  return out2;
12267
12300
  }
12268
12301
  async function markAddressedResolved(files, note) {
12302
+ const failed = [];
12269
12303
  const trimmedNote = note?.trim();
12270
12304
  for (const f of files) {
12271
12305
  if (f.triage_status !== "addressed")
@@ -12281,9 +12315,14 @@ async function markAddressedResolved(files, note) {
12281
12315
  if (updated !== raw)
12282
12316
  await atomicWriteFile(f.file, updated);
12283
12317
  });
12284
- } catch {
12318
+ } catch (err) {
12319
+ failed.push({
12320
+ file: f.file,
12321
+ error: err instanceof Error ? err.message : String(err)
12322
+ });
12285
12323
  }
12286
12324
  }
12325
+ return failed;
12287
12326
  }
12288
12327
  function originOf(url) {
12289
12328
  if (!url)
@@ -12466,7 +12505,9 @@ async function updateFixStatus(projectRoot, slug, status2) {
12466
12505
  await atomicWriteFile(filePath, updated);
12467
12506
  }
12468
12507
  });
12469
- } catch {
12508
+ return null;
12509
+ } catch (err) {
12510
+ return err instanceof Error ? err.message : String(err);
12470
12511
  }
12471
12512
  }
12472
12513
  async function listRunsInternal(projectRoot) {
@@ -12916,6 +12957,7 @@ async function mirrorLocalWalkthrough(projectRoot, runId, deps) {
12916
12957
  body: form,
12917
12958
  signal: controller.signal
12918
12959
  });
12960
+ const clockOffset = serverClockOffset(response);
12919
12961
  if (response.ok) {
12920
12962
  let body = null;
12921
12963
  try {
@@ -12961,7 +13003,8 @@ async function mirrorLocalWalkthrough(projectRoot, runId, deps) {
12961
13003
  runCloudId: parsed.data.cloud_walkthrough_id,
12962
13004
  contentHash,
12963
13005
  cloudOutcome: parsed.data.status,
12964
- ...recordedFindings.length > 0 ? { recordedFindings } : {}
13006
+ ...recordedFindings.length > 0 ? { recordedFindings } : {},
13007
+ ...clockOffset !== null ? { serverClockOffsetMs: clockOffset } : {}
12965
13008
  };
12966
13009
  }
12967
13010
  if (response.status === 409) {
@@ -13608,6 +13651,7 @@ async function drainRetryQueue(projectRoot, deps) {
13608
13651
  const deleteUrl = projectEndpoint(config.cloud_api_url, config.cloud_project_id, "delete");
13609
13652
  const remaining = [];
13610
13653
  const failures = [];
13654
+ const pushedRuns = [];
13611
13655
  let drained = 0;
13612
13656
  let dropped = 0;
13613
13657
  let notAttempted = 0;
@@ -13719,6 +13763,8 @@ async function drainRetryQueue(projectRoot, deps) {
13719
13763
  });
13720
13764
  if (result.mirrored || result.skippedReason === "bundle_too_large") {
13721
13765
  drained++;
13766
+ if (result.status === "pushed")
13767
+ pushedRuns.push(entry.entity_id);
13722
13768
  } else if (result.skippedReason === "missing_run" || result.skippedReason === "unsupported") {
13723
13769
  drained++;
13724
13770
  } else if (result.skippedReason === "cloud_conflict") {
@@ -13810,7 +13856,8 @@ async function drainRetryQueue(projectRoot, deps) {
13810
13856
  dropped,
13811
13857
  remaining: after.length,
13812
13858
  failures,
13813
- warnings
13859
+ warnings,
13860
+ ...pushedRuns.length > 0 ? { pushedRuns } : {}
13814
13861
  };
13815
13862
  }
13816
13863
  function unreadableBody(text, isDelete) {
@@ -14256,10 +14303,50 @@ async function ownEarlierWrites(projectRoot, batch, conflicts) {
14256
14303
  }
14257
14304
  return out2;
14258
14305
  }
14306
+ function findingRun(frontmatter) {
14307
+ if (typeof frontmatter.run === "string" && frontmatter.run) {
14308
+ return frontmatter.run;
14309
+ }
14310
+ const seen = frontmatter.seen_in;
14311
+ if (typeof seen !== "string")
14312
+ return null;
14313
+ const i = seen.indexOf(":");
14314
+ return i >= 0 ? seen.slice(i + 1) : seen;
14315
+ }
14316
+ async function rowsFromOwnBundles(projectRoot, batch, conflicts, adopt) {
14317
+ if (!adopt || adopt.runs.size === 0 || conflicts.length === 0)
14318
+ return [];
14319
+ const bases = await readBaseHashes(projectRoot);
14320
+ const byId = new Map(batch.map((e) => [e.id, e]));
14321
+ const out2 = [];
14322
+ for (const c of conflicts) {
14323
+ const entity = byId.get(c.entity_id);
14324
+ if (!entity || entity.type !== "finding")
14325
+ continue;
14326
+ if (!c.cloud_hash?.startsWith("cloud:"))
14327
+ continue;
14328
+ const run = findingRun(entity.frontmatter);
14329
+ if (!run || !adopt.runs.has(run))
14330
+ continue;
14331
+ const at = c.cloud_updated_at ? Date.parse(c.cloud_updated_at) : Number.NaN;
14332
+ const slack = adopt.serverClock ? ADOPT_CLOCK_SLACK_MS : 0;
14333
+ if (Number.isNaN(at) || at < adopt.since - slack)
14334
+ continue;
14335
+ if (adopt.identity && c.cloud_changed_by !== adopt.identity)
14336
+ continue;
14337
+ await recordCloudBase(projectRoot, c.entity_id, c.cloud_hash);
14338
+ out2.push({
14339
+ entity,
14340
+ restamped: Boolean(c.base_hash || bases[c.entity_id])
14341
+ });
14342
+ }
14343
+ return out2;
14344
+ }
14259
14345
  async function pushBatches(target, batches, byType, opts = {}) {
14260
14346
  let pushed = 0;
14261
14347
  let enqueued = 0;
14262
14348
  const selfResolved = [];
14349
+ const adopted = [];
14263
14350
  const conflicts = [];
14264
14351
  const overwritten = [];
14265
14352
  const errors = [];
@@ -14281,19 +14368,41 @@ async function pushBatches(target, batches, byType, opts = {}) {
14281
14368
  conflicts,
14282
14369
  overwritten,
14283
14370
  errors,
14284
- selfResolved
14371
+ selfResolved,
14372
+ adopted
14285
14373
  };
14286
14374
  }
14287
14375
  absorb(first);
14288
14376
  let unresolved = first.conflicts;
14289
14377
  const own = await ownEarlierWrites(target.projectRoot, batch, unresolved);
14290
- if (own.length > 0) {
14291
- const ownIds = new Set(own.map((e) => e.id));
14292
- unresolved = unresolved.filter((c) => !ownIds.has(c.entity_id));
14293
- const again = await pushOneBatch(target, own, byType, `batch ${i} own-version retry`);
14378
+ const ownIds = new Set(own.map((e) => e.id));
14379
+ const basesBefore = opts.adopt ? await readCloudBase(target.projectRoot) : {};
14380
+ const fromBundles = await rowsFromOwnBundles(target.projectRoot, batch, unresolved.filter((c) => !ownIds.has(c.entity_id)), opts.adopt);
14381
+ const resend = [...own, ...fromBundles.map((a) => a.entity)];
14382
+ if (resend.length > 0) {
14383
+ const resendIds = new Set(resend.map((e) => e.id));
14384
+ unresolved = unresolved.filter((c) => !resendIds.has(c.entity_id));
14385
+ const again = await pushOneBatch(target, resend, byType, `batch ${i} own-version retry`);
14294
14386
  absorb(again);
14295
14387
  conflicts.push(...again.conflicts);
14296
- selfResolved.push(...again.landed);
14388
+ const landed2 = new Set(again.landed);
14389
+ selfResolved.push(...own.filter((e) => landed2.has(e.id)).map((e) => e.id));
14390
+ for (const a of fromBundles) {
14391
+ if (landed2.has(a.entity.id)) {
14392
+ adopted.push({
14393
+ slug: a.entity.slug,
14394
+ restamped: a.restamped,
14395
+ serverClock: opts.adopt?.serverClock ?? false
14396
+ });
14397
+ continue;
14398
+ }
14399
+ const prior = basesBefore[a.entity.id];
14400
+ if (prior === void 0) {
14401
+ await forgetCloudBase(target.projectRoot, a.entity.id);
14402
+ } else {
14403
+ await recordCloudBase(target.projectRoot, a.entity.id, prior);
14404
+ }
14405
+ }
14297
14406
  }
14298
14407
  if (!opts.keepMine || unresolved.length === 0) {
14299
14408
  conflicts.push(...unresolved);
@@ -14346,8 +14455,17 @@ async function pushBatches(target, batches, byType, opts = {}) {
14346
14455
  }
14347
14456
  await forgetQueuedUpserts(target.projectRoot, revoked);
14348
14457
  }
14349
- return { pushed, enqueued, conflicts, overwritten, errors, selfResolved };
14458
+ return {
14459
+ pushed,
14460
+ enqueued,
14461
+ conflicts,
14462
+ overwritten,
14463
+ errors,
14464
+ selfResolved,
14465
+ adopted
14466
+ };
14350
14467
  }
14468
+ var ADOPT_CLOCK_SLACK_MS;
14351
14469
  var init_push = __esm({
14352
14470
  "../../packages/local-store/dist/sync/push.js"() {
14353
14471
  "use strict";
@@ -14355,6 +14473,7 @@ var init_push = __esm({
14355
14473
  init_server_reason();
14356
14474
  init_sync_tracking();
14357
14475
  init_types();
14476
+ ADOPT_CLOCK_SLACK_MS = 5e3;
14358
14477
  }
14359
14478
  });
14360
14479
 
@@ -14749,15 +14868,33 @@ async function syncWalkthroughs(projectRoot, deps, unpushableScenarios = /* @__P
14749
14868
  const hold = deps.capabilities === null;
14750
14869
  let held = 0;
14751
14870
  const recordedFindings = /* @__PURE__ */ new Set();
14871
+ const pushedRuns = /* @__PURE__ */ new Set();
14872
+ let serverClockOffsetMs = null;
14752
14873
  let runIds;
14753
14874
  try {
14754
14875
  runIds = await listRuns(projectRoot);
14755
14876
  } catch (err) {
14756
14877
  errors.push(`walkthrough scan failed: ${err instanceof Error ? err.message : String(err)} \u2014 check that iamu/.runs/ exists and is readable`);
14757
- return { summary, errors, withheldRuns, held, recordedFindings };
14878
+ return {
14879
+ summary,
14880
+ errors,
14881
+ withheldRuns,
14882
+ held,
14883
+ recordedFindings,
14884
+ pushedRuns,
14885
+ serverClockOffsetMs
14886
+ };
14758
14887
  }
14759
14888
  if (runIds.length === 0)
14760
- return { summary, errors, withheldRuns, held, recordedFindings };
14889
+ return {
14890
+ summary,
14891
+ errors,
14892
+ withheldRuns,
14893
+ held,
14894
+ recordedFindings,
14895
+ pushedRuns,
14896
+ serverClockOffsetMs
14897
+ };
14761
14898
  const lastPush = await readLastPush(projectRoot);
14762
14899
  const pendingWalkthroughQueueEntries = /* @__PURE__ */ new Set();
14763
14900
  const retryQueue = await readRetryQueue(projectRoot);
@@ -14824,6 +14961,9 @@ async function syncWalkthroughs(projectRoot, deps, unpushableScenarios = /* @__P
14824
14961
  });
14825
14962
  if (result.status === "pushed" || result.status === "already_pushed") {
14826
14963
  summary.pushed++;
14964
+ if (result.status === "pushed")
14965
+ pushedRuns.add(runId);
14966
+ serverClockOffsetMs ??= result.serverClockOffsetMs ?? null;
14827
14967
  for (const id of result.recordedFindings ?? [])
14828
14968
  recordedFindings.add(id);
14829
14969
  } else if (result.skippedReason === "bundle_too_large" || result.skippedReason === "unsupported" || result.skippedReason === "missing_run" || result.skippedReason === "cloud_conflict") {
@@ -14846,7 +14986,15 @@ async function syncWalkthroughs(projectRoot, deps, unpushableScenarios = /* @__P
14846
14986
  }
14847
14987
  }
14848
14988
  }
14849
- return { summary, errors, withheldRuns, held, recordedFindings };
14989
+ return {
14990
+ summary,
14991
+ errors,
14992
+ withheldRuns,
14993
+ held,
14994
+ recordedFindings,
14995
+ pushedRuns,
14996
+ serverClockOffsetMs
14997
+ };
14850
14998
  }
14851
14999
  var HOLD_SHAPES, WALKTHROUGH_SKIP_HINTS;
14852
15000
  var init_walkthroughs = __esm({
@@ -14896,6 +15044,7 @@ function mergePushProgress(target, outcome) {
14896
15044
  if (!outcome)
14897
15045
  return;
14898
15046
  target.selfResolved.push(...outcome.selfResolved ?? []);
15047
+ target.adopted.push(...outcome.adopted ?? []);
14899
15048
  target.pushed += outcome.pushed;
14900
15049
  target.enqueued += outcome.enqueued;
14901
15050
  target.conflicts.push(...outcome.conflicts);
@@ -14942,6 +15091,7 @@ async function pushDeferredFindings(projectRoot, capabilities, deferredFindings,
14942
15091
  return pushBatches(target, toBatches(retryFindings, batchSize), byType, pushOpts);
14943
15092
  }
14944
15093
  async function runSync(projectRoot, deps) {
15094
+ const startedAt = Date.now();
14945
15095
  const config = await readConfig(projectRoot);
14946
15096
  if (!config.cloud_linked) {
14947
15097
  return emptySyncResult([
@@ -14956,11 +15106,20 @@ async function runSync(projectRoot, deps) {
14956
15106
  const apiKey = deps.apiKey;
14957
15107
  const fetchFn = deps.fetch ?? globalThis.fetch;
14958
15108
  let capabilitiesFailure = "";
15109
+ let serverClockOffsetMs = null;
14959
15110
  const capabilities = deps.capabilities !== void 0 ? deps.capabilities : await fetchServerCapabilities(config.cloud_api_url, apiKey, fetchFn, deps.timeoutMs ?? DEFAULT_TIMEOUT_MS4, (detail) => {
14960
15111
  capabilitiesFailure = detail;
15112
+ }, (offset) => {
15113
+ serverClockOffsetMs = offset;
14961
15114
  });
14962
15115
  deps = { ...deps, capabilities };
14963
- const drain = await drainRetryQueue(projectRoot, deps);
15116
+ const { pushedRuns: drainedRuns = [], ...drain } = await drainRetryQueue(projectRoot, deps);
15117
+ const adoptFrom = (runs) => ({
15118
+ runs: /* @__PURE__ */ new Set([...drainedRuns, ...runs]),
15119
+ since: startedAt + (serverClockOffsetMs ?? 0),
15120
+ serverClock: serverClockOffsetMs !== null,
15121
+ identity: deps.identity ?? null
15122
+ });
14964
15123
  const scanned = await scanPending(projectRoot);
14965
15124
  if (scanned.errors.length === 0) {
14966
15125
  await pruneSentHashes(projectRoot, scanned.seenIds);
@@ -14984,14 +15143,15 @@ async function runSync(projectRoot, deps) {
14984
15143
  const pushOpts = { keepMine: deps.keepMine };
14985
15144
  const guidance = scan.pending.filter((e) => e.type === "guidance");
14986
15145
  const nonGuidance = scan.pending.filter((e) => e.type !== "guidance");
14987
- const phase1 = await pushBatches(target, toBatches(nonGuidance, batchSize), byType, pushOpts);
15146
+ const phase1 = await pushBatches(target, toBatches(nonGuidance, batchSize), byType, { ...pushOpts, adopt: adoptFrom([]) });
14988
15147
  const progress = {
14989
15148
  pushed: phase1.pushed,
14990
15149
  enqueued: phase1.enqueued,
14991
15150
  conflicts: [...phase1.conflicts],
14992
15151
  overwritten: [...phase1.overwritten],
14993
15152
  errors,
14994
- selfResolved: [...phase1.selfResolved]
15153
+ selfResolved: [...phase1.selfResolved],
15154
+ adopted: [...phase1.adopted]
14995
15155
  };
14996
15156
  progress.errors.push(...phase1.errors);
14997
15157
  const notices = [];
@@ -15001,10 +15161,11 @@ async function runSync(projectRoot, deps) {
15001
15161
  const guidanceResult = await pushGuidanceBatch(target, guidance, batchSize, byType, { ...pushOpts, detectUnsupported: !cloudSupportsGuidance(capabilities) }, notices);
15002
15162
  mergePushProgress(progress, guidanceResult);
15003
15163
  const walkthroughs = await syncWalkthroughs(projectRoot, deps, scan.unpushableScenarios);
15164
+ serverClockOffsetMs ??= walkthroughs.serverClockOffsetMs;
15004
15165
  if (walkthroughs.errors.length > 0) {
15005
15166
  progress.errors.push(...walkthroughs.errors);
15006
15167
  }
15007
- const phase3 = capabilities === null ? null : await pushDeferredFindings(projectRoot, capabilities, deferredFindings, walkthroughs, target, batchSize, byType, pushOpts, reportedRefErrors, progress.errors);
15168
+ const phase3 = capabilities === null ? null : await pushDeferredFindings(projectRoot, capabilities, deferredFindings, walkthroughs, target, batchSize, byType, { ...pushOpts, adopt: adoptFrom(walkthroughs.pushedRuns) }, reportedRefErrors, progress.errors);
15008
15169
  mergePushProgress(progress, phase3);
15009
15170
  if (capabilities === null) {
15010
15171
  const heldFindings = shaped.heldFindings + deferredFindings.size;
@@ -15025,6 +15186,11 @@ async function runSync(projectRoot, deps) {
15025
15186
  const deletion = await syncDeletions(projectRoot, config, deps);
15026
15187
  progress.errors.push(...deletion.errors);
15027
15188
  notices.push(...deletion.notices);
15189
+ for (const a of progress.adopted) {
15190
+ const what = a.restamped ? "overwrote the cloud row re-stamped during this sync (its version token came from this sync's own bundle of the finding's run)" : "overwrote the cloud row stamped during this sync (its version token came from this sync's own bundle)";
15191
+ const clock = a.serverClock ? "" : "; the server sent no clock, so only rows stamped after this sync began by this machine's clock counted";
15192
+ notices.push(`${a.slug}: ${what}${clock}`);
15193
+ }
15028
15194
  if (progress.selfResolved.length > 0) {
15029
15195
  const n = progress.selfResolved.length;
15030
15196
  notices.push(`${n} conflict${n === 1 ? " was" : "s were"} this machine's own earlier push (it reached the cloud without being recorded); re-sent against it`);
@@ -19274,7 +19440,14 @@ async function buildRunDesignerInput(projectRoot, runId) {
19274
19440
  await chooseKeyFrames(rd, grouped.candidates);
19275
19441
  const screens = grouped.screens;
19276
19442
  const screenKeys = new Set(screens.map((s) => s.key));
19277
- const earlier = await designerFindingsOn(projectRoot, screenKeys, manifest?.created_at ?? null, target);
19443
+ const earlier = await designerFindingsOn(
19444
+ projectRoot,
19445
+ screenKeys,
19446
+ manifest?.created_at ?? null,
19447
+ target,
19448
+ // A fix a designer's review already verified is not asked about again.
19449
+ await verifiedDesignerFixes(projectRoot, manifest?.created_at ?? null)
19450
+ );
19278
19451
  for (const o of earlier.open)
19279
19452
  refs2[o.ref] = o.id;
19280
19453
  const fullFrameScreens = new Set(screens.filter((s) => s.visits.some((v) => v.steps.some((st) => existsSync4(path34.join(rd, "screenshots", `step-${st.step}.full.png`))))).map((s) => s.key));
@@ -19430,6 +19603,7 @@ var init_designer_input = __esm({
19430
19603
  init_designer_files();
19431
19604
  init_designer_ignored();
19432
19605
  init_designer_ledger();
19606
+ init_fix_state();
19433
19607
  init_walkthrough_canonical2();
19434
19608
  init_dist();
19435
19609
  LONG_VISIT = 6;
@@ -22382,6 +22556,69 @@ function stepNumberOf(s) {
22382
22556
  const m = /^(?:step-)?(\d+)$/i.exec(s.trim());
22383
22557
  return m ? Number(m[1]) : null;
22384
22558
  }
22559
+ async function writeDesignerFixStatus(projectRoot, runId, verification, checks) {
22560
+ const verified = [];
22561
+ const untriaged = [];
22562
+ const warnings = [];
22563
+ const out2 = { verified, untriaged, warnings };
22564
+ const resolved = new Set(verification.resolved);
22565
+ const persists = new Set(verification.persists);
22566
+ if (resolved.size + persists.size === 0)
22567
+ return out2;
22568
+ const notWritten = (what, err) => warnings.push(`could not update ${what}: ${err instanceof Error ? err.message : String(err)}; designer.json holds the verification`);
22569
+ let files;
22570
+ try {
22571
+ files = (await listDesignerFindings(projectRoot)).map((f) => f.frontmatter).filter((fm) => !fm.design_cause_of && fm.canonical_id && (resolved.has(fm.canonical_id) || persists.has(fm.canonical_id)));
22572
+ } catch (err) {
22573
+ notWritten("the checked findings' fix_status", err);
22574
+ return out2;
22575
+ }
22576
+ const checkOf = new Map(checks.map((c) => [c.canonical_id, c]));
22577
+ for (const cid of verification.resolved) {
22578
+ const mine = files.filter((fm) => fm.canonical_id === cid);
22579
+ if (mine.some((fm) => fm.triage_status === "addressed"))
22580
+ continue;
22581
+ const latest = mine.filter((fm) => fm.triage_status !== "dismissed").sort((a, b) => String(a.created_at ?? "").localeCompare(String(b.created_at ?? ""))).at(-1);
22582
+ if (latest) {
22583
+ untriaged.push({
22584
+ ref: checkOf.get(cid)?.ref ?? null,
22585
+ finding: latest.slug
22586
+ });
22587
+ }
22588
+ }
22589
+ let states;
22590
+ try {
22591
+ states = deriveFixStates(files, await readRunEvidence(projectRoot));
22592
+ } catch (err) {
22593
+ notWritten("the checked findings' fix_status", err);
22594
+ return out2;
22595
+ }
22596
+ const decidedHere = (slug, state) => {
22597
+ const s = states.get(slug);
22598
+ return s?.fix_state === state && s.decided_by === runId;
22599
+ };
22600
+ for (const fm of files) {
22601
+ if (fm.triage_status !== "addressed" || !fm.canonical_id)
22602
+ continue;
22603
+ if (resolved.has(fm.canonical_id) && decidedHere(fm.slug, "verified")) {
22604
+ const [failed] = await markAddressedResolved([
22605
+ {
22606
+ file: entityFilePath(projectRoot, "finding", fm.slug),
22607
+ triage_status: fm.triage_status
22608
+ }
22609
+ ], checkOf.get(fm.canonical_id)?.note ?? void 0);
22610
+ if (failed)
22611
+ notWritten(fm.slug, failed.error);
22612
+ else
22613
+ verified.push(fm.slug);
22614
+ } else if (persists.has(fm.canonical_id) && decidedHere(fm.slug, "recurred")) {
22615
+ const error = await updateFixStatus(projectRoot, fm.slug, "verified_persists");
22616
+ if (error)
22617
+ notWritten(fm.slug, error);
22618
+ }
22619
+ }
22620
+ return out2;
22621
+ }
22385
22622
  async function readRefs2(rd) {
22386
22623
  try {
22387
22624
  return JSON.parse(await fs49.readFile(designerRefsFile(rd), "utf8"));
@@ -22702,6 +22939,11 @@ async function recordDesigner(projectRoot, runId, answer, opts) {
22702
22939
  };
22703
22940
  await atomicWriteFile(file, `${JSON.stringify(record, null, 2)}
22704
22941
  `);
22942
+ const fixes = await writeDesignerFixStatus(projectRoot, runId, verification, checks);
22943
+ warnings.push(...fixes.warnings);
22944
+ for (const u of fixes.untriaged) {
22945
+ warnings.push(`checked ${u.ref ?? "?"}: ${u.finding} is gone but was never marked addressed; its fix_status is left alone (checked_but_untriaged)`);
22946
+ }
22705
22947
  const bySeverity = {};
22706
22948
  const ruleCount = groupDesignerRules(rules);
22707
22949
  for (const i of issues)
@@ -22715,7 +22957,9 @@ async function recordDesigner(projectRoot, runId, answer, opts) {
22715
22957
  proposals: proposals.written,
22716
22958
  rejected,
22717
22959
  warnings,
22718
- ...invalidChecked.length > 0 ? { invalid_checked: invalidChecked } : {}
22960
+ ...invalidChecked.length > 0 ? { invalid_checked: invalidChecked } : {},
22961
+ ...fixes.verified.length > 0 ? { verified: fixes.verified } : {},
22962
+ ...fixes.untriaged.length > 0 ? { checked_but_untriaged: fixes.untriaged } : {}
22719
22963
  };
22720
22964
  }
22721
22965
  var DESIGNER_CATEGORIES, steps, refs, designerAnswerSchema;
@@ -22725,13 +22969,14 @@ var init_designer_record = __esm({
22725
22969
  init_atomic();
22726
22970
  init_design_proposals();
22727
22971
  init_design_review();
22728
- init_paths();
22729
22972
  init_url_path();
22730
22973
  init_review_issues();
22731
22974
  init_designer_files();
22732
22975
  init_designer_input();
22733
22976
  init_designer_ledger();
22734
22977
  init_entity();
22978
+ init_fix_state();
22979
+ init_paths();
22735
22980
  init_walkthrough_canonical2();
22736
22981
  DESIGNER_CATEGORIES = [
22737
22982
  "hierarchy",
@@ -23774,15 +24019,15 @@ function resolveApiUrl(configured) {
23774
24019
  assertSecureApiUrl(url, configured ? "API URL" : "IAMU_API_URL");
23775
24020
  return url;
23776
24021
  }
23777
- function parseStore(raw, path77) {
24022
+ function parseStore(raw, path78) {
23778
24023
  let parsed;
23779
24024
  try {
23780
24025
  parsed = JSON.parse(raw);
23781
24026
  } catch (err) {
23782
- throw new CredentialsFileError(path77, "not valid JSON", err);
24027
+ throw new CredentialsFileError(path78, "not valid JSON", err);
23783
24028
  }
23784
24029
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
23785
- throw new CredentialsFileError(path77, "expected a JSON object");
24030
+ throw new CredentialsFileError(path78, "expected a JSON object");
23786
24031
  }
23787
24032
  return parsed;
23788
24033
  }
@@ -23790,26 +24035,26 @@ function isNotFound(err) {
23790
24035
  return typeof err === "object" && err !== null && err.code === "ENOENT";
23791
24036
  }
23792
24037
  async function readCredentialsStore() {
23793
- const path77 = getCredentialsPath();
24038
+ const path78 = getCredentialsPath();
23794
24039
  let raw;
23795
24040
  try {
23796
- raw = await readFile(path77, "utf-8");
24041
+ raw = await readFile(path78, "utf-8");
23797
24042
  } catch (err) {
23798
24043
  if (isNotFound(err)) return {};
23799
24044
  warnUnreadableStoreOnce(err);
23800
24045
  throw err;
23801
24046
  }
23802
24047
  try {
23803
- return parseStore(raw, path77);
24048
+ return parseStore(raw, path78);
23804
24049
  } catch (err) {
23805
24050
  warnUnreadableStoreOnce(err);
23806
24051
  throw err;
23807
24052
  }
23808
24053
  }
23809
24054
  async function writeCredentialsStore(store) {
23810
- const path77 = getCredentialsPath();
23811
- await mkdir(dirname(path77), { recursive: true, mode: 448 });
23812
- await atomicWriteFile(path77, `${JSON.stringify(store, null, 2)}
24055
+ const path78 = getCredentialsPath();
24056
+ await mkdir(dirname(path78), { recursive: true, mode: 448 });
24057
+ await atomicWriteFile(path78, `${JSON.stringify(store, null, 2)}
23813
24058
  `, {
23814
24059
  mode: 384
23815
24060
  });
@@ -23837,16 +24082,16 @@ function resolveApiKey(apiUrl) {
23837
24082
  }
23838
24083
  }
23839
24084
  const normalized = url.replace(/\/+$/, "");
23840
- for (const path77 of candidatePaths) {
24085
+ for (const path78 of candidatePaths) {
23841
24086
  let raw;
23842
24087
  try {
23843
- raw = readFileSync3(path77, "utf-8");
24088
+ raw = readFileSync3(path78, "utf-8");
23844
24089
  } catch (err) {
23845
24090
  if (!isNotFound(err)) warnUnreadableStoreOnce(err);
23846
24091
  continue;
23847
24092
  }
23848
24093
  try {
23849
- const store = parseStore(raw, path77);
24094
+ const store = parseStore(raw, path78);
23850
24095
  const entry = store[url] ?? store[normalized] ?? store[`${normalized}/`];
23851
24096
  if (typeof entry !== "object" || entry === null) continue;
23852
24097
  const token = entry.token;
@@ -23887,12 +24132,12 @@ var init_credentials = __esm({
23887
24132
  * @param reason - What is wrong with it.
23888
24133
  * @param cause - Underlying parse error, if any.
23889
24134
  */
23890
- constructor(path77, reason, cause) {
24135
+ constructor(path78, reason, cause) {
23891
24136
  super(
23892
- `Credentials file ${path77} is corrupt (${reason}). Fix it by hand, or delete it and run \`iamu auth login\` again.`,
24137
+ `Credentials file ${path78} is corrupt (${reason}). Fix it by hand, or delete it and run \`iamu auth login\` again.`,
23893
24138
  {
23894
24139
  cause,
23895
- suggestedAction: `Delete ${path77} and run \`iamu auth login\`, or set IAMU_TOKEN.`
24140
+ suggestedAction: `Delete ${path78} and run \`iamu auth login\`, or set IAMU_TOKEN.`
23896
24141
  }
23897
24142
  );
23898
24143
  }
@@ -24832,8 +25077,8 @@ import { dirname as dirname3, join as join5, relative, resolve as resolve2 } fro
24832
25077
  import { fileURLToPath as fileURLToPath2 } from "url";
24833
25078
  import chalk6 from "chalk";
24834
25079
  function getVersion() {
24835
- if ("0.8.0-beta.5") {
24836
- return "0.8.0-beta.5";
25080
+ if ("0.8.0-beta.6") {
25081
+ return "0.8.0-beta.6";
24837
25082
  }
24838
25083
  try {
24839
25084
  const thisDir = dirname3(fileURLToPath2(import.meta.url));
@@ -24956,10 +25201,10 @@ function hasGeneratedByMarker(content) {
24956
25201
  function withoutMarker(content) {
24957
25202
  return content.replace(/^generatedBy:[^\r\n]*\r?\n/m, "");
24958
25203
  }
24959
- function cliSkillState(path77, template) {
25204
+ function cliSkillState(path78, template) {
24960
25205
  let content;
24961
25206
  try {
24962
- content = readFileSync7(path77, "utf-8");
25207
+ content = readFileSync7(path78, "utf-8");
24963
25208
  } catch {
24964
25209
  return null;
24965
25210
  }
@@ -24967,9 +25212,9 @@ function cliSkillState(path77, template) {
24967
25212
  if (template === void 0) return "edited";
24968
25213
  return withoutMarker(content) === withoutMarker(template) ? "clean" : "edited";
24969
25214
  }
24970
- function isCliWrittenPrompt(path77) {
25215
+ function isCliWrittenPrompt(path78) {
24971
25216
  try {
24972
- const content = readFileSync7(path77, "utf-8");
25217
+ const content = readFileSync7(path78, "utf-8");
24973
25218
  return hasGeneratedByMarker(content) || /^#\s+iamu:/m.test(content) || /^description:\s*.*iamu/im.test(content);
24974
25219
  } catch {
24975
25220
  return false;
@@ -24979,10 +25224,10 @@ function planSkillFiles(hosts, projectRoot, version2) {
24979
25224
  const skillTemplates = loadSkillTemplates(version2);
24980
25225
  const files = [];
24981
25226
  const keptEdited = [];
24982
- const removeIfClean = (host, path77, name) => {
24983
- const state = cliSkillState(path77, skillTemplates.get(name));
24984
- if (state === "clean") files.push({ host, path: path77, content: null });
24985
- else if (state === "edited") keptEdited.push({ host, path: path77 });
25227
+ const removeIfClean = (host, path78, name) => {
25228
+ const state = cliSkillState(path78, skillTemplates.get(name));
25229
+ if (state === "clean") files.push({ host, path: path78, content: null });
25230
+ else if (state === "edited") keptEdited.push({ host, path: path78 });
24986
25231
  };
24987
25232
  for (const host of hosts) {
24988
25233
  if (pluginProvidesSkills(host, projectRoot)) {
@@ -25079,9 +25324,9 @@ async function findStaleSkills(projectRoot) {
25079
25324
  }
25080
25325
  return stale;
25081
25326
  }
25082
- async function removeSkillFile(path77) {
25083
- await rm(path77, { force: true });
25084
- await rmdir(dirname3(path77)).catch(() => {
25327
+ async function removeSkillFile(path78) {
25328
+ await rm(path78, { force: true });
25329
+ await rmdir(dirname3(path78)).catch(() => {
25085
25330
  });
25086
25331
  }
25087
25332
  async function installSkillsForHosts(hosts, projectRoot, version2, opts) {
@@ -25883,29 +26128,29 @@ async function writeSyncMcpEntry(mcpPath) {
25883
26128
  return { removedLegacy };
25884
26129
  }
25885
26130
  async function registerSyncMcpForHost(host, projectRoot) {
25886
- const path77 = host.getMcpConfigPath(projectRoot);
25887
- if (path77 === null) {
26131
+ const path78 = host.getMcpConfigPath(projectRoot);
26132
+ if (path78 === null) {
25888
26133
  return {
25889
26134
  status: "manual",
25890
26135
  instruction: host.manualMcpSetup ?? `add an "iamu-sync" server that runs \`${SYNC_SERVER_COMMAND.join(" ")}\``
25891
26136
  };
25892
26137
  }
25893
26138
  try {
25894
- const { removedLegacy } = await writeSyncMcpEntry(path77);
25895
- return { status: "written", path: path77, removedLegacy };
26139
+ const { removedLegacy } = await writeSyncMcpEntry(path78);
26140
+ return { status: "written", path: path78, removedLegacy };
25896
26141
  } catch (err) {
25897
26142
  return {
25898
26143
  status: "failed",
25899
- path: path77,
26144
+ path: path78,
25900
26145
  message: err instanceof Error ? err.message : String(err)
25901
26146
  };
25902
26147
  }
25903
26148
  }
25904
26149
  async function removeLegacyMcpForHost(host, projectRoot) {
25905
- const path77 = host.getMcpConfigPath(projectRoot);
25906
- if (path77 === null) return null;
26150
+ const path78 = host.getMcpConfigPath(projectRoot);
26151
+ if (path78 === null) return null;
25907
26152
  try {
25908
- return await removeLegacyIamuEntry(path77) ? { status: "legacy_removed", path: path77, removedLegacy: true } : null;
26153
+ return await removeLegacyIamuEntry(path78) ? { status: "legacy_removed", path: path78, removedLegacy: true } : null;
25909
26154
  } catch {
25910
26155
  return null;
25911
26156
  }
@@ -33483,6 +33728,7 @@ __export(triage_exports, {
33483
33728
  triage: () => triage
33484
33729
  });
33485
33730
  import { promises as fs65 } from "fs";
33731
+ import path62 from "path";
33486
33732
  import chalk29 from "chalk";
33487
33733
  async function awaitingSteps(projectRoot, findings2) {
33488
33734
  const scenarios = /* @__PURE__ */ new Set();
@@ -33621,14 +33867,53 @@ async function triage(refs2, opts) {
33621
33867
  );
33622
33868
  return;
33623
33869
  }
33870
+ let note = opts.note;
33871
+ if (opts.noteFile !== void 0) {
33872
+ if (opts.note !== void 0) {
33873
+ commandError("Pass --note or --note-file, not both.", {
33874
+ ...opts,
33875
+ code: "invalid_field_combination",
33876
+ fix: `iamu triage ${refs2.join(" ")} --status ${status2.data} --note-file <path>`
33877
+ });
33878
+ return;
33879
+ }
33880
+ try {
33881
+ const text = opts.noteFile === "-" ? await readStdinText() : await fs65.readFile(
33882
+ path62.resolve(process.cwd(), opts.noteFile),
33883
+ "utf8"
33884
+ );
33885
+ note = text.trim();
33886
+ } catch (err) {
33887
+ commandError(
33888
+ `Could not read --note-file ${opts.noteFile}: ${err instanceof Error ? err.message : String(err)}`,
33889
+ {
33890
+ ...opts,
33891
+ code: "note_read_error",
33892
+ fix: `iamu triage ${refs2.join(" ")} --status ${status2.data} --note "<what changed>"`
33893
+ }
33894
+ );
33895
+ return;
33896
+ }
33897
+ if (!note) {
33898
+ commandError(`--note-file ${opts.noteFile} is empty`, {
33899
+ ...opts,
33900
+ code: "note_empty",
33901
+ fix: `iamu triage ${refs2.join(" ")} --status ${status2.data} --note "<what changed>"`
33902
+ });
33903
+ return;
33904
+ }
33905
+ }
33624
33906
  let reason = null;
33625
33907
  if (opts.reason !== void 0) {
33626
33908
  if (status2.data !== "dismissed") {
33627
- commandError("--reason applies only to --status dismissed", {
33628
- ...opts,
33629
- code: "invalid_reason_usage",
33630
- fix: `iamu triage ${refs2.join(" ")} --status dismissed --reason ${opts.reason}`
33631
- });
33909
+ commandError(
33910
+ "--reason applies only to --status dismissed \u2014 to record why or what changed, use --note",
33911
+ {
33912
+ ...opts,
33913
+ code: "invalid_reason_usage",
33914
+ fix: `iamu triage ${refs2.join(" ")} --status ${status2.data} --note "<what changed>"`
33915
+ }
33916
+ );
33632
33917
  return;
33633
33918
  }
33634
33919
  if (!DISMISS_REASONS.includes(opts.reason)) {
@@ -33820,7 +34105,7 @@ async function triage(refs2, opts) {
33820
34105
  const rule = await createGuidanceRule(projectRoot, {
33821
34106
  kind: effectiveReason,
33822
34107
  rule: ruleText,
33823
- reason: opts.note,
34108
+ reason: note,
33824
34109
  scope,
33825
34110
  sourceCanonicalIds: allTargets.map((f) => f.frontmatter.canonical_id).filter((id) => Boolean(id && UUID_RE4.test(id)))
33826
34111
  });
@@ -33831,7 +34116,7 @@ async function triage(refs2, opts) {
33831
34116
  status: status2.data,
33832
34117
  reason: effectiveReason,
33833
34118
  duplicateOf: duplicateTarget,
33834
- ...opts.note !== void 0 ? { note: opts.note } : {},
34119
+ ...note !== void 0 ? { note } : {},
33835
34120
  by: "triage",
33836
34121
  cascade: true,
33837
34122
  guidance: guidance ? { id: guidance.id, all: isSweep } : null,
@@ -33916,6 +34201,7 @@ var init_triage = __esm({
33916
34201
  init_dist2();
33917
34202
  init_dist();
33918
34203
  init_agent_commands();
34204
+ init_answer_input();
33919
34205
  init_complete();
33920
34206
  init_context4();
33921
34207
  SCOPES = ["project", "outline", "capability"];
@@ -34383,7 +34669,7 @@ var init_browse_driver = __esm({
34383
34669
 
34384
34670
  // src/commands/browse-actions.ts
34385
34671
  import { existsSync as existsSync15 } from "fs";
34386
- import path62 from "path";
34672
+ import path63 from "path";
34387
34673
  function byRole(page, role, name, opts) {
34388
34674
  const loc = page.getByRole(role, { name, exact: false });
34389
34675
  if (opts.nth !== void 0) {
@@ -34684,7 +34970,7 @@ async function fillIndexedElement(page, index, text, submit) {
34684
34970
  await fillOrSelect(loc.first(), text, submit);
34685
34971
  }
34686
34972
  async function setFilesOnElement(el, filePath) {
34687
- const resolved = path62.resolve(filePath);
34973
+ const resolved = path63.resolve(filePath);
34688
34974
  if (SENSITIVE_UPLOAD_PATH.test(resolved)) {
34689
34975
  throw new Error(
34690
34976
  `Refusing to upload sensitive path: "${resolved}". Choose a test fixture file inside the project or temp directory.`
@@ -34917,7 +35203,7 @@ var init_browse_actions = __esm({
34917
35203
 
34918
35204
  // src/commands/step-numbering.ts
34919
35205
  import { open, readFile as readFile6, readdir, stat as stat2, unlink } from "fs/promises";
34920
- import path63 from "path";
35206
+ import path64 from "path";
34921
35207
  function reservationMarker() {
34922
35208
  const marker = {
34923
35209
  reservation: { pid: process.pid, ts: Date.now() }
@@ -34959,7 +35245,7 @@ async function peekNextStepNumber(stepsDir) {
34959
35245
  for (const f of files) {
34960
35246
  const m = /^(\d+)\.json$/.exec(f);
34961
35247
  if (!m) continue;
34962
- const fullPath = path63.join(stepsDir, f);
35248
+ const fullPath = path64.join(stepsDir, f);
34963
35249
  const st = await stat2(fullPath).catch(() => null);
34964
35250
  if (!st) continue;
34965
35251
  if (await isAbandonedReservation(fullPath, st)) {
@@ -34977,7 +35263,7 @@ async function reserveStepFile(stepsDir, limit) {
34977
35263
  if (candidate > limit.maxSteps) {
34978
35264
  throw new Error(stepLimitMessage(limit.maxSteps, limit.runId));
34979
35265
  }
34980
- const stepPath = path63.join(stepsDir, stepFileName(candidate));
35266
+ const stepPath = path64.join(stepsDir, stepFileName(candidate));
34981
35267
  try {
34982
35268
  const handle = await open(stepPath, "wx");
34983
35269
  try {
@@ -35023,7 +35309,7 @@ __export(step_exports, {
35023
35309
  });
35024
35310
  import { existsSync as existsSync16 } from "fs";
35025
35311
  import { copyFile, mkdir as mkdir4, rename, stat as stat3 } from "fs/promises";
35026
- import path64 from "path";
35312
+ import path65 from "path";
35027
35313
  import chalk31 from "chalk";
35028
35314
  function parseMaxSteps(val) {
35029
35315
  if (typeof val === "number" && Number.isFinite(val) && val > 0) return val;
@@ -35039,11 +35325,11 @@ function parseMaxSteps(val) {
35039
35325
  }
35040
35326
  async function recordStep(input) {
35041
35327
  const runDirPath = runDir(input.projectRoot, input.runId);
35042
- if (!existsSync16(path64.join(runDirPath, "walkthrough.json"))) {
35328
+ if (!existsSync16(path65.join(runDirPath, "walkthrough.json"))) {
35043
35329
  throw new Error(`Run not found: ${input.runId}`);
35044
35330
  }
35045
- const stepsDir = path64.join(runDirPath, "steps");
35046
- const screenshotsDir = path64.join(runDirPath, "screenshots");
35331
+ const stepsDir = path65.join(runDirPath, "steps");
35332
+ const screenshotsDir = path65.join(runDirPath, "screenshots");
35047
35333
  await mkdir4(stepsDir, { recursive: true });
35048
35334
  await mkdir4(screenshotsDir, { recursive: true });
35049
35335
  const shotSource = input.shot ? await existingShot(input.shot) : null;
@@ -35058,9 +35344,9 @@ async function recordStep(input) {
35058
35344
  let screenshotRef = null;
35059
35345
  if (shotSource) {
35060
35346
  const destName = `step-${stepNumber2}.png`;
35061
- const destPath = path64.join(screenshotsDir, destName);
35347
+ const destPath = path65.join(screenshotsDir, destName);
35062
35348
  finalScreenshotPath = destPath;
35063
- if (path64.resolve(destPath) !== shotSource) {
35349
+ if (path65.resolve(destPath) !== shotSource) {
35064
35350
  if (input.moveShot) {
35065
35351
  await rename(shotSource, destPath).catch(
35066
35352
  () => copyFile(shotSource, destPath)
@@ -35069,16 +35355,16 @@ async function recordStep(input) {
35069
35355
  await copyFile(shotSource, destPath);
35070
35356
  }
35071
35357
  }
35072
- screenshotRef = path64.posix.join("screenshots", destName);
35358
+ screenshotRef = path65.posix.join("screenshots", destName);
35073
35359
  }
35074
35360
  let fullRef = null;
35075
35361
  if (input.fullShot && existsSync16(input.fullShot)) {
35076
35362
  const fullName = `step-${stepNumber2}.full.png`;
35077
35363
  const moved = await rename(
35078
35364
  input.fullShot,
35079
- path64.join(screenshotsDir, fullName)
35365
+ path65.join(screenshotsDir, fullName)
35080
35366
  ).then(() => true).catch(() => false);
35081
- if (moved) fullRef = path64.posix.join("screenshots", fullName);
35367
+ if (moved) fullRef = path65.posix.join("screenshots", fullName);
35082
35368
  }
35083
35369
  parsedStep = runStepSchema.parse({
35084
35370
  step_number: stepNumber2,
@@ -35125,7 +35411,7 @@ async function recordStep(input) {
35125
35411
  };
35126
35412
  }
35127
35413
  async function existingShot(shot) {
35128
- const resolved = path64.resolve(shot);
35414
+ const resolved = path65.resolve(shot);
35129
35415
  const isFile = await stat3(resolved).then((s) => s.isFile()).catch(() => false);
35130
35416
  if (!isFile) {
35131
35417
  throw new Error(
@@ -35186,7 +35472,7 @@ async function stepCommand(runArg, opts) {
35186
35472
  {
35187
35473
  step_number: res.step.step_number,
35188
35474
  cancelled: true,
35189
- path: path64.relative(projectRoot, res.stepPath).split(path64.sep).join("/"),
35475
+ path: path65.relative(projectRoot, res.stepPath).split(path65.sep).join("/"),
35190
35476
  action: res.step.action,
35191
35477
  note: res.step.note,
35192
35478
  url: res.step.url,
@@ -35214,7 +35500,7 @@ async function stepCommand(runArg, opts) {
35214
35500
  JSON.stringify(
35215
35501
  {
35216
35502
  step_number: res.step.step_number,
35217
- path: path64.relative(projectRoot, res.stepPath).split(path64.sep).join("/"),
35503
+ path: path65.relative(projectRoot, res.stepPath).split(path65.sep).join("/"),
35218
35504
  action: res.step.action,
35219
35505
  note: res.step.note,
35220
35506
  url: res.step.url,
@@ -35243,7 +35529,7 @@ async function stepCommand(runArg, opts) {
35243
35529
  console.log(` ${chalk31.dim("shot:")} ${res.step.screenshot}`);
35244
35530
  }
35245
35531
  console.log(
35246
- ` ${chalk31.dim("file:")} ${path64.relative(projectRoot, res.stepPath)}`
35532
+ ` ${chalk31.dim("file:")} ${path65.relative(projectRoot, res.stepPath)}`
35247
35533
  );
35248
35534
  console.log();
35249
35535
  } else {
@@ -35315,16 +35601,16 @@ import {
35315
35601
  import { rm as rm2 } from "fs/promises";
35316
35602
  import { createServer } from "net";
35317
35603
  import { homedir as homedir3 } from "os";
35318
- import path65 from "path";
35604
+ import path66 from "path";
35319
35605
  import chalk32 from "chalk";
35320
35606
  function stateDir() {
35321
- return path65.join(
35322
- process.env.IAMU_HOME ?? path65.join(homedir3(), ".iamu"),
35607
+ return path66.join(
35608
+ process.env.IAMU_HOME ?? path66.join(homedir3(), ".iamu"),
35323
35609
  "browse"
35324
35610
  );
35325
35611
  }
35326
35612
  function profileDir() {
35327
- return path65.join(stateDir(), "profile");
35613
+ return path66.join(stateDir(), "profile");
35328
35614
  }
35329
35615
  function privateDir(dir) {
35330
35616
  mkdirSync3(dir, { recursive: true, mode: 448 });
@@ -35335,7 +35621,7 @@ function privateDir(dir) {
35335
35621
  }
35336
35622
  function stateFile(run) {
35337
35623
  const key = run && STATE_KEY.test(run) && `${run}.json` !== SHARED_STATE ? `${run}.json` : SHARED_STATE;
35338
- return path65.join(stateDir(), key);
35624
+ return path66.join(stateDir(), key);
35339
35625
  }
35340
35626
  function loadState(file) {
35341
35627
  try {
@@ -35376,7 +35662,7 @@ function storedStates() {
35376
35662
  }
35377
35663
  const out2 = [];
35378
35664
  for (const name of names2.sort()) {
35379
- const file = path65.join(stateDir(), name);
35665
+ const file = path66.join(stateDir(), name);
35380
35666
  const state = loadState(file);
35381
35667
  if (state) out2.push({ state, file });
35382
35668
  }
@@ -35394,16 +35680,16 @@ function removeState(file) {
35394
35680
  }
35395
35681
  function runStillOpen(state, now = Date.now()) {
35396
35682
  if (!state.run || !state.project) return false;
35397
- const dir = path65.join(state.project, "iamu", ".runs", state.run);
35683
+ const dir = path66.join(state.project, "iamu", ".runs", state.run);
35398
35684
  try {
35399
- const manifestPath = path65.join(dir, "walkthrough.json");
35685
+ const manifestPath = path66.join(dir, "walkthrough.json");
35400
35686
  const manifest = JSON.parse(readFileSync10(manifestPath, "utf8"));
35401
35687
  if (typeof manifest.status !== "string" || !OPEN_RUN_STATUSES.has(manifest.status)) {
35402
35688
  return false;
35403
35689
  }
35404
35690
  let last = statSync3(manifestPath).mtimeMs;
35405
35691
  try {
35406
- last = Math.max(last, statSync3(path65.join(dir, "steps")).mtimeMs);
35692
+ last = Math.max(last, statSync3(path66.join(dir, "steps")).mtimeMs);
35407
35693
  } catch {
35408
35694
  }
35409
35695
  return now - last < RUN_IDLE_MS;
@@ -35502,7 +35788,7 @@ async function requestedViewport(opts) {
35502
35788
  let manifest;
35503
35789
  try {
35504
35790
  manifest = JSON.parse(
35505
- readFileSync10(path65.join(dir, "walkthrough.json"), "utf8")
35791
+ readFileSync10(path66.join(dir, "walkthrough.json"), "utf8")
35506
35792
  );
35507
35793
  } catch {
35508
35794
  fail(
@@ -35681,7 +35967,7 @@ function computePageFingerprint(url, bodySnippet) {
35681
35967
  return createHash6("sha256").update(`${url}|${bodySnippet.trim().replace(/\s+/g, " ")}`).digest("hex").slice(0, 16);
35682
35968
  }
35683
35969
  function checkAndRecordStagnation(runDirPath, fingerprint, action) {
35684
- const cacheFile = path65.join(runDirPath, ".stagnation.json");
35970
+ const cacheFile = path66.join(runDirPath, ".stagnation.json");
35685
35971
  let previous = null;
35686
35972
  try {
35687
35973
  if (existsSync17(cacheFile)) {
@@ -35962,8 +36248,8 @@ async function actOnPage(opts, attached, state, fn, onPostShot) {
35962
36248
  let contentSnippet;
35963
36249
  if (opts.shot) {
35964
36250
  await waitForVisualStability(page);
35965
- screenshot = path65.resolve(opts.shot);
35966
- mkdirSync3(path65.dirname(screenshot), { recursive: true });
36251
+ screenshot = path66.resolve(opts.shot);
36252
+ mkdirSync3(path66.dirname(screenshot), { recursive: true });
35967
36253
  await page.screenshot({
35968
36254
  path: screenshot,
35969
36255
  fullPage: Boolean(opts.full),
@@ -36173,7 +36459,7 @@ function httpOrigin(raw) {
36173
36459
  function readTargetUrl(runDirPath) {
36174
36460
  try {
36175
36461
  const m = JSON.parse(
36176
- readFileSync10(path65.join(runDirPath, "walkthrough.json"), "utf8")
36462
+ readFileSync10(path66.join(runDirPath, "walkthrough.json"), "utf8")
36177
36463
  );
36178
36464
  return typeof m.target_url === "string" ? m.target_url : null;
36179
36465
  } catch {
@@ -36185,7 +36471,7 @@ function fullFramePlan(runDirPath, url, scrolled) {
36185
36471
  let manifest = {};
36186
36472
  try {
36187
36473
  manifest = JSON.parse(
36188
- readFileSync10(path65.join(runDirPath, "walkthrough.json"), "utf8")
36474
+ readFileSync10(path66.join(runDirPath, "walkthrough.json"), "utf8")
36189
36475
  );
36190
36476
  } catch {
36191
36477
  }
@@ -36196,7 +36482,7 @@ function fullFramePlan(runDirPath, url, scrolled) {
36196
36482
  if (designer2.includes(key) || scrolled) {
36197
36483
  return { take: true, lastHeight: null };
36198
36484
  }
36199
- const stepsDir = path65.join(runDirPath, "steps");
36485
+ const stepsDir = path66.join(runDirPath, "steps");
36200
36486
  let names2 = [];
36201
36487
  try {
36202
36488
  names2 = readdirSync3(stepsDir).filter((n) => /^\d+\.json$/.test(n)).sort();
@@ -36207,7 +36493,7 @@ function fullFramePlan(runDirPath, url, scrolled) {
36207
36493
  for (const name of names2) {
36208
36494
  try {
36209
36495
  const earlier = JSON.parse(
36210
- readFileSync10(path65.join(stepsDir, name), "utf8")
36496
+ readFileSync10(path66.join(stepsDir, name), "utf8")
36211
36497
  );
36212
36498
  if (typeof earlier.url === "string" && stepScreenKey(earlier.url, target) === key) {
36213
36499
  seen = true;
@@ -36274,7 +36560,7 @@ function printStep(opts, record, projectRoot, stagnationWarning, challengeWarnin
36274
36560
  if (opts.json) {
36275
36561
  const doc = {
36276
36562
  step_number: step.step_number,
36277
- path: path65.relative(projectRoot, record.stepPath).split(path65.sep).join("/"),
36563
+ path: path66.relative(projectRoot, record.stepPath).split(path66.sep).join("/"),
36278
36564
  action: step.action,
36279
36565
  note: step.note,
36280
36566
  url: step.url,
@@ -36392,7 +36678,7 @@ async function clearStorage(opts, driver) {
36392
36678
  try {
36393
36679
  if (dir) {
36394
36680
  target = JSON.parse(
36395
- readFileSync10(path65.join(dir, "walkthrough.json"), "utf8")
36681
+ readFileSync10(path66.join(dir, "walkthrough.json"), "utf8")
36396
36682
  ).target_url;
36397
36683
  }
36398
36684
  } catch {
@@ -36579,15 +36865,15 @@ async function browseStep(args2, opts, driver) {
36579
36865
  ))
36580
36866
  return;
36581
36867
  const maxSteps = parseMaxSteps(opts.maxSteps);
36582
- if (await peekNextStepNumber(path65.join(runDirPath, "steps")) > maxSteps) {
36868
+ if (await peekNextStepNumber(path66.join(runDirPath, "steps")) > maxSteps) {
36583
36869
  return fail(stepLimitMessage(maxSteps, opts.run), opts);
36584
36870
  }
36585
- const pendingShot = path65.join(
36871
+ const pendingShot = path66.join(
36586
36872
  runDirPath,
36587
36873
  "screenshots",
36588
36874
  `.pending-${randomUUID11()}.png`
36589
36875
  );
36590
- const pendingFull = path65.join(
36876
+ const pendingFull = path66.join(
36591
36877
  runDirPath,
36592
36878
  "screenshots",
36593
36879
  `.pending-${randomUUID11()}.full.png`
@@ -38470,18 +38756,18 @@ __export(preflight_exports, {
38470
38756
  });
38471
38757
  import { spawnSync } from "child_process";
38472
38758
  import { existsSync as existsSync20, promises as fs67 } from "fs";
38473
- import path66 from "path";
38759
+ import path67 from "path";
38474
38760
  import chalk36 from "chalk";
38475
38761
  function detectPackageManager(targetDir) {
38476
- if (existsSync20(path66.join(targetDir, "pnpm-lock.yaml"))) return "pnpm";
38477
- if (existsSync20(path66.join(targetDir, "yarn.lock"))) return "yarn";
38478
- if (existsSync20(path66.join(targetDir, "bun.lockb")) || existsSync20(path66.join(targetDir, "bun.lock"))) {
38762
+ if (existsSync20(path67.join(targetDir, "pnpm-lock.yaml"))) return "pnpm";
38763
+ if (existsSync20(path67.join(targetDir, "yarn.lock"))) return "yarn";
38764
+ if (existsSync20(path67.join(targetDir, "bun.lockb")) || existsSync20(path67.join(targetDir, "bun.lock"))) {
38479
38765
  return "bun";
38480
38766
  }
38481
38767
  return "npm";
38482
38768
  }
38483
38769
  async function detectPreflightCommand(targetDir) {
38484
- const pkgPath = path66.join(targetDir, "package.json");
38770
+ const pkgPath = path67.join(targetDir, "package.json");
38485
38771
  if (existsSync20(pkgPath)) {
38486
38772
  try {
38487
38773
  const raw = await fs67.readFile(pkgPath, "utf8");
@@ -38494,7 +38780,7 @@ async function detectPreflightCommand(targetDir) {
38494
38780
  } catch {
38495
38781
  }
38496
38782
  }
38497
- const tsconfigPath = path66.join(targetDir, "tsconfig.json");
38783
+ const tsconfigPath = path67.join(targetDir, "tsconfig.json");
38498
38784
  if (existsSync20(tsconfigPath)) {
38499
38785
  return { command: "npx", args: ["--no-install", "tsc", "--noEmit"] };
38500
38786
  }
@@ -38533,7 +38819,7 @@ async function runPreflightCheck(targetDir) {
38533
38819
  };
38534
38820
  }
38535
38821
  async function preflight(opts = {}) {
38536
- const targetDir = opts.cwd ? path66.resolve(opts.cwd) : process.cwd();
38822
+ const targetDir = opts.cwd ? path67.resolve(opts.cwd) : process.cwd();
38537
38823
  const result = await runPreflightCheck(targetDir);
38538
38824
  if (result.ok) {
38539
38825
  if (opts.json) {
@@ -39042,12 +39328,12 @@ __export(validate_exports, {
39042
39328
  });
39043
39329
  import { randomUUID as randomUUID12 } from "crypto";
39044
39330
  import { promises as fs68 } from "fs";
39045
- import path67 from "path";
39331
+ import path68 from "path";
39046
39332
  import chalk38 from "chalk";
39047
39333
  function inferTypeFromPath(filePath, projectRoot) {
39048
- const rel = path67.relative(path67.join(projectRoot, "iamu"), filePath);
39049
- if (rel.startsWith("..") || path67.isAbsolute(rel)) return null;
39050
- const segments = rel.split(path67.sep);
39334
+ const rel = path68.relative(path68.join(projectRoot, "iamu"), filePath);
39335
+ if (rel.startsWith("..") || path68.isAbsolute(rel)) return null;
39336
+ const segments = rel.split(path68.sep);
39051
39337
  if (segments.length < 2) return null;
39052
39338
  return TYPE_BY_ALIAS.get(segments[0]) ?? null;
39053
39339
  }
@@ -39064,7 +39350,7 @@ function applyZodValidation(schema2, data, result) {
39064
39350
  }
39065
39351
  function validateFile(filePath, raw, projectRoot) {
39066
39352
  const result = { path: filePath, valid: true, errors: [] };
39067
- if (path67.basename(filePath) === "config.json") {
39353
+ if (path68.basename(filePath) === "config.json") {
39068
39354
  let parsedJson;
39069
39355
  try {
39070
39356
  parsedJson = JSON.parse(raw);
@@ -39091,11 +39377,11 @@ function validateFile(filePath, raw, projectRoot) {
39091
39377
  );
39092
39378
  return result;
39093
39379
  }
39094
- if (path67.basename(filePath) === "testability.md") {
39380
+ if (path68.basename(filePath) === "testability.md") {
39095
39381
  applyZodValidation(testabilityFrontmatterSchema, frontmatter, result);
39096
39382
  return result;
39097
39383
  }
39098
- if (path67.basename(filePath) === "context.yml") {
39384
+ if (path68.basename(filePath) === "context.yml") {
39099
39385
  applyZodValidation(contextFrontmatterSchema, frontmatter, result);
39100
39386
  const warnings = [];
39101
39387
  const hasNotes = Boolean(
@@ -39157,7 +39443,7 @@ async function buildRepairLookups(projectRoot) {
39157
39443
  }
39158
39444
  }
39159
39445
  const runScenario = /* @__PURE__ */ new Map();
39160
- const runsDir2 = path67.join(projectRoot, "iamu", ".runs");
39446
+ const runsDir2 = path68.join(projectRoot, "iamu", ".runs");
39161
39447
  let runIds = [];
39162
39448
  try {
39163
39449
  runIds = await fs68.readdir(runsDir2);
@@ -39167,7 +39453,7 @@ async function buildRepairLookups(projectRoot) {
39167
39453
  try {
39168
39454
  const manifest = JSON.parse(
39169
39455
  await fs68.readFile(
39170
- path67.join(runsDir2, runId, "walkthrough.json"),
39456
+ path68.join(runsDir2, runId, "walkthrough.json"),
39171
39457
  "utf8"
39172
39458
  )
39173
39459
  );
@@ -39198,7 +39484,7 @@ async function fixFindings(projectRoot, results, dryRun) {
39198
39484
  parsed.frontmatter,
39199
39485
  {
39200
39486
  ...lookups,
39201
- fileSlug: path67.basename(result.path, ".md"),
39487
+ fileSlug: path68.basename(result.path, ".md"),
39202
39488
  newId: randomUUID12,
39203
39489
  body: parsed.body
39204
39490
  }
@@ -39240,7 +39526,7 @@ async function validate(filePath, opts) {
39240
39526
  if (process.exitCode === 1) return;
39241
39527
  const results = [];
39242
39528
  if (filePath) {
39243
- const abs = path67.isAbsolute(filePath) ? filePath : path67.resolve(process.cwd(), filePath);
39529
+ const abs = path68.isAbsolute(filePath) ? filePath : path68.resolve(process.cwd(), filePath);
39244
39530
  try {
39245
39531
  const raw = await fs68.readFile(abs, "utf8");
39246
39532
  results.push(validateFile(abs, raw, projectRoot));
@@ -39256,7 +39542,7 @@ async function validate(filePath, opts) {
39256
39542
  return;
39257
39543
  }
39258
39544
  } else if (opts.run) {
39259
- const findingsDir = path67.join(projectRoot, "iamu", ENTITY_DIRS.finding);
39545
+ const findingsDir = path68.join(projectRoot, "iamu", ENTITY_DIRS.finding);
39260
39546
  let names2 = [];
39261
39547
  try {
39262
39548
  names2 = await fs68.readdir(findingsDir);
@@ -39264,7 +39550,7 @@ async function validate(filePath, opts) {
39264
39550
  }
39265
39551
  for (const name of names2) {
39266
39552
  if (!name.endsWith(".md")) continue;
39267
- const abs = path67.join(findingsDir, name);
39553
+ const abs = path68.join(findingsDir, name);
39268
39554
  try {
39269
39555
  const raw = await fs68.readFile(abs, "utf8");
39270
39556
  const { frontmatter } = parseFrontmatter(raw);
@@ -39273,7 +39559,7 @@ async function validate(filePath, opts) {
39273
39559
  }
39274
39560
  } catch {
39275
39561
  results.push({
39276
- path: path67.relative(projectRoot, abs),
39562
+ path: path68.relative(projectRoot, abs),
39277
39563
  valid: false,
39278
39564
  errors: ["Cannot read file or parse frontmatter"]
39279
39565
  });
@@ -39306,7 +39592,7 @@ async function validate(filePath, opts) {
39306
39592
  } else {
39307
39593
  const typesToCheck = typeFilter ? ENTITY_TYPES.filter((t) => typeFilter.has(t)) : ENTITY_TYPES;
39308
39594
  for (const type2 of typesToCheck) {
39309
- const iamuTypeDir = path67.join(projectRoot, "iamu", ENTITY_DIRS[type2]);
39595
+ const iamuTypeDir = path68.join(projectRoot, "iamu", ENTITY_DIRS[type2]);
39310
39596
  let names2;
39311
39597
  try {
39312
39598
  names2 = await fs68.readdir(iamuTypeDir);
@@ -39315,13 +39601,13 @@ async function validate(filePath, opts) {
39315
39601
  }
39316
39602
  for (const name of names2) {
39317
39603
  if (!name.endsWith(".md")) continue;
39318
- const abs = path67.join(iamuTypeDir, name);
39604
+ const abs = path68.join(iamuTypeDir, name);
39319
39605
  try {
39320
39606
  const raw = await fs68.readFile(abs, "utf8");
39321
39607
  results.push(validateFile(abs, raw, projectRoot));
39322
39608
  } catch {
39323
39609
  results.push({
39324
- path: path67.relative(projectRoot, abs),
39610
+ path: path68.relative(projectRoot, abs),
39325
39611
  valid: false,
39326
39612
  errors: ["Cannot read file"]
39327
39613
  });
@@ -39329,7 +39615,7 @@ async function validate(filePath, opts) {
39329
39615
  }
39330
39616
  }
39331
39617
  for (const extraFile of ["context.yml", "testability.md", "config.json"]) {
39332
- const extraPath = path67.join(projectRoot, "iamu", extraFile);
39618
+ const extraPath = path68.join(projectRoot, "iamu", extraFile);
39333
39619
  try {
39334
39620
  const raw = await fs68.readFile(extraPath, "utf8");
39335
39621
  results.push(validateFile(extraPath, raw, projectRoot));
@@ -39355,19 +39641,19 @@ async function validate(filePath, opts) {
39355
39641
  valid,
39356
39642
  errors: results.filter((r) => !r.valid).flatMap(
39357
39643
  (r) => r.errors.map((e) => ({
39358
- path: path67.relative(projectRoot, r.path),
39644
+ path: path68.relative(projectRoot, r.path),
39359
39645
  message: e
39360
39646
  }))
39361
39647
  ),
39362
39648
  warnings: results.filter((r) => r.warnings && r.warnings.length > 0).flatMap(
39363
39649
  (r) => (r.warnings ?? []).map((w) => ({
39364
- path: path67.relative(projectRoot, r.path),
39650
+ path: path68.relative(projectRoot, r.path),
39365
39651
  message: w
39366
39652
  }))
39367
39653
  ),
39368
39654
  ...opts.fix ? {
39369
39655
  repaired: repaired.map((r) => ({
39370
- path: path67.relative(projectRoot, r.path),
39656
+ path: path68.relative(projectRoot, r.path),
39371
39657
  changes: r.repairs,
39372
39658
  valid: r.valid
39373
39659
  }))
@@ -39389,7 +39675,7 @@ async function validate(filePath, opts) {
39389
39675
  }
39390
39676
  let hasErrors = false;
39391
39677
  for (const r of results) {
39392
- const relPath = path67.relative(projectRoot, r.path);
39678
+ const relPath = path68.relative(projectRoot, r.path);
39393
39679
  if (r.valid) {
39394
39680
  if (r.warnings && r.warnings.length > 0) {
39395
39681
  console.log(` ${symbols.warning} ` + chalk38.yellow(relPath));
@@ -39584,7 +39870,7 @@ __export(new_entity_exports, {
39584
39870
  });
39585
39871
  import { randomUUID as randomUUID13 } from "crypto";
39586
39872
  import { readFile as readFile8 } from "fs/promises";
39587
- import path68 from "path";
39873
+ import path69 from "path";
39588
39874
  import chalk40 from "chalk";
39589
39875
  async function resolveBodyInput(opts, command, flag = "--body") {
39590
39876
  if (opts.bodyFile !== void 0) {
@@ -39597,7 +39883,7 @@ async function resolveBodyInput(opts, command, flag = "--body") {
39597
39883
  return null;
39598
39884
  }
39599
39885
  try {
39600
- const body = opts.bodyFile === "-" ? await readStdinText() : await readFile8(path68.resolve(process.cwd(), opts.bodyFile), "utf8");
39886
+ const body = opts.bodyFile === "-" ? await readStdinText() : await readFile8(path69.resolve(process.cwd(), opts.bodyFile), "utf8");
39601
39887
  return { body };
39602
39888
  } catch (err) {
39603
39889
  commandError(
@@ -39847,7 +40133,7 @@ __export(set_entity_exports, {
39847
40133
  setEntity: () => setEntity
39848
40134
  });
39849
40135
  import { promises as fs69 } from "fs";
39850
- import path69 from "path";
40136
+ import path70 from "path";
39851
40137
  import chalk41 from "chalk";
39852
40138
  import { ZodError as ZodError2 } from "zod";
39853
40139
  function normalizeAuthStrategy(raw) {
@@ -40038,7 +40324,7 @@ async function setEntity(type2, slug, opts) {
40038
40324
  }
40039
40325
  raw = Buffer.concat(chunks).toString("utf8");
40040
40326
  } else {
40041
- raw = await fs69.readFile(path69.resolve(projectRoot, opts.file), "utf8");
40327
+ raw = await fs69.readFile(path70.resolve(projectRoot, opts.file), "utf8");
40042
40328
  }
40043
40329
  } catch (err) {
40044
40330
  commandError(
@@ -40624,7 +40910,7 @@ __export(edit_entity_exports, {
40624
40910
  });
40625
40911
  import { spawn as spawn2 } from "child_process";
40626
40912
  import { promises as fs70 } from "fs";
40627
- import path70 from "path";
40913
+ import path71 from "path";
40628
40914
  import chalk42 from "chalk";
40629
40915
  async function editEntity(type2, slug, opts = {}) {
40630
40916
  const ctx = await resolveProject(opts);
@@ -40648,7 +40934,7 @@ async function editEntity(type2, slug, opts = {}) {
40648
40934
  }
40649
40935
  const effectiveSlug = isSpecial ? type2 : slug;
40650
40936
  const resolvedPath = isSpecial ? type2 === "testability" ? testabilityPath(projectRoot) : contextPath(projectRoot) : await resolveEntityPath(projectRoot, type2, effectiveSlug);
40651
- const filePath = resolvedPath ?? path70.join(
40937
+ const filePath = resolvedPath ?? path71.join(
40652
40938
  projectRoot,
40653
40939
  "iamu",
40654
40940
  ENTITY_DIRS[type2],
@@ -40659,7 +40945,7 @@ async function editEntity(type2, slug, opts = {}) {
40659
40945
  await fs70.access(filePath);
40660
40946
  } catch {
40661
40947
  commandError(
40662
- `${type2}${isSpecial ? "" : ` "${effectiveSlug}"`} not found at ${path70.relative(projectRoot, filePath)}.`,
40948
+ `${type2}${isSpecial ? "" : ` "${effectiveSlug}"`} not found at ${path71.relative(projectRoot, filePath)}.`,
40663
40949
  {
40664
40950
  ...opts,
40665
40951
  code: "entity_not_found",
@@ -40670,7 +40956,7 @@ async function editEntity(type2, slug, opts = {}) {
40670
40956
  }
40671
40957
  if (!process.stdin.isTTY || process.env.CI) {
40672
40958
  commandError(
40673
- `Cannot open editor in a non-interactive environment. Edit the file directly: ${path70.relative(projectRoot, filePath)}`,
40959
+ `Cannot open editor in a non-interactive environment. Edit the file directly: ${path71.relative(projectRoot, filePath)}`,
40674
40960
  {
40675
40961
  ...opts,
40676
40962
  code: "non_interactive_environment",
@@ -40746,7 +41032,7 @@ async function editEntity(type2, slug, opts = {}) {
40746
41032
  console.log();
40747
41033
  console.log(
40748
41034
  chalk42.dim(
40749
- ` Fix the file and run: iamu validate ${path70.relative(projectRoot, filePath)}`
41035
+ ` Fix the file and run: iamu validate ${path71.relative(projectRoot, filePath)}`
40750
41036
  )
40751
41037
  );
40752
41038
  console.log();
@@ -40776,7 +41062,7 @@ async function editEntity(type2, slug, opts = {}) {
40776
41062
  {
40777
41063
  ...opts,
40778
41064
  code: "validation_error",
40779
- fix: `iamu validate ${path70.relative(projectRoot, filePath)}`
41065
+ fix: `iamu validate ${path71.relative(projectRoot, filePath)}`
40780
41066
  }
40781
41067
  );
40782
41068
  }
@@ -40945,7 +41231,7 @@ async function crawlFrom(page, opts, origin, takeBlocked) {
40945
41231
  const byKey = /* @__PURE__ */ new Map();
40946
41232
  const byPlaceView = /* @__PURE__ */ new Map();
40947
41233
  const signatureOf = (s) => exploreSignature(s.headings, s.title);
40948
- function addSurface(state, place, view, path77, depth) {
41234
+ function addSurface(state, place, view, path78, depth) {
40949
41235
  const key = exploreSurfaceKey(place, view);
40950
41236
  const surface = {
40951
41237
  key,
@@ -40957,7 +41243,7 @@ async function crawlFrom(page, opts, origin, takeBlocked) {
40957
41243
  headings: state.headings,
40958
41244
  fields: state.fields,
40959
41245
  depth,
40960
- path: path77,
41246
+ path: path78,
40961
41247
  actions: []
40962
41248
  };
40963
41249
  surfaces.push(surface);
@@ -40975,9 +41261,9 @@ ${surface.signature}`, key);
40975
41261
  });
40976
41262
  await settle(page, settleMs);
40977
41263
  }
40978
- async function replay(path77) {
40979
- if (!("goto" in (path77[0] ?? {}))) await goto(opts.startUrl);
40980
- for (const step of path77) {
41264
+ async function replay(path78) {
41265
+ if (!("goto" in (path78[0] ?? {}))) await goto(opts.startUrl);
41266
+ for (const step of path78) {
40981
41267
  if ("goto" in step) {
40982
41268
  await goto(step.goto);
40983
41269
  } else {
@@ -41104,8 +41390,8 @@ ${sig}`, key);
41104
41390
  if (stats.surfaces >= budget.max_surfaces) {
41105
41391
  stats.truncated = true;
41106
41392
  } else {
41107
- const path77 = !sameDoc && view === null ? [{ goto: after.url }] : [...surface.path, ...via, click];
41108
- addSurface(after, place, view, path77, surface.depth + 1);
41393
+ const path78 = !sameDoc && view === null ? [{ goto: after.url }] : [...surface.path, ...via, click];
41394
+ addSurface(after, place, view, path78, surface.depth + 1);
41109
41395
  }
41110
41396
  }
41111
41397
  }
@@ -41375,7 +41661,7 @@ __export(explore_exports, {
41375
41661
  exploreList: () => exploreList,
41376
41662
  exploreRun: () => exploreRun
41377
41663
  });
41378
- import path71 from "path";
41664
+ import path72 from "path";
41379
41665
  import chalk43 from "chalk";
41380
41666
  function fail2(message, json2) {
41381
41667
  if (json2) console.error(JSON.stringify({ error: message }));
@@ -41515,7 +41801,7 @@ async function exploreRun(url, opts) {
41515
41801
  surfaces: result.surfaces
41516
41802
  };
41517
41803
  const file = await writeExploreMap(ctx.projectRoot, map2);
41518
- const rel = path71.relative(process.cwd(), file);
41804
+ const rel = path72.relative(process.cwd(), file);
41519
41805
  if (opts.json) {
41520
41806
  console.log(JSON.stringify({ id: map2.id, path: rel, stats: map2.stats }));
41521
41807
  return;
@@ -42711,7 +42997,7 @@ __export(new_finding_exports, {
42711
42997
  });
42712
42998
  import { randomUUID as randomUUID14 } from "crypto";
42713
42999
  import { access, readFile as readFile9 } from "fs/promises";
42714
- import path72 from "path";
43000
+ import path73 from "path";
42715
43001
  import chalk46 from "chalk";
42716
43002
  async function newFinding(opts) {
42717
43003
  const ctx = await resolveProject(opts);
@@ -42799,7 +43085,7 @@ async function newFinding(opts) {
42799
43085
  }
42800
43086
  try {
42801
43087
  await access(
42802
- path72.join(runDirPath, "steps", `${String(n).padStart(3, "0")}.json`)
43088
+ path73.join(runDirPath, "steps", `${String(n).padStart(3, "0")}.json`)
42803
43089
  );
42804
43090
  } catch {
42805
43091
  commandError(
@@ -42818,7 +43104,7 @@ async function newFinding(opts) {
42818
43104
  if (!scenarioSlug) {
42819
43105
  try {
42820
43106
  const manifestRaw = await readFile9(
42821
- path72.join(runDirPath, "walkthrough.json"),
43107
+ path73.join(runDirPath, "walkthrough.json"),
42822
43108
  "utf8"
42823
43109
  );
42824
43110
  const manifest = JSON.parse(manifestRaw);
@@ -42965,7 +43251,7 @@ __export(summary_exports, {
42965
43251
  summaryCommand: () => summaryCommand
42966
43252
  });
42967
43253
  import { promises as fs71 } from "fs";
42968
- import path73 from "path";
43254
+ import path74 from "path";
42969
43255
  import chalk47 from "chalk";
42970
43256
  function endedFrom(value) {
42971
43257
  if (!value || typeof value !== "object") return void 0;
@@ -42996,7 +43282,7 @@ async function summaryCommand(runIdArg, opts) {
42996
43282
  let openQuestions = [];
42997
43283
  let setupNotes = [];
42998
43284
  let model = opts.model?.trim() || void 0;
42999
- const summaryPath = path73.join(runDirPath, "summary.json");
43285
+ const summaryPath = path74.join(runDirPath, "summary.json");
43000
43286
  let blocked;
43001
43287
  let ended;
43002
43288
  try {
@@ -43016,7 +43302,7 @@ async function summaryCommand(runIdArg, opts) {
43016
43302
  if (opts.file === "-") {
43017
43303
  raw = await readStdinText();
43018
43304
  } else {
43019
- raw = await fs71.readFile(path73.resolve(projectRoot, opts.file), "utf8");
43305
+ raw = await fs71.readFile(path74.resolve(projectRoot, opts.file), "utf8");
43020
43306
  }
43021
43307
  const parsed = JSON.parse(raw);
43022
43308
  if (Array.isArray(parsed.what_worked)) {
@@ -43093,7 +43379,7 @@ async function summaryCommand(runIdArg, opts) {
43093
43379
  JSON.stringify(
43094
43380
  {
43095
43381
  run_id: runId,
43096
- path: path73.relative(projectRoot, summaryPath),
43382
+ path: path74.relative(projectRoot, summaryPath),
43097
43383
  summary: data
43098
43384
  },
43099
43385
  null,
@@ -43155,7 +43441,7 @@ __export(advise_exports, {
43155
43441
  readAdvisePrompt: () => readAdvisePrompt
43156
43442
  });
43157
43443
  import { existsSync as existsSync23, promises as fs72 } from "fs";
43158
- import path74 from "path";
43444
+ import path75 from "path";
43159
43445
  import chalk48 from "chalk";
43160
43446
  function readAdvisePrompt(projectRoot) {
43161
43447
  return readInstalledPrompt(projectRoot, "advise.md");
@@ -43213,7 +43499,7 @@ async function advise(runIdArg, opts = {}) {
43213
43499
  findings2 = input.findings.length;
43214
43500
  needed = findings2 >= 2;
43215
43501
  if (!needed) reason = "fewer than two open findings in the project";
43216
- promptPath = opts.promptFile ?? path74.join(analysisDir(projectRoot), "advise_prompt.md");
43502
+ promptPath = opts.promptFile ?? path75.join(analysisDir(projectRoot), "advise_prompt.md");
43217
43503
  } else {
43218
43504
  const runId = resolveRunId(projectRoot, runIdArg ?? opts.run);
43219
43505
  if (!requireRunId(runId, opts, "iamu advise <run-id>")) return;
@@ -43224,12 +43510,12 @@ async function advise(runIdArg, opts = {}) {
43224
43510
  input = await buildAdviseInput(projectRoot, runId, manifest.scenario_slug);
43225
43511
  refsDir = runDirPath;
43226
43512
  findings2 = input.findings.length;
43227
- const advised = existsSync23(path74.join(runDirPath, ADVICE_FILE));
43513
+ const advised = existsSync23(path75.join(runDirPath, ADVICE_FILE));
43228
43514
  needed = !manifest.blocked && findings2 > 0 && !advised;
43229
43515
  if (manifest.blocked) reason = "the run was blocked";
43230
43516
  else if (advised) reason = "the run is already advised";
43231
43517
  else if (findings2 === 0) reason = "no open findings to advise";
43232
- promptPath = opts.promptFile ?? path74.join(runDirPath, "advise_prompt.md");
43518
+ promptPath = opts.promptFile ?? path75.join(runDirPath, "advise_prompt.md");
43233
43519
  }
43234
43520
  if (needed) input = await withCodeIndex(projectRoot, input);
43235
43521
  const { bundle, refs: refs2 } = promptBundle(input);
@@ -43239,11 +43525,11 @@ async function advise(runIdArg, opts = {}) {
43239
43525
  promptSizeWarning(prompt)
43240
43526
  ].filter((w) => w !== null) : [];
43241
43527
  if (prompt) {
43242
- await fs72.mkdir(path74.dirname(promptPath), { recursive: true });
43528
+ await fs72.mkdir(path75.dirname(promptPath), { recursive: true });
43243
43529
  await fs72.writeFile(promptPath, prompt, "utf8");
43244
43530
  await fs72.mkdir(refsDir, { recursive: true });
43245
43531
  await fs72.writeFile(
43246
- path74.join(refsDir, ADVISE_REFS_FILE),
43532
+ path75.join(refsDir, ADVISE_REFS_FILE),
43247
43533
  `${JSON.stringify(refs2, null, 2)}
43248
43534
  `,
43249
43535
  "utf8"
@@ -43258,8 +43544,8 @@ async function advise(runIdArg, opts = {}) {
43258
43544
  ...reason ? { reason } : {},
43259
43545
  mode: opts.project ? "project" : "run",
43260
43546
  findings: findings2,
43261
- prompt_file: prompt ? path74.relative(projectRoot, promptPath).split(path74.sep).join("/") : null,
43262
- prompt_file_abs: prompt ? path74.resolve(promptPath) : null,
43547
+ prompt_file: prompt ? path75.relative(projectRoot, promptPath).split(path75.sep).join("/") : null,
43548
+ prompt_file_abs: prompt ? path75.resolve(promptPath) : null,
43263
43549
  prompt_chars: prompt?.length ?? 0,
43264
43550
  warnings,
43265
43551
  advise_prompt: prompt
@@ -43335,7 +43621,7 @@ async function adviseRecord(runIdArg, opts) {
43335
43621
  const { projectRoot } = ctx;
43336
43622
  if (opts.project) {
43337
43623
  const input2 = await readAnswerInput(opts, "advice", {
43338
- defaultPath: path74.join(analysisDir(projectRoot), "answer.json"),
43624
+ defaultPath: path75.join(analysisDir(projectRoot), "answer.json"),
43339
43625
  code: "missing_advice_input",
43340
43626
  fix: "iamu advise-record --project --data '<json>'"
43341
43627
  });
@@ -43367,7 +43653,7 @@ async function adviseRecord(runIdArg, opts) {
43367
43653
  if (!manifest) return;
43368
43654
  await logTiming(runDirPath, "advise-record", "start");
43369
43655
  const input = await readAnswerInput(opts, "advice", {
43370
- defaultPath: path74.join(runDir(projectRoot, runId), "advise_answer.json"),
43656
+ defaultPath: path75.join(runDir(projectRoot, runId), "advise_answer.json"),
43371
43657
  code: "missing_advice_input",
43372
43658
  fix: `iamu advise-record ${runId} --data '<json>'`
43373
43659
  });
@@ -43417,7 +43703,7 @@ async function directionsList(opts) {
43417
43703
  problem: d.texts.problem,
43418
43704
  change: d.texts.change,
43419
43705
  leading_practice: d.texts.leading_practice,
43420
- path: path74.relative(ctx.projectRoot, d.path)
43706
+ path: path75.relative(ctx.projectRoot, d.path)
43421
43707
  })),
43422
43708
  null,
43423
43709
  2
@@ -43566,7 +43852,7 @@ __export(designer_exports, {
43566
43852
  designerRecord: () => designerRecord
43567
43853
  });
43568
43854
  import { promises as fs73 } from "fs";
43569
- import path75 from "path";
43855
+ import path76 from "path";
43570
43856
  import chalk49 from "chalk";
43571
43857
  import { ZodError as ZodError3 } from "zod";
43572
43858
  function describeError(err) {
@@ -43586,7 +43872,7 @@ async function designer(runId, opts = {}) {
43586
43872
  const { projectRoot, runDirPath } = ctx;
43587
43873
  if (!await completedManifest2(runDirPath, runId, opts)) return;
43588
43874
  const input = await buildRunDesignerInput(projectRoot, runId);
43589
- const promptPath = path75.join(runDirPath, DESIGNER_PROMPT_FILE);
43875
+ const promptPath = path76.join(runDirPath, DESIGNER_PROMPT_FILE);
43590
43876
  const prompt = input.needed ? composeDesignPrompt(
43591
43877
  projectRoot,
43592
43878
  "designer.md",
@@ -43595,7 +43881,7 @@ async function designer(runId, opts = {}) {
43595
43881
  if (prompt) {
43596
43882
  await fs73.writeFile(promptPath, prompt, "utf8");
43597
43883
  await fs73.writeFile(
43598
- path75.join(runDirPath, DESIGNER_REFS_FILE),
43884
+ path76.join(runDirPath, DESIGNER_REFS_FILE),
43599
43885
  `${JSON.stringify(input.refs, null, 2)}
43600
43886
  `,
43601
43887
  "utf8"
@@ -43606,7 +43892,7 @@ async function designer(runId, opts = {}) {
43606
43892
  installedPromptWarning(projectRoot, "designer.md"),
43607
43893
  ...input.warnings
43608
43894
  ].filter((w) => w !== null) : [];
43609
- const answer = path75.join(runDirPath, DESIGNER_ANSWER_FILE);
43895
+ const answer = path76.join(runDirPath, DESIGNER_ANSWER_FILE);
43610
43896
  const result = {
43611
43897
  needed: input.needed,
43612
43898
  reason: input.reason,
@@ -43622,11 +43908,11 @@ async function designer(runId, opts = {}) {
43622
43908
  title: f.title
43623
43909
  })),
43624
43910
  design_files: (input.bundle.design?.files ?? []).map((f) => f.entry),
43625
- prompt_file: prompt ? path75.relative(projectRoot, promptPath).split(path75.sep).join("/") : null,
43911
+ prompt_file: prompt ? path76.relative(projectRoot, promptPath).split(path76.sep).join("/") : null,
43626
43912
  prompt_file_abs: prompt ? promptPath : null,
43627
43913
  prompt_chars: prompt?.length ?? 0,
43628
43914
  answer_file_abs: prompt ? answer : null,
43629
- next: prompt ? `Give a fresh agent ${path75.relative(projectRoot, promptPath)} as its only context, then record its answer: iamu designer-record ${runId} --data '<answer JSON>' (or --file <path>)` : null,
43915
+ next: prompt ? `Give a fresh agent ${path76.relative(projectRoot, promptPath)} as its only context, then record its answer: iamu designer-record ${runId} --data '<answer JSON>' (or --file <path>)` : null,
43630
43916
  hint: input.judged_against === "general-craft" ? await designDocsHint(projectRoot) : null,
43631
43917
  // No design doc recorded or found, and the template not declined:
43632
43918
  // the run summary offers to start one (iamu-design).
@@ -43672,6 +43958,9 @@ function printDesignerRecord(res) {
43672
43958
  ` ${chalk49.cyan("\u25C6")} Proposed doc edit ${p.outcome}: ${p.slug} (iamu design proposals)`
43673
43959
  );
43674
43960
  }
43961
+ for (const slug of res.verified ?? []) {
43962
+ console.log(` ${chalk49.green("\u2713")} Fix verified: ${slug}`);
43963
+ }
43675
43964
  for (const r of res.rejected) {
43676
43965
  console.log(` ${chalk49.yellow("!")} Dropped ${r.id}: ${r.reason}`);
43677
43966
  }
@@ -43757,7 +44046,7 @@ async function designerRecordLocked(projectRoot, runDirPath, runId, manifest, op
43757
44046
  return;
43758
44047
  }
43759
44048
  const input = await readAnswerInput(opts, "designer's review", {
43760
- defaultPath: path75.join(runDirPath, DESIGNER_ANSWER_FILE),
44049
+ defaultPath: path76.join(runDirPath, DESIGNER_ANSWER_FILE),
43761
44050
  code: "missing_designer_answer",
43762
44051
  fix: `iamu designer-record ${runId} --data '<json>'`
43763
44052
  });
@@ -43889,7 +44178,7 @@ __export(post_walk_exports, {
43889
44178
  postWalk: () => postWalk
43890
44179
  });
43891
44180
  import { existsSync as existsSync24, promises as fs74 } from "fs";
43892
- import path76 from "path";
44181
+ import path77 from "path";
43893
44182
  import chalk50 from "chalk";
43894
44183
  async function captureStageJson(fn) {
43895
44184
  const captured = [];
@@ -43932,7 +44221,7 @@ async function postWalk(runIdArg, opts = {}) {
43932
44221
  }
43933
44222
  const runDirPath = requireRun(projectRoot, runId, opts);
43934
44223
  if (!runDirPath) return;
43935
- const manifestPath = path76.join(runDirPath, "walkthrough.json");
44224
+ const manifestPath = path77.join(runDirPath, "walkthrough.json");
43936
44225
  let manifest;
43937
44226
  try {
43938
44227
  manifest = JSON.parse(
@@ -43973,7 +44262,7 @@ async function postWalk(runIdArg, opts = {}) {
43973
44262
  return;
43974
44263
  }
43975
44264
  const recordedNow = [];
43976
- const matchesAnswerPath = path76.join(runDirPath, MATCH_ANSWER_FILE);
44265
+ const matchesAnswerPath = path77.join(runDirPath, MATCH_ANSWER_FILE);
43977
44266
  if (existsSync24(matchesAnswerPath)) {
43978
44267
  const res = await captureStageJson(
43979
44268
  () => matchRecord(runId, { file: matchesAnswerPath, json: true })
@@ -43984,7 +44273,7 @@ async function postWalk(runIdArg, opts = {}) {
43984
44273
  });
43985
44274
  }
43986
44275
  }
43987
- const judgeAnswerPath = path76.join(runDirPath, "judge_answer.json");
44276
+ const judgeAnswerPath = path77.join(runDirPath, "judge_answer.json");
43988
44277
  if (existsSync24(judgeAnswerPath)) {
43989
44278
  const res = await captureStageJson(
43990
44279
  () => evaluateRecord(runId, { file: judgeAnswerPath, json: true })
@@ -43995,8 +44284,8 @@ async function postWalk(runIdArg, opts = {}) {
43995
44284
  });
43996
44285
  }
43997
44286
  }
43998
- const adviseAnswerPath = path76.join(runDirPath, "advise_answer.json");
43999
- if (!opts.critic && !existsSync24(path76.join(runDirPath, ADVICE_FILE)) && existsSync24(adviseAnswerPath)) {
44287
+ const adviseAnswerPath = path77.join(runDirPath, "advise_answer.json");
44288
+ if (!opts.critic && !existsSync24(path77.join(runDirPath, ADVICE_FILE)) && existsSync24(adviseAnswerPath)) {
44000
44289
  const res = await captureStageJson(
44001
44290
  () => adviseRecord(runId, { file: adviseAnswerPath, json: true })
44002
44291
  );
@@ -44006,7 +44295,7 @@ async function postWalk(runIdArg, opts = {}) {
44006
44295
  });
44007
44296
  }
44008
44297
  }
44009
- const designerAnswerPath = path76.join(runDirPath, DESIGNER_ANSWER_FILE);
44298
+ const designerAnswerPath = path77.join(runDirPath, DESIGNER_ANSWER_FILE);
44010
44299
  let designerWarnings = [];
44011
44300
  let designerInvalidChecked = [];
44012
44301
  if (!existingDesignerFile(runDirPath)) {
@@ -44038,9 +44327,9 @@ async function postWalk(runIdArg, opts = {}) {
44038
44327
  }
44039
44328
  }
44040
44329
  const matchInfo = await captureStageJson(() => match(runId, { json: true }));
44041
- const evalRecorded = existsSync24(path76.join(runDirPath, "verdicts.json"));
44330
+ const evalRecorded = existsSync24(path77.join(runDirPath, "verdicts.json"));
44042
44331
  const evalInfo = evalRecorded ? null : await captureStageJson(() => evaluate(runId, { json: true }));
44043
- const adviseRecorded = existsSync24(path76.join(runDirPath, ADVICE_FILE));
44332
+ const adviseRecorded = existsSync24(path77.join(runDirPath, ADVICE_FILE));
44044
44333
  const awaitingJudge = !opts.critic && !adviseRecorded && !evalRecorded;
44045
44334
  const adviseInfo = opts.critic || adviseRecorded || awaitingJudge ? null : await captureStageJson(() => advise(runId, { json: true }));
44046
44335
  const designerRecorded = Boolean(existingDesignerFile(runDirPath));
@@ -44547,7 +44836,10 @@ function registerFindingsCommands(program2) {
44547
44836
  program2.command("triage [findings...]").helpGroup("Findings:").description("Set findings' triage status").requiredOption(
44548
44837
  "--status <status>",
44549
44838
  "open, addressed, dismissed, deferred or wont_fix"
44550
- ).option("--note <text>", "Optional triage note or reason").option(
44839
+ ).option(
44840
+ "--note <text>",
44841
+ "Triage note, any status. For addressed: one line on what changed on screen, so the next run's matcher can confirm the fix"
44842
+ ).option("--note-file <path>", "Read the note from a file (- reads stdin)").option(
44551
44843
  "--reason <reason>",
44552
44844
  "Dismiss reason: not_relevant (default), walker_error, out_of_scope or duplicate"
44553
44845
  ).option(
@@ -44564,7 +44856,7 @@ function registerFindingsCommands(program2) {
44564
44856
  "Project-wide sweep ('we never want X'): dismiss all matching open persona & designer findings across every scenario/surface and record a project-wide guidance rule"
44565
44857
  ).option("--no-guidance", "Dismiss without writing a tester guidance rule").option("--json", "Output as JSON").addHelpText(
44566
44858
  "after",
44567
- "\nDismissing as not_relevant, walker_error, or out_of_scope teaches the walker: it writes a\ntester guidance rule (skip it with --no-guidance)."
44859
+ '\nDismissing as not_relevant, walker_error, or out_of_scope teaches the walker: it writes a\ntester guidance rule (skip it with --no-guidance).\n\nExamples:\n $ iamu triage <finding> --status addressed --note "Icons on /orders now carry text labels"\n $ iamu triage <finding> --status dismissed --reason walker_error --note "<why>"'
44568
44860
  ).action(
44569
44861
  async (refs2, opts) => {
44570
44862
  const { triage: triage2 } = await Promise.resolve().then(() => (init_triage(), triage_exports));
@@ -44663,9 +44955,9 @@ function registerProjectCommands(program2) {
44663
44955
  "after",
44664
44956
  "\nExamples:\n $ iamu validate --all\n $ iamu validate --all --fix --dry-run\n $ iamu validate iamu/personas/maria.md"
44665
44957
  ).action(
44666
- async (path77, opts) => {
44958
+ async (path78, opts) => {
44667
44959
  const { validate: validate2 } = await Promise.resolve().then(() => (init_validate(), validate_exports));
44668
- await validate2(path77, opts);
44960
+ await validate2(path78, opts);
44669
44961
  }
44670
44962
  );
44671
44963
  program2.command("update").helpGroup("Project:").description("Update and repair agent skills and prompts to latest version").option(