ccqa 1.30.0 → 1.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/ccqa.mjs +120 -34
- package/dist/hub-client/index.d.mts +7 -2
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/bin/ccqa.mjs
CHANGED
|
@@ -7537,6 +7537,7 @@ z.object({
|
|
|
7537
7537
|
const SpecDriftEntrySchema = z.object({
|
|
7538
7538
|
label: DriftLabelSchema.nullable(),
|
|
7539
7539
|
surface: DriftSurfaceSchema.optional(),
|
|
7540
|
+
subDiagnosis: DriftSubDiagnosisSchema.optional(),
|
|
7540
7541
|
specChangeKind: SpecChangeKindSchema.optional(),
|
|
7541
7542
|
confidence: z.number().optional(),
|
|
7542
7543
|
headline: z.string().optional(),
|
|
@@ -13844,8 +13845,12 @@ function createRunTeardown() {
|
|
|
13844
13845
|
* A command must install at most one: a second handler that also exits would
|
|
13845
13846
|
* race this one and could terminate mid-finalizer. A second signal while
|
|
13846
13847
|
* tearing down hard-exits immediately rather than waiting.
|
|
13848
|
+
*
|
|
13849
|
+
* `onSignal` runs synchronously before the teardown starts, so a finalizer
|
|
13850
|
+
* can already see which signal is ending the process (e.g. `ccqa record`
|
|
13851
|
+
* seals its hub run with a "terminated by signal" note).
|
|
13847
13852
|
*/
|
|
13848
|
-
function installTeardownSignalHandlers(teardown) {
|
|
13853
|
+
function installTeardownSignalHandlers(teardown, onSignal) {
|
|
13849
13854
|
let handling = false;
|
|
13850
13855
|
const handler = (sig) => {
|
|
13851
13856
|
const code = sig === "SIGINT" ? 130 : 143;
|
|
@@ -13854,6 +13859,7 @@ function installTeardownSignalHandlers(teardown) {
|
|
|
13854
13859
|
return;
|
|
13855
13860
|
}
|
|
13856
13861
|
handling = true;
|
|
13862
|
+
onSignal?.(sig);
|
|
13857
13863
|
teardown.run().finally(() => process.exit(code));
|
|
13858
13864
|
};
|
|
13859
13865
|
const onInt = () => handler("SIGINT");
|
|
@@ -14018,6 +14024,16 @@ function generateSessionName() {
|
|
|
14018
14024
|
*/
|
|
14019
14025
|
function buildTraceSystemPrompt(input) {
|
|
14020
14026
|
const sessionName = input.sessionName ?? generateSessionName();
|
|
14027
|
+
const callerGuidance = input.instruction ? `## Caller Guidance
|
|
14028
|
+
|
|
14029
|
+
The caller provided extra guidance for this recording — for example, a drift
|
|
14030
|
+
audit's finding about what a previous recording of this spec got wrong. Treat
|
|
14031
|
+
it as advice on what to avoid or verify while recording; the spec's steps
|
|
14032
|
+
above remain the contract for what to do.
|
|
14033
|
+
|
|
14034
|
+
${input.instruction}
|
|
14035
|
+
|
|
14036
|
+
` : "";
|
|
14021
14037
|
const stepsText = input.steps.map((step) => `### ${step.id} [${step.source}]
|
|
14022
14038
|
- **Instruction**: ${step.instruction}
|
|
14023
14039
|
- **Expected**: ${step.expected}`).join("\n\n");
|
|
@@ -14405,7 +14421,7 @@ RUN_COMPLETED|passed|<summary>
|
|
|
14405
14421
|
RUN_COMPLETED|failed|<summary>
|
|
14406
14422
|
\`\`\`
|
|
14407
14423
|
|
|
14408
|
-
## Start
|
|
14424
|
+
${callerGuidance}## Start
|
|
14409
14425
|
|
|
14410
14426
|
Begin by clearing cookies, then proceed straight to the first step's instruction.
|
|
14411
14427
|
|
|
@@ -14881,7 +14897,8 @@ async function runTrace(featureName, specName, model, validationMode = "lenient"
|
|
|
14881
14897
|
const baseSystemPrompt = buildTraceSystemPrompt({
|
|
14882
14898
|
title: spec.title,
|
|
14883
14899
|
steps: expanded,
|
|
14884
|
-
sessionName
|
|
14900
|
+
sessionName,
|
|
14901
|
+
...opts.instruction ? { instruction: opts.instruction } : {}
|
|
14885
14902
|
});
|
|
14886
14903
|
const promptBundle = await loadPromptBundleFromHub(opts.hubContext ?? null, "record");
|
|
14887
14904
|
if (promptBundle !== null) meta("prompt", promptBundle.loaded.join(" + "));
|
|
@@ -14892,7 +14909,7 @@ async function runTrace(featureName, specName, model, validationMode = "lenient"
|
|
|
14892
14909
|
const statusLines = [];
|
|
14893
14910
|
let overallStatus = "passed";
|
|
14894
14911
|
const traceActions = [];
|
|
14895
|
-
const stepTracker = createStepTracker();
|
|
14912
|
+
const stepTracker = createStepTracker(opts.onStep);
|
|
14896
14913
|
const withStepId = (action, stepId) => {
|
|
14897
14914
|
if (!action) return null;
|
|
14898
14915
|
return stepId ? {
|
|
@@ -15234,15 +15251,18 @@ function groupCountByStep(actions) {
|
|
|
15234
15251
|
}
|
|
15235
15252
|
return counts;
|
|
15236
15253
|
}
|
|
15237
|
-
function createStepTracker() {
|
|
15254
|
+
function createStepTracker(onChange) {
|
|
15238
15255
|
let currentStepId;
|
|
15256
|
+
const advance = (stepId) => {
|
|
15257
|
+
if (stepId === currentStepId) return;
|
|
15258
|
+
currentStepId = stepId;
|
|
15259
|
+
onChange?.(stepId);
|
|
15260
|
+
};
|
|
15239
15261
|
return {
|
|
15240
15262
|
current: () => currentStepId,
|
|
15241
|
-
fromStepStartLine:
|
|
15242
|
-
currentStepId = stepId;
|
|
15243
|
-
},
|
|
15263
|
+
fromStepStartLine: advance,
|
|
15244
15264
|
fromCommand: (stepId) => {
|
|
15245
|
-
if (stepId)
|
|
15265
|
+
if (stepId) advance(stepId);
|
|
15246
15266
|
return currentStepId;
|
|
15247
15267
|
}
|
|
15248
15268
|
};
|
|
@@ -15500,10 +15520,10 @@ async function runGenerateCli(specPath, opts) {
|
|
|
15500
15520
|
//#endregion
|
|
15501
15521
|
//#region src/cli/record.ts
|
|
15502
15522
|
const VALIDATION_MODES = ["lenient", "strict"];
|
|
15503
|
-
const recordCommand = addHubOptions(addProfileOption(addLanguageOption(new Command("record").argument("<feature/spec>", "Spec id in '<feature>/<spec>' form (resolves to .ccqa/features/<feature>/test-cases/<spec>/)").description("Record a test from a spec: run agent-browser to collect actions (trace), then compile them into runnable code via the spec's target (generate) — a vitest test.spec.ts for agent-browser, a @playwright/test spec for the playwright target. Recording-backed targets only; spec-input targets like runn have no trace step (use `ccqa generate`), and agent-browser live specs need no recording.").optionsGroup("How to record:").option("-m, --model <name>", "Claude model alias ('sonnet'|'opus'|'haiku') or full ID. Overrides CCQA_MODEL.").option("--trace-validation <mode>", "What to do with actions that fail post-trace validation: 'lenient' (default) tags them; 'strict' drops them.", (raw) => {
|
|
15523
|
+
const recordCommand = addHubOptions(addProfileOption(addLanguageOption(new Command("record").argument("<feature/spec>", "Spec id in '<feature>/<spec>' form (resolves to .ccqa/features/<feature>/test-cases/<spec>/)").description("Record a test from a spec: run agent-browser to collect actions (trace), then compile them into runnable code via the spec's target (generate) — a vitest test.spec.ts for agent-browser, a @playwright/test spec for the playwright target. Recording-backed targets only; spec-input targets like runn have no trace step (use `ccqa generate`), and agent-browser live specs need no recording.").optionsGroup("How to record:").option("-m, --model <name>", "Claude model alias ('sonnet'|'opus'|'haiku') or full ID. Overrides CCQA_MODEL.").option("--instruction <text>", "Extra guidance for the recording agent — e.g. the drift audit's finding when re-recording a drifted spec.").option("--trace-validation <mode>", "What to do with actions that fail post-trace validation: 'lenient' (default) tags them; 'strict' drops them.", (raw) => {
|
|
15504
15524
|
if (VALIDATION_MODES.includes(raw)) return raw;
|
|
15505
15525
|
throw new Error(`--trace-validation must be one of ${VALIDATION_MODES.join(" | ")}`);
|
|
15506
|
-
}, "lenient").option("--auto-fix <mode>", "Auto-fix behaviour during script generation: 'interactive' (default, prompt y/N; declines on non-TTY), 'auto' (apply without prompt, for CI), 'skip' (agent-browser: apply only high-confidence fixes; external targets like playwright/runn: no fix pass at all).", parseAutoFixFlag, "interactive").option("--auto-fix-max-retries <n>", "Maximum number of auto-fix retries", "3").option("--trace-only", "Stop after the trace step; do not generate test code").option("--no-session-pin", "Don't pin AGENT_BROWSER_SESSION / capture page snapshots after a failure (debug toggle)").optionsGroup("What to do with the result:").option("--overwrite", "Replace an existing test.spec.ts without warning").option("--report-to-hub", "Leave a run (kind: record) on the hub saying this spec was recorded and what the recording spent on Claude, so a budget summed over the hub's runs sees it. It advances no ledger: a recording verifies nothing.").optionsGroup("Learning:").option("--learn-hub-trace-prompt", "After the trace finishes, ask Claude to refresh the \"record.agent\" prompt on the hub from a summary of the run. Requires a hub connection.").optionsGroup("Environment and connection:").option("--cwd <path>", "Working directory containing the .ccqa/ tree (monorepo support). Defaults to the current directory.").option("--project <name>", "Project name for the hub. Defaults to the current directory's name.")))).action(withUsageErrors(async (specPath, opts) => {
|
|
15526
|
+
}, "lenient").option("--auto-fix <mode>", "Auto-fix behaviour during script generation: 'interactive' (default, prompt y/N; declines on non-TTY), 'auto' (apply without prompt, for CI), 'skip' (agent-browser: apply only high-confidence fixes; external targets like playwright/runn: no fix pass at all).", parseAutoFixFlag, "interactive").option("--auto-fix-max-retries <n>", "Maximum number of auto-fix retries", "3").option("--timeout <seconds>", "Abort the recording after this many seconds, wherever it is (trace, generate, auto-fix): reap the browser session, seal the open hub run (--report-to-hub) with a 'timed out' note, and exit 124. Prefer this over wrapping the command in an external `timeout`, whose SIGTERM may never reach this process.", parseTimeoutSeconds).option("--trace-only", "Stop after the trace step; do not generate test code").option("--no-session-pin", "Don't pin AGENT_BROWSER_SESSION / capture page snapshots after a failure (debug toggle)").optionsGroup("What to do with the result:").option("--overwrite", "Replace an existing test.spec.ts without warning").option("--report-to-hub", "Leave a run (kind: record) on the hub saying this spec was recorded and what the recording spent on Claude, so a budget summed over the hub's runs sees it. It advances no ledger: a recording verifies nothing.").optionsGroup("Learning:").option("--learn-hub-trace-prompt", "After the trace finishes, ask Claude to refresh the \"record.agent\" prompt on the hub from a summary of the run. Requires a hub connection.").optionsGroup("Environment and connection:").option("--cwd <path>", "Working directory containing the .ccqa/ tree (monorepo support). Defaults to the current directory.").option("--project <name>", "Project name for the hub. Defaults to the current directory's name.")))).action(withUsageErrors(async (specPath, opts) => {
|
|
15507
15527
|
await withCostReporting("record", () => runRecord(specPath, opts));
|
|
15508
15528
|
}));
|
|
15509
15529
|
async function runRecord(specPath, opts) {
|
|
@@ -15557,20 +15577,48 @@ async function runRecord(specPath, opts) {
|
|
|
15557
15577
|
if (push) info(`hub: record run opened (${push.runId})`);
|
|
15558
15578
|
let recorded = false;
|
|
15559
15579
|
let sealed = true;
|
|
15580
|
+
let tracingStep;
|
|
15581
|
+
let abortCause;
|
|
15560
15582
|
const teardown = createRunTeardown();
|
|
15561
15583
|
teardown.onFinalize(async () => {
|
|
15562
|
-
if (push)
|
|
15584
|
+
if (!push) return;
|
|
15585
|
+
sealed = await sealRecordPush(push, featureName, specName, recorded, abortCause !== void 0 ? abortNote(abortCause, tracingStep) : void 0);
|
|
15563
15586
|
});
|
|
15564
|
-
const disposeSignalHandlers = installTeardownSignalHandlers(teardown)
|
|
15587
|
+
const disposeSignalHandlers = installTeardownSignalHandlers(teardown, (sig) => {
|
|
15588
|
+
abortCause = `terminated by signal (${sig})`;
|
|
15589
|
+
});
|
|
15590
|
+
let deadline;
|
|
15591
|
+
if (opts.timeout !== void 0) {
|
|
15592
|
+
const seconds = opts.timeout;
|
|
15593
|
+
deadline = setTimeout(() => {
|
|
15594
|
+
abortCause = `timed out after ${seconds}s`;
|
|
15595
|
+
error(`--timeout: ${abortNote(abortCause, tracingStep)}`);
|
|
15596
|
+
teardown.run().finally(() => process.exit(124));
|
|
15597
|
+
}, seconds * 1e3);
|
|
15598
|
+
deadline.unref();
|
|
15599
|
+
}
|
|
15565
15600
|
try {
|
|
15566
|
-
let traceResult = null;
|
|
15567
15601
|
let generated = true;
|
|
15568
15602
|
try {
|
|
15569
|
-
traceResult = await runTrace(featureName, specName, opts.model, opts.traceValidation ?? "lenient", language, {
|
|
15603
|
+
const traceResult = await runTrace(featureName, specName, opts.model, opts.traceValidation ?? "lenient", language, {
|
|
15570
15604
|
cwd: cwdForProfile,
|
|
15571
|
-
hubContext
|
|
15605
|
+
hubContext,
|
|
15606
|
+
...opts.instruction ? { instruction: opts.instruction } : {},
|
|
15607
|
+
onStep: (stepId) => {
|
|
15608
|
+
tracingStep = stepId;
|
|
15609
|
+
}
|
|
15572
15610
|
});
|
|
15611
|
+
tracingStep = void 0;
|
|
15573
15612
|
blank();
|
|
15613
|
+
await learnFromTrace({
|
|
15614
|
+
enabled: opts.learnHubTracePrompt === true,
|
|
15615
|
+
featureName,
|
|
15616
|
+
specName,
|
|
15617
|
+
traceResult,
|
|
15618
|
+
hubContext,
|
|
15619
|
+
...opts.model ? { model: opts.model } : {},
|
|
15620
|
+
...language ? { language } : {}
|
|
15621
|
+
});
|
|
15574
15622
|
if (!opts.traceOnly) generated = (await runGenerate(featureName, specName, {
|
|
15575
15623
|
maxRetries: parseInt(opts.autoFixMaxRetries ?? "3", 10),
|
|
15576
15624
|
fixMode: toFixMode(opts.autoFix ?? "interactive"),
|
|
@@ -15585,38 +15633,73 @@ async function runRecord(specPath, opts) {
|
|
|
15585
15633
|
} finally {
|
|
15586
15634
|
await releaseLock();
|
|
15587
15635
|
}
|
|
15588
|
-
if (opts.learnHubTracePrompt && traceResult !== null) {
|
|
15589
|
-
blank();
|
|
15590
|
-
await updateAgentPrompt({
|
|
15591
|
-
kind: "record",
|
|
15592
|
-
flag: "--learn-hub-trace-prompt",
|
|
15593
|
-
runSummary: buildRecordRunSummary(featureName, specName, traceResult),
|
|
15594
|
-
hubContext,
|
|
15595
|
-
...opts.model ? { model: opts.model } : {},
|
|
15596
|
-
...language ? { language } : {}
|
|
15597
|
-
});
|
|
15598
|
-
}
|
|
15599
15636
|
recorded = generated;
|
|
15600
15637
|
} finally {
|
|
15638
|
+
if (deadline !== void 0) clearTimeout(deadline);
|
|
15601
15639
|
await teardown.run();
|
|
15602
15640
|
disposeSignalHandlers();
|
|
15603
15641
|
}
|
|
15604
15642
|
if (!sealed) process.exit(2);
|
|
15605
15643
|
if (!recorded) process.exit(1);
|
|
15606
15644
|
}
|
|
15645
|
+
/** `--timeout <seconds>`: a positive whole number of seconds. */
|
|
15646
|
+
function parseTimeoutSeconds(raw) {
|
|
15647
|
+
const n = Number(raw);
|
|
15648
|
+
if (!Number.isFinite(n) || n <= 0 || Math.floor(n) !== n) throw new Error(`--timeout must be a positive integer number of seconds, got "${raw}"`);
|
|
15649
|
+
return n;
|
|
15650
|
+
}
|
|
15651
|
+
/**
|
|
15652
|
+
* The one line an aborted recording leaves on its hub row: what ended it
|
|
15653
|
+
* ("terminated by signal (SIGTERM)", "timed out after 900s") plus the spec
|
|
15654
|
+
* step that was tracing, when one was in flight. The signal handlers and the
|
|
15655
|
+
* --timeout deadline both seal through this, so every abort dies with the
|
|
15656
|
+
* same shape of reason.
|
|
15657
|
+
*/
|
|
15658
|
+
function abortNote(cause, tracingStep) {
|
|
15659
|
+
return `${cause}${tracingStep !== void 0 ? ` during ${tracingStep}` : ""}`;
|
|
15660
|
+
}
|
|
15661
|
+
/**
|
|
15662
|
+
* The rule for `--learn-hub-trace-prompt`: a browser trace ran → learn from
|
|
15663
|
+
* it; no trace → stay silent. `runRecord` calls this immediately after the
|
|
15664
|
+
* trace, before generate — sequencing it after the generate/auto-fix half
|
|
15665
|
+
* (as record once did) let any death there discard a completed trace's
|
|
15666
|
+
* learnings. Returns whether the refresh fired, and takes the updater as a
|
|
15667
|
+
* seam so the rule is testable without a browser.
|
|
15668
|
+
*/
|
|
15669
|
+
async function learnFromTrace(args, update = updateAgentPrompt) {
|
|
15670
|
+
if (!args.enabled || args.traceResult === null) return false;
|
|
15671
|
+
blank();
|
|
15672
|
+
await update({
|
|
15673
|
+
kind: "record",
|
|
15674
|
+
flag: "--learn-hub-trace-prompt",
|
|
15675
|
+
runSummary: buildRecordRunSummary(args.featureName, args.specName, args.traceResult),
|
|
15676
|
+
hubContext: args.hubContext,
|
|
15677
|
+
...args.model !== void 0 ? { model: args.model } : {},
|
|
15678
|
+
...args.language !== void 0 ? { language: args.language } : {}
|
|
15679
|
+
});
|
|
15680
|
+
return true;
|
|
15681
|
+
}
|
|
15607
15682
|
/**
|
|
15608
15683
|
* Close the record run with the one row this command produced, answering
|
|
15609
15684
|
* whether it closed. One spec is recorded per invocation, so one row is the
|
|
15610
15685
|
* whole run — enough for the runs list to say what the money bought.
|
|
15686
|
+
*
|
|
15687
|
+
* `failureNote` (e.g. "terminated by signal (SIGTERM) during step-03") rides
|
|
15688
|
+
* in the row's `failureLogExcerpt` — the field a failed `ccqa run` row already
|
|
15689
|
+
* uses for its failure text — so the hub says why a recording died instead of
|
|
15690
|
+
* a bare status:"failed". Ignored on a successful recording.
|
|
15611
15691
|
*/
|
|
15612
|
-
async function sealRecordPush(push, featureName, specName, recorded) {
|
|
15692
|
+
async function sealRecordPush(push, featureName, specName, recorded, failureNote) {
|
|
15613
15693
|
return sealHubRun(push, {
|
|
15614
|
-
rows: [
|
|
15615
|
-
|
|
15616
|
-
|
|
15617
|
-
|
|
15618
|
-
|
|
15619
|
-
|
|
15694
|
+
rows: [{
|
|
15695
|
+
...emptySpecRow({
|
|
15696
|
+
feature: featureName,
|
|
15697
|
+
spec: specName,
|
|
15698
|
+
title: null,
|
|
15699
|
+
status: recorded ? "passed" : "failed"
|
|
15700
|
+
}),
|
|
15701
|
+
...!recorded && failureNote ? { failureLogExcerpt: failureNote } : {}
|
|
15702
|
+
}],
|
|
15620
15703
|
reportMeta: {
|
|
15621
15704
|
git: {
|
|
15622
15705
|
head: push.gitHead,
|
|
@@ -17457,6 +17540,7 @@ function gradedDriftEntry(ledger, key, runId, label) {
|
|
|
17457
17540
|
};
|
|
17458
17541
|
if (label === null) {
|
|
17459
17542
|
delete graded.surface;
|
|
17543
|
+
delete graded.subDiagnosis;
|
|
17460
17544
|
delete graded.headline;
|
|
17461
17545
|
delete graded.confidence;
|
|
17462
17546
|
}
|
|
@@ -17821,9 +17905,11 @@ async function updateDriftLedger(storage, run, results) {
|
|
|
17821
17905
|
if (row.status === "skipped") continue;
|
|
17822
17906
|
const key = `${row.feature}/${row.spec}`;
|
|
17823
17907
|
const diagnosis = row.analysis ? normalizeDiagnosis(row.analysis) : null;
|
|
17908
|
+
const subDiagnosis = DriftSubDiagnosisSchema.safeParse(diagnosis?.subDiagnosis);
|
|
17824
17909
|
ledger.specs[key] = {
|
|
17825
17910
|
label: diagnosis ? diagnosis.label : null,
|
|
17826
17911
|
surface: diagnosis?.surface,
|
|
17912
|
+
subDiagnosis: subDiagnosis.success ? subDiagnosis.data : void 0,
|
|
17827
17913
|
specChangeKind: diagnosis?.specChangeKind,
|
|
17828
17914
|
confidence: diagnosis?.confidence,
|
|
17829
17915
|
headline: diagnosis?.headline,
|
|
@@ -383,6 +383,11 @@ declare const DriftLedgerResponseSchema: z.ZodObject<{
|
|
|
383
383
|
spec: "spec";
|
|
384
384
|
generated: "generated";
|
|
385
385
|
}>>;
|
|
386
|
+
subDiagnosis: z.ZodOptional<z.ZodEnum<{
|
|
387
|
+
OVER_ASSERTION: "OVER_ASSERTION";
|
|
388
|
+
SELECTOR_DRIFT: "SELECTOR_DRIFT";
|
|
389
|
+
NONE: "NONE";
|
|
390
|
+
}>>;
|
|
386
391
|
specChangeKind: z.ZodOptional<z.ZodEnum<{
|
|
387
392
|
FEATURE_REMOVED: "FEATURE_REMOVED";
|
|
388
393
|
BEHAVIOUR_CHANGED: "BEHAVIOUR_CHANGED";
|
|
@@ -476,8 +481,8 @@ declare const ReportSpecResultSchema: z.ZodObject<{
|
|
|
476
481
|
title: z.ZodNullable<z.ZodString>;
|
|
477
482
|
target: z.ZodOptional<z.ZodString>;
|
|
478
483
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
479
|
-
live: "live";
|
|
480
484
|
deterministic: "deterministic";
|
|
485
|
+
live: "live";
|
|
481
486
|
}>>;
|
|
482
487
|
status: z.ZodEnum<{
|
|
483
488
|
passed: "passed";
|
|
@@ -660,8 +665,8 @@ declare const RunReportDataSchema: z.ZodObject<{
|
|
|
660
665
|
title: z.ZodNullable<z.ZodString>;
|
|
661
666
|
target: z.ZodOptional<z.ZodString>;
|
|
662
667
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
663
|
-
live: "live";
|
|
664
668
|
deterministic: "deterministic";
|
|
669
|
+
live: "live";
|
|
665
670
|
}>>;
|
|
666
671
|
status: z.ZodEnum<{
|
|
667
672
|
passed: "passed";
|
package/dist/package.json
CHANGED