project-context-ai 1.3.1 → 2.0.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.
Files changed (41) hide show
  1. package/dist/context/store.d.ts.map +1 -1
  2. package/dist/context/store.js +1 -0
  3. package/dist/context/store.js.map +1 -1
  4. package/dist/generators/claude.d.ts.map +1 -1
  5. package/dist/generators/claude.js +10 -27
  6. package/dist/generators/claude.js.map +1 -1
  7. package/dist/generators/codex.d.ts.map +1 -1
  8. package/dist/generators/codex.js +12 -34
  9. package/dist/generators/codex.js.map +1 -1
  10. package/dist/generators/copilot.d.ts.map +1 -1
  11. package/dist/generators/copilot.js +12 -27
  12. package/dist/generators/copilot.js.map +1 -1
  13. package/dist/generators/cursor.d.ts.map +1 -1
  14. package/dist/generators/cursor.js +11 -33
  15. package/dist/generators/cursor.js.map +1 -1
  16. package/dist/generators/gemini.d.ts.map +1 -1
  17. package/dist/generators/gemini.js +11 -26
  18. package/dist/generators/gemini.js.map +1 -1
  19. package/dist/generators/index.d.ts.map +1 -1
  20. package/dist/generators/index.js +97 -0
  21. package/dist/generators/index.js.map +1 -1
  22. package/dist/generators/template.d.ts +10 -9
  23. package/dist/generators/template.d.ts.map +1 -1
  24. package/dist/generators/template.js +233 -312
  25. package/dist/generators/template.js.map +1 -1
  26. package/dist/generators/trae.d.ts.map +1 -1
  27. package/dist/generators/trae.js +11 -28
  28. package/dist/generators/trae.js.map +1 -1
  29. package/dist/generators/windsurf.d.ts.map +1 -1
  30. package/dist/generators/windsurf.js +11 -26
  31. package/dist/generators/windsurf.js.map +1 -1
  32. package/dist/scanner/index.d.ts.map +1 -1
  33. package/dist/scanner/index.js +4 -1
  34. package/dist/scanner/index.js.map +1 -1
  35. package/dist/scanner/rules.d.ts +3 -0
  36. package/dist/scanner/rules.d.ts.map +1 -0
  37. package/dist/scanner/rules.js +177 -0
  38. package/dist/scanner/rules.js.map +1 -0
  39. package/dist/types.d.ts +6 -0
  40. package/dist/types.d.ts.map +1 -1
  41. package/package.json +1 -1
@@ -1,119 +1,169 @@
1
+ // ─── High-Signal Format: Rules → Stack → Patterns → Details → Pointers ───
1
2
  export function buildProjectOverview(ctx) {
2
3
  const lines = [];
3
4
  lines.push(`# ${ctx.meta.name}`);
4
5
  if (ctx.meta.description)
5
6
  lines.push(`\n${ctx.meta.description}`);
6
7
  lines.push("");
7
- // Tech stack summary
8
- lines.push("## Tech Stack");
9
- lines.push("");
10
- lines.push(`- **Type:** ${ctx.meta.type}`);
11
- lines.push(`- **Language(s):** ${ctx.meta.languages.join(", ")}`);
12
- if (ctx.dependencies.packageManager !== "unknown") {
13
- lines.push(`- **Package Manager:** ${ctx.dependencies.packageManager}`);
14
- }
8
+ // Compact tech stack (one-liners)
15
9
  const categories = groupFrameworksByCategory(ctx);
16
- // Track which categories are already covered by frameworks
17
10
  const coveredCategories = new Set(Object.keys(categories));
18
- for (const [category, fws] of Object.entries(categories)) {
19
- const label = capitalize(category);
20
- const names = fws.map((f) => `${f.name} (${f.version})`).join(", ");
21
- lines.push(`- **${label}:** ${names}`);
22
- }
23
- // Only add conventions that aren't already covered by frameworks
11
+ const stackParts = [];
12
+ stackParts.push(ctx.meta.languages.join(", "));
13
+ if (ctx.dependencies.packageManager !== "unknown")
14
+ stackParts.push(ctx.dependencies.packageManager);
15
+ const fwParts = [];
16
+ for (const [, fws] of Object.entries(categories)) {
17
+ for (const fw of fws)
18
+ fwParts.push(`${fw.name} ${fw.version.replace(/^\^/, "")}`);
19
+ }
20
+ if (fwParts.length > 0)
21
+ stackParts.push(fwParts.join(", "));
22
+ if (ctx.conventions.api)
23
+ stackParts.push(ctx.conventions.api);
24
+ lines.push(`## Tech Stack`);
25
+ lines.push(`${stackParts.join(" | ")}`);
26
+ // Extra lines only for non-covered info
24
27
  if (ctx.conventions.styling !== "CSS" && !coveredCategories.has("styling")) {
25
- lines.push(`- **Styling:** ${ctx.conventions.styling}`);
28
+ lines.push(`Styling: ${ctx.conventions.styling}`);
26
29
  }
27
30
  if (ctx.conventions.stateManagement !== "None detected" && !coveredCategories.has("state")) {
28
- lines.push(`- **State:** ${ctx.conventions.stateManagement}`);
29
- }
30
- if (ctx.conventions.api) {
31
- lines.push(`- **API Pattern:** ${ctx.conventions.api}`);
32
- }
33
- if (ctx.conventions.testing !== "No testing framework detected" && !coveredCategories.has("testing")) {
34
- lines.push(`- **Testing:** ${ctx.conventions.testing}`);
31
+ lines.push(`State: ${ctx.conventions.stateManagement}`);
35
32
  }
36
33
  lines.push("");
37
34
  return lines.join("\n");
38
35
  }
39
- export function buildStructureSection(ctx) {
36
+ export function buildRulesSection(ctx) {
37
+ if (!ctx.rules?.length)
38
+ return "";
40
39
  const lines = [];
41
- lines.push("## Project Structure");
40
+ lines.push("## Critical Rules");
42
41
  lines.push("");
43
- lines.push("```");
44
- // Group by top-level directory
45
- const topLevel = ctx.structure.filter((d) => !d.path.includes("/"));
46
- const nested = ctx.structure.filter((d) => d.path.includes("/"));
47
- for (const dir of topLevel) {
48
- lines.push(`${dir.path}/ — ${dir.description} (${dir.fileCount} files)`);
49
- const children = nested.filter((d) => d.path.startsWith(dir.path + "/") && d.path.split("/").length === 2);
50
- for (const child of children) {
51
- const childName = child.path.split("/").pop();
52
- lines.push(` ${childName}/ — ${child.description} (${child.fileCount} files)`);
53
- }
42
+ const nevers = ctx.rules.filter((r) => r.type === "never");
43
+ const always = ctx.rules.filter((r) => r.type === "always");
44
+ for (const r of nevers) {
45
+ lines.push(`- NEVER ${r.rule}`);
46
+ }
47
+ for (const r of always) {
48
+ lines.push(`- ALWAYS ${r.rule}`);
54
49
  }
55
- lines.push("```");
56
50
  lines.push("");
57
51
  return lines.join("\n");
58
52
  }
59
- export function buildKeyFilesSection(ctx) {
53
+ export function buildPatternsSection(ctx) {
54
+ if (!ctx.patterns)
55
+ return "";
56
+ const p = ctx.patterns;
60
57
  const lines = [];
61
- if (ctx.keyFiles.length > 0) {
62
- lines.push("## Key Files");
58
+ lines.push("## Code Patterns");
59
+ lines.push("");
60
+ // DI
61
+ if (p.di) {
62
+ lines.push(`**DI:** ${p.di}`);
63
+ const diEx = p.codeExamples.find((e) => e.category === "di");
64
+ if (diEx) {
65
+ lines.push("```typescript");
66
+ lines.push(diEx.code);
67
+ lines.push("```");
68
+ }
63
69
  lines.push("");
64
- for (const kf of ctx.keyFiles) {
65
- lines.push(`- \`${kf.path}\` — ${kf.role}`);
70
+ }
71
+ // Imports
72
+ if (p.imports.length > 0) {
73
+ lines.push("**Imports:**");
74
+ for (const imp of p.imports) {
75
+ const icon = imp.toLowerCase().includes("no ") || imp.toLowerCase().includes("never") ? "❌" : "✅";
76
+ lines.push(`- ${icon} ${imp}`);
66
77
  }
67
78
  lines.push("");
68
79
  }
69
- return lines.join("\n");
70
- }
71
- export function buildEntryPointsSection(ctx) {
72
- const lines = [];
73
- if (ctx.entryPoints.length > 0) {
74
- lines.push("## Entry Points");
80
+ // Error handling
81
+ if (p.errorHandling.length > 0) {
82
+ const bases = [...new Set(p.errorHandling.map((e) => e.extendsFrom))];
83
+ lines.push(`**Errors:** Custom classes extending ${bases.join(", ")}`);
84
+ for (const err of p.errorHandling.slice(0, 8)) {
85
+ lines.push(`- \`${err.className}\` → \`${err.file}\``);
86
+ }
87
+ const errEx = p.codeExamples.find((e) => e.category === "error-handling");
88
+ if (errEx) {
89
+ lines.push("```typescript");
90
+ lines.push(errEx.code);
91
+ lines.push("```");
92
+ }
75
93
  lines.push("");
76
- for (const ep of ctx.entryPoints) {
77
- lines.push(`- \`${ep}\``);
94
+ }
95
+ // Testing
96
+ if (p.testPatterns) {
97
+ const t = p.testPatterns;
98
+ const parts = [`**Testing:** ${t.framework}`];
99
+ if (t.coverageThreshold !== null)
100
+ parts.push(`${t.coverageThreshold}% coverage`);
101
+ parts.push(`\`${t.unitFilePattern}\``);
102
+ if (t.integrationFilePattern)
103
+ parts.push(`integration: \`${t.integrationFilePattern}\``);
104
+ if (t.assertionStyle)
105
+ parts.push(t.assertionStyle);
106
+ lines.push(parts.join(" | "));
107
+ lines.push("");
108
+ }
109
+ // Architecture rules
110
+ if (p.architecturalRules.length > 0) {
111
+ lines.push("**Architecture Rules:**");
112
+ for (const rule of p.architecturalRules) {
113
+ const icon = rule.toLowerCase().includes("not") || rule.toLowerCase().includes("forbidden") ? "❌" : "✅";
114
+ lines.push(`- ${icon} ${rule}`);
78
115
  }
79
116
  lines.push("");
80
117
  }
81
- return lines.join("\n");
82
- }
83
- export function buildScriptsSection(ctx) {
84
- const lines = [];
85
- if (Object.keys(ctx.scripts).length > 0) {
86
- lines.push("## Available Scripts");
118
+ // Naming (compact)
119
+ const namingParts = [`Files: ${p.naming.files}`, `Vars: ${p.naming.variables}`];
120
+ if (p.naming.dbColumns !== "unknown")
121
+ namingParts.push(`DB: ${p.naming.dbColumns}`);
122
+ lines.push(`**Naming:** ${namingParts.join(" | ")}`);
123
+ lines.push("");
124
+ // Code conventions
125
+ if (p.codeConventions.length > 0) {
126
+ for (const conv of p.codeConventions)
127
+ lines.push(`- ${conv}`);
87
128
  lines.push("");
88
- for (const [name, cmd] of Object.entries(ctx.scripts)) {
89
- lines.push(`- \`${ctx.dependencies.packageManager} run ${name}\` — \`${cmd}\``);
129
+ }
130
+ // Code examples (non-DI, non-error)
131
+ const otherExamples = p.codeExamples.filter((e) => !["di", "error-handling"].includes(e.category));
132
+ if (otherExamples.length > 0) {
133
+ lines.push("### Code Examples");
134
+ for (const ex of otherExamples) {
135
+ lines.push(`**${ex.label}** (\`${ex.file}\`):`);
136
+ lines.push("```typescript");
137
+ lines.push(ex.code);
138
+ lines.push("```");
139
+ lines.push("");
90
140
  }
141
+ }
142
+ // Workflows
143
+ if (p.workflows.length > 0) {
144
+ lines.push("### Workflows");
145
+ for (const wf of p.workflows)
146
+ lines.push(`- ${wf}`);
91
147
  lines.push("");
92
148
  }
93
- return lines.join("\n");
94
- }
95
- export function buildDependenciesSection(ctx) {
96
- const lines = [];
97
- const importantDeps = ctx.dependencies.runtime.filter((d) => d.purpose);
98
- if (importantDeps.length > 0) {
99
- lines.push("## Key Dependencies");
149
+ // IDE Skills table
150
+ if (p.ideSkills.length > 0) {
151
+ lines.push("### IDE Skills");
100
152
  lines.push("");
101
- for (const dep of importantDeps) {
102
- lines.push(`- **${dep.name}** (${dep.version}) — ${dep.purpose}`);
153
+ lines.push("| Skill | File | Activates On |");
154
+ lines.push("|-------|------|-------------|");
155
+ for (const s of p.ideSkills) {
156
+ lines.push(`| ${s.name} | \`${s.file}\` | ${s.activatesOn || "manual"} |`);
103
157
  }
104
158
  lines.push("");
105
159
  }
106
- return lines.join("\n");
107
- }
108
- export function buildArchitectureSection(ctx) {
109
- const lines = [];
110
- lines.push("## Architecture");
111
- lines.push("");
112
- lines.push(`- **Pattern:** ${ctx.conventions.architecture}`);
113
- if (ctx.conventions.api) {
114
- lines.push(`- **API:** ${ctx.conventions.api}`);
160
+ // IDE Commands
161
+ if (p.ideCommands.length > 0) {
162
+ lines.push("### IDE Commands");
163
+ for (const c of p.ideCommands)
164
+ lines.push(`- \`/${c.name}\` — ${c.description}`);
165
+ lines.push("");
115
166
  }
116
- lines.push("");
117
167
  return lines.join("\n");
118
168
  }
119
169
  export function buildRoutesSection(ctx) {
@@ -131,16 +181,14 @@ export function buildRoutesSection(ctx) {
131
181
  }
132
182
  lines.push(header);
133
183
  lines.push(sep);
134
- const routes = ctx.routes.slice(0, 30);
135
- for (const r of routes) {
136
- let row = `| ${r.method} | ${r.path} | \`${r.file}\` | ${r.auth ? "Yes" : "No"} |`;
184
+ for (const r of ctx.routes.slice(0, 30)) {
185
+ let row = `| ${r.method} | ${r.path} | \`${r.file}\` | ${r.auth ? "✓" : "—"} |`;
137
186
  if (hasHandlers)
138
- row += ` ${r.handler || "-"} |`;
187
+ row += ` ${r.handler || ""} |`;
139
188
  lines.push(row);
140
189
  }
141
190
  if (ctx.routes.length > 30) {
142
- lines.push("");
143
- lines.push(`> ${ctx.routes.length} routes total (showing first 30)`);
191
+ lines.push(`\n> ${ctx.routes.length} routes total`);
144
192
  }
145
193
  lines.push("");
146
194
  return lines.join("\n");
@@ -151,123 +199,102 @@ export function buildDatabaseSection(ctx) {
151
199
  const lines = [];
152
200
  lines.push("## Database Schema");
153
201
  lines.push("");
154
- const models = ctx.database.slice(0, 15);
155
- for (const model of models) {
202
+ for (const model of ctx.database.slice(0, 15)) {
156
203
  lines.push(`### ${model.name} (${model.source})`);
157
- for (const field of model.fields) {
204
+ for (const f of model.fields) {
158
205
  const tags = [];
159
- if (field.primary)
160
- tags.push("primary");
161
- if (field.unique)
206
+ if (f.primary)
207
+ tags.push("PK");
208
+ if (f.unique)
162
209
  tags.push("unique");
163
- if (field.required === false)
210
+ if (f.required === false)
164
211
  tags.push("optional");
165
- if (field.defaultValue)
166
- tags.push(`default: ${field.defaultValue}`);
167
- const tagStr = tags.length ? ` (${tags.join(", ")})` : "";
168
- lines.push(`- **${field.name}** ${field.type}${tagStr}`);
212
+ if (f.defaultValue)
213
+ tags.push(`default: ${f.defaultValue}`);
214
+ const t = tags.length ? ` (${tags.join(", ")})` : "";
215
+ lines.push(`- **${f.name}** ${f.type}${t}`);
169
216
  }
170
- for (const rel of model.relations) {
171
- lines.push(`- **${rel.name}** → ${rel.target} (${rel.type})`);
217
+ for (const r of model.relations) {
218
+ lines.push(`- **${r.name}** → ${r.target} (${r.type})`);
172
219
  }
173
- if (model.indexes && model.indexes.length > 0) {
174
- lines.push("");
175
- lines.push("**Indexes:**");
220
+ if (model.indexes?.length) {
176
221
  for (const idx of model.indexes) {
177
- lines.push(`- ${idx.unique ? "unique" : "index"}(${idx.fields.join(", ")})`);
222
+ lines.push(`- 📇 ${idx.unique ? "unique" : "index"}(${idx.fields.join(", ")})`);
178
223
  }
179
224
  }
180
- if (model.enums && model.enums.length > 0) {
181
- lines.push("");
182
- lines.push("**Enums:**");
225
+ if (model.enums?.length) {
183
226
  for (const en of model.enums) {
184
- lines.push(`- \`${en.name}\`: ${en.values.join(", ")}`);
227
+ lines.push(`- 📋 \`${en.name}\`: ${en.values.join(" | ")}`);
185
228
  }
186
229
  }
187
230
  lines.push("");
188
231
  }
189
- if (ctx.database.length > 15) {
190
- lines.push(`> ... and ${ctx.database.length - 15} more models`);
191
- lines.push("");
192
- }
232
+ if (ctx.database.length > 15)
233
+ lines.push(`> ... and ${ctx.database.length - 15} more models\n`);
193
234
  return lines.join("\n");
194
235
  }
195
- export function buildEnvVarsSection(ctx) {
196
- if (!ctx.envVars?.length)
197
- return "";
198
- const lines = [];
199
- lines.push("## Environment Variables");
200
- lines.push("");
201
- // Group by category
202
- const groups = new Map();
203
- for (const v of ctx.envVars) {
204
- if (!groups.has(v.category))
205
- groups.set(v.category, []);
206
- groups.get(v.category).push(v);
207
- }
208
- const categoryLabels = {
209
- database: "Database",
210
- auth: "Auth",
211
- "api-key": "API Keys",
212
- service: "Services",
213
- "feature-flag": "Feature Flags",
214
- config: "Config",
215
- other: "Other",
216
- };
217
- for (const [category, vars] of groups) {
218
- const label = categoryLabels[category] || capitalize(category);
219
- const varList = vars.map((v) => `\`${v.name}\`${v.required ? " (required)" : ""}`).join(", ");
220
- lines.push(`**${label}:** ${varList}`);
221
- lines.push("");
222
- }
223
- return lines.join("\n");
224
- }
225
- export function buildServicesSection(ctx) {
226
- if (!ctx.services?.length)
236
+ export function buildModulesSection(ctx) {
237
+ if (!ctx.modules?.length)
227
238
  return "";
228
239
  const lines = [];
229
- lines.push("## External Services");
240
+ lines.push("## Modules");
230
241
  lines.push("");
231
- for (const svc of ctx.services) {
232
- lines.push(`- **${svc.name}** ${svc.type} (${svc.source})`);
242
+ for (const m of ctx.modules) {
243
+ const deps = m.dependsOn.length > 0 ? `→ ${m.dependsOn.join(", ")}` : "(no deps)";
244
+ lines.push(`- **${m.name}** (${m.files} files) ${deps}`);
233
245
  }
234
246
  lines.push("");
235
247
  return lines.join("\n");
236
248
  }
237
- export function buildModulesSection(ctx) {
238
- if (!ctx.modules?.length)
239
- return "";
249
+ export function buildEnvServicesSection(ctx) {
240
250
  const lines = [];
241
- lines.push("## Modules");
242
- lines.push("");
243
- for (const mod of ctx.modules) {
244
- const deps = mod.dependsOn.length > 0
245
- ? `depends on: ${mod.dependsOn.join(", ")}`
246
- : "no dependencies";
247
- lines.push(`- **${mod.name}** (${mod.files} files) → ${deps}`);
251
+ // Services (compact)
252
+ if (ctx.services?.length) {
253
+ lines.push("## External Services");
254
+ lines.push(ctx.services.map((s) => `**${s.name}** (${s.type})`).join(" · "));
255
+ lines.push("");
256
+ }
257
+ // Env vars (compact by category)
258
+ if (ctx.envVars?.length) {
259
+ lines.push("## Environment Variables");
260
+ lines.push("");
261
+ const groups = new Map();
262
+ for (const v of ctx.envVars) {
263
+ if (!groups.has(v.category))
264
+ groups.set(v.category, []);
265
+ groups.get(v.category).push(v);
266
+ }
267
+ const labels = {
268
+ database: "DB", auth: "Auth", "api-key": "API Keys",
269
+ service: "Services", "feature-flag": "Flags", config: "Config", other: "Other",
270
+ };
271
+ for (const [cat, vars] of groups) {
272
+ const label = labels[cat] || cat;
273
+ const required = vars.filter((v) => v.required).map((v) => `\`${v.name}\``);
274
+ const optional = vars.filter((v) => !v.required).map((v) => `\`${v.name}\``);
275
+ const parts = [];
276
+ if (required.length)
277
+ parts.push(required.join(", "));
278
+ if (optional.length)
279
+ parts.push(`optional: ${optional.join(", ")}`);
280
+ lines.push(`**${label}:** ${parts.join(" | ")}`);
281
+ }
282
+ lines.push("");
248
283
  }
249
- lines.push("");
250
284
  return lines.join("\n");
251
285
  }
252
286
  export function buildBusinessSection(ctx) {
253
287
  if (!ctx.business)
254
288
  return "";
255
- const lines = [];
256
289
  const biz = ctx.business;
257
- lines.push("## Business Context");
258
- lines.push("");
259
- if (biz.description) {
260
- lines.push(biz.description);
261
- lines.push("");
262
- }
290
+ const lines = [];
291
+ // Features
263
292
  if (biz.features.length > 0) {
264
- lines.push("### Features");
293
+ lines.push("## Features");
265
294
  lines.push("");
266
295
  for (const f of biz.features) {
267
- // Category markers from extractAllBullets start with [
268
296
  if (f.startsWith("[") && f.endsWith("]")) {
269
- lines.push("");
270
- lines.push(`**${f.slice(1, -1)}:**`);
297
+ lines.push(`\n**${f.slice(1, -1)}:**`);
271
298
  }
272
299
  else {
273
300
  lines.push(`- ${f}`);
@@ -275,8 +302,9 @@ export function buildBusinessSection(ctx) {
275
302
  }
276
303
  lines.push("");
277
304
  }
305
+ // Skills
278
306
  if (biz.skills.length > 0) {
279
- lines.push("### Skills / Plugins");
307
+ lines.push("## Skills / Plugins");
280
308
  lines.push("");
281
309
  const interfaces = new Set(biz.skills.map((s) => s.interface).filter(Boolean));
282
310
  if (interfaces.size === 1) {
@@ -284,181 +312,74 @@ export function buildBusinessSection(ctx) {
284
312
  lines.push("");
285
313
  }
286
314
  for (const skill of biz.skills) {
287
- const toolInfo = skill.toolCount ? ` (${skill.toolCount} tools)` : "";
288
- lines.push(`- **${skill.name}**${toolInfo} — \`${skill.file}\``);
289
- if (skill.methods && skill.methods.length > 0) {
290
- for (const method of skill.methods.slice(0, 5)) {
291
- lines.push(` - \`${method}\``);
292
- }
293
- }
294
- }
295
- lines.push("");
296
- }
297
- if (biz.documentation.length > 0) {
298
- lines.push("### Documentation");
299
- lines.push("");
300
- for (const doc of biz.documentation) {
301
- lines.push(`- **${doc.title}** (\`${doc.file}\`) — ${doc.summary}`);
302
- if (doc.keyRules && doc.keyRules.length > 0) {
303
- for (const rule of doc.keyRules) {
304
- lines.push(` - ⚠️ ${rule}`);
305
- }
315
+ const tools = skill.toolCount ? ` (${skill.toolCount} tools)` : "";
316
+ lines.push(`- **${skill.name}**${tools} — \`${skill.file}\``);
317
+ if (skill.methods?.length) {
318
+ for (const m of skill.methods.slice(0, 4))
319
+ lines.push(` - \`${m}\``);
306
320
  }
307
321
  }
308
322
  lines.push("");
309
323
  }
324
+ // Validation rules
310
325
  if (biz.validationRules.length > 0) {
311
- lines.push("### Validation Rules");
326
+ lines.push("## Validation");
312
327
  lines.push("");
313
- for (const rule of biz.validationRules) {
314
- const fields = rule.fields.length > 0 ? ` — ${rule.fields.join(", ")}` : "";
315
- lines.push(`- \`${rule.schema}\` (${rule.library})${fields}`);
328
+ for (const r of biz.validationRules) {
329
+ const fields = r.fields.length > 0 ? ` — ${r.fields.join(", ")}` : "";
330
+ lines.push(`- \`${r.schema}\` (${r.library})${fields}`);
316
331
  }
317
332
  lines.push("");
318
333
  }
334
+ // Auth
319
335
  if (biz.authPatterns.length > 0) {
320
- lines.push("### Auth & Permissions");
336
+ lines.push("## Auth & Permissions");
321
337
  lines.push("");
322
- for (const pattern of biz.authPatterns) {
323
- lines.push(`- ${pattern}`);
324
- }
338
+ for (const p of biz.authPatterns)
339
+ lines.push(`- ${p}`);
325
340
  lines.push("");
326
341
  }
342
+ // Domain entities
327
343
  if (biz.domainEntities.length > 0) {
328
- lines.push("### Domain Entities");
329
- lines.push("");
344
+ lines.push("## Domain Entities");
330
345
  lines.push(biz.domainEntities.join(", "));
331
346
  lines.push("");
332
347
  }
333
348
  return lines.join("\n");
334
349
  }
335
- export function buildPatternsSection(ctx) {
336
- if (!ctx.patterns)
350
+ export function buildDocIndexSection(ctx) {
351
+ if (!ctx.business?.documentation?.length && !ctx.patterns?.ideSkills?.length)
337
352
  return "";
338
- const p = ctx.patterns;
339
353
  const lines = [];
340
- lines.push("## Code Patterns & Conventions");
354
+ lines.push("## Documentation Index");
355
+ lines.push("Read these files for detailed context:");
341
356
  lines.push("");
342
- // ─── DI with code example ───
343
- if (p.di) {
344
- lines.push("### Dependency Injection");
345
- lines.push(`Uses ${p.di}`);
346
- const diEx = p.codeExamples.find((e) => e.category === "di");
347
- if (diEx) {
348
- lines.push("```typescript");
349
- lines.push(`// ${diEx.file}`);
350
- lines.push(diEx.code);
351
- lines.push("```");
352
- }
353
- lines.push("");
354
- }
355
- // ─── Import rules ───
356
- if (p.imports.length > 0) {
357
- lines.push("### Import Rules");
358
- for (const imp of p.imports) {
359
- const isPositive = imp.toLowerCase().includes("relative") || imp.toLowerCase().includes("barrel");
360
- const isNegative = imp.toLowerCase().includes("no ") || imp.toLowerCase().includes("never");
361
- lines.push(`- ${isNegative ? "❌" : isPositive ? "✅" : "•"} ${imp}`);
362
- }
363
- lines.push("");
364
- }
365
- // ─── Error handling ───
366
- if (p.errorHandling.length > 0) {
367
- lines.push("### Error Handling");
368
- const baseClasses = [...new Set(p.errorHandling.map((e) => e.extendsFrom))];
369
- lines.push(`Custom errors extending ${baseClasses.join(", ")}:`);
370
- lines.push("");
371
- for (const err of p.errorHandling.slice(0, 10)) {
372
- lines.push(`- \`${err.className}\` extends \`${err.extendsFrom}\` — \`${err.file}\``);
373
- }
374
- const errEx = p.codeExamples.find((e) => e.category === "error-handling");
375
- if (errEx) {
376
- lines.push("");
377
- lines.push("```typescript");
378
- lines.push(`// ${errEx.file}`);
379
- lines.push(errEx.code);
380
- lines.push("```");
357
+ if (ctx.business?.documentation) {
358
+ for (const doc of ctx.business.documentation) {
359
+ lines.push(`- \`${doc.file}\` — ${doc.title}`);
360
+ if (doc.keyRules?.length) {
361
+ for (const rule of doc.keyRules)
362
+ lines.push(` - ⚠️ ${rule}`);
363
+ }
381
364
  }
382
- lines.push("");
383
365
  }
384
- // ─── Testing ───
385
- if (p.testPatterns) {
386
- const t = p.testPatterns;
387
- lines.push("### Testing");
388
- lines.push(`- **Framework:** ${t.framework}`);
389
- if (t.coverageThreshold !== null)
390
- lines.push(`- **Coverage threshold:** ${t.coverageThreshold}%`);
391
- lines.push(`- **Unit tests:** \`${t.unitFilePattern}\` in \`${t.testDir}\``);
392
- if (t.integrationFilePattern)
393
- lines.push(`- **Integration tests:** \`${t.integrationFilePattern}\``);
394
- if (t.assertionStyle)
395
- lines.push(`- **Assertion style:** ${t.assertionStyle}`);
396
- lines.push("");
397
- }
398
- // ─── Architecture rules ───
399
- if (p.architecturalRules.length > 0) {
400
- lines.push("### Architecture Rules");
401
- for (const rule of p.architecturalRules) {
402
- const isNeg = rule.toLowerCase().includes("not") || rule.toLowerCase().includes("forbidden");
403
- lines.push(`- ${isNeg ? "❌" : "✅"} ${rule}`);
366
+ if (ctx.patterns?.ideSkills?.length) {
367
+ for (const skill of ctx.patterns.ideSkills) {
368
+ const when = skill.activatesOn ? ` (read when editing ${skill.activatesOn})` : "";
369
+ lines.push(`- \`${skill.file}\` — ${skill.description || skill.name}${when}`);
404
370
  }
405
- lines.push("");
406
371
  }
407
- // ─── Naming ───
408
- lines.push("### Naming Conventions");
409
- lines.push(`- **Files:** ${p.naming.files}`);
410
- lines.push(`- **Variables:** ${p.naming.variables}`);
411
- if (p.naming.dbColumns !== "unknown")
412
- lines.push(`- **DB columns:** ${p.naming.dbColumns}`);
413
372
  lines.push("");
414
- // ─── Code conventions ───
415
- if (p.codeConventions.length > 0) {
416
- lines.push("### Code Conventions");
417
- for (const conv of p.codeConventions)
418
- lines.push(`- ${conv}`);
419
- lines.push("");
420
- }
421
- // ─── Code examples ───
422
- const otherExamples = p.codeExamples.filter((e) => !["di", "error-handling"].includes(e.category));
423
- if (otherExamples.length > 0) {
424
- lines.push("### Code Examples");
425
- lines.push("");
426
- for (const ex of otherExamples) {
427
- lines.push(`**${ex.label}** (\`${ex.file}\`):`);
428
- lines.push("```typescript");
429
- lines.push(ex.code);
430
- lines.push("```");
431
- lines.push("");
432
- }
433
- }
434
- // ─── Workflows ───
435
- if (p.workflows.length > 0) {
436
- lines.push("### Workflows");
437
- for (const wf of p.workflows)
438
- lines.push(`- ${wf}`);
439
- lines.push("");
440
- }
441
- // ─── IDE Skills ───
442
- if (p.ideSkills.length > 0) {
443
- lines.push("### IDE Skills");
444
- lines.push("");
445
- lines.push("| Skill | File | Activates On |");
446
- lines.push("|-------|------|-------------|");
447
- for (const skill of p.ideSkills) {
448
- lines.push(`| ${skill.name} | \`${skill.file}\` | ${skill.activatesOn || "manual"} |`);
449
- }
450
- lines.push("");
451
- }
452
- // ─── IDE Commands ───
453
- if (p.ideCommands.length > 0) {
454
- lines.push("### IDE Commands");
455
- for (const cmd of p.ideCommands) {
456
- lines.push(`- \`/${cmd.name}\` — ${cmd.description} (\`${cmd.file}\`)`);
457
- }
458
- lines.push("");
459
- }
460
373
  return lines.join("\n");
461
374
  }
375
+ // ─── Legacy exports (kept for backward compat but now unused by generators) ───
376
+ export function buildStructureSection(_ctx) { return ""; }
377
+ export function buildKeyFilesSection(_ctx) { return ""; }
378
+ export function buildEntryPointsSection(_ctx) { return ""; }
379
+ export function buildScriptsSection(_ctx) { return ""; }
380
+ export function buildDependenciesSection(_ctx) { return ""; }
381
+ export function buildArchitectureSection(_ctx) { return ""; }
382
+ // ─── Helpers ──────────────────────────────────────────────
462
383
  function groupFrameworksByCategory(ctx) {
463
384
  const groups = {};
464
385
  for (const fw of ctx.frameworks) {