@slowcook-ai/cli 0.21.2 → 0.23.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/AGENTS.md +11 -0
- package/README.md +8 -4
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/brand/index.d.ts.map +1 -1
- package/dist/commands/brand/index.js +18 -8
- package/dist/commands/brand/index.js.map +1 -1
- package/dist/commands/estimate/index.d.ts +2 -0
- package/dist/commands/estimate/index.d.ts.map +1 -0
- package/dist/commands/estimate/index.js +70 -0
- package/dist/commands/estimate/index.js.map +1 -0
- package/dist/commands/estimate/model.d.ts +117 -0
- package/dist/commands/estimate/model.d.ts.map +1 -0
- package/dist/commands/estimate/model.js +158 -0
- package/dist/commands/estimate/model.js.map +1 -0
- package/dist/commands/eye/index.d.ts.map +1 -1
- package/dist/commands/eye/index.js +16 -6
- package/dist/commands/eye/index.js.map +1 -1
- package/dist/commands/eye/plan.d.ts +41 -6
- package/dist/commands/eye/plan.d.ts.map +1 -1
- package/dist/commands/eye/plan.js +52 -9
- package/dist/commands/eye/plan.js.map +1 -1
- package/dist/commands/eye/run.d.ts +17 -1
- package/dist/commands/eye/run.d.ts.map +1 -1
- package/dist/commands/eye/run.js +38 -6
- package/dist/commands/eye/run.js.map +1 -1
- package/dist/commands/greenfield/index.d.ts.map +1 -1
- package/dist/commands/greenfield/index.js +33 -3
- package/dist/commands/greenfield/index.js.map +1 -1
- package/dist/commands/greenfield/status.d.ts +26 -5
- package/dist/commands/greenfield/status.d.ts.map +1 -1
- package/dist/commands/greenfield/status.js +28 -9
- package/dist/commands/greenfield/status.js.map +1 -1
- package/dist/commands/menu/assemble.d.ts.map +1 -1
- package/dist/commands/menu/assemble.js +6 -0
- package/dist/commands/menu/assemble.js.map +1 -1
- package/dist/commands/menu/index.d.ts.map +1 -1
- package/dist/commands/menu/index.js +42 -14
- package/dist/commands/menu/index.js.map +1 -1
- package/dist/commands/menu/prd.d.ts.map +1 -1
- package/dist/commands/menu/prd.js +17 -0
- package/dist/commands/menu/prd.js.map +1 -1
- package/dist/commands/reconcile/index.d.ts +2 -0
- package/dist/commands/reconcile/index.d.ts.map +1 -0
- package/dist/commands/reconcile/index.js +174 -0
- package/dist/commands/reconcile/index.js.map +1 -0
- package/dist/commands/refine/agent.d.ts.map +1 -1
- package/dist/commands/refine/agent.js +22 -2
- package/dist/commands/refine/agent.js.map +1 -1
- package/dist/commands/refine/context.d.ts +2 -0
- package/dist/commands/refine/context.d.ts.map +1 -1
- package/dist/commands/refine/context.js +21 -0
- package/dist/commands/refine/context.js.map +1 -1
- package/dist/commands/refine/history-index.d.ts +17 -0
- package/dist/commands/refine/history-index.d.ts.map +1 -1
- package/dist/commands/refine/history-index.js +106 -12
- package/dist/commands/refine/history-index.js.map +1 -1
- package/dist/commands/refine/index.d.ts.map +1 -1
- package/dist/commands/refine/index.js +11 -6
- package/dist/commands/refine/index.js.map +1 -1
- package/dist/commands/refine/llm.d.ts +1 -1
- package/dist/commands/refine/llm.d.ts.map +1 -1
- package/dist/commands/refine/llm.js +1 -1
- package/dist/commands/refine/llm.js.map +1 -1
- package/dist/commands/refine/mock-fixtures.d.ts +2 -0
- package/dist/commands/refine/mock-fixtures.d.ts.map +1 -1
- package/dist/commands/refine/mock-fixtures.js +32 -5
- package/dist/commands/refine/mock-fixtures.js.map +1 -1
- package/dist/commands/refine/spec-yaml.d.ts +27 -1
- package/dist/commands/refine/spec-yaml.d.ts.map +1 -1
- package/dist/commands/refine/spec-yaml.js +81 -5
- package/dist/commands/refine/spec-yaml.js.map +1 -1
- package/dist/commands/testgen/agent.d.ts +5 -0
- package/dist/commands/testgen/agent.d.ts.map +1 -1
- package/dist/commands/testgen/agent.js +65 -1
- package/dist/commands/testgen/agent.js.map +1 -1
- package/dist/commands/testgen/index.d.ts.map +1 -1
- package/dist/commands/testgen/index.js +11 -6
- package/dist/commands/testgen/index.js.map +1 -1
- package/dist/commands/trace/check.d.ts +72 -0
- package/dist/commands/trace/check.d.ts.map +1 -1
- package/dist/commands/trace/check.js +93 -0
- package/dist/commands/trace/check.js.map +1 -1
- package/dist/commands/trace/index.d.ts +5 -0
- package/dist/commands/trace/index.d.ts.map +1 -1
- package/dist/commands/trace/index.js +183 -7
- package/dist/commands/trace/index.js.map +1 -1
- package/dist/commands/upsert-agent-docs.d.ts.map +1 -1
- package/dist/commands/upsert-agent-docs.js +11 -0
- package/dist/commands/upsert-agent-docs.js.map +1 -1
- package/dist/commands/vibe/app-gen.d.ts +43 -0
- package/dist/commands/vibe/app-gen.d.ts.map +1 -0
- package/dist/commands/vibe/app-gen.js +512 -0
- package/dist/commands/vibe/app-gen.js.map +1 -0
- package/dist/commands/vibe/index.d.ts.map +1 -1
- package/dist/commands/vibe/index.js +287 -2
- package/dist/commands/vibe/index.js.map +1 -1
- package/dist/commands/vibe/lcr-plan.d.ts +125 -0
- package/dist/commands/vibe/lcr-plan.d.ts.map +1 -0
- package/dist/commands/vibe/lcr-plan.js +155 -0
- package/dist/commands/vibe/lcr-plan.js.map +1 -0
- package/dist/commands/vibe/schema-gen.d.ts +52 -0
- package/dist/commands/vibe/schema-gen.d.ts.map +1 -0
- package/dist/commands/vibe/schema-gen.js +205 -0
- package/dist/commands/vibe/schema-gen.js.map +1 -0
- package/dist/commands.manifest.d.ts.map +1 -1
- package/dist/commands.manifest.js +10 -4
- package/dist/commands.manifest.js.map +1 -1
- package/package.json +9 -9
|
@@ -9,16 +9,22 @@
|
|
|
9
9
|
*
|
|
10
10
|
* slowcook eye --reference http://localhost:33010 --candidate http://localhost:3001 \
|
|
11
11
|
* [--story 020] [--cwd .] [--out .brewing/eye] [--viewport mobile|desktop] \
|
|
12
|
-
* [--scheme light|dark] [--
|
|
12
|
+
* [--scheme light|dark] [--locale fa,en] [--scenario <name>] \
|
|
13
|
+
* [--max-violations N] [--fail-on color,box,computed-style,missing]
|
|
14
|
+
*
|
|
15
|
+
* --locale (§6) drives the consumer's language via `?lang=<code>` on BOTH sides
|
|
16
|
+
* (the locale/direction axis: viewport × scheme × locale). --scenario (§4) appends
|
|
17
|
+
* `?scenario=<name>` to BOTH sides so the mock + the candidate's dev-only data
|
|
18
|
+
* adaptor render the same fixture → a 1-1, data-noise-free diff.
|
|
13
19
|
*/
|
|
14
20
|
import { writeFileSync } from "node:fs";
|
|
15
21
|
import { join } from "node:path";
|
|
16
|
-
import { parseEyeArgs, matrixFromModes, narrowMatrix } from "./plan.js";
|
|
22
|
+
import { parseEyeArgs, matrixFromModes, narrowMatrix, applyLocaleAxis } from "./plan.js";
|
|
17
23
|
import { loadFidelityModes } from "./spec-modes.js";
|
|
18
|
-
import { runEyeMatrix, runEyeWatch } from "./run.js";
|
|
24
|
+
import { runEyeMatrix, runEyeWatch, cellLabel } from "./run.js";
|
|
19
25
|
export async function eye(args, _version) {
|
|
20
26
|
if (args[0] === "--help" || args[0] === "-h") {
|
|
21
|
-
console.log("usage: slowcook eye --reference <url> --candidate <url> [--story <id>] [--cwd <dir>] [--out dir] [--viewport m] [--scheme s] [--max-violations N] [--fail-on a,b] [--watch [--interval ms] [--until-converged] [--max-passes N]]");
|
|
27
|
+
console.log("usage: slowcook eye --reference <url> --candidate <url> [--story <id>] [--cwd <dir>] [--out dir] [--viewport m] [--scheme s] [--locale fa,en] [--scenario name] [--max-violations N] [--fail-on a,b] [--watch [--interval ms] [--until-converged] [--max-passes N]]");
|
|
22
28
|
return;
|
|
23
29
|
}
|
|
24
30
|
let opts;
|
|
@@ -34,7 +40,9 @@ export async function eye(args, _version) {
|
|
|
34
40
|
if (opts.story) {
|
|
35
41
|
const modes = loadFidelityModes(opts.cwd, opts.story);
|
|
36
42
|
if (modes && modes.length) {
|
|
37
|
-
|
|
43
|
+
// Spec declares the axes (incl. `locale:` tokens); CLI --locale narrows a
|
|
44
|
+
// declared locale axis, or opts one in if the spec declared none.
|
|
45
|
+
opts.matrix = applyLocaleAxis(narrowMatrix(matrixFromModes(modes), { viewport: opts.viewport, scheme: opts.scheme, locales: opts.locales }), opts.locales);
|
|
38
46
|
console.log(`eye: matrix from story-${opts.story} fidelity.modes [${modes.join(", ")}] → ${opts.matrix.length} cell(s)`);
|
|
39
47
|
}
|
|
40
48
|
else {
|
|
@@ -50,6 +58,7 @@ export async function eye(args, _version) {
|
|
|
50
58
|
matrix: opts.matrix,
|
|
51
59
|
outDir: opts.outDir,
|
|
52
60
|
gate: opts.gate,
|
|
61
|
+
scenario: opts.scenario,
|
|
53
62
|
intervalMs: opts.intervalMs,
|
|
54
63
|
untilConverged: opts.untilConverged,
|
|
55
64
|
maxPasses: opts.maxPasses,
|
|
@@ -66,13 +75,14 @@ export async function eye(args, _version) {
|
|
|
66
75
|
matrix: opts.matrix,
|
|
67
76
|
outDir: opts.outDir,
|
|
68
77
|
gate: opts.gate,
|
|
78
|
+
scenario: opts.scenario,
|
|
69
79
|
});
|
|
70
80
|
writeFileSync(join(opts.outDir, "eye-report.json"), JSON.stringify({ ...result, screenshots }, null, 2));
|
|
71
81
|
console.log(`\nslowcook eye — ${result.passed ? "PASS ✓" : "FAIL ✗"} (${result.violations.length} violation(s) across ${opts.matrix.length} render(s))`);
|
|
72
82
|
for (const ctx of result.byContext) {
|
|
73
83
|
if (ctx.violations.length === 0)
|
|
74
84
|
continue;
|
|
75
|
-
console.log(` [${
|
|
85
|
+
console.log(` [${cellLabel({ ...ctx.context, width: 0, height: 0 })}] ${ctx.violations.length}: ${JSON.stringify(ctx.summary.byAxis)}`);
|
|
76
86
|
for (const v of ctx.violations.slice(0, 5))
|
|
77
87
|
console.log(` ${v.axis}: ${v.evidence}`);
|
|
78
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/eye/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/eye/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,13 @@ export interface EyeContext {
|
|
|
15
15
|
scheme: "light" | "dark";
|
|
16
16
|
width: number;
|
|
17
17
|
height: number;
|
|
18
|
+
/**
|
|
19
|
+
* design §6 — locale/direction axis. When set, the runner drives the
|
|
20
|
+
* consumer's language by appending `?lang=<locale>` to BOTH the reference
|
|
21
|
+
* and the candidate URL (RTL/LTR layouts drift independently). Absent on
|
|
22
|
+
* the default matrix → unchanged viewport×scheme behaviour.
|
|
23
|
+
*/
|
|
24
|
+
locale?: string;
|
|
18
25
|
}
|
|
19
26
|
export interface EyeOptions {
|
|
20
27
|
referenceUrl: string;
|
|
@@ -29,6 +36,18 @@ export interface EyeOptions {
|
|
|
29
36
|
/** Raw narrowing flags, re-applied after a spec-derived matrix is built. */
|
|
30
37
|
viewport?: string;
|
|
31
38
|
scheme?: string;
|
|
39
|
+
/**
|
|
40
|
+
* design §6 — locale codes from `--locale fa,en`. Applied as a third matrix
|
|
41
|
+
* axis (driven via `?lang=` on both sides). When the spec/CLI declares none,
|
|
42
|
+
* the matrix has no locale dimension and behaviour is unchanged.
|
|
43
|
+
*/
|
|
44
|
+
locales?: string[];
|
|
45
|
+
/**
|
|
46
|
+
* design §4 — shared-fixture scenario from `--scenario <name>`. Appended as
|
|
47
|
+
* `?scenario=<name>` to BOTH sides so the mock's mock-data layer and the
|
|
48
|
+
* candidate's dev-only data adaptor render the SAME fixture → 1-1 diff.
|
|
49
|
+
*/
|
|
50
|
+
scenario?: string;
|
|
32
51
|
/** design #8 / sc#189 — warm-browser HMR re-eye loop. */
|
|
33
52
|
watch: boolean;
|
|
34
53
|
/** Poll interval between watch passes (ms). Default 2000. */
|
|
@@ -44,24 +63,40 @@ export declare const VIEWPORTS: Record<string, {
|
|
|
44
63
|
}>;
|
|
45
64
|
/** Full default matrix: {mobile,desktop} × {light,dark}. */
|
|
46
65
|
export declare const DEFAULT_MATRIX: EyeContext[];
|
|
66
|
+
/**
|
|
67
|
+
* design §6 — extract locale codes from `fidelity.modes`. Locales are namespaced
|
|
68
|
+
* tokens (`locale:fa`, `locale:en`) so they never collide with viewport/scheme
|
|
69
|
+
* values and a typo stays ignored (fail-open). Returns [] when none declared.
|
|
70
|
+
*/
|
|
71
|
+
export declare function localesFromModes(modes: string[]): string[];
|
|
72
|
+
/**
|
|
73
|
+
* Add (or filter) the locale axis on a matrix (pure). If the matrix already
|
|
74
|
+
* carries a locale dimension, narrow it to `locales`; otherwise multiply each
|
|
75
|
+
* cell by the locales (CLI/spec opting the axis in). No-op when `locales` empty.
|
|
76
|
+
*/
|
|
77
|
+
export declare function applyLocaleAxis(matrix: EyeContext[], locales: string[] | undefined): EyeContext[];
|
|
47
78
|
/**
|
|
48
79
|
* Build the capture matrix from a spec's declared `fidelity.modes` (pure).
|
|
49
|
-
* Tokens are dimension VALUES (`light`/`dark`/`mobile`/`desktop
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
80
|
+
* Tokens are dimension VALUES (`light`/`dark`/`mobile`/`desktop`, plus
|
|
81
|
+
* `locale:<code>` for the §6 locale axis), expanded to the product: a dimension
|
|
82
|
+
* with no declared value defaults to its full set (so `[dark]` → dark ×
|
|
83
|
+
* {mobile,desktop}; `[mobile]` → {light,dark} × mobile). Locale is OPTIONAL — no
|
|
84
|
+
* `locale:` token means no locale dimension. Unrecognised tokens are ignored; if
|
|
85
|
+
* NONE are recognised, the full default matrix is returned (fail-open — a typo
|
|
86
|
+
* never silently checks nothing).
|
|
54
87
|
*/
|
|
55
88
|
export declare function matrixFromModes(modes: string[]): EyeContext[];
|
|
56
|
-
/** Narrow a matrix by explicit --viewport / --scheme flags (pure). Validates. */
|
|
89
|
+
/** Narrow a matrix by explicit --viewport / --scheme / --locale flags (pure). Validates. */
|
|
57
90
|
export declare function narrowMatrix(base: EyeContext[], opts: {
|
|
58
91
|
viewport?: string;
|
|
59
92
|
scheme?: string;
|
|
93
|
+
locales?: string[];
|
|
60
94
|
}): EyeContext[];
|
|
61
95
|
/**
|
|
62
96
|
* Parse `slowcook eye` flags. Required: --reference <url>, --candidate <url>.
|
|
63
97
|
* Optional: --story <id> (derive the matrix from the spec's fidelity.modes),
|
|
64
98
|
* --cwd <dir>, --out <dir>, --viewport <name> + --scheme <light|dark> (narrow),
|
|
99
|
+
* --locale <fa,en> (§6 locale axis), --scenario <name> (§4 shared fixture),
|
|
65
100
|
* --max-violations <n>, --fail-on <a,b>. The returned `matrix` is the flag-only
|
|
66
101
|
* default; when `story` is set the runner rebuilds it from the spec.
|
|
67
102
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/commands/eye/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAgB,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/commands/eye/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAgB,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,KAAK,EAAE,OAAO,CAAC;IACf,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,cAAc,EAAE,OAAO,CAAC;IACxB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAGvE,CAAC;AAIF,4DAA4D;AAC5D,eAAO,MAAM,cAAc,EAAE,UAAU,EAEtC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAM1D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,UAAU,EAAE,CAOjG;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,CAU7D;AAED,4FAA4F;AAC5F,wBAAgB,YAAY,CAC1B,IAAI,EAAE,UAAU,EAAE,EAClB,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC/D,UAAU,EAAE,CAkBd;AAOD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA0CvD"}
|
|
@@ -5,25 +5,55 @@ export const VIEWPORTS = {
|
|
|
5
5
|
const SCHEMES = ["light", "dark"];
|
|
6
6
|
/** Full default matrix: {mobile,desktop} × {light,dark}. */
|
|
7
7
|
export const DEFAULT_MATRIX = Object.entries(VIEWPORTS).flatMap(([viewport, dim]) => SCHEMES.map((scheme) => ({ viewport, scheme, ...dim })));
|
|
8
|
+
/**
|
|
9
|
+
* design §6 — extract locale codes from `fidelity.modes`. Locales are namespaced
|
|
10
|
+
* tokens (`locale:fa`, `locale:en`) so they never collide with viewport/scheme
|
|
11
|
+
* values and a typo stays ignored (fail-open). Returns [] when none declared.
|
|
12
|
+
*/
|
|
13
|
+
export function localesFromModes(modes) {
|
|
14
|
+
return modes
|
|
15
|
+
.map((m) => String(m).toLowerCase().trim())
|
|
16
|
+
.filter((m) => m.startsWith("locale:"))
|
|
17
|
+
.map((m) => m.slice("locale:".length))
|
|
18
|
+
.filter(Boolean);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Add (or filter) the locale axis on a matrix (pure). If the matrix already
|
|
22
|
+
* carries a locale dimension, narrow it to `locales`; otherwise multiply each
|
|
23
|
+
* cell by the locales (CLI/spec opting the axis in). No-op when `locales` empty.
|
|
24
|
+
*/
|
|
25
|
+
export function applyLocaleAxis(matrix, locales) {
|
|
26
|
+
if (!locales || !locales.length)
|
|
27
|
+
return matrix;
|
|
28
|
+
const set = new Set(locales);
|
|
29
|
+
if (matrix.some((c) => c.locale != null)) {
|
|
30
|
+
return matrix.filter((c) => c.locale != null && set.has(c.locale));
|
|
31
|
+
}
|
|
32
|
+
return matrix.flatMap((c) => locales.map((locale) => ({ ...c, locale })));
|
|
33
|
+
}
|
|
8
34
|
/**
|
|
9
35
|
* Build the capture matrix from a spec's declared `fidelity.modes` (pure).
|
|
10
|
-
* Tokens are dimension VALUES (`light`/`dark`/`mobile`/`desktop
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
36
|
+
* Tokens are dimension VALUES (`light`/`dark`/`mobile`/`desktop`, plus
|
|
37
|
+
* `locale:<code>` for the §6 locale axis), expanded to the product: a dimension
|
|
38
|
+
* with no declared value defaults to its full set (so `[dark]` → dark ×
|
|
39
|
+
* {mobile,desktop}; `[mobile]` → {light,dark} × mobile). Locale is OPTIONAL — no
|
|
40
|
+
* `locale:` token means no locale dimension. Unrecognised tokens are ignored; if
|
|
41
|
+
* NONE are recognised, the full default matrix is returned (fail-open — a typo
|
|
42
|
+
* never silently checks nothing).
|
|
15
43
|
*/
|
|
16
44
|
export function matrixFromModes(modes) {
|
|
17
45
|
const wanted = new Set(modes.map((m) => String(m).toLowerCase().trim()));
|
|
18
46
|
const viewports = Object.keys(VIEWPORTS).filter((v) => wanted.has(v));
|
|
19
47
|
const schemes = SCHEMES.filter((s) => wanted.has(s));
|
|
20
|
-
|
|
48
|
+
const locales = localesFromModes(modes);
|
|
49
|
+
if (!viewports.length && !schemes.length && !locales.length)
|
|
21
50
|
return DEFAULT_MATRIX;
|
|
22
51
|
const vps = viewports.length ? viewports : Object.keys(VIEWPORTS);
|
|
23
52
|
const schs = schemes.length ? schemes : SCHEMES;
|
|
24
|
-
|
|
53
|
+
const base = vps.flatMap((viewport) => schs.map((scheme) => ({ viewport, scheme, ...VIEWPORTS[viewport] })));
|
|
54
|
+
return applyLocaleAxis(base, locales);
|
|
25
55
|
}
|
|
26
|
-
/** Narrow a matrix by explicit --viewport / --scheme flags (pure). Validates. */
|
|
56
|
+
/** Narrow a matrix by explicit --viewport / --scheme / --locale flags (pure). Validates. */
|
|
27
57
|
export function narrowMatrix(base, opts) {
|
|
28
58
|
let m = base;
|
|
29
59
|
if (opts.viewport) {
|
|
@@ -37,6 +67,11 @@ export function narrowMatrix(base, opts) {
|
|
|
37
67
|
throw new Error("eye: --scheme must be light|dark");
|
|
38
68
|
m = m.filter((c) => c.scheme === opts.scheme);
|
|
39
69
|
}
|
|
70
|
+
// Locale flags can only NARROW a spec-declared locale axis here; when the base
|
|
71
|
+
// has no locale dimension, applyLocaleAxis (in parseEyeArgs/index) opts it in.
|
|
72
|
+
if (opts.locales && opts.locales.length && m.some((c) => c.locale != null)) {
|
|
73
|
+
m = applyLocaleAxis(m, opts.locales);
|
|
74
|
+
}
|
|
40
75
|
return m;
|
|
41
76
|
}
|
|
42
77
|
function val(args, flag) {
|
|
@@ -47,6 +82,7 @@ function val(args, flag) {
|
|
|
47
82
|
* Parse `slowcook eye` flags. Required: --reference <url>, --candidate <url>.
|
|
48
83
|
* Optional: --story <id> (derive the matrix from the spec's fidelity.modes),
|
|
49
84
|
* --cwd <dir>, --out <dir>, --viewport <name> + --scheme <light|dark> (narrow),
|
|
85
|
+
* --locale <fa,en> (§6 locale axis), --scenario <name> (§4 shared fixture),
|
|
50
86
|
* --max-violations <n>, --fail-on <a,b>. The returned `matrix` is the flag-only
|
|
51
87
|
* default; when `story` is set the runner rebuilds it from the spec.
|
|
52
88
|
*/
|
|
@@ -58,7 +94,12 @@ export function parseEyeArgs(args) {
|
|
|
58
94
|
}
|
|
59
95
|
const viewport = val(args, "--viewport");
|
|
60
96
|
const scheme = val(args, "--scheme");
|
|
61
|
-
const
|
|
97
|
+
const localeArg = val(args, "--locale");
|
|
98
|
+
const locales = localeArg
|
|
99
|
+
? localeArg.split(",").map((s) => s.trim()).filter(Boolean)
|
|
100
|
+
: undefined;
|
|
101
|
+
// CLI default matrix has no locale dimension → applyLocaleAxis multiplies it in.
|
|
102
|
+
const matrix = applyLocaleAxis(narrowMatrix(DEFAULT_MATRIX, { viewport, scheme }), locales);
|
|
62
103
|
const maxV = val(args, "--max-violations");
|
|
63
104
|
const failOn = val(args, "--fail-on");
|
|
64
105
|
const gate = {};
|
|
@@ -78,6 +119,8 @@ export function parseEyeArgs(args) {
|
|
|
78
119
|
cwd: val(args, "--cwd") ?? ".",
|
|
79
120
|
viewport,
|
|
80
121
|
scheme,
|
|
122
|
+
locales,
|
|
123
|
+
scenario: val(args, "--scenario"),
|
|
81
124
|
watch: args.includes("--watch"),
|
|
82
125
|
intervalMs: interval !== undefined ? Number.parseInt(interval, 10) : 2000,
|
|
83
126
|
untilConverged: args.includes("--until-converged"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/commands/eye/plan.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/commands/eye/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,12 +4,28 @@ export interface RunEyeOptions {
|
|
|
4
4
|
referenceUrl: string;
|
|
5
5
|
candidateUrl: string;
|
|
6
6
|
matrix: EyeContext[];
|
|
7
|
-
/** Directory for screenshots. Files named `<label>-<viewport>-<scheme
|
|
7
|
+
/** Directory for screenshots. Files named `<label>-<viewport>-<scheme>[-<locale>].png`. */
|
|
8
8
|
outDir: string;
|
|
9
9
|
gate?: FidelityGateOptions;
|
|
10
10
|
/** Screenshot filename prefix (e.g. `eye-pr-123`); default none. */
|
|
11
11
|
shotPrefix?: string;
|
|
12
|
+
/**
|
|
13
|
+
* design §4 — shared-fixture scenario, appended as `?scenario=<name>` to BOTH
|
|
14
|
+
* sides so the mock's mock-data layer + the candidate's dev-only data adaptor
|
|
15
|
+
* render the SAME data → only real UI drift, no data noise.
|
|
16
|
+
*/
|
|
17
|
+
scenario?: string;
|
|
12
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Pure: build the per-cell URL by merging the §6 locale (`lang=`) and §4
|
|
21
|
+
* scenario (`scenario=`) query params into `url`, preserving any params already
|
|
22
|
+
* present (e.g. `?__preview=1`). Applied identically to reference + candidate so
|
|
23
|
+
* both render the same locale/fixture. Returns `url` unchanged when neither
|
|
24
|
+
* applies and the URL has no params to normalise.
|
|
25
|
+
*/
|
|
26
|
+
export declare function withEyeParams(url: string, ctx: EyeContext, scenario?: string): string;
|
|
27
|
+
/** Pure: screenshot/label suffix for a cell — locale appended only when present. */
|
|
28
|
+
export declare function cellLabel(ctx: EyeContext): string;
|
|
13
29
|
export interface RunEyeResult {
|
|
14
30
|
result: FidelityGateResult;
|
|
15
31
|
screenshots: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/eye/run.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAExB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/eye/run.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAExB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,2FAA2F;IAC3F,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAgBrF;AAED,oFAAoF;AACpF,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAEjD;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,sFAAsF;AACtF,wBAAsB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAmC7E;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAIzG;AAED,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAqDhF"}
|
package/dist/commands/eye/run.js
CHANGED
|
@@ -9,6 +9,38 @@ import { mkdirSync } from "node:fs";
|
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { chromium } from "@playwright/test";
|
|
11
11
|
import { captureSnapshot, gradeFidelity, } from "@slowcook-ai/gates";
|
|
12
|
+
/**
|
|
13
|
+
* Pure: build the per-cell URL by merging the §6 locale (`lang=`) and §4
|
|
14
|
+
* scenario (`scenario=`) query params into `url`, preserving any params already
|
|
15
|
+
* present (e.g. `?__preview=1`). Applied identically to reference + candidate so
|
|
16
|
+
* both render the same locale/fixture. Returns `url` unchanged when neither
|
|
17
|
+
* applies and the URL has no params to normalise.
|
|
18
|
+
*/
|
|
19
|
+
export function withEyeParams(url, ctx, scenario) {
|
|
20
|
+
if (!ctx.locale && !scenario)
|
|
21
|
+
return url;
|
|
22
|
+
try {
|
|
23
|
+
const u = new URL(url);
|
|
24
|
+
if (ctx.locale)
|
|
25
|
+
u.searchParams.set("lang", ctx.locale);
|
|
26
|
+
if (scenario)
|
|
27
|
+
u.searchParams.set("scenario", scenario);
|
|
28
|
+
return u.toString();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Relative/opaque URL — fall back to naive append (keeps existing query).
|
|
32
|
+
const sep = url.includes("?") ? "&" : "?";
|
|
33
|
+
const extra = [
|
|
34
|
+
ctx.locale ? `lang=${encodeURIComponent(ctx.locale)}` : "",
|
|
35
|
+
scenario ? `scenario=${encodeURIComponent(scenario)}` : "",
|
|
36
|
+
].filter(Boolean).join("&");
|
|
37
|
+
return extra ? `${url}${sep}${extra}` : url;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Pure: screenshot/label suffix for a cell — locale appended only when present. */
|
|
41
|
+
export function cellLabel(ctx) {
|
|
42
|
+
return `${ctx.viewport}-${ctx.scheme}${ctx.locale ? `-${ctx.locale}` : ""}`;
|
|
43
|
+
}
|
|
12
44
|
/** Render + grade the full matrix. Launches one browser, a fresh context per cell. */
|
|
13
45
|
export async function runEyeMatrix(opts) {
|
|
14
46
|
mkdirSync(opts.outDir, { recursive: true });
|
|
@@ -22,12 +54,12 @@ export async function runEyeMatrix(opts) {
|
|
|
22
54
|
deviceScaleFactor: 2,
|
|
23
55
|
});
|
|
24
56
|
const page = await c.newPage();
|
|
25
|
-
await page.goto(url, { waitUntil: "networkidle" });
|
|
57
|
+
await page.goto(withEyeParams(url, ctx, opts.scenario), { waitUntil: "networkidle" });
|
|
26
58
|
await page.waitForTimeout(400); // let lazy / client styles settle
|
|
27
|
-
const shot = join(opts.outDir, `${prefix}${label}-${ctx
|
|
59
|
+
const shot = join(opts.outDir, `${prefix}${label}-${cellLabel(ctx)}.png`);
|
|
28
60
|
await page.screenshot({ path: shot, fullPage: true });
|
|
29
61
|
screenshots.push(shot);
|
|
30
|
-
const snap = await captureSnapshot(page, { viewport: ctx.viewport, scheme: ctx.scheme });
|
|
62
|
+
const snap = await captureSnapshot(page, { viewport: ctx.viewport, scheme: ctx.scheme, locale: ctx.locale });
|
|
31
63
|
await c.close();
|
|
32
64
|
return snap;
|
|
33
65
|
};
|
|
@@ -71,13 +103,13 @@ export async function runEyeWatch(opts) {
|
|
|
71
103
|
deviceScaleFactor: 2,
|
|
72
104
|
});
|
|
73
105
|
const p = await c.newPage();
|
|
74
|
-
await p.goto(url, { waitUntil: "networkidle" });
|
|
106
|
+
await p.goto(withEyeParams(url, ctx, opts.scenario), { waitUntil: "networkidle" });
|
|
75
107
|
await p.waitForTimeout(400);
|
|
76
108
|
return { c, p };
|
|
77
109
|
};
|
|
78
110
|
for (const ctx of opts.matrix) {
|
|
79
111
|
const ref = await newCell(opts.referenceUrl, ctx);
|
|
80
|
-
const reference = await captureSnapshot(ref.p, { viewport: ctx.viewport, scheme: ctx.scheme });
|
|
112
|
+
const reference = await captureSnapshot(ref.p, { viewport: ctx.viewport, scheme: ctx.scheme, locale: ctx.locale });
|
|
81
113
|
await ref.c.close(); // reference is static — capture once, release it
|
|
82
114
|
const cand = await newCell(opts.candidateUrl, ctx);
|
|
83
115
|
cells.push({ ctx, reference, page: cand.p, close: () => cand.c.close() });
|
|
@@ -91,7 +123,7 @@ export async function runEyeWatch(opts) {
|
|
|
91
123
|
for (const cell of cells) {
|
|
92
124
|
await cell.page.reload({ waitUntil: "networkidle" });
|
|
93
125
|
await cell.page.waitForTimeout(300);
|
|
94
|
-
const candidate = await captureSnapshot(cell.page, { viewport: cell.ctx.viewport, scheme: cell.ctx.scheme });
|
|
126
|
+
const candidate = await captureSnapshot(cell.page, { viewport: cell.ctx.viewport, scheme: cell.ctx.scheme, locale: cell.ctx.locale });
|
|
95
127
|
pairs.push({ reference: cell.reference, candidate });
|
|
96
128
|
}
|
|
97
129
|
result = gradeFidelity(pairs, opts.gate);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/commands/eye/run.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAa,MAAM,kBAAkB,CAAC;AACvD,OAAO,EACL,eAAe,EACf,aAAa,GAId,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/commands/eye/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/greenfield/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/greenfield/index.ts"],"names":[],"mappings":"AA4CA,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuEnF"}
|
|
@@ -13,8 +13,16 @@ import { join, relative, resolve } from "node:path";
|
|
|
13
13
|
import { listActiveSpecs } from "../refine/spec-yaml.js";
|
|
14
14
|
import { loadMockShapeConfig } from "../../lib/mock-shape.js";
|
|
15
15
|
import { parsePrdInitiatives } from "../menu/prd.js";
|
|
16
|
-
import { checkTrace, parseLcrProvenance } from "../trace/check.js";
|
|
16
|
+
import { checkTrace, parseLcrProvenance, routeSatisfies } from "../trace/check.js";
|
|
17
17
|
import { computeGreenfieldStatus } from "./status.js";
|
|
18
|
+
import { compileLcrPlan } from "../vibe/lcr-plan.js";
|
|
19
|
+
/** Concrete route paths declared in a react-router file (path="..."). */
|
|
20
|
+
function readRouterPaths(file) {
|
|
21
|
+
if (!existsSync(file))
|
|
22
|
+
return [];
|
|
23
|
+
const src = readFileSync(file, "utf8");
|
|
24
|
+
return [...src.matchAll(/path\s*=\s*["'`]([^"'`]+)["'`]/g)].map((m) => m[1]).filter((p) => p && p !== "*");
|
|
25
|
+
}
|
|
18
26
|
function val(args, flag) {
|
|
19
27
|
const i = args.indexOf(flag);
|
|
20
28
|
return i >= 0 ? args[i + 1] : undefined;
|
|
@@ -54,7 +62,6 @@ export async function greenfield(argv, _cliVersion) {
|
|
|
54
62
|
file: relative(cwd, f).replace(/\\/g, "/"),
|
|
55
63
|
provenance: parseLcrProvenance(readFileSync(f, "utf8")),
|
|
56
64
|
}));
|
|
57
|
-
const referenced = new Set(lcrNodes.flatMap((n) => n.provenance.filter((p) => p.kind === "story").map((p) => p.id)));
|
|
58
65
|
const brandPresent = existsSync(resolve(cwd, mock.design_system_dir, "tokens.ts"));
|
|
59
66
|
const specNodes = specs.map((s) => ({ storyId: s.story_id, prdAnchor: s.prd_ref?.anchor, sourceIssue: s.source_issue }));
|
|
60
67
|
const traceViolations = checkTrace({ specs: specNodes, prdAnchors: prdInitiatives.map((i) => i.anchor), lcrNodes }).violations.length;
|
|
@@ -62,13 +69,36 @@ export async function greenfield(argv, _cliVersion) {
|
|
|
62
69
|
storyId: s.story_id,
|
|
63
70
|
anchored: Boolean(s.prd_ref?.anchor || s.source_issue),
|
|
64
71
|
addressableQuestions: s.open_questions?.addressable?.length ?? 0,
|
|
65
|
-
hasLcr: referenced.has(`story-${s.story_id}`),
|
|
66
72
|
}));
|
|
73
|
+
// Whole-app LCR facts: the plan (data model + declared surfaces) + what's built
|
|
74
|
+
// in the mock (schema / data adaptor / app router) + how many surfaces resolve.
|
|
75
|
+
const planSpecs = specs.map((s) => ({
|
|
76
|
+
storyId: s.story_id,
|
|
77
|
+
entities: (s.data_contract?.entities ?? []).map((e) => ({ name: e.name, fields: (e.fields ?? []).map((f) => ({ name: f.name, type: f.type })), relations: e.relations })),
|
|
78
|
+
actors: (s.actors ?? []).map((a) => ({ name: a.name })),
|
|
79
|
+
persona: s.persona,
|
|
80
|
+
surfaces: s.surfaces,
|
|
81
|
+
}));
|
|
82
|
+
const plan = compileLcrPlan(planSpecs);
|
|
83
|
+
const libDir = resolve(cwd, mock.mock_root, "src/lib");
|
|
84
|
+
const routerFile = mock.router_file ? resolve(cwd, mock.router_file) : resolve(cwd, mock.mock_root, "src/App.tsx");
|
|
85
|
+
const appPresent = existsSync(routerFile);
|
|
86
|
+
const routes = appPresent ? readRouterPaths(routerFile) : [];
|
|
87
|
+
const surfacesBuilt = plan.surfaces.filter((s) => routes.some((r) => routeSatisfies(r, s.route))).length;
|
|
67
88
|
const status = computeGreenfieldStatus({
|
|
68
89
|
prdInitiatives: prdInitiatives.length,
|
|
69
90
|
specs: specFacts,
|
|
70
91
|
brandPresent,
|
|
71
92
|
traceViolations,
|
|
93
|
+
lcr: {
|
|
94
|
+
surfacesDeclared: plan.surfaces.length,
|
|
95
|
+
entities: plan.entities.length,
|
|
96
|
+
conflicts: plan.conflicts.length,
|
|
97
|
+
schemaPresent: existsSync(join(libDir, "schema.ts")),
|
|
98
|
+
dataAdaptorPresent: existsSync(join(libDir, "db.ts")),
|
|
99
|
+
appPresent,
|
|
100
|
+
surfacesBuilt,
|
|
101
|
+
},
|
|
72
102
|
});
|
|
73
103
|
console.log("slowcook greenfield — scope status\n");
|
|
74
104
|
for (const st of status.stages) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/greenfield/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAA+B,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/greenfield/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
* GUCDI — `greenfield status` core (pure). Computes where a greenfield project
|
|
3
3
|
* is in the PRD → stories → brand → LCR → trace pipeline, and the next action.
|
|
4
4
|
* It is also the **scope-completeness signal**: a scope is "complete" when every
|
|
5
|
-
* addressable question is answered, the trace is green,
|
|
6
|
-
*
|
|
5
|
+
* addressable question is answered, the trace is green, the whole-app LCR is
|
|
6
|
+
* built, and the brand is set — only then does the backend phase begin.
|
|
7
|
+
*
|
|
8
|
+
* The LCR is a WHOLE-APP mock (not per-story): one clickable app over a shared
|
|
9
|
+
* SQLite data adaptor. So LCR progress is staged — data model → schema → data
|
|
10
|
+
* adaptor → app shell → surfaces — and coverage is "declared surfaces reachable
|
|
11
|
+
* in the app", not "stories with an @story marker".
|
|
7
12
|
*
|
|
8
13
|
* Pure + unit-tested; the IO (reading PRD/specs/brand/LCR) is in ./index.ts.
|
|
9
|
-
* See docs/plans/
|
|
14
|
+
* See docs/plans/vibe-whole-mock-lcr.md.
|
|
10
15
|
*/
|
|
11
16
|
export interface GreenfieldSpecFact {
|
|
12
17
|
storyId: string;
|
|
@@ -14,14 +19,30 @@ export interface GreenfieldSpecFact {
|
|
|
14
19
|
anchored: boolean;
|
|
15
20
|
/** Count of unresolved *addressable* open questions (block scope-complete). */
|
|
16
21
|
addressableQuestions: number;
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
}
|
|
23
|
+
/** Whole-app LCR build facts (from the plan + the mock filesystem). */
|
|
24
|
+
export interface GreenfieldLcr {
|
|
25
|
+
/** Total UI surfaces (routes) declared across specs. 0 = no UI declared. */
|
|
26
|
+
surfacesDeclared: number;
|
|
27
|
+
/** Plan entities (the unified data model). */
|
|
28
|
+
entities: number;
|
|
29
|
+
/** Cross-story data-model conflicts (block schema-gen). */
|
|
30
|
+
conflicts: number;
|
|
31
|
+
/** The LCR Drizzle schema exists (`vibe schema`). */
|
|
32
|
+
schemaPresent: boolean;
|
|
33
|
+
/** The SQLite data adaptor exists (`vibe seed` → db.ts + seed + queries). */
|
|
34
|
+
dataAdaptorPresent: boolean;
|
|
35
|
+
/** The clickable app exists (`vibe app` → router/shell). */
|
|
36
|
+
appPresent: boolean;
|
|
37
|
+
/** Declared surfaces whose route resolves to a real route in the app router. */
|
|
38
|
+
surfacesBuilt: number;
|
|
19
39
|
}
|
|
20
40
|
export interface GreenfieldInput {
|
|
21
41
|
prdInitiatives: number;
|
|
22
42
|
specs: GreenfieldSpecFact[];
|
|
23
43
|
brandPresent: boolean;
|
|
24
44
|
traceViolations: number;
|
|
45
|
+
lcr: GreenfieldLcr;
|
|
25
46
|
}
|
|
26
47
|
export interface GreenfieldStage {
|
|
27
48
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/greenfield/status.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/greenfield/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,QAAQ,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,aAAa,EAAE,OAAO,CAAC;IACvB,6EAA6E;IAC7E,kBAAkB,EAAE,OAAO,CAAC;IAC5B,4DAA4D;IAC5D,UAAU,EAAE,OAAO,CAAC;IACpB,gFAAgF;IAChF,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,EAAE,aAAa,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,gBAAgB,CA+ChF"}
|