@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.
- package/dist/api-client.d.ts +10 -1
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +26 -1
- package/dist/api-client.js.map +1 -1
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +78 -12
- package/dist/commands/plan.js.map +1 -1
- package/dist/services/integrations/TicketService.d.ts +4 -0
- package/dist/services/integrations/TicketService.d.ts.map +1 -1
- package/dist/services/integrations/TicketService.js +11 -5
- package/dist/services/integrations/TicketService.js.map +1 -1
- package/dist/services/project-knowledge-service.d.ts +127 -0
- package/dist/services/project-knowledge-service.d.ts.map +1 -0
- package/dist/services/project-knowledge-service.js +535 -0
- package/dist/services/project-knowledge-service.js.map +1 -0
- package/package.json +3 -2
|
@@ -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
|