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,328 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Semantic Linter — Validates cross-reference consistency across the framework.
5
- *
6
- * Goes beyond structural validation (validate-agents, validate-tasks) to check
7
- * semantic consistency: entity registry integrity, domain-agent alignment,
8
- * workflow references, i18n completeness, schema existence, constitution articles.
9
- *
10
- * Exports:
11
- * semanticLint(frameworkDir) → { errors, warnings, checks, passed }
12
- */
13
-
14
- import { existsSync, readFileSync, readdirSync } from 'fs';
15
- import { join, dirname, basename } from 'path';
16
- import { fileURLToPath } from 'url';
17
- import yaml from 'js-yaml';
18
-
19
- const __dirname = dirname(fileURLToPath(import.meta.url));
20
-
21
- /**
22
- * Check that all paths in entity-registry.yaml point to existing files.
23
- */
24
- function checkEntityRegistryIntegrity(frameworkDir, results) {
25
- results.checks++;
26
- const registryPath = join(frameworkDir, 'data', 'entity-registry.yaml');
27
-
28
- if (!existsSync(registryPath)) {
29
- results.errors.push('Entity registry not found at data/entity-registry.yaml');
30
- return;
31
- }
32
-
33
- const registry = yaml.load(readFileSync(registryPath, 'utf-8'));
34
- const entities = registry.entities || {};
35
- let total = 0;
36
- let found = 0;
37
- const missing = [];
38
-
39
- for (const category of Object.values(entities)) {
40
- for (const [name, entity] of Object.entries(category)) {
41
- if (!entity.path) continue;
42
- total++;
43
-
44
- // Path in registry is relative to project root (e.g., "chati.dev/agents/...")
45
- // Strip "chati.dev/" prefix to get path relative to frameworkDir
46
- const relPath = entity.path.replace(/^chati\.dev\//, '');
47
- if (existsSync(join(frameworkDir, relPath))) {
48
- found++;
49
- } else {
50
- missing.push(`${name}: ${entity.path}`);
51
- }
52
- }
53
- }
54
-
55
- if (missing.length === 0) {
56
- results.passed++;
57
- results.details.push(`Entity registry integrity: ${found}/${total} paths exist`);
58
- } else {
59
- results.errors.push(`Entity registry: ${missing.length} missing files — ${missing.slice(0, 5).join('; ')}${missing.length > 5 ? '...' : ''}`);
60
- }
61
- }
62
-
63
- /**
64
- * Check that each agent in domains/agents/ has a corresponding agent definition file.
65
- */
66
- function checkDomainAgentAlignment(frameworkDir, results) {
67
- results.checks++;
68
- const domainsDir = join(frameworkDir, 'domains', 'agents');
69
-
70
- if (!existsSync(domainsDir)) {
71
- results.errors.push('Domain agents directory not found at domains/agents/');
72
- return;
73
- }
74
-
75
- const domainFiles = readdirSync(domainsDir).filter(f => f.endsWith('.yaml'));
76
- const mismatches = [];
77
-
78
- for (const file of domainFiles) {
79
- const agentName = basename(file, '.yaml');
80
-
81
- // orchestrator has a different path
82
- if (agentName === 'orchestrator') {
83
- if (!existsSync(join(frameworkDir, 'orchestrator', 'chati.md'))) {
84
- mismatches.push('orchestrator');
85
- }
86
- continue;
87
- }
88
-
89
- // Other agents: check all category dirs
90
- const agentDirs = ['agents/discover', 'agents/plan', 'agents/quality', 'agents/build', 'agents/deploy'];
91
- const found = agentDirs.some(dir =>
92
- existsSync(join(frameworkDir, dir, `${agentName}.md`))
93
- );
94
-
95
- if (!found) {
96
- mismatches.push(agentName);
97
- }
98
- }
99
-
100
- if (mismatches.length === 0) {
101
- results.passed++;
102
- results.details.push(`Domain-agent alignment: ${domainFiles.length}/${domainFiles.length} agents matched`);
103
- } else {
104
- results.errors.push(`Domain-agent mismatch: ${mismatches.join(', ')} have domain YAML but no agent .md`);
105
- }
106
- }
107
-
108
- /**
109
- * Check that i18n files have consistent keys across all languages.
110
- */
111
- function checkI18nCompleteness(frameworkDir, results) {
112
- results.checks++;
113
- const i18nDir = join(frameworkDir, 'i18n');
114
-
115
- if (!existsSync(i18nDir)) {
116
- results.errors.push('i18n directory not found');
117
- return;
118
- }
119
-
120
- const languages = ['en', 'pt', 'es', 'fr'];
121
- const keysByLang = {};
122
-
123
- for (const lang of languages) {
124
- const filePath = join(i18nDir, `${lang}.yaml`);
125
- if (!existsSync(filePath)) {
126
- results.errors.push(`i18n file missing: ${lang}.yaml`);
127
- return;
128
- }
129
-
130
- const content = yaml.load(readFileSync(filePath, 'utf-8'));
131
- keysByLang[lang] = flattenKeys(content);
132
- }
133
-
134
- // Use 'en' as reference
135
- const refKeys = new Set(keysByLang.en);
136
- const missingByLang = {};
137
-
138
- for (const lang of languages) {
139
- if (lang === 'en') continue;
140
- const langKeys = new Set(keysByLang[lang]);
141
-
142
- for (const key of refKeys) {
143
- // Skip non-translatable keys
144
- if (key === 'language' || key === 'name') continue;
145
-
146
- if (!langKeys.has(key)) {
147
- if (!missingByLang[lang]) missingByLang[lang] = [];
148
- missingByLang[lang].push(key);
149
- }
150
- }
151
- }
152
-
153
- const totalMissing = Object.values(missingByLang).reduce((sum, arr) => sum + arr.length, 0);
154
-
155
- if (totalMissing === 0) {
156
- results.passed++;
157
- results.details.push(`i18n completeness: all ${languages.length} languages have consistent keys`);
158
- } else {
159
- for (const [lang, keys] of Object.entries(missingByLang)) {
160
- results.warnings.push(`i18n: '${lang}' missing ${keys.length} key(s): ${keys.slice(0, 3).join(', ')}${keys.length > 3 ? '...' : ''}`);
161
- }
162
- results.passed++; // warnings don't fail the check
163
- }
164
- }
165
-
166
- /**
167
- * Check that all expected schema files exist.
168
- */
169
- function checkSchemaExistence(frameworkDir, results) {
170
- results.checks++;
171
- const schemasDir = join(frameworkDir, 'schemas');
172
- const expectedSchemas = [
173
- 'session.schema.json', 'config.schema.json', 'task.schema.json',
174
- 'context.schema.json', 'memory.schema.json',
175
- ];
176
-
177
- const missing = expectedSchemas.filter(s => !existsSync(join(schemasDir, s)));
178
-
179
- if (missing.length === 0) {
180
- results.passed++;
181
- results.details.push(`Schema existence: ${expectedSchemas.length}/${expectedSchemas.length} schemas found`);
182
- } else {
183
- results.errors.push(`Missing schemas: ${missing.join(', ')}`);
184
- }
185
- }
186
-
187
- /**
188
- * Check constitution has >= 19 articles.
189
- */
190
- function checkConstitution(frameworkDir, results) {
191
- results.checks++;
192
- const constitutionPath = join(frameworkDir, 'constitution.md');
193
-
194
- if (!existsSync(constitutionPath)) {
195
- results.errors.push('constitution.md not found');
196
- return;
197
- }
198
-
199
- const content = readFileSync(constitutionPath, 'utf-8');
200
- const articleCount = (content.match(/^## Article/gm) || []).length;
201
-
202
- if (articleCount >= 19) {
203
- results.passed++;
204
- results.details.push(`Constitution: ${articleCount} articles found`);
205
- } else {
206
- results.errors.push(`Constitution has only ${articleCount} articles (expected >= 19)`);
207
- }
208
- }
209
-
210
- /**
211
- * Check that workflow files reference valid agents.
212
- */
213
- function checkWorkflowAgentRefs(frameworkDir, results) {
214
- results.checks++;
215
- const workflowsDir = join(frameworkDir, 'workflows');
216
-
217
- if (!existsSync(workflowsDir)) {
218
- results.errors.push('workflows/ directory not found');
219
- return;
220
- }
221
-
222
- // Collect known agent names
223
- const knownAgents = new Set(['orchestrator']);
224
- const agentDirs = ['agents/discover', 'agents/plan', 'agents/quality', 'agents/build', 'agents/deploy'];
225
- for (const dir of agentDirs) {
226
- const fullDir = join(frameworkDir, dir);
227
- if (!existsSync(fullDir)) continue;
228
- for (const file of readdirSync(fullDir)) {
229
- if (file.endsWith('.md')) {
230
- knownAgents.add(basename(file, '.md'));
231
- }
232
- }
233
- }
234
-
235
- const workflowFiles = readdirSync(workflowsDir).filter(f => f.endsWith('.yaml'));
236
- const unknownRefs = [];
237
-
238
- for (const file of workflowFiles) {
239
- const content = readFileSync(join(workflowsDir, file), 'utf-8');
240
- // Look for agent references in YAML (agent: xxx or - xxx in steps)
241
- const agentRefs = content.match(/agent:\s*(\S+)/g) || [];
242
- for (const ref of agentRefs) {
243
- const agentName = ref.replace('agent:', '').trim();
244
- if (agentName && !knownAgents.has(agentName)) {
245
- unknownRefs.push(`${file}: ${agentName}`);
246
- }
247
- }
248
- }
249
-
250
- if (unknownRefs.length === 0) {
251
- results.passed++;
252
- results.details.push(`Workflow-agent references: ${workflowFiles.length} workflows, all agents valid`);
253
- } else {
254
- results.warnings.push(`Unknown agent refs in workflows: ${unknownRefs.join('; ')}`);
255
- results.passed++; // warnings don't fail
256
- }
257
- }
258
-
259
- /**
260
- * Flatten a nested object into dot-notation keys.
261
- */
262
- function flattenKeys(obj, prefix = '') {
263
- const keys = [];
264
- for (const [key, value] of Object.entries(obj)) {
265
- const fullKey = prefix ? `${prefix}.${key}` : key;
266
- if (value && typeof value === 'object' && !Array.isArray(value)) {
267
- keys.push(...flattenKeys(value, fullKey));
268
- } else {
269
- keys.push(fullKey);
270
- }
271
- }
272
- return keys;
273
- }
274
-
275
- /**
276
- * Run all semantic lint checks.
277
- * @param {string} frameworkDir - Path to the framework directory (chati.dev/)
278
- * @returns {{ errors: string[], warnings: string[], details: string[], checks: number, passed: number }}
279
- */
280
- export function semanticLint(frameworkDir) {
281
- const results = { errors: [], warnings: [], details: [], checks: 0, passed: 0 };
282
-
283
- checkEntityRegistryIntegrity(frameworkDir, results);
284
- checkDomainAgentAlignment(frameworkDir, results);
285
- checkWorkflowAgentRefs(frameworkDir, results);
286
- checkI18nCompleteness(frameworkDir, results);
287
- checkSchemaExistence(frameworkDir, results);
288
- checkConstitution(frameworkDir, results);
289
-
290
- return results;
291
- }
292
-
293
- /**
294
- * Format results for CLI output.
295
- */
296
- function formatResults(results) {
297
- const status = results.errors.length === 0 ? 'PASS' : 'FAIL';
298
- const lines = [
299
- `Semantic Lint: ${status} (${results.passed}/${results.checks} checks, ${results.warnings.length} warnings, ${results.errors.length} errors)`,
300
- '',
301
- ];
302
-
303
- for (const detail of results.details) {
304
- lines.push(` ✓ ${detail}`);
305
- }
306
-
307
- for (const warning of results.warnings) {
308
- lines.push(` ⚠ ${warning}`);
309
- }
310
-
311
- for (const error of results.errors) {
312
- lines.push(` ✗ ${error}`);
313
- }
314
-
315
- return lines.join('\n');
316
- }
317
-
318
- // CLI entry point
319
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
320
- const frameworkDir = join(__dirname, '..', '..', '..', 'chati.dev');
321
- const results = semanticLint(frameworkDir);
322
-
323
- console.log(formatResults(results));
324
-
325
- if (results.errors.length > 0) {
326
- process.exit(1);
327
- }
328
- }
@@ -1,53 +0,0 @@
1
- /**
2
- * Sign the framework manifest with Ed25519.
3
- * Generates manifest.json (file hashes) + manifest.sig (signature).
4
- *
5
- * Run: node scripts/sign-manifest.js
6
- * Requires: .signing-key.pem (generated by generate-signing-key.js)
7
- */
8
- import { sign, createPrivateKey } from 'crypto';
9
- import { readFileSync, writeFileSync, readdirSync, existsSync } from 'fs';
10
- import { join, dirname, relative } from 'path';
11
- import { fileURLToPath } from 'url';
12
- import { generateManifest } from '../src/installer/manifest.js';
13
-
14
- const __dirname = dirname(fileURLToPath(import.meta.url));
15
- const frameworkDir = join(__dirname, '..', 'framework');
16
- const privateKeyPath = join(__dirname, '..', '.signing-key.pem');
17
-
18
- if (!existsSync(frameworkDir)) {
19
- console.error('Framework directory not found. Run bundle-framework.js first.');
20
- process.exit(1);
21
- }
22
-
23
- if (!existsSync(privateKeyPath)) {
24
- console.warn('No signing key found at .signing-key.pem — skipping manifest signing.');
25
- process.exit(0);
26
- }
27
-
28
- function collectFiles(dir, base = dir) {
29
- let files = [];
30
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
31
- const full = join(dir, entry.name);
32
- if (entry.isDirectory()) {
33
- files = files.concat(collectFiles(full, base));
34
- } else if (entry.name !== 'manifest.json' && entry.name !== 'manifest.sig') {
35
- files.push(relative(base, full));
36
- }
37
- }
38
- return files.sort();
39
- }
40
-
41
- const files = collectFiles(frameworkDir);
42
- const version = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')).version;
43
- const manifest = generateManifest(frameworkDir, files, version);
44
-
45
- const manifestJson = JSON.stringify(manifest, Object.keys(manifest).sort(), 2);
46
-
47
- const privateKey = createPrivateKey(readFileSync(privateKeyPath));
48
- const signature = sign(null, Buffer.from(manifestJson), privateKey);
49
-
50
- writeFileSync(join(frameworkDir, 'manifest.json'), manifestJson + '\n');
51
- writeFileSync(join(frameworkDir, 'manifest.sig'), signature.toString('base64'));
52
-
53
- console.log(`Signed manifest: ${Object.keys(manifest.files).length} files, v${version}`);