chati-dev 4.2.1 → 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 (222) 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 +8 -7
  23. package/framework/constitution.md +127 -43
  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 +91 -36
  35. package/framework/hooks/license-guard.js +129 -190
  36. package/framework/hooks/mode-governance.js +68 -16
  37. package/framework/hooks/model-governance.js +19 -8
  38. package/framework/hooks/package.json +3 -0
  39. package/framework/hooks/post-dev.js +207 -0
  40. package/framework/hooks/prism-engine.js +288 -105
  41. package/framework/hooks/read-protection.js +37 -9
  42. package/framework/hooks/reasoning-escalator.js +371 -0
  43. package/framework/hooks/reference-trigger.js +117 -0
  44. package/framework/hooks/session-digest.js +94 -20
  45. package/framework/hooks/settings.json +32 -1
  46. package/framework/hooks/style-guard.js +52 -13
  47. package/framework/hooks/team-quality-gate.js +58 -25
  48. package/framework/hooks/undercover-guard.js +34 -13
  49. package/framework/i18n/en.yaml +3 -3
  50. package/framework/i18n/es.yaml +3 -3
  51. package/framework/i18n/fr.yaml +3 -3
  52. package/framework/i18n/pt.yaml +3 -3
  53. package/framework/intelligence/context-engine.md +4 -5
  54. package/framework/intelligence/decision-engine.md +1 -1
  55. package/framework/intelligence/hooks-performance.md +3 -3
  56. package/framework/migrations/v1.0-to-v1.1.yaml +1 -1
  57. package/framework/migrations/v1.4-to-v2.0.yaml +11 -11
  58. package/framework/migrations/v4.0-to-v4.1.yaml +2 -2
  59. package/framework/migrations/v4.2-to-v4.3.yaml +29 -0
  60. package/framework/orchestrator/chati-router.js +387 -0
  61. package/framework/orchestrator/chati-update.md +40 -40
  62. package/framework/orchestrator/chati.md +318 -115
  63. package/framework/scaffold/motion-premium/README.md +89 -0
  64. package/framework/scaffold/motion-premium/app/globals.css.template +400 -0
  65. package/framework/scaffold/motion-premium/app/layout.tsx.template +110 -0
  66. package/framework/scaffold/motion-premium/components/animation/BackgroundCrossfadeProvider.tsx.template +170 -0
  67. package/framework/scaffold/motion-premium/components/animation/LenisProvider.tsx.template +49 -0
  68. package/framework/scaffold/motion-premium/components/animation/PageTransitionWrapper.tsx.template +83 -0
  69. package/framework/scaffold/motion-premium/components/animation/Preloader.tsx.template +171 -0
  70. package/framework/scaffold/motion-premium/components/ui/Container.tsx.template +69 -0
  71. package/framework/scaffold/motion-premium/components/ui/PageSection.tsx.template +74 -0
  72. package/framework/scaffold/motion-premium/lib/animations/gsap.ts.template +112 -0
  73. package/framework/scaffold/motion-premium/lib/animations/refreshCoordinator.ts.template +75 -0
  74. package/framework/scaffold/motion-premium/lib/animations/tokens.ts.template +119 -0
  75. package/framework/scaffold/motion-premium/lib/animations/useGsapContext.ts.template +92 -0
  76. package/framework/scaffold/motion-premium/lib/animations/useScrollSnapStepper.ts.template +265 -0
  77. package/framework/scaffold/motion-premium/lib/animations/useSmoothScroll.ts.template +67 -0
  78. package/framework/scaffold/motion-premium/lib/brand.ts.template +43 -0
  79. package/framework/scaffold/motion-premium/scaffold.yaml +174 -0
  80. package/framework/scaffold/motion-premium-3d/README.md +80 -0
  81. package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoCanvas.tsx.template +81 -0
  82. package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoClient.tsx.template +75 -0
  83. package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/page.tsx.template +26 -0
  84. package/framework/scaffold/motion-premium-3d/components/3d/CameraRig.tsx.template +100 -0
  85. package/framework/scaffold/motion-premium-3d/components/3d/CanvasProvider.tsx.template +85 -0
  86. package/framework/scaffold/motion-premium-3d/components/3d/InvalidateOnScroll.tsx.template +51 -0
  87. package/framework/scaffold/motion-premium-3d/components/3d/MeshCrossfade.tsx.template +79 -0
  88. package/framework/scaffold/motion-premium-3d/components/3d/ScrollCrossfade.tsx.template +88 -0
  89. package/framework/scaffold/motion-premium-3d/components/3d/ScrollScene.tsx.template +121 -0
  90. package/framework/scaffold/motion-premium-3d/components/webgl/SceneFallback.tsx.template +65 -0
  91. package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +68 -0
  92. package/framework/scaffold/motion-premium-3d/lib/webgl/detect.ts.template +69 -0
  93. package/framework/scaffold/motion-premium-3d/scaffold.yaml +133 -0
  94. package/framework/schemas/session.schema.json +109 -21
  95. package/framework/scripts/reference-capture.js +430 -0
  96. package/framework/scripts/visual-qa.js +674 -0
  97. package/framework/tasks/orchestrator-handoff.md +1 -1
  98. package/framework/tasks/orchestrator-resume.md +1 -1
  99. package/framework/tasks/orchestrator-route.md +1 -1
  100. package/framework/tasks/orchestrator-status.md +3 -3
  101. package/framework/tasks/qa-planning-gate-define.md +1 -1
  102. package/framework/templates/brandbook-html-tmpl.md +1 -1
  103. package/framework/templates/brandbook-tmpl.yaml +1 -1
  104. package/framework/templates/component-spec-tmpl.yaml +1 -1
  105. package/framework/templates/design-token-tmpl.yaml +1 -1
  106. package/framework/templates/icon-system-tmpl.yaml +1 -1
  107. package/framework/templates/team-planning-tasks.yaml +6 -5
  108. package/framework/workflows/brownfield-discovery.yaml +2 -2
  109. package/framework/workflows/brownfield-fullstack.yaml +15 -11
  110. package/framework/workflows/brownfield-service.yaml +14 -10
  111. package/framework/workflows/brownfield-ui.yaml +15 -11
  112. package/framework/workflows/greenfield-fullstack.yaml +16 -13
  113. package/framework/workflows/quick-flow.yaml +3 -3
  114. package/framework/workflows/standard-flow.yaml +12 -9
  115. package/package.json +10 -5
  116. package/src/autonomy/autonomous-gate.js +1 -0
  117. package/src/autonomy/build-state.js +1 -2
  118. package/src/autonomy/progress-reporter.js +1 -1
  119. package/src/config/agent-customizer.js +11 -3
  120. package/src/config/claude-settings-generator.js +226 -0
  121. package/src/config/context-file-generator.js +41 -21
  122. package/src/config/framework-adapter.js +1 -0
  123. package/src/config/gemini-hooks-generator.js +76 -6
  124. package/src/config/mcp-configs.js +1 -0
  125. package/src/context/layers/l1-global.js +2 -1
  126. package/src/dashboard/data-reader.js +4 -3
  127. package/src/dashboard/layout.js +2 -1
  128. package/src/decision/analyzer.js +6 -30
  129. package/src/decision/engine.js +4 -28
  130. package/src/decision/registry-healer.js +3 -2
  131. package/src/decision/registry-updater.js +23 -14
  132. package/src/extensions/loader.js +2 -8
  133. package/src/gates/g1-planning-complete.js +2 -1
  134. package/src/gates/g2-qa-planning.js +2 -1
  135. package/src/gates/g3-implementation.js +2 -1
  136. package/src/gates/g4-qa-implementation.js +3 -2
  137. package/src/gates/g5-deploy-ready.js +2 -1
  138. package/src/health/engine.js +4 -3
  139. package/src/installer/core.js +557 -81
  140. package/src/installer/preflight.js +131 -0
  141. package/src/installer/provider-overlay.js +3 -3
  142. package/src/installer/scaffold-applier.js +358 -0
  143. package/src/installer/templates.js +52 -31
  144. package/src/installer/validator.js +17 -12
  145. package/src/intelligence/registry-manager.js +22 -29
  146. package/src/intelligence/timeline.js +11 -6
  147. package/src/license/commands.js +1 -1
  148. package/src/license/wait.js +102 -0
  149. package/src/memory/agent-memory.js +81 -0
  150. package/src/memory/dream.js +32 -1
  151. package/src/merger/replace-merger.js +28 -15
  152. package/src/orchestrator/agent-selector.js +2 -1
  153. package/src/orchestrator/cli.js +1908 -80
  154. package/src/orchestrator/doctor.js +270 -0
  155. package/src/orchestrator/handoff-engine.js +4 -3
  156. package/src/orchestrator/index.js +2 -0
  157. package/src/orchestrator/pipeline-manager.js +306 -15
  158. package/src/orchestrator/session-manager.js +331 -6
  159. package/src/tasks/handoff.js +3 -2
  160. package/src/telemetry/config.js +4 -3
  161. package/src/telemetry/schema.js +1 -0
  162. package/src/terminal/collector.js +3 -2
  163. package/src/terminal/index.js +1 -2
  164. package/src/terminal/isolation.js +52 -18
  165. package/src/terminal/prompt-builder.js +42 -25
  166. package/src/terminal/run-parallel.js +1 -1
  167. package/src/terminal/run-team.js +3 -3
  168. package/src/terminal/team-task-list.js +43 -4
  169. package/src/upgrade/backup.js +3 -2
  170. package/src/upgrade/checker.js +3 -2
  171. package/src/upgrade/migrator.js +65 -7
  172. package/src/upgrade/tracked-files-detector.js +86 -0
  173. package/src/upgrade/user-messages.js +94 -0
  174. package/src/utils/config-parser.js +2 -1
  175. package/src/utils/feature-flags.js +2 -1
  176. package/src/utils/flatten-entities.js +69 -0
  177. package/src/utils/framework-dir.js +16 -0
  178. package/src/utils/model-id.js +85 -0
  179. package/src/utils/provider-limits.js +84 -23
  180. package/src/utils/schema-validator.js +1 -1
  181. package/src/wizard/i18n.js +5 -4
  182. package/src/wizard/index.js +14 -0
  183. package/assets/logo - c/303/263pia.png +0 -0
  184. package/assets/logo.svg +0 -42
  185. package/assets/logo2.png +0 -0
  186. package/assets/social-preview.png +0 -0
  187. package/scripts/bundle-framework.js +0 -69
  188. package/scripts/changelog-generator.js +0 -222
  189. package/scripts/codebase-mapper.js +0 -728
  190. package/scripts/commit-message-generator.js +0 -167
  191. package/scripts/coverage-analyzer.js +0 -260
  192. package/scripts/dependency-analyzer.js +0 -280
  193. package/scripts/doctor/checks/agents.js +0 -77
  194. package/scripts/doctor/checks/constitution.js +0 -41
  195. package/scripts/doctor/checks/domain-alignment.js +0 -58
  196. package/scripts/doctor/checks/prism-layers.js +0 -84
  197. package/scripts/doctor/checks/registry.js +0 -55
  198. package/scripts/doctor/checks/schemas.js +0 -61
  199. package/scripts/doctor/fixes/reference-fix.js +0 -100
  200. package/scripts/doctor/fixes/registry-fix.js +0 -56
  201. package/scripts/doctor/index.js +0 -212
  202. package/scripts/framework-analyzer.js +0 -308
  203. package/scripts/generate-constitution-domain.js +0 -253
  204. package/scripts/generate-signing-key.js +0 -33
  205. package/scripts/health-check.js +0 -481
  206. package/scripts/ide-sync.js +0 -326
  207. package/scripts/performance-analyzer.js +0 -325
  208. package/scripts/plan-tracker.js +0 -278
  209. package/scripts/populate-entity-registry.js +0 -481
  210. package/scripts/pr-review.js +0 -317
  211. package/scripts/rollback-manager.js +0 -310
  212. package/scripts/semantic-lint.js +0 -328
  213. package/scripts/sign-manifest.js +0 -53
  214. package/scripts/stuck-detector.js +0 -343
  215. package/scripts/test-quality-assessment.js +0 -257
  216. package/scripts/validate-agents.js +0 -368
  217. package/scripts/validate-package.js +0 -367
  218. package/scripts/validate-tasks.js +0 -465
  219. package/src/autonomy/worktree-manager.js +0 -250
  220. package/src/intelligence/decision-engine.js +0 -256
  221. package/src/intelligence/document-sharder.js +0 -221
  222. package/src/intelligence/elicitation.js +0 -265
@@ -1,367 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Package Completeness Validator
5
- *
6
- * Validates that the npm package has all required files before publishing.
7
- * Run as part of prepublishOnly (after bundle, before sign-manifest).
8
- *
9
- * Exports:
10
- * validatePackage(packageRoot) → { errors, warnings, checks, passed }
11
- */
12
-
13
- import { existsSync, readFileSync, readdirSync } from 'fs';
14
- import { join, dirname } from 'path';
15
- import { fileURLToPath } from 'url';
16
-
17
- const __dirname = dirname(fileURLToPath(import.meta.url));
18
-
19
- /**
20
- * Expected directories in framework/ (must match bundle-framework.js)
21
- */
22
- const EXPECTED_BUNDLE_DIRS = [
23
- 'orchestrator',
24
- 'agents/discover', 'agents/plan', 'agents/quality', 'agents/build', 'agents/deploy',
25
- 'templates', 'workflows', 'quality-gates',
26
- 'schemas', 'frameworks', 'intelligence', 'patterns',
27
- 'hooks', 'domains',
28
- 'i18n', 'migrations', 'data',
29
- 'tasks', 'context',
30
- ];
31
-
32
- const EXPECTED_ROOT_FILES = ['constitution.md', 'config.yaml'];
33
-
34
- const SENSITIVE_FILES = ['.signing-key.pem', '.env', '.env.local', '.env.production'];
35
-
36
- /**
37
- * Validate that framework/ directory exists.
38
- */
39
- function checkFrameworkExists(packageRoot, results) {
40
- results.checks++;
41
- const frameworkDir = join(packageRoot, 'framework');
42
- if (existsSync(frameworkDir)) {
43
- results.passed++;
44
- } else {
45
- results.errors.push('framework/ directory not found. Run `npm run bundle` first.');
46
- }
47
- }
48
-
49
- /**
50
- * Validate all expected bundle directories exist.
51
- */
52
- function checkBundledDirs(packageRoot, results) {
53
- results.checks++;
54
- const frameworkDir = join(packageRoot, 'framework');
55
- if (!existsSync(frameworkDir)) return;
56
-
57
- const missing = [];
58
- for (const dir of EXPECTED_BUNDLE_DIRS) {
59
- if (!existsSync(join(frameworkDir, dir))) {
60
- missing.push(dir);
61
- }
62
- }
63
-
64
- if (missing.length === 0) {
65
- results.passed++;
66
- } else {
67
- results.errors.push(`Missing framework directories: ${missing.join(', ')}`);
68
- }
69
- }
70
-
71
- /**
72
- * Validate root framework files exist.
73
- */
74
- function checkRootFiles(packageRoot, results) {
75
- results.checks++;
76
- const frameworkDir = join(packageRoot, 'framework');
77
- if (!existsSync(frameworkDir)) return;
78
-
79
- const missing = [];
80
- for (const file of EXPECTED_ROOT_FILES) {
81
- if (!existsSync(join(frameworkDir, file))) {
82
- missing.push(file);
83
- }
84
- }
85
-
86
- if (missing.length === 0) {
87
- results.passed++;
88
- } else {
89
- results.errors.push(`Missing framework root files: ${missing.join(', ')}`);
90
- }
91
- }
92
-
93
- /**
94
- * Check that no sensitive files leaked into the bundle.
95
- */
96
- function checkNoSensitiveFiles(packageRoot, results) {
97
- results.checks++;
98
- const found = [];
99
-
100
- // Only check inside publishable directories (bin/, src/, assets/, framework/, scripts/)
101
- // Root-level files like .signing-key.pem are excluded by package.json "files" field
102
- const publishableDirs = ['framework', 'src', 'scripts', 'bin', 'assets'];
103
- for (const file of SENSITIVE_FILES) {
104
- for (const dir of publishableDirs) {
105
- if (existsSync(join(packageRoot, dir, file))) {
106
- found.push(`${dir}/${file}`);
107
- }
108
- }
109
- }
110
-
111
- if (found.length === 0) {
112
- results.passed++;
113
- } else {
114
- results.errors.push(`Sensitive files found in package: ${found.join(', ')}`);
115
- }
116
- }
117
-
118
- /**
119
- * Validate that all package.json exports resolve to existing files.
120
- */
121
- function checkExportsResolve(packageRoot, results) {
122
- results.checks++;
123
- const pkgPath = join(packageRoot, 'package.json');
124
- if (!existsSync(pkgPath)) return;
125
-
126
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
127
- const exports = pkg.exports || {};
128
- const missing = [];
129
-
130
- for (const [key, value] of Object.entries(exports)) {
131
- const filePath = join(packageRoot, value);
132
- if (!existsSync(filePath)) {
133
- missing.push(`${key} → ${value}`);
134
- }
135
- }
136
-
137
- if (missing.length === 0) {
138
- results.passed++;
139
- } else {
140
- results.errors.push(`Unresolved exports: ${missing.join(', ')}`);
141
- }
142
- }
143
-
144
- /**
145
- * Validate that bin entry exists.
146
- */
147
- function checkBinExists(packageRoot, results) {
148
- results.checks++;
149
- const pkgPath = join(packageRoot, 'package.json');
150
- if (!existsSync(pkgPath)) return;
151
-
152
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
153
- const bin = pkg.bin || {};
154
- const missing = [];
155
-
156
- for (const [name, path] of Object.entries(bin)) {
157
- if (!existsSync(join(packageRoot, path))) {
158
- missing.push(`${name} → ${path}`);
159
- }
160
- }
161
-
162
- if (missing.length === 0) {
163
- results.passed++;
164
- } else {
165
- results.errors.push(`Missing bin entries: ${missing.join(', ')}`);
166
- }
167
- }
168
-
169
- /**
170
- * Validate that every hook referenced in hooks/settings.json exists on disk.
171
- * Prevents shipping a bundle where settings.json references a hook file that
172
- * was never copied.
173
- */
174
- function checkHooksParity(packageRoot, results) {
175
- results.checks++;
176
- const settingsPath = join(packageRoot, 'framework', 'hooks', 'settings.json');
177
- if (!existsSync(settingsPath)) {
178
- results.warnings.push('framework/hooks/settings.json not found — skipping hooks parity check.');
179
- results.passed++;
180
- return;
181
- }
182
-
183
- try {
184
- const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
185
- const missing = new Set();
186
- const hooksDir = join(packageRoot, 'framework', 'hooks');
187
-
188
- // Walk all hook events and collect referenced .js files
189
- for (const event of Object.keys(settings.hooks || {})) {
190
- for (const matcher of settings.hooks[event] || []) {
191
- for (const hook of matcher.hooks || []) {
192
- if (hook.type === 'command' && typeof hook.command === 'string') {
193
- // command format: "node chati.dev/hooks/foo.js"
194
- const match = hook.command.match(/hooks\/([^\s]+\.js)/);
195
- if (match) {
196
- const hookFile = match[1];
197
- if (!existsSync(join(hooksDir, hookFile))) {
198
- missing.add(hookFile);
199
- }
200
- }
201
- }
202
- }
203
- }
204
- }
205
-
206
- if (missing.size === 0) {
207
- results.passed++;
208
- } else {
209
- results.errors.push(`Hooks referenced in settings.json but missing from framework/hooks/: ${[...missing].join(', ')}`);
210
- }
211
- } catch (err) {
212
- results.errors.push(`Failed to parse hooks/settings.json: ${err.message}`);
213
- }
214
- }
215
-
216
- /**
217
- * Parity check: every file in source chati.dev/ (that belongs to a copied
218
- * directory) must exist in framework/. Catches bundling bugs where new files
219
- * are added to the source but not included in the bundle.
220
- *
221
- * Only runs when the monorepo source is available (skipped inside the
222
- * published package since the source is not shipped).
223
- */
224
- function checkSourceBundleParity(packageRoot, results) {
225
- results.checks++;
226
- const monorepoSource = join(packageRoot, '..', '..', 'chati.dev');
227
- const bundleDir = join(packageRoot, 'framework');
228
-
229
- if (!existsSync(monorepoSource)) {
230
- // Running inside the published package — skip (nothing to compare against)
231
- results.passed++;
232
- return;
233
- }
234
-
235
- // Collect all files in source, grouped by the top-level directory
236
- const missing = [];
237
- const COPIED_DIRS = [
238
- 'orchestrator', 'agents', 'templates', 'workflows', 'quality-gates',
239
- 'schemas', 'frameworks', 'intelligence', 'patterns', 'hooks',
240
- 'domains', 'i18n', 'migrations', 'data', 'context', 'tasks', 'presets',
241
- ];
242
- const COPIED_ROOT_FILES = ['constitution.md'];
243
-
244
- function walk(srcDir, relBase) {
245
- if (!existsSync(srcDir)) return;
246
- for (const entry of readdirSync(srcDir, { withFileTypes: true })) {
247
- const srcPath = join(srcDir, entry.name);
248
- const relPath = relBase ? `${relBase}/${entry.name}` : entry.name;
249
- if (entry.isDirectory()) {
250
- walk(srcPath, relPath);
251
- } else if (entry.isFile()) {
252
- const bundlePath = join(bundleDir, relPath);
253
- if (!existsSync(bundlePath)) missing.push(relPath);
254
- }
255
- }
256
- }
257
-
258
- for (const file of COPIED_ROOT_FILES) {
259
- const src = join(monorepoSource, file);
260
- const bundled = join(bundleDir, file);
261
- if (existsSync(src) && !existsSync(bundled)) missing.push(file);
262
- }
263
-
264
- for (const dir of COPIED_DIRS) {
265
- walk(join(monorepoSource, dir), dir);
266
- }
267
-
268
- if (missing.length === 0) {
269
- results.passed++;
270
- } else {
271
- const sample = missing.slice(0, 10).join(', ');
272
- const more = missing.length > 10 ? ` (+ ${missing.length - 10} more)` : '';
273
- results.errors.push(`Files in source chati.dev/ missing from framework/ bundle: ${sample}${more}`);
274
- }
275
- }
276
-
277
- /**
278
- * Compare entity count in registry vs actual files in framework/.
279
- */
280
- function checkEntityCount(packageRoot, results) {
281
- results.checks++;
282
- const registryPath = join(packageRoot, 'framework', 'data', 'entity-registry.yaml');
283
- if (!existsSync(registryPath)) {
284
- results.warnings.push('Entity registry not found in framework/data/ — skipping count check.');
285
- results.passed++;
286
- return;
287
- }
288
-
289
- // Count files in framework/ recursively (excluding manifest.json, manifest.sig)
290
- let fileCount = 0;
291
- function countFiles(dir) {
292
- try {
293
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
294
- if (entry.isDirectory()) {
295
- countFiles(join(dir, entry.name));
296
- } else if (entry.name !== 'manifest.json' && entry.name !== 'manifest.sig') {
297
- fileCount++;
298
- }
299
- }
300
- } catch { /* skip unreadable dirs */ }
301
- }
302
-
303
- countFiles(join(packageRoot, 'framework'));
304
-
305
- if (fileCount > 0) {
306
- results.passed++;
307
- } else {
308
- results.errors.push('Framework directory is empty (0 files).');
309
- }
310
- }
311
-
312
- /**
313
- * Validate the npm package completeness.
314
- * @param {string} packageRoot - Root of the package (packages/chati-dev/)
315
- * @returns {{ errors: string[], warnings: string[], checks: number, passed: number }}
316
- */
317
- export function validatePackage(packageRoot) {
318
- const results = { errors: [], warnings: [], checks: 0, passed: 0 };
319
-
320
- checkFrameworkExists(packageRoot, results);
321
- checkBundledDirs(packageRoot, results);
322
- checkRootFiles(packageRoot, results);
323
- checkNoSensitiveFiles(packageRoot, results);
324
- checkExportsResolve(packageRoot, results);
325
- checkBinExists(packageRoot, results);
326
- checkEntityCount(packageRoot, results);
327
- checkHooksParity(packageRoot, results);
328
- checkSourceBundleParity(packageRoot, results);
329
-
330
- return results;
331
- }
332
-
333
- /**
334
- * Format results for CLI output.
335
- */
336
- function formatResults(results) {
337
- const status = results.errors.length === 0 ? 'PASS' : 'FAIL';
338
- const lines = [
339
- `Package Validation: ${status} (${results.passed}/${results.checks} checks passed)`,
340
- ];
341
-
342
- if (results.errors.length > 0) {
343
- lines.push('');
344
- lines.push('Errors:');
345
- results.errors.forEach(e => lines.push(` ✗ ${e}`));
346
- }
347
-
348
- if (results.warnings.length > 0) {
349
- lines.push('');
350
- lines.push('Warnings:');
351
- results.warnings.forEach(w => lines.push(` ⚠ ${w}`));
352
- }
353
-
354
- return lines.join('\n');
355
- }
356
-
357
- // CLI entry point
358
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
359
- const packageRoot = join(__dirname, '..');
360
- const results = validatePackage(packageRoot);
361
-
362
- console.log(formatResults(results));
363
-
364
- if (results.errors.length > 0) {
365
- process.exit(1);
366
- }
367
- }