@njeybe/nativ 2.4.1 → 2.5.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 (139) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +26 -0
  3. package/dist/commands/db/db-formatter.d.ts +5 -0
  4. package/dist/commands/db/db-formatter.js +116 -0
  5. package/dist/commands/db/db-introspect.d.ts +11 -0
  6. package/dist/commands/db/db-introspect.js +84 -0
  7. package/dist/commands/db.js +4 -206
  8. package/dist/commands/profile.d.ts +3 -0
  9. package/dist/commands/profile.js +39 -0
  10. package/dist/commands/task/task-add.d.ts +11 -0
  11. package/dist/commands/task/task-add.js +169 -0
  12. package/dist/commands/task/task-common.d.ts +57 -0
  13. package/dist/commands/task/task-common.js +45 -0
  14. package/dist/commands/task/task-escalate.d.ts +7 -0
  15. package/dist/commands/task/task-escalate.js +119 -0
  16. package/dist/commands/task/task-lifecycle.d.ts +5 -0
  17. package/dist/commands/task/task-lifecycle.js +252 -0
  18. package/dist/commands/task/task-query.d.ts +10 -0
  19. package/dist/commands/task/task-query.js +269 -0
  20. package/dist/commands/task.d.ts +9 -87
  21. package/dist/commands/task.js +8 -850
  22. package/dist/commands/triage/triage-store.d.ts +56 -0
  23. package/dist/commands/triage/triage-store.js +108 -0
  24. package/dist/commands/triage/triage-ui.d.ts +14 -0
  25. package/dist/commands/triage/triage-ui.js +104 -0
  26. package/dist/commands/triage.d.ts +3 -52
  27. package/dist/commands/triage.js +8 -216
  28. package/dist/core/enforcement.d.ts +1 -0
  29. package/dist/core/enforcement.js +19 -0
  30. package/dist/core/human-gate.d.ts +2 -1
  31. package/dist/core/human-gate.js +9 -2
  32. package/dist/core/profiles.d.ts +14 -0
  33. package/dist/core/profiles.js +82 -0
  34. package/dist/core/setup/config-merger.d.ts +59 -0
  35. package/dist/core/setup/config-merger.js +107 -0
  36. package/dist/core/setup/session-context.d.ts +4 -0
  37. package/dist/core/setup/session-context.js +65 -0
  38. package/dist/core/setup/setup-planner.d.ts +14 -0
  39. package/dist/core/setup/setup-planner.js +180 -0
  40. package/dist/core/setup/template-planner.d.ts +8 -0
  41. package/dist/core/setup/template-planner.js +32 -0
  42. package/dist/core/setup/types.d.ts +65 -0
  43. package/dist/core/setup/types.js +55 -0
  44. package/dist/core/setup-assets.d.ts +8 -119
  45. package/dist/core/setup-assets.js +7 -437
  46. package/dist/core/tier1-liaison.d.ts +2 -0
  47. package/dist/core/tier1-liaison.js +64 -3
  48. package/dist/core/verifier/executor.d.ts +5 -0
  49. package/dist/core/verifier/executor.js +62 -0
  50. package/dist/core/verifier/phases.d.ts +5 -0
  51. package/dist/core/verifier/phases.js +71 -0
  52. package/dist/core/verifier/task-verifier.d.ts +37 -0
  53. package/dist/core/verifier/task-verifier.js +233 -0
  54. package/dist/core/verifier/types.d.ts +51 -0
  55. package/dist/core/verifier/types.js +1 -0
  56. package/dist/core/verifier.d.ts +5 -93
  57. package/dist/core/verifier.js +5 -359
  58. package/dist/db/introspector.js +59 -59
  59. package/dist/governor/evaluator.d.ts +4 -64
  60. package/dist/governor/evaluator.js +21 -686
  61. package/dist/governor/patch-applier.d.ts +8 -0
  62. package/dist/governor/patch-applier.js +121 -0
  63. package/dist/governor/self-healing.d.ts +24 -0
  64. package/dist/governor/self-healing.js +351 -0
  65. package/dist/governor/test-integrity.d.ts +41 -0
  66. package/dist/governor/test-integrity.js +237 -0
  67. package/dist/index.js +8 -0
  68. package/dist/mcp/capture.d.ts +4 -0
  69. package/dist/mcp/capture.js +33 -0
  70. package/dist/mcp/resources.d.ts +39 -0
  71. package/dist/mcp/resources.js +44 -0
  72. package/dist/mcp/server.d.ts +11 -0
  73. package/dist/mcp/server.js +14 -89
  74. package/dist/mcp/tools.d.ts +1 -0
  75. package/dist/mcp/tools.js +1 -0
  76. package/dist/runner/agent-supervisor.d.ts +8 -302
  77. package/dist/runner/agent-supervisor.js +41 -1030
  78. package/dist/runner/cli-config.d.ts +84 -0
  79. package/dist/runner/cli-config.js +215 -0
  80. package/dist/runner/native-driver.d.ts +18 -0
  81. package/dist/runner/native-driver.js +208 -0
  82. package/dist/runner/native-engine.d.ts +27 -0
  83. package/dist/runner/native-engine.js +184 -0
  84. package/dist/runner/native-tools.d.ts +31 -0
  85. package/dist/runner/native-tools.js +241 -0
  86. package/dist/runner/process-utils.d.ts +12 -0
  87. package/dist/runner/process-utils.js +96 -0
  88. package/dist/runner/run-lifecycle.d.ts +6 -0
  89. package/dist/runner/run-lifecycle.js +42 -0
  90. package/dist/runner/types.d.ts +215 -0
  91. package/dist/runner/types.js +41 -0
  92. package/dist/scanner/detector.js +42 -663
  93. package/dist/scanner/detectors/ecosystem-detector.d.ts +16 -0
  94. package/dist/scanner/detectors/ecosystem-detector.js +354 -0
  95. package/dist/scanner/detectors/orm-detector.d.ts +5 -0
  96. package/dist/scanner/detectors/orm-detector.js +59 -0
  97. package/dist/scanner/detectors/workspace-detector.d.ts +19 -0
  98. package/dist/scanner/detectors/workspace-detector.js +266 -0
  99. package/dist/server/cli-runner.d.ts +15 -0
  100. package/dist/server/cli-runner.js +43 -0
  101. package/dist/server/event-hub.d.ts +42 -0
  102. package/dist/server/event-hub.js +169 -0
  103. package/dist/server/http-utils.d.ts +15 -0
  104. package/dist/server/http-utils.js +56 -0
  105. package/dist/server/plan-utils.d.ts +9 -0
  106. package/dist/server/plan-utils.js +31 -0
  107. package/dist/server/routes/db-routes.d.ts +57 -0
  108. package/dist/server/routes/db-routes.js +484 -0
  109. package/dist/server/routes/task-routes.d.ts +266 -0
  110. package/dist/server/routes/task-routes.js +285 -0
  111. package/dist/server/routes/telemetry-routes.d.ts +128 -0
  112. package/dist/server/routes/telemetry-routes.js +179 -0
  113. package/dist/server/routes/triage-routes.d.ts +81 -0
  114. package/dist/server/routes/triage-routes.js +244 -0
  115. package/dist/server/routes/worktree-routes.d.ts +31 -0
  116. package/dist/server/routes/worktree-routes.js +144 -0
  117. package/dist/server/studio-server.d.ts +4 -11
  118. package/dist/server/studio-server.js +34 -1578
  119. package/dist/server/studio-ui/shell/pipeline-state.js +2 -0
  120. package/dist/server/studio-ui/shell/triage.js +10 -0
  121. package/package.json +2 -2
  122. package/plugin/.claude-plugin/plugin.json +1 -1
  123. package/plugin/agents/architect.md +4 -2
  124. package/plugin/agents/verifier.md +1 -1
  125. package/plugin/agents/worker.md +7 -4
  126. package/plugin/skills/nativ/SKILL.md +1 -0
  127. package/templates/.claudeignore +62 -45
  128. package/templates/AGENTS.md +1 -0
  129. package/templates/CLAUDE.md +13 -0
  130. package/templates/claude-agents/architect.md +4 -2
  131. package/templates/claude-agents/verifier.md +1 -1
  132. package/templates/claude-agents/worker.md +7 -4
  133. package/templates/dot-ai/api_contracts.json +66 -66
  134. package/templates/dot-ai/context.md +38 -38
  135. package/templates/dot-ai/db_schema.json +39 -39
  136. package/dist/commands/session.d.ts +0 -22
  137. package/dist/commands/session.js +0 -106
  138. package/dist/core/session-memory.d.ts +0 -42
  139. package/dist/core/session-memory.js +0 -121
@@ -0,0 +1,16 @@
1
+ export interface EcosystemProfile {
2
+ projectName?: string;
3
+ projectGoal?: string;
4
+ projectType?: string;
5
+ runtime: string;
6
+ framework: string;
7
+ databaseOrm: string;
8
+ styling: string;
9
+ testing: string;
10
+ packageManager: string;
11
+ verificationCommand: string;
12
+ ecosystemManifests: string[];
13
+ monorepoWorkspaces: string[];
14
+ monorepoIndicators: string[];
15
+ }
16
+ export declare function detectEcosystems(resolvedTarget: string, baseName: string, fileExists: (relPath: string) => boolean, readFileSafe: (filePath: string) => string): EcosystemProfile;
@@ -0,0 +1,354 @@
1
+ import path from 'node:path';
2
+ export function detectEcosystems(resolvedTarget, baseName, fileExists, readFileSafe) {
3
+ let projectName;
4
+ let projectGoal;
5
+ let projectType;
6
+ let runtime = 'Unknown / Greenfield';
7
+ let framework = 'None detected';
8
+ let databaseOrm = 'None detected';
9
+ let styling = 'None detected';
10
+ let testing = 'None detected';
11
+ let packageManager = 'None detected';
12
+ let verificationCommand = 'npm test';
13
+ const ecosystemManifests = [];
14
+ const monorepoWorkspaces = [];
15
+ const monorepoIndicators = [];
16
+ // --- Ecosystem A: Node.js / JavaScript / TypeScript ---
17
+ const pkgPath = path.join(resolvedTarget, 'package.json');
18
+ if (fileExists('package.json')) {
19
+ ecosystemManifests.push('package.json');
20
+ try {
21
+ const pkg = JSON.parse(readFileSafe(pkgPath));
22
+ if (pkg.name)
23
+ projectName = pkg.name;
24
+ if (pkg.description)
25
+ projectGoal = pkg.description;
26
+ if (pkg.workspaces) {
27
+ if (Array.isArray(pkg.workspaces)) {
28
+ monorepoWorkspaces.push(...pkg.workspaces);
29
+ }
30
+ else if (Array.isArray(pkg.workspaces.packages)) {
31
+ monorepoWorkspaces.push(...pkg.workspaces.packages);
32
+ }
33
+ if (!monorepoIndicators.includes('npm/yarn workspaces')) {
34
+ monorepoIndicators.push('npm/yarn workspaces');
35
+ }
36
+ }
37
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
38
+ if (deps.typescript || fileExists('tsconfig.json')) {
39
+ runtime = 'Node.js (TypeScript)';
40
+ if (fileExists('tsconfig.json'))
41
+ ecosystemManifests.push('tsconfig.json');
42
+ }
43
+ else {
44
+ runtime = 'Node.js (JavaScript)';
45
+ }
46
+ if (deps['react-native'] || deps.expo) {
47
+ framework = deps.expo ? 'Expo Mobile App' : 'React Native';
48
+ }
49
+ else if (deps.next)
50
+ framework = `Next.js (${deps.next})`;
51
+ else if (deps.nuxt)
52
+ framework = `Nuxt (${deps.nuxt})`;
53
+ else if (deps.remix || deps['@remix-run/react'])
54
+ framework = 'Remix';
55
+ else if (deps.astro)
56
+ framework = 'Astro';
57
+ else if (deps['@sveltejs/kit'] || deps.svelte)
58
+ framework = 'Svelte / SvelteKit';
59
+ else if (deps.vite)
60
+ framework = 'Vite / React/Vue';
61
+ else if (deps['@nestjs/core'])
62
+ framework = 'NestJS';
63
+ else if (deps.hono)
64
+ framework = 'Hono';
65
+ else if (deps.fastify)
66
+ framework = 'Fastify';
67
+ else if (deps.express)
68
+ framework = 'Express.js';
69
+ else if (deps['@angular/core'])
70
+ framework = 'Angular';
71
+ else if (deps.react)
72
+ framework = 'React SPA';
73
+ else if (deps.vue)
74
+ framework = 'Vue.js SPA';
75
+ if (deps.prisma || deps['@prisma/client'])
76
+ databaseOrm = 'Prisma ORM';
77
+ else if (deps['drizzle-orm'])
78
+ databaseOrm = 'Drizzle ORM';
79
+ else if (deps.typeorm)
80
+ databaseOrm = 'TypeORM';
81
+ else if (deps.mongoose)
82
+ databaseOrm = 'Mongoose / MongoDB';
83
+ else if (deps.sequelize)
84
+ databaseOrm = 'Sequelize';
85
+ else if (deps.knex)
86
+ databaseOrm = 'Knex';
87
+ else if (deps['@supabase/supabase-js'])
88
+ databaseOrm = 'Supabase Client';
89
+ else if (deps.pg)
90
+ databaseOrm = 'pg (node-postgres)';
91
+ else if (deps.mysql2)
92
+ databaseOrm = 'mysql2';
93
+ else if (deps['better-sqlite3'] || deps.sqlite3)
94
+ databaseOrm = 'SQLite';
95
+ if (deps.tailwindcss)
96
+ styling = 'Tailwind CSS';
97
+ else if (deps['styled-components'])
98
+ styling = 'Styled Components';
99
+ else if (deps['@emotion/react'])
100
+ styling = 'Emotion';
101
+ else if (deps.sass)
102
+ styling = 'SASS / SCSS';
103
+ if (deps.vitest) {
104
+ testing = 'Vitest';
105
+ verificationCommand = 'npm run test';
106
+ }
107
+ else if (deps.jest) {
108
+ testing = 'Jest';
109
+ verificationCommand = 'npm test';
110
+ }
111
+ else if (deps.playwright || deps['@playwright/test']) {
112
+ testing = 'Playwright';
113
+ verificationCommand = 'npx playwright test';
114
+ }
115
+ if (fileExists('pnpm-lock.yaml')) {
116
+ packageManager = 'pnpm';
117
+ ecosystemManifests.push('pnpm-lock.yaml');
118
+ }
119
+ else if (fileExists('yarn.lock')) {
120
+ packageManager = 'yarn';
121
+ ecosystemManifests.push('yarn.lock');
122
+ }
123
+ else if (fileExists('bun.lockb') || fileExists('bun.lock')) {
124
+ packageManager = 'bun';
125
+ ecosystemManifests.push(fileExists('bun.lockb') ? 'bun.lockb' : 'bun.lock');
126
+ }
127
+ else if (fileExists('package-lock.json')) {
128
+ packageManager = 'npm';
129
+ ecosystemManifests.push('package-lock.json');
130
+ }
131
+ else {
132
+ packageManager = 'npm';
133
+ }
134
+ if (pkg.scripts?.test && pkg.scripts.test !== 'echo "Error: no test specified" && exit 1') {
135
+ verificationCommand = `${packageManager === 'npm' ? 'npm test' : `${packageManager} test`}`;
136
+ }
137
+ else if (pkg.scripts?.build) {
138
+ verificationCommand = `${packageManager === 'npm' ? 'npm run build' : `${packageManager} build`}`;
139
+ }
140
+ projectType = framework !== 'None detected' ? `Web Application (${framework})` : 'Node.js Application';
141
+ }
142
+ catch {
143
+ // ignore parse failure
144
+ }
145
+ }
146
+ // --- Ecosystem B: PHP (composer.json) ---
147
+ if (fileExists('composer.json')) {
148
+ ecosystemManifests.push('composer.json');
149
+ if (runtime === 'Unknown / Greenfield') {
150
+ runtime = 'PHP';
151
+ packageManager = 'composer';
152
+ projectType = 'PHP Application';
153
+ verificationCommand = 'composer test';
154
+ }
155
+ const composerRaw = readFileSafe(path.join(resolvedTarget, 'composer.json'));
156
+ try {
157
+ const composerPkg = JSON.parse(composerRaw);
158
+ if (composerPkg.name && !projectName) {
159
+ projectName = composerPkg.name;
160
+ }
161
+ if (composerPkg.description && !projectGoal) {
162
+ projectGoal = composerPkg.description;
163
+ }
164
+ const allPhpDeps = { ...composerPkg.require, ...composerPkg['require-dev'] };
165
+ if (allPhpDeps['laravel/framework']) {
166
+ framework = 'Laravel';
167
+ projectType = 'Laravel Web Application';
168
+ databaseOrm = 'Eloquent ORM';
169
+ verificationCommand = 'php artisan test';
170
+ }
171
+ else if (allPhpDeps['symfony/framework-bundle'] || allPhpDeps['symfony/symfony']) {
172
+ framework = 'Symfony';
173
+ projectType = 'Symfony Application';
174
+ databaseOrm = 'Doctrine ORM';
175
+ verificationCommand = 'bin/phpunit';
176
+ }
177
+ else if (allPhpDeps['slim/slim']) {
178
+ framework = 'Slim Framework';
179
+ }
180
+ else if (allPhpDeps['roots/bedrock'] || composerRaw.includes('wordpress')) {
181
+ framework = 'WordPress';
182
+ }
183
+ if (allPhpDeps['pestphp/pest']) {
184
+ testing = 'Pest';
185
+ }
186
+ else if (allPhpDeps['phpunit/phpunit']) {
187
+ testing = 'PHPUnit';
188
+ }
189
+ }
190
+ catch {
191
+ if (composerRaw.includes('laravel/framework')) {
192
+ framework = 'Laravel';
193
+ databaseOrm = 'Eloquent ORM';
194
+ }
195
+ }
196
+ }
197
+ // --- Ecosystem C: Python (pyproject.toml, requirements.txt, poetry.lock, Pipfile) ---
198
+ const hasPyproject = fileExists('pyproject.toml');
199
+ const hasRequirements = fileExists('requirements.txt');
200
+ const hasPipfile = fileExists('Pipfile');
201
+ if (hasPyproject || hasRequirements || hasPipfile) {
202
+ if (hasPyproject)
203
+ ecosystemManifests.push('pyproject.toml');
204
+ if (hasRequirements)
205
+ ecosystemManifests.push('requirements.txt');
206
+ if (hasPipfile)
207
+ ecosystemManifests.push('Pipfile');
208
+ if (fileExists('poetry.lock'))
209
+ ecosystemManifests.push('poetry.lock');
210
+ if (fileExists('uv.lock'))
211
+ ecosystemManifests.push('uv.lock');
212
+ if (runtime === 'Unknown / Greenfield') {
213
+ runtime = 'Python 3.x';
214
+ projectType = 'Python Service / Application';
215
+ packageManager = fileExists('poetry.lock')
216
+ ? 'Poetry'
217
+ : fileExists('uv.lock')
218
+ ? 'uv'
219
+ : fileExists('Pipfile')
220
+ ? 'Pipenv'
221
+ : 'pip';
222
+ verificationCommand = 'pytest';
223
+ }
224
+ let pyContent = '';
225
+ if (hasRequirements)
226
+ pyContent += readFileSafe(path.join(resolvedTarget, 'requirements.txt'));
227
+ if (hasPyproject)
228
+ pyContent += readFileSafe(path.join(resolvedTarget, 'pyproject.toml'));
229
+ if (pyContent.includes('fastapi'))
230
+ framework = 'FastAPI';
231
+ else if (pyContent.includes('django')) {
232
+ framework = 'Django';
233
+ databaseOrm = 'Django ORM';
234
+ verificationCommand = 'python manage.py test';
235
+ }
236
+ else if (pyContent.includes('flask'))
237
+ framework = 'Flask';
238
+ else if (pyContent.includes('litestar'))
239
+ framework = 'Litestar';
240
+ if (pyContent.includes('sqlalchemy'))
241
+ databaseOrm = 'SQLAlchemy';
242
+ else if (pyContent.includes('tortoise-orm'))
243
+ databaseOrm = 'Tortoise ORM';
244
+ else if (pyContent.includes('sqlmodel'))
245
+ databaseOrm = 'SQLModel';
246
+ if (pyContent.includes('pytest'))
247
+ testing = 'pytest';
248
+ }
249
+ // --- Ecosystem D: Go (go.mod) ---
250
+ if (fileExists('go.mod')) {
251
+ ecosystemManifests.push('go.mod');
252
+ if (runtime === 'Unknown / Greenfield') {
253
+ runtime = 'Go';
254
+ projectType = 'Go Service';
255
+ packageManager = 'go modules';
256
+ verificationCommand = 'go test ./...';
257
+ }
258
+ const modContent = readFileSafe(path.join(resolvedTarget, 'go.mod'));
259
+ const moduleMatch = modContent.match(/module\s+([^\s\n]+)/);
260
+ if (moduleMatch && !projectName) {
261
+ projectName = path.basename(moduleMatch[1]);
262
+ }
263
+ if (modContent.includes('gin-gonic/gin'))
264
+ framework = 'Gin';
265
+ else if (modContent.includes('gofiber/fiber'))
266
+ framework = 'Fiber';
267
+ else if (modContent.includes('labstack/echo'))
268
+ framework = 'Echo';
269
+ else if (modContent.includes('go-chi/chi'))
270
+ framework = 'Chi';
271
+ if (modContent.includes('gorm.io/gorm'))
272
+ databaseOrm = 'GORM';
273
+ else if (modContent.includes('entgo.io/ent'))
274
+ databaseOrm = 'Ent';
275
+ else if (modContent.includes('jmoiron/sqlx'))
276
+ databaseOrm = 'sqlx';
277
+ }
278
+ // --- Ecosystem E: Rust (Cargo.toml) ---
279
+ if (fileExists('Cargo.toml')) {
280
+ ecosystemManifests.push('Cargo.toml');
281
+ if (runtime === 'Unknown / Greenfield') {
282
+ runtime = 'Rust';
283
+ projectType = 'Rust Application';
284
+ packageManager = 'cargo';
285
+ verificationCommand = 'cargo test';
286
+ }
287
+ const cargoContent = readFileSafe(path.join(resolvedTarget, 'Cargo.toml'));
288
+ if (cargoContent.includes('actix-web'))
289
+ framework = 'Actix Web';
290
+ else if (cargoContent.includes('axum'))
291
+ framework = 'Axum';
292
+ else if (cargoContent.includes('rocket'))
293
+ framework = 'Rocket';
294
+ else if (cargoContent.includes('tauri'))
295
+ framework = 'Tauri';
296
+ if (cargoContent.includes('diesel'))
297
+ databaseOrm = 'Diesel';
298
+ else if (cargoContent.includes('sqlx'))
299
+ databaseOrm = 'SQLx';
300
+ else if (cargoContent.includes('sea-orm'))
301
+ databaseOrm = 'SeaORM';
302
+ }
303
+ // --- Ecosystem F: Java / JVM (pom.xml, build.gradle) ---
304
+ if (fileExists('pom.xml') || fileExists('build.gradle') || fileExists('build.gradle.kts')) {
305
+ if (fileExists('pom.xml'))
306
+ ecosystemManifests.push('pom.xml');
307
+ if (fileExists('build.gradle'))
308
+ ecosystemManifests.push('build.gradle');
309
+ if (fileExists('build.gradle.kts'))
310
+ ecosystemManifests.push('build.gradle.kts');
311
+ if (runtime === 'Unknown / Greenfield') {
312
+ runtime = 'Java / JVM';
313
+ projectType = 'Java Service / Application';
314
+ packageManager = fileExists('pom.xml') ? 'Maven' : 'Gradle';
315
+ verificationCommand = fileExists('pom.xml') ? 'mvn test' : './gradlew test';
316
+ }
317
+ const jvmContent = readFileSafe(path.join(resolvedTarget, fileExists('pom.xml') ? 'pom.xml' : 'build.gradle'));
318
+ if (jvmContent.includes('spring-boot'))
319
+ framework = 'Spring Boot';
320
+ else if (jvmContent.includes('quarkus'))
321
+ framework = 'Quarkus';
322
+ else if (jvmContent.includes('micronaut'))
323
+ framework = 'Micronaut';
324
+ if (jvmContent.includes('hibernate') || jvmContent.includes('spring-boot-starter-data-jpa')) {
325
+ databaseOrm = 'Hibernate / JPA';
326
+ }
327
+ }
328
+ // --- Ecosystem G: Mobile / Flutter (pubspec.yaml) ---
329
+ if (fileExists('pubspec.yaml')) {
330
+ ecosystemManifests.push('pubspec.yaml');
331
+ if (runtime === 'Unknown / Greenfield') {
332
+ runtime = 'Dart / Flutter';
333
+ framework = 'Flutter Mobile App';
334
+ projectType = 'Mobile Application (Flutter)';
335
+ packageManager = 'flutter pub';
336
+ verificationCommand = 'flutter test';
337
+ }
338
+ }
339
+ return {
340
+ projectName,
341
+ projectGoal,
342
+ projectType,
343
+ runtime,
344
+ framework,
345
+ databaseOrm,
346
+ styling,
347
+ testing,
348
+ packageManager,
349
+ verificationCommand,
350
+ ecosystemManifests,
351
+ monorepoWorkspaces,
352
+ monorepoIndicators,
353
+ };
354
+ }
@@ -0,0 +1,5 @@
1
+ export interface OrmDetectionResult {
2
+ detectedOrmConfig: string;
3
+ databaseOrm: string;
4
+ }
5
+ export declare function detectOrm(resolvedTarget: string, fileExists: (relPath: string) => boolean, initialOrm: string): OrmDetectionResult;
@@ -0,0 +1,59 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export function detectOrm(resolvedTarget, fileExists, initialOrm) {
4
+ let detectedOrmConfig = '';
5
+ let databaseOrm = initialOrm;
6
+ if (fileExists('prisma/schema.prisma')) {
7
+ detectedOrmConfig = 'prisma/schema.prisma';
8
+ databaseOrm = 'Prisma ORM';
9
+ }
10
+ else if (fileExists('schema.prisma')) {
11
+ detectedOrmConfig = 'schema.prisma';
12
+ databaseOrm = 'Prisma ORM';
13
+ }
14
+ if (fileExists('drizzle.config.ts')) {
15
+ detectedOrmConfig = 'drizzle.config.ts';
16
+ databaseOrm = 'Drizzle ORM';
17
+ }
18
+ else if (fileExists('drizzle.config.js')) {
19
+ detectedOrmConfig = 'drizzle.config.js';
20
+ databaseOrm = 'Drizzle ORM';
21
+ }
22
+ else if (fileExists('drizzle.config.json')) {
23
+ detectedOrmConfig = 'drizzle.config.json';
24
+ databaseOrm = 'Drizzle ORM';
25
+ }
26
+ if (fileExists('knexfile.js')) {
27
+ detectedOrmConfig = 'knexfile.js';
28
+ databaseOrm = 'Knex';
29
+ }
30
+ else if (fileExists('knexfile.ts')) {
31
+ detectedOrmConfig = 'knexfile.ts';
32
+ databaseOrm = 'Knex';
33
+ }
34
+ if (fileExists('alembic.ini')) {
35
+ detectedOrmConfig = 'alembic.ini';
36
+ databaseOrm = databaseOrm === 'None detected' ? 'SQLAlchemy (Alembic)' : `${databaseOrm} (Alembic)`;
37
+ }
38
+ if (fileExists('database/migrations')) {
39
+ try {
40
+ const isDir = fs.statSync(path.join(resolvedTarget, 'database/migrations')).isDirectory();
41
+ if (isDir) {
42
+ detectedOrmConfig = 'database/migrations';
43
+ if (databaseOrm === 'None detected')
44
+ databaseOrm = 'SQL Migrations';
45
+ }
46
+ }
47
+ catch {
48
+ // ignore
49
+ }
50
+ }
51
+ if (fileExists('ormconfig.json')) {
52
+ detectedOrmConfig = 'ormconfig.json';
53
+ databaseOrm = 'TypeORM';
54
+ }
55
+ return {
56
+ detectedOrmConfig,
57
+ databaseOrm,
58
+ };
59
+ }
@@ -0,0 +1,19 @@
1
+ export interface SubServiceInfo {
2
+ name: string;
3
+ dirPath: string;
4
+ manifests: string[];
5
+ tech: string;
6
+ runtime?: string;
7
+ framework?: string;
8
+ orm?: string;
9
+ ormConfig?: string;
10
+ }
11
+ export interface WorkspaceDetectionResult {
12
+ monorepoIndicators: string[];
13
+ monorepoWorkspaces: string[];
14
+ keyDirectories: string[];
15
+ detectedSubpackagesCount: number;
16
+ independentServices: SubServiceInfo[];
17
+ ecosystemManifests: string[];
18
+ }
19
+ export declare function detectWorkspacesAndServices(resolvedTarget: string, fileExists: (relPath: string) => boolean, readFileSafe: (filePath: string) => string): WorkspaceDetectionResult;