ccqa 1.45.1 → 1.46.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 +42 -22
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/bin/ccqa.mjs
CHANGED
|
@@ -223,6 +223,7 @@ const AGENT_BROWSER_TARGET = "agent-browser";
|
|
|
223
223
|
*/
|
|
224
224
|
const TestSpecSchema = z.object({
|
|
225
225
|
title: z.string().min(1),
|
|
226
|
+
disabled: z.boolean().optional(),
|
|
226
227
|
target: TargetIdSchema.optional(),
|
|
227
228
|
mode: SpecModeSchema.optional(),
|
|
228
229
|
session: SessionFieldSchema.optional(),
|
|
@@ -647,6 +648,21 @@ async function getTestScript(featureName, specName, cwd) {
|
|
|
647
648
|
async function listAllSpecsWithSpecFile(cwd) {
|
|
648
649
|
return listAllSpecsFilteredBy(SPEC_FILE, cwd);
|
|
649
650
|
}
|
|
651
|
+
/**
|
|
652
|
+
* The active suite — the tree minus the specs marked `disabled` — which is
|
|
653
|
+
* what `ccqa run` expands "all specs" to. Kept separate from the enumeration
|
|
654
|
+
* above because `serialGroups` and `actors` validate that a spec *name*
|
|
655
|
+
* exists, and a disabled spec is still a name.
|
|
656
|
+
*
|
|
657
|
+
* A spec that will not read or parse stays in: unreadable is not the same as
|
|
658
|
+
* asking to be skipped.
|
|
659
|
+
*/
|
|
660
|
+
async function listActiveSpecs(cwd) {
|
|
661
|
+
const all = await listAllSpecsWithSpecFile(cwd);
|
|
662
|
+
return (await Promise.all(all.map(async (ref) => {
|
|
663
|
+
return tryParseTestSpec(await tryReadSpecFile(ref.featureName, ref.specName, cwd))?.disabled === true ? null : ref;
|
|
664
|
+
}))).filter((ref) => ref !== null);
|
|
665
|
+
}
|
|
650
666
|
async function listAllSpecsFilteredBy(requiredFilename, cwd) {
|
|
651
667
|
const featuresDir = join(getCcqaDir(cwd), "features");
|
|
652
668
|
const featureDirs = await readdir(featuresDir).catch(() => []);
|
|
@@ -676,13 +692,7 @@ async function resolveSpecTargets(target, enumerateAll, cwd) {
|
|
|
676
692
|
specName
|
|
677
693
|
}];
|
|
678
694
|
}
|
|
679
|
-
return (await
|
|
680
|
-
featureName: target,
|
|
681
|
-
specName
|
|
682
|
-
}));
|
|
683
|
-
}
|
|
684
|
-
async function listSpecsForFeature(featureName, cwd) {
|
|
685
|
-
return readdir(join(getFeatureDir(featureName, cwd), "test-cases")).catch(() => []);
|
|
695
|
+
return (await listActiveSpecs(cwd)).filter((ref) => ref.featureName === target);
|
|
686
696
|
}
|
|
687
697
|
/**
|
|
688
698
|
* Lists every feature/spec dir under .ccqa/features/, regardless of whether
|
|
@@ -4968,6 +4978,7 @@ const PerspectiveSpecSchema = z.object({
|
|
|
4968
4978
|
steps: z.array(PerspectiveStepSchema).optional(),
|
|
4969
4979
|
status: PerspectiveStatusSchema,
|
|
4970
4980
|
changedAt: z.string().optional(),
|
|
4981
|
+
disabled: z.boolean().optional(),
|
|
4971
4982
|
note: z.string().optional()
|
|
4972
4983
|
}).strip();
|
|
4973
4984
|
const PerspectiveFeatureSchema = z.object({
|
|
@@ -12166,6 +12177,7 @@ async function loadSpecInventory(cwd) {
|
|
|
12166
12177
|
const content = await tryReadSpecFile(featureName, specName, cwd);
|
|
12167
12178
|
if (content === null) return null;
|
|
12168
12179
|
const spec = parseTestSpec(content, `${featureName}/${specName}/spec.yaml`);
|
|
12180
|
+
if (spec.disabled) return null;
|
|
12169
12181
|
return {
|
|
12170
12182
|
featureName,
|
|
12171
12183
|
specName,
|
|
@@ -17096,7 +17108,7 @@ async function executeRun(targets, opts) {
|
|
|
17096
17108
|
customPrompt,
|
|
17097
17109
|
triageUserPrompt
|
|
17098
17110
|
};
|
|
17099
|
-
const enumerateAll = () =>
|
|
17111
|
+
const enumerateAll = () => listActiveSpecs(cwd);
|
|
17100
17112
|
let specs = dedupeSpecs((await Promise.all((targets.length ? targets : [void 0]).map((t) => resolveSpecTargets(t, enumerateAll, cwd)))).flat());
|
|
17101
17113
|
if (filtering) {
|
|
17102
17114
|
const before = specs.length;
|
|
@@ -21128,13 +21140,15 @@ async function collectTargets(specPath, cwd) {
|
|
|
21128
21140
|
specName
|
|
21129
21141
|
}];
|
|
21130
21142
|
}
|
|
21143
|
+
const active = new Set((await listActiveSpecs(cwd)).map(specKey));
|
|
21131
21144
|
const out = [];
|
|
21132
21145
|
for (const feature of tree) for (const spec of feature.specs) {
|
|
21133
21146
|
if (!spec.hasSpecFile) continue;
|
|
21134
|
-
|
|
21147
|
+
const target = {
|
|
21135
21148
|
featureName: feature.featureName,
|
|
21136
21149
|
specName: spec.specName
|
|
21137
|
-
}
|
|
21150
|
+
};
|
|
21151
|
+
if (active.has(specKey(target))) out.push(target);
|
|
21138
21152
|
}
|
|
21139
21153
|
return out;
|
|
21140
21154
|
}
|
|
@@ -21358,6 +21372,7 @@ function comparePerspectivesSkeleton(local, remote) {
|
|
|
21358
21372
|
}
|
|
21359
21373
|
const fields = [];
|
|
21360
21374
|
if (remoteSpec.title !== spec.title) fields.push("title");
|
|
21375
|
+
if ((remoteSpec.disabled ?? false) !== (spec.disabled ?? false)) fields.push("disabled");
|
|
21361
21376
|
if (remoteSpec.status.mode !== spec.status.mode || remoteSpec.status.traced !== spec.status.traced || remoteSpec.status.generated !== spec.status.generated || remoteSpec.status.target !== spec.status.target) fields.push(`status (local: ${formatStatus(spec.status)}, hub: ${formatStatus(remoteSpec.status)})`);
|
|
21362
21377
|
if (fields.length > 0) issues.push(`${key}: out of date — ${fields.join(", ")}`);
|
|
21363
21378
|
}
|
|
@@ -21446,7 +21461,7 @@ async function buildSkeleton(tree) {
|
|
|
21446
21461
|
const config = await loadProjectConfig(process.cwd()).catch(() => null);
|
|
21447
21462
|
const changedAt = await readSpecChangedAt(process.cwd());
|
|
21448
21463
|
return (await Promise.all(tree.map(async (feature) => {
|
|
21449
|
-
const
|
|
21464
|
+
const built = await Promise.all(feature.specs.filter((s) => s.hasSpecFile).map(async (s) => {
|
|
21450
21465
|
const specYaml = await tryReadSpecFile(feature.featureName, s.specName);
|
|
21451
21466
|
const meta = readSpecMeta(s.specName, specYaml);
|
|
21452
21467
|
const plugin = resolveSpecTarget(specYaml, config);
|
|
@@ -21458,12 +21473,13 @@ async function buildSkeleton(tree) {
|
|
|
21458
21473
|
summary: "",
|
|
21459
21474
|
...meta.steps.length > 0 ? { steps: meta.steps } : {},
|
|
21460
21475
|
status,
|
|
21461
|
-
...lastEdit ? { changedAt: lastEdit } : {}
|
|
21476
|
+
...lastEdit ? { changedAt: lastEdit } : {},
|
|
21477
|
+
...meta.disabled ? { disabled: true } : {}
|
|
21462
21478
|
};
|
|
21463
21479
|
}));
|
|
21464
21480
|
return {
|
|
21465
21481
|
featureName: feature.featureName,
|
|
21466
|
-
specs
|
|
21482
|
+
specs: built
|
|
21467
21483
|
};
|
|
21468
21484
|
}))).filter((f) => f.specs.length > 0).map((f) => ({
|
|
21469
21485
|
featureName: f.featureName,
|
|
@@ -21526,13 +21542,19 @@ function withoutGeneratedAt(yamlText) {
|
|
|
21526
21542
|
function noteKey(featureName, specName) {
|
|
21527
21543
|
return `${featureName}/${specName}`;
|
|
21528
21544
|
}
|
|
21529
|
-
/**
|
|
21545
|
+
/**
|
|
21546
|
+
* Lenient read of an already-loaded spec.yaml. A file that is missing or will
|
|
21547
|
+
* not parse falls back to `defaults`, which reports the spec as enabled: a
|
|
21548
|
+
* spec nobody could read has not asked to be skipped.
|
|
21549
|
+
*/
|
|
21530
21550
|
function readSpecMeta(specName, specYaml) {
|
|
21531
|
-
|
|
21551
|
+
const defaults = {
|
|
21532
21552
|
title: specName,
|
|
21533
21553
|
mode: DEFAULT_SPEC_MODE,
|
|
21534
|
-
steps: []
|
|
21554
|
+
steps: [],
|
|
21555
|
+
disabled: false
|
|
21535
21556
|
};
|
|
21557
|
+
if (specYaml === null) return defaults;
|
|
21536
21558
|
try {
|
|
21537
21559
|
const parsed = parse(specYaml);
|
|
21538
21560
|
const title = typeof parsed.title === "string" && parsed.title.length > 0 ? parsed.title : specName;
|
|
@@ -21540,14 +21562,11 @@ function readSpecMeta(specName, specYaml) {
|
|
|
21540
21562
|
return {
|
|
21541
21563
|
title,
|
|
21542
21564
|
mode: modeResult.success ? modeResult.data : DEFAULT_SPEC_MODE,
|
|
21543
|
-
steps: transcribeSteps(parsed.steps)
|
|
21565
|
+
steps: transcribeSteps(parsed.steps),
|
|
21566
|
+
disabled: tryParseTestSpec(specYaml)?.disabled === true
|
|
21544
21567
|
};
|
|
21545
21568
|
} catch {
|
|
21546
|
-
return
|
|
21547
|
-
title: specName,
|
|
21548
|
-
mode: DEFAULT_SPEC_MODE,
|
|
21549
|
-
steps: []
|
|
21550
|
-
};
|
|
21569
|
+
return defaults;
|
|
21551
21570
|
}
|
|
21552
21571
|
}
|
|
21553
21572
|
/**
|
|
@@ -23076,6 +23095,7 @@ function readSpecTargets(doc) {
|
|
|
23076
23095
|
for (const spec of specs) {
|
|
23077
23096
|
const specName = prop(spec, "specName");
|
|
23078
23097
|
if (typeof specName !== "string") continue;
|
|
23098
|
+
if (prop(spec, "disabled") === true) continue;
|
|
23079
23099
|
const changedAt = prop(spec, "changedAt");
|
|
23080
23100
|
out.push({
|
|
23081
23101
|
key: `${featureName}/${specName}`,
|
package/dist/package.json
CHANGED