/** * @slowcook 0.17.0 — refine becomes history-aware. * * Builds a structured snapshot of the consumer's existing brownfield * surface so refine (and downstream vibe + testgen + brew) can answer * "what already exists for this story?" mechanically instead of by * hallucination. * * The output (`.brewing/history-index.json`) is the input contract for: * - refine's brownfield-conflict Q&A (does new spec collide with * existing component prop shape, existing migration columns, etc.?) * - vibe's "extend existing file, don't create duplicate" rule * - testgen's "use existing prop names + existing test helpers" rule * - brew's "what already exists in migrations/handlers?" pre-check * - recon's brownfield rename-safety check * * Pure functions over the filesystem. No LLM. Generated on every refine * invocation so it's always current. */ import type { GitAttentionData } from "./git-attention.js"; export interface ComponentEntry { /** PascalCase component name (the default-export or first named export). */ name: string; /** repo-relative path */ file: string; /** Top-level Props interface keys (e.g. ["owner", "viewer", "reactions?", "pins?"]). */ props: string[]; /** Test files (repo-relative) that import this component. */ tests_covering: string[]; } export interface ApiRouteEntry { /** HTTP method exported by the route (GET/POST/PUT/PATCH/DELETE). */ method: string; /** URL path (e.g. /api/bookmarks, /api/members/[handle]/reactions). */ path: string; /** repo-relative file */ file: string; } export interface MigrationEntry { /** Migration file basename. */ file: string; /** Tables created in this migration (`create table X`). */ tables_created: string[]; /** Map of table → columns added (in this migration's create + alter add column). */ columns_added: Record; } export interface TestHelperEntry { /** Exported symbol name. */ name: string; /** repo-relative file. */ file: string; /** Best-effort one-line purpose extracted from JSDoc or first comment. */ purpose: string; } export interface TestFileEntry { /** repo-relative path. */ file: string; /** Imports the file makes (only `@/...` and relative paths captured). */ imports: string[]; /** describe / it titles found in the file (best-effort regex). */ test_names: string[]; } /** * A mock page or component, captured so refine can answer * "match the mock" without making the PM cite paths. * * 0.19.0-α.23 — added because real PM issues describe user pain * ("registration should look like the mock"), and the indexer * previously only saw production `src/`. Refine then either * hallucinated a design or had to ask. Surfacing mock files in * context closes the loop: PM says "as mock" → refine reads the * actual mock excerpt → spec mirrors it. * * The excerpt is bounded to the first ~1.5KB so refine's prompt * doesn't blow up on a 5KB mock file. */ export interface MockEntry { /** repo-relative path. */ file: string; /** Route inferred from app/router-shape file location, or null for components. */ route: string | null; /** Component or page name (best-effort extraction, falls back to file basename). */ name: string; /** First ~1500 chars of the file (after trimming whitespace) so refine sees the actual JSX/markup. */ excerpt: string; } export interface HistoryIndex { generated_at: string; generator: "slowcook-refine-history-index@0.17.0"; components: ComponentEntry[]; api_routes: ApiRouteEntry[]; migrations: MigrationEntry[]; test_helpers: TestHelperEntry[]; test_files: TestFileEntry[]; /** 0.19.0-α.23 — mock surface (design source-of-truth). */ mock_surface: MockEntry[]; /** * 0.19.0-α.43 — git-history attention layer. Set when enrichment ran * (refine emits with it on by default; pure-filesystem callers / tests * may leave it undefined). See git-attention.ts for the four sub-signals. */ git_attention?: GitAttentionData; } interface BuildOptions { repoRoot: string; /** Override default scan paths (used by tests). */ scanPaths?: { components?: string; api?: string; migrations?: string; tests?: string; helpers?: string; /** Default: `mock/src` (matches slowcook init scaffold). */ mockRoot?: string; }; } export declare function buildHistoryIndex(opts: BuildOptions): HistoryIndex; export declare const TYPEORM_MIGRATION_FALLBACK_DIRS: string[]; /** * The columns `DatabaseCreateTable` (delgoosh's helper) adds implicitly on * EVERY table. Knowing these prevents the migration gate from raising a * false-positive "missing column" verdict when the spec references e.g. * `created_at` and the migration uses the helper. * * Kept conservative: only columns added by the helper at delgoosh-monorepo's * version (id, created_at, updated_at, deleted_at). Future TypeORM helpers * with different defaults need their own entry — or, longer-term, slowcook * should infer this from the helper's source. */ export declare const TYPEORM_HELPER_IMPLICIT_COLUMNS: string[]; export declare function scanMigrations(repoRoot: string, dir: string): MigrationEntry[]; /** * Parse a single TypeORM migration TS file into the same MigrationEntry shape * the SQL parser produces. Sees two patterns: * * 1. `await queryRunner.query(\`CREATE TABLE x ...\`)` — extract the SQL * template body and run it through the existing SQL parsers. * 2. `await DatabaseCreateTable(queryRunner, 'tbl', [{name:'a'},{name:'b'}])` * — extract `tbl` + each column's name + the implicit-columns helpers * add (id, created_at, updated_at, deleted_at). * * Pattern 2 is delgoosh-monorepo-specific; pattern 1 covers raw SQL writers. * EXPORTED for unit testing. */ export declare function parseTypeOrmMigration(name: string, body: string): MigrationEntry; export declare function extractCreateTables(sql: string): string[]; export declare function extractColumnsAdded(sql: string): Record; export declare function scanMockSurface(repoRoot: string, mockRoot: string): MockEntry[]; /** * Route-FILE conventions (src/app/api/**​/route.ts) miss code-routed * frameworks entirely — dash mounts everything via Hono `app.post("/api/...")` * in one file, which indexed as "0 api routes" and led testgen to FORK an * existing webhook handler it couldn't see (aminazar/slowcook#240). This pass * greps literal `app.("...")` registrations out of every package's * src/ tree. Regex-level fidelity is deliberate: no AST dependency, and a * route the regex misses degrades to the old behavior, never worse. */ export declare function scanCodeRoutes(repoRoot: string, pkgDirs: string[]): ApiRouteEntry[]; /** * Every place code can live by convention: the repo root ("") plus any * first-level directory containing a package.json (covers dash's server/ + * mock/, simple monorepos) plus pnpm-workspace.yaml globs one level deep * (covers packages/star layouts). Deduped, deterministic order. */ export declare function discoverPackageDirs(repoRoot: string): string[]; export {}; //# sourceMappingURL=history-index.d.ts.map