@slowcook-ai/cli 0.19.0-alpha.14 → 0.19.0-alpha.17
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 +27 -0
- package/REPORTING.md +40 -1
- package/dist/cli.js +13 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/extract/index.d.ts.map +1 -1
- package/dist/commands/extract/index.js +23 -1
- package/dist/commands/extract/index.js.map +1 -1
- package/dist/commands/garnish/index.d.ts +56 -0
- package/dist/commands/garnish/index.d.ts.map +1 -0
- package/dist/commands/garnish/index.js +281 -0
- package/dist/commands/garnish/index.js.map +1 -0
- package/dist/commands/garnish/trailer.d.ts +79 -0
- package/dist/commands/garnish/trailer.d.ts.map +1 -0
- package/dist/commands/garnish/trailer.js +118 -0
- package/dist/commands/garnish/trailer.js.map +1 -0
- package/dist/commands/init/templates.d.ts.map +1 -1
- package/dist/commands/init/templates.js +12 -4
- package/dist/commands/init/templates.js.map +1 -1
- package/dist/commands/map/emit-typeorm.d.ts +117 -0
- package/dist/commands/map/emit-typeorm.d.ts.map +1 -0
- package/dist/commands/map/emit-typeorm.js +341 -0
- package/dist/commands/map/emit-typeorm.js.map +1 -0
- package/dist/commands/map/index.d.ts +18 -0
- package/dist/commands/map/index.d.ts.map +1 -1
- package/dist/commands/map/index.js +28 -0
- package/dist/commands/map/index.js.map +1 -1
- package/dist/commands/run-mock/index.d.ts.map +1 -1
- package/dist/commands/run-mock/index.js +128 -21
- package/dist/commands/run-mock/index.js.map +1 -1
- package/package.json +9 -9
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0.19.0+ (slowcook#36) — TypeORM entity-graph extractor. Walks all
|
|
3
|
+
* `**\/*.entity.ts` files containing `@Entity(...)` decorators and emits
|
|
4
|
+
* a Mermaid ERD + per-entity summary table to
|
|
5
|
+
* `.brewing/diagrams/entities.md`.
|
|
6
|
+
*
|
|
7
|
+
* Why: slowcook's existing `emitSchemaDiagram` only knows about
|
|
8
|
+
* `supabase/migrations/*.sql`. Consumers on TypeORM (delgoosh, plus
|
|
9
|
+
* any NestJS monorepo) get nothing from the brownfield-extract step,
|
|
10
|
+
* leaving their slowcook agents (vibe / recipe / brew / chef /
|
|
11
|
+
* investigate) without entity grounding. Hand-curated entities.md
|
|
12
|
+
* is the workaround — this module replaces it with auto-extraction.
|
|
13
|
+
*
|
|
14
|
+
* Detection signal: any `*.entity.ts` file with `@Entity(` decorator.
|
|
15
|
+
* (Skips `node_modules`, `dist`, `.next`, `coverage`.)
|
|
16
|
+
*
|
|
17
|
+
* Parser is regex-based — TypeORM decorators have a strict shape
|
|
18
|
+
* across the ecosystem. Same approach as `ddlToMermaidErd` in
|
|
19
|
+
* refine/mermaid.ts; no AST tooling needed.
|
|
20
|
+
*/
|
|
21
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
22
|
+
import { join, basename } from "node:path";
|
|
23
|
+
/** Skip these directories on the recursive walk. */
|
|
24
|
+
const EXCLUDED_DIRS = new Set([
|
|
25
|
+
"node_modules",
|
|
26
|
+
"dist",
|
|
27
|
+
".next",
|
|
28
|
+
".turbo",
|
|
29
|
+
"coverage",
|
|
30
|
+
".git",
|
|
31
|
+
"build",
|
|
32
|
+
]);
|
|
33
|
+
/**
|
|
34
|
+
* Recursive walk under `root` collecting absolute file paths matching
|
|
35
|
+
* the predicate. Skips EXCLUDED_DIRS at any depth.
|
|
36
|
+
*/
|
|
37
|
+
function walk(root, predicate) {
|
|
38
|
+
const out = [];
|
|
39
|
+
const stack = [root];
|
|
40
|
+
while (stack.length > 0) {
|
|
41
|
+
const dir = stack.pop();
|
|
42
|
+
let entries;
|
|
43
|
+
try {
|
|
44
|
+
entries = readdirSync(dir);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
for (const entry of entries) {
|
|
50
|
+
if (EXCLUDED_DIRS.has(entry))
|
|
51
|
+
continue;
|
|
52
|
+
const path = join(dir, entry);
|
|
53
|
+
let st;
|
|
54
|
+
try {
|
|
55
|
+
st = statSync(path);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (st.isDirectory()) {
|
|
61
|
+
stack.push(path);
|
|
62
|
+
}
|
|
63
|
+
else if (st.isFile() && predicate(path)) {
|
|
64
|
+
out.push(path);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Find all `*.entity.ts` files under `repoRoot` whose content contains
|
|
72
|
+
* an `@Entity(` decorator. Returns paths sorted alphabetically for
|
|
73
|
+
* deterministic output.
|
|
74
|
+
*/
|
|
75
|
+
export function findEntityFiles(repoRoot) {
|
|
76
|
+
const candidates = walk(repoRoot, (p) => p.endsWith(".entity.ts"));
|
|
77
|
+
const real = candidates.filter((p) => {
|
|
78
|
+
try {
|
|
79
|
+
const src = readFileSync(p, "utf8");
|
|
80
|
+
return /@Entity\s*\(/.test(src);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
real.sort();
|
|
87
|
+
return real;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Parse one TypeORM entity source file. Returns null if no `@Entity`
|
|
91
|
+
* decorator is found (defense-in-depth — findEntityFiles already
|
|
92
|
+
* filtered).
|
|
93
|
+
*/
|
|
94
|
+
export function parseEntityFile(source, sourcePath) {
|
|
95
|
+
// Class name + extends BaseEntity check.
|
|
96
|
+
const classMatch = source.match(/export\s+class\s+(\w+)(?:\s+extends\s+(\w+))?/);
|
|
97
|
+
if (!classMatch)
|
|
98
|
+
return null;
|
|
99
|
+
const className = classMatch[1];
|
|
100
|
+
const extendsBaseEntity = classMatch[2] === "BaseEntity";
|
|
101
|
+
// Table name from @Entity('snake_case_plural'). Fallback to className.
|
|
102
|
+
const entityMatch = source.match(/@Entity\s*\(\s*['"]([^'"]+)['"]\s*\)/);
|
|
103
|
+
const tableName = entityMatch?.[1] ??
|
|
104
|
+
className
|
|
105
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
106
|
+
.toLowerCase();
|
|
107
|
+
// JSDoc above the class (TABLE-DESCRIPTION: ...).
|
|
108
|
+
const tableDescMatch = source.match(/TABLE-DESCRIPTION:\s*([^\n*]+?)(?:\s*\*\/|\s*\n\s*\*\s*TABLE-)/);
|
|
109
|
+
const description = tableDescMatch?.[1]?.trim();
|
|
110
|
+
// Columns: @Column(...) followed by `[public ]<property>: <type>`.
|
|
111
|
+
// The decorator may span multiple lines; we capture the args block in
|
|
112
|
+
// a balanced way using a permissive `[^@]*?` lookahead — fine because
|
|
113
|
+
// the next `@` always opens the next decorator or the property.
|
|
114
|
+
const columns = [];
|
|
115
|
+
const columnRe = /@Column\s*\(\s*(\{[\s\S]*?\})\s*\)\s*(?:public\s+|readonly\s+)?(\w+)\s*[?!]?\s*:\s*([^;]+);/g;
|
|
116
|
+
let cm;
|
|
117
|
+
while ((cm = columnRe.exec(source)) !== null) {
|
|
118
|
+
const [, args, property, tsType] = cm;
|
|
119
|
+
columns.push({
|
|
120
|
+
property: property,
|
|
121
|
+
columnName: args.match(/name:\s*['"]([^'"]+)['"]/)?.[1],
|
|
122
|
+
columnType: args.match(/type:\s*['"]([^'"]+)['"]/)?.[1],
|
|
123
|
+
nullable: /nullable:\s*true/.test(args),
|
|
124
|
+
tsType: tsType.trim(),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
// Also catch bare `@Column()` (no args) — TypeORM allows this.
|
|
128
|
+
const bareColumnRe = /@Column\s*\(\s*\)\s*(?:public\s+|readonly\s+)?(\w+)\s*[?!]?\s*:\s*([^;]+);/g;
|
|
129
|
+
while ((cm = bareColumnRe.exec(source)) !== null) {
|
|
130
|
+
const [, property, tsType] = cm;
|
|
131
|
+
columns.push({
|
|
132
|
+
property: property,
|
|
133
|
+
tsType: tsType.trim(),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Relations: @ManyToOne / @OneToOne / @OneToMany / @ManyToMany.
|
|
137
|
+
const relations = [];
|
|
138
|
+
const relRe = /@(ManyToOne|OneToOne|OneToMany|ManyToMany)\s*\(\s*\(\)\s*=>\s*(\w+)[\s\S]*?\)\s*(?:@JoinColumn\s*\(\s*\{?\s*(?:name:\s*['"]([^'"]+)['"])?[^}]*\}?\s*\)\s*)?(?:public\s+|readonly\s+)?(\w+)/g;
|
|
139
|
+
let rm;
|
|
140
|
+
while ((rm = relRe.exec(source)) !== null) {
|
|
141
|
+
const [, kind, target, joinColumn, property] = rm;
|
|
142
|
+
relations.push({
|
|
143
|
+
property: property,
|
|
144
|
+
kind: kind,
|
|
145
|
+
target: target,
|
|
146
|
+
joinColumn,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
className,
|
|
151
|
+
tableName,
|
|
152
|
+
extendsBaseEntity,
|
|
153
|
+
sourcePath,
|
|
154
|
+
description,
|
|
155
|
+
columns,
|
|
156
|
+
relations,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Mermaid relation shape per TypeORM kind.
|
|
161
|
+
* ManyToOne N owners → 1 target → `}o--||`
|
|
162
|
+
* OneToOne 1 owner → 1 target → `||--o|`
|
|
163
|
+
* OneToMany 1 owner → 0..N targets → `||--o{`
|
|
164
|
+
* ManyToMany N owners → N targets → `}o--o{`
|
|
165
|
+
*/
|
|
166
|
+
const RELATION_SHAPES = {
|
|
167
|
+
ManyToOne: "}o--||",
|
|
168
|
+
OneToOne: "||--o|",
|
|
169
|
+
OneToMany: "||--o{",
|
|
170
|
+
ManyToMany: "}o--o{",
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* Render one Mermaid `erDiagram` covering all entities + their
|
|
174
|
+
* relations. For very large graphs (>40 entities) the diagram is hard
|
|
175
|
+
* to read — but splitting by domain requires semantic knowledge we
|
|
176
|
+
* don't have. We render one big ERD; consumers can grep for entities
|
|
177
|
+
* they care about + use the per-entity table below for details.
|
|
178
|
+
*/
|
|
179
|
+
export function entitiesToMermaidErd(entities) {
|
|
180
|
+
if (entities.length === 0) {
|
|
181
|
+
return "```mermaid\nerDiagram\n %% No @Entity decorators found.\n```";
|
|
182
|
+
}
|
|
183
|
+
const lines = ["```mermaid", "erDiagram"];
|
|
184
|
+
const known = new Set(entities.map((e) => e.className));
|
|
185
|
+
for (const e of entities) {
|
|
186
|
+
for (const r of e.relations) {
|
|
187
|
+
// Skip relations whose target isn't a known entity (e.g. enum types).
|
|
188
|
+
if (!known.has(r.target))
|
|
189
|
+
continue;
|
|
190
|
+
const label = r.property.replace(/"/g, "");
|
|
191
|
+
lines.push(` ${e.className} ${RELATION_SHAPES[r.kind]} ${r.target} : "${label}"`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Always render entity boxes even with no columns (helps when a
|
|
195
|
+
// class only has relations, e.g. junction tables).
|
|
196
|
+
for (const e of entities) {
|
|
197
|
+
lines.push(` ${e.className} {`);
|
|
198
|
+
// Show only NOTABLE columns: anything that looks like an FK or
|
|
199
|
+
// status enum or has a tableName (the rest belong in the per-
|
|
200
|
+
// entity table below). Cap at 6 to keep diagram readable.
|
|
201
|
+
const notable = e.columns
|
|
202
|
+
.filter((c) => c.columnName?.endsWith("_id") || c.columnType === "enum")
|
|
203
|
+
.slice(0, 6);
|
|
204
|
+
if (notable.length === 0) {
|
|
205
|
+
// Show the first ~3 columns so the box isn't empty.
|
|
206
|
+
for (const c of e.columns.slice(0, 3)) {
|
|
207
|
+
lines.push(` ${c.columnType ?? "any"} ${c.columnName ?? c.property}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
for (const c of notable) {
|
|
212
|
+
const t = c.columnType ?? "any";
|
|
213
|
+
lines.push(` ${t} ${c.columnName ?? c.property}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
lines.push(` }`);
|
|
217
|
+
}
|
|
218
|
+
lines.push("```");
|
|
219
|
+
return lines.join("\n");
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Render the per-entity summary table for the entities.md artifact.
|
|
223
|
+
* Pairs with the Mermaid ERD above to give agents structured access
|
|
224
|
+
* to the entity vocabulary.
|
|
225
|
+
*/
|
|
226
|
+
export function entitiesToSummaryTable(entities) {
|
|
227
|
+
const lines = [];
|
|
228
|
+
lines.push("| Entity | Table | Purpose | Key relations | Notable columns |");
|
|
229
|
+
lines.push("|---|---|---|---|---|");
|
|
230
|
+
for (const e of entities) {
|
|
231
|
+
const purpose = (e.description ?? "—").replace(/\|/g, "\\|");
|
|
232
|
+
const relations = e.relations
|
|
233
|
+
.slice(0, 4)
|
|
234
|
+
.map((r) => `${r.kind} ${r.target}`)
|
|
235
|
+
.join("; ") || "—";
|
|
236
|
+
const notableCols = e.columns
|
|
237
|
+
.filter((c) => c.columnName?.endsWith("_id") || c.columnType === "enum")
|
|
238
|
+
.slice(0, 5)
|
|
239
|
+
.map((c) => c.columnName ?? c.property)
|
|
240
|
+
.join(", ") || "—";
|
|
241
|
+
lines.push(`| ${e.className} | \`${e.tableName}\` | ${purpose} | ${relations} | ${notableCols} |`);
|
|
242
|
+
}
|
|
243
|
+
return lines.join("\n");
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Full entities.md document body. Static header + conventions section
|
|
247
|
+
* (drawn from delgoosh dogfood — these are the same conventions every
|
|
248
|
+
* NestJS+TypeORM consumer follows) + the ERD + summary table.
|
|
249
|
+
*/
|
|
250
|
+
export function renderEntitiesMarkdown(entities) {
|
|
251
|
+
const baseEntityHits = entities.filter((e) => e.extendsBaseEntity).length;
|
|
252
|
+
const baseEntityHint = baseEntityHits > 0
|
|
253
|
+
? `${baseEntityHits} of ${entities.length} entities \`extend BaseEntity\` — assume the same UUID-id + soft-delete pattern when adding new entities.`
|
|
254
|
+
: "No `BaseEntity` parent class detected — entities define their own primary keys.";
|
|
255
|
+
return `# Entity graph (auto-generated by \`slowcook extract --entities\`)
|
|
256
|
+
|
|
257
|
+
> **Auto-generated; do not hand-edit.** Regenerate by running \`slowcook extract --entities\`.
|
|
258
|
+
> Source: \`*.entity.ts\` files containing an \`@Entity(\` decorator.
|
|
259
|
+
|
|
260
|
+
This artifact is consumed by slowcook agents (vibe / recipe / brew / chef / investigate) to ground their work in the existing entity vocabulary. Without it agents hallucinate table shapes and column names.
|
|
261
|
+
|
|
262
|
+
## Quick stats
|
|
263
|
+
|
|
264
|
+
- **${entities.length} entities** discovered
|
|
265
|
+
- **${entities.reduce((n, e) => n + e.relations.length, 0)} relations** declared
|
|
266
|
+
- ${baseEntityHint}
|
|
267
|
+
|
|
268
|
+
## Conventions (inferred from the codebase)
|
|
269
|
+
|
|
270
|
+
- Tables follow snake_case_plural (e.g. \`@Entity('patients')\`).
|
|
271
|
+
- TS properties are camelCase; SQL columns are snake_case via \`@Column({ name: 'snake_case' })\`.
|
|
272
|
+
- Foreign keys follow the \`<foreign_table_singular>_id\` pattern.
|
|
273
|
+
- Enum columns reference \`@Column({ type: 'enum', enum: <EnumFromRepoEnums> })\`.
|
|
274
|
+
- Relations are declared via \`@ManyToOne\` / \`@OneToOne\` / \`@OneToMany\` / \`@ManyToMany\` + \`@JoinColumn\`.
|
|
275
|
+
|
|
276
|
+
## Entity-relationship diagram
|
|
277
|
+
|
|
278
|
+
${entitiesToMermaidErd(entities)}
|
|
279
|
+
|
|
280
|
+
## Per-entity summary
|
|
281
|
+
|
|
282
|
+
${entitiesToSummaryTable(entities)}
|
|
283
|
+
|
|
284
|
+
## Source paths
|
|
285
|
+
|
|
286
|
+
${entities.map((e) => `- \`${e.sourcePath}\` — \`${e.className}\``).join("\n")}
|
|
287
|
+
`;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Public entry — walks the repo, parses entities, returns the rendered
|
|
291
|
+
* markdown body PLUS counts for the caller (which writes the file).
|
|
292
|
+
* Skipped silently if no .entity.ts files with @Entity are found —
|
|
293
|
+
* consumer probably uses Prisma / Drizzle / Supabase / raw SQL.
|
|
294
|
+
*/
|
|
295
|
+
export function buildEntitiesArtifact(repoRoot) {
|
|
296
|
+
const files = findEntityFiles(repoRoot);
|
|
297
|
+
if (files.length === 0) {
|
|
298
|
+
return {
|
|
299
|
+
written: false,
|
|
300
|
+
skippedReason: "no `*.entity.ts` files with `@Entity(...)` decorator found (TypeORM signal absent)",
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
const entities = [];
|
|
304
|
+
for (const f of files) {
|
|
305
|
+
try {
|
|
306
|
+
const src = readFileSync(f, "utf8");
|
|
307
|
+
const repoRelative = f.startsWith(repoRoot)
|
|
308
|
+
? f.slice(repoRoot.length + 1)
|
|
309
|
+
: f;
|
|
310
|
+
const e = parseEntityFile(src, repoRelative);
|
|
311
|
+
if (e)
|
|
312
|
+
entities.push(e);
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
// Skip unreadable files silently.
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (entities.length === 0) {
|
|
319
|
+
return {
|
|
320
|
+
written: false,
|
|
321
|
+
skippedReason: `${files.length} candidate file(s) found but none parsed cleanly`,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
written: true,
|
|
326
|
+
body: renderEntitiesMarkdown(entities),
|
|
327
|
+
entityCount: entities.length,
|
|
328
|
+
relationCount: entities.reduce((n, e) => n + e.relations.length, 0),
|
|
329
|
+
fileCount: files.length,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
// Test-only helper. Avoids exporting internals to the public surface.
|
|
333
|
+
export const __testOnly__ = {
|
|
334
|
+
parseEntityFile,
|
|
335
|
+
walk,
|
|
336
|
+
entitiesToMermaidErd,
|
|
337
|
+
entitiesToSummaryTable,
|
|
338
|
+
};
|
|
339
|
+
// Avoid unused-import warning on `basename` if not used above.
|
|
340
|
+
void basename;
|
|
341
|
+
//# sourceMappingURL=emit-typeorm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-typeorm.js","sourceRoot":"","sources":["../../../src/commands/map/emit-typeorm.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
import type { CodeMap } from "./scan.js";
|
|
2
2
|
export { emitTokensCatalog } from "./emit-tokens.js";
|
|
3
|
+
export { buildEntitiesArtifact } from "./emit-typeorm.js";
|
|
4
|
+
/**
|
|
5
|
+
* 0.19.0+ (slowcook#36) — TypeORM entity-graph emitter. Mirrors
|
|
6
|
+
* `emitSchemaDiagram`'s shape for the (different) Supabase-migration
|
|
7
|
+
* source. Skipped silently when no `*.entity.ts` files with `@Entity(`
|
|
8
|
+
* decorators are found — not every consumer uses TypeORM.
|
|
9
|
+
*
|
|
10
|
+
* Output: `.brewing/diagrams/entities.md` (Mermaid ERD + per-entity
|
|
11
|
+
* summary + agent-facing conventions header). Tracked in git by
|
|
12
|
+
* default per the updated init gitignore template (slowcook#38).
|
|
13
|
+
*/
|
|
14
|
+
export declare function emitEntitiesDiagram(repoRoot: string): {
|
|
15
|
+
written: boolean;
|
|
16
|
+
entityCount?: number;
|
|
17
|
+
relationCount?: number;
|
|
18
|
+
fileCount?: number;
|
|
19
|
+
skippedReason?: string;
|
|
20
|
+
};
|
|
3
21
|
export declare function map(argv: string[], cliVersion: string): Promise<void>;
|
|
4
22
|
export declare function writeFreshMap(repoRoot: string, outJson: string, outMd: string, fresh: CodeMap): void;
|
|
5
23
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/map/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/map/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAeA;AAuFD,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6E3E;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,OAAO,GACb,IAAI,CAMN;AAWD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACnD,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAuBA"}
|
|
@@ -4,7 +4,35 @@ import { generateMap } from "./scan.js";
|
|
|
4
4
|
import { renderJson, renderMarkdown, mapsEqual, CODE_MAP_JSON_PATH, CODE_MAP_MD_PATH, } from "./render.js";
|
|
5
5
|
import { ddlToMermaidErd } from "../refine/mermaid.js";
|
|
6
6
|
import { emitTokensCatalog } from "./emit-tokens.js";
|
|
7
|
+
import { buildEntitiesArtifact } from "./emit-typeorm.js";
|
|
7
8
|
export { emitTokensCatalog } from "./emit-tokens.js";
|
|
9
|
+
export { buildEntitiesArtifact } from "./emit-typeorm.js";
|
|
10
|
+
/**
|
|
11
|
+
* 0.19.0+ (slowcook#36) — TypeORM entity-graph emitter. Mirrors
|
|
12
|
+
* `emitSchemaDiagram`'s shape for the (different) Supabase-migration
|
|
13
|
+
* source. Skipped silently when no `*.entity.ts` files with `@Entity(`
|
|
14
|
+
* decorators are found — not every consumer uses TypeORM.
|
|
15
|
+
*
|
|
16
|
+
* Output: `.brewing/diagrams/entities.md` (Mermaid ERD + per-entity
|
|
17
|
+
* summary + agent-facing conventions header). Tracked in git by
|
|
18
|
+
* default per the updated init gitignore template (slowcook#38).
|
|
19
|
+
*/
|
|
20
|
+
export function emitEntitiesDiagram(repoRoot) {
|
|
21
|
+
const r = buildEntitiesArtifact(repoRoot);
|
|
22
|
+
if (!r.written || !r.body) {
|
|
23
|
+
return { written: false, skippedReason: r.skippedReason };
|
|
24
|
+
}
|
|
25
|
+
const outDir = join(repoRoot, ".brewing/diagrams");
|
|
26
|
+
mkdirSync(outDir, { recursive: true });
|
|
27
|
+
const outPath = join(outDir, "entities.md");
|
|
28
|
+
writeFileSync(outPath, r.body, "utf8");
|
|
29
|
+
return {
|
|
30
|
+
written: true,
|
|
31
|
+
entityCount: r.entityCount,
|
|
32
|
+
relationCount: r.relationCount,
|
|
33
|
+
fileCount: r.fileCount,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
8
36
|
function parseArgs(argv) {
|
|
9
37
|
const args = {
|
|
10
38
|
subcommand: "generate",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/map/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EACL,UAAU,EACV,cAAc,EACd,SAAS,EACT,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/map/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/run-mock/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/run-mock/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAqJH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyPhF"}
|
|
@@ -45,6 +45,7 @@ function parseArgs(argv) {
|
|
|
45
45
|
pollSeconds: 15,
|
|
46
46
|
skipInstall: false,
|
|
47
47
|
branchOverride: null,
|
|
48
|
+
garnish: false,
|
|
48
49
|
};
|
|
49
50
|
// Positional first arg is story id (consumer convenience).
|
|
50
51
|
if (argv.length > 0 && argv[0] && !argv[0].startsWith("-")) {
|
|
@@ -76,6 +77,9 @@ function parseArgs(argv) {
|
|
|
76
77
|
else if (a === "--skip-install") {
|
|
77
78
|
args.skipInstall = true;
|
|
78
79
|
}
|
|
80
|
+
else if (a === "--garnish") {
|
|
81
|
+
args.garnish = true;
|
|
82
|
+
}
|
|
79
83
|
else if (a === "--help" || a === "-h") {
|
|
80
84
|
printHelp();
|
|
81
85
|
process.exit(0);
|
|
@@ -109,6 +113,13 @@ Options:
|
|
|
109
113
|
--poll-seconds <n> Auto-pull interval (default 15; 0 disables).
|
|
110
114
|
--no-poll Disable auto-pull.
|
|
111
115
|
--skip-install Skip npm install even on lockfile drift.
|
|
116
|
+
--garnish (0.19.0-α.16) DevTools Workspaces mode. Disables
|
|
117
|
+
the review-overlay; instead prints Chrome
|
|
118
|
+
Workspaces pairing instructions + watches
|
|
119
|
+
mock/src/ for file saves. Each debounced batch
|
|
120
|
+
runs vitest related + auto-commits via garnish
|
|
121
|
+
on green (Tweaks-output-of: trailers recorded
|
|
122
|
+
for learning signal).
|
|
112
123
|
|
|
113
124
|
What it does:
|
|
114
125
|
1. git fetch + git checkout the mockup branch
|
|
@@ -242,35 +253,61 @@ export async function runMock(argv, _cliVersion) {
|
|
|
242
253
|
// without prompting the PM for a PAT. Uses `gh auth token` from the
|
|
243
254
|
// local gh CLI; falls back silently when gh isn't installed or the
|
|
244
255
|
// user hasn't logged in (overlay then uses its old PAT-prompt path).
|
|
256
|
+
//
|
|
257
|
+
// 0.19.0-α.16 — in --garnish mode the overlay is disabled, so we
|
|
258
|
+
// skip starting the proxy (saves a port + a couple of stderr lines).
|
|
245
259
|
let proxy = null;
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
260
|
+
if (!args.garnish) {
|
|
261
|
+
const ghToken = readGhToken();
|
|
262
|
+
if (ghToken) {
|
|
263
|
+
try {
|
|
264
|
+
proxy = await startGhProxy(ghToken);
|
|
265
|
+
console.log(` proxy gh-proxy on ${proxy.url} (no PAT prompt — uses 'gh auth token')`);
|
|
266
|
+
}
|
|
267
|
+
catch (e) {
|
|
268
|
+
console.warn(` proxy gh-proxy failed to start (${e.message}); overlay will fall back to PAT prompt.`);
|
|
269
|
+
}
|
|
251
270
|
}
|
|
252
|
-
|
|
253
|
-
console.warn(` proxy gh
|
|
271
|
+
else {
|
|
272
|
+
console.warn(` proxy gh CLI not authenticated ('gh auth token' returned empty). Overlay will prompt for a PAT instead.`);
|
|
254
273
|
}
|
|
255
274
|
}
|
|
256
275
|
else {
|
|
257
|
-
console.
|
|
276
|
+
console.log(` proxy skipped (--garnish mode; overlay disabled)`);
|
|
258
277
|
}
|
|
259
278
|
// Step 4: spawn next dev with env vars.
|
|
260
|
-
const env = {
|
|
261
|
-
|
|
262
|
-
NEXT_PUBLIC_SLOWCOOK_REVIEW
|
|
263
|
-
NEXT_PUBLIC_SLOWCOOK_OWNER
|
|
264
|
-
NEXT_PUBLIC_SLOWCOOK_REPO
|
|
265
|
-
NEXT_PUBLIC_SLOWCOOK_PR_NUMBER
|
|
266
|
-
NEXT_PUBLIC_SLOWCOOK_STORY_ID
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
279
|
+
const env = { ...process.env };
|
|
280
|
+
if (!args.garnish) {
|
|
281
|
+
env["NEXT_PUBLIC_SLOWCOOK_REVIEW"] = "1";
|
|
282
|
+
env["NEXT_PUBLIC_SLOWCOOK_OWNER"] = detected.owner;
|
|
283
|
+
env["NEXT_PUBLIC_SLOWCOOK_REPO"] = detected.repo;
|
|
284
|
+
env["NEXT_PUBLIC_SLOWCOOK_PR_NUMBER"] = prNumber ? String(prNumber) : "0";
|
|
285
|
+
env["NEXT_PUBLIC_SLOWCOOK_STORY_ID"] = args.story;
|
|
286
|
+
if (proxy)
|
|
287
|
+
env["NEXT_PUBLIC_SLOWCOOK_GH_PROXY"] = proxy.url;
|
|
288
|
+
}
|
|
270
289
|
console.log(` npm run dev (next dev :3100)`);
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
290
|
+
if (!args.garnish) {
|
|
291
|
+
console.log(` overlay env: REVIEW=1 OWNER=${detected.owner} REPO=${detected.repo} PR=${prNumber ?? "?"} STORY=${args.story}${proxy ? ` GH_PROXY=${proxy.url}` : ""}`);
|
|
292
|
+
if (!prNumber) {
|
|
293
|
+
console.warn(` (no open mockup PR found for branch ${branch}; overlay submits will fail until one exists)`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
const srcDir = join(mockDir, "src");
|
|
298
|
+
console.log(` (--garnish mode: overlay disabled; DevTools Workspaces pairing instructions below)`);
|
|
299
|
+
console.log(``);
|
|
300
|
+
console.log(` ─── Chrome DevTools Workspaces ─────────────────────────────────────`);
|
|
301
|
+
console.log(` Once-only setup (Chrome saves the workspace mapping after this):`);
|
|
302
|
+
console.log(` 1. Open the mock at http://localhost:3100`);
|
|
303
|
+
console.log(` 2. F12 → Sources panel → Filesystem (left sidebar) → "+ Add folder"`);
|
|
304
|
+
console.log(` 3. Paste this path: ${srcDir}`);
|
|
305
|
+
console.log(` 4. Approve the permission dialog Chrome shows`);
|
|
306
|
+
console.log(``);
|
|
307
|
+
console.log(` After that, your DevTools Sources-panel edits save directly to`);
|
|
308
|
+
console.log(` the mock app's source files. slowcook watches them + auto-commits.`);
|
|
309
|
+
console.log(` ─────────────────────────────────────────────────────────────────────`);
|
|
310
|
+
console.log(``);
|
|
274
311
|
}
|
|
275
312
|
const dev = spawn("npm", ["run", "dev"], { cwd: mockDir, env, stdio: "inherit" });
|
|
276
313
|
// Step 5: background poll for branch updates.
|
|
@@ -299,6 +336,66 @@ export async function runMock(argv, _cliVersion) {
|
|
|
299
336
|
}
|
|
300
337
|
}, args.pollSeconds * 1000);
|
|
301
338
|
}
|
|
339
|
+
// Step 5b: --garnish mode — watch mock/src/ for file saves +
|
|
340
|
+
// auto-commit via the shared runGarnish core. Debounced so a flurry
|
|
341
|
+
// of saves (Chrome DevTools sometimes saves twice in quick succession;
|
|
342
|
+
// editors can too) collapses to one commit.
|
|
343
|
+
let watcher = null;
|
|
344
|
+
let watcherDebounceTimer = null;
|
|
345
|
+
let garnishInFlight = false;
|
|
346
|
+
if (args.garnish) {
|
|
347
|
+
const { watch } = await import("node:fs");
|
|
348
|
+
const { runGarnish } = await import("../garnish/index.js");
|
|
349
|
+
const watchTarget = join(mockDir, "src");
|
|
350
|
+
console.log(`[run-mock] watching ${watchTarget.replace(args.repoRoot + "/", "")} for file saves (debounce 1.5s)`);
|
|
351
|
+
const onSaveBatch = async () => {
|
|
352
|
+
if (garnishInFlight)
|
|
353
|
+
return; // skip overlapping runs
|
|
354
|
+
garnishInFlight = true;
|
|
355
|
+
try {
|
|
356
|
+
console.log(`\n[run-mock] file save detected; running tests + garnishing...`);
|
|
357
|
+
const result = await runGarnish({
|
|
358
|
+
repoRoot: args.repoRoot,
|
|
359
|
+
push: false,
|
|
360
|
+
});
|
|
361
|
+
if (result.kind === "no-changes") {
|
|
362
|
+
console.log(`[run-mock] no committable changes (test files or transient saves).`);
|
|
363
|
+
}
|
|
364
|
+
else if (result.kind === "tests-failed") {
|
|
365
|
+
console.log(`[run-mock] ✗ tests failed; not committing. Leave the file as-is + fix, slowcook will re-test on next save.`);
|
|
366
|
+
const tail = result.outputTail.split("\n").slice(-12).join("\n");
|
|
367
|
+
console.log(` ${tail.replace(/\n/g, "\n ")}`);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
console.log(`[run-mock] ✓ garnished ${result.sha.slice(0, 7)} (${result.touchedFiles.length} file(s), ${result.agentRefCount} agent ref(s))`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
finally {
|
|
374
|
+
garnishInFlight = false;
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
try {
|
|
378
|
+
watcher = watch(watchTarget, { recursive: true }, (_eventType, filename) => {
|
|
379
|
+
if (!filename)
|
|
380
|
+
return;
|
|
381
|
+
const f = filename.toString();
|
|
382
|
+
if (f.startsWith("node_modules/"))
|
|
383
|
+
return;
|
|
384
|
+
if (f.startsWith(".next/"))
|
|
385
|
+
return;
|
|
386
|
+
if (f.startsWith("scenarios/"))
|
|
387
|
+
return; // vibe's output; tweaking these by hand is unusual
|
|
388
|
+
if (!/\.(tsx?|css|json)$/.test(f))
|
|
389
|
+
return;
|
|
390
|
+
if (watcherDebounceTimer)
|
|
391
|
+
clearTimeout(watcherDebounceTimer);
|
|
392
|
+
watcherDebounceTimer = setTimeout(() => { void onSaveBatch(); }, 1500);
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
catch (e) {
|
|
396
|
+
console.warn(`[run-mock] could not start file watcher (${e.message}); --garnish mode disabled.`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
302
399
|
// Step 6: clean shutdown on Ctrl-C / dev exit. Pop any stash we
|
|
303
400
|
// pushed in step 1 so the user's working tree is restored to its
|
|
304
401
|
// pre-run-mock state — same UX guarantee as `git stash pop` after
|
|
@@ -306,6 +403,16 @@ export async function runMock(argv, _cliVersion) {
|
|
|
306
403
|
const cleanup = (signal) => {
|
|
307
404
|
if (pollTimer)
|
|
308
405
|
clearInterval(pollTimer);
|
|
406
|
+
if (watcher) {
|
|
407
|
+
try {
|
|
408
|
+
watcher.close();
|
|
409
|
+
}
|
|
410
|
+
catch { /* ignore */ }
|
|
411
|
+
}
|
|
412
|
+
if (watcherDebounceTimer) {
|
|
413
|
+
clearTimeout(watcherDebounceTimer);
|
|
414
|
+
watcherDebounceTimer = null;
|
|
415
|
+
}
|
|
309
416
|
if (proxy) {
|
|
310
417
|
try {
|
|
311
418
|
proxy.close();
|