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.
- package/dist/context/store.d.ts.map +1 -1
- package/dist/context/store.js +1 -0
- package/dist/context/store.js.map +1 -1
- package/dist/generators/claude.d.ts.map +1 -1
- package/dist/generators/claude.js +10 -27
- package/dist/generators/claude.js.map +1 -1
- package/dist/generators/codex.d.ts.map +1 -1
- package/dist/generators/codex.js +12 -34
- package/dist/generators/codex.js.map +1 -1
- package/dist/generators/copilot.d.ts.map +1 -1
- package/dist/generators/copilot.js +12 -27
- package/dist/generators/copilot.js.map +1 -1
- package/dist/generators/cursor.d.ts.map +1 -1
- package/dist/generators/cursor.js +11 -33
- package/dist/generators/cursor.js.map +1 -1
- package/dist/generators/gemini.d.ts.map +1 -1
- package/dist/generators/gemini.js +11 -26
- package/dist/generators/gemini.js.map +1 -1
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +97 -0
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/template.d.ts +10 -9
- package/dist/generators/template.d.ts.map +1 -1
- package/dist/generators/template.js +233 -312
- package/dist/generators/template.js.map +1 -1
- package/dist/generators/trae.d.ts.map +1 -1
- package/dist/generators/trae.js +11 -28
- package/dist/generators/trae.js.map +1 -1
- package/dist/generators/windsurf.d.ts.map +1 -1
- package/dist/generators/windsurf.js +11 -26
- package/dist/generators/windsurf.js.map +1 -1
- package/dist/scanner/index.d.ts.map +1 -1
- package/dist/scanner/index.js +4 -1
- package/dist/scanner/index.js.map +1 -1
- package/dist/scanner/rules.d.ts +3 -0
- package/dist/scanner/rules.d.ts.map +1 -0
- package/dist/scanner/rules.js +177 -0
- package/dist/scanner/rules.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- 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
|
-
//
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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(
|
|
28
|
+
lines.push(`Styling: ${ctx.conventions.styling}`);
|
|
26
29
|
}
|
|
27
30
|
if (ctx.conventions.stateManagement !== "None detected" && !coveredCategories.has("state")) {
|
|
28
|
-
lines.push(
|
|
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
|
|
36
|
+
export function buildRulesSection(ctx) {
|
|
37
|
+
if (!ctx.rules?.length)
|
|
38
|
+
return "";
|
|
40
39
|
const lines = [];
|
|
41
|
-
lines.push("##
|
|
40
|
+
lines.push("## Critical Rules");
|
|
42
41
|
lines.push("");
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
|
53
|
+
export function buildPatternsSection(ctx) {
|
|
54
|
+
if (!ctx.patterns)
|
|
55
|
+
return "";
|
|
56
|
+
const p = ctx.patterns;
|
|
60
57
|
const lines = [];
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
65
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
89
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
102
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
|
135
|
-
|
|
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
|
|
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
|
|
204
|
+
for (const f of model.fields) {
|
|
158
205
|
const tags = [];
|
|
159
|
-
if (
|
|
160
|
-
tags.push("
|
|
161
|
-
if (
|
|
206
|
+
if (f.primary)
|
|
207
|
+
tags.push("PK");
|
|
208
|
+
if (f.unique)
|
|
162
209
|
tags.push("unique");
|
|
163
|
-
if (
|
|
210
|
+
if (f.required === false)
|
|
164
211
|
tags.push("optional");
|
|
165
|
-
if (
|
|
166
|
-
tags.push(`default: ${
|
|
167
|
-
const
|
|
168
|
-
lines.push(`- **${
|
|
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
|
|
171
|
-
lines.push(`- **${
|
|
217
|
+
for (const r of model.relations) {
|
|
218
|
+
lines.push(`- **${r.name}** → ${r.target} (${r.type})`);
|
|
172
219
|
}
|
|
173
|
-
if (model.indexes
|
|
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
|
|
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
|
|
196
|
-
if (!ctx.
|
|
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("##
|
|
240
|
+
lines.push("## Modules");
|
|
230
241
|
lines.push("");
|
|
231
|
-
for (const
|
|
232
|
-
|
|
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
|
|
238
|
-
if (!ctx.modules?.length)
|
|
239
|
-
return "";
|
|
249
|
+
export function buildEnvServicesSection(ctx) {
|
|
240
250
|
const lines = [];
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
|
258
|
-
|
|
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("
|
|
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("
|
|
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
|
|
288
|
-
lines.push(`- **${skill.name}**${
|
|
289
|
-
if (skill.methods
|
|
290
|
-
for (const
|
|
291
|
-
lines.push(` - \`${
|
|
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("
|
|
326
|
+
lines.push("## Validation");
|
|
312
327
|
lines.push("");
|
|
313
|
-
for (const
|
|
314
|
-
const fields =
|
|
315
|
-
lines.push(`- \`${
|
|
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("
|
|
336
|
+
lines.push("## Auth & Permissions");
|
|
321
337
|
lines.push("");
|
|
322
|
-
for (const
|
|
323
|
-
lines.push(`- ${
|
|
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("
|
|
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
|
|
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("##
|
|
354
|
+
lines.push("## Documentation Index");
|
|
355
|
+
lines.push("Read these files for detailed context:");
|
|
341
356
|
lines.push("");
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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) {
|