@neurcode-ai/cli 0.8.3 → 0.8.5

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.
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Project Knowledge Service
3
+ *
4
+ * Detects and maintains persistent knowledge about project tech stack and architecture.
5
+ * This service provides context-aware information that helps the Architect make better decisions.
6
+ *
7
+ * Features:
8
+ * - Tech stack detection (Node.js, Python, Go)
9
+ * - Architecture pattern detection and memory
10
+ * - Persistent storage in .neurcode/architecture.json
11
+ * - Natural language project summaries
12
+ */
13
+ import { z } from 'zod';
14
+ /**
15
+ * Architecture pattern types
16
+ */
17
+ export type ArchitecturePattern = 'feature-based' | 'layered' | 'mvc' | 'unknown';
18
+ /**
19
+ * Architecture memory schema
20
+ */
21
+ declare const ArchitectureMemorySchema: z.ZodObject<{
22
+ pattern: z.ZodEnum<{
23
+ unknown: "unknown";
24
+ "feature-based": "feature-based";
25
+ layered: "layered";
26
+ mvc: "mvc";
27
+ }>;
28
+ invariants: z.ZodArray<z.ZodString>;
29
+ domainBoundaries: z.ZodArray<z.ZodString>;
30
+ }, z.core.$strip>;
31
+ export type ArchitectureMemory = z.infer<typeof ArchitectureMemorySchema>;
32
+ /**
33
+ * Tech stack information
34
+ */
35
+ export interface TechStack {
36
+ language: 'node' | 'python' | 'go' | 'unknown';
37
+ framework?: string;
38
+ orm?: string;
39
+ styling?: string;
40
+ buildTool?: string;
41
+ packageManager?: string;
42
+ version?: string;
43
+ }
44
+ /**
45
+ * Project summary combining tech stack and architecture
46
+ */
47
+ export interface ProjectSummary {
48
+ techStack: TechStack;
49
+ architecture: ArchitectureMemory;
50
+ summary: string;
51
+ }
52
+ export declare class ProjectKnowledgeService {
53
+ /**
54
+ * Detect tech stack from project root
55
+ */
56
+ detectTechStack(rootPath: string): Promise<TechStack>;
57
+ /**
58
+ * Detect Node.js framework from package.json
59
+ */
60
+ private detectNodeFramework;
61
+ /**
62
+ * Detect Node.js ORM from package.json
63
+ */
64
+ private detectNodeORM;
65
+ /**
66
+ * Detect styling library from package.json
67
+ */
68
+ private detectStyling;
69
+ /**
70
+ * Detect build tool from package.json
71
+ */
72
+ private detectBuildTool;
73
+ /**
74
+ * Detect package manager from lock files
75
+ */
76
+ private detectPackageManager;
77
+ /**
78
+ * Detect Python framework from requirements.txt
79
+ */
80
+ private detectPythonFramework;
81
+ /**
82
+ * Detect Python ORM from requirements.txt
83
+ */
84
+ private detectPythonORM;
85
+ /**
86
+ * Detect Go framework from go.mod
87
+ */
88
+ private detectGoFramework;
89
+ /**
90
+ * Detect Go ORM from go.mod
91
+ */
92
+ private detectGoORM;
93
+ /**
94
+ * Detect architecture pattern from folder structure
95
+ */
96
+ private detectArchitecturePattern;
97
+ /**
98
+ * Detect domain boundaries from folder structure
99
+ */
100
+ private detectDomainBoundaries;
101
+ /**
102
+ * Generate default invariants based on architecture pattern
103
+ */
104
+ private generateDefaultInvariants;
105
+ /**
106
+ * Read architecture memory from .neurcode/architecture.json
107
+ */
108
+ readArchitectureMemory(rootPath: string): Promise<ArchitectureMemory | null>;
109
+ /**
110
+ * Write architecture memory to .neurcode/architecture.json
111
+ */
112
+ writeArchitectureMemory(rootPath: string, memory: ArchitectureMemory): Promise<void>;
113
+ /**
114
+ * Initialize architecture memory with defaults based on folder structure
115
+ */
116
+ initializeArchitectureMemory(rootPath: string): Promise<ArchitectureMemory>;
117
+ /**
118
+ * Get or create architecture memory (reads from disk or initializes)
119
+ */
120
+ getArchitectureMemory(rootPath: string): Promise<ArchitectureMemory>;
121
+ /**
122
+ * Generate natural language project summary
123
+ */
124
+ getProjectSummary(rootPath: string): Promise<ProjectSummary>;
125
+ }
126
+ export {};
127
+ //# sourceMappingURL=project-knowledge-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-knowledge-service.d.ts","sourceRoot":"","sources":["../../src/services/project-knowledge-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;AAElF;;GAEG;AACH,QAAA,MAAM,wBAAwB;;;;;;;;;iBAI5B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,EAAE,kBAAkB,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,uBAAuB;IAClC;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IA6F3D;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAwC3B;;OAEG;IACH,OAAO,CAAC,aAAa;IAgBrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAiBrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAgBvB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAS5B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAY7B;;OAEG;IACH,OAAO,CAAC,eAAe;IAYvB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAqCjC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA2C9B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA8BjC;;OAEG;IACG,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAmBlF;;OAEG;IACG,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB1F;;OAEG;IACG,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAiBjF;;OAEG;IACG,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAW1E;;OAEG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAgEnE"}
@@ -0,0 +1,535 @@
1
+ "use strict";
2
+ /**
3
+ * Project Knowledge Service
4
+ *
5
+ * Detects and maintains persistent knowledge about project tech stack and architecture.
6
+ * This service provides context-aware information that helps the Architect make better decisions.
7
+ *
8
+ * Features:
9
+ * - Tech stack detection (Node.js, Python, Go)
10
+ * - Architecture pattern detection and memory
11
+ * - Persistent storage in .neurcode/architecture.json
12
+ * - Natural language project summaries
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ProjectKnowledgeService = void 0;
16
+ const fs_1 = require("fs");
17
+ const path_1 = require("path");
18
+ const zod_1 = require("zod");
19
+ /**
20
+ * Architecture memory schema
21
+ */
22
+ const ArchitectureMemorySchema = zod_1.z.object({
23
+ pattern: zod_1.z.enum(['feature-based', 'layered', 'mvc', 'unknown']),
24
+ invariants: zod_1.z.array(zod_1.z.string()),
25
+ domainBoundaries: zod_1.z.array(zod_1.z.string()),
26
+ });
27
+ class ProjectKnowledgeService {
28
+ /**
29
+ * Detect tech stack from project root
30
+ */
31
+ async detectTechStack(rootPath) {
32
+ const techStack = {
33
+ language: 'unknown',
34
+ };
35
+ // Try Node.js (package.json)
36
+ const packageJsonPath = (0, path_1.join)(rootPath, 'package.json');
37
+ if ((0, fs_1.existsSync)(packageJsonPath)) {
38
+ try {
39
+ const packageJson = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, 'utf-8'));
40
+ techStack.language = 'node';
41
+ techStack.packageManager = this.detectPackageManager(rootPath);
42
+ techStack.version = packageJson.version;
43
+ // Detect framework
44
+ techStack.framework = this.detectNodeFramework(packageJson);
45
+ // Detect ORM
46
+ techStack.orm = this.detectNodeORM(packageJson);
47
+ // Detect styling
48
+ techStack.styling = this.detectStyling(packageJson);
49
+ // Detect build tool
50
+ techStack.buildTool = this.detectBuildTool(packageJson);
51
+ return techStack;
52
+ }
53
+ catch (error) {
54
+ console.warn('Failed to parse package.json:', error);
55
+ }
56
+ }
57
+ // Try Python (requirements.txt or pyproject.toml)
58
+ const requirementsPath = (0, path_1.join)(rootPath, 'requirements.txt');
59
+ const pyprojectPath = (0, path_1.join)(rootPath, 'pyproject.toml');
60
+ if ((0, fs_1.existsSync)(requirementsPath) || (0, fs_1.existsSync)(pyprojectPath)) {
61
+ techStack.language = 'python';
62
+ if ((0, fs_1.existsSync)(requirementsPath)) {
63
+ try {
64
+ const requirements = (0, fs_1.readFileSync)(requirementsPath, 'utf-8');
65
+ techStack.framework = this.detectPythonFramework(requirements);
66
+ techStack.orm = this.detectPythonORM(requirements);
67
+ }
68
+ catch (error) {
69
+ console.warn('Failed to read requirements.txt:', error);
70
+ }
71
+ }
72
+ if ((0, fs_1.existsSync)(pyprojectPath)) {
73
+ try {
74
+ const pyproject = (0, fs_1.readFileSync)(pyprojectPath, 'utf-8');
75
+ // Simple parsing for pyproject.toml (basic implementation)
76
+ if (pyproject.includes('django')) {
77
+ techStack.framework = 'Django';
78
+ }
79
+ else if (pyproject.includes('fastapi')) {
80
+ techStack.framework = 'FastAPI';
81
+ }
82
+ else if (pyproject.includes('flask')) {
83
+ techStack.framework = 'Flask';
84
+ }
85
+ }
86
+ catch (error) {
87
+ console.warn('Failed to read pyproject.toml:', error);
88
+ }
89
+ }
90
+ return techStack;
91
+ }
92
+ // Try Go (go.mod)
93
+ const goModPath = (0, path_1.join)(rootPath, 'go.mod');
94
+ if ((0, fs_1.existsSync)(goModPath)) {
95
+ try {
96
+ const goMod = (0, fs_1.readFileSync)(goModPath, 'utf-8');
97
+ techStack.language = 'go';
98
+ // Extract module name and version
99
+ const moduleMatch = goMod.match(/^module\s+(\S+)/m);
100
+ if (moduleMatch) {
101
+ techStack.version = moduleMatch[1];
102
+ }
103
+ // Detect Go framework
104
+ techStack.framework = this.detectGoFramework(goMod);
105
+ techStack.orm = this.detectGoORM(goMod);
106
+ return techStack;
107
+ }
108
+ catch (error) {
109
+ console.warn('Failed to read go.mod:', error);
110
+ }
111
+ }
112
+ return techStack;
113
+ }
114
+ /**
115
+ * Detect Node.js framework from package.json
116
+ */
117
+ detectNodeFramework(packageJson) {
118
+ const deps = {
119
+ ...packageJson.dependencies,
120
+ ...packageJson.devDependencies,
121
+ };
122
+ // React frameworks
123
+ if (deps['next'])
124
+ return 'Next.js';
125
+ if (deps['remix'])
126
+ return 'Remix';
127
+ if (deps['gatsby'])
128
+ return 'Gatsby';
129
+ if (deps['react']) {
130
+ // Check for Vite
131
+ if (deps['vite'])
132
+ return 'React + Vite';
133
+ if (deps['@vitejs/plugin-react'])
134
+ return 'React + Vite';
135
+ return 'React';
136
+ }
137
+ // Vue frameworks
138
+ if (deps['nuxt'])
139
+ return 'Nuxt.js';
140
+ if (deps['vue'])
141
+ return 'Vue.js';
142
+ // Angular
143
+ if (deps['@angular/core'])
144
+ return 'Angular';
145
+ // Backend frameworks
146
+ if (deps['express'])
147
+ return 'Express';
148
+ if (deps['fastify'])
149
+ return 'Fastify';
150
+ if (deps['koa'])
151
+ return 'Koa';
152
+ if (deps['nest'])
153
+ return 'NestJS';
154
+ if (deps['hapi'])
155
+ return 'Hapi';
156
+ // Check scripts for framework hints
157
+ if (packageJson.scripts) {
158
+ if (packageJson.scripts.dev?.includes('next'))
159
+ return 'Next.js';
160
+ if (packageJson.scripts.start?.includes('next'))
161
+ return 'Next.js';
162
+ }
163
+ return undefined;
164
+ }
165
+ /**
166
+ * Detect Node.js ORM from package.json
167
+ */
168
+ detectNodeORM(packageJson) {
169
+ const deps = {
170
+ ...packageJson.dependencies,
171
+ ...packageJson.devDependencies,
172
+ };
173
+ if (deps['prisma'])
174
+ return 'Prisma';
175
+ if (deps['typeorm'])
176
+ return 'TypeORM';
177
+ if (deps['sequelize'])
178
+ return 'Sequelize';
179
+ if (deps['mongoose'])
180
+ return 'Mongoose';
181
+ if (deps['drizzle-orm'])
182
+ return 'Drizzle ORM';
183
+ if (deps['kysely'])
184
+ return 'Kysely';
185
+ return undefined;
186
+ }
187
+ /**
188
+ * Detect styling library from package.json
189
+ */
190
+ detectStyling(packageJson) {
191
+ const deps = {
192
+ ...packageJson.dependencies,
193
+ ...packageJson.devDependencies,
194
+ };
195
+ if (deps['tailwindcss'])
196
+ return 'Tailwind CSS';
197
+ if (deps['@mui/material'] || deps['@material-ui/core'])
198
+ return 'Material UI';
199
+ if (deps['styled-components'])
200
+ return 'Styled Components';
201
+ if (deps['emotion'])
202
+ return 'Emotion';
203
+ if (deps['sass'] || deps['node-sass'])
204
+ return 'Sass';
205
+ if (deps['less'])
206
+ return 'Less';
207
+ if (deps['bootstrap'])
208
+ return 'Bootstrap';
209
+ return undefined;
210
+ }
211
+ /**
212
+ * Detect build tool from package.json
213
+ */
214
+ detectBuildTool(packageJson) {
215
+ const deps = {
216
+ ...packageJson.dependencies,
217
+ ...packageJson.devDependencies,
218
+ };
219
+ if (deps['vite'])
220
+ return 'Vite';
221
+ if (deps['webpack'])
222
+ return 'Webpack';
223
+ if (deps['rollup'])
224
+ return 'Rollup';
225
+ if (deps['esbuild'])
226
+ return 'esbuild';
227
+ if (deps['turbo'])
228
+ return 'Turborepo';
229
+ if (deps['nx'])
230
+ return 'Nx';
231
+ return undefined;
232
+ }
233
+ /**
234
+ * Detect package manager from lock files
235
+ */
236
+ detectPackageManager(rootPath) {
237
+ if ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'pnpm-lock.yaml')))
238
+ return 'pnpm';
239
+ if ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'yarn.lock')))
240
+ return 'yarn';
241
+ if ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'package-lock.json')))
242
+ return 'npm';
243
+ if ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'bun.lockb')))
244
+ return 'bun';
245
+ return undefined;
246
+ }
247
+ /**
248
+ * Detect Python framework from requirements.txt
249
+ */
250
+ detectPythonFramework(requirements) {
251
+ const lowerRequirements = requirements.toLowerCase();
252
+ if (lowerRequirements.includes('django'))
253
+ return 'Django';
254
+ if (lowerRequirements.includes('fastapi'))
255
+ return 'FastAPI';
256
+ if (lowerRequirements.includes('flask'))
257
+ return 'Flask';
258
+ if (lowerRequirements.includes('tornado'))
259
+ return 'Tornado';
260
+ if (lowerRequirements.includes('bottle'))
261
+ return 'Bottle';
262
+ return undefined;
263
+ }
264
+ /**
265
+ * Detect Python ORM from requirements.txt
266
+ */
267
+ detectPythonORM(requirements) {
268
+ const lowerRequirements = requirements.toLowerCase();
269
+ if (lowerRequirements.includes('sqlalchemy'))
270
+ return 'SQLAlchemy';
271
+ if (lowerRequirements.includes('django') && lowerRequirements.includes('orm'))
272
+ return 'Django ORM';
273
+ if (lowerRequirements.includes('peewee'))
274
+ return 'Peewee';
275
+ if (lowerRequirements.includes('tortoise-orm'))
276
+ return 'Tortoise ORM';
277
+ if (lowerRequirements.includes('prisma') || lowerRequirements.includes('prisma-client'))
278
+ return 'Prisma';
279
+ return undefined;
280
+ }
281
+ /**
282
+ * Detect Go framework from go.mod
283
+ */
284
+ detectGoFramework(goMod) {
285
+ if (goMod.includes('github.com/gin-gonic/gin'))
286
+ return 'Gin';
287
+ if (goMod.includes('github.com/gorilla/mux'))
288
+ return 'Gorilla Mux';
289
+ if (goMod.includes('github.com/labstack/echo'))
290
+ return 'Echo';
291
+ if (goMod.includes('github.com/go-chi/chi'))
292
+ return 'Chi';
293
+ if (goMod.includes('github.com/beego/beego'))
294
+ return 'Beego';
295
+ return undefined;
296
+ }
297
+ /**
298
+ * Detect Go ORM from go.mod
299
+ */
300
+ detectGoORM(goMod) {
301
+ if (goMod.includes('gorm.io/gorm'))
302
+ return 'GORM';
303
+ if (goMod.includes('github.com/jinzhu/gorm'))
304
+ return 'GORM (legacy)';
305
+ if (goMod.includes('github.com/volatiletech/sqlboiler'))
306
+ return 'SQLBoiler';
307
+ if (goMod.includes('github.com/go-pg/pg'))
308
+ return 'go-pg';
309
+ return undefined;
310
+ }
311
+ /**
312
+ * Detect architecture pattern from folder structure
313
+ */
314
+ detectArchitecturePattern(rootPath) {
315
+ // Check for Next.js App Router structure
316
+ if ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src', 'app')) || (0, fs_1.existsSync)((0, path_1.join)(rootPath, 'app'))) {
317
+ return 'feature-based'; // Next.js App Router uses feature-based routing
318
+ }
319
+ // Check for feature-based structure (modules, features, domains)
320
+ if ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src', 'modules')) ||
321
+ (0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src', 'features')) ||
322
+ (0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src', 'domains'))) {
323
+ return 'feature-based';
324
+ }
325
+ // Check for layered architecture (controllers, services, models)
326
+ if ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src', 'controllers')) &&
327
+ (0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src', 'services')) &&
328
+ (0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src', 'models'))) {
329
+ return 'layered';
330
+ }
331
+ // Check for MVC structure
332
+ if ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src', 'models')) &&
333
+ (0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src', 'views')) &&
334
+ (0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src', 'controllers'))) {
335
+ return 'mvc';
336
+ }
337
+ // Check for Django-like structure (apps)
338
+ if ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'apps')) ||
339
+ ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'src')) &&
340
+ (0, fs_1.existsSync)((0, path_1.join)(rootPath, 'manage.py')))) {
341
+ return 'feature-based';
342
+ }
343
+ return 'unknown';
344
+ }
345
+ /**
346
+ * Detect domain boundaries from folder structure
347
+ */
348
+ detectDomainBoundaries(rootPath) {
349
+ const boundaries = [];
350
+ // Check common patterns
351
+ const srcPath = (0, path_1.join)(rootPath, 'src');
352
+ if ((0, fs_1.existsSync)(srcPath)) {
353
+ // Feature-based boundaries
354
+ if ((0, fs_1.existsSync)((0, path_1.join)(srcPath, 'modules'))) {
355
+ boundaries.push('src/modules/*');
356
+ }
357
+ if ((0, fs_1.existsSync)((0, path_1.join)(srcPath, 'features'))) {
358
+ boundaries.push('src/features/*');
359
+ }
360
+ if ((0, fs_1.existsSync)((0, path_1.join)(srcPath, 'domains'))) {
361
+ boundaries.push('src/domains/*');
362
+ }
363
+ // App Router (Next.js)
364
+ if ((0, fs_1.existsSync)((0, path_1.join)(srcPath, 'app'))) {
365
+ boundaries.push('src/app/**/route.ts');
366
+ boundaries.push('src/app/**/page.tsx');
367
+ }
368
+ // Layered architecture boundaries
369
+ if ((0, fs_1.existsSync)((0, path_1.join)(srcPath, 'controllers'))) {
370
+ boundaries.push('src/controllers/*');
371
+ }
372
+ if ((0, fs_1.existsSync)((0, path_1.join)(srcPath, 'services'))) {
373
+ boundaries.push('src/services/*');
374
+ }
375
+ if ((0, fs_1.existsSync)((0, path_1.join)(srcPath, 'models'))) {
376
+ boundaries.push('src/models/*');
377
+ }
378
+ }
379
+ // Django apps
380
+ if ((0, fs_1.existsSync)((0, path_1.join)(rootPath, 'apps'))) {
381
+ boundaries.push('apps/*');
382
+ }
383
+ return boundaries;
384
+ }
385
+ /**
386
+ * Generate default invariants based on architecture pattern
387
+ */
388
+ generateDefaultInvariants(pattern) {
389
+ const invariants = [];
390
+ switch (pattern) {
391
+ case 'layered':
392
+ invariants.push('No direct database access in controllers');
393
+ invariants.push('Business logic must be in service layer');
394
+ invariants.push('Models should only contain data structures');
395
+ break;
396
+ case 'mvc':
397
+ invariants.push('Models should not contain business logic');
398
+ invariants.push('Views should not contain business logic');
399
+ invariants.push('Controllers should delegate to services');
400
+ break;
401
+ case 'feature-based':
402
+ invariants.push('Features should be self-contained modules');
403
+ invariants.push('No cross-feature dependencies without interfaces');
404
+ invariants.push('Shared code should be in common/shared directory');
405
+ break;
406
+ case 'unknown':
407
+ invariants.push('Follow existing project structure');
408
+ break;
409
+ }
410
+ return invariants;
411
+ }
412
+ /**
413
+ * Read architecture memory from .neurcode/architecture.json
414
+ */
415
+ async readArchitectureMemory(rootPath) {
416
+ const neurcodeDir = (0, path_1.join)(rootPath, '.neurcode');
417
+ const architecturePath = (0, path_1.join)(neurcodeDir, 'architecture.json');
418
+ if (!(0, fs_1.existsSync)(architecturePath)) {
419
+ return null;
420
+ }
421
+ try {
422
+ const content = (0, fs_1.readFileSync)(architecturePath, 'utf-8');
423
+ const parsed = JSON.parse(content);
424
+ const validated = ArchitectureMemorySchema.parse(parsed);
425
+ return validated;
426
+ }
427
+ catch (error) {
428
+ console.warn('Failed to read or validate architecture.json:', error);
429
+ return null;
430
+ }
431
+ }
432
+ /**
433
+ * Write architecture memory to .neurcode/architecture.json
434
+ */
435
+ async writeArchitectureMemory(rootPath, memory) {
436
+ const neurcodeDir = (0, path_1.join)(rootPath, '.neurcode');
437
+ const architecturePath = (0, path_1.join)(neurcodeDir, 'architecture.json');
438
+ // Ensure .neurcode directory exists
439
+ if (!(0, fs_1.existsSync)(neurcodeDir)) {
440
+ (0, fs_1.mkdirSync)(neurcodeDir, { recursive: true });
441
+ }
442
+ // Validate before writing
443
+ const validated = ArchitectureMemorySchema.parse(memory);
444
+ // Write to file
445
+ (0, fs_1.writeFileSync)(architecturePath, JSON.stringify(validated, null, 2), 'utf-8');
446
+ }
447
+ /**
448
+ * Initialize architecture memory with defaults based on folder structure
449
+ */
450
+ async initializeArchitectureMemory(rootPath) {
451
+ const pattern = this.detectArchitecturePattern(rootPath);
452
+ const domainBoundaries = this.detectDomainBoundaries(rootPath);
453
+ const invariants = this.generateDefaultInvariants(pattern);
454
+ const memory = {
455
+ pattern,
456
+ invariants,
457
+ domainBoundaries,
458
+ };
459
+ // Save to disk
460
+ await this.writeArchitectureMemory(rootPath, memory);
461
+ return memory;
462
+ }
463
+ /**
464
+ * Get or create architecture memory (reads from disk or initializes)
465
+ */
466
+ async getArchitectureMemory(rootPath) {
467
+ // Try to read existing
468
+ const existing = await this.readArchitectureMemory(rootPath);
469
+ if (existing) {
470
+ return existing;
471
+ }
472
+ // Initialize if not found
473
+ return await this.initializeArchitectureMemory(rootPath);
474
+ }
475
+ /**
476
+ * Generate natural language project summary
477
+ */
478
+ async getProjectSummary(rootPath) {
479
+ const techStack = await this.detectTechStack(rootPath);
480
+ const architecture = await this.getArchitectureMemory(rootPath);
481
+ // Build natural language summary
482
+ const parts = [];
483
+ // Tech stack description
484
+ if (techStack.language !== 'unknown') {
485
+ const stackParts = [];
486
+ if (techStack.framework) {
487
+ stackParts.push(techStack.framework);
488
+ }
489
+ else {
490
+ // Fallback to language name
491
+ const languageNames = {
492
+ node: 'Node.js',
493
+ python: 'Python',
494
+ go: 'Go',
495
+ };
496
+ stackParts.push(languageNames[techStack.language] || techStack.language);
497
+ }
498
+ if (techStack.orm) {
499
+ stackParts.push(`using ${techStack.orm}`);
500
+ }
501
+ if (techStack.styling) {
502
+ stackParts.push(`with ${techStack.styling}`);
503
+ }
504
+ if (techStack.buildTool) {
505
+ stackParts.push(`built with ${techStack.buildTool}`);
506
+ }
507
+ parts.push(stackParts.join(' ') + ' project');
508
+ }
509
+ else {
510
+ parts.push('Unknown technology stack');
511
+ }
512
+ // Architecture description
513
+ if (architecture.pattern !== 'unknown') {
514
+ const patternNames = {
515
+ 'feature-based': 'feature-based architecture',
516
+ 'layered': 'layered architecture',
517
+ 'mvc': 'MVC architecture',
518
+ 'unknown': 'unknown architecture',
519
+ };
520
+ parts.push(`Follows ${patternNames[architecture.pattern]}`);
521
+ }
522
+ // Add invariants if present
523
+ if (architecture.invariants.length > 0) {
524
+ parts.push(`Key architectural rules: ${architecture.invariants.slice(0, 2).join(', ')}`);
525
+ }
526
+ const summary = parts.join('. ') + '.';
527
+ return {
528
+ techStack,
529
+ architecture,
530
+ summary,
531
+ };
532
+ }
533
+ }
534
+ exports.ProjectKnowledgeService = ProjectKnowledgeService;
535
+ //# sourceMappingURL=project-knowledge-service.js.map