@jevitate/cli 0.16.1 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -31320,6 +31320,8 @@ var USAGE_ERROR_PATTERNS = [
31320
31320
  var USAGE_ERROR_CODES = /* @__PURE__ */ new Set([
31321
31321
  "E_CHECK_SUITE",
31322
31322
  // the suite (or its preflight) was refused
31323
+ "E_CHAIN_REQUEST",
31324
+ // #580: an approved-requests line is malformed or carries an unknown key — nothing ran
31323
31325
  "E_CAMPAIGN_PREFLIGHT",
31324
31326
  // #485: a campaign's preconditions failed (start URL, session, allow list) — no mission ran
31325
31327
  "E_AI_SETUP_REQUIRED",
@@ -35996,11 +35998,31 @@ async function waitForOutcome(actor, expect, wait, step) {
35996
35998
  }
35997
35999
 
35998
36000
  // ../interpreter/dist/run-step.js
36001
+ var SelectAlternativeUnavailableError = class extends Error {
36002
+ constructor() {
36003
+ super("no-alternative: the select has no enabled option other than the one this proof avoids");
36004
+ this.name = "SelectAlternativeUnavailableError";
36005
+ }
36006
+ };
35999
36007
  async function strictTarget(actor, d, opts) {
36000
36008
  const page = actor.ability(BrowseTheWebToken).session.page;
36001
36009
  const locator = await resolveTarget(page, d, opts);
36002
36010
  return Target.named(descriptorToTarget(d).description).locatedBy(() => locator);
36003
36011
  }
36012
+ async function selectAlternativeValue(locator, avoid) {
36013
+ const value = await locator.evaluate((el, avoided) => {
36014
+ const options = el.options ?? [];
36015
+ for (let i = 0; i < options.length; i += 1) {
36016
+ const option = options[i];
36017
+ if (!option.disabled && option.value !== "" && option.value !== avoided)
36018
+ return option.value;
36019
+ }
36020
+ return null;
36021
+ }, avoid);
36022
+ if (value === null)
36023
+ throw new SelectAlternativeUnavailableError();
36024
+ return value;
36025
+ }
36004
36026
  function resolveValue(value, vars) {
36005
36027
  if ("var" in value) {
36006
36028
  const v = vars.get(value.var);
@@ -36101,9 +36123,12 @@ async function runStep(actor, rec, vars, index = 0, targetOpts = {}) {
36101
36123
  return { kind: "done" };
36102
36124
  }
36103
36125
  case "select": {
36104
- const value = resolveValue(step.value, vars);
36126
+ const alternative = targetOpts.selectAlternative?.(index);
36127
+ const chosen = alternative === void 0 ? resolveValue(step.value, vars) : void 0;
36105
36128
  const page = actor.ability(BrowseTheWebToken).session.page;
36106
- await (await resolveTarget(page, step.target, targetOpts)).selectOption(value);
36129
+ const locator = await resolveTarget(page, step.target, targetOpts);
36130
+ const value = chosen ?? await selectAlternativeValue(locator, alternative.avoid);
36131
+ await locator.selectOption(value);
36107
36132
  await postcondition(actor, expected(step.expect), step.waitFor, "select", index, targetOpts);
36108
36133
  return { kind: "done" };
36109
36134
  }
@@ -36150,8 +36175,14 @@ async function runStep(actor, rec, vars, index = 0, targetOpts = {}) {
36150
36175
  vars.set(`${step.as}.__index`, String(i));
36151
36176
  for (const childStep of step.steps) {
36152
36177
  await runRowScopedChildStep(actor, childStep, rowLocator, vars, expected);
36178
+ if (childStep.kind === "extract") {
36179
+ const value = vars.get(childStep.as);
36180
+ if (value !== void 0)
36181
+ vars.set(`${step.as}.${i}.${childStep.as}`, value);
36182
+ }
36153
36183
  }
36154
36184
  }
36185
+ vars.set(`${step.as}.count`, String(count));
36155
36186
  return { kind: "done" };
36156
36187
  }
36157
36188
  case "handback": {
@@ -36266,6 +36297,7 @@ var RecordingInterpreter = class {
36266
36297
  ...this.options.targetTimeoutMs === void 0 ? {} : { timeoutMs: this.options.targetTimeoutMs },
36267
36298
  ...this.options.observer === void 0 ? {} : { observer: this.options.observer },
36268
36299
  ...this.options.skipStep === void 0 ? {} : { skipStep: this.options.skipStep },
36300
+ ...this.options.selectAlternative === void 0 ? {} : { selectAlternative: this.options.selectAlternative },
36269
36301
  ...this.options.fixtureBaseDir === void 0 ? {} : { fixtureBaseDir: this.options.fixtureBaseDir },
36270
36302
  ...this.options.refLookup === void 0 ? {} : { refLookup: this.options.refLookup }
36271
36303
  };
@@ -53506,7 +53538,7 @@ function assertionSiteKey(site) {
53506
53538
  return `step-request:${site.step}:${site.checkIndex}`;
53507
53539
  return `end-state:${site.index}`;
53508
53540
  }
53509
- var MUTATION_RE = /^(skip|block-write|stale-value|swap-param|truncate-param):(.+)$/;
53541
+ var MUTATION_RE = /^(skip|block-write|stale-value|swap-param|truncate-param|guard-param):(.+)$/;
53510
53542
  var SITE_RE = /^(?:step:[1-9][0-9]*|step-request:[1-9][0-9]*:(?:0|[1-9][0-9]*)|end-state:(?:0|[1-9][0-9]*))$/;
53511
53543
  function flat(journey) {
53512
53544
  return journey.recording.pages.flatMap((p) => p.steps);
@@ -53518,15 +53550,36 @@ function firstActionStep(journey, name) {
53518
53550
  const i = flat(journey).findIndex((r) => actionRefs(r.step).includes(name));
53519
53551
  return i < 0 ? null : i + 1;
53520
53552
  }
53553
+ function allActionReadsAreSelect(journey, name) {
53554
+ const reads2 = flat(journey).filter((r) => actionRefs(r.step).includes(name));
53555
+ return reads2.length > 0 && reads2.every((r) => r.step.kind === "select");
53556
+ }
53557
+ function reviewedValue(journey, name, supplied) {
53558
+ const declared = (journey.metadata.parameters ?? []).find((p) => p.name === name);
53559
+ return declared?.mutationValues?.find((v) => v !== supplied) ?? null;
53560
+ }
53561
+ function selectsVar(step, name) {
53562
+ return step.kind === "select" && "var" in step.value && step.value.var === name;
53563
+ }
53521
53564
  function paramMutation(kind, step, param) {
53522
53565
  return { kind, step, id: `${kind}:${param}`, param };
53523
53566
  }
53567
+ function guardSites(journey, sites, name) {
53568
+ const action = firstActionStep(journey, name);
53569
+ return sites.filter((s3) => s3.where === "step" && siteRefs(s3).includes(name) && (action === null || s3.step < action));
53570
+ }
53524
53571
  function paramMutationRef(journey, kind, name, value) {
53525
53572
  const declared = [...journey.metadata.params, ...(journey.metadata.parameters ?? []).map((p) => p.name)];
53526
53573
  if (!declared.includes(name))
53527
53574
  throw new Error(`${JSON.stringify(value)}: ${JSON.stringify(name)} is not a declared parameter`);
53528
53575
  if (secretParamNames(journey).includes(name))
53529
53576
  throw new Error(`${JSON.stringify(value)}: ${name} is a secret parameter \u2014 a secret is never mutated`);
53577
+ if (kind === "guard-param") {
53578
+ const first = guardSites(journey, journeyAssertions(journey), name)[0];
53579
+ if (first === void 0)
53580
+ throw new Error(`${JSON.stringify(value)}: no step assertion checks ${name} before an action reads it`);
53581
+ return paramMutation(kind, first.step, name);
53582
+ }
53530
53583
  const step = firstActionStep(journey, name);
53531
53584
  if (step === null)
53532
53585
  throw new Error(`${JSON.stringify(value)}: no step's action reads ${name} (a fill or a navigate URL)`);
@@ -53535,9 +53588,9 @@ function paramMutationRef(journey, kind, name, value) {
53535
53588
  function resolveMutationRef(journey, value) {
53536
53589
  const m = MUTATION_RE.exec(value.trim());
53537
53590
  if (m === null)
53538
- throw new Error(`${JSON.stringify(value)} is not a mutation \u2014 expected skip:<step>, block-write:<step> or stale-value:<step> (a step number or an anchor name), or swap-param:<param> / truncate-param:<param>`);
53591
+ throw new Error(`${JSON.stringify(value)} is not a mutation \u2014 expected skip:<step>, block-write:<step> or stale-value:<step> (a step number or an anchor name), or swap-param:<param> / truncate-param:<param> / guard-param:<param>`);
53539
53592
  const ref = m[2];
53540
- if (m[1] === "swap-param" || m[1] === "truncate-param")
53593
+ if (m[1] === "swap-param" || m[1] === "truncate-param" || m[1] === "guard-param")
53541
53594
  return paramMutationRef(journey, m[1], ref, value);
53542
53595
  let step;
53543
53596
  try {
@@ -53653,17 +53706,30 @@ function planJourneyMutations(journey, opts = {}) {
53653
53706
  const params = opts.params ?? {};
53654
53707
  const names = [...new Set(sites.flatMap(siteRefs))];
53655
53708
  for (const name of names) {
53709
+ const supplied = mutableParamValue(journey, name, params);
53710
+ const guards = guardSites(journey, sites, name);
53711
+ const guardValue = supplied === null ? null : reviewedValue(journey, name, supplied) ?? swappedValue(journey, name, params);
53712
+ if (guards.length > 0 && guardValue !== null) {
53713
+ const g = { ...paramMutation("guard-param", guards[0].step, name), source: reviewedValue(journey, name, supplied) === null ? "generated" : "reviewed" };
53714
+ mutations.push(g);
53715
+ for (const s3 of guards)
53716
+ pair(s3, g);
53717
+ }
53656
53718
  const at3 = firstActionStep(journey, name);
53657
53719
  if (at3 === null)
53658
53720
  continue;
53659
- const naming = sites.filter((s3) => siteRefs(s3).includes(name));
53660
- for (const [kind, value] of [
53721
+ const naming = sites.filter((s3) => siteRefs(s3).includes(name) && !guards.includes(s3));
53722
+ if (naming.length === 0)
53723
+ continue;
53724
+ const candidates = [
53661
53725
  ["swap-param", swappedValue(journey, name, params)],
53662
- ["truncate-param", truncatedValue(journey, name, params)]
53663
- ]) {
53726
+ ...allActionReadsAreSelect(journey, name) ? [] : [["truncate-param", truncatedValue(journey, name, params)]]
53727
+ ];
53728
+ const source = supplied !== null && reviewedValue(journey, name, supplied) !== null ? "reviewed" : allActionReadsAreSelect(journey, name) ? "option" : "generated";
53729
+ for (const [kind, value] of candidates) {
53664
53730
  if (value === null)
53665
53731
  continue;
53666
- const m = paramMutation(kind, at3, name);
53732
+ const m = kind === "swap-param" ? { ...paramMutation(kind, at3, name), source } : paramMutation(kind, at3, name);
53667
53733
  mutations.push(m);
53668
53734
  for (const s3 of naming)
53669
53735
  pair(s3, m);
@@ -53686,7 +53752,7 @@ function mutationWait(wait) {
53686
53752
  var MUTATION_WAIT_MARGIN_MS = 5e3;
53687
53753
  function mutationReplay(journey, m, opts = {}) {
53688
53754
  const index = m.step - 1;
53689
- if (m.kind === "swap-param" || m.kind === "truncate-param")
53755
+ if (m.kind === "swap-param" || m.kind === "truncate-param" || m.kind === "guard-param")
53690
53756
  return paramReplay(journey, m, opts.params ?? {});
53691
53757
  if (m.kind === "block-write") {
53692
53758
  const requests = journeyWriteSteps(journey, opts).find((w) => w.step === m.step)?.requests ?? [];
@@ -53719,6 +53785,25 @@ function mutationReplay(journey, m, opts = {}) {
53719
53785
  }
53720
53786
  function paramReplay(journey, m, params) {
53721
53787
  const name = m.param ?? "";
53788
+ const index = m.step - 1;
53789
+ const target = flat(journey)[index]?.step;
53790
+ if (m.kind === "guard-param") {
53791
+ const supplied2 = mutableParamValue(journey, name, params);
53792
+ const wrong = supplied2 === null ? null : reviewedValue(journey, name, supplied2) ?? swappedValue(journey, name, params);
53793
+ if (wrong === null)
53794
+ throw new Error(`${m.id}: parameter ${name} has no value this proof may alter (not supplied, blank, too short, or secret)`);
53795
+ return { journey, params: { ...params, [name]: wrong } };
53796
+ }
53797
+ const reviewedFrom = m.kind === "swap-param" ? mutableParamValue(journey, name, params) : null;
53798
+ const reviewed = reviewedFrom === null ? null : reviewedValue(journey, name, reviewedFrom);
53799
+ if (reviewedFrom !== null && reviewed !== null)
53800
+ return { journey: pinAssertionRefs(journey, name, reviewedFrom), params: { ...params, [name]: reviewed } };
53801
+ if (m.kind === "swap-param" && target !== void 0 && selectsVar(target, name)) {
53802
+ const supplied2 = mutableParamValue(journey, name, params);
53803
+ if (supplied2 === null)
53804
+ throw new Error(`${m.id}: parameter ${name} has no value this proof may alter (not supplied, blank, too short, or secret)`);
53805
+ return { journey: structuredClone(journey), swapSelectAtStep: { index, avoid: supplied2 } };
53806
+ }
53722
53807
  const supplied = mutableParamValue(journey, name, params);
53723
53808
  const altered = m.kind === "swap-param" ? swappedValue(journey, name, params) : truncatedValue(journey, name, params);
53724
53809
  if (supplied === null || altered === null)
@@ -53734,7 +53819,7 @@ function relaxedMutationReplay(journey, m, opts = {}) {
53734
53819
  const index = m.step - 1;
53735
53820
  if (m.kind === "skip")
53736
53821
  return { journey, skipIndex: index };
53737
- if (m.kind === "swap-param" || m.kind === "truncate-param") {
53822
+ if (m.kind === "swap-param" || m.kind === "truncate-param" || m.kind === "guard-param") {
53738
53823
  const how = paramReplay(journey, m, opts.params ?? {});
53739
53824
  const target2 = flat(how.journey)[index];
53740
53825
  if (target2 !== void 0 && "expect" in target2.step) {
@@ -53987,7 +54072,9 @@ var JourneySuccessCriterionSchema = external_exports.object({
53987
54072
  var JourneyParameterSchema = external_exports.object({
53988
54073
  name: external_exports.string().min(1).max(200),
53989
54074
  description: external_exports.string().max(2e3).optional(),
53990
- secret: external_exports.boolean().optional()
54075
+ secret: external_exports.boolean().optional(),
54076
+ // #579: reviewed, non-secret alternative values — at most 20 distinct 1..2000-char strings.
54077
+ mutationValues: external_exports.array(TEXT).min(1).max(20).refine((vs) => new Set(vs).size === vs.length, { message: "mutationValues: duplicate value" }).optional()
53991
54078
  }).strict();
53992
54079
  var CATALOG_REF_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
53993
54080
  var CatalogRefSchema = external_exports.string().regex(CATALOG_REF_RE, "a catalog id: 1-64 of [A-Za-z0-9._-], starting alphanumeric");
@@ -54072,6 +54159,17 @@ var JourneySchema = external_exports.object({
54072
54159
  }));
54073
54160
  for (const issue3 of assertionRefIssues(j))
54074
54161
  ctx.addIssue({ code: "custom", path: [...issue3.path], message: issue3.message });
54162
+ (j.metadata.parameters ?? []).forEach((p, i) => {
54163
+ if (p.mutationValues === void 0)
54164
+ return;
54165
+ if (p.secret === true || SECRET_PARAM_NAME_RE2.test(p.name)) {
54166
+ ctx.addIssue({
54167
+ code: "custom",
54168
+ path: ["metadata", "parameters", i, "mutationValues"],
54169
+ message: `E_MUTATION_VALUES_SECRET: parameter "${p.name}" is a secret (secret: true or a credential-like name) \u2014 mutationValues are reviewed, non-secret values and may never carry a credential`
54170
+ });
54171
+ }
54172
+ });
54075
54173
  });
54076
54174
  function ownAssertions(step) {
54077
54175
  if (step.kind === "assert")
@@ -54305,6 +54403,9 @@ function journeyParamSchema(journey) {
54305
54403
  };
54306
54404
  for (const page of journey.recording.pages) {
54307
54405
  for (const { step } of page.steps) {
54406
+ for (const name of actionRefs(step))
54407
+ if (declared.has(name) && !extracted.has(name) && !required2.includes(name))
54408
+ required2.push(name);
54308
54409
  if (step.kind === "extract")
54309
54410
  extracted.add(step.as);
54310
54411
  for (const { assertion } of ownAssertions(step))
@@ -61887,9 +61988,9 @@ function hostStarvedFailure(failure3, health) {
61887
61988
  }
61888
61989
 
61889
61990
  // src/build-info.generated.ts
61890
- var GENERATED_COMMIT = "2a7bac2";
61891
- var GENERATED_TREE = "e32e8c8";
61892
- var GENERATED_BUILT_AT = "2026-10-18T13:00:37.992Z";
61991
+ var GENERATED_COMMIT = "89237bd";
61992
+ var GENERATED_TREE = "b6b4c8d";
61993
+ var GENERATED_BUILT_AT = "2026-10-18T16:47:05.375Z";
61893
61994
 
61894
61995
  // src/version.ts
61895
61996
  import { readFileSync as readFileSync5 } from "node:fs";
@@ -61911,13 +62012,13 @@ function readCliVersion() {
61911
62012
 
61912
62013
  // src/engine.ts
61913
62014
  function bundledCommit() {
61914
- return true ? "2a7bac2" : void 0;
62015
+ return true ? "89237bd" : void 0;
61915
62016
  }
61916
62017
  function bundledBuiltAt() {
61917
- return true ? "2026-10-18T13:00:37.992Z" : void 0;
62018
+ return true ? "2026-10-18T16:47:05.375Z" : void 0;
61918
62019
  }
61919
62020
  function bundledTree() {
61920
- return true ? "e32e8c8" : void 0;
62021
+ return true ? "b6b4c8d" : void 0;
61921
62022
  }
61922
62023
  function currentBuildTree() {
61923
62024
  return bundledTree() ?? GENERATED_TREE;
@@ -80255,13 +80356,13 @@ import { readFile as readFile9, writeFile as writeFile8, mkdir as mkdir8, rm as
80255
80356
  import { homedir as realHomedir } from "node:os";
80256
80357
  import { join as join19, dirname as dirname6 } from "node:path";
80257
80358
  function detectRuntimes(deps = {}) {
80258
- const existsSync46 = deps.existsSync ?? realExistsSync;
80359
+ const existsSync47 = deps.existsSync ?? realExistsSync;
80259
80360
  const homedir6 = deps.homedir ?? realHomedir;
80260
80361
  const cwd = deps.cwd ?? process.cwd;
80261
80362
  const detected = [];
80262
- if (existsSync46(join19(homedir6(), ".claude"))) detected.push("claude-code");
80263
- if (existsSync46(join19(homedir6(), ".codex"))) detected.push("codex");
80264
- if (existsSync46(join19(cwd(), ".cursor"))) detected.push("cursor");
80363
+ if (existsSync47(join19(homedir6(), ".claude"))) detected.push("claude-code");
80364
+ if (existsSync47(join19(homedir6(), ".codex"))) detected.push("codex");
80365
+ if (existsSync47(join19(cwd(), ".cursor"))) detected.push("cursor");
80265
80366
  detected.push("generic");
80266
80367
  return detected;
80267
80368
  }
@@ -94313,8 +94414,15 @@ async function runJourneyProgrammatically(opts, mutation2 = {}) {
94313
94414
  shots === void 0 ? void 0 : screenshotObserver(shots, (a) => a.ability(BrowseTheWebToken).session.page, whatOf)
94314
94415
  );
94315
94416
  const skipStep = mutation2.skipStep;
94417
+ const selectAlternative = mutation2.selectAlternativeAtStep;
94316
94418
  const fixtureBaseDir = opts.fixtureBaseDir ?? journeyFixtureBaseDir();
94317
- const interpreter = opts.interpreter ?? (opts.observer === void 0 && shots === void 0 && replayDeltas === void 0 && outcomeChecks.observer() === void 0 && blocker === void 0 && healGuard === void 0 && skipStep === void 0 ? new RecordingInterpreter({ fixtureBaseDir, refLookup: refs }) : new RecordingInterpreter({ observer, fixtureBaseDir, refLookup: refs, ...skipStep === void 0 ? {} : { skipStep: (i) => skipStep(i) } }));
94419
+ const interpreter = opts.interpreter ?? (opts.observer === void 0 && shots === void 0 && replayDeltas === void 0 && outcomeChecks.observer() === void 0 && blocker === void 0 && healGuard === void 0 && skipStep === void 0 && selectAlternative === void 0 ? new RecordingInterpreter({ fixtureBaseDir, refLookup: refs }) : new RecordingInterpreter({
94420
+ observer,
94421
+ fixtureBaseDir,
94422
+ refLookup: refs,
94423
+ ...skipStep === void 0 ? {} : { skipStep: (i) => skipStep(i) },
94424
+ ...selectAlternative === void 0 ? {} : { selectAlternative: (i) => i === selectAlternative.index ? { avoid: selectAlternative.avoid } : void 0 }
94425
+ }));
94318
94426
  const heal = opts.heal === void 0 || healGuard === void 0 ? void 0 : { scope: opts.heal.scope, riskOf: journeyStepRisk(), writeGuard: healGuard.guard, allowedOrigins, observe: healObserver(healDir, mask) };
94319
94427
  const runner = new JourneyRunner(actor, interpreter, void 0, void 0, opts.selfHealer, heal);
94320
94428
  let result;
@@ -107504,6 +107612,249 @@ function registerJourneyRun(journey, program2, deps) {
107504
107612
  }));
107505
107613
  }
107506
107614
 
107615
+ // src/journey-cli/chain.ts
107616
+ import { existsSync as existsSync27, readFileSync as readFileSync33 } from "node:fs";
107617
+
107618
+ // src/journey-chain.ts
107619
+ var JourneyChainError = class extends Error {
107620
+ code;
107621
+ constructor(code, message2) {
107622
+ super(message2);
107623
+ this.name = "JourneyChainError";
107624
+ this.code = code;
107625
+ }
107626
+ };
107627
+ var E_CHAIN_FIELD = "E_CHAIN_FIELD";
107628
+ var REQUEST_KEYS = ["commentId", "account", "replyText"];
107629
+ function parseChainRequests(text2) {
107630
+ const requests = [];
107631
+ const lines = text2.split(/\r?\n/);
107632
+ for (let n3 = 0; n3 < lines.length; n3++) {
107633
+ const line2 = lines[n3]?.trim() ?? "";
107634
+ if (line2 === "") continue;
107635
+ let parsed;
107636
+ try {
107637
+ parsed = JSON.parse(line2);
107638
+ } catch {
107639
+ throw new JourneyChainError("E_CHAIN_REQUEST", `request line ${n3 + 1} is not valid JSON`);
107640
+ }
107641
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
107642
+ throw new JourneyChainError("E_CHAIN_REQUEST", `request line ${n3 + 1} must be a JSON object`);
107643
+ }
107644
+ const bag = parsed;
107645
+ const keys = Object.keys(bag);
107646
+ const missing = REQUEST_KEYS.filter((k) => !keys.includes(k));
107647
+ const extra = keys.filter((k) => !REQUEST_KEYS.includes(k));
107648
+ if (missing.length > 0 || extra.length > 0) {
107649
+ throw new JourneyChainError("E_CHAIN_REQUEST", `request line ${n3 + 1} \u2014 missing: [${missing.join(", ")}], unknown: [${extra.join(", ")}]`);
107650
+ }
107651
+ for (const k of REQUEST_KEYS) {
107652
+ if (typeof bag[k] !== "string") {
107653
+ throw new JourneyChainError("E_CHAIN_REQUEST", `request line ${n3 + 1} \u2014 ${k} must be a string`);
107654
+ }
107655
+ }
107656
+ requests.push({ commentId: bag.commentId, account: bag.account, replyText: bag.replyText });
107657
+ }
107658
+ return requests;
107659
+ }
107660
+ var recordKey2 = (commentId, account) => `${commentId}\0${account}`;
107661
+ var asString = (v) => typeof v === "string" && v !== "" ? v : void 0;
107662
+ function readRecords(output3) {
107663
+ const bag = output3 !== null && typeof output3 === "object" ? output3 : {};
107664
+ const raw = bag["records.count"];
107665
+ const count = typeof raw === "string" ? Number.parseInt(raw, 10) : Number.NaN;
107666
+ if (!Number.isInteger(count) || count <= 0) {
107667
+ throw new JourneyChainError("E_CHAIN_EMPTY", `the discover Journey returned no records (records.count = ${raw === void 0 ? "missing" : JSON.stringify(raw)})`);
107668
+ }
107669
+ const field3 = (i, name) => asString(bag[`records.${i}.${name}`]);
107670
+ const records = Array.from({ length: count }, (_, i) => ({
107671
+ commentId: field3(i, "commentId"),
107672
+ account: field3(i, "account"),
107673
+ threadId: field3(i, "threadId"),
107674
+ sourceText: field3(i, "sourceText"),
107675
+ parentId: field3(i, "parentId")
107676
+ }));
107677
+ return { count, records };
107678
+ }
107679
+ function chainParams(record2, request, declared) {
107680
+ const sources = {
107681
+ commentId: record2.commentId,
107682
+ replyIdentity: record2.account,
107683
+ threadId: record2.threadId,
107684
+ expected_commentid: record2.commentId,
107685
+ expected_account: record2.account,
107686
+ expected_sourcetext: record2.sourceText,
107687
+ expected_parentid: record2.parentId
107688
+ };
107689
+ const params = { replyText: request.replyText };
107690
+ for (const [name, value] of Object.entries(sources)) {
107691
+ if (!declared.has(name)) continue;
107692
+ if (value === void 0) return { ok: false, detail: `E_CHAIN_FIELD: the record has no value for ${name}` };
107693
+ params[name] = value;
107694
+ }
107695
+ return { ok: true, params };
107696
+ }
107697
+ var TEXT_PARAMS = ["replyText", "expected_sourcetext"];
107698
+ function redactReason(reason, params) {
107699
+ let out = reason;
107700
+ for (const name of TEXT_PARAMS) {
107701
+ const value = params[name];
107702
+ if (value === void 0 || value === "") continue;
107703
+ for (const form of /* @__PURE__ */ new Set([value, JSON.stringify(value).slice(1, -1)])) out = out.split(form).join(`<param ${name}>`);
107704
+ }
107705
+ return out;
107706
+ }
107707
+ function chainSucceeded(result) {
107708
+ return result.unmatched.length === 0 && result.runs.every((run) => run.outcome === "ok");
107709
+ }
107710
+ function sharedRunOptions(opts) {
107711
+ return {
107712
+ dir: opts.dir,
107713
+ ...opts.environment === void 0 ? {} : { environment: opts.environment },
107714
+ ...opts.storageState === void 0 ? {} : { storageState: opts.storageState },
107715
+ ...opts.browser === void 0 ? {} : { browser: opts.browser },
107716
+ ...opts.emulation === void 0 ? {} : { emulation: opts.emulation },
107717
+ ...opts.browserPortFactory === void 0 ? {} : { browserPortFactory: opts.browserPortFactory },
107718
+ ...opts.allow === void 0 ? {} : { allow: opts.allow },
107719
+ ...opts.siteGate === void 0 ? {} : { siteGate: opts.siteGate }
107720
+ };
107721
+ }
107722
+ async function runJourneyChain(opts, deps = {}) {
107723
+ const requests = parseChainRequests(opts.requests);
107724
+ const runner = deps.runJourney ?? runJourneyProgrammatically;
107725
+ const shared3 = sharedRunOptions(opts);
107726
+ const registry3 = new JourneyRegistry(new FsJourneyStore(opts.dir));
107727
+ const toJourney = await registry3.get(opts.to);
107728
+ if (toJourney === null) throw new UnknownJourneyError(`unknown journey '${opts.to}'`);
107729
+ if (opts.requirePromoted === true) {
107730
+ const fromJourney = await registry3.get(opts.from);
107731
+ if (fromJourney === null) throw new UnknownJourneyError(`unknown journey '${opts.from}'`);
107732
+ for (const j of [fromJourney, toJourney]) {
107733
+ if (!j.metadata.promoted) throw new JourneyChainError("E_CHAIN_NOT_PROMOTED", `journey '${j.metadata.id}' is not promoted \u2014 a chain runs promoted Journeys (journey chain --allow-draft runs drafts on the CLI)`);
107734
+ }
107735
+ }
107736
+ const fromResult = await runner({ ...shared3, id: opts.from, params: {} });
107737
+ if (fromResult.outcome !== "ok") {
107738
+ const reason = "reason" in fromResult ? fromResult.reason : void 0;
107739
+ throw new JourneyChainError(
107740
+ "E_CHAIN_FROM_FAILED",
107741
+ `discover Journey '${opts.from}' did not run ok (${fromResult.outcome})${reason === void 0 ? "" : `: ${reason}`}`
107742
+ );
107743
+ }
107744
+ const { count, records } = readRecords(fromResult.output);
107745
+ const declared = new Set(journeyParamSchema(toJourney).required);
107746
+ const byKey = /* @__PURE__ */ new Map();
107747
+ for (const record2 of records) {
107748
+ if (record2.commentId !== void 0 && record2.account !== void 0) byKey.set(recordKey2(record2.commentId, record2.account), record2);
107749
+ }
107750
+ const runs = [];
107751
+ const unmatched = [];
107752
+ for (const request of requests) {
107753
+ const record2 = byKey.get(recordKey2(request.commentId, request.account));
107754
+ if (record2 === void 0) {
107755
+ unmatched.push({ commentId: request.commentId, account: request.account });
107756
+ continue;
107757
+ }
107758
+ const mapped = chainParams(record2, request, declared);
107759
+ if (!mapped.ok) {
107760
+ runs.push({ commentId: request.commentId, account: request.account, outcome: E_CHAIN_FIELD, reason: mapped.detail });
107761
+ continue;
107762
+ }
107763
+ try {
107764
+ const result = await runner({ ...shared3, id: opts.to, params: mapped.params });
107765
+ runs.push({
107766
+ commentId: request.commentId,
107767
+ account: request.account,
107768
+ outcome: result.outcome,
107769
+ ..."reason" in result ? { reason: redactReason(result.reason, mapped.params) } : {}
107770
+ });
107771
+ } catch (err) {
107772
+ runs.push({ commentId: request.commentId, account: request.account, outcome: "error", reason: redactReason(err instanceof Error ? err.message : String(err), mapped.params) });
107773
+ }
107774
+ }
107775
+ return { from: { journey: opts.from, outcome: "ok", records: count }, runs, unmatched };
107776
+ }
107777
+
107778
+ // src/journey-cli/chain.ts
107779
+ function registerJourneyChain(journey, program2, deps) {
107780
+ withReplayAllowFlag(withEnvironmentFlags(withBrowserLaunchFlags(withEmulationFlags(journey.command("chain"))))).requiredOption("--from <id>", "the discover Journey, run once to produce the records").requiredOption("--to <id>", "the prepare-only reply Journey, run once per matched request").requiredOption("--requests <file>", "JSON Lines file of approved requests ({commentId, account, replyText})").option("--dir <path>", "journeys directory (default: the repo's .jevitate/journeys; outside a repo ~/.jevitate/journeys)").option("--storage-state <file>", "Playwright storageState JSON to start each run authenticated; must exist").option("--allow-draft", "also run Journeys that are not promoted (authoring); without it both must be promoted").option("--json", "emit a JSON envelope").action(async function() {
107781
+ const { from, to, requests: requestsFile, dir, storageState: storageStateFlag, json: json2, allowDraft } = this.opts();
107782
+ const { env: envName, baseUrl } = this.opts();
107783
+ let environment;
107784
+ let allow;
107785
+ try {
107786
+ allow = replayAllowFromFlags(this.opts().allow);
107787
+ environment = environmentFromFlags(
107788
+ { ...envName === void 0 ? {} : { env: envName }, ...baseUrl === void 0 ? {} : { baseUrl } },
107789
+ environmentSeams(deps)
107790
+ );
107791
+ } catch (err) {
107792
+ if (!isEnvironmentError(err)) throw err;
107793
+ emitJson(program2, fail(err.code, err.message));
107794
+ return;
107795
+ }
107796
+ const storageState = storageStateFlag ?? environment?.storageState;
107797
+ if (storageState !== void 0 && !existsSync27(storageState)) {
107798
+ emitJson(program2, fail("E_CHAIN_ARGS", `storage state not found: ${storageState}`));
107799
+ return;
107800
+ }
107801
+ let requests;
107802
+ try {
107803
+ requests = readFileSync33(requestsFile, "utf8");
107804
+ } catch (err) {
107805
+ emitJson(program2, fail("E_CHAIN_ARGS", `could not read requests file ${requestsFile}: ${err instanceof Error ? err.message : String(err)}`));
107806
+ return;
107807
+ }
107808
+ let browser;
107809
+ try {
107810
+ browser = browserRunFromFlags(this.opts(), deps.explore?.env ?? process.env);
107811
+ } catch (err) {
107812
+ emitJson(program2, fail("E_CHAIN_ARGS", err instanceof Error ? err.message : String(err)));
107813
+ return;
107814
+ }
107815
+ let emulation;
107816
+ try {
107817
+ emulation = emulationFromFlags(this.opts());
107818
+ } catch (err) {
107819
+ emitJson(program2, fail("E_CHAIN_ARGS", err instanceof Error ? err.message : String(err)));
107820
+ return;
107821
+ }
107822
+ try {
107823
+ const result = await withSiteGate(
107824
+ resolveDbPath(deps),
107825
+ (siteGate) => runJourneyChain({
107826
+ from,
107827
+ to,
107828
+ requests,
107829
+ dir: resolveJourneysDir(deps, dir),
107830
+ requirePromoted: allowDraft !== true,
107831
+ ...siteGate === void 0 ? {} : { siteGate },
107832
+ browserPortFactory: deps.explore?.browserPortFactory,
107833
+ ...browser === void 0 ? {} : { browser },
107834
+ ...emulation === void 0 ? {} : { emulation },
107835
+ ...storageState !== void 0 ? { storageState } : {},
107836
+ ...environment === void 0 ? {} : { environment },
107837
+ ...allow.length === 0 ? {} : { allow }
107838
+ })
107839
+ );
107840
+ const envelope = ok(result);
107841
+ if (json2) emitJson(program2, envelope);
107842
+ else writeRawResult(program2, result);
107843
+ process.exitCode = chainSucceeded(result) ? 0 : 1;
107844
+ } catch (err) {
107845
+ if (err instanceof JourneyChainError) {
107846
+ emitJson(program2, fail(err.code, err.message));
107847
+ } else if (err instanceof UnknownJourneyError) {
107848
+ emitJson(program2, fail("E_UNKNOWN_JOURNEY", String(err.message)));
107849
+ } else if (isEnvironmentError(err)) {
107850
+ emitJson(program2, fail(err.code, err.message));
107851
+ } else {
107852
+ emitJson(program2, fail("E_CHAIN", String(err instanceof Error ? err.message : err)));
107853
+ }
107854
+ }
107855
+ });
107856
+ }
107857
+
107507
107858
  // src/journey-cli/promote.ts
107508
107859
  import { readFile as readFile31 } from "node:fs/promises";
107509
107860
 
@@ -108052,7 +108403,7 @@ function registerJourneyReview(journey, program2, deps) {
108052
108403
  }
108053
108404
 
108054
108405
  // src/journey-cli/migrate.ts
108055
- import { existsSync as existsSync27 } from "node:fs";
108406
+ import { existsSync as existsSync28 } from "node:fs";
108056
108407
 
108057
108408
  // src/journey-migrate-api.ts
108058
108409
  import { readdir as readdir11, readFile as readFile32, writeFile as writeFile37 } from "node:fs/promises";
@@ -108308,7 +108659,7 @@ function registerJourneyMigrate(journey, program2, deps) {
108308
108659
  return;
108309
108660
  }
108310
108661
  const storageState = storageStateFlag ?? environment?.storageState;
108311
- if (storageState !== void 0 && !existsSync27(storageState)) {
108662
+ if (storageState !== void 0 && !existsSync28(storageState)) {
108312
108663
  emitJson(program2, fail("E_JOURNEY_MIGRATE_ARGS", `storage state not found: ${storageState}`));
108313
108664
  return;
108314
108665
  }
@@ -108641,7 +108992,7 @@ function registerJourneyLint(journey, program2, deps) {
108641
108992
  }
108642
108993
 
108643
108994
  // src/journey-cli/verify.ts
108644
- import { existsSync as existsSync28 } from "node:fs";
108995
+ import { existsSync as existsSync29 } from "node:fs";
108645
108996
 
108646
108997
  // src/journey-verify.ts
108647
108998
  function verifyExitCode(verdict) {
@@ -108691,10 +109042,14 @@ async function verifyJourneyMutations(opts, run = runJourneyProgrammatically) {
108691
109042
  structuredFailures: true,
108692
109043
  ...how.journey === journey ? {} : { mutateJourney: (j) => describe6(j, m, replayOpts2).journey },
108693
109044
  ...how.skipIndex === void 0 ? {} : { skipStep: (i) => i === how.skipIndex },
109045
+ ...how.swapSelectAtStep === void 0 ? {} : { selectAlternativeAtStep: how.swapSelectAtStep },
108694
109046
  ...how.blockIndex === void 0 ? {} : { blockWritesAtStep: how.blockIndex }
108695
109047
  });
108696
109048
  const blocked = r.blockedWrites ?? [];
108697
109049
  const blockedFields = how.blockIndex === void 0 ? {} : { blockedWrites: blocked.map((b2) => `${b2.method} ${b2.path}`) };
109050
+ if (r.outcome === "quarantined" && /no-alternative/.test(r.reason)) {
109051
+ return { outcome: "not-applied", failedSites: [], ...blockedFields, reason: r.reason };
109052
+ }
108698
109053
  if (how.blockIndex !== void 0 && !blockedOwnWrite(how.blockRequests ?? [], blocked)) {
108699
109054
  return {
108700
109055
  outcome: "not-applied",
@@ -108716,7 +109071,15 @@ async function verifyJourneyMutations(opts, run = runJourneyProgrammatically) {
108716
109071
  for (const m of plan2.mutations) {
108717
109072
  const first = await replay(m, mutationReplay);
108718
109073
  const relaxed2 = needsRelaxedReplay(plan2, m, first) ? await replay(m, relaxedMutationReplay) : void 0;
108719
- mutations.push({ kind: m.kind, step: m.step, id: m.id, ...m.param === void 0 ? {} : { param: m.param }, ...first, ...relaxed2 === void 0 ? {} : { relaxed: relaxed2 } });
109074
+ mutations.push({
109075
+ kind: m.kind,
109076
+ step: m.step,
109077
+ id: m.id,
109078
+ ...m.param === void 0 ? {} : { param: m.param },
109079
+ ...m.source === void 0 ? {} : { source: m.source },
109080
+ ...first,
109081
+ ...relaxed2 === void 0 ? {} : { relaxed: relaxed2 }
109082
+ });
108720
109083
  }
108721
109084
  }
108722
109085
  const results = new Map(
@@ -108784,7 +109147,7 @@ function registerJourneyVerify(journey, program2, deps) {
108784
109147
  ...ownFixtureFlags.after === void 0 && environment?.hooks?.after !== void 0 ? { after: environment.hooks.after } : {}
108785
109148
  };
108786
109149
  const storageState = storageStateFlag ?? environment?.storageState;
108787
- if (storageState !== void 0 && !existsSync28(storageState)) {
109150
+ if (storageState !== void 0 && !existsSync29(storageState)) {
108788
109151
  emitJson(program2, fail("E_JOURNEY_VERIFY_ARGS", `storage state not found: ${storageState}`));
108789
109152
  return;
108790
109153
  }
@@ -109211,7 +109574,7 @@ function registerJourneyLinkCommand(journey, program2, deps) {
109211
109574
  }
109212
109575
 
109213
109576
  // src/journey-annotate-cli.ts
109214
- import { existsSync as existsSync29 } from "node:fs";
109577
+ import { existsSync as existsSync30 } from "node:fs";
109215
109578
  function registerJourneyAnnotateCommand(journey, program2, deps) {
109216
109579
  withScreenshotsFlag(withEnvironmentFlags(withBrowserLaunchFlags(withEmulationFlags(withFixtureFlags(journey.command("annotate <id>")))))).description(
109217
109580
  "draft each step's objective/expected result (and the goal/success criteria when missing) by replaying the Journey; writes a reviewable draft, never the Journey \u2014 `--approve` applies a reviewed draft (human gate)"
@@ -109260,7 +109623,7 @@ function registerJourneyAnnotateCommand(journey, program2, deps) {
109260
109623
  ...ownFixtureFlags.after === void 0 && environment?.hooks?.after !== void 0 ? { after: environment.hooks.after } : {}
109261
109624
  };
109262
109625
  const storageState = storageStateFlag ?? environment?.storageState;
109263
- if (storageState !== void 0 && !existsSync29(storageState)) {
109626
+ if (storageState !== void 0 && !existsSync30(storageState)) {
109264
109627
  emitJson(program2, fail("E_JOURNEY_ANNOTATE_ARGS", `storage state not found: ${storageState}`));
109265
109628
  return;
109266
109629
  }
@@ -109348,7 +109711,7 @@ review or edit it, then apply it: jevitate journey annotate ${id} --approve
109348
109711
  }
109349
109712
 
109350
109713
  // src/journey-demo-cli.ts
109351
- import { existsSync as existsSync30 } from "node:fs";
109714
+ import { existsSync as existsSync31 } from "node:fs";
109352
109715
  import { join as join64, resolve as resolvePath15 } from "node:path";
109353
109716
  function registerJourneyDemoCommand(journey, program2, deps) {
109354
109717
  withScreenshotsFlag(withEnvironmentFlags(withDemoFlags(withBrowserLaunchFlags(withEmulationFlags(withFixtureFlags(journey.command("demo <id>"))))))).description(
@@ -109372,7 +109735,7 @@ function registerJourneyDemoCommand(journey, program2, deps) {
109372
109735
  ...ownFixtureFlags.after === void 0 && environment?.hooks?.after !== void 0 ? { after: environment.hooks.after } : {}
109373
109736
  };
109374
109737
  const storageState = storageStateFlag ?? environment?.storageState;
109375
- if (storageState !== void 0 && !existsSync30(storageState)) {
109738
+ if (storageState !== void 0 && !existsSync31(storageState)) {
109376
109739
  emitJson(program2, fail("E_JOURNEY_DEMO_ARGS", `storage state not found: ${storageState}`));
109377
109740
  return;
109378
109741
  }
@@ -109468,6 +109831,7 @@ function registerJourneyCommands(program2, deps) {
109468
109831
  registerJourneyList(journey, program2, deps);
109469
109832
  registerJourneyFind(journey, program2, deps);
109470
109833
  registerJourneyRun(journey, program2, deps);
109834
+ registerJourneyChain(journey, program2, deps);
109471
109835
  registerJourneyPromote(journey, program2, deps);
109472
109836
  registerJourneyReview(journey, program2, deps);
109473
109837
  registerJourneyMigrate(journey, program2, deps);
@@ -109492,7 +109856,7 @@ function registerBuiltinAnalyzers() {
109492
109856
  }
109493
109857
 
109494
109858
  // src/source-cli.ts
109495
- import { existsSync as existsSync31 } from "node:fs";
109859
+ import { existsSync as existsSync32 } from "node:fs";
109496
109860
 
109497
109861
  // src/source-run-api.ts
109498
109862
  var realResolvedJourneyRunner = async (file2, params, policy, storageState, emulation, browser, siteGate) => {
@@ -109710,7 +110074,7 @@ function registerSourceCommands(program2, deps) {
109710
110074
  "Playwright storageState JSON to start the session authenticated (#118: required when the journey declares metadata.requiresAuth); must exist"
109711
110075
  ).option("--json", "emit a JSON envelope").option(TAG_FLAG, TAG_HELP, collectTag, []).action(taggedAction(program2, "source run", async function(name, journeyId) {
109712
110076
  const { param, storageState, json: json2, ...emulationFlags } = this.opts();
109713
- if (storageState !== void 0 && !existsSync31(storageState)) {
110077
+ if (storageState !== void 0 && !existsSync32(storageState)) {
109714
110078
  emitJson(program2, fail("E_SOURCE_RUN_ARGS", `storage state not found: ${storageState}`));
109715
110079
  return;
109716
110080
  }
@@ -109773,7 +110137,7 @@ function registerSourceCommands(program2, deps) {
109773
110137
  }
109774
110138
 
109775
110139
  // src/load-cli.ts
109776
- import { existsSync as existsSync32 } from "node:fs";
110140
+ import { existsSync as existsSync33 } from "node:fs";
109777
110141
 
109778
110142
  // ../load/dist/percentiles.js
109779
110143
  function percentile(sorted2, p) {
@@ -109981,7 +110345,7 @@ function registerLoadCommands(program2, deps) {
109981
110345
  return;
109982
110346
  }
109983
110347
  const storageState = storageStateFlag ?? environment?.storageState;
109984
- if (storageState !== void 0 && !existsSync32(storageState)) {
110348
+ if (storageState !== void 0 && !existsSync33(storageState)) {
109985
110349
  emitJson(program2, fail("E_LOAD_RUN_ARGS", `storage state not found: ${storageState}`));
109986
110350
  return;
109987
110351
  }
@@ -110031,10 +110395,10 @@ function registerLoadCommands(program2, deps) {
110031
110395
  }
110032
110396
 
110033
110397
  // src/explore-cli/run.ts
110034
- import { existsSync as existsSync34 } from "node:fs";
110398
+ import { existsSync as existsSync35 } from "node:fs";
110035
110399
 
110036
110400
  // src/type-fixture-file.ts
110037
- import { readFileSync as readFileSync33, statSync as statSync10 } from "node:fs";
110401
+ import { readFileSync as readFileSync34, statSync as statSync10 } from "node:fs";
110038
110402
  import { basename as basename15, resolve as resolve18 } from "node:path";
110039
110403
  var TYPE_FIXTURE_MAX_BYTES = 256 * 1024;
110040
110404
  function loadTypeFixtures(specs, cwd = process.cwd()) {
@@ -110053,7 +110417,7 @@ function loadTypeFixtures(specs, cwd = process.cwd()) {
110053
110417
  if (size > TYPE_FIXTURE_MAX_BYTES) {
110054
110418
  throw new TypeFixtureSpecError(`--type-fixture ${descriptor}: ${path2} is ${size} bytes (at most ${TYPE_FIXTURE_MAX_BYTES})`);
110055
110419
  }
110056
- const bytes = readFileSync33(abs);
110420
+ const bytes = readFileSync34(abs);
110057
110421
  let text2;
110058
110422
  try {
110059
110423
  text2 = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
@@ -110374,7 +110738,7 @@ async function runExploreMultiRun(args) {
110374
110738
  import { resolve as resolvePath16 } from "node:path";
110375
110739
 
110376
110740
  // src/campaign-api.ts
110377
- import { existsSync as existsSync33, readFileSync as readFileSync34 } from "node:fs";
110741
+ import { existsSync as existsSync34, readFileSync as readFileSync35 } from "node:fs";
110378
110742
  import { mkdir as mkdir31, writeFile as writeFile39 } from "node:fs/promises";
110379
110743
  import { homedir as homedir5 } from "node:os";
110380
110744
  import { dirname as dirname28, isAbsolute as isAbsolute11, join as join66, resolve as resolve19 } from "node:path";
@@ -110491,7 +110855,7 @@ var at2 = (path2) => path2.length === 0 ? "spec" : path2.map((p) => typeof p ===
110491
110855
  async function validateCampaign(specPath, opts) {
110492
110856
  let raw;
110493
110857
  try {
110494
- raw = JSON.parse(readFileSync34(specPath, "utf8"));
110858
+ raw = JSON.parse(readFileSync35(specPath, "utf8"));
110495
110859
  } catch (e) {
110496
110860
  throw new CampaignSpecError([`cannot read ${specPath}: ${e instanceof SyntaxError ? "not valid JSON" : e instanceof Error ? e.message : String(e)}`]);
110497
110861
  }
@@ -110515,8 +110879,8 @@ async function validateCampaignSpec(raw, specPath, opts) {
110515
110879
  problems.push(`env: ${err.message}`);
110516
110880
  }
110517
110881
  const defaultSession = spec.storageState === void 0 ? environment?.storageState : abs(spec.storageState);
110518
- if (spec.storageState !== void 0 && !existsSync33(abs(spec.storageState))) problems.push(`storageState: not found: ${abs(spec.storageState)}`);
110519
- if (spec.fixtures !== void 0 && !existsSync33(abs(spec.fixtures))) problems.push(`fixtures: not found: ${abs(spec.fixtures)}`);
110882
+ if (spec.storageState !== void 0 && !existsSync34(abs(spec.storageState))) problems.push(`storageState: not found: ${abs(spec.storageState)}`);
110883
+ if (spec.fixtures !== void 0 && !existsSync34(abs(spec.fixtures))) problems.push(`fixtures: not found: ${abs(spec.fixtures)}`);
110520
110884
  if ((spec.before !== void 0 || spec.after !== void 0) && opts.allowShellHooks !== true) {
110521
110885
  problems.push("before/after: operator shell hooks run only with --allow-shell-hooks");
110522
110886
  }
@@ -110541,7 +110905,7 @@ async function validateCampaignSpec(raw, specPath, opts) {
110541
110905
  }
110542
110906
  if (new Set(job.strategies).size !== job.strategies.length) problems.push(`${where}.strategies: duplicate strategy`);
110543
110907
  const session2 = job.storageState === void 0 ? defaultSession : abs(job.storageState);
110544
- if (job.storageState !== void 0 && !existsSync33(abs(job.storageState))) problems.push(`${where}.storageState: not found: ${abs(job.storageState)}`);
110908
+ if (job.storageState !== void 0 && !existsSync34(abs(job.storageState))) problems.push(`${where}.storageState: not found: ${abs(job.storageState)}`);
110545
110909
  let stored = null;
110546
110910
  try {
110547
110911
  stored = await registry3.get(job.journey);
@@ -112309,7 +112673,7 @@ function registerExploreRun(program2, deps, buildProgram2) {
112309
112673
  emitExplore(fail(err.code, err.message));
112310
112674
  return;
112311
112675
  }
112312
- if (o.storageState !== void 0 && !existsSync34(o.storageState) && (authCheck.mode === "off" || projectPersona?.login === void 0)) {
112676
+ if (o.storageState !== void 0 && !existsSync35(o.storageState) && (authCheck.mode === "off" || projectPersona?.login === void 0)) {
112313
112677
  emitExplore(fail("E_EXPLORE_ARGS", `storage state not found: ${o.storageState}`));
112314
112678
  return;
112315
112679
  }
@@ -112601,11 +112965,11 @@ function pick3(k, v) {
112601
112965
  import { resolve as resolve22 } from "node:path";
112602
112966
 
112603
112967
  // src/sweep-api.ts
112604
- import { existsSync as existsSync36, mkdirSync as mkdirSync11, readFileSync as readFileSync35, realpathSync as realpathSync5, statSync as statSync11, writeFileSync as writeFileSync13 } from "node:fs";
112968
+ import { existsSync as existsSync37, mkdirSync as mkdirSync11, readFileSync as readFileSync36, realpathSync as realpathSync5, statSync as statSync11, writeFileSync as writeFileSync13 } from "node:fs";
112605
112969
  import { basename as basename18, dirname as dirname30, extname as extname2, join as join68, resolve as resolve21 } from "node:path";
112606
112970
 
112607
112971
  // src/mcp-paths.ts
112608
- import { existsSync as existsSync35, realpathSync as realpathSync4 } from "node:fs";
112972
+ import { existsSync as existsSync36, realpathSync as realpathSync4 } from "node:fs";
112609
112973
  import { basename as basename17, dirname as dirname29, isAbsolute as isAbsolute12, join as join67, relative as relative9, resolve as resolve20, sep as sep9 } from "node:path";
112610
112974
  var McpPathError = class extends Error {
112611
112975
  error = "invalid_args";
@@ -112623,7 +112987,7 @@ function realish(p) {
112623
112987
  let head2 = p;
112624
112988
  const tail = [];
112625
112989
  for (; ; ) {
112626
- if (existsSync35(head2)) {
112990
+ if (existsSync36(head2)) {
112627
112991
  try {
112628
112992
  return join67(realpathSync4(head2), ...tail);
112629
112993
  } catch {
@@ -112999,6 +113363,29 @@ var CLI_TOOL_SPECS = [
112999
113363
  omitted: { "--dir": OMIT.storeDir, "--allow": OMIT.mcpOrigins, ...HOOK_FLAGS, ...BROWSER_FLAGS, ...JSON_FLAG }
113000
113364
  }
113001
113365
  },
113366
+ {
113367
+ name: "chain_journeys",
113368
+ description: "`jevitate journey chain --from <discover> --to <reply> --requests <file>` (#580): run a discover Journey once, then a prepare-only reply Journey once per approved request in the JSON Lines file ({commentId, account, replyText}) matched to a discovered record by commentId AND account. Both Journeys must be promoted. Unmatched requests never run; an empty discovery stops the chain (no target is guessed). The result names ids and outcomes only, never record or reply text. Exit 0 only when every request matched and its run was ok.",
113369
+ command: {
113370
+ path: "journey chain",
113371
+ params: {
113372
+ from: s2("--from", { required: true }),
113373
+ to: s2("--to", { required: true }),
113374
+ requests: path("--requests", { required: true }),
113375
+ storageState: session("--storage-state"),
113376
+ ...EXTENSION,
113377
+ ...EMULATION,
113378
+ ...ENVIRONMENT
113379
+ },
113380
+ omitted: {
113381
+ "--allow-draft": "#580: over MCP a chain runs promoted Journeys only, as run_journey does; running drafts is the operator's CLI call",
113382
+ "--dir": OMIT.storeDir,
113383
+ "--allow": OMIT.mcpOrigins,
113384
+ ...BROWSER_FLAGS,
113385
+ ...JSON_FLAG
113386
+ }
113387
+ }
113388
+ },
113002
113389
  {
113003
113390
  name: "publish_journey",
113004
113391
  description: "`jevitate journey publish <id> --to <source>`: publish a promoted Journey into a registered source on a new publish/<id> branch (a PR when gh is available). Secret references only; declared origins must cover its steps.",
@@ -114025,7 +114412,7 @@ function personaOf(value, base, roots, where, problems) {
114025
114412
  }
114026
114413
  try {
114027
114414
  const confined = confineMcpPath(abs, `persona of ${where}`, roots, { session: true });
114028
- if (!existsSync36(confined)) {
114415
+ if (!existsSync37(confined)) {
114029
114416
  problems.push(`${where}: persona storage state not found: ${confined}`);
114030
114417
  return void 0;
114031
114418
  }
@@ -114094,8 +114481,8 @@ function validateRunShaping(options, strategy, where, problems) {
114094
114481
  }
114095
114482
  function loadSweepTargets(path2, opts = {}) {
114096
114483
  const abs = resolve21(path2);
114097
- if (!existsSync36(abs)) throw new SweepSpecError(`targets file not found: ${abs}`);
114098
- const text2 = readFileSync35(abs, "utf8");
114484
+ if (!existsSync37(abs)) throw new SweepSpecError(`targets file not found: ${abs}`);
114485
+ const text2 = readFileSync36(abs, "utf8");
114099
114486
  const isTsv = /\.(tsv|txt)$/i.test(abs);
114100
114487
  const parsed = isTsv ? parseTsv(text2, path2) : parseJson(text2, path2);
114101
114488
  const problems = [...parsed.problems];
@@ -114342,9 +114729,9 @@ function targetArgv(plan2, target, runDir) {
114342
114729
  ];
114343
114730
  }
114344
114731
  function finishedEnvelope(envelopePath) {
114345
- if (!existsSync36(envelopePath)) return void 0;
114732
+ if (!existsSync37(envelopePath)) return void 0;
114346
114733
  try {
114347
- const env = JSON.parse(readFileSync35(envelopePath, "utf8"));
114734
+ const env = JSON.parse(readFileSync36(envelopePath, "utf8"));
114348
114735
  if (!isRecord(env) || env.ok !== true || !isRecord(env.data)) return void 0;
114349
114736
  if (env.data.interrupted !== void 0) return void 0;
114350
114737
  return env;
@@ -114718,7 +115105,7 @@ function registerVerifyFixCommands(program2, deps) {
114718
115105
  }
114719
115106
 
114720
115107
  // src/author-journey-cli.ts
114721
- import { existsSync as existsSync37 } from "node:fs";
115108
+ import { existsSync as existsSync38 } from "node:fs";
114722
115109
  var AUTHOR_GOAL_RUN_FLAGS = [
114723
115110
  "successWhen",
114724
115111
  "allowVacuousChecks",
@@ -114814,7 +115201,7 @@ function registerAuthorJourneyCommands(program2, deps) {
114814
115201
  ].join("\n")
114815
115202
  ).action(async function() {
114816
115203
  const o = this.opts();
114817
- if (o.storageState !== void 0 && !existsSync37(o.storageState)) {
115204
+ if (o.storageState !== void 0 && !existsSync38(o.storageState)) {
114818
115205
  emitJson(program2, fail("E_EXPLORE_ARGS", `storage state not found: ${o.storageState}`));
114819
115206
  return;
114820
115207
  }
@@ -114936,11 +115323,11 @@ function registerAuthorJourneyCommands(program2, deps) {
114936
115323
  }
114937
115324
 
114938
115325
  // src/demo-aspect-cli.ts
114939
- import { existsSync as existsSync39 } from "node:fs";
115326
+ import { existsSync as existsSync40 } from "node:fs";
114940
115327
  import { join as join71, resolve as resolvePath18 } from "node:path";
114941
115328
 
114942
115329
  // src/demo-aspect-api.ts
114943
- import { existsSync as existsSync38 } from "node:fs";
115330
+ import { existsSync as existsSync39 } from "node:fs";
114944
115331
  import { mkdir as mkdir33, mkdtemp as mkdtemp5, readFile as readFile33, rm as rm13, writeFile as writeFile41 } from "node:fs/promises";
114945
115332
  import { tmpdir as tmpdir5 } from "node:os";
114946
115333
  import { dirname as dirname31, join as join70 } from "node:path";
@@ -115277,7 +115664,7 @@ async function demoAspect(opts) {
115277
115664
  const store = new FsJourneyStore(opts.journeysDir);
115278
115665
  if (await store.get(id) !== null) throw new DemoExistsError(`journey '${id}' already exists \u2014 pick another --id (nothing was changed)`);
115279
115666
  const recordPath = demoDraftPath(opts.journeysDir, id);
115280
- if (existsSync38(recordPath)) {
115667
+ if (existsSync39(recordPath)) {
115281
115668
  throw new DemoExistsError(`a demo draft '${id}' is waiting for approval (${recordPath}) \u2014 approve it with \`jevitate demo approve ${id}\`, or pick another --id`);
115282
115669
  }
115283
115670
  const maxReplays = opts.maxReplays ?? DEMO_MINIMIZE_MAX_REPLAYS;
@@ -115524,7 +115911,7 @@ function replayOptionsFrom(cmd, deps, o, environment) {
115524
115911
  fixtureIdentity: o.fixtureIdentity
115525
115912
  };
115526
115913
  const storageState = o.storageState ?? environment.storageState;
115527
- if (storageState !== void 0 && !existsSync39(storageState)) throw new DemoAspectArgsError(`storage state not found: ${storageState}`);
115914
+ if (storageState !== void 0 && !existsSync40(storageState)) throw new DemoAspectArgsError(`storage state not found: ${storageState}`);
115528
115915
  let browser;
115529
115916
  let emulation;
115530
115917
  try {
@@ -115877,12 +116264,12 @@ function registerRecordCommands(program2, deps) {
115877
116264
  }
115878
116265
 
115879
116266
  // src/regression-cli.ts
115880
- import { existsSync as existsSync41 } from "node:fs";
116267
+ import { existsSync as existsSync42 } from "node:fs";
115881
116268
  import { readFile as readFile35, writeFile as writeFile43 } from "node:fs/promises";
115882
116269
  import { join as join73 } from "node:path";
115883
116270
 
115884
116271
  // src/regression-api.ts
115885
- import { existsSync as existsSync40 } from "node:fs";
116272
+ import { existsSync as existsSync41 } from "node:fs";
115886
116273
  import { readFile as readFile34 } from "node:fs/promises";
115887
116274
  var RegressionExistsError = class extends Error {
115888
116275
  code = "E_REGRESSION_EXISTS";
@@ -115970,7 +116357,7 @@ function describeNoOracle(missionResult) {
115970
116357
  }
115971
116358
  async function runRegressionCapture(opts) {
115972
116359
  const recordingPath = safeChildPath(opts.regressionsDir, opts.id, { what: "regression id", suffix: ".recording.json" });
115973
- if (opts.force !== true && existsSync40(recordingPath)) {
116360
+ if (opts.force !== true && existsSync41(recordingPath)) {
115974
116361
  throw new RegressionExistsError(opts.id, opts.regressionsDir);
115975
116362
  }
115976
116363
  const raw = JSON.parse(await readFile34(opts.failingRecordingPath, "utf8"));
@@ -116212,12 +116599,12 @@ function registerRegressionCommands(program2, deps) {
116212
116599
  const { from, id, dir, attempts, summary: summary2, result: resultPath, fingerprint: fingerprint2, storageState, force, json: json2, param } = flags;
116213
116600
  if (refuseUnsafeName(program2, id, "regression id")) return;
116214
116601
  for (const [flag, path2] of [["--from", from], ["--result", resultPath]]) {
116215
- if (path2 !== void 0 && !existsSync41(path2)) {
116602
+ if (path2 !== void 0 && !existsSync42(path2)) {
116216
116603
  emitJson(program2, fail("E_REGRESSION_ARGS", `${flag} file not found: ${path2}`));
116217
116604
  return;
116218
116605
  }
116219
116606
  }
116220
- if (storageState !== void 0 && !existsSync41(storageState)) {
116607
+ if (storageState !== void 0 && !existsSync42(storageState)) {
116221
116608
  emitJson(program2, fail("E_REGRESSION_ARGS", `storage state not found: ${storageState}`));
116222
116609
  return;
116223
116610
  }
@@ -116314,7 +116701,7 @@ function registerRegressionCommands(program2, deps) {
116314
116701
  return;
116315
116702
  }
116316
116703
  const storageState = storageStateFlag ?? environment?.storageState;
116317
- if (storageState !== void 0 && !existsSync41(storageState)) {
116704
+ if (storageState !== void 0 && !existsSync42(storageState)) {
116318
116705
  emitJson(program2, fail("E_REGRESSION_ARGS", `storage state not found: ${storageState}`));
116319
116706
  return;
116320
116707
  }
@@ -116327,7 +116714,7 @@ function registerRegressionCommands(program2, deps) {
116327
116714
  }
116328
116715
  if (refuseUnsafeName(program2, id, "regression id")) return;
116329
116716
  const regressionsDir = resolveRegressionsDir(dir);
116330
- if (!existsSync41(join73(regressionsDir, `${id}.recording.json`))) {
116717
+ if (!existsSync42(join73(regressionsDir, `${id}.recording.json`))) {
116331
116718
  const notFound = new RegressionNotFoundError(id, regressionsDir);
116332
116719
  emitJson(program2, fail(notFound.code, notFound.message));
116333
116720
  return;
@@ -116385,7 +116772,7 @@ function registerRegressionCommands(program2, deps) {
116385
116772
  }
116386
116773
 
116387
116774
  // src/mission-api.ts
116388
- import { existsSync as existsSync42 } from "node:fs";
116775
+ import { existsSync as existsSync43 } from "node:fs";
116389
116776
  import { resolve as resolvePath19 } from "node:path";
116390
116777
  var UnknownMissionTargetError = class extends Error {
116391
116778
  };
@@ -116423,7 +116810,7 @@ function applyAuth(target, auth) {
116423
116810
  }
116424
116811
  if (auth.storageState !== void 0) {
116425
116812
  const abs = resolvePath19(auth.storageState);
116426
- if (!existsSync42(abs)) throw new MissionTargetAuthError(`storage state not found: ${abs}`);
116813
+ if (!existsSync43(abs)) throw new MissionTargetAuthError(`storage state not found: ${abs}`);
116427
116814
  base.storageState = abs;
116428
116815
  }
116429
116816
  if (auth.saveStorageState !== void 0) base.saveStorageState = auth.saveStorageState === true ? true : resolvePath19(auth.saveStorageState);
@@ -116468,7 +116855,7 @@ async function promoteMissionTarget(ctx, id) {
116468
116855
  }
116469
116856
 
116470
116857
  // src/mission-queue-cli.ts
116471
- import { readFileSync as readFileSync36 } from "node:fs";
116858
+ import { readFileSync as readFileSync37 } from "node:fs";
116472
116859
  import { Option as Option2 } from "commander";
116473
116860
 
116474
116861
  // src/mcp-api.ts
@@ -116527,6 +116914,9 @@ var ALLOWED_TOOLS = [
116527
116914
  // #401 — the assertion-strength lint promote_journey applies; #402 — its mutation proof.
116528
116915
  "lint_journey",
116529
116916
  "verify_journey",
116917
+ // #580 — the two-journey chain: discover once, prepare-only reply per approved request. Promoted
116918
+ // Journeys only (--allow-draft is CLI-only); ids and outcomes only, never record or reply text.
116919
+ "chain_journeys",
116530
116920
  // #425 — a sweep: many explore missions over a targets file, one aggregated result.
116531
116921
  "run_sweep",
116532
116922
  // #432 — the read-only review sheet a person reads before promote_journey (bound by its content hash).
@@ -117296,7 +117686,7 @@ var tagsArg = (args) => {
117296
117686
  };
117297
117687
 
117298
117688
  // src/mcp-tools/findings.ts
117299
- import { existsSync as existsSync43 } from "node:fs";
117689
+ import { existsSync as existsSync44 } from "node:fs";
117300
117690
  import { access, readFile as readFile37 } from "node:fs/promises";
117301
117691
  import { join as join77 } from "node:path";
117302
117692
  function findingTools(ctx) {
@@ -117386,7 +117776,7 @@ function findingTools(ctx) {
117386
117776
  };
117387
117777
  const verifyFixOptions = (args) => {
117388
117778
  const storageState = optPath(args, "storageState", pathRoots, { session: true });
117389
- if (storageState !== void 0 && !existsSync43(storageState)) throw new McpArgError(`storage state not found: ${storageState}`);
117779
+ if (storageState !== void 0 && !existsSync44(storageState)) throw new McpArgError(`storage state not found: ${storageState}`);
117390
117780
  const replays = optInt(args, "replays", 1);
117391
117781
  const invariantFiles = (optStringArray(args, "invariants") ?? []).map((f2, i) => optPath({ [`invariants[${i}]`]: f2 }, `invariants[${i}]`, pathRoots));
117392
117782
  const fixtures = optPath(args, "fixtures", pathRoots);
@@ -117515,7 +117905,7 @@ function findingTools(ctx) {
117515
117905
  }
117516
117906
 
117517
117907
  // src/mcp-tools/journey.ts
117518
- import { existsSync as existsSync44 } from "node:fs";
117908
+ import { existsSync as existsSync45 } from "node:fs";
117519
117909
  function journeyTools(ctx) {
117520
117910
  const { deps, pathRoots, credentialStore, runJourney } = ctx;
117521
117911
  const findCaps = deps.findCapabilities ?? ((query) => findCapabilities(new JourneyRegistry(new FsJourneyStore(deps.journeysDir)), query));
@@ -117528,7 +117918,7 @@ function journeyTools(ctx) {
117528
117918
  { ...deps.environmentsFile === void 0 ? {} : { environmentsFile: deps.environmentsFile }, ...deps.targetsConfigPath === void 0 ? {} : { targetsFile: deps.targetsConfigPath } }
117529
117919
  );
117530
117920
  const storageState = optPath(args, "storageState", pathRoots, { session: true }) ?? environment?.storageState;
117531
- if (args.storageState !== void 0 && storageState !== void 0 && !existsSync44(storageState)) throw new McpArgError(`storage state not found: ${storageState}`);
117921
+ if (args.storageState !== void 0 && storageState !== void 0 && !existsSync45(storageState)) throw new McpArgError(`storage state not found: ${storageState}`);
117532
117922
  const headed = optBool(args, "headed");
117533
117923
  const slowMo = optInt(args, "slowMo", 0);
117534
117924
  const recordVideo = optRecordVideo(args, pathRoots);
@@ -118142,7 +118532,7 @@ function registerMissionQueueCommands(program2, mission, deps) {
118142
118532
  let invariants;
118143
118533
  if (o.invariants !== void 0) {
118144
118534
  try {
118145
- invariants = JSON.parse(readFileSync36(o.invariants, "utf8"));
118535
+ invariants = JSON.parse(readFileSync37(o.invariants, "utf8"));
118146
118536
  } catch (e) {
118147
118537
  refuse4("E_MISSION_QUEUE_INVARIANTS", `cannot read invariants file ${o.invariants}: ${e instanceof Error ? e.message.split("\n")[0] : String(e)}`);
118148
118538
  return;
@@ -118899,7 +119289,7 @@ function registerUxCommands(program2, deps) {
118899
119289
  }
118900
119290
 
118901
119291
  // src/logs-retention.ts
118902
- import { readFileSync as readFileSync37, readdirSync as readdirSync11, rmSync as rmSync2, rmdirSync as rmdirSync2, statSync as statSync12 } from "node:fs";
119292
+ import { readFileSync as readFileSync38, readdirSync as readdirSync11, rmSync as rmSync2, rmdirSync as rmdirSync2, statSync as statSync12 } from "node:fs";
118903
119293
  import { join as join79 } from "node:path";
118904
119294
  var DEFAULT_LOGS_RETENTION = { ttlDays: 14, keepLatest: 50 };
118905
119295
  var LogsConfigError = class extends Error {
@@ -118908,7 +119298,7 @@ var LogsConfigError = class extends Error {
118908
119298
  function loadLogsRetention(path2 = resolveDataDir(["config.json"])) {
118909
119299
  let raw;
118910
119300
  try {
118911
- raw = readFileSync37(path2, "utf8");
119301
+ raw = readFileSync38(path2, "utf8");
118912
119302
  } catch (e) {
118913
119303
  if (typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT") return DEFAULT_LOGS_RETENTION;
118914
119304
  throw new LogsConfigError(`cannot read ${path2}: ${e instanceof Error ? e.message : String(e)}`);
@@ -118969,8 +119359,8 @@ function pruneLogs(root2, retention, opts = {}) {
118969
119359
  }
118970
119360
 
118971
119361
  // src/logs-cli.ts
118972
- import { readFileSync as readFileSync38 } from "node:fs";
118973
- import { existsSync as existsSync45 } from "node:fs";
119362
+ import { readFileSync as readFileSync39 } from "node:fs";
119363
+ import { existsSync as existsSync46 } from "node:fs";
118974
119364
  var LOG_WRITING_COMMANDS = /* @__PURE__ */ new Set(["explore", "explore-author-journey", "record", "ux", "check", "run", "verify-fix", "capture"]);
118975
119365
  function registerLogsCommands(program2, deps) {
118976
119366
  const configPath = deps.logs?.configPath ?? resolveDataDir(["config.json"]);
@@ -119008,7 +119398,7 @@ function registerLogsCommands(program2, deps) {
119008
119398
  const emit5 = (envelope) => emitJson(program2, envelope);
119009
119399
  if (o.real === true && o.fakeAi === true) return emit5(fail("E_LOGS_ARGS", "--real and --fake-ai are mutually exclusive \u2014 pass one, not both"));
119010
119400
  if (o.threshold !== void 0 && !(o.threshold >= 0 && o.threshold <= 1)) return emit5(fail("E_LOGS_ARGS", "--threshold must be a probability in 0..1"));
119011
- if (!existsSync45(signalsPathFor(o.result))) {
119401
+ if (!existsSync46(signalsPathFor(o.result))) {
119012
119402
  return emit5(fail("E_LOGS_ARGS", `no signals next to ${o.result} (${signalsPathFor(o.result)}): run explore with --log-source and --log-triage first`));
119013
119403
  }
119014
119404
  let secrets;
@@ -119021,7 +119411,7 @@ function registerLogsCommands(program2, deps) {
119021
119411
  throw err;
119022
119412
  }
119023
119413
  try {
119024
- const file2 = JSON.parse(readFileSync38(o.result, "utf8"));
119414
+ const file2 = JSON.parse(readFileSync39(o.result, "utf8"));
119025
119415
  if (typeof file2.result !== "object" || file2.result === null) return emit5(fail("E_LOGS_ARGS", `${o.result} is not a jevitate run result`));
119026
119416
  const judge = o.real === true ? (await buildExploreGateways(deps, { real: true, fakeAi: false, jevProvider: o.jevProvider })).judge : void 0;
119027
119417
  const updated = await triageRunResult(file2.result, o.result, {
@@ -119045,7 +119435,7 @@ result ${o.result}
119045
119435
  }
119046
119436
 
119047
119437
  // src/inbox-cli.ts
119048
- import { readFileSync as readFileSync39 } from "node:fs";
119438
+ import { readFileSync as readFileSync40 } from "node:fs";
119049
119439
  import { Option as Option3 } from "commander";
119050
119440
  var INBOX_DIR_HELP = "inbox store directory (default: ~/.jevitate/inbox \u2014 the dir `jevitate mcp` and `jevitate ui` use)";
119051
119441
  var REDACTED = "***REDACTED***";
@@ -119153,7 +119543,7 @@ function registerInboxCommands(program2, deps) {
119153
119543
  let findings;
119154
119544
  if (o.findings !== void 0) {
119155
119545
  try {
119156
- findings = JSON.parse(readFileSync39(o.findings, "utf8"));
119546
+ findings = JSON.parse(readFileSync40(o.findings, "utf8"));
119157
119547
  } catch (e) {
119158
119548
  const code = `E_${commandPath(cmd).toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_INPUT`;
119159
119549
  emitJsonOrRefusal(program2, fail(code, `cannot read --findings ${o.findings}: ${e instanceof Error ? e.message.split("\n")[0] : String(e)}`));