openwork-agent 1.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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +436 -0
  3. package/package.json +78 -0
  4. package/src/core/TechDetector.js +351 -0
  5. package/src/generators/ProjectGenerator.js +1241 -0
  6. package/src/generators/ProjectGeneratorExtensions.js +14 -0
  7. package/src/generators/TemplateMethods.js +402 -0
  8. package/src/generators/index.js +5 -0
  9. package/src/index.js +152 -0
  10. package/src/main.js +8 -0
  11. package/src/templates/common/README.md.hbs +358 -0
  12. package/src/templates/docker/index.js +518 -0
  13. package/src/templates/docker.js +58 -0
  14. package/src/templates/go/basic/api/routes/user.go.hbs +138 -0
  15. package/src/templates/go/basic/config/config.go.hbs +54 -0
  16. package/src/templates/go/basic/go.mod.hbs +8 -0
  17. package/src/templates/go/basic/main.go.hbs +70 -0
  18. package/src/templates/go/basic/models/user.go.hbs +69 -0
  19. package/src/templates/go/basic/services/user_service.go.hbs +173 -0
  20. package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/controller/UserController.java.hbs +91 -0
  21. package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/dto/ApiResponse.java.hbs +40 -0
  22. package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/model/User.java.hbs +102 -0
  23. package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/repository/UserRepository.java.hbs +20 -0
  24. package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/service/UserService.java.hbs +65 -0
  25. package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/{{pascalCase projectName}}Application.java.hbs +16 -0
  26. package/src/templates/node/basic/src/config/database.ts.hbs +18 -0
  27. package/src/templates/node/basic/src/controllers/UserController.ts.hbs +98 -0
  28. package/src/templates/node/basic/src/index.ts.hbs +45 -0
  29. package/src/templates/node/basic/src/middleware/errorHandler.ts.hbs +33 -0
  30. package/src/templates/node/basic/src/routes/index.ts.hbs +42 -0
  31. package/src/templates/node/basic/src/types/index.ts.hbs +18 -0
  32. package/src/templates/python/basic/config/database.py.hbs +36 -0
  33. package/src/templates/python/basic/main.py.hbs +58 -0
  34. package/src/templates/python/basic/middleware/error_handler.py.hbs +41 -0
  35. package/src/templates/python/basic/models/user.py.hbs +40 -0
  36. package/src/templates/python/basic/routes/__init__.py.hbs +12 -0
  37. package/src/templates/python/basic/routes/users.py.hbs +64 -0
  38. package/src/templates/rust/basic/Cargo.toml.hbs +39 -0
  39. package/src/templates/rust/basic/src/config/database.rs.hbs +27 -0
  40. package/src/templates/rust/basic/src/handlers/user.rs.hbs +130 -0
  41. package/src/templates/rust/basic/src/handlers/user_routes.rs.hbs +15 -0
  42. package/src/templates/rust/basic/src/main.rs.hbs +53 -0
  43. package/src/templates/rust/basic/src/models/mod.rs.hbs +79 -0
  44. package/src/templates/rust/basic/src/schema.rs.hbs +10 -0
  45. package/src/utils/FileManager.js +186 -0
  46. package/src/utils/Templates.js +231 -0
@@ -0,0 +1,351 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ class TechDetector {
5
+ constructor() {
6
+ this.techSignatures = {
7
+ 'node': {
8
+ files: ['package.json', 'yarn.lock', 'package-lock.json'],
9
+ extensions: ['.js', '.ts', '.mjs', '.cjs'],
10
+ patterns: ['require\\(', 'import.*from', 'module.exports', 'export.*'],
11
+ frameworks: {
12
+ 'express': ['express\\(\\)', 'require.*express', 'import.*express'],
13
+ 'nestjs': ['@nestjs/core', 'Controller', 'Injectable', 'Module'],
14
+ 'fastify': ['fastify\\(\\)', 'require.*fastify', 'import.*fastify'],
15
+ 'koa': ['koa\\(\\)', 'require.*koa', 'import.*koa'],
16
+ 'hapi': ['@hapi/hapi', 'server\\.route'],
17
+ 'sails': ['sails\\.lift', 'require.*sails']
18
+ }
19
+ },
20
+ 'python': {
21
+ files: ['requirements.txt', 'setup.py', 'pyproject.toml', 'Pipfile', 'poetry.lock'],
22
+ extensions: ['.py'],
23
+ patterns: ['import ', 'from .* import', 'def ', 'class '],
24
+ frameworks: {
25
+ 'django': ['django-admin', 'manage.py', 'DJANGO_SETTINGS_MODULE', 'from django'],
26
+ 'fastapi': ['FastAPI\\(', 'from fastapi import', 'APIRouter'],
27
+ 'flask': ['Flask\\(', 'from flask import', '@app.route'],
28
+ 'tornado': ['tornado.web', 'from tornado import', 'RequestHandler'],
29
+ 'aiohttp': ['aiohttp.web', 'from aiohttp import']
30
+ }
31
+ },
32
+ 'java': {
33
+ files: ['pom.xml', 'build.gradle', 'build.gradle.kts'],
34
+ extensions: ['.java', '.kt'],
35
+ patterns: ['public class', 'import java\\.', 'package ', 'public static void main'],
36
+ frameworks: {
37
+ 'spring': ['@SpringBootApplication', 'SpringApplication', '@RestController', '@Autowired'],
38
+ 'quarkus': ['@Path', '@ApplicationPath', 'Quarkus', '@GET'],
39
+ 'micronaut': ['@Controller', '@Inject', 'Micronaut', '@Get'],
40
+ 'vertx': ['Vertx', 'vertx\\.deployVerticle', '@Route']
41
+ }
42
+ },
43
+ 'go': {
44
+ files: ['go.mod', 'go.sum'],
45
+ extensions: ['.go'],
46
+ patterns: ['package ', 'func \\(', 'import \\(', 'type.*struct'],
47
+ frameworks: {
48
+ 'gin': ['gin\\.Default\\(', 'gin-gonic', 'gin\\.Engine'],
49
+ 'echo': ['echo\\.New\\(', 'echo framework', 'echo\\.Echo'],
50
+ 'fiber': ['fiber\\.New\\(', 'gofiber', 'fiber\\.App'],
51
+ 'chi': ['chi\\.Router\\(', 'go-chi/chi'],
52
+ 'gorilla': ['gorilla/mux', 'mux\\.NewRouter']
53
+ }
54
+ },
55
+ 'rust': {
56
+ files: ['Cargo.toml', 'Cargo.lock'],
57
+ extensions: ['.rs'],
58
+ patterns: ['fn main\\(\\)', 'use ', 'mod ', 'pub fn'],
59
+ frameworks: {
60
+ 'actix': ['actix_web', 'HttpServer', 'App'],
61
+ 'rocket': ['#\\[get\\(', 'rocket::', '#\\[derive'],
62
+ 'warp': ['warp::', 'Filter', 'warp::serve'],
63
+ 'axum': ['axum', 'Router', 'extract']
64
+ }
65
+ },
66
+ 'php': {
67
+ files: ['composer.json', 'composer.lock'],
68
+ extensions: ['.php'],
69
+ patterns: ['<?php', 'namespace ', 'class ', 'function '],
70
+ frameworks: {
71
+ 'laravel': ['laravel/framework', 'Route::', 'Illuminate'],
72
+ 'symfony': ['symfony/framework', '@Route', 'Symfony'],
73
+ 'slim': ['slim/framework', 'Slim\\App', '$app->get']
74
+ }
75
+ },
76
+ 'csharp': {
77
+ files: ['project.json', '*.csproj', '*.sln'],
78
+ extensions: ['.cs'],
79
+ patterns: ['using ', 'namespace ', 'public class', 'public static void Main'],
80
+ frameworks: {
81
+ 'aspnet': ['Microsoft.AspNetCore', 'ControllerBase', '[HttpGet]'],
82
+ 'nancy': ['Nancy', 'NancyModule']
83
+ }
84
+ }
85
+ };
86
+
87
+ this.databaseSignatures = {
88
+ 'mongodb': ['mongodb', 'mongoose', 'mongo-client', 'pymongo', 'mongodb-driver'],
89
+ 'postgresql': ['pg', 'postgresql', 'psycopg2', 'postgres', 'npgsql'],
90
+ 'mysql': ['mysql2', 'mysql', 'pymysql', 'sqlalchemy.*mysql', 'mysql-connector'],
91
+ 'sqlite': ['sqlite3', 'sqlite', 'better-sqlite3', 'sqlite-net'],
92
+ 'redis': ['redis', 'ioredis', 'redis-py', 'stackexchange.redis'],
93
+ 'oracle': ['oracledb', 'cx_Oracle', 'oracle-driver'],
94
+ 'sqlserver': ['mssql', 'pymssql', 'sql-server-driver']
95
+ };
96
+ }
97
+
98
+ async analyzeCurrentDirectory() {
99
+ const analysis = {
100
+ technologies: [],
101
+ frameworks: [],
102
+ databases: [],
103
+ confidence: {},
104
+ files: [],
105
+ packageInfo: {}
106
+ };
107
+
108
+ const currentDir = process.cwd();
109
+ const files = await this.getAllFiles(currentDir);
110
+ analysis.files = files;
111
+
112
+ // Check for package managers and extract info
113
+ analysis.packageInfo = await this.extractPackageInfo(currentDir);
114
+
115
+ // Detect technologies
116
+ for (const [tech, config] of Object.entries(this.techSignatures)) {
117
+ const confidence = await this.detectTechnology(files, tech, config);
118
+ if (confidence > 0.3) {
119
+ analysis.technologies.push(tech);
120
+ analysis.confidence[tech] = confidence;
121
+
122
+ // Detect frameworks for this technology
123
+ const detectedFrameworks = await this.detectFrameworks(files, tech, config.frameworks);
124
+ analysis.frameworks.push(...detectedFrameworks);
125
+ }
126
+ }
127
+
128
+ // Detect databases
129
+ analysis.databases = await this.detectDatabases(files);
130
+
131
+ return analysis;
132
+ }
133
+
134
+ async extractPackageInfo(dir) {
135
+ const info = {};
136
+
137
+ // Node.js package.json
138
+ if (await fs.pathExists(path.join(dir, 'package.json'))) {
139
+ try {
140
+ info.node = await fs.readJson(path.join(dir, 'package.json'));
141
+ } catch (e) {}
142
+ }
143
+
144
+ // Python requirements
145
+ if (await fs.pathExists(path.join(dir, 'requirements.txt'))) {
146
+ try {
147
+ const content = await fs.readFile(path.join(dir, 'requirements.txt'), 'utf8');
148
+ info.python = content.split('\n').filter(line => line.trim() && !line.startsWith('#'));
149
+ } catch (e) {}
150
+ }
151
+
152
+ // Java pom.xml
153
+ if (await fs.pathExists(path.join(dir, 'pom.xml'))) {
154
+ try {
155
+ info.java = await fs.readFile(path.join(dir, 'pom.xml'), 'utf8');
156
+ } catch (e) {}
157
+ }
158
+
159
+ // Go go.mod
160
+ if (await fs.pathExists(path.join(dir, 'go.mod'))) {
161
+ try {
162
+ const content = await fs.readFile(path.join(dir, 'go.mod'), 'utf8');
163
+ const match = content.match(/module\s+(.+)/);
164
+ if (match) info.go = { module: match[1].trim() };
165
+ } catch (e) {}
166
+ }
167
+
168
+ // Rust Cargo.toml
169
+ if (await fs.pathExists(path.join(dir, 'Cargo.toml'))) {
170
+ try {
171
+ info.rust = await fs.readFile(path.join(dir, 'Cargo.toml'), 'utf8');
172
+ } catch (e) {}
173
+ }
174
+
175
+ return info;
176
+ }
177
+
178
+ async getAllFiles(dir) {
179
+ let files = [];
180
+
181
+ try {
182
+ const items = await fs.readdir(dir);
183
+
184
+ for (const item of items) {
185
+ const fullPath = path.join(dir, item);
186
+ const stat = await fs.stat(fullPath);
187
+
188
+ if (stat.isDirectory() && !this.shouldSkipDirectory(item)) {
189
+ files = files.concat(await this.getAllFiles(fullPath));
190
+ } else if (stat.isFile()) {
191
+ files.push(fullPath);
192
+ }
193
+ }
194
+ } catch (error) {
195
+ // Skip directories we can't read
196
+ }
197
+
198
+ return files;
199
+ }
200
+
201
+ shouldSkipDirectory(dirName) {
202
+ const skipDirs = ['.git', 'node_modules', '__pycache__', 'target', 'vendor', '.vscode', '.idea', 'build', 'dist', '.next', '.nuxt'];
203
+ return skipDirs.includes(dirName);
204
+ }
205
+
206
+ async detectTechnology(files, tech, config) {
207
+ let score = 0;
208
+ let maxScore = 0;
209
+
210
+ // Check for signature files
211
+ maxScore += config.files.length * 10;
212
+ for (const file of config.files) {
213
+ if (files.some(f => f.endsWith(file))) {
214
+ score += 10;
215
+ }
216
+ }
217
+
218
+ // Check file extensions
219
+ maxScore += files.length;
220
+ const matchingExtensions = files.filter(f =>
221
+ config.extensions.some(ext => f.endsWith(ext))
222
+ );
223
+ score += matchingExtensions.length;
224
+
225
+ // Check content patterns (sample first 10 matching files)
226
+ const sampleFiles = matchingExtensions.slice(0, 10);
227
+ maxScore += sampleFiles.length * config.patterns.length * 5;
228
+
229
+ for (const file of sampleFiles) {
230
+ try {
231
+ const content = await fs.readFile(file, 'utf8');
232
+ for (const pattern of config.patterns) {
233
+ if (new RegExp(pattern, 'i').test(content)) {
234
+ score += 5;
235
+ }
236
+ }
237
+ } catch (error) {
238
+ // Skip files we can't read
239
+ }
240
+ }
241
+
242
+ return maxScore > 0 ? score / maxScore : 0;
243
+ }
244
+
245
+ async detectFrameworks(files, tech, frameworks) {
246
+ const detected = [];
247
+
248
+ for (const [framework, patterns] of Object.entries(frameworks)) {
249
+ let confidence = 0;
250
+ let checkedFiles = 0;
251
+
252
+ for (const file of files) {
253
+ const ext = path.extname(file);
254
+ if (!this.techSignatures[tech].extensions.includes(ext)) continue;
255
+
256
+ try {
257
+ const content = await fs.readFile(file, 'utf8');
258
+ for (const pattern of patterns) {
259
+ if (new RegExp(pattern, 'i').test(content)) {
260
+ confidence += 1;
261
+ }
262
+ }
263
+ checkedFiles++;
264
+ } catch (error) {
265
+ // Skip files we can't read
266
+ }
267
+ }
268
+
269
+ // Threshold detection
270
+ if (confidence >= 2 || (confidence > 0 && checkedFiles > 0)) {
271
+ detected.push({
272
+ technology: tech,
273
+ framework,
274
+ confidence: confidence / Math.max(1, checkedFiles)
275
+ });
276
+ }
277
+ }
278
+
279
+ return detected;
280
+ }
281
+
282
+ async detectDatabases(files) {
283
+ const detected = {};
284
+
285
+ for (const file of files) {
286
+ try {
287
+ const content = await fs.readFile(file, 'utf8');
288
+
289
+ for (const [db, patterns] of Object.entries(this.databaseSignatures)) {
290
+ for (const pattern of patterns) {
291
+ if (new RegExp(pattern, 'i').test(content)) {
292
+ detected[db] = (detected[db] || 0) + 1;
293
+ }
294
+ }
295
+ }
296
+ } catch (error) {
297
+ // Skip files we can't read
298
+ }
299
+ }
300
+
301
+ // Return databases sorted by detection frequency
302
+ return Object.entries(detected)
303
+ .sort(([,a], [,b]) => b - a)
304
+ .map(([db]) => db);
305
+ }
306
+
307
+ getAvailableTechnologies() {
308
+ return Object.keys(this.techSignatures);
309
+ }
310
+
311
+ getFrameworksForTechnology(tech) {
312
+ const config = this.techSignatures[tech];
313
+ return config ? Object.keys(config.frameworks) : [];
314
+ }
315
+
316
+ getAvailableDatabases() {
317
+ return Object.keys(this.databaseSignatures);
318
+ }
319
+
320
+ getRecommendedTechStack() {
321
+ return {
322
+ 'node': {
323
+ frameworks: ['express', 'nestjs', 'fastify'],
324
+ databases: ['mongodb', 'postgresql', 'mysql'],
325
+ reason: 'Great for APIs, microservices, and rapid development'
326
+ },
327
+ 'python': {
328
+ frameworks: ['fastapi', 'django', 'flask'],
329
+ databases: ['postgresql', 'mongodb', 'sqlite'],
330
+ reason: 'Excellent for data processing, ML, and web applications'
331
+ },
332
+ 'java': {
333
+ frameworks: ['spring', 'quarkus'],
334
+ databases: ['postgresql', 'mysql', 'oracle'],
335
+ reason: 'Enterprise-grade, high performance, and great for large systems'
336
+ },
337
+ 'go': {
338
+ frameworks: ['gin', 'fiber', 'echo'],
339
+ databases: ['postgresql', 'mongodb', 'redis'],
340
+ reason: 'High performance, great for microservices and cloud-native'
341
+ },
342
+ 'rust': {
343
+ frameworks: ['actix', 'rocket'],
344
+ databases: ['postgresql', 'sqlite'],
345
+ reason: 'Maximum performance and memory safety'
346
+ }
347
+ };
348
+ }
349
+ }
350
+
351
+ module.exports = TechDetector;