chati-dev 3.3.2 → 4.0.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 (48) hide show
  1. package/README.md +4 -4
  2. package/framework/agents/plan/ux.md +41 -1
  3. package/framework/config.yaml +18 -3
  4. package/framework/constitution.md +18 -10
  5. package/framework/context/governance.md +2 -0
  6. package/framework/context/root.md +1 -1
  7. package/framework/data/entity-registry.yaml +43 -3
  8. package/framework/domains/constitution.yaml +1 -1
  9. package/framework/domains/global.yaml +7 -3
  10. package/framework/domains/workflows/standard-flow.yaml +33 -0
  11. package/framework/i18n/en.yaml +11 -2
  12. package/framework/i18n/es.yaml +11 -2
  13. package/framework/i18n/fr.yaml +11 -2
  14. package/framework/i18n/pt.yaml +11 -2
  15. package/framework/intelligence/context-engine.md +22 -17
  16. package/framework/presets/nextjs.yaml +41 -0
  17. package/framework/presets/node-express.yaml +39 -0
  18. package/framework/presets/react-vite.yaml +37 -0
  19. package/framework/presets/supabase-fullstack.yaml +37 -0
  20. package/framework/templates/brandbook-tmpl.yaml +113 -0
  21. package/framework/templates/component-spec-tmpl.yaml +74 -0
  22. package/framework/templates/design-token-tmpl.yaml +55 -0
  23. package/framework/templates/icon-system-tmpl.yaml +95 -0
  24. package/package.json +1 -1
  25. package/scripts/bundle-framework.js +1 -1
  26. package/scripts/doctor/checks/agents.js +77 -0
  27. package/scripts/doctor/checks/constitution.js +41 -0
  28. package/scripts/doctor/checks/domain-alignment.js +58 -0
  29. package/scripts/doctor/checks/prism-layers.js +84 -0
  30. package/scripts/doctor/checks/registry.js +55 -0
  31. package/scripts/doctor/checks/schemas.js +61 -0
  32. package/scripts/doctor/fixes/reference-fix.js +100 -0
  33. package/scripts/doctor/fixes/registry-fix.js +56 -0
  34. package/scripts/doctor/index.js +212 -0
  35. package/scripts/health-check.js +8 -8
  36. package/src/autonomy/surface-criteria.js +226 -0
  37. package/src/context/bracket-tracker.js +44 -13
  38. package/src/context/domain-loader.js +22 -0
  39. package/src/context/engine.js +18 -7
  40. package/src/context/formatter.js +21 -1
  41. package/src/context/layers/l5-keywords.js +53 -0
  42. package/src/intelligence/context-status.js +20 -9
  43. package/src/intelligence/decision-engine.js +253 -0
  44. package/src/terminal/prompt-builder.js +341 -1
  45. package/src/terminal/run-agent.js +15 -0
  46. package/src/terminal/run-parallel.js +77 -5
  47. package/src/terminal/spawner.js +13 -0
  48. package/src/utils/feature-flags.js +106 -0
@@ -0,0 +1,37 @@
1
+ # Tech Preset: Supabase Fullstack
2
+ # Auto-loaded by Architect agent when Supabase stack is detected
3
+
4
+ stack: supabase-fullstack
5
+ displayName: "Supabase Fullstack"
6
+
7
+ detection:
8
+ - supabase/config.toml
9
+ - .env.local containing SUPABASE_URL
10
+
11
+ conventions:
12
+ auth: "Supabase Auth with RLS policies for authorization"
13
+ database: "PostgreSQL with Row Level Security (RLS) on every table"
14
+ storage: "Supabase Storage for file uploads with bucket policies"
15
+ functions: "Supabase Edge Functions (Deno) for serverless logic"
16
+ realtime: "Supabase Realtime for live subscriptions"
17
+
18
+ structure:
19
+ - "supabase/ — Supabase project configuration"
20
+ - "supabase/migrations/ — SQL migration files"
21
+ - "supabase/functions/ — Edge Functions (Deno)"
22
+ - "supabase/seed.sql — Seed data"
23
+ - "src/lib/supabase.ts — Supabase client initialization"
24
+
25
+ rules:
26
+ - id: supabase-rls
27
+ text: "EVERY table MUST have RLS enabled. No exceptions. Create policies before exposing data."
28
+ priority: critical
29
+ - id: supabase-migrations
30
+ text: "All schema changes go through migration files. Never modify production DB directly."
31
+ priority: critical
32
+ - id: supabase-types
33
+ text: "Generate TypeScript types from database schema (supabase gen types)."
34
+ priority: high
35
+ - id: supabase-auth
36
+ text: "Use Supabase Auth helpers for SSR frameworks. Handle auth state server-side."
37
+ priority: high
@@ -0,0 +1,113 @@
1
+ # Brandbook Template
2
+ # Used by: UX Agent (Phase 0: Brand Identity)
3
+ # Language: English (Constitution Article VII)
4
+
5
+ template:
6
+ name: Brandbook
7
+ version: "1.0.0"
8
+ description: >
9
+ Brand identity foundation document. Defines voice, visual language,
10
+ typography rationale, color philosophy, spacing rhythm, and iconography
11
+ style. Must be completed BEFORE design tokens.
12
+
13
+ output_path: chati.dev/artifacts/4-UX/brandbook.md
14
+
15
+ sections:
16
+ - brand_voice
17
+ - visual_language
18
+ - typography_rationale
19
+ - color_philosophy
20
+ - spacing_rhythm
21
+ - iconography_style
22
+
23
+ brand_voice:
24
+ description: "Brand personality, tone, and communication style"
25
+ fields:
26
+ - name: personality_traits
27
+ type: array
28
+ description: "3-5 adjectives defining the brand personality"
29
+ - name: tone_spectrum
30
+ type: object
31
+ description: "Formal vs casual, technical vs approachable spectrum"
32
+ - name: writing_guidelines
33
+ type: array
34
+ description: "Dos and don'ts for brand voice"
35
+ - name: example_phrases
36
+ type: array
37
+ description: "Sample phrases demonstrating brand voice"
38
+
39
+ visual_language:
40
+ description: "Core visual principles and aesthetic direction"
41
+ fields:
42
+ - name: design_principles
43
+ type: array
44
+ description: "3-5 guiding principles for visual design"
45
+ - name: mood_keywords
46
+ type: array
47
+ description: "Keywords capturing the visual mood"
48
+ - name: inspiration_references
49
+ type: array
50
+ description: "Visual references and mood board elements"
51
+
52
+ typography_rationale:
53
+ description: "Font selection rationale and typographic hierarchy"
54
+ fields:
55
+ - name: primary_font
56
+ type: object
57
+ description: "Primary typeface and why it was chosen"
58
+ - name: secondary_font
59
+ type: object
60
+ description: "Secondary typeface for contrast"
61
+ - name: hierarchy_rules
62
+ type: array
63
+ description: "Heading, body, caption sizing rationale"
64
+
65
+ color_philosophy:
66
+ description: "Color palette rationale and emotional associations"
67
+ fields:
68
+ - name: primary_palette
69
+ type: array
70
+ description: "Primary colors with emotional rationale"
71
+ - name: semantic_mapping
72
+ type: object
73
+ description: "Color-to-meaning mapping (success, warning, error)"
74
+ - name: accessibility_notes
75
+ type: string
76
+ description: "WCAG contrast compliance notes"
77
+
78
+ spacing_rhythm:
79
+ description: "Spacing scale rationale and rhythm system"
80
+ fields:
81
+ - name: base_unit
82
+ type: number
83
+ description: "Base spacing unit in pixels"
84
+ - name: scale_rationale
85
+ type: string
86
+ description: "Why this scale was chosen (4px, 8px, etc.)"
87
+ - name: rhythm_rules
88
+ type: array
89
+ description: "Rules for consistent vertical and horizontal rhythm"
90
+
91
+ iconography_style:
92
+ description: "Icon style direction and usage philosophy"
93
+ fields:
94
+ - name: style_direction
95
+ type: string
96
+ description: "Outlined, filled, duotone, etc."
97
+ - name: stroke_weight
98
+ type: string
99
+ description: "Consistent stroke weight for icon set"
100
+ - name: metaphor_guidelines
101
+ type: array
102
+ description: "Guidelines for icon metaphor selection"
103
+
104
+ rules:
105
+ - id: brand-before-tokens
106
+ text: "Brandbook MUST be completed before design tokens are defined."
107
+ priority: critical
108
+ - id: brand-consistency
109
+ text: "All visual decisions must trace back to brandbook principles."
110
+ priority: high
111
+ - id: brand-voice-artifacts
112
+ text: "All user-facing text in artifacts must follow brand voice guidelines."
113
+ priority: high
@@ -0,0 +1,74 @@
1
+ # Component Spec Template
2
+ # Used by: UX Agent (Phase 2: Component Specifications)
3
+ # Language: English (Constitution Article VII)
4
+
5
+ template:
6
+ name: Component Spec
7
+ version: "1.0.0"
8
+ description: >
9
+ UI component specification document. Defines variants, states,
10
+ anatomy, props, accessibility, and responsive behavior.
11
+
12
+ output_path: chati.dev/artifacts/4-UX/components/
13
+
14
+ fields:
15
+ - name: id
16
+ type: string
17
+ description: "Unique component identifier (kebab-case)"
18
+ required: true
19
+ - name: name
20
+ type: string
21
+ description: "Human-readable component name"
22
+ required: true
23
+ - name: category
24
+ type: enum
25
+ values: [primitive, composite, layout, feedback, navigation, data-display, form]
26
+ description: "Component category for organization"
27
+ required: true
28
+ - name: description
29
+ type: string
30
+ description: "One-sentence description of the component purpose"
31
+ required: true
32
+ - name: variants
33
+ type: array
34
+ description: "Visual variants (primary, secondary, ghost, destructive, etc.)"
35
+ required: true
36
+ - name: sizes
37
+ type: array
38
+ description: "Size variants (xs, sm, md, lg, xl)"
39
+ required: true
40
+ - name: states
41
+ type: array
42
+ description: "Interactive states (default, hover, active, focus, disabled, loading, error)"
43
+ required: true
44
+ - name: anatomy
45
+ type: object
46
+ description: "Component parts and their structure"
47
+ required: true
48
+ - name: props
49
+ type: array
50
+ description: "Component API (props with types, defaults, descriptions)"
51
+ required: true
52
+ - name: tokens_used
53
+ type: array
54
+ description: "Design tokens consumed by this component"
55
+ required: true
56
+ - name: accessibility
57
+ type: object
58
+ description: "ARIA roles, keyboard navigation, screen reader behavior"
59
+ required: true
60
+ - name: responsive_behavior
61
+ type: object
62
+ description: "How component adapts across breakpoints"
63
+ required: false
64
+
65
+ rules:
66
+ - id: tokens-required
67
+ text: "Every visual property MUST reference a design token. No hardcoded values."
68
+ priority: critical
69
+ - id: accessibility-required
70
+ text: "Every component MUST have ARIA roles and keyboard navigation defined."
71
+ priority: critical
72
+ - id: state-coverage
73
+ text: "All interactive states must be specified including disabled and loading."
74
+ priority: high
@@ -0,0 +1,55 @@
1
+ # Design Token Template
2
+ # Used by: UX Agent (Phase 1: Design Tokens)
3
+ # Language: English (Constitution Article VII)
4
+
5
+ template:
6
+ name: Design Tokens
7
+ version: "1.0.0"
8
+ description: >
9
+ Structured design token system with 4 layers: primitive, semantic,
10
+ component, and utility. Derived from brandbook decisions.
11
+
12
+ output_path: chati.dev/artifacts/4-UX/design-tokens.md
13
+
14
+ layers:
15
+ - primitive
16
+ - semantic
17
+ - component
18
+ - utility
19
+
20
+ token_categories:
21
+ color:
22
+ primitive: "Raw color values (hex, hsl)"
23
+ semantic: "Mapped to meaning (primary, success, error)"
24
+ component: "Component-specific (button-bg, card-border)"
25
+ spacing:
26
+ primitive: "Base unit multiples (4, 8, 12, 16, 24, 32, 48, 64)"
27
+ semantic: "Mapped to usage (compact, default, relaxed)"
28
+ component: "Component-specific (card-padding, input-gap)"
29
+ typography:
30
+ primitive: "Font families, raw sizes, weights"
31
+ semantic: "Mapped to roles (heading, body, caption, label)"
32
+ component: "Component-specific (button-text, input-label)"
33
+ radius:
34
+ primitive: "Raw radius values (0, 2, 4, 8, 12, full)"
35
+ semantic: "Mapped to shape intent (sharp, soft, round, pill)"
36
+ shadow:
37
+ primitive: "Raw shadow definitions (offset, blur, spread, color)"
38
+ semantic: "Mapped to elevation (flat, raised, floating, overlay)"
39
+ motion:
40
+ primitive: "Duration and easing values"
41
+ semantic: "Mapped to intent (enter, exit, emphasis, feedback)"
42
+
43
+ rules:
44
+ - id: tokens-after-brandbook
45
+ text: "Design tokens MUST be derived from brandbook decisions."
46
+ priority: critical
47
+ - id: primitive-first
48
+ text: "Define primitive tokens before semantic. Semantic references primitive."
49
+ priority: high
50
+ - id: token-naming
51
+ text: "Use consistent naming: layer-category-variant (e.g., color-primary-500)."
52
+ priority: high
53
+ - id: accessibility-contrast
54
+ text: "All text color tokens must meet WCAG AA contrast ratio (4.5:1)."
55
+ priority: critical
@@ -0,0 +1,95 @@
1
+ # Icon System Template
2
+ # Used by: UX Agent (Phase 0: Brand Identity / Iconography)
3
+ # Language: English (Constitution Article VII)
4
+
5
+ template:
6
+ name: Icon System
7
+ version: "1.0.0"
8
+ description: >
9
+ Icon library selection, sizing scale, usage guidelines, and inventory.
10
+ Aligned with brandbook iconography style.
11
+
12
+ output_path: chati.dev/artifacts/4-UX/icon-system.md
13
+
14
+ sections:
15
+ library_selection:
16
+ description: "Chosen icon library and rationale"
17
+ fields:
18
+ - name: library_name
19
+ type: string
20
+ description: "Selected icon library (e.g., Lucide, Phosphor, Heroicons)"
21
+ - name: rationale
22
+ type: string
23
+ description: "Why this library was chosen"
24
+ - name: style
25
+ type: enum
26
+ values: [outlined, filled, duotone, solid]
27
+ description: "Icon style variant"
28
+ - name: license
29
+ type: string
30
+ description: "Icon library license (MIT, Apache, etc.)"
31
+
32
+ sizing_scale:
33
+ description: "Icon size scale aligned with spacing tokens"
34
+ fields:
35
+ - name: xs
36
+ type: number
37
+ description: "Extra small icon size (12-14px)"
38
+ - name: sm
39
+ type: number
40
+ description: "Small icon size (16px)"
41
+ - name: md
42
+ type: number
43
+ description: "Medium icon size (20-24px)"
44
+ - name: lg
45
+ type: number
46
+ description: "Large icon size (28-32px)"
47
+ - name: xl
48
+ type: number
49
+ description: "Extra large icon size (40-48px)"
50
+ - name: xxl
51
+ type: number
52
+ description: "Display icon size (56-64px)"
53
+
54
+ usage_guidelines:
55
+ description: "Rules for consistent icon usage"
56
+ fields:
57
+ - name: with_text
58
+ type: string
59
+ description: "When to pair icons with text labels"
60
+ - name: standalone
61
+ type: string
62
+ description: "When icons can stand alone (with aria-label)"
63
+ - name: color_rules
64
+ type: string
65
+ description: "How icons inherit or override color tokens"
66
+ - name: touch_target
67
+ type: string
68
+ description: "Minimum touch target size (44x44px for mobile)"
69
+
70
+ icon_inventory:
71
+ description: "Catalog of icons used in the project"
72
+ fields:
73
+ - name: navigation
74
+ type: array
75
+ description: "Icons used in navigation elements"
76
+ - name: actions
77
+ type: array
78
+ description: "Icons for user actions (add, edit, delete, etc.)"
79
+ - name: status
80
+ type: array
81
+ description: "Icons for status indicators (success, warning, error, info)"
82
+ - name: content
83
+ type: array
84
+ description: "Icons for content types (file, folder, image, etc.)"
85
+
86
+ rules:
87
+ - id: icon-library-consistency
88
+ text: "Use ONE icon library per project. Do not mix libraries."
89
+ priority: critical
90
+ - id: icon-accessibility
91
+ text: "Standalone icons MUST have aria-label. Decorative icons use aria-hidden."
92
+ priority: critical
93
+ - id: icon-sizing-alignment
94
+ text: "Icon sizes must align with the spacing token scale from design tokens."
95
+ priority: high
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chati-dev",
3
- "version": "3.3.2",
3
+ "version": "4.0.1",
4
4
  "description": "AI-Powered Multi-Agent Orchestration System — Structured vibe coding for Full Stack Development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -37,7 +37,7 @@ const dirs = [
37
37
  'schemas', 'frameworks', 'intelligence', 'patterns',
38
38
  'hooks', 'domains',
39
39
  'i18n', 'migrations', 'data',
40
- 'tasks', 'context',
40
+ 'tasks', 'context', 'presets',
41
41
  ];
42
42
 
43
43
  for (const dir of dirs) {
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @fileoverview Doctor check: Agent definition files.
3
+ *
4
+ * Validates that all 13 agent definition files exist with valid structure.
5
+ */
6
+
7
+ import { readFileSync, existsSync } from 'fs';
8
+ import { join } from 'path';
9
+
10
+ const EXPECTED_AGENTS = {
11
+ 'discover/greenfield-wu.md': 'greenfield-wu',
12
+ 'discover/brownfield-wu.md': 'brownfield-wu',
13
+ 'discover/brief.md': 'brief',
14
+ 'plan/detail.md': 'detail',
15
+ 'plan/architect.md': 'architect',
16
+ 'plan/ux.md': 'ux',
17
+ 'plan/phases.md': 'phases',
18
+ 'plan/tasks.md': 'tasks',
19
+ 'quality/qa-planning.md': 'qa-planning',
20
+ 'quality/qa-implementation.md': 'qa-implementation',
21
+ 'build/dev.md': 'dev',
22
+ 'deploy/devops.md': 'devops',
23
+ };
24
+
25
+ /**
26
+ * Run agents check.
27
+ *
28
+ * @param {string} frameworkDir - Path to framework directory
29
+ * @returns {{ pass: boolean, details: string, severity: string, fixable: boolean, fixId: string|null }}
30
+ */
31
+ export function checkAgents(frameworkDir) {
32
+ const agentsDir = join(frameworkDir, 'agents');
33
+ const orchestratorDir = join(frameworkDir, 'orchestrator');
34
+
35
+ const missing = [];
36
+ const invalid = [];
37
+
38
+ for (const [relPath, name] of Object.entries(EXPECTED_AGENTS)) {
39
+ const fullPath = join(agentsDir, relPath);
40
+ if (!existsSync(fullPath)) {
41
+ missing.push(name);
42
+ continue;
43
+ }
44
+ try {
45
+ const content = readFileSync(fullPath, 'utf8');
46
+ if (!content.includes('## Identity') && !content.includes('## Mission')) {
47
+ invalid.push(name);
48
+ }
49
+ } catch {
50
+ invalid.push(name);
51
+ }
52
+ }
53
+
54
+ // Check orchestrator
55
+ const orchPath = join(orchestratorDir, 'chati.md');
56
+ if (!existsSync(orchPath)) {
57
+ missing.push('orchestrator');
58
+ }
59
+
60
+ const total = Object.keys(EXPECTED_AGENTS).length + 1;
61
+ const found = total - missing.length;
62
+
63
+ if (missing.length > 0 || invalid.length > 0) {
64
+ const issues = [];
65
+ if (missing.length) issues.push(`missing: ${missing.join(', ')}`);
66
+ if (invalid.length) issues.push(`invalid: ${invalid.join(', ')}`);
67
+ return {
68
+ pass: false,
69
+ details: `${found}/${total} agents found; ${issues.join('; ')}`,
70
+ severity: missing.length > 0 ? 'critical' : 'warning',
71
+ fixable: false,
72
+ fixId: null,
73
+ };
74
+ }
75
+
76
+ return { pass: true, details: `${found}/${total} agents present`, severity: 'info', fixable: false, fixId: null };
77
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @fileoverview Doctor check: Constitution integrity.
3
+ *
4
+ * Validates constitution.md exists and contains the expected number of articles.
5
+ */
6
+
7
+ import { readFileSync, existsSync } from 'fs';
8
+ import { join } from 'path';
9
+
10
+ /**
11
+ * Run constitution integrity check.
12
+ *
13
+ * @param {string} frameworkDir - Path to framework directory
14
+ * @returns {{ pass: boolean, details: string, severity: string, fixable: boolean, fixId: string|null }}
15
+ */
16
+ export function checkConstitution(frameworkDir) {
17
+ const constPath = join(frameworkDir, 'constitution.md');
18
+ if (!existsSync(constPath)) {
19
+ return { pass: false, details: 'constitution.md not found', severity: 'critical', fixable: false, fixId: null };
20
+ }
21
+
22
+ try {
23
+ const content = readFileSync(constPath, 'utf8');
24
+ const articleMatches = content.match(/^## Article [IVXLCDM]+/gm) || [];
25
+ const articleCount = articleMatches.length;
26
+
27
+ if (articleCount < 10) {
28
+ return {
29
+ pass: false,
30
+ details: `Only ${articleCount} articles found (expected 10+)`,
31
+ severity: 'warning',
32
+ fixable: false,
33
+ fixId: null,
34
+ };
35
+ }
36
+
37
+ return { pass: true, details: `${articleCount} articles found`, severity: 'info', fixable: false, fixId: null };
38
+ } catch (err) {
39
+ return { pass: false, details: `Failed to read: ${err.message}`, severity: 'critical', fixable: false, fixId: null };
40
+ }
41
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @fileoverview Doctor check: Domain-Agent alignment.
3
+ *
4
+ * Validates that each agent domain YAML has a corresponding agent .md file.
5
+ */
6
+
7
+ import { existsSync, readdirSync } from 'fs';
8
+ import { join, basename } from 'path';
9
+
10
+ /**
11
+ * Run domain-agent alignment check.
12
+ *
13
+ * @param {string} frameworkDir - Path to framework directory
14
+ * @returns {{ pass: boolean, details: string, severity: string, fixable: boolean, fixId: string|null }}
15
+ */
16
+ export function checkDomainAlignment(frameworkDir) {
17
+ const domainsDir = join(frameworkDir, 'domains', 'agents');
18
+ if (!existsSync(domainsDir)) {
19
+ return { pass: false, details: 'domains/agents/ directory not found', severity: 'warning', fixable: false, fixId: null };
20
+ }
21
+
22
+ const domainFiles = readdirSync(domainsDir).filter(f => f.endsWith('.yaml'));
23
+ const mismatches = [];
24
+
25
+ for (const file of domainFiles) {
26
+ const agentName = basename(file, '.yaml');
27
+
28
+ // Orchestrator has a different path
29
+ if (agentName === 'orchestrator') {
30
+ if (!existsSync(join(frameworkDir, 'orchestrator', 'chati.md'))) {
31
+ mismatches.push('orchestrator');
32
+ }
33
+ continue;
34
+ }
35
+
36
+ // Other agents: check all category dirs
37
+ const agentDirs = ['agents/discover', 'agents/plan', 'agents/quality', 'agents/build', 'agents/deploy'];
38
+ const found = agentDirs.some(dir =>
39
+ existsSync(join(frameworkDir, dir, `${agentName}.md`))
40
+ );
41
+
42
+ if (!found) {
43
+ mismatches.push(agentName);
44
+ }
45
+ }
46
+
47
+ if (mismatches.length > 0) {
48
+ return {
49
+ pass: false,
50
+ details: `Mismatched agents: ${mismatches.join(', ')}`,
51
+ severity: 'warning',
52
+ fixable: false,
53
+ fixId: null,
54
+ };
55
+ }
56
+
57
+ return { pass: true, details: `${domainFiles.length} domain-agent pairs aligned`, severity: 'info', fixable: false, fixId: null };
58
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @fileoverview Doctor check: PRISM Layer integrity.
3
+ *
4
+ * Validates that all 6 PRISM layers (L0-L5) have the required
5
+ * domain files and configuration in place.
6
+ */
7
+
8
+ import { existsSync, readdirSync, readFileSync } from 'fs';
9
+ import { join } from 'path';
10
+
11
+ /**
12
+ * Run PRISM layers integrity check.
13
+ *
14
+ * @param {string} frameworkDir - Path to framework directory
15
+ * @returns {{ pass: boolean, details: string, severity: string, fixable: boolean, fixId: string|null }}
16
+ */
17
+ export function checkPrismLayers(frameworkDir) {
18
+ const domainsDir = join(frameworkDir, 'domains');
19
+ if (!existsSync(domainsDir)) {
20
+ return { pass: false, details: 'domains/ directory not found', severity: 'critical', fixable: false, fixId: null };
21
+ }
22
+
23
+ const issues = [];
24
+
25
+ // L0: Constitution domain
26
+ const constitutionDomain = join(domainsDir, 'constitution.yaml');
27
+ if (!existsSync(constitutionDomain)) {
28
+ issues.push('L0: constitution.yaml missing');
29
+ }
30
+
31
+ // L1: Global domain
32
+ const globalDomain = join(domainsDir, 'global.yaml');
33
+ if (!existsSync(globalDomain)) {
34
+ issues.push('L1: global.yaml missing');
35
+ }
36
+
37
+ // L2: Agent domains
38
+ const agentsDir = join(domainsDir, 'agents');
39
+ if (!existsSync(agentsDir)) {
40
+ issues.push('L2: agents/ directory missing');
41
+ } else {
42
+ const agentDomains = readdirSync(agentsDir).filter(f => f.endsWith('.yaml'));
43
+ if (agentDomains.length < 12) {
44
+ issues.push(`L2: only ${agentDomains.length}/12 agent domains found`);
45
+ }
46
+ }
47
+
48
+ // L3: Workflow domains
49
+ const workflowsDir = join(domainsDir, 'workflows');
50
+ if (!existsSync(workflowsDir)) {
51
+ issues.push('L3: workflows/ directory missing');
52
+ }
53
+
54
+ // L4: Task context (checked via task domain files or inline)
55
+ // L4 is dynamic (loaded from handoff data), so we check that the task
56
+ // processing layer module exists
57
+ const l4Module = join(frameworkDir, '..', 'src', 'context', 'layers', 'l4-task.js');
58
+ if (!existsSync(l4Module)) {
59
+ issues.push('L4: l4-task.js module missing');
60
+ }
61
+
62
+ // L5: Keywords domains
63
+ const keywordsDir = join(domainsDir, 'keywords');
64
+ if (!existsSync(keywordsDir)) {
65
+ issues.push('L5: keywords/ directory missing');
66
+ } else {
67
+ const keywordFiles = readdirSync(keywordsDir).filter(f => f.endsWith('.yaml'));
68
+ if (keywordFiles.length === 0) {
69
+ issues.push('L5: no keyword domain files found');
70
+ }
71
+ }
72
+
73
+ if (issues.length > 0) {
74
+ return {
75
+ pass: false,
76
+ details: issues.join('; '),
77
+ severity: issues.some(i => i.includes('L0') || i.includes('L1')) ? 'critical' : 'warning',
78
+ fixable: false,
79
+ fixId: null,
80
+ };
81
+ }
82
+
83
+ return { pass: true, details: 'All 6 PRISM layers (L0-L5) validated', severity: 'info', fixable: false, fixId: null };
84
+ }