@jevitate/cli 0.16.0 → 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/README.md +55 -5
- package/dist/bin.js +513 -92
- package/dist/build-info.generated.js +3 -3
- package/dist/campaign-api.js +2 -2
- package/dist/campaign-api.js.map +1 -1
- package/dist/exit-codes.js +1 -0
- package/dist/exit-codes.js.map +1 -1
- package/dist/journey-api.d.ts +9 -1
- package/dist/journey-api.js +14 -7
- package/dist/journey-api.js.map +1 -1
- package/dist/journey-chain.d.ts +92 -0
- package/dist/journey-chain.js +200 -0
- package/dist/journey-chain.js.map +1 -0
- package/dist/journey-cli/chain.d.ts +8 -0
- package/dist/journey-cli/chain.js +106 -0
- package/dist/journey-cli/chain.js.map +1 -0
- package/dist/journey-cli.d.ts +1 -1
- package/dist/journey-cli.js +4 -1
- package/dist/journey-cli.js.map +1 -1
- package/dist/journey-prefix.js +2 -2
- package/dist/journey-prefix.js.map +1 -1
- package/dist/journey-verify.d.ts +2 -0
- package/dist/journey-verify.js +14 -1
- package/dist/journey-verify.js.map +1 -1
- package/dist/load-api.js +2 -2
- package/dist/load-api.js.map +1 -1
- package/dist/mcp-cli-tools.js +23 -0
- package/dist/mcp-cli-tools.js.map +1 -1
- package/dist/source-run-api.d.ts +1 -1
- package/dist/source-run-api.js +3 -3
- package/dist/source-run-api.js.map +1 -1
- package/package.json +8 -8
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
|
|
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
|
-
|
|
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
|
-
|
|
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")
|
|
@@ -54293,6 +54391,40 @@ function deriveParamSchema(rec) {
|
|
|
54293
54391
|
}
|
|
54294
54392
|
return { required: required2 };
|
|
54295
54393
|
}
|
|
54394
|
+
function journeyParamSchema(journey) {
|
|
54395
|
+
const { required: required2 } = deriveParamSchema(journey.recording);
|
|
54396
|
+
const declared = /* @__PURE__ */ new Set([...journey.metadata.params, ...(journey.metadata.parameters ?? []).map((p) => p.name)]);
|
|
54397
|
+
const extracted = /* @__PURE__ */ new Set();
|
|
54398
|
+
const add = (a) => {
|
|
54399
|
+
for (const name of assertionRefs(a)) {
|
|
54400
|
+
if (declared.has(name) && !extracted.has(name) && !required2.includes(name))
|
|
54401
|
+
required2.push(name);
|
|
54402
|
+
}
|
|
54403
|
+
};
|
|
54404
|
+
for (const page of journey.recording.pages) {
|
|
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);
|
|
54409
|
+
if (step.kind === "extract")
|
|
54410
|
+
extracted.add(step.as);
|
|
54411
|
+
for (const { assertion } of ownAssertions(step))
|
|
54412
|
+
add(assertion);
|
|
54413
|
+
if (step.kind === "forEach") {
|
|
54414
|
+
for (const child of step.steps) {
|
|
54415
|
+
if (child.kind === "extract")
|
|
54416
|
+
extracted.add(child.as);
|
|
54417
|
+
for (const { assertion } of ownAssertions(child))
|
|
54418
|
+
add(assertion);
|
|
54419
|
+
}
|
|
54420
|
+
}
|
|
54421
|
+
}
|
|
54422
|
+
}
|
|
54423
|
+
for (const c of journey.metadata.endState ?? [])
|
|
54424
|
+
if (c.kind === "page" || c.kind === "reloadThen")
|
|
54425
|
+
add(c.assertion);
|
|
54426
|
+
return { required: required2 };
|
|
54427
|
+
}
|
|
54296
54428
|
function validateParams(schema, params) {
|
|
54297
54429
|
const provided = Object.keys(params);
|
|
54298
54430
|
const missing = schema.required.filter((v) => !(v in params));
|
|
@@ -54303,7 +54435,7 @@ function validateParams(schema, params) {
|
|
|
54303
54435
|
}
|
|
54304
54436
|
function journeyRunParams(journey) {
|
|
54305
54437
|
const out = [...journey.metadata.params];
|
|
54306
|
-
for (const p of
|
|
54438
|
+
for (const p of journeyParamSchema(journey).required)
|
|
54307
54439
|
if (!out.includes(p))
|
|
54308
54440
|
out.push(p);
|
|
54309
54441
|
return out;
|
|
@@ -61856,9 +61988,9 @@ function hostStarvedFailure(failure3, health) {
|
|
|
61856
61988
|
}
|
|
61857
61989
|
|
|
61858
61990
|
// src/build-info.generated.ts
|
|
61859
|
-
var GENERATED_COMMIT = "
|
|
61860
|
-
var GENERATED_TREE = "
|
|
61861
|
-
var GENERATED_BUILT_AT = "2026-10-
|
|
61991
|
+
var GENERATED_COMMIT = "89237bd";
|
|
61992
|
+
var GENERATED_TREE = "b6b4c8d";
|
|
61993
|
+
var GENERATED_BUILT_AT = "2026-10-18T16:47:05.375Z";
|
|
61862
61994
|
|
|
61863
61995
|
// src/version.ts
|
|
61864
61996
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
@@ -61880,13 +62012,13 @@ function readCliVersion() {
|
|
|
61880
62012
|
|
|
61881
62013
|
// src/engine.ts
|
|
61882
62014
|
function bundledCommit() {
|
|
61883
|
-
return true ? "
|
|
62015
|
+
return true ? "89237bd" : void 0;
|
|
61884
62016
|
}
|
|
61885
62017
|
function bundledBuiltAt() {
|
|
61886
|
-
return true ? "2026-10-
|
|
62018
|
+
return true ? "2026-10-18T16:47:05.375Z" : void 0;
|
|
61887
62019
|
}
|
|
61888
62020
|
function bundledTree() {
|
|
61889
|
-
return true ? "
|
|
62021
|
+
return true ? "b6b4c8d" : void 0;
|
|
61890
62022
|
}
|
|
61891
62023
|
function currentBuildTree() {
|
|
61892
62024
|
return bundledTree() ?? GENERATED_TREE;
|
|
@@ -80224,13 +80356,13 @@ import { readFile as readFile9, writeFile as writeFile8, mkdir as mkdir8, rm as
|
|
|
80224
80356
|
import { homedir as realHomedir } from "node:os";
|
|
80225
80357
|
import { join as join19, dirname as dirname6 } from "node:path";
|
|
80226
80358
|
function detectRuntimes(deps = {}) {
|
|
80227
|
-
const
|
|
80359
|
+
const existsSync47 = deps.existsSync ?? realExistsSync;
|
|
80228
80360
|
const homedir6 = deps.homedir ?? realHomedir;
|
|
80229
80361
|
const cwd = deps.cwd ?? process.cwd;
|
|
80230
80362
|
const detected = [];
|
|
80231
|
-
if (
|
|
80232
|
-
if (
|
|
80233
|
-
if (
|
|
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");
|
|
80234
80366
|
detected.push("generic");
|
|
80235
80367
|
return detected;
|
|
80236
80368
|
}
|
|
@@ -82119,7 +82251,7 @@ var JourneyRunner = class {
|
|
|
82119
82251
|
}
|
|
82120
82252
|
async #run(req, collect9) {
|
|
82121
82253
|
assertCompletePolicy(req?.policy);
|
|
82122
|
-
validateParams(
|
|
82254
|
+
validateParams(journeyParamSchema(req.journey), req.params);
|
|
82123
82255
|
if (req.policy.secret.secretMode === "vault-autofill") {
|
|
82124
82256
|
await this.preflightSecretRefs(req.journey.metadata.secretRefs ?? []);
|
|
82125
82257
|
}
|
|
@@ -90742,7 +90874,7 @@ async function resolveJourneyPrefix(opts) {
|
|
|
90742
90874
|
}
|
|
90743
90875
|
const prefix = journeyPrefix(full, resolved.step);
|
|
90744
90876
|
const used = prefixParams(full, prefix, opts.params);
|
|
90745
|
-
validateParams(
|
|
90877
|
+
validateParams(journeyParamSchema(prefix), used);
|
|
90746
90878
|
const branch = journeyBranchPoint(full, resolved);
|
|
90747
90879
|
const site = full.recording.site;
|
|
90748
90880
|
let startUrl;
|
|
@@ -94050,10 +94182,10 @@ function redactSecretValues(result, secrets) {
|
|
|
94050
94182
|
return scrub3(result);
|
|
94051
94183
|
}
|
|
94052
94184
|
function prefixParams(full, prefix, params) {
|
|
94053
|
-
const known =
|
|
94185
|
+
const known = journeyParamSchema(full).required;
|
|
94054
94186
|
const unknown2 = Object.keys(params).filter((k) => !known.includes(k));
|
|
94055
94187
|
if (unknown2.length > 0) throw new ParamValidationError(`param mismatch \u2014 missing: [], unknown: [${unknown2.join(", ")}]`);
|
|
94056
|
-
const needed =
|
|
94188
|
+
const needed = journeyParamSchema(prefix).required;
|
|
94057
94189
|
return Object.fromEntries(Object.entries(params).filter(([k]) => needed.includes(k)));
|
|
94058
94190
|
}
|
|
94059
94191
|
function journeyFixtureBaseDir(deps = {}) {
|
|
@@ -94211,7 +94343,7 @@ async function runJourneyProgrammatically(opts, mutation2 = {}) {
|
|
|
94211
94343
|
);
|
|
94212
94344
|
}
|
|
94213
94345
|
const inputParams = journey === full ? opts.params : prefixParams(full, journey, opts.params);
|
|
94214
|
-
validateParams(
|
|
94346
|
+
validateParams(journeyParamSchema(journey), inputParams);
|
|
94215
94347
|
const replayed = mutation2.mutateJourney === void 0 || journey !== full ? journey : mutation2.mutateJourney(journey);
|
|
94216
94348
|
const policy = opts.policy ?? safeRunPolicy();
|
|
94217
94349
|
const gate2 = await gateJourney(opts.siteGate, journey.recording, { ...opts.account === void 0 ? {} : { account: opts.account }, enforceLimits: true });
|
|
@@ -94282,8 +94414,15 @@ async function runJourneyProgrammatically(opts, mutation2 = {}) {
|
|
|
94282
94414
|
shots === void 0 ? void 0 : screenshotObserver(shots, (a) => a.ability(BrowseTheWebToken).session.page, whatOf)
|
|
94283
94415
|
);
|
|
94284
94416
|
const skipStep = mutation2.skipStep;
|
|
94417
|
+
const selectAlternative = mutation2.selectAlternativeAtStep;
|
|
94285
94418
|
const fixtureBaseDir = opts.fixtureBaseDir ?? journeyFixtureBaseDir();
|
|
94286
|
-
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({
|
|
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
|
+
}));
|
|
94287
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) };
|
|
94288
94427
|
const runner = new JourneyRunner(actor, interpreter, void 0, void 0, opts.selfHealer, heal);
|
|
94289
94428
|
let result;
|
|
@@ -107473,6 +107612,249 @@ function registerJourneyRun(journey, program2, deps) {
|
|
|
107473
107612
|
}));
|
|
107474
107613
|
}
|
|
107475
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
|
+
|
|
107476
107858
|
// src/journey-cli/promote.ts
|
|
107477
107859
|
import { readFile as readFile31 } from "node:fs/promises";
|
|
107478
107860
|
|
|
@@ -108021,7 +108403,7 @@ function registerJourneyReview(journey, program2, deps) {
|
|
|
108021
108403
|
}
|
|
108022
108404
|
|
|
108023
108405
|
// src/journey-cli/migrate.ts
|
|
108024
|
-
import { existsSync as
|
|
108406
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
108025
108407
|
|
|
108026
108408
|
// src/journey-migrate-api.ts
|
|
108027
108409
|
import { readdir as readdir11, readFile as readFile32, writeFile as writeFile37 } from "node:fs/promises";
|
|
@@ -108277,7 +108659,7 @@ function registerJourneyMigrate(journey, program2, deps) {
|
|
|
108277
108659
|
return;
|
|
108278
108660
|
}
|
|
108279
108661
|
const storageState = storageStateFlag ?? environment?.storageState;
|
|
108280
|
-
if (storageState !== void 0 && !
|
|
108662
|
+
if (storageState !== void 0 && !existsSync28(storageState)) {
|
|
108281
108663
|
emitJson(program2, fail("E_JOURNEY_MIGRATE_ARGS", `storage state not found: ${storageState}`));
|
|
108282
108664
|
return;
|
|
108283
108665
|
}
|
|
@@ -108610,7 +108992,7 @@ function registerJourneyLint(journey, program2, deps) {
|
|
|
108610
108992
|
}
|
|
108611
108993
|
|
|
108612
108994
|
// src/journey-cli/verify.ts
|
|
108613
|
-
import { existsSync as
|
|
108995
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
108614
108996
|
|
|
108615
108997
|
// src/journey-verify.ts
|
|
108616
108998
|
function verifyExitCode(verdict) {
|
|
@@ -108660,10 +109042,14 @@ async function verifyJourneyMutations(opts, run = runJourneyProgrammatically) {
|
|
|
108660
109042
|
structuredFailures: true,
|
|
108661
109043
|
...how.journey === journey ? {} : { mutateJourney: (j) => describe6(j, m, replayOpts2).journey },
|
|
108662
109044
|
...how.skipIndex === void 0 ? {} : { skipStep: (i) => i === how.skipIndex },
|
|
109045
|
+
...how.swapSelectAtStep === void 0 ? {} : { selectAlternativeAtStep: how.swapSelectAtStep },
|
|
108663
109046
|
...how.blockIndex === void 0 ? {} : { blockWritesAtStep: how.blockIndex }
|
|
108664
109047
|
});
|
|
108665
109048
|
const blocked = r.blockedWrites ?? [];
|
|
108666
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
|
+
}
|
|
108667
109053
|
if (how.blockIndex !== void 0 && !blockedOwnWrite(how.blockRequests ?? [], blocked)) {
|
|
108668
109054
|
return {
|
|
108669
109055
|
outcome: "not-applied",
|
|
@@ -108685,7 +109071,15 @@ async function verifyJourneyMutations(opts, run = runJourneyProgrammatically) {
|
|
|
108685
109071
|
for (const m of plan2.mutations) {
|
|
108686
109072
|
const first = await replay(m, mutationReplay);
|
|
108687
109073
|
const relaxed2 = needsRelaxedReplay(plan2, m, first) ? await replay(m, relaxedMutationReplay) : void 0;
|
|
108688
|
-
mutations.push({
|
|
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
|
+
});
|
|
108689
109083
|
}
|
|
108690
109084
|
}
|
|
108691
109085
|
const results = new Map(
|
|
@@ -108753,7 +109147,7 @@ function registerJourneyVerify(journey, program2, deps) {
|
|
|
108753
109147
|
...ownFixtureFlags.after === void 0 && environment?.hooks?.after !== void 0 ? { after: environment.hooks.after } : {}
|
|
108754
109148
|
};
|
|
108755
109149
|
const storageState = storageStateFlag ?? environment?.storageState;
|
|
108756
|
-
if (storageState !== void 0 && !
|
|
109150
|
+
if (storageState !== void 0 && !existsSync29(storageState)) {
|
|
108757
109151
|
emitJson(program2, fail("E_JOURNEY_VERIFY_ARGS", `storage state not found: ${storageState}`));
|
|
108758
109152
|
return;
|
|
108759
109153
|
}
|
|
@@ -109180,7 +109574,7 @@ function registerJourneyLinkCommand(journey, program2, deps) {
|
|
|
109180
109574
|
}
|
|
109181
109575
|
|
|
109182
109576
|
// src/journey-annotate-cli.ts
|
|
109183
|
-
import { existsSync as
|
|
109577
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
109184
109578
|
function registerJourneyAnnotateCommand(journey, program2, deps) {
|
|
109185
109579
|
withScreenshotsFlag(withEnvironmentFlags(withBrowserLaunchFlags(withEmulationFlags(withFixtureFlags(journey.command("annotate <id>")))))).description(
|
|
109186
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)"
|
|
@@ -109229,7 +109623,7 @@ function registerJourneyAnnotateCommand(journey, program2, deps) {
|
|
|
109229
109623
|
...ownFixtureFlags.after === void 0 && environment?.hooks?.after !== void 0 ? { after: environment.hooks.after } : {}
|
|
109230
109624
|
};
|
|
109231
109625
|
const storageState = storageStateFlag ?? environment?.storageState;
|
|
109232
|
-
if (storageState !== void 0 && !
|
|
109626
|
+
if (storageState !== void 0 && !existsSync30(storageState)) {
|
|
109233
109627
|
emitJson(program2, fail("E_JOURNEY_ANNOTATE_ARGS", `storage state not found: ${storageState}`));
|
|
109234
109628
|
return;
|
|
109235
109629
|
}
|
|
@@ -109317,7 +109711,7 @@ review or edit it, then apply it: jevitate journey annotate ${id} --approve
|
|
|
109317
109711
|
}
|
|
109318
109712
|
|
|
109319
109713
|
// src/journey-demo-cli.ts
|
|
109320
|
-
import { existsSync as
|
|
109714
|
+
import { existsSync as existsSync31 } from "node:fs";
|
|
109321
109715
|
import { join as join64, resolve as resolvePath15 } from "node:path";
|
|
109322
109716
|
function registerJourneyDemoCommand(journey, program2, deps) {
|
|
109323
109717
|
withScreenshotsFlag(withEnvironmentFlags(withDemoFlags(withBrowserLaunchFlags(withEmulationFlags(withFixtureFlags(journey.command("demo <id>"))))))).description(
|
|
@@ -109341,7 +109735,7 @@ function registerJourneyDemoCommand(journey, program2, deps) {
|
|
|
109341
109735
|
...ownFixtureFlags.after === void 0 && environment?.hooks?.after !== void 0 ? { after: environment.hooks.after } : {}
|
|
109342
109736
|
};
|
|
109343
109737
|
const storageState = storageStateFlag ?? environment?.storageState;
|
|
109344
|
-
if (storageState !== void 0 && !
|
|
109738
|
+
if (storageState !== void 0 && !existsSync31(storageState)) {
|
|
109345
109739
|
emitJson(program2, fail("E_JOURNEY_DEMO_ARGS", `storage state not found: ${storageState}`));
|
|
109346
109740
|
return;
|
|
109347
109741
|
}
|
|
@@ -109437,6 +109831,7 @@ function registerJourneyCommands(program2, deps) {
|
|
|
109437
109831
|
registerJourneyList(journey, program2, deps);
|
|
109438
109832
|
registerJourneyFind(journey, program2, deps);
|
|
109439
109833
|
registerJourneyRun(journey, program2, deps);
|
|
109834
|
+
registerJourneyChain(journey, program2, deps);
|
|
109440
109835
|
registerJourneyPromote(journey, program2, deps);
|
|
109441
109836
|
registerJourneyReview(journey, program2, deps);
|
|
109442
109837
|
registerJourneyMigrate(journey, program2, deps);
|
|
@@ -109461,7 +109856,7 @@ function registerBuiltinAnalyzers() {
|
|
|
109461
109856
|
}
|
|
109462
109857
|
|
|
109463
109858
|
// src/source-cli.ts
|
|
109464
|
-
import { existsSync as
|
|
109859
|
+
import { existsSync as existsSync32 } from "node:fs";
|
|
109465
109860
|
|
|
109466
109861
|
// src/source-run-api.ts
|
|
109467
109862
|
var realResolvedJourneyRunner = async (file2, params, policy, storageState, emulation, browser, siteGate) => {
|
|
@@ -109470,7 +109865,7 @@ var realResolvedJourneyRunner = async (file2, params, policy, storageState, emul
|
|
|
109470
109865
|
`journey '${file2.metadata.id}' requires auth (metadata.requiresAuth) \u2014 run with --storage-state <file>`
|
|
109471
109866
|
);
|
|
109472
109867
|
}
|
|
109473
|
-
validateParams(
|
|
109868
|
+
validateParams(journeyParamSchema(file2), params);
|
|
109474
109869
|
const allowedOrigins = [.../* @__PURE__ */ new Set([file2.recording.site, ...file2.declaredOrigins])];
|
|
109475
109870
|
const gate2 = await gateJourney(siteGate, file2.recording, { enforceLimits: true });
|
|
109476
109871
|
const port = new PlaywrightBrowserPort();
|
|
@@ -109679,7 +110074,7 @@ function registerSourceCommands(program2, deps) {
|
|
|
109679
110074
|
"Playwright storageState JSON to start the session authenticated (#118: required when the journey declares metadata.requiresAuth); must exist"
|
|
109680
110075
|
).option("--json", "emit a JSON envelope").option(TAG_FLAG, TAG_HELP, collectTag, []).action(taggedAction(program2, "source run", async function(name, journeyId) {
|
|
109681
110076
|
const { param, storageState, json: json2, ...emulationFlags } = this.opts();
|
|
109682
|
-
if (storageState !== void 0 && !
|
|
110077
|
+
if (storageState !== void 0 && !existsSync32(storageState)) {
|
|
109683
110078
|
emitJson(program2, fail("E_SOURCE_RUN_ARGS", `storage state not found: ${storageState}`));
|
|
109684
110079
|
return;
|
|
109685
110080
|
}
|
|
@@ -109742,7 +110137,7 @@ function registerSourceCommands(program2, deps) {
|
|
|
109742
110137
|
}
|
|
109743
110138
|
|
|
109744
110139
|
// src/load-cli.ts
|
|
109745
|
-
import { existsSync as
|
|
110140
|
+
import { existsSync as existsSync33 } from "node:fs";
|
|
109746
110141
|
|
|
109747
110142
|
// ../load/dist/percentiles.js
|
|
109748
110143
|
function percentile(sorted2, p) {
|
|
@@ -109870,7 +110265,7 @@ async function runJourneyLoadTest(opts) {
|
|
|
109870
110265
|
`journey '${opts.id}' requires auth (metadata.requiresAuth) \u2014 run with --storage-state <file>`
|
|
109871
110266
|
);
|
|
109872
110267
|
}
|
|
109873
|
-
validateParams(
|
|
110268
|
+
validateParams(journeyParamSchema(journey), opts.params);
|
|
109874
110269
|
const policy = opts.policy ?? safeRunPolicy();
|
|
109875
110270
|
const browserPortFactory = opts.browserPortFactory ?? (() => new PlaywrightBrowserPort());
|
|
109876
110271
|
const fixtureBaseDir = journeyFixtureBaseDir();
|
|
@@ -109950,7 +110345,7 @@ function registerLoadCommands(program2, deps) {
|
|
|
109950
110345
|
return;
|
|
109951
110346
|
}
|
|
109952
110347
|
const storageState = storageStateFlag ?? environment?.storageState;
|
|
109953
|
-
if (storageState !== void 0 && !
|
|
110348
|
+
if (storageState !== void 0 && !existsSync33(storageState)) {
|
|
109954
110349
|
emitJson(program2, fail("E_LOAD_RUN_ARGS", `storage state not found: ${storageState}`));
|
|
109955
110350
|
return;
|
|
109956
110351
|
}
|
|
@@ -110000,10 +110395,10 @@ function registerLoadCommands(program2, deps) {
|
|
|
110000
110395
|
}
|
|
110001
110396
|
|
|
110002
110397
|
// src/explore-cli/run.ts
|
|
110003
|
-
import { existsSync as
|
|
110398
|
+
import { existsSync as existsSync35 } from "node:fs";
|
|
110004
110399
|
|
|
110005
110400
|
// src/type-fixture-file.ts
|
|
110006
|
-
import { readFileSync as
|
|
110401
|
+
import { readFileSync as readFileSync34, statSync as statSync10 } from "node:fs";
|
|
110007
110402
|
import { basename as basename15, resolve as resolve18 } from "node:path";
|
|
110008
110403
|
var TYPE_FIXTURE_MAX_BYTES = 256 * 1024;
|
|
110009
110404
|
function loadTypeFixtures(specs, cwd = process.cwd()) {
|
|
@@ -110022,7 +110417,7 @@ function loadTypeFixtures(specs, cwd = process.cwd()) {
|
|
|
110022
110417
|
if (size > TYPE_FIXTURE_MAX_BYTES) {
|
|
110023
110418
|
throw new TypeFixtureSpecError(`--type-fixture ${descriptor}: ${path2} is ${size} bytes (at most ${TYPE_FIXTURE_MAX_BYTES})`);
|
|
110024
110419
|
}
|
|
110025
|
-
const bytes =
|
|
110420
|
+
const bytes = readFileSync34(abs);
|
|
110026
110421
|
let text2;
|
|
110027
110422
|
try {
|
|
110028
110423
|
text2 = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
@@ -110343,7 +110738,7 @@ async function runExploreMultiRun(args) {
|
|
|
110343
110738
|
import { resolve as resolvePath16 } from "node:path";
|
|
110344
110739
|
|
|
110345
110740
|
// src/campaign-api.ts
|
|
110346
|
-
import { existsSync as
|
|
110741
|
+
import { existsSync as existsSync34, readFileSync as readFileSync35 } from "node:fs";
|
|
110347
110742
|
import { mkdir as mkdir31, writeFile as writeFile39 } from "node:fs/promises";
|
|
110348
110743
|
import { homedir as homedir5 } from "node:os";
|
|
110349
110744
|
import { dirname as dirname28, isAbsolute as isAbsolute11, join as join66, resolve as resolve19 } from "node:path";
|
|
@@ -110460,7 +110855,7 @@ var at2 = (path2) => path2.length === 0 ? "spec" : path2.map((p) => typeof p ===
|
|
|
110460
110855
|
async function validateCampaign(specPath, opts) {
|
|
110461
110856
|
let raw;
|
|
110462
110857
|
try {
|
|
110463
|
-
raw = JSON.parse(
|
|
110858
|
+
raw = JSON.parse(readFileSync35(specPath, "utf8"));
|
|
110464
110859
|
} catch (e) {
|
|
110465
110860
|
throw new CampaignSpecError([`cannot read ${specPath}: ${e instanceof SyntaxError ? "not valid JSON" : e instanceof Error ? e.message : String(e)}`]);
|
|
110466
110861
|
}
|
|
@@ -110484,8 +110879,8 @@ async function validateCampaignSpec(raw, specPath, opts) {
|
|
|
110484
110879
|
problems.push(`env: ${err.message}`);
|
|
110485
110880
|
}
|
|
110486
110881
|
const defaultSession = spec.storageState === void 0 ? environment?.storageState : abs(spec.storageState);
|
|
110487
|
-
if (spec.storageState !== void 0 && !
|
|
110488
|
-
if (spec.fixtures !== void 0 && !
|
|
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)}`);
|
|
110489
110884
|
if ((spec.before !== void 0 || spec.after !== void 0) && opts.allowShellHooks !== true) {
|
|
110490
110885
|
problems.push("before/after: operator shell hooks run only with --allow-shell-hooks");
|
|
110491
110886
|
}
|
|
@@ -110510,7 +110905,7 @@ async function validateCampaignSpec(raw, specPath, opts) {
|
|
|
110510
110905
|
}
|
|
110511
110906
|
if (new Set(job.strategies).size !== job.strategies.length) problems.push(`${where}.strategies: duplicate strategy`);
|
|
110512
110907
|
const session2 = job.storageState === void 0 ? defaultSession : abs(job.storageState);
|
|
110513
|
-
if (job.storageState !== void 0 && !
|
|
110908
|
+
if (job.storageState !== void 0 && !existsSync34(abs(job.storageState))) problems.push(`${where}.storageState: not found: ${abs(job.storageState)}`);
|
|
110514
110909
|
let stored = null;
|
|
110515
110910
|
try {
|
|
110516
110911
|
stored = await registry3.get(job.journey);
|
|
@@ -110555,7 +110950,7 @@ async function validateCampaignSpec(raw, specPath, opts) {
|
|
|
110555
110950
|
if (deepest > 0) {
|
|
110556
110951
|
try {
|
|
110557
110952
|
const prefix = journeyPrefix(full, deepest);
|
|
110558
|
-
validateParams(
|
|
110953
|
+
validateParams(journeyParamSchema(prefix), prefixParams(full, prefix, job.params ?? {}));
|
|
110559
110954
|
} catch (err) {
|
|
110560
110955
|
problems.push(`${where}.params: ${err instanceof Error ? err.message : String(err)}`);
|
|
110561
110956
|
}
|
|
@@ -112278,7 +112673,7 @@ function registerExploreRun(program2, deps, buildProgram2) {
|
|
|
112278
112673
|
emitExplore(fail(err.code, err.message));
|
|
112279
112674
|
return;
|
|
112280
112675
|
}
|
|
112281
|
-
if (o.storageState !== void 0 && !
|
|
112676
|
+
if (o.storageState !== void 0 && !existsSync35(o.storageState) && (authCheck.mode === "off" || projectPersona?.login === void 0)) {
|
|
112282
112677
|
emitExplore(fail("E_EXPLORE_ARGS", `storage state not found: ${o.storageState}`));
|
|
112283
112678
|
return;
|
|
112284
112679
|
}
|
|
@@ -112570,11 +112965,11 @@ function pick3(k, v) {
|
|
|
112570
112965
|
import { resolve as resolve22 } from "node:path";
|
|
112571
112966
|
|
|
112572
112967
|
// src/sweep-api.ts
|
|
112573
|
-
import { existsSync as
|
|
112968
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync11, readFileSync as readFileSync36, realpathSync as realpathSync5, statSync as statSync11, writeFileSync as writeFileSync13 } from "node:fs";
|
|
112574
112969
|
import { basename as basename18, dirname as dirname30, extname as extname2, join as join68, resolve as resolve21 } from "node:path";
|
|
112575
112970
|
|
|
112576
112971
|
// src/mcp-paths.ts
|
|
112577
|
-
import { existsSync as
|
|
112972
|
+
import { existsSync as existsSync36, realpathSync as realpathSync4 } from "node:fs";
|
|
112578
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";
|
|
112579
112974
|
var McpPathError = class extends Error {
|
|
112580
112975
|
error = "invalid_args";
|
|
@@ -112592,7 +112987,7 @@ function realish(p) {
|
|
|
112592
112987
|
let head2 = p;
|
|
112593
112988
|
const tail = [];
|
|
112594
112989
|
for (; ; ) {
|
|
112595
|
-
if (
|
|
112990
|
+
if (existsSync36(head2)) {
|
|
112596
112991
|
try {
|
|
112597
112992
|
return join67(realpathSync4(head2), ...tail);
|
|
112598
112993
|
} catch {
|
|
@@ -112968,6 +113363,29 @@ var CLI_TOOL_SPECS = [
|
|
|
112968
113363
|
omitted: { "--dir": OMIT.storeDir, "--allow": OMIT.mcpOrigins, ...HOOK_FLAGS, ...BROWSER_FLAGS, ...JSON_FLAG }
|
|
112969
113364
|
}
|
|
112970
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
|
+
},
|
|
112971
113389
|
{
|
|
112972
113390
|
name: "publish_journey",
|
|
112973
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.",
|
|
@@ -113994,7 +114412,7 @@ function personaOf(value, base, roots, where, problems) {
|
|
|
113994
114412
|
}
|
|
113995
114413
|
try {
|
|
113996
114414
|
const confined = confineMcpPath(abs, `persona of ${where}`, roots, { session: true });
|
|
113997
|
-
if (!
|
|
114415
|
+
if (!existsSync37(confined)) {
|
|
113998
114416
|
problems.push(`${where}: persona storage state not found: ${confined}`);
|
|
113999
114417
|
return void 0;
|
|
114000
114418
|
}
|
|
@@ -114063,8 +114481,8 @@ function validateRunShaping(options, strategy, where, problems) {
|
|
|
114063
114481
|
}
|
|
114064
114482
|
function loadSweepTargets(path2, opts = {}) {
|
|
114065
114483
|
const abs = resolve21(path2);
|
|
114066
|
-
if (!
|
|
114067
|
-
const text2 =
|
|
114484
|
+
if (!existsSync37(abs)) throw new SweepSpecError(`targets file not found: ${abs}`);
|
|
114485
|
+
const text2 = readFileSync36(abs, "utf8");
|
|
114068
114486
|
const isTsv = /\.(tsv|txt)$/i.test(abs);
|
|
114069
114487
|
const parsed = isTsv ? parseTsv(text2, path2) : parseJson(text2, path2);
|
|
114070
114488
|
const problems = [...parsed.problems];
|
|
@@ -114311,9 +114729,9 @@ function targetArgv(plan2, target, runDir) {
|
|
|
114311
114729
|
];
|
|
114312
114730
|
}
|
|
114313
114731
|
function finishedEnvelope(envelopePath) {
|
|
114314
|
-
if (!
|
|
114732
|
+
if (!existsSync37(envelopePath)) return void 0;
|
|
114315
114733
|
try {
|
|
114316
|
-
const env = JSON.parse(
|
|
114734
|
+
const env = JSON.parse(readFileSync36(envelopePath, "utf8"));
|
|
114317
114735
|
if (!isRecord(env) || env.ok !== true || !isRecord(env.data)) return void 0;
|
|
114318
114736
|
if (env.data.interrupted !== void 0) return void 0;
|
|
114319
114737
|
return env;
|
|
@@ -114687,7 +115105,7 @@ function registerVerifyFixCommands(program2, deps) {
|
|
|
114687
115105
|
}
|
|
114688
115106
|
|
|
114689
115107
|
// src/author-journey-cli.ts
|
|
114690
|
-
import { existsSync as
|
|
115108
|
+
import { existsSync as existsSync38 } from "node:fs";
|
|
114691
115109
|
var AUTHOR_GOAL_RUN_FLAGS = [
|
|
114692
115110
|
"successWhen",
|
|
114693
115111
|
"allowVacuousChecks",
|
|
@@ -114783,7 +115201,7 @@ function registerAuthorJourneyCommands(program2, deps) {
|
|
|
114783
115201
|
].join("\n")
|
|
114784
115202
|
).action(async function() {
|
|
114785
115203
|
const o = this.opts();
|
|
114786
|
-
if (o.storageState !== void 0 && !
|
|
115204
|
+
if (o.storageState !== void 0 && !existsSync38(o.storageState)) {
|
|
114787
115205
|
emitJson(program2, fail("E_EXPLORE_ARGS", `storage state not found: ${o.storageState}`));
|
|
114788
115206
|
return;
|
|
114789
115207
|
}
|
|
@@ -114905,11 +115323,11 @@ function registerAuthorJourneyCommands(program2, deps) {
|
|
|
114905
115323
|
}
|
|
114906
115324
|
|
|
114907
115325
|
// src/demo-aspect-cli.ts
|
|
114908
|
-
import { existsSync as
|
|
115326
|
+
import { existsSync as existsSync40 } from "node:fs";
|
|
114909
115327
|
import { join as join71, resolve as resolvePath18 } from "node:path";
|
|
114910
115328
|
|
|
114911
115329
|
// src/demo-aspect-api.ts
|
|
114912
|
-
import { existsSync as
|
|
115330
|
+
import { existsSync as existsSync39 } from "node:fs";
|
|
114913
115331
|
import { mkdir as mkdir33, mkdtemp as mkdtemp5, readFile as readFile33, rm as rm13, writeFile as writeFile41 } from "node:fs/promises";
|
|
114914
115332
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
114915
115333
|
import { dirname as dirname31, join as join70 } from "node:path";
|
|
@@ -115246,7 +115664,7 @@ async function demoAspect(opts) {
|
|
|
115246
115664
|
const store = new FsJourneyStore(opts.journeysDir);
|
|
115247
115665
|
if (await store.get(id) !== null) throw new DemoExistsError(`journey '${id}' already exists \u2014 pick another --id (nothing was changed)`);
|
|
115248
115666
|
const recordPath = demoDraftPath(opts.journeysDir, id);
|
|
115249
|
-
if (
|
|
115667
|
+
if (existsSync39(recordPath)) {
|
|
115250
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`);
|
|
115251
115669
|
}
|
|
115252
115670
|
const maxReplays = opts.maxReplays ?? DEMO_MINIMIZE_MAX_REPLAYS;
|
|
@@ -115493,7 +115911,7 @@ function replayOptionsFrom(cmd, deps, o, environment) {
|
|
|
115493
115911
|
fixtureIdentity: o.fixtureIdentity
|
|
115494
115912
|
};
|
|
115495
115913
|
const storageState = o.storageState ?? environment.storageState;
|
|
115496
|
-
if (storageState !== void 0 && !
|
|
115914
|
+
if (storageState !== void 0 && !existsSync40(storageState)) throw new DemoAspectArgsError(`storage state not found: ${storageState}`);
|
|
115497
115915
|
let browser;
|
|
115498
115916
|
let emulation;
|
|
115499
115917
|
try {
|
|
@@ -115846,12 +116264,12 @@ function registerRecordCommands(program2, deps) {
|
|
|
115846
116264
|
}
|
|
115847
116265
|
|
|
115848
116266
|
// src/regression-cli.ts
|
|
115849
|
-
import { existsSync as
|
|
116267
|
+
import { existsSync as existsSync42 } from "node:fs";
|
|
115850
116268
|
import { readFile as readFile35, writeFile as writeFile43 } from "node:fs/promises";
|
|
115851
116269
|
import { join as join73 } from "node:path";
|
|
115852
116270
|
|
|
115853
116271
|
// src/regression-api.ts
|
|
115854
|
-
import { existsSync as
|
|
116272
|
+
import { existsSync as existsSync41 } from "node:fs";
|
|
115855
116273
|
import { readFile as readFile34 } from "node:fs/promises";
|
|
115856
116274
|
var RegressionExistsError = class extends Error {
|
|
115857
116275
|
code = "E_REGRESSION_EXISTS";
|
|
@@ -115939,7 +116357,7 @@ function describeNoOracle(missionResult) {
|
|
|
115939
116357
|
}
|
|
115940
116358
|
async function runRegressionCapture(opts) {
|
|
115941
116359
|
const recordingPath = safeChildPath(opts.regressionsDir, opts.id, { what: "regression id", suffix: ".recording.json" });
|
|
115942
|
-
if (opts.force !== true &&
|
|
116360
|
+
if (opts.force !== true && existsSync41(recordingPath)) {
|
|
115943
116361
|
throw new RegressionExistsError(opts.id, opts.regressionsDir);
|
|
115944
116362
|
}
|
|
115945
116363
|
const raw = JSON.parse(await readFile34(opts.failingRecordingPath, "utf8"));
|
|
@@ -116181,12 +116599,12 @@ function registerRegressionCommands(program2, deps) {
|
|
|
116181
116599
|
const { from, id, dir, attempts, summary: summary2, result: resultPath, fingerprint: fingerprint2, storageState, force, json: json2, param } = flags;
|
|
116182
116600
|
if (refuseUnsafeName(program2, id, "regression id")) return;
|
|
116183
116601
|
for (const [flag, path2] of [["--from", from], ["--result", resultPath]]) {
|
|
116184
|
-
if (path2 !== void 0 && !
|
|
116602
|
+
if (path2 !== void 0 && !existsSync42(path2)) {
|
|
116185
116603
|
emitJson(program2, fail("E_REGRESSION_ARGS", `${flag} file not found: ${path2}`));
|
|
116186
116604
|
return;
|
|
116187
116605
|
}
|
|
116188
116606
|
}
|
|
116189
|
-
if (storageState !== void 0 && !
|
|
116607
|
+
if (storageState !== void 0 && !existsSync42(storageState)) {
|
|
116190
116608
|
emitJson(program2, fail("E_REGRESSION_ARGS", `storage state not found: ${storageState}`));
|
|
116191
116609
|
return;
|
|
116192
116610
|
}
|
|
@@ -116283,7 +116701,7 @@ function registerRegressionCommands(program2, deps) {
|
|
|
116283
116701
|
return;
|
|
116284
116702
|
}
|
|
116285
116703
|
const storageState = storageStateFlag ?? environment?.storageState;
|
|
116286
|
-
if (storageState !== void 0 && !
|
|
116704
|
+
if (storageState !== void 0 && !existsSync42(storageState)) {
|
|
116287
116705
|
emitJson(program2, fail("E_REGRESSION_ARGS", `storage state not found: ${storageState}`));
|
|
116288
116706
|
return;
|
|
116289
116707
|
}
|
|
@@ -116296,7 +116714,7 @@ function registerRegressionCommands(program2, deps) {
|
|
|
116296
116714
|
}
|
|
116297
116715
|
if (refuseUnsafeName(program2, id, "regression id")) return;
|
|
116298
116716
|
const regressionsDir = resolveRegressionsDir(dir);
|
|
116299
|
-
if (!
|
|
116717
|
+
if (!existsSync42(join73(regressionsDir, `${id}.recording.json`))) {
|
|
116300
116718
|
const notFound = new RegressionNotFoundError(id, regressionsDir);
|
|
116301
116719
|
emitJson(program2, fail(notFound.code, notFound.message));
|
|
116302
116720
|
return;
|
|
@@ -116354,7 +116772,7 @@ function registerRegressionCommands(program2, deps) {
|
|
|
116354
116772
|
}
|
|
116355
116773
|
|
|
116356
116774
|
// src/mission-api.ts
|
|
116357
|
-
import { existsSync as
|
|
116775
|
+
import { existsSync as existsSync43 } from "node:fs";
|
|
116358
116776
|
import { resolve as resolvePath19 } from "node:path";
|
|
116359
116777
|
var UnknownMissionTargetError = class extends Error {
|
|
116360
116778
|
};
|
|
@@ -116392,7 +116810,7 @@ function applyAuth(target, auth) {
|
|
|
116392
116810
|
}
|
|
116393
116811
|
if (auth.storageState !== void 0) {
|
|
116394
116812
|
const abs = resolvePath19(auth.storageState);
|
|
116395
|
-
if (!
|
|
116813
|
+
if (!existsSync43(abs)) throw new MissionTargetAuthError(`storage state not found: ${abs}`);
|
|
116396
116814
|
base.storageState = abs;
|
|
116397
116815
|
}
|
|
116398
116816
|
if (auth.saveStorageState !== void 0) base.saveStorageState = auth.saveStorageState === true ? true : resolvePath19(auth.saveStorageState);
|
|
@@ -116437,7 +116855,7 @@ async function promoteMissionTarget(ctx, id) {
|
|
|
116437
116855
|
}
|
|
116438
116856
|
|
|
116439
116857
|
// src/mission-queue-cli.ts
|
|
116440
|
-
import { readFileSync as
|
|
116858
|
+
import { readFileSync as readFileSync37 } from "node:fs";
|
|
116441
116859
|
import { Option as Option2 } from "commander";
|
|
116442
116860
|
|
|
116443
116861
|
// src/mcp-api.ts
|
|
@@ -116496,6 +116914,9 @@ var ALLOWED_TOOLS = [
|
|
|
116496
116914
|
// #401 — the assertion-strength lint promote_journey applies; #402 — its mutation proof.
|
|
116497
116915
|
"lint_journey",
|
|
116498
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",
|
|
116499
116920
|
// #425 — a sweep: many explore missions over a targets file, one aggregated result.
|
|
116500
116921
|
"run_sweep",
|
|
116501
116922
|
// #432 — the read-only review sheet a person reads before promote_journey (bound by its content hash).
|
|
@@ -117265,7 +117686,7 @@ var tagsArg = (args) => {
|
|
|
117265
117686
|
};
|
|
117266
117687
|
|
|
117267
117688
|
// src/mcp-tools/findings.ts
|
|
117268
|
-
import { existsSync as
|
|
117689
|
+
import { existsSync as existsSync44 } from "node:fs";
|
|
117269
117690
|
import { access, readFile as readFile37 } from "node:fs/promises";
|
|
117270
117691
|
import { join as join77 } from "node:path";
|
|
117271
117692
|
function findingTools(ctx) {
|
|
@@ -117355,7 +117776,7 @@ function findingTools(ctx) {
|
|
|
117355
117776
|
};
|
|
117356
117777
|
const verifyFixOptions = (args) => {
|
|
117357
117778
|
const storageState = optPath(args, "storageState", pathRoots, { session: true });
|
|
117358
|
-
if (storageState !== void 0 && !
|
|
117779
|
+
if (storageState !== void 0 && !existsSync44(storageState)) throw new McpArgError(`storage state not found: ${storageState}`);
|
|
117359
117780
|
const replays = optInt(args, "replays", 1);
|
|
117360
117781
|
const invariantFiles = (optStringArray(args, "invariants") ?? []).map((f2, i) => optPath({ [`invariants[${i}]`]: f2 }, `invariants[${i}]`, pathRoots));
|
|
117361
117782
|
const fixtures = optPath(args, "fixtures", pathRoots);
|
|
@@ -117484,7 +117905,7 @@ function findingTools(ctx) {
|
|
|
117484
117905
|
}
|
|
117485
117906
|
|
|
117486
117907
|
// src/mcp-tools/journey.ts
|
|
117487
|
-
import { existsSync as
|
|
117908
|
+
import { existsSync as existsSync45 } from "node:fs";
|
|
117488
117909
|
function journeyTools(ctx) {
|
|
117489
117910
|
const { deps, pathRoots, credentialStore, runJourney } = ctx;
|
|
117490
117911
|
const findCaps = deps.findCapabilities ?? ((query) => findCapabilities(new JourneyRegistry(new FsJourneyStore(deps.journeysDir)), query));
|
|
@@ -117497,7 +117918,7 @@ function journeyTools(ctx) {
|
|
|
117497
117918
|
{ ...deps.environmentsFile === void 0 ? {} : { environmentsFile: deps.environmentsFile }, ...deps.targetsConfigPath === void 0 ? {} : { targetsFile: deps.targetsConfigPath } }
|
|
117498
117919
|
);
|
|
117499
117920
|
const storageState = optPath(args, "storageState", pathRoots, { session: true }) ?? environment?.storageState;
|
|
117500
|
-
if (args.storageState !== void 0 && storageState !== void 0 && !
|
|
117921
|
+
if (args.storageState !== void 0 && storageState !== void 0 && !existsSync45(storageState)) throw new McpArgError(`storage state not found: ${storageState}`);
|
|
117501
117922
|
const headed = optBool(args, "headed");
|
|
117502
117923
|
const slowMo = optInt(args, "slowMo", 0);
|
|
117503
117924
|
const recordVideo = optRecordVideo(args, pathRoots);
|
|
@@ -118111,7 +118532,7 @@ function registerMissionQueueCommands(program2, mission, deps) {
|
|
|
118111
118532
|
let invariants;
|
|
118112
118533
|
if (o.invariants !== void 0) {
|
|
118113
118534
|
try {
|
|
118114
|
-
invariants = JSON.parse(
|
|
118535
|
+
invariants = JSON.parse(readFileSync37(o.invariants, "utf8"));
|
|
118115
118536
|
} catch (e) {
|
|
118116
118537
|
refuse4("E_MISSION_QUEUE_INVARIANTS", `cannot read invariants file ${o.invariants}: ${e instanceof Error ? e.message.split("\n")[0] : String(e)}`);
|
|
118117
118538
|
return;
|
|
@@ -118868,7 +119289,7 @@ function registerUxCommands(program2, deps) {
|
|
|
118868
119289
|
}
|
|
118869
119290
|
|
|
118870
119291
|
// src/logs-retention.ts
|
|
118871
|
-
import { readFileSync as
|
|
119292
|
+
import { readFileSync as readFileSync38, readdirSync as readdirSync11, rmSync as rmSync2, rmdirSync as rmdirSync2, statSync as statSync12 } from "node:fs";
|
|
118872
119293
|
import { join as join79 } from "node:path";
|
|
118873
119294
|
var DEFAULT_LOGS_RETENTION = { ttlDays: 14, keepLatest: 50 };
|
|
118874
119295
|
var LogsConfigError = class extends Error {
|
|
@@ -118877,7 +119298,7 @@ var LogsConfigError = class extends Error {
|
|
|
118877
119298
|
function loadLogsRetention(path2 = resolveDataDir(["config.json"])) {
|
|
118878
119299
|
let raw;
|
|
118879
119300
|
try {
|
|
118880
|
-
raw =
|
|
119301
|
+
raw = readFileSync38(path2, "utf8");
|
|
118881
119302
|
} catch (e) {
|
|
118882
119303
|
if (typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT") return DEFAULT_LOGS_RETENTION;
|
|
118883
119304
|
throw new LogsConfigError(`cannot read ${path2}: ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -118938,8 +119359,8 @@ function pruneLogs(root2, retention, opts = {}) {
|
|
|
118938
119359
|
}
|
|
118939
119360
|
|
|
118940
119361
|
// src/logs-cli.ts
|
|
118941
|
-
import { readFileSync as
|
|
118942
|
-
import { existsSync as
|
|
119362
|
+
import { readFileSync as readFileSync39 } from "node:fs";
|
|
119363
|
+
import { existsSync as existsSync46 } from "node:fs";
|
|
118943
119364
|
var LOG_WRITING_COMMANDS = /* @__PURE__ */ new Set(["explore", "explore-author-journey", "record", "ux", "check", "run", "verify-fix", "capture"]);
|
|
118944
119365
|
function registerLogsCommands(program2, deps) {
|
|
118945
119366
|
const configPath = deps.logs?.configPath ?? resolveDataDir(["config.json"]);
|
|
@@ -118977,7 +119398,7 @@ function registerLogsCommands(program2, deps) {
|
|
|
118977
119398
|
const emit5 = (envelope) => emitJson(program2, envelope);
|
|
118978
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"));
|
|
118979
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"));
|
|
118980
|
-
if (!
|
|
119401
|
+
if (!existsSync46(signalsPathFor(o.result))) {
|
|
118981
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`));
|
|
118982
119403
|
}
|
|
118983
119404
|
let secrets;
|
|
@@ -118990,7 +119411,7 @@ function registerLogsCommands(program2, deps) {
|
|
|
118990
119411
|
throw err;
|
|
118991
119412
|
}
|
|
118992
119413
|
try {
|
|
118993
|
-
const file2 = JSON.parse(
|
|
119414
|
+
const file2 = JSON.parse(readFileSync39(o.result, "utf8"));
|
|
118994
119415
|
if (typeof file2.result !== "object" || file2.result === null) return emit5(fail("E_LOGS_ARGS", `${o.result} is not a jevitate run result`));
|
|
118995
119416
|
const judge = o.real === true ? (await buildExploreGateways(deps, { real: true, fakeAi: false, jevProvider: o.jevProvider })).judge : void 0;
|
|
118996
119417
|
const updated = await triageRunResult(file2.result, o.result, {
|
|
@@ -119014,7 +119435,7 @@ result ${o.result}
|
|
|
119014
119435
|
}
|
|
119015
119436
|
|
|
119016
119437
|
// src/inbox-cli.ts
|
|
119017
|
-
import { readFileSync as
|
|
119438
|
+
import { readFileSync as readFileSync40 } from "node:fs";
|
|
119018
119439
|
import { Option as Option3 } from "commander";
|
|
119019
119440
|
var INBOX_DIR_HELP = "inbox store directory (default: ~/.jevitate/inbox \u2014 the dir `jevitate mcp` and `jevitate ui` use)";
|
|
119020
119441
|
var REDACTED = "***REDACTED***";
|
|
@@ -119122,7 +119543,7 @@ function registerInboxCommands(program2, deps) {
|
|
|
119122
119543
|
let findings;
|
|
119123
119544
|
if (o.findings !== void 0) {
|
|
119124
119545
|
try {
|
|
119125
|
-
findings = JSON.parse(
|
|
119546
|
+
findings = JSON.parse(readFileSync40(o.findings, "utf8"));
|
|
119126
119547
|
} catch (e) {
|
|
119127
119548
|
const code = `E_${commandPath(cmd).toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_INPUT`;
|
|
119128
119549
|
emitJsonOrRefusal(program2, fail(code, `cannot read --findings ${o.findings}: ${e instanceof Error ? e.message.split("\n")[0] : String(e)}`));
|