@slowcook-ai/cli 0.21.1 → 0.22.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 +5 -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/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/reconcile/index.d.ts +2 -0
- package/dist/commands/reconcile/index.d.ts.map +1 -0
- package/dist/commands/reconcile/index.js +171 -0
- package/dist/commands/reconcile/index.js.map +1 -0
- package/dist/commands/refine/spec-yaml.d.ts +26 -0
- package/dist/commands/refine/spec-yaml.d.ts.map +1 -1
- package/dist/commands/refine/spec-yaml.js +64 -3
- package/dist/commands/refine/spec-yaml.js.map +1 -1
- package/dist/commands/trace/check.d.ts +116 -0
- package/dist/commands/trace/check.d.ts.map +1 -1
- package/dist/commands/trace/check.js +135 -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 +273 -12
- 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 +8 -8
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"}
|
|
@@ -2,28 +2,36 @@
|
|
|
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 function computeGreenfieldStatus(input) {
|
|
12
|
-
const { prdInitiatives, specs, brandPresent, traceViolations } = input;
|
|
17
|
+
const { prdInitiatives, specs, brandPresent, traceViolations, lcr } = input;
|
|
13
18
|
const anchored = specs.filter((s) => s.anchored).length;
|
|
14
|
-
const vibed = specs.filter((s) => s.hasLcr).length;
|
|
15
19
|
const addressable = specs.reduce((n, s) => n + s.addressableQuestions, 0);
|
|
16
20
|
const prdDone = prdInitiatives > 0;
|
|
17
21
|
const storiesDone = specs.length > 0 && anchored === specs.length;
|
|
18
22
|
const brandDone = brandPresent;
|
|
19
|
-
|
|
23
|
+
// The LCR is done when the app exists and every declared surface is reachable.
|
|
24
|
+
const lcrDone = lcr.surfacesDeclared > 0 && lcr.appPresent && lcr.surfacesBuilt === lcr.surfacesDeclared;
|
|
20
25
|
const traceDone = traceViolations === 0;
|
|
21
26
|
const questionsDone = addressable === 0;
|
|
27
|
+
const lcrDetail = lcr.surfacesDeclared === 0
|
|
28
|
+
? "no UI surfaces declared"
|
|
29
|
+
: `${lcr.entities} entities · schema ${lcr.schemaPresent ? "✓" : "✗"} · adaptor ${lcr.dataAdaptorPresent ? "✓" : "✗"} · app ${lcr.appPresent ? "✓" : "✗"} · ${lcr.surfacesBuilt}/${lcr.surfacesDeclared} surfaces`;
|
|
22
30
|
const stages = [
|
|
23
31
|
{ name: "PRD", done: prdDone, detail: `${prdInitiatives} initiative(s)` },
|
|
24
32
|
{ name: "Stories (menu)", done: storiesDone, detail: `${specs.length} stories, ${anchored} anchored` },
|
|
25
33
|
{ name: "Brand", done: brandDone, detail: brandPresent ? "design system present" : "no design system" },
|
|
26
|
-
{ name: "LCR (
|
|
34
|
+
{ name: "LCR (whole-app)", done: lcrDone, detail: lcrDetail },
|
|
27
35
|
{ name: "Trace", done: traceDone, detail: traceViolations === 0 ? "provenance complete" : `${traceViolations} violation(s)` },
|
|
28
36
|
{ name: "Open questions", done: questionsDone, detail: `${addressable} addressable unresolved` },
|
|
29
37
|
];
|
|
@@ -38,8 +46,19 @@ export function computeGreenfieldStatus(input) {
|
|
|
38
46
|
else if (!brandDone)
|
|
39
47
|
nextAction = "Run `slowcook brand` to turn the brand brief into the design system.";
|
|
40
48
|
else if (!lcrDone) {
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
// The whole-app LCR ladder: data model → schema → adaptor → app → surfaces.
|
|
50
|
+
if (lcr.surfacesDeclared === 0)
|
|
51
|
+
nextAction = "Stories declare no UI surfaces — re-run `slowcook menu` so it emits persona + surfaces.";
|
|
52
|
+
else if (lcr.conflicts > 0)
|
|
53
|
+
nextAction = `Resolve ${lcr.conflicts} data-model conflict(s) across specs (see \`slowcook vibe plan\`).`;
|
|
54
|
+
else if (!lcr.schemaPresent)
|
|
55
|
+
nextAction = "Run `slowcook vibe schema` to generate the LCR data adaptor's Drizzle schema.";
|
|
56
|
+
else if (!lcr.dataAdaptorPresent)
|
|
57
|
+
nextAction = "Run `slowcook vibe seed` to build the SQLite data adaptor (seed + queries).";
|
|
58
|
+
else if (!lcr.appPresent)
|
|
59
|
+
nextAction = "Run `slowcook vibe app` to scaffold the clickable LCR (router + persona shell + pages).";
|
|
60
|
+
else
|
|
61
|
+
nextAction = `${lcr.surfacesBuilt}/${lcr.surfacesDeclared} surfaces built — run \`slowcook vibe surfaces\` to generate the remaining pages, then \`slowcook run-mock\` to review.`;
|
|
43
62
|
}
|
|
44
63
|
else if (!traceDone)
|
|
45
64
|
nextAction = "Resolve `trace check` violations (orphans / dangling refs).";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/greenfield/status.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/greenfield/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../../src/commands/menu/assemble.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,+EAA+E;IAC/E,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACrD;AAMD,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,eAAe,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../../src/commands/menu/assemble.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,+EAA+E;IAC/E,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACrD;AAMD,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,eAAe,GAAG,cAAc,CAmC/F"}
|
|
@@ -30,6 +30,12 @@ export function assembleStories(drafts, opts) {
|
|
|
30
30
|
spec.ui_behavior = d.ui_behavior;
|
|
31
31
|
if (d.fidelity_modes && d.fidelity_modes.length > 0)
|
|
32
32
|
spec.fidelity = { modes: d.fidelity_modes };
|
|
33
|
+
if (d.epic)
|
|
34
|
+
spec.epic = d.epic;
|
|
35
|
+
if (d.persona)
|
|
36
|
+
spec.persona = d.persona;
|
|
37
|
+
if (d.surfaces && d.surfaces.length > 0)
|
|
38
|
+
spec.surfaces = d.surfaces;
|
|
33
39
|
return spec;
|
|
34
40
|
});
|
|
35
41
|
return { specs, unanchored };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../../src/commands/menu/assemble.ts"],"names":[],"mappings":"AA6BA,SAAS,GAAG,CAAC,CAAS;IACpB,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAwB,EAAE,IAAqB;IAC7E,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,MAAM,UAAU,GAA4C,EAAE,CAAC;IAE/D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAQ,EAAE;QACtC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;YACtC,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,MAAM,IAAI,GAAS;YACjB,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;YAC/B,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,IAAI,CAAC,GAAG;YACpB,UAAU,EAAE,EAAE;YACd,aAAa,EAAE,IAAI;YACnB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,UAAU,EAAE,iBAAiB,IAAI,CAAC,UAAU,EAAE;YAC9C,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,aAAa,EAAE,EAAE;YACjB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,oBAAoB,EAAE,CAAC,CAAC,oBAAoB;YAC5C,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE;YACrD,aAAa,EAAE,CAAC,CAAC,aAAa;YAC9B,cAAc,EAAE,CAAC,CAAC,cAAc;SACjC,CAAC;QACF,IAAI,CAAC,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC;QAC7F,IAAI,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,QAAQ,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,cAAc,EAAE,CAAC;QACjG,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AAC/B,CAAC"}
|
|
1
|
+
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../../src/commands/menu/assemble.ts"],"names":[],"mappings":"AA6BA,SAAS,GAAG,CAAC,CAAS;IACpB,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAwB,EAAE,IAAqB;IAC7E,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,MAAM,UAAU,GAA4C,EAAE,CAAC;IAE/D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAQ,EAAE;QACtC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;YACtC,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,MAAM,IAAI,GAAS;YACjB,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;YAC/B,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,IAAI,CAAC,GAAG;YACpB,UAAU,EAAE,EAAE;YACd,aAAa,EAAE,IAAI;YACnB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,UAAU,EAAE,iBAAiB,IAAI,CAAC,UAAU,EAAE;YAC9C,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,aAAa,EAAE,EAAE;YACjB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,oBAAoB,EAAE,CAAC,CAAC,oBAAoB;YAC5C,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE;YACrD,aAAa,EAAE,CAAC,CAAC,aAAa;YAC9B,cAAc,EAAE,CAAC,CAAC,cAAc;SACjC,CAAC;QACF,IAAI,CAAC,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC;QAC7F,IAAI,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,QAAQ,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,cAAc,EAAE,CAAC;QACjG,IAAI,CAAC,CAAC,IAAI;YAAE,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;QAC/B,IAAI,CAAC,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;QACxC,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;QACpE,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AAC/B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/menu/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAY/F,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/menu/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAY/F,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAY7D;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuG5E"}
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
*
|
|
9
9
|
* slowcook menu [--prd docs/PRD.md] [--cwd .] [--model <id>] [--dry-run]
|
|
10
10
|
*/
|
|
11
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
11
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
12
12
|
import { relative, resolve } from "node:path";
|
|
13
13
|
import { AnthropicClient, MENU_SYSTEM } from "@slowcook-ai/llm-anthropic";
|
|
14
14
|
import { parsePrdInitiatives } from "./prd.js";
|
|
15
15
|
import { assembleStories } from "./assemble.js";
|
|
16
|
-
import { writeSpec, nextStoryId } from "../refine/spec-yaml.js";
|
|
16
|
+
import { writeSpec, nextStoryId, normalizeScenarioArrays } from "../refine/spec-yaml.js";
|
|
17
17
|
const DEFAULT_MODEL = "claude-sonnet-4-6";
|
|
18
18
|
function val(args, flag) {
|
|
19
19
|
const i = args.indexOf(flag);
|
|
@@ -28,7 +28,9 @@ export function extractStories(text) {
|
|
|
28
28
|
if (start < 0 || end <= start)
|
|
29
29
|
throw new Error("no JSON object found");
|
|
30
30
|
const parsed = JSON.parse(body.slice(start, end + 1));
|
|
31
|
-
|
|
31
|
+
// Normalise each story the same way refine does (e.g. {given,when,then} →
|
|
32
|
+
// string), so menu's specs conform to the Spec schema like refine's do.
|
|
33
|
+
return (parsed.stories ?? []).map((s) => normalizeScenarioArrays(s));
|
|
32
34
|
}
|
|
33
35
|
export async function menu(argv, cliVersion) {
|
|
34
36
|
if (argv[0] === "--help" || argv[0] === "-h") {
|
|
@@ -60,19 +62,45 @@ export async function menu(argv, cliVersion) {
|
|
|
60
62
|
const llm = new AnthropicClient(anthropicKey);
|
|
61
63
|
const userMsg = `PRD initiative anchors (cite exactly one per story as prd_anchor): ${initiatives.map((i) => i.anchor).join(", ")}\n\n` +
|
|
62
64
|
`--- PRD ---\n${prdText}`;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
model,
|
|
67
|
-
maxTokens: 16384,
|
|
68
|
-
cacheSystem: true,
|
|
69
|
-
});
|
|
65
|
+
// Retry on parse failure: the agent's large JSON is occasionally malformed
|
|
66
|
+
// (non-deterministic) — a fresh attempt usually succeeds. Stream so big
|
|
67
|
+
// outputs aren't truncated.
|
|
70
68
|
let drafts;
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
let lastErr;
|
|
70
|
+
let lastText = "";
|
|
71
|
+
const ATTEMPTS = 3;
|
|
72
|
+
for (let attempt = 1; attempt <= ATTEMPTS && !drafts; attempt++) {
|
|
73
|
+
const resp = await llm.complete({
|
|
74
|
+
system: MENU_SYSTEM,
|
|
75
|
+
messages: [{ role: "user", content: userMsg }],
|
|
76
|
+
model,
|
|
77
|
+
maxTokens: 64000,
|
|
78
|
+
cacheSystem: true,
|
|
79
|
+
stream: true,
|
|
80
|
+
});
|
|
81
|
+
lastText = resp.text;
|
|
82
|
+
try {
|
|
83
|
+
drafts = extractStories(resp.text);
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
lastErr = e;
|
|
87
|
+
if (attempt < ATTEMPTS) {
|
|
88
|
+
console.warn(`menu: attempt ${attempt}/${ATTEMPTS} — JSON parse failed (${e instanceof Error ? e.message : e}); retrying...`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
73
91
|
}
|
|
74
|
-
|
|
75
|
-
|
|
92
|
+
if (!drafts) {
|
|
93
|
+
// Dump the raw output so the failure is debuggable, not a silent mystery.
|
|
94
|
+
let dumpPath = "";
|
|
95
|
+
try {
|
|
96
|
+
mkdirSync(resolve(cwd, ".brewing"), { recursive: true });
|
|
97
|
+
dumpPath = resolve(cwd, ".brewing", "menu-raw.txt");
|
|
98
|
+
writeFileSync(dumpPath, lastText, "utf8");
|
|
99
|
+
}
|
|
100
|
+
catch { /* best-effort */ }
|
|
101
|
+
console.error(`menu: could not parse agent output as JSON after ${ATTEMPTS} attempts — ${String(lastErr instanceof Error ? lastErr.message : lastErr)}`);
|
|
102
|
+
if (dumpPath)
|
|
103
|
+
console.error(`menu: raw agent output written to ${relative(cwd, dumpPath)} (${lastText.length} chars)`);
|
|
76
104
|
process.exit(70);
|
|
77
105
|
}
|
|
78
106
|
if (drafts.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/menu/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/menu/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/reconcile/index.ts"],"names":[],"mappings":"AAuDA,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyIlF"}
|