chati-dev 4.2.2 → 4.3.1

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 (221) hide show
  1. package/README.md +80 -53
  2. package/bin/chati.js +170 -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 +158 -22
  6. package/framework/agents/discover/brownfield-wu.md +26 -14
  7. package/framework/agents/discover/greenfield-wu.md +102 -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 +38 -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 +448 -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 +441 -0
  59. package/framework/orchestrator/chati-update.md +40 -40
  60. package/framework/orchestrator/chati.md +295 -94
  61. package/framework/rules/human-writing-style.md +47 -0
  62. package/framework/scaffold/motion-premium/README.md +99 -0
  63. package/framework/scaffold/motion-premium/app/globals.css.template +400 -0
  64. package/framework/scaffold/motion-premium/app/layout.tsx.template +110 -0
  65. package/framework/scaffold/motion-premium/components/animation/BackgroundCrossfadeProvider.tsx.template +170 -0
  66. package/framework/scaffold/motion-premium/components/animation/LenisProvider.tsx.template +49 -0
  67. package/framework/scaffold/motion-premium/components/animation/PageTransitionWrapper.tsx.template +83 -0
  68. package/framework/scaffold/motion-premium/components/animation/Preloader.tsx.template +171 -0
  69. package/framework/scaffold/motion-premium/components/ui/Container.tsx.template +69 -0
  70. package/framework/scaffold/motion-premium/components/ui/PageSection.tsx.template +74 -0
  71. package/framework/scaffold/motion-premium/lib/animations/gsap.ts.template +112 -0
  72. package/framework/scaffold/motion-premium/lib/animations/refreshCoordinator.ts.template +75 -0
  73. package/framework/scaffold/motion-premium/lib/animations/tokens.ts.template +119 -0
  74. package/framework/scaffold/motion-premium/lib/animations/useGsapContext.ts.template +92 -0
  75. package/framework/scaffold/motion-premium/lib/animations/useScrollSnapStepper.ts.template +265 -0
  76. package/framework/scaffold/motion-premium/lib/animations/useSmoothScroll.ts.template +67 -0
  77. package/framework/scaffold/motion-premium/lib/brand.ts.template +43 -0
  78. package/framework/scaffold/motion-premium/scaffold.yaml +178 -0
  79. package/framework/scaffold/motion-premium-3d/README.md +90 -0
  80. package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoCanvas.tsx.template +81 -0
  81. package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoClient.tsx.template +75 -0
  82. package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/page.tsx.template +26 -0
  83. package/framework/scaffold/motion-premium-3d/components/3d/CameraRig.tsx.template +100 -0
  84. package/framework/scaffold/motion-premium-3d/components/3d/CanvasProvider.tsx.template +85 -0
  85. package/framework/scaffold/motion-premium-3d/components/3d/InvalidateOnScroll.tsx.template +51 -0
  86. package/framework/scaffold/motion-premium-3d/components/3d/MeshCrossfade.tsx.template +79 -0
  87. package/framework/scaffold/motion-premium-3d/components/3d/ScrollCrossfade.tsx.template +88 -0
  88. package/framework/scaffold/motion-premium-3d/components/3d/ScrollScene.tsx.template +121 -0
  89. package/framework/scaffold/motion-premium-3d/components/webgl/SceneFallback.tsx.template +65 -0
  90. package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +68 -0
  91. package/framework/scaffold/motion-premium-3d/lib/webgl/detect.ts.template +69 -0
  92. package/framework/scaffold/motion-premium-3d/scaffold.yaml +136 -0
  93. package/framework/schemas/session.schema.json +109 -21
  94. package/framework/scripts/reference-capture.js +430 -0
  95. package/framework/scripts/visual-qa.js +686 -0
  96. package/framework/tasks/orchestrator-handoff.md +1 -1
  97. package/framework/tasks/orchestrator-resume.md +1 -1
  98. package/framework/tasks/orchestrator-route.md +1 -1
  99. package/framework/tasks/orchestrator-status.md +3 -3
  100. package/framework/tasks/qa-planning-gate-define.md +1 -1
  101. package/framework/templates/brandbook-html-tmpl.md +2 -2
  102. package/framework/templates/brandbook-tmpl.yaml +1 -1
  103. package/framework/templates/component-spec-tmpl.yaml +1 -1
  104. package/framework/templates/design-token-tmpl.yaml +1 -1
  105. package/framework/templates/icon-system-tmpl.yaml +1 -1
  106. package/framework/templates/team-planning-tasks.yaml +6 -5
  107. package/framework/workflows/brownfield-discovery.yaml +2 -2
  108. package/framework/workflows/brownfield-fullstack.yaml +15 -11
  109. package/framework/workflows/brownfield-service.yaml +14 -10
  110. package/framework/workflows/brownfield-ui.yaml +15 -11
  111. package/framework/workflows/greenfield-fullstack.yaml +16 -13
  112. package/framework/workflows/quick-flow.yaml +3 -3
  113. package/framework/workflows/standard-flow.yaml +12 -9
  114. package/package.json +12 -6
  115. package/src/autonomy/autonomous-gate.js +1 -0
  116. package/src/autonomy/build-state.js +1 -2
  117. package/src/autonomy/progress-reporter.js +1 -1
  118. package/src/config/agent-customizer.js +11 -3
  119. package/src/config/claude-settings-generator.js +27 -7
  120. package/src/config/context-file-generator.js +41 -21
  121. package/src/config/framework-adapter.js +1 -0
  122. package/src/config/gemini-hooks-generator.js +19 -7
  123. package/src/config/mcp-configs.js +1 -0
  124. package/src/context/layers/l1-global.js +2 -1
  125. package/src/dashboard/data-reader.js +4 -3
  126. package/src/dashboard/layout.js +2 -1
  127. package/src/decision/analyzer.js +6 -30
  128. package/src/decision/engine.js +4 -28
  129. package/src/decision/registry-healer.js +3 -2
  130. package/src/decision/registry-updater.js +23 -14
  131. package/src/extensions/loader.js +2 -8
  132. package/src/gates/g1-planning-complete.js +2 -1
  133. package/src/gates/g2-qa-planning.js +2 -1
  134. package/src/gates/g3-implementation.js +2 -1
  135. package/src/gates/g4-qa-implementation.js +3 -2
  136. package/src/gates/g5-deploy-ready.js +2 -1
  137. package/src/health/engine.js +4 -3
  138. package/src/installer/core.js +431 -81
  139. package/src/installer/preflight.js +131 -0
  140. package/src/installer/provider-overlay.js +3 -3
  141. package/src/installer/scaffold-applier.js +358 -0
  142. package/src/installer/templates.js +46 -29
  143. package/src/installer/validator.js +17 -12
  144. package/src/intelligence/registry-manager.js +22 -29
  145. package/src/intelligence/timeline.js +11 -6
  146. package/src/license/commands.js +1 -1
  147. package/src/license/wait.js +102 -0
  148. package/src/memory/agent-memory.js +81 -0
  149. package/src/memory/dream.js +32 -1
  150. package/src/merger/replace-merger.js +28 -15
  151. package/src/orchestrator/agent-selector.js +2 -1
  152. package/src/orchestrator/cli.js +1880 -71
  153. package/src/orchestrator/doctor.js +270 -0
  154. package/src/orchestrator/handoff-engine.js +4 -3
  155. package/src/orchestrator/index.js +2 -0
  156. package/src/orchestrator/pipeline-manager.js +306 -15
  157. package/src/orchestrator/session-manager.js +339 -6
  158. package/src/tasks/handoff.js +3 -2
  159. package/src/telemetry/config.js +4 -3
  160. package/src/telemetry/schema.js +1 -0
  161. package/src/terminal/collector.js +3 -2
  162. package/src/terminal/index.js +1 -2
  163. package/src/terminal/isolation.js +52 -18
  164. package/src/terminal/prompt-builder.js +42 -25
  165. package/src/terminal/run-parallel.js +1 -1
  166. package/src/terminal/run-team.js +3 -3
  167. package/src/terminal/team-task-list.js +43 -4
  168. package/src/upgrade/backup.js +3 -2
  169. package/src/upgrade/checker.js +3 -2
  170. package/src/upgrade/migrator.js +65 -7
  171. package/src/upgrade/tracked-files-detector.js +86 -0
  172. package/src/upgrade/user-messages.js +94 -0
  173. package/src/utils/config-parser.js +2 -1
  174. package/src/utils/feature-flags.js +2 -1
  175. package/src/utils/flatten-entities.js +69 -0
  176. package/src/utils/framework-dir.js +16 -0
  177. package/src/utils/model-id.js +85 -0
  178. package/src/utils/provider-limits.js +84 -23
  179. package/src/utils/schema-validator.js +1 -1
  180. package/src/wizard/i18n.js +5 -4
  181. package/src/wizard/index.js +14 -0
  182. package/assets/logo - c/303/263pia.png +0 -0
  183. package/assets/logo.svg +0 -42
  184. package/assets/logo2.png +0 -0
  185. package/assets/social-preview.png +0 -0
  186. package/scripts/bundle-framework.js +0 -69
  187. package/scripts/changelog-generator.js +0 -222
  188. package/scripts/codebase-mapper.js +0 -728
  189. package/scripts/commit-message-generator.js +0 -167
  190. package/scripts/coverage-analyzer.js +0 -260
  191. package/scripts/dependency-analyzer.js +0 -280
  192. package/scripts/doctor/checks/agents.js +0 -77
  193. package/scripts/doctor/checks/constitution.js +0 -41
  194. package/scripts/doctor/checks/domain-alignment.js +0 -58
  195. package/scripts/doctor/checks/prism-layers.js +0 -84
  196. package/scripts/doctor/checks/registry.js +0 -55
  197. package/scripts/doctor/checks/schemas.js +0 -61
  198. package/scripts/doctor/fixes/reference-fix.js +0 -100
  199. package/scripts/doctor/fixes/registry-fix.js +0 -56
  200. package/scripts/doctor/index.js +0 -212
  201. package/scripts/framework-analyzer.js +0 -308
  202. package/scripts/generate-constitution-domain.js +0 -253
  203. package/scripts/generate-signing-key.js +0 -33
  204. package/scripts/health-check.js +0 -481
  205. package/scripts/ide-sync.js +0 -326
  206. package/scripts/performance-analyzer.js +0 -325
  207. package/scripts/plan-tracker.js +0 -278
  208. package/scripts/populate-entity-registry.js +0 -481
  209. package/scripts/pr-review.js +0 -317
  210. package/scripts/rollback-manager.js +0 -310
  211. package/scripts/semantic-lint.js +0 -328
  212. package/scripts/sign-manifest.js +0 -53
  213. package/scripts/stuck-detector.js +0 -343
  214. package/scripts/test-quality-assessment.js +0 -257
  215. package/scripts/validate-agents.js +0 -368
  216. package/scripts/validate-package.js +0 -505
  217. package/scripts/validate-tasks.js +0 -465
  218. package/src/autonomy/worktree-manager.js +0 -250
  219. package/src/intelligence/decision-engine.js +0 -256
  220. package/src/intelligence/document-sharder.js +0 -221
  221. package/src/intelligence/elicitation.js +0 -265
@@ -1,326 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * IDE Sync — Synchronizes agent files to IDE-specific locations.
5
- *
6
- * Exports:
7
- * IDE_CONFIGS — Map of IDE names to their config.
8
- * syncToIDE(targetDir, frameworkDir, ideName) → { synced: number, files: [] }
9
- * syncAllIDEs(targetDir, frameworkDir, installedIDEs) → { results: { ide: syncResult } }
10
- * detectInstalledIDEs(targetDir) → string[]
11
- * buildIDEContent(agentContent, format, agentName) → transformed content
12
- */
13
-
14
- import { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync } from 'fs';
15
- import { join, basename, relative } from 'path';
16
-
17
- /**
18
- * IDE configuration definitions.
19
- */
20
- export const IDE_CONFIGS = {
21
- 'claude-code': {
22
- commandDir: '.claude/commands/',
23
- extension: '.md',
24
- format: 'markdown',
25
- description: 'Claude Code (Anthropic)',
26
- },
27
- cursor: {
28
- rulesDir: '.cursor/rules/',
29
- extension: '.mdc',
30
- format: 'cursor-rules',
31
- description: 'Cursor',
32
- },
33
- windsurf: {
34
- rulesDir: '.windsurf/rules/',
35
- extension: '.md',
36
- format: 'markdown',
37
- description: 'Windsurf',
38
- },
39
- vscode: {
40
- configDir: '.vscode/',
41
- extension: '.md',
42
- format: 'markdown',
43
- description: 'Visual Studio Code',
44
- },
45
- antigravity: {
46
- agentsDir: '.antigravity/agents/',
47
- extension: '.md',
48
- format: 'markdown',
49
- description: 'AntiGravity',
50
- },
51
- 'gemini-cli': {
52
- commandDir: '.gemini/commands/',
53
- extension: '.toml',
54
- format: 'toml',
55
- description: 'Gemini CLI',
56
- },
57
- };
58
-
59
- // ---------------------------------------------------------------------------
60
- // Internal Helpers
61
- // ---------------------------------------------------------------------------
62
-
63
- /**
64
- * Collect all agent .md files from the framework directory.
65
- * @param {string} frameworkDir - Path to the framework directory.
66
- * @returns {object[]} Array of { name, path, content }.
67
- */
68
- function collectAgentFiles(frameworkDir) {
69
- const agents = [];
70
-
71
- // Collect agents from subdirectories
72
- const agentsDir = join(frameworkDir, 'agents');
73
- if (existsSync(agentsDir)) {
74
- const categories = readdirSync(agentsDir, { withFileTypes: true })
75
- .filter(e => e.isDirectory())
76
- .map(e => e.name);
77
-
78
- for (const category of categories) {
79
- const catDir = join(agentsDir, category);
80
- try {
81
- const files = readdirSync(catDir).filter(f => f.endsWith('.md'));
82
- for (const file of files) {
83
- const fullPath = join(catDir, file);
84
- agents.push({
85
- name: basename(file, '.md'),
86
- path: fullPath,
87
- content: readFileSync(fullPath, 'utf8'),
88
- category,
89
- });
90
- }
91
- } catch {
92
- // Skip unreadable directories
93
- }
94
- }
95
- }
96
-
97
- // Collect orchestrator
98
- const orchPath = join(frameworkDir, 'orchestrator', 'chati.md');
99
- if (existsSync(orchPath)) {
100
- agents.push({
101
- name: 'chati',
102
- path: orchPath,
103
- content: readFileSync(orchPath, 'utf8'),
104
- category: 'orchestrator',
105
- });
106
- }
107
-
108
- return agents;
109
- }
110
-
111
- /**
112
- * Get the target directory path for a specific IDE.
113
- * @param {string} targetDir - Project root directory.
114
- * @param {string} ideName - IDE identifier.
115
- * @returns {string} Target directory for sync.
116
- */
117
- function getIDETargetDir(targetDir, ideName) {
118
- const config = IDE_CONFIGS[ideName];
119
- if (!config) return null;
120
-
121
- // Pick the first defined directory key
122
- const dirKey = config.commandDir || config.rulesDir || config.configDir
123
- || config.agentsDir || config.instructionsDir;
124
-
125
- return join(targetDir, dirKey);
126
- }
127
-
128
- /**
129
- * Transform agent markdown content for a specific IDE format.
130
- * @param {string} agentContent - Raw agent markdown content.
131
- * @param {string} format - Target format ('markdown' | 'cursor-rules').
132
- * @param {string} agentName - Agent name for metadata.
133
- * @returns {string} Transformed content.
134
- */
135
- export function buildIDEContent(agentContent, format, agentName = '') {
136
- switch (format) {
137
- case 'cursor-rules': {
138
- // Cursor uses .mdc format with YAML-like frontmatter
139
- const lines = [
140
- '---',
141
- `description: chati.dev agent — ${agentName}`,
142
- 'globs:',
143
- 'alwaysApply: false',
144
- '---',
145
- '',
146
- agentContent,
147
- ];
148
- return lines.join('\n');
149
- }
150
-
151
- case 'toml': {
152
- // Gemini CLI uses TOML format for commands
153
- return `description = "chati.dev agent — ${agentName}"\n\nprompt = """\n${agentContent}\n"""\n`;
154
- }
155
-
156
- case 'markdown':
157
- default:
158
- return agentContent;
159
- }
160
- }
161
-
162
- // ---------------------------------------------------------------------------
163
- // Public API
164
- // ---------------------------------------------------------------------------
165
-
166
- /**
167
- * Detect which IDEs have existing config directories in the project.
168
- * @param {string} targetDir - Project root directory.
169
- * @returns {string[]} Array of detected IDE names.
170
- */
171
- export function detectInstalledIDEs(targetDir) {
172
- const detected = [];
173
-
174
- for (const [ideName, config] of Object.entries(IDE_CONFIGS)) {
175
- const dirKey = config.commandDir || config.rulesDir || config.configDir
176
- || config.agentsDir || config.instructionsDir;
177
- const checkDir = dirKey.split('/')[0]; // Check first directory component
178
-
179
- if (existsSync(join(targetDir, checkDir))) {
180
- detected.push(ideName);
181
- }
182
- }
183
-
184
- return detected;
185
- }
186
-
187
- /**
188
- * Sync agent files to a specific IDE's location.
189
- * @param {string} targetDir - Project root directory.
190
- * @param {string} frameworkDir - Path to the framework directory.
191
- * @param {string} ideName - IDE identifier.
192
- * @returns {{ synced: number, files: string[], errors: string[] }}
193
- */
194
- export function syncToIDE(targetDir, frameworkDir, ideName) {
195
- const config = IDE_CONFIGS[ideName];
196
- if (!config) {
197
- return { synced: 0, files: [], errors: [`Unknown IDE: ${ideName}`] };
198
- }
199
-
200
- const result = { synced: 0, files: [], errors: [] };
201
-
202
- const ideTargetDir = getIDETargetDir(targetDir, ideName);
203
- if (!ideTargetDir) {
204
- result.errors.push(`Cannot determine target directory for ${ideName}`);
205
- return result;
206
- }
207
-
208
- // Collect agent files
209
- const agents = collectAgentFiles(frameworkDir);
210
- if (agents.length === 0) {
211
- result.errors.push('No agent files found in framework directory');
212
- return result;
213
- }
214
-
215
- // Create target directory
216
- mkdirSync(ideTargetDir, { recursive: true });
217
-
218
- // Sync each agent
219
- for (const agent of agents) {
220
- const targetFileName = `${agent.name}${config.extension}`;
221
- const targetPath = join(ideTargetDir, targetFileName);
222
-
223
- try {
224
- const content = buildIDEContent(agent.content, config.format, agent.name);
225
- writeFileSync(targetPath, content, 'utf8');
226
- result.synced++;
227
- result.files.push(relative(targetDir, targetPath));
228
- } catch (err) {
229
- result.errors.push(`Failed to write ${targetFileName}: ${err.message}`);
230
- }
231
- }
232
-
233
- return result;
234
- }
235
-
236
- /**
237
- * Sync agent files to all specified IDEs.
238
- * @param {string} targetDir - Project root directory.
239
- * @param {string} frameworkDir - Path to the framework directory.
240
- * @param {string[]} installedIDEs - List of IDE names to sync to.
241
- * @returns {{ results: object, totalSynced: number, totalErrors: number }}
242
- */
243
- export function syncAllIDEs(targetDir, frameworkDir, installedIDEs) {
244
- const results = {};
245
- let totalSynced = 0;
246
- let totalErrors = 0;
247
-
248
- for (const ide of installedIDEs) {
249
- const result = syncToIDE(targetDir, frameworkDir, ide);
250
- results[ide] = result;
251
- totalSynced += result.synced;
252
- totalErrors += result.errors.length;
253
- }
254
-
255
- return { results, totalSynced, totalErrors };
256
- }
257
-
258
- /**
259
- * Format sync results as a human-readable string.
260
- * @param {object} syncResults - Results from syncAllIDEs.
261
- * @returns {string}
262
- */
263
- export function formatSyncReport(syncResults) {
264
- const lines = [
265
- '=== IDE Sync Report ===',
266
- `Total synced: ${syncResults.totalSynced} files`,
267
- `Total errors: ${syncResults.totalErrors}`,
268
- '',
269
- ];
270
-
271
- for (const [ide, result] of Object.entries(syncResults.results)) {
272
- const config = IDE_CONFIGS[ide];
273
- const desc = config?.description || ide;
274
- const symbol = result.errors.length === 0 ? '[OK]' : '[WARN]';
275
-
276
- lines.push(` ${symbol} ${desc}: ${result.synced} files synced`);
277
- for (const file of result.files) {
278
- lines.push(` ${file}`);
279
- }
280
- for (const err of result.errors) {
281
- lines.push(` ERROR: ${err}`);
282
- }
283
- }
284
-
285
- lines.push('');
286
- lines.push('=== End Report ===');
287
- return lines.join('\n');
288
- }
289
-
290
- // ---------------------------------------------------------------------------
291
- // CLI entrypoint
292
- // ---------------------------------------------------------------------------
293
-
294
- const isMainModule = process.argv[1] && (
295
- process.argv[1].endsWith('ide-sync.js') ||
296
- process.argv[1].endsWith('ide-sync')
297
- );
298
-
299
- if (isMainModule) {
300
- const targetDir = process.argv[2] || process.cwd();
301
- const frameworkDir = process.argv[3] || join(targetDir, 'chati.dev');
302
- const specificIDE = process.argv[4];
303
-
304
- if (specificIDE) {
305
- console.log(`Syncing to ${specificIDE}...`);
306
- const result = syncToIDE(targetDir, frameworkDir, specificIDE);
307
- console.log(`Synced: ${result.synced} files`);
308
- for (const file of result.files) console.log(` ${file}`);
309
- if (result.errors.length > 0) {
310
- for (const err of result.errors) console.log(` ERROR: ${err}`);
311
- }
312
- } else {
313
- console.log('Detecting installed IDEs...');
314
- const detected = detectInstalledIDEs(targetDir);
315
-
316
- if (detected.length === 0) {
317
- console.log('No IDE configurations detected. Specify IDE: node scripts/ide-sync.js <targetDir> <frameworkDir> <ideName>');
318
- console.log(`Available: ${Object.keys(IDE_CONFIGS).join(', ')}`);
319
- process.exit(0);
320
- }
321
-
322
- console.log(`Detected: ${detected.join(', ')}`);
323
- const results = syncAllIDEs(targetDir, frameworkDir, detected);
324
- console.log(formatSyncReport(results));
325
- }
326
- }
@@ -1,325 +0,0 @@
1
- /**
2
- * Performance Analyzer — Static analysis of code patterns that affect performance.
3
- *
4
- * Scans source files for large files, deep nesting, long functions,
5
- * excessive imports, and synchronous filesystem operations.
6
- *
7
- * @module scripts/performance-analyzer
8
- */
9
-
10
- import { readFileSync, readdirSync, statSync } from 'node:fs';
11
- import { join, extname } from 'node:path';
12
-
13
- /**
14
- * @typedef {Object} ComplexityResult
15
- * @property {number} cyclomaticComplexity
16
- * @property {number} nestingDepth
17
- * @property {Array<{ name: string, lines: number }>} functionLengths
18
- */
19
-
20
- /**
21
- * @typedef {Object} FilePerformanceReport
22
- * @property {string} filePath
23
- * @property {number} lineCount
24
- * @property {number} importCount
25
- * @property {ComplexityResult} complexity
26
- * @property {boolean} hasSyncFsOps
27
- * @property {string[]} warnings
28
- * @property {string[]} errors
29
- */
30
-
31
- /**
32
- * @typedef {Object} PerformanceReport
33
- * @property {FilePerformanceReport[]} files
34
- * @property {{ totalFiles: number, totalWarnings: number, totalErrors: number }} summary
35
- */
36
-
37
- // Thresholds
38
- const THRESHOLDS = {
39
- fileSizeWarning: 500,
40
- fileSizeError: 1000,
41
- nestingDepth: 4,
42
- functionLength: 50,
43
- importCount: 15,
44
- cyclomaticComplexityWarning: 10,
45
- cyclomaticComplexityError: 20,
46
- };
47
-
48
- // Sync fs methods that should be avoided in non-script files
49
- const SYNC_FS_PATTERN = /\b(?:readFileSync|writeFileSync|appendFileSync|mkdirSync|rmdirSync|unlinkSync|renameSync|copyFileSync|readdirSync|statSync|lstatSync|existsSync|accessSync)\b/g;
50
-
51
- /**
52
- * Collects JS/TS source files recursively (excludes tests, node_modules, .git).
53
- * @param {string} dir
54
- * @returns {string[]}
55
- */
56
- function collectSourceFiles(dir) {
57
- const results = [];
58
- const sourceExtensions = new Set(['.js', '.ts', '.mjs', '.mts']);
59
-
60
- function walk(currentDir) {
61
- let entries;
62
- try {
63
- entries = readdirSync(currentDir);
64
- } catch {
65
- return;
66
- }
67
- for (const entry of entries) {
68
- if (entry === 'node_modules' || entry === '.git' || entry === 'dist' || entry === 'build') continue;
69
- const fullPath = join(currentDir, entry);
70
- let stat;
71
- try {
72
- stat = statSync(fullPath);
73
- } catch {
74
- continue;
75
- }
76
- if (stat.isDirectory()) {
77
- walk(fullPath);
78
- } else if (stat.isFile() && sourceExtensions.has(extname(entry))) {
79
- // Skip test files
80
- if (entry.endsWith('.test.js') || entry.endsWith('.spec.js') ||
81
- entry.endsWith('.test.ts') || entry.endsWith('.spec.ts')) {
82
- continue;
83
- }
84
- results.push(fullPath);
85
- }
86
- }
87
- }
88
-
89
- walk(dir);
90
- return results.sort();
91
- }
92
-
93
- /**
94
- * Calculates code complexity metrics for a given source string.
95
- *
96
- * @param {string} code
97
- * @returns {ComplexityResult}
98
- */
99
- export function calculateComplexity(code) {
100
- const lines = code.split('\n');
101
-
102
- // Cyclomatic complexity: count decision points
103
- const decisionPatterns = [
104
- /\bif\s*\(/g,
105
- /\belse\s+if\s*\(/g,
106
- /\bfor\s*\(/g,
107
- /\bwhile\s*\(/g,
108
- /\bswitch\s*\(/g,
109
- /\bcase\s+/g,
110
- /\bcatch\s*\(/g,
111
- /\?\s*[^:]/g, // ternary
112
- /&&/g,
113
- /\|\|/g,
114
- ];
115
-
116
- let cyclomaticComplexity = 1; // base complexity
117
- for (const pattern of decisionPatterns) {
118
- const matches = code.match(pattern);
119
- if (matches) cyclomaticComplexity += matches.length;
120
- pattern.lastIndex = 0;
121
- }
122
-
123
- // Max nesting depth
124
- let maxNesting = 0;
125
- let currentNesting = 0;
126
- for (const line of lines) {
127
- const trimmed = line.trim();
128
- // Skip comments and strings (simple heuristic)
129
- if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*')) continue;
130
-
131
- const opens = (trimmed.match(/\{/g) || []).length;
132
- const closes = (trimmed.match(/\}/g) || []).length;
133
- currentNesting += opens - closes;
134
- if (currentNesting > maxNesting) maxNesting = currentNesting;
135
- if (currentNesting < 0) currentNesting = 0;
136
- }
137
-
138
- // Function lengths
139
- const functionLengths = [];
140
- const funcStartRegex = /(?:(?:export\s+)?(?:async\s+)?function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|[^=])\s*=>|(\w+)\s*\([^)]*\)\s*\{)/;
141
-
142
- let funcName = null;
143
- let funcStartLine = 0;
144
- let braceDepth = 0;
145
- let inFunction = false;
146
-
147
- for (let i = 0; i < lines.length; i++) {
148
- const line = lines[i];
149
- const trimmed = line.trim();
150
-
151
- if (!inFunction) {
152
- const match = trimmed.match(funcStartRegex);
153
- if (match) {
154
- funcName = match[1] || match[2] || match[3] || 'anonymous';
155
- funcStartLine = i;
156
- inFunction = true;
157
- braceDepth = 0;
158
- }
159
- }
160
-
161
- if (inFunction) {
162
- const opens = (trimmed.match(/\{/g) || []).length;
163
- const closes = (trimmed.match(/\}/g) || []).length;
164
- braceDepth += opens - closes;
165
-
166
- if (braceDepth <= 0 && i > funcStartLine) {
167
- const length = i - funcStartLine + 1;
168
- functionLengths.push({ name: funcName, lines: length });
169
- inFunction = false;
170
- funcName = null;
171
- }
172
- }
173
- }
174
-
175
- return {
176
- cyclomaticComplexity,
177
- nestingDepth: maxNesting,
178
- functionLengths,
179
- };
180
- }
181
-
182
- /**
183
- * Analyzes a single file for performance-related patterns.
184
- *
185
- * @param {string} filePath
186
- * @returns {FilePerformanceReport}
187
- */
188
- export function analyzeFile(filePath) {
189
- let content;
190
- try {
191
- content = readFileSync(filePath, 'utf-8');
192
- } catch (err) {
193
- return {
194
- filePath,
195
- lineCount: 0,
196
- importCount: 0,
197
- complexity: { cyclomaticComplexity: 0, nestingDepth: 0, functionLengths: [] },
198
- hasSyncFsOps: false,
199
- warnings: [`Cannot read file: ${err.message}`],
200
- errors: [],
201
- };
202
- }
203
-
204
- const lines = content.split('\n');
205
- const lineCount = lines.length;
206
- const warnings = [];
207
- const errors = [];
208
-
209
- // Count imports
210
- const importMatches = content.match(/\b(?:import\s+|require\s*\()/g) || [];
211
- const importCount = importMatches.length;
212
-
213
- // Check sync fs operations (only flag in non-script files)
214
- const isScript = filePath.includes('/scripts/') || filePath.includes('/bin/');
215
- const syncMatches = content.match(SYNC_FS_PATTERN) || [];
216
- const hasSyncFsOps = syncMatches.length > 0;
217
-
218
- // Calculate complexity
219
- const complexity = calculateComplexity(content);
220
-
221
- // Generate warnings and errors
222
- if (lineCount > THRESHOLDS.fileSizeError) {
223
- errors.push(`File has ${lineCount} lines (threshold: ${THRESHOLDS.fileSizeError})`);
224
- } else if (lineCount > THRESHOLDS.fileSizeWarning) {
225
- warnings.push(`File has ${lineCount} lines (threshold: ${THRESHOLDS.fileSizeWarning})`);
226
- }
227
-
228
- if (complexity.nestingDepth > THRESHOLDS.nestingDepth) {
229
- warnings.push(`Max nesting depth: ${complexity.nestingDepth} (threshold: ${THRESHOLDS.nestingDepth})`);
230
- }
231
-
232
- if (importCount > THRESHOLDS.importCount) {
233
- warnings.push(`${importCount} imports (threshold: ${THRESHOLDS.importCount})`);
234
- }
235
-
236
- if (hasSyncFsOps && !isScript) {
237
- warnings.push(`${syncMatches.length} synchronous filesystem operation(s) in non-script file`);
238
- }
239
-
240
- for (const func of complexity.functionLengths) {
241
- if (func.lines > THRESHOLDS.functionLength) {
242
- warnings.push(`Function "${func.name}" is ${func.lines} lines (threshold: ${THRESHOLDS.functionLength})`);
243
- }
244
- }
245
-
246
- if (complexity.cyclomaticComplexity > THRESHOLDS.cyclomaticComplexityError) {
247
- errors.push(`Cyclomatic complexity: ${complexity.cyclomaticComplexity} (threshold: ${THRESHOLDS.cyclomaticComplexityError})`);
248
- } else if (complexity.cyclomaticComplexity > THRESHOLDS.cyclomaticComplexityWarning) {
249
- warnings.push(`Cyclomatic complexity: ${complexity.cyclomaticComplexity} (threshold: ${THRESHOLDS.cyclomaticComplexityWarning})`);
250
- }
251
-
252
- return {
253
- filePath,
254
- lineCount,
255
- importCount,
256
- complexity,
257
- hasSyncFsOps,
258
- warnings,
259
- errors,
260
- };
261
- }
262
-
263
- /**
264
- * Analyzes all source files in a directory.
265
- *
266
- * @param {string} srcDir
267
- * @returns {PerformanceReport}
268
- */
269
- export function analyzePerformance(srcDir) {
270
- const sourceFiles = collectSourceFiles(srcDir);
271
- const files = sourceFiles.map((f) => analyzeFile(f));
272
-
273
- const totalWarnings = files.reduce((s, f) => s + f.warnings.length, 0);
274
- const totalErrors = files.reduce((s, f) => s + f.errors.length, 0);
275
-
276
- return {
277
- files,
278
- summary: {
279
- totalFiles: files.length,
280
- totalWarnings,
281
- totalErrors,
282
- },
283
- };
284
- }
285
-
286
- /**
287
- * Formats the performance report as a human-readable string.
288
- *
289
- * @param {PerformanceReport} report
290
- * @returns {string}
291
- */
292
- export function formatPerformanceReport(report) {
293
- const lines = [];
294
-
295
- lines.push('=== Performance Analysis Report ===');
296
- lines.push('');
297
- lines.push(`Files analyzed : ${report.summary.totalFiles}`);
298
- lines.push(`Total warnings : ${report.summary.totalWarnings}`);
299
- lines.push(`Total errors : ${report.summary.totalErrors}`);
300
- lines.push('');
301
-
302
- const filesWithIssues = report.files.filter(
303
- (f) => f.warnings.length > 0 || f.errors.length > 0
304
- );
305
-
306
- if (filesWithIssues.length === 0) {
307
- lines.push('No performance issues detected.');
308
- return lines.join('\n');
309
- }
310
-
311
- for (const file of filesWithIssues) {
312
- lines.push(`--- ${file.filePath} ---`);
313
- lines.push(` Lines: ${file.lineCount} | Imports: ${file.importCount} | Complexity: ${file.complexity.cyclomaticComplexity} | Nesting: ${file.complexity.nestingDepth}`);
314
-
315
- for (const err of file.errors) {
316
- lines.push(` [ERR] ${err}`);
317
- }
318
- for (const warn of file.warnings) {
319
- lines.push(` [WRN] ${warn}`);
320
- }
321
- lines.push('');
322
- }
323
-
324
- return lines.join('\n');
325
- }