@slowcook-ai/cli 0.15.0-alpha.4 → 0.16.0-alpha.10

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.
Files changed (59) hide show
  1. package/README.md +10 -0
  2. package/dist/cli.js +18 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/brew/agent.d.ts.map +1 -1
  5. package/dist/commands/brew/agent.js +26 -3
  6. package/dist/commands/brew/agent.js.map +1 -1
  7. package/dist/commands/init/index.d.ts.map +1 -1
  8. package/dist/commands/init/index.js +7 -0
  9. package/dist/commands/init/index.js.map +1 -1
  10. package/dist/commands/init/mock.d.ts +35 -0
  11. package/dist/commands/init/mock.d.ts.map +1 -0
  12. package/dist/commands/init/mock.js +500 -0
  13. package/dist/commands/init/mock.js.map +1 -0
  14. package/dist/commands/plate/classify.d.ts +65 -0
  15. package/dist/commands/plate/classify.d.ts.map +1 -0
  16. package/dist/commands/plate/classify.js +194 -0
  17. package/dist/commands/plate/classify.js.map +1 -0
  18. package/dist/commands/plate/index.d.ts.map +1 -1
  19. package/dist/commands/plate/index.js +121 -17
  20. package/dist/commands/plate/index.js.map +1 -1
  21. package/dist/commands/port/index.d.ts +21 -0
  22. package/dist/commands/port/index.d.ts.map +1 -0
  23. package/dist/commands/port/index.js +203 -0
  24. package/dist/commands/port/index.js.map +1 -0
  25. package/dist/commands/port/transform.d.ts +51 -0
  26. package/dist/commands/port/transform.d.ts.map +1 -0
  27. package/dist/commands/port/transform.js +102 -0
  28. package/dist/commands/port/transform.js.map +1 -0
  29. package/dist/commands/preview/config.d.ts +73 -0
  30. package/dist/commands/preview/config.d.ts.map +1 -0
  31. package/dist/commands/preview/config.js +200 -0
  32. package/dist/commands/preview/config.js.map +1 -0
  33. package/dist/commands/preview/deploy.d.ts +35 -0
  34. package/dist/commands/preview/deploy.d.ts.map +1 -0
  35. package/dist/commands/preview/deploy.js +247 -0
  36. package/dist/commands/preview/deploy.js.map +1 -0
  37. package/dist/commands/preview/index.d.ts +9 -0
  38. package/dist/commands/preview/index.d.ts.map +1 -0
  39. package/dist/commands/preview/index.js +67 -0
  40. package/dist/commands/preview/index.js.map +1 -0
  41. package/dist/commands/preview/ssh.d.ts +49 -0
  42. package/dist/commands/preview/ssh.d.ts.map +1 -0
  43. package/dist/commands/preview/ssh.js +99 -0
  44. package/dist/commands/preview/ssh.js.map +1 -0
  45. package/dist/commands/preview/teardown.d.ts +25 -0
  46. package/dist/commands/preview/teardown.d.ts.map +1 -0
  47. package/dist/commands/preview/teardown.js +164 -0
  48. package/dist/commands/preview/teardown.js.map +1 -0
  49. package/dist/commands/refine/proposals-synth.js +17 -1
  50. package/dist/commands/refine/proposals-synth.js.map +1 -1
  51. package/dist/commands/refine/spec-yaml.d.ts +100 -100
  52. package/dist/commands/vibe/emit.d.ts +6 -0
  53. package/dist/commands/vibe/emit.d.ts.map +1 -1
  54. package/dist/commands/vibe/emit.js +12 -0
  55. package/dist/commands/vibe/emit.js.map +1 -1
  56. package/dist/commands/vibe/index.d.ts.map +1 -1
  57. package/dist/commands/vibe/index.js +143 -44
  58. package/dist/commands/vibe/index.js.map +1 -1
  59. package/package.json +6 -5
@@ -0,0 +1,500 @@
1
+ /**
2
+ * `slowcook init mock` — scaffold the consumer's mock/ directory.
3
+ *
4
+ * Writes the consumer-side shell of the singular mock app: package.json
5
+ * (depending on @slowcook-ai/mock-runtime + next + react), Dockerfile,
6
+ * tsconfig, next.config.js, postcss.config.mjs, layout.tsx, page.tsx,
7
+ * scenario-registry.ts, globals.css (copied from src/app/globals.css if
8
+ * present), .gitignore, README.md.
9
+ *
10
+ * Refuses to overwrite existing files unless --force.
11
+ *
12
+ * After running this once, the consumer commits + pushes; vibe runs
13
+ * after (slowcook 0.16-α.3+) populate `mock/scenarios/` + extend
14
+ * `mock/src/lib/scenario-registry.ts`.
15
+ */
16
+ import { writeFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
17
+ import { dirname, join, relative } from "node:path";
18
+ export function parseMockInitArgs(argv, runtimeVersion) {
19
+ const args = {
20
+ cwd: process.cwd(),
21
+ force: false,
22
+ dryRun: false,
23
+ runtimeVersion,
24
+ };
25
+ for (let i = 0; i < argv.length; i++) {
26
+ const a = argv[i];
27
+ const next = argv[i + 1];
28
+ if (a === "--cwd" && next) {
29
+ args.cwd = next;
30
+ i++;
31
+ }
32
+ else if (a === "--force") {
33
+ args.force = true;
34
+ }
35
+ else if (a === "--dry-run") {
36
+ args.dryRun = true;
37
+ }
38
+ else if (a === "--runtime-version" && next) {
39
+ args.runtimeVersion = next;
40
+ i++;
41
+ }
42
+ else if (a === "--help" || a === "-h") {
43
+ printHelp();
44
+ process.exit(0);
45
+ }
46
+ }
47
+ return args;
48
+ }
49
+ function printHelp() {
50
+ console.log(`
51
+ slowcook init mock — scaffold the consumer's mock/ directory
52
+
53
+ Writes the consumer-side shell of the singular UI mock app.
54
+ Imports its runtime (Scenario types, hooks, ScenarioPicker,
55
+ ScenarioRegistryProvider) from @slowcook-ai/mock-runtime so updates
56
+ ship via npm bump rather than a re-init.
57
+
58
+ Usage:
59
+ slowcook init mock [--cwd <path>] [--force] [--dry-run]
60
+
61
+ Options:
62
+ --cwd <path> Repo root (default: cwd).
63
+ --force Overwrite existing files.
64
+ --dry-run Print planned actions without writing.
65
+ --runtime-version <v> Pin of @slowcook-ai/mock-runtime (default: matches cli version).
66
+
67
+ What it writes:
68
+ mock/package.json depends on @slowcook-ai/mock-runtime + next + react
69
+ mock/Dockerfile multi-stage; runs on port 3100
70
+ mock/tsconfig.json path aliases @/* → src/*; @/mock/* → lib/mock-runtime/*
71
+ mock/next.config.js turbopack root pinned to mock/ (avoids parent-src auto-discovery)
72
+ mock/postcss.config.mjs @tailwindcss/postcss plugin
73
+ mock/.gitignore node_modules, .next, .turbo, .env*.local
74
+ mock/README.md what the mock is + scenario authoring guide
75
+ mock/src/app/layout.tsx root layout; ScenarioRegistryProvider wraps children
76
+ mock/src/app/page.tsx renders <ScenarioPicker /> from the runtime
77
+ mock/src/app/globals.css copied from src/app/globals.css if present, else a minimal
78
+ Tailwind-v4 directives file (consumer expected to extend)
79
+ mock/src/lib/scenario-registry.ts consumer-owned; vibe extends this with scenario imports
80
+ mock/scenarios/.gitkeep empty until vibe writes story-N.ts files
81
+ `);
82
+ }
83
+ export function planMockFiles(args) {
84
+ const productionGlobals = join(args.cwd, "src/app/globals.css");
85
+ let globalsContents;
86
+ let globalsNote;
87
+ if (existsSync(productionGlobals)) {
88
+ try {
89
+ globalsContents = readFileSync(productionGlobals, "utf8");
90
+ globalsNote = `(copied from src/app/globals.css — design tokens shared with production)`;
91
+ }
92
+ catch {
93
+ globalsContents = MINIMAL_GLOBALS_CSS;
94
+ globalsNote = "(could not read src/app/globals.css; wrote minimal Tailwind directives — extend manually)";
95
+ }
96
+ }
97
+ else {
98
+ globalsContents = MINIMAL_GLOBALS_CSS;
99
+ globalsNote = "(no src/app/globals.css found; wrote minimal Tailwind directives — extend manually)";
100
+ }
101
+ return [
102
+ { path: "mock/package.json", contents: PACKAGE_JSON(args.runtimeVersion), skipIfExists: true },
103
+ { path: "mock/Dockerfile", contents: DOCKERFILE, skipIfExists: true },
104
+ { path: "mock/tsconfig.json", contents: TSCONFIG, skipIfExists: true },
105
+ { path: "mock/next.config.js", contents: NEXT_CONFIG, skipIfExists: true },
106
+ { path: "mock/postcss.config.mjs", contents: POSTCSS_CONFIG, skipIfExists: true },
107
+ { path: "mock/.gitignore", contents: GITIGNORE, skipIfExists: true },
108
+ { path: "mock/README.md", contents: README, skipIfExists: true },
109
+ { path: "mock/src/app/layout.tsx", contents: LAYOUT_TSX, skipIfExists: true },
110
+ { path: "mock/src/app/page.tsx", contents: PAGE_TSX, skipIfExists: true },
111
+ {
112
+ path: "mock/src/app/globals.css",
113
+ contents: globalsContents + `\n/* ${globalsNote} */\n`,
114
+ skipIfExists: true,
115
+ },
116
+ { path: "mock/src/lib/scenario-registry.ts", contents: SCENARIO_REGISTRY, skipIfExists: true },
117
+ { path: "mock/scenarios/.gitkeep", contents: "", skipIfExists: true },
118
+ ];
119
+ }
120
+ export async function initMock(argv, cliVersion) {
121
+ const runtimeVersion = mockRuntimeVersionFor(cliVersion);
122
+ const args = parseMockInitArgs(argv, runtimeVersion);
123
+ const files = planMockFiles(args);
124
+ console.log(`slowcook init mock · cwd: ${relative(process.cwd(), args.cwd) || "."}`);
125
+ console.log(`runtime: @slowcook-ai/mock-runtime@${args.runtimeVersion}`);
126
+ console.log();
127
+ const actions = [];
128
+ for (const f of files) {
129
+ const full = join(args.cwd, f.path);
130
+ if (existsSync(full) && !args.force) {
131
+ actions.push({ action: "SKIP", reason: "exists (pass --force to overwrite)", path: f.path });
132
+ }
133
+ else {
134
+ actions.push({ action: "WRITE", reason: "", path: f.path });
135
+ }
136
+ }
137
+ for (const a of actions) {
138
+ const tag = a.action === "WRITE" ? "WRITE" : "SKIP ";
139
+ console.log(` ${tag} ${a.path}${a.reason ? ` (${a.reason})` : ""}`);
140
+ }
141
+ console.log();
142
+ if (args.dryRun) {
143
+ console.log("--dry-run: no files written.");
144
+ return;
145
+ }
146
+ let written = 0;
147
+ let skipped = 0;
148
+ for (const f of files) {
149
+ const full = join(args.cwd, f.path);
150
+ if (existsSync(full) && !args.force) {
151
+ skipped += 1;
152
+ continue;
153
+ }
154
+ mkdirSync(dirname(full), { recursive: true });
155
+ writeFileSync(full, f.contents, "utf8");
156
+ written += 1;
157
+ }
158
+ console.log(`Done. Wrote ${written} file(s); skipped ${skipped}.`);
159
+ console.log();
160
+ console.log("Next steps:");
161
+ console.log(" 1. cd mock && npm install");
162
+ console.log(" 2. npm run dev # http://localhost:3100");
163
+ console.log(" 3. Verify the empty scenario picker renders");
164
+ console.log(" 4. Commit + push the mock/ directory");
165
+ console.log(" 5. Future vibe runs (slowcook 0.16-α.3+) populate mock/scenarios/ +");
166
+ console.log(" extend mock/src/lib/scenario-registry.ts");
167
+ }
168
+ /**
169
+ * The mock-runtime package versions track slowcook's overall release
170
+ * cadence. Until 0.16 final cuts we hardcode the latest known version
171
+ * here. After 0.16 the cli's package.json could carry a peer-pin field.
172
+ */
173
+ function mockRuntimeVersionFor(_cliVersion) {
174
+ return "^0.1.1";
175
+ }
176
+ // ---------------- templates ----------------
177
+ const PACKAGE_JSON = (runtimeVersion) => `{
178
+ "name": "${"$"}{REPO_NAME}-mock",
179
+ "version": "0.0.0",
180
+ "private": true,
181
+ "description": "Singular UI mock app. Run with \`npm run dev\` on :3100. See mock/README.md.",
182
+ "type": "module",
183
+ "scripts": {
184
+ "dev": "next dev -p 3100",
185
+ "build": "next build",
186
+ "start": "next start -p 3100",
187
+ "lint": "next lint"
188
+ },
189
+ "dependencies": {
190
+ "@slowcook-ai/mock-runtime": "${runtimeVersion}",
191
+ "next": "^16.0.0",
192
+ "react": "^19.0.0",
193
+ "react-dom": "^19.0.0"
194
+ },
195
+ "devDependencies": {
196
+ "@tailwindcss/postcss": "^4",
197
+ "@types/node": "^22",
198
+ "@types/react": "^19",
199
+ "@types/react-dom": "^19",
200
+ "tailwindcss": "^4",
201
+ "typescript": "^5"
202
+ }
203
+ }
204
+ `;
205
+ const DOCKERFILE = `# Singular UI mock — runnable on the consumer's box per scenario.
206
+ # Build (from repo root): docker build -t mock -f mock/Dockerfile .
207
+ # Run: docker run -p 3100:3100 mock
208
+ # Open: http://localhost:3100/?scenario=story-N
209
+
210
+ FROM node:20-alpine AS deps
211
+ WORKDIR /app
212
+ COPY mock/package.json mock/package-lock.json* ./
213
+ RUN if [ -f package-lock.json ]; then npm ci; else npm install; fi
214
+
215
+ FROM node:20-alpine AS builder
216
+ WORKDIR /app
217
+ COPY --from=deps /app/node_modules ./node_modules
218
+ COPY mock ./
219
+ RUN npm run build
220
+
221
+ FROM node:20-alpine AS runner
222
+ WORKDIR /app
223
+ ENV NODE_ENV=production
224
+ ENV PORT=3100
225
+ ENV HOSTNAME=0.0.0.0
226
+ COPY --from=builder /app/public ./public
227
+ COPY --from=builder /app/.next ./.next
228
+ COPY --from=builder /app/node_modules ./node_modules
229
+ COPY --from=builder /app/package.json ./package.json
230
+ EXPOSE 3100
231
+ CMD ["npm", "run", "start"]
232
+ `;
233
+ const TSCONFIG = `{
234
+ "compilerOptions": {
235
+ "target": "ES2017",
236
+ "lib": ["dom", "dom.iterable", "esnext"],
237
+ "allowJs": true,
238
+ "skipLibCheck": true,
239
+ "strict": true,
240
+ "noEmit": true,
241
+ "esModuleInterop": true,
242
+ "module": "esnext",
243
+ "moduleResolution": "bundler",
244
+ "resolveJsonModule": true,
245
+ "isolatedModules": true,
246
+ "jsx": "react-jsx",
247
+ "incremental": true,
248
+ "plugins": [{ "name": "next" }],
249
+ "baseUrl": ".",
250
+ "paths": {
251
+ "@/*": ["src/*"]
252
+ }
253
+ },
254
+ "include": ["next-env.d.ts", "src/**/*.ts", "src/**/*.tsx", "scenarios/**/*.ts", ".next/types/**/*.ts"],
255
+ "exclude": ["node_modules"]
256
+ }
257
+ `;
258
+ const NEXT_CONFIG = `import { fileURLToPath } from "node:url";
259
+ import { dirname } from "node:path";
260
+
261
+ const __dirname = dirname(fileURLToPath(import.meta.url));
262
+
263
+ /** @type {import('next').NextConfig} */
264
+ const nextConfig = {
265
+ reactStrictMode: true,
266
+ images: { unoptimized: true },
267
+ // Mock app lives inside the consumer's repo. Without an explicit
268
+ // turbopack root, Next walks up + treats the parent as the workspace
269
+ // root, which can pull the parent's src/ into the mock build. Pinning
270
+ // to this directory keeps the mock self-contained.
271
+ turbopack: { root: __dirname },
272
+ outputFileTracingRoot: __dirname,
273
+ };
274
+
275
+ export default nextConfig;
276
+ `;
277
+ const POSTCSS_CONFIG = `export default {
278
+ plugins: {
279
+ "@tailwindcss/postcss": {},
280
+ },
281
+ };
282
+ `;
283
+ const GITIGNORE = `node_modules
284
+ .next
285
+ .turbo
286
+ out
287
+ .env*.local
288
+ `;
289
+ const MINIMAL_GLOBALS_CSS = `@import "tailwindcss";
290
+
291
+ /*
292
+ * No src/app/globals.css was found at init time. This is a minimal
293
+ * Tailwind-v4 directives file. Add your project's tokens (CSS custom
294
+ * properties, @theme block) here so the mock matches production
295
+ * visually.
296
+ *
297
+ * Vibe + plate work best when this file mirrors production's tokens
298
+ * exactly — they steer toward existing token names, so the better the
299
+ * token coverage here the cleaner their output.
300
+ */
301
+
302
+ :root {
303
+ --background: #ffffff;
304
+ --foreground: #1a1a1a;
305
+ --card-bg: #ffffff;
306
+ --card-border: rgba(26, 26, 26, 0.06);
307
+ }
308
+
309
+ @media (prefers-color-scheme: dark) {
310
+ :root {
311
+ --background: #0f0f18;
312
+ --foreground: #e8e8f0;
313
+ --card-bg: rgba(255, 255, 255, 0.03);
314
+ --card-border: rgba(255, 255, 255, 0.06);
315
+ }
316
+ }
317
+
318
+ @theme inline {
319
+ --color-background: var(--background);
320
+ --color-foreground: var(--foreground);
321
+ --color-card-bg: var(--card-bg);
322
+ --color-card-border: var(--card-border);
323
+ }
324
+
325
+ body {
326
+ background: var(--background);
327
+ color: var(--foreground);
328
+ }
329
+ `;
330
+ const LAYOUT_TSX = `import type { Metadata } from "next";
331
+ import type { ReactNode } from "react";
332
+ import { ScenarioRegistryProvider } from "@slowcook-ai/mock-runtime";
333
+ import { registry } from "@/lib/scenario-registry";
334
+ import "./globals.css";
335
+
336
+ export const metadata: Metadata = {
337
+ title: "mock",
338
+ description: "Singular mock app. Each ?scenario=story-N renders the UI with that story's fixture data.",
339
+ };
340
+
341
+ export default function RootLayout({ children }: { children: ReactNode }) {
342
+ return (
343
+ <html lang="en">
344
+ <body className="bg-background text-foreground antialiased">
345
+ <ScenarioRegistryProvider registry={registry}>
346
+ {children}
347
+ {/*
348
+ Review-overlay mount-point.
349
+ npm install @slowcook-ai/review-overlay
350
+ import { SlowcookReviewOverlay } from "@slowcook-ai/review-overlay/react";
351
+ <SlowcookReviewOverlay
352
+ enabled={process.env["NEXT_PUBLIC_SLOWCOOK_REVIEW"] === "1"}
353
+ owner={process.env["NEXT_PUBLIC_SLOWCOOK_OWNER"] ?? ""}
354
+ repo={process.env["NEXT_PUBLIC_SLOWCOOK_REPO"] ?? ""}
355
+ prNumber={parseInt(process.env["NEXT_PUBLIC_SLOWCOOK_PR_NUMBER"] ?? "0", 10)}
356
+ storyId={process.env["NEXT_PUBLIC_SLOWCOOK_STORY_ID"] ?? null}
357
+ />
358
+ Slowcook's preview-deploy workflow sets the env vars from the PR
359
+ context. Production builds keep NEXT_PUBLIC_SLOWCOOK_REVIEW unset
360
+ so the overlay tree-shakes out.
361
+ */}
362
+ </ScenarioRegistryProvider>
363
+ </body>
364
+ </html>
365
+ );
366
+ }
367
+ `;
368
+ const PAGE_TSX = `import { ScenarioPicker } from "@slowcook-ai/mock-runtime";
369
+
370
+ /**
371
+ * Mock app homepage = scenario picker (provided by the runtime).
372
+ *
373
+ * Replaces this with a custom picker if you want different grouping/
374
+ * filtering. The runtime's hooks + registry API are stable; this UI
375
+ * is a default that consumers can swap.
376
+ */
377
+ export default function Page() {
378
+ return <ScenarioPicker />;
379
+ }
380
+ `;
381
+ const SCENARIO_REGISTRY = `import { defineScenarios } from "@slowcook-ai/mock-runtime";
382
+
383
+ /**
384
+ * The consumer-owned scenario registry.
385
+ *
386
+ * Vibe extends this when it adds a new scenario:
387
+ * - one new \`import\` line for the scenario file
388
+ * - one new entry in the \`defineScenarios([...])\` array
389
+ *
390
+ * Hand-edits are fine too — vibe + plate respect existing entries
391
+ * and only append.
392
+ */
393
+
394
+ // Vibe-managed imports below this line. Don't reorder; vibe inserts
395
+ // new lines at the bottom of the import block.
396
+ // e.g. import story017 from "../../scenarios/story-017.js";
397
+
398
+ export const registry = defineScenarios([
399
+ // story017,
400
+ ]);
401
+ `;
402
+ const README = `# \`mock/\` — singular UI mock app
403
+
404
+ Per-consumer mock app, scaffolded by \`slowcook init mock\`. The runtime
405
+ (scenario types + hooks + picker UI) ships via \`@slowcook-ai/mock-runtime\`;
406
+ the bits in this directory are the consumer-owned shell.
407
+
408
+ ## Run it
409
+
410
+ \`\`\`bash
411
+ cd mock
412
+ npm install
413
+ npm run dev
414
+ # → http://localhost:3100
415
+ \`\`\`
416
+
417
+ The homepage is the **scenario picker**. Each scenario maps to one
418
+ story (or one flow within a story) — clicking a scenario navigates to
419
+ that story's preferred initial path with \`?scenario=story-N\` set.
420
+
421
+ ## Architecture in one paragraph
422
+
423
+ The mock is the **design contract**. Vibe writes scenarios for each
424
+ story (\`mock/scenarios/story-N.ts\`); plate amends per PM feedback;
425
+ PM reviews via the live mock URL on the consumer's box. After PM
426
+ approves, brew copies the mock's components into \`src/\` and adds the
427
+ real-data wiring. The mock + production stay in two separate
428
+ filesystems; mock never touches \`src/\`, brew never touches \`mock/\`.
429
+
430
+ The mock has NO backend. Scenarios are plain TypeScript modules read
431
+ by React hooks. Mutations are local component state — they reset on
432
+ page reload, which is the right behavior for a mockup (PM either keeps
433
+ clicking or refreshes to start over).
434
+
435
+ ## Add a scenario by hand
436
+
437
+ \`\`\`ts
438
+ // mock/scenarios/story-017.ts
439
+ import type { Scenario } from "@slowcook-ai/mock-runtime";
440
+
441
+ const scenario: Scenario = {
442
+ id: "017",
443
+ name: "Owner with 3 pins, 8 reactions",
444
+ user: { id: "amin", handle: "amin", display_name: "Amin Azar" },
445
+ initialPath: "/u/amin",
446
+ fixtures: {
447
+ pins: [/* ... */],
448
+ reactions: [/* ... */],
449
+ },
450
+ expectedInteractions: [
451
+ "Click Pin on first reaction → strip prepends",
452
+ "Click Pinned on strip card → strip removes; reaction's Pin re-enables",
453
+ ],
454
+ };
455
+
456
+ export default scenario;
457
+ \`\`\`
458
+
459
+ Then add to the registry in \`mock/src/lib/scenario-registry.ts\`:
460
+
461
+ \`\`\`ts
462
+ import { defineScenarios } from "@slowcook-ai/mock-runtime";
463
+ import story017 from "../../scenarios/story-017.js";
464
+
465
+ export const registry = defineScenarios([story017]);
466
+ \`\`\`
467
+
468
+ Refresh the dev server — the scenario appears in the picker.
469
+
470
+ ## Use scenario data in a component
471
+
472
+ \`\`\`tsx
473
+ "use client";
474
+ import { useScenarioFixture } from "@slowcook-ai/mock-runtime";
475
+
476
+ interface Pin { id: string; rewo_id: string; pinned_at: string; }
477
+
478
+ export function PinsStrip() {
479
+ const pins = useScenarioFixture<Pin[]>("pins");
480
+ return <div>{pins.map(p => /* ... */)}</div>;
481
+ }
482
+ \`\`\`
483
+
484
+ The hook is a typed accessor over \`useScenario().fixtures[domain]\`.
485
+ It throws a clear error in dev when the scenario doesn't have that
486
+ domain populated.
487
+
488
+ ## Roadmap
489
+
490
+ - \`@slowcook-ai/review-overlay\` package (slowcook 0.16-α.5) — adds
491
+ a floating toggle for nav-mode ↔ comment-mode; comments post to
492
+ the mockup PR with element selector + screenshot + viewport metadata
493
+ - \`slowcook preview deploy\` (0.16-α.4) — SSH-deploys the docker
494
+ build to the consumer's box; preview URL posted to PR
495
+ - \`slowcook port\` (0.16-α.7) — deterministic copy of mock components
496
+ → \`src/\` (mock + production stay separate filesystems)
497
+ - Vibe + plate v2 (0.16-α.3 / α.6) — populate this directory based
498
+ on spec + PM feedback
499
+ `;
500
+ //# sourceMappingURL=mock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.js","sourceRoot":"","sources":["../../../src/commands/init/mock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * PM-comment classifier — 0.16.0-α.7.
3
+ *
4
+ * Each element-anchored review-overlay comment on a slowcook-mockup PR
5
+ * gets categorized so plate knows what to do with it:
6
+ *
7
+ * - "cosmetic" → amend the mock with minimum diff
8
+ * - "spec-altering" → ESCALATE: would invalidate a spec assertion or
9
+ * acceptance scenario; PM must confirm the spec
10
+ * change before plate touches the mock
11
+ * - "mock-divergence" → the mock diverged from the spec; align mock
12
+ * to spec; note in summary why the PM ask is
13
+ * being interpreted this way
14
+ *
15
+ * α.7 ships a deterministic heuristic. Each classification has a clear
16
+ * rationale string so the escalation comment can quote the trigger.
17
+ *
18
+ * Heuristic structure:
19
+ * 1. Parse the spec YAML to extract the salient assertion targets:
20
+ * - acceptance_scenarios prose lines
21
+ * - api_contract response field names
22
+ * - invariants prose
23
+ * - ui_behavior viewport prose
24
+ * → a flat set of "spec terms" (lowercased, normalized words).
25
+ * 2. Score the comment prose against those terms:
26
+ * - any direct mention of an acceptance keyword phrase → spec-altering
27
+ * - mention of a domain noun + a "remove/change/replace" → spec-altering
28
+ * - mentions only adjective/style words (color, padding, → cosmetic
29
+ * font, spacing, alignment, shadow, etc.)
30
+ * - else → mock-divergence
31
+ *
32
+ * The heuristic is intentionally conservative on spec-altering: false
33
+ * positives only cost a PM confirm round; false negatives let plate
34
+ * silently weaken the spec, which is the failure mode the architecture
35
+ * is designed to prevent. When in doubt → escalate.
36
+ *
37
+ * No LLM dep here — pure functions over inputs. LLM-backed classifier
38
+ * is a future α.7.1 upgrade if heuristic shows real misses.
39
+ */
40
+ export type Classification = "cosmetic" | "spec-altering" | "mock-divergence";
41
+ export interface ClassifyResult {
42
+ classification: Classification;
43
+ /** Why this classification — included verbatim in escalation comments. */
44
+ rationale: string;
45
+ /** The spec terms (if any) that matched in the comment prose. */
46
+ matchedSpecTerms: string[];
47
+ }
48
+ export interface ClassifyArgs {
49
+ /** Free prose written by the PM in the review-overlay comment. */
50
+ prose: string;
51
+ /**
52
+ * Spec YAML body. Hand-parsed for the assertion targets; we don't
53
+ * need a full YAML parser since the heuristic only needs salient
54
+ * words from acceptance_scenarios / invariants / api_contract.
55
+ */
56
+ specYaml: string;
57
+ }
58
+ export declare function classifyComment(args: ClassifyArgs): ClassifyResult;
59
+ /**
60
+ * Extract candidate "spec terms" — lowercase, deduplicated significant
61
+ * tokens from the spec sections plate cares about. Used by the
62
+ * classifier to detect overlap between PM prose and spec assertions.
63
+ */
64
+ export declare function extractSpecTerms(specYaml: string): string[];
65
+ //# sourceMappingURL=classify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../../src/commands/plate/classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAE9E,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,cAAc,CAAC;IAC/B,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAyBD,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,CAgElE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAe3D"}