chati-dev 4.2.2 → 4.3.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 (220) hide show
  1. package/README.md +80 -53
  2. package/bin/chati.js +150 -5
  3. package/framework/agents/build/dev.md +509 -76
  4. package/framework/agents/deploy/devops.md +40 -25
  5. package/framework/agents/discover/brief.md +156 -22
  6. package/framework/agents/discover/brownfield-wu.md +24 -14
  7. package/framework/agents/discover/greenfield-wu.md +100 -14
  8. package/framework/agents/plan/architect-data-engineer.md +6 -6
  9. package/framework/agents/plan/architect-system.md +46 -12
  10. package/framework/agents/plan/architect.md +40 -20
  11. package/framework/agents/plan/detail.md +36 -24
  12. package/framework/agents/plan/phases.md +36 -26
  13. package/framework/agents/plan/tasks.md +114 -33
  14. package/framework/agents/plan/ux-brand-architect.md +240 -8
  15. package/framework/agents/plan/ux-component-engineer.md +28 -13
  16. package/framework/agents/plan/ux-researcher.md +7 -6
  17. package/framework/agents/plan/ux.md +55 -22
  18. package/framework/agents/quality/qa-implementation.md +143 -74
  19. package/framework/agents/quality/qa-planning.md +115 -42
  20. package/framework/agents/quality/qa-visual.md +439 -0
  21. package/framework/agents/shared/visualizer.md +128 -0
  22. package/framework/config.yaml +7 -6
  23. package/framework/constitution.md +127 -44
  24. package/framework/context/governance.md +12 -7
  25. package/framework/context/quality.md +6 -5
  26. package/framework/context/root.md +6 -6
  27. package/framework/data/entity-registry.yaml +377 -4
  28. package/framework/data/model-limits.json +19 -0
  29. package/framework/domains/agents/qa-visual.yaml +74 -0
  30. package/framework/domains/constitution.yaml +46 -2
  31. package/framework/domains/workflows/greenfield-fullstack.yaml +2 -2
  32. package/framework/hooks/advance-trigger.js +131 -0
  33. package/framework/hooks/brief-validator.js +83 -0
  34. package/framework/hooks/constitution-guard.js +24 -5
  35. package/framework/hooks/license-guard.js +62 -27
  36. package/framework/hooks/mode-governance.js +13 -2
  37. package/framework/hooks/model-governance.js +1 -0
  38. package/framework/hooks/post-dev.js +207 -0
  39. package/framework/hooks/prism-engine.js +274 -105
  40. package/framework/hooks/reasoning-escalator.js +371 -0
  41. package/framework/hooks/reference-trigger.js +117 -0
  42. package/framework/hooks/session-digest.js +50 -1
  43. package/framework/hooks/settings.json +32 -1
  44. package/framework/hooks/style-guard.js +25 -6
  45. package/framework/hooks/team-quality-gate.js +19 -12
  46. package/framework/hooks/undercover-guard.js +4 -2
  47. package/framework/i18n/en.yaml +3 -3
  48. package/framework/i18n/es.yaml +3 -3
  49. package/framework/i18n/fr.yaml +3 -3
  50. package/framework/i18n/pt.yaml +3 -3
  51. package/framework/intelligence/context-engine.md +4 -5
  52. package/framework/intelligence/decision-engine.md +1 -1
  53. package/framework/intelligence/hooks-performance.md +3 -3
  54. package/framework/migrations/v1.0-to-v1.1.yaml +1 -1
  55. package/framework/migrations/v1.4-to-v2.0.yaml +11 -11
  56. package/framework/migrations/v4.0-to-v4.1.yaml +2 -2
  57. package/framework/migrations/v4.2-to-v4.3.yaml +29 -0
  58. package/framework/orchestrator/chati-router.js +387 -0
  59. package/framework/orchestrator/chati-update.md +40 -40
  60. package/framework/orchestrator/chati.md +294 -94
  61. package/framework/scaffold/motion-premium/README.md +89 -0
  62. package/framework/scaffold/motion-premium/app/globals.css.template +400 -0
  63. package/framework/scaffold/motion-premium/app/layout.tsx.template +110 -0
  64. package/framework/scaffold/motion-premium/components/animation/BackgroundCrossfadeProvider.tsx.template +170 -0
  65. package/framework/scaffold/motion-premium/components/animation/LenisProvider.tsx.template +49 -0
  66. package/framework/scaffold/motion-premium/components/animation/PageTransitionWrapper.tsx.template +83 -0
  67. package/framework/scaffold/motion-premium/components/animation/Preloader.tsx.template +171 -0
  68. package/framework/scaffold/motion-premium/components/ui/Container.tsx.template +69 -0
  69. package/framework/scaffold/motion-premium/components/ui/PageSection.tsx.template +74 -0
  70. package/framework/scaffold/motion-premium/lib/animations/gsap.ts.template +112 -0
  71. package/framework/scaffold/motion-premium/lib/animations/refreshCoordinator.ts.template +75 -0
  72. package/framework/scaffold/motion-premium/lib/animations/tokens.ts.template +119 -0
  73. package/framework/scaffold/motion-premium/lib/animations/useGsapContext.ts.template +92 -0
  74. package/framework/scaffold/motion-premium/lib/animations/useScrollSnapStepper.ts.template +265 -0
  75. package/framework/scaffold/motion-premium/lib/animations/useSmoothScroll.ts.template +67 -0
  76. package/framework/scaffold/motion-premium/lib/brand.ts.template +43 -0
  77. package/framework/scaffold/motion-premium/scaffold.yaml +174 -0
  78. package/framework/scaffold/motion-premium-3d/README.md +80 -0
  79. package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoCanvas.tsx.template +81 -0
  80. package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoClient.tsx.template +75 -0
  81. package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/page.tsx.template +26 -0
  82. package/framework/scaffold/motion-premium-3d/components/3d/CameraRig.tsx.template +100 -0
  83. package/framework/scaffold/motion-premium-3d/components/3d/CanvasProvider.tsx.template +85 -0
  84. package/framework/scaffold/motion-premium-3d/components/3d/InvalidateOnScroll.tsx.template +51 -0
  85. package/framework/scaffold/motion-premium-3d/components/3d/MeshCrossfade.tsx.template +79 -0
  86. package/framework/scaffold/motion-premium-3d/components/3d/ScrollCrossfade.tsx.template +88 -0
  87. package/framework/scaffold/motion-premium-3d/components/3d/ScrollScene.tsx.template +121 -0
  88. package/framework/scaffold/motion-premium-3d/components/webgl/SceneFallback.tsx.template +65 -0
  89. package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +68 -0
  90. package/framework/scaffold/motion-premium-3d/lib/webgl/detect.ts.template +69 -0
  91. package/framework/scaffold/motion-premium-3d/scaffold.yaml +133 -0
  92. package/framework/schemas/session.schema.json +109 -21
  93. package/framework/scripts/reference-capture.js +430 -0
  94. package/framework/scripts/visual-qa.js +674 -0
  95. package/framework/tasks/orchestrator-handoff.md +1 -1
  96. package/framework/tasks/orchestrator-resume.md +1 -1
  97. package/framework/tasks/orchestrator-route.md +1 -1
  98. package/framework/tasks/orchestrator-status.md +3 -3
  99. package/framework/tasks/qa-planning-gate-define.md +1 -1
  100. package/framework/templates/brandbook-html-tmpl.md +1 -1
  101. package/framework/templates/brandbook-tmpl.yaml +1 -1
  102. package/framework/templates/component-spec-tmpl.yaml +1 -1
  103. package/framework/templates/design-token-tmpl.yaml +1 -1
  104. package/framework/templates/icon-system-tmpl.yaml +1 -1
  105. package/framework/templates/team-planning-tasks.yaml +6 -5
  106. package/framework/workflows/brownfield-discovery.yaml +2 -2
  107. package/framework/workflows/brownfield-fullstack.yaml +15 -11
  108. package/framework/workflows/brownfield-service.yaml +14 -10
  109. package/framework/workflows/brownfield-ui.yaml +15 -11
  110. package/framework/workflows/greenfield-fullstack.yaml +16 -13
  111. package/framework/workflows/quick-flow.yaml +3 -3
  112. package/framework/workflows/standard-flow.yaml +12 -9
  113. package/package.json +10 -5
  114. package/src/autonomy/autonomous-gate.js +1 -0
  115. package/src/autonomy/build-state.js +1 -2
  116. package/src/autonomy/progress-reporter.js +1 -1
  117. package/src/config/agent-customizer.js +11 -3
  118. package/src/config/claude-settings-generator.js +27 -7
  119. package/src/config/context-file-generator.js +41 -21
  120. package/src/config/framework-adapter.js +1 -0
  121. package/src/config/gemini-hooks-generator.js +19 -7
  122. package/src/config/mcp-configs.js +1 -0
  123. package/src/context/layers/l1-global.js +2 -1
  124. package/src/dashboard/data-reader.js +4 -3
  125. package/src/dashboard/layout.js +2 -1
  126. package/src/decision/analyzer.js +6 -30
  127. package/src/decision/engine.js +4 -28
  128. package/src/decision/registry-healer.js +3 -2
  129. package/src/decision/registry-updater.js +23 -14
  130. package/src/extensions/loader.js +2 -8
  131. package/src/gates/g1-planning-complete.js +2 -1
  132. package/src/gates/g2-qa-planning.js +2 -1
  133. package/src/gates/g3-implementation.js +2 -1
  134. package/src/gates/g4-qa-implementation.js +3 -2
  135. package/src/gates/g5-deploy-ready.js +2 -1
  136. package/src/health/engine.js +4 -3
  137. package/src/installer/core.js +422 -81
  138. package/src/installer/preflight.js +131 -0
  139. package/src/installer/provider-overlay.js +3 -3
  140. package/src/installer/scaffold-applier.js +358 -0
  141. package/src/installer/templates.js +46 -29
  142. package/src/installer/validator.js +17 -12
  143. package/src/intelligence/registry-manager.js +22 -29
  144. package/src/intelligence/timeline.js +11 -6
  145. package/src/license/commands.js +1 -1
  146. package/src/license/wait.js +102 -0
  147. package/src/memory/agent-memory.js +81 -0
  148. package/src/memory/dream.js +32 -1
  149. package/src/merger/replace-merger.js +28 -15
  150. package/src/orchestrator/agent-selector.js +2 -1
  151. package/src/orchestrator/cli.js +1869 -71
  152. package/src/orchestrator/doctor.js +270 -0
  153. package/src/orchestrator/handoff-engine.js +4 -3
  154. package/src/orchestrator/index.js +2 -0
  155. package/src/orchestrator/pipeline-manager.js +306 -15
  156. package/src/orchestrator/session-manager.js +331 -6
  157. package/src/tasks/handoff.js +3 -2
  158. package/src/telemetry/config.js +4 -3
  159. package/src/telemetry/schema.js +1 -0
  160. package/src/terminal/collector.js +3 -2
  161. package/src/terminal/index.js +1 -2
  162. package/src/terminal/isolation.js +52 -18
  163. package/src/terminal/prompt-builder.js +42 -25
  164. package/src/terminal/run-parallel.js +1 -1
  165. package/src/terminal/run-team.js +3 -3
  166. package/src/terminal/team-task-list.js +43 -4
  167. package/src/upgrade/backup.js +3 -2
  168. package/src/upgrade/checker.js +3 -2
  169. package/src/upgrade/migrator.js +65 -7
  170. package/src/upgrade/tracked-files-detector.js +86 -0
  171. package/src/upgrade/user-messages.js +94 -0
  172. package/src/utils/config-parser.js +2 -1
  173. package/src/utils/feature-flags.js +2 -1
  174. package/src/utils/flatten-entities.js +69 -0
  175. package/src/utils/framework-dir.js +16 -0
  176. package/src/utils/model-id.js +85 -0
  177. package/src/utils/provider-limits.js +84 -23
  178. package/src/utils/schema-validator.js +1 -1
  179. package/src/wizard/i18n.js +5 -4
  180. package/src/wizard/index.js +14 -0
  181. package/assets/logo - c/303/263pia.png +0 -0
  182. package/assets/logo.svg +0 -42
  183. package/assets/logo2.png +0 -0
  184. package/assets/social-preview.png +0 -0
  185. package/scripts/bundle-framework.js +0 -69
  186. package/scripts/changelog-generator.js +0 -222
  187. package/scripts/codebase-mapper.js +0 -728
  188. package/scripts/commit-message-generator.js +0 -167
  189. package/scripts/coverage-analyzer.js +0 -260
  190. package/scripts/dependency-analyzer.js +0 -280
  191. package/scripts/doctor/checks/agents.js +0 -77
  192. package/scripts/doctor/checks/constitution.js +0 -41
  193. package/scripts/doctor/checks/domain-alignment.js +0 -58
  194. package/scripts/doctor/checks/prism-layers.js +0 -84
  195. package/scripts/doctor/checks/registry.js +0 -55
  196. package/scripts/doctor/checks/schemas.js +0 -61
  197. package/scripts/doctor/fixes/reference-fix.js +0 -100
  198. package/scripts/doctor/fixes/registry-fix.js +0 -56
  199. package/scripts/doctor/index.js +0 -212
  200. package/scripts/framework-analyzer.js +0 -308
  201. package/scripts/generate-constitution-domain.js +0 -253
  202. package/scripts/generate-signing-key.js +0 -33
  203. package/scripts/health-check.js +0 -481
  204. package/scripts/ide-sync.js +0 -326
  205. package/scripts/performance-analyzer.js +0 -325
  206. package/scripts/plan-tracker.js +0 -278
  207. package/scripts/populate-entity-registry.js +0 -481
  208. package/scripts/pr-review.js +0 -317
  209. package/scripts/rollback-manager.js +0 -310
  210. package/scripts/semantic-lint.js +0 -328
  211. package/scripts/sign-manifest.js +0 -53
  212. package/scripts/stuck-detector.js +0 -343
  213. package/scripts/test-quality-assessment.js +0 -257
  214. package/scripts/validate-agents.js +0 -368
  215. package/scripts/validate-package.js +0 -505
  216. package/scripts/validate-tasks.js +0 -465
  217. package/src/autonomy/worktree-manager.js +0 -250
  218. package/src/intelligence/decision-engine.js +0 -256
  219. package/src/intelligence/document-sharder.js +0 -221
  220. package/src/intelligence/elicitation.js +0 -265
@@ -1,212 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * @fileoverview Doctor — Modular diagnostic system with auto-fix capability.
5
- *
6
- * Orchestrates individual check modules and fix modules to provide
7
- * comprehensive framework health validation and automatic repair.
8
- *
9
- * Exports:
10
- * runDoctor(frameworkDir, options) → DoctorReport
11
- * formatDoctorReport(report) → human-readable string
12
- *
13
- * DoctorReport:
14
- * { overall, checks, fixes, timestamp, summary }
15
- */
16
-
17
- import { existsSync } from 'fs';
18
- import { join } from 'path';
19
- import { fileURLToPath } from 'url';
20
-
21
- // Check modules
22
- import { checkRegistry } from './checks/registry.js';
23
- import { checkSchemas } from './checks/schemas.js';
24
- import { checkConstitution } from './checks/constitution.js';
25
- import { checkAgents } from './checks/agents.js';
26
- import { checkPrismLayers } from './checks/prism-layers.js';
27
- import { checkDomainAlignment } from './checks/domain-alignment.js';
28
-
29
- // Fix modules
30
- import { fixRegistryCount } from './fixes/registry-fix.js';
31
- import { fixBrokenReferences } from './fixes/reference-fix.js';
32
-
33
- /**
34
- * Map of fixId to fix function.
35
- */
36
- const FIX_REGISTRY = {
37
- 'registry-count': fixRegistryCount,
38
- 'broken-references': fixBrokenReferences,
39
- };
40
-
41
- /**
42
- * All available check functions.
43
- */
44
- const CHECK_REGISTRY = {
45
- registry: checkRegistry,
46
- schemas: checkSchemas,
47
- constitution: checkConstitution,
48
- agents: checkAgents,
49
- prismLayers: checkPrismLayers,
50
- domainAlignment: checkDomainAlignment,
51
- };
52
-
53
- /**
54
- * Run the doctor diagnostic suite.
55
- *
56
- * @param {string} frameworkDir - Path to the framework directory
57
- * @param {object} [options={}] - Configuration options
58
- * @param {boolean} [options.fix=false] - Run auto-fix for fixable issues
59
- * @param {string[]} [options.checks] - Specific checks to run (default: all)
60
- * @returns {object} DoctorReport
61
- */
62
- export function runDoctor(frameworkDir, options = {}) {
63
- const { fix = false, checks: checkFilter } = options;
64
-
65
- if (!existsSync(frameworkDir)) {
66
- return {
67
- overall: 'UNHEALTHY',
68
- checks: {
69
- frameworkDir: { pass: false, details: `Directory not found: ${frameworkDir}`, severity: 'critical', fixable: false, fixId: null },
70
- },
71
- fixes: [],
72
- timestamp: new Date().toISOString(),
73
- summary: { total: 1, passed: 0, failed: 1, criticalFailures: 1, warnings: 0, fixesApplied: 0 },
74
- };
75
- }
76
-
77
- // Run checks
78
- const checksToRun = checkFilter
79
- ? Object.entries(CHECK_REGISTRY).filter(([name]) => checkFilter.includes(name))
80
- : Object.entries(CHECK_REGISTRY);
81
-
82
- const checkResults = {};
83
- for (const [name, checkFn] of checksToRun) {
84
- checkResults[name] = checkFn(frameworkDir);
85
- }
86
-
87
- // Run fixes if requested
88
- const fixes = [];
89
- if (fix) {
90
- for (const [name, result] of Object.entries(checkResults)) {
91
- if (!result.pass && result.fixable && result.fixId) {
92
- const fixFn = FIX_REGISTRY[result.fixId];
93
- if (fixFn) {
94
- const fixResult = fixFn(frameworkDir);
95
- fixes.push({ check: name, fixId: result.fixId, ...fixResult });
96
-
97
- // Re-run the check if fix was applied
98
- if (fixResult.fixed) {
99
- const checkFn = CHECK_REGISTRY[name];
100
- if (checkFn) {
101
- checkResults[name] = checkFn(frameworkDir);
102
- }
103
- }
104
- }
105
- }
106
- }
107
- }
108
-
109
- // Determine overall health
110
- const criticalFailures = Object.values(checkResults).filter(c => !c.pass && c.severity === 'critical');
111
- const warnings = Object.values(checkResults).filter(c => !c.pass && c.severity === 'warning');
112
-
113
- let overall;
114
- if (criticalFailures.length > 0) {
115
- overall = 'UNHEALTHY';
116
- } else if (warnings.length > 0) {
117
- overall = 'DEGRADED';
118
- } else {
119
- overall = 'HEALTHY';
120
- }
121
-
122
- return {
123
- overall,
124
- checks: checkResults,
125
- fixes,
126
- timestamp: new Date().toISOString(),
127
- summary: {
128
- total: Object.keys(checkResults).length,
129
- passed: Object.values(checkResults).filter(c => c.pass).length,
130
- failed: Object.values(checkResults).filter(c => !c.pass).length,
131
- criticalFailures: criticalFailures.length,
132
- warnings: warnings.length,
133
- fixesApplied: fixes.filter(f => f.fixed).length,
134
- },
135
- };
136
- }
137
-
138
- /**
139
- * Format a DoctorReport into a human-readable string.
140
- *
141
- * @param {object} report - DoctorReport from runDoctor
142
- * @returns {string} Formatted report
143
- */
144
- export function formatDoctorReport(report) {
145
- const statusSymbol = {
146
- HEALTHY: '[OK]',
147
- DEGRADED: '[WARN]',
148
- UNHEALTHY: '[FAIL]',
149
- };
150
-
151
- const checkSymbol = (check) => check.pass ? '[PASS]' : '[FAIL]';
152
-
153
- const lines = [
154
- '=== Doctor Report ===',
155
- `Status: ${statusSymbol[report.overall] || '[ ? ]'} ${report.overall}`,
156
- `Time: ${report.timestamp}`,
157
- '',
158
- ];
159
-
160
- if (report.summary) {
161
- lines.push(`Summary: ${report.summary.passed}/${report.summary.total} checks passed`);
162
- if (report.summary.criticalFailures > 0) {
163
- lines.push(` ${report.summary.criticalFailures} critical failure(s)`);
164
- }
165
- if (report.summary.warnings > 0) {
166
- lines.push(` ${report.summary.warnings} warning(s)`);
167
- }
168
- if (report.summary.fixesApplied > 0) {
169
- lines.push(` ${report.summary.fixesApplied} fix(es) applied`);
170
- }
171
- lines.push('');
172
- }
173
-
174
- lines.push('Checks:');
175
- for (const [name, check] of Object.entries(report.checks)) {
176
- const symbol = checkSymbol(check);
177
- const severity = check.severity !== 'info' ? ` (${check.severity})` : '';
178
- const fixable = check.fixable ? ' [fixable]' : '';
179
- lines.push(` ${symbol} ${name}: ${check.details}${severity}${fixable}`);
180
- }
181
-
182
- if (report.fixes && report.fixes.length > 0) {
183
- lines.push('');
184
- lines.push('Fixes:');
185
- for (const fix of report.fixes) {
186
- const symbol = fix.fixed ? '[FIXED]' : '[SKIP]';
187
- lines.push(` ${symbol} ${fix.check}: ${fix.details}`);
188
- }
189
- }
190
-
191
- lines.push('');
192
- lines.push('=== End Report ===');
193
-
194
- return lines.join('\n');
195
- }
196
-
197
- // ---------------------------------------------------------------------------
198
- // CLI entrypoint
199
- // ---------------------------------------------------------------------------
200
-
201
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
202
- const args = process.argv.slice(2);
203
- const fix = args.includes('--fix');
204
- const frameworkDir = args.find(a => !a.startsWith('--')) || join(process.cwd(), 'chati.dev');
205
-
206
- const report = runDoctor(frameworkDir, { fix });
207
- console.log(formatDoctorReport(report));
208
-
209
- if (report.overall === 'UNHEALTHY') {
210
- process.exit(1);
211
- }
212
- }
@@ -1,308 +0,0 @@
1
- /**
2
- * Framework Analyzer — Detects project technology stack through static analysis.
3
- *
4
- * Inspects package.json, configuration files, and file patterns to identify
5
- * frameworks, languages, package managers, ORMs, databases, and monorepo tools.
6
- *
7
- * @module scripts/framework-analyzer
8
- */
9
-
10
- import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';
11
- import { join } from 'node:path';
12
-
13
- /**
14
- * @typedef {Object} FrameworkReport
15
- * @property {string[]} frontendFrameworks
16
- * @property {string[]} backendFrameworks
17
- * @property {string[]} languages
18
- * @property {string} packageManager
19
- * @property {string[]} monorepoTools
20
- * @property {string[]} orms
21
- * @property {string[]} databases
22
- * @property {string[]} testingFrameworks
23
- * @property {string[]} buildTools
24
- * @property {Object} raw — raw detection results before merging
25
- */
26
-
27
- /**
28
- * Safely reads and parses a JSON file.
29
- * @param {string} filePath
30
- * @returns {Object|null}
31
- */
32
- function readJSON(filePath) {
33
- try {
34
- return JSON.parse(readFileSync(filePath, 'utf-8'));
35
- } catch {
36
- return null;
37
- }
38
- }
39
-
40
- /**
41
- * Checks if a file or directory exists.
42
- * @param {...string} segments
43
- * @returns {boolean}
44
- */
45
- function pathExists(...segments) {
46
- return existsSync(join(...segments));
47
- }
48
-
49
- /**
50
- * Detects technologies from package.json dependencies.
51
- *
52
- * @param {string} targetDir
53
- * @returns {Partial<FrameworkReport>}
54
- */
55
- export function detectByPackageJson(targetDir) {
56
- const pkg = readJSON(join(targetDir, 'package.json'));
57
- if (!pkg) return {};
58
-
59
- const allDeps = {
60
- ...pkg.dependencies,
61
- ...pkg.devDependencies,
62
- ...pkg.peerDependencies,
63
- };
64
- const depNames = new Set(Object.keys(allDeps));
65
-
66
- const frontendFrameworks = [];
67
- const backendFrameworks = [];
68
- const orms = [];
69
- const databases = [];
70
- const testingFrameworks = [];
71
- const buildTools = [];
72
- const monorepoTools = [];
73
-
74
- // Frontend
75
- if (depNames.has('next')) frontendFrameworks.push('Next.js');
76
- else if (depNames.has('react')) frontendFrameworks.push('React');
77
- if (depNames.has('nuxt') || depNames.has('nuxt3')) frontendFrameworks.push('Nuxt');
78
- else if (depNames.has('vue')) frontendFrameworks.push('Vue');
79
- if (depNames.has('@sveltejs/kit')) frontendFrameworks.push('SvelteKit');
80
- else if (depNames.has('svelte')) frontendFrameworks.push('Svelte');
81
- if (depNames.has('@angular/core')) frontendFrameworks.push('Angular');
82
-
83
- // Backend
84
- if (depNames.has('express')) backendFrameworks.push('Express');
85
- if (depNames.has('fastify')) backendFrameworks.push('Fastify');
86
- if (depNames.has('koa')) backendFrameworks.push('Koa');
87
- if (depNames.has('@nestjs/core')) backendFrameworks.push('NestJS');
88
- if (depNames.has('hono')) backendFrameworks.push('Hono');
89
- if (depNames.has('@hapi/hapi') || depNames.has('hapi')) backendFrameworks.push('Hapi');
90
-
91
- // ORM
92
- if (depNames.has('prisma') || depNames.has('@prisma/client')) orms.push('Prisma');
93
- if (depNames.has('drizzle-orm')) orms.push('Drizzle');
94
- if (depNames.has('typeorm')) orms.push('TypeORM');
95
- if (depNames.has('sequelize')) orms.push('Sequelize');
96
- if (depNames.has('mongoose')) orms.push('Mongoose');
97
- if (depNames.has('knex')) orms.push('Knex');
98
-
99
- // Database
100
- if (depNames.has('pg') || depNames.has('postgres') || depNames.has('@vercel/postgres')) databases.push('PostgreSQL');
101
- if (depNames.has('mysql2') || depNames.has('mysql')) databases.push('MySQL');
102
- if (depNames.has('mongodb') || depNames.has('mongoose')) databases.push('MongoDB');
103
- if (depNames.has('better-sqlite3') || depNames.has('sqlite3')) databases.push('SQLite');
104
- if (depNames.has('redis') || depNames.has('ioredis')) databases.push('Redis');
105
-
106
- // Testing
107
- if (depNames.has('jest')) testingFrameworks.push('Jest');
108
- if (depNames.has('vitest')) testingFrameworks.push('Vitest');
109
- if (depNames.has('mocha')) testingFrameworks.push('Mocha');
110
- if (depNames.has('@playwright/test') || depNames.has('playwright')) testingFrameworks.push('Playwright');
111
- if (depNames.has('cypress')) testingFrameworks.push('Cypress');
112
-
113
- // Build tools
114
- if (depNames.has('vite')) buildTools.push('Vite');
115
- if (depNames.has('webpack')) buildTools.push('Webpack');
116
- if (depNames.has('esbuild')) buildTools.push('esbuild');
117
- if (depNames.has('rollup')) buildTools.push('Rollup');
118
- if (depNames.has('tsup')) buildTools.push('tsup');
119
- if (depNames.has('turbo')) buildTools.push('Turborepo');
120
-
121
- // Monorepo
122
- if (depNames.has('turbo') || depNames.has('turborepo')) monorepoTools.push('Turborepo');
123
- if (depNames.has('lerna')) monorepoTools.push('Lerna');
124
- if (depNames.has('nx') || depNames.has('@nrwl/workspace')) monorepoTools.push('Nx');
125
-
126
- return { frontendFrameworks, backendFrameworks, orms, databases, testingFrameworks, buildTools, monorepoTools };
127
- }
128
-
129
- /**
130
- * Detects technologies from configuration files present in the project.
131
- *
132
- * @param {string} targetDir
133
- * @returns {Partial<FrameworkReport>}
134
- */
135
- export function detectByConfigFiles(targetDir) {
136
- const languages = [];
137
- const buildTools = [];
138
- const monorepoTools = [];
139
-
140
- // TypeScript
141
- if (pathExists(targetDir, 'tsconfig.json') || pathExists(targetDir, 'tsconfig.base.json')) {
142
- languages.push('TypeScript');
143
- }
144
-
145
- // Python
146
- if (pathExists(targetDir, 'pyproject.toml') || pathExists(targetDir, 'setup.py') || pathExists(targetDir, 'requirements.txt')) {
147
- languages.push('Python');
148
- }
149
-
150
- // Go
151
- if (pathExists(targetDir, 'go.mod')) {
152
- languages.push('Go');
153
- }
154
-
155
- // Rust
156
- if (pathExists(targetDir, 'Cargo.toml')) {
157
- languages.push('Rust');
158
- }
159
-
160
- // Build tools
161
- if (pathExists(targetDir, 'vite.config.js') || pathExists(targetDir, 'vite.config.ts')) {
162
- buildTools.push('Vite');
163
- }
164
- if (pathExists(targetDir, 'webpack.config.js') || pathExists(targetDir, 'webpack.config.ts')) {
165
- buildTools.push('Webpack');
166
- }
167
- if (pathExists(targetDir, 'rollup.config.js') || pathExists(targetDir, 'rollup.config.mjs')) {
168
- buildTools.push('Rollup');
169
- }
170
-
171
- // Monorepo
172
- if (pathExists(targetDir, 'turbo.json')) monorepoTools.push('Turborepo');
173
- if (pathExists(targetDir, 'lerna.json')) monorepoTools.push('Lerna');
174
- if (pathExists(targetDir, 'nx.json')) monorepoTools.push('Nx');
175
- if (pathExists(targetDir, 'pnpm-workspace.yaml')) monorepoTools.push('pnpm workspaces');
176
-
177
- // Package manager detection
178
- let packageManager = 'npm'; // default
179
- if (pathExists(targetDir, 'bun.lockb') || pathExists(targetDir, 'bun.lock')) {
180
- packageManager = 'bun';
181
- } else if (pathExists(targetDir, 'pnpm-lock.yaml')) {
182
- packageManager = 'pnpm';
183
- } else if (pathExists(targetDir, 'yarn.lock')) {
184
- packageManager = 'yarn';
185
- }
186
-
187
- return { languages, buildTools, monorepoTools, packageManager };
188
- }
189
-
190
- /**
191
- * Detects technologies from file patterns in the project directory.
192
- *
193
- * @param {string} targetDir
194
- * @returns {Partial<FrameworkReport>}
195
- */
196
- export function detectByFilePatterns(targetDir) {
197
- const languages = [];
198
-
199
- // Check top-level files and src/ for language clues
200
- const dirsToCheck = [targetDir];
201
- if (pathExists(targetDir, 'src')) dirsToCheck.push(join(targetDir, 'src'));
202
-
203
- const extensions = new Set();
204
- for (const dir of dirsToCheck) {
205
- let entries;
206
- try {
207
- entries = readdirSync(dir);
208
- } catch {
209
- continue;
210
- }
211
- for (const entry of entries) {
212
- try {
213
- const stat = statSync(join(dir, entry));
214
- if (stat.isFile()) {
215
- const ext = entry.slice(entry.lastIndexOf('.'));
216
- extensions.add(ext);
217
- }
218
- } catch {
219
- // skip
220
- }
221
- }
222
- }
223
-
224
- if (extensions.has('.ts') || extensions.has('.tsx')) {
225
- languages.push('TypeScript');
226
- }
227
- if (extensions.has('.js') || extensions.has('.jsx') || extensions.has('.mjs')) {
228
- languages.push('JavaScript');
229
- }
230
- if (extensions.has('.py')) {
231
- languages.push('Python');
232
- }
233
- if (extensions.has('.go')) {
234
- languages.push('Go');
235
- }
236
- if (extensions.has('.rs')) {
237
- languages.push('Rust');
238
- }
239
-
240
- return { languages };
241
- }
242
-
243
- /**
244
- * Merges multiple partial detection reports, deduplicating arrays.
245
- *
246
- * @param {...Partial<FrameworkReport>} reports
247
- * @returns {FrameworkReport}
248
- */
249
- export function mergeDetections(...reports) {
250
- const merged = {
251
- frontendFrameworks: [],
252
- backendFrameworks: [],
253
- languages: [],
254
- packageManager: 'npm',
255
- monorepoTools: [],
256
- orms: [],
257
- databases: [],
258
- testingFrameworks: [],
259
- buildTools: [],
260
- raw: {},
261
- };
262
-
263
- const arrayFields = [
264
- 'frontendFrameworks',
265
- 'backendFrameworks',
266
- 'languages',
267
- 'monorepoTools',
268
- 'orms',
269
- 'databases',
270
- 'testingFrameworks',
271
- 'buildTools',
272
- ];
273
-
274
- for (const report of reports) {
275
- if (!report) continue;
276
- for (const field of arrayFields) {
277
- if (Array.isArray(report[field])) {
278
- for (const item of report[field]) {
279
- if (!merged[field].includes(item)) {
280
- merged[field].push(item);
281
- }
282
- }
283
- }
284
- }
285
- if (report.packageManager) {
286
- merged.packageManager = report.packageManager;
287
- }
288
- }
289
-
290
- // Store raw detections for debugging
291
- merged.raw = { reports: reports.filter(Boolean) };
292
-
293
- return merged;
294
- }
295
-
296
- /**
297
- * Full framework analysis for a target directory.
298
- *
299
- * @param {string} targetDir
300
- * @returns {FrameworkReport}
301
- */
302
- export function analyzeFramework(targetDir) {
303
- const byPackage = detectByPackageJson(targetDir);
304
- const byConfig = detectByConfigFiles(targetDir);
305
- const byFiles = detectByFilePatterns(targetDir);
306
-
307
- return mergeDetections(byPackage, byConfig, byFiles);
308
- }