chati-dev 4.3.1 → 4.4.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.
- package/README.md +18 -13
- package/bin/chati.js +12 -4
- package/framework/agents/build/dev.md +5 -1
- package/framework/agents/discover/greenfield-wu.md +16 -1
- package/framework/agents/plan/tasks.md +31 -0
- package/framework/agents/plan/ux-brand-architect.md +21 -2
- package/framework/agents/plan/ux-component-engineer.md +10 -0
- package/framework/agents/quality/qa-implementation.md +1 -1
- package/framework/agents/quality/qa-planning.md +1 -1
- package/framework/agents/quality/qa-visual.md +24 -21
- package/framework/config.yaml +5 -4
- package/framework/constitution.md +58 -11
- package/framework/context/governance.md +12 -10
- package/framework/context/root.md +2 -2
- package/framework/data/entity-registry.yaml +12 -4
- package/framework/data/qa-rubrics.yaml +335 -0
- package/framework/domains/constitution.yaml +3 -3
- package/framework/executors/json-validate.js +80 -0
- package/framework/executors/npm-script.js +72 -0
- package/framework/executors/path-check.js +67 -0
- package/framework/executors/registry.yaml +36 -0
- package/framework/hooks/advance-trigger.js +47 -3
- package/framework/hooks/constitution-guard.js +9 -4
- package/framework/hooks/git-push-authority.js +113 -0
- package/framework/hooks/license-guard.js +59 -9
- package/framework/hooks/model-governance.js +40 -17
- package/framework/hooks/prism-engine.js +78 -11
- package/framework/hooks/session-digest.js +12 -3
- package/framework/hooks/settings.json +7 -3
- package/framework/hooks/style-guard.js +52 -3
- package/framework/hooks/team-quality-gate.js +43 -5
- package/framework/i18n/en.yaml +3 -3
- package/framework/i18n/es.yaml +3 -3
- package/framework/i18n/fr.yaml +3 -3
- package/framework/i18n/pt.yaml +3 -3
- package/framework/intelligence/confidence.yaml +85 -6
- package/framework/intelligence/context-engine.md +9 -5
- package/framework/intelligence/decision-engine.md +1 -1
- package/framework/orchestrator/chati-router.js +1 -1
- package/framework/orchestrator/chati-update.md +19 -3
- package/framework/orchestrator/chati.md +19 -1
- package/framework/quality-gates/planning-gate.md +2 -0
- package/framework/scaffold/motion-premium/scaffold.yaml +2 -1
- package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
- package/framework/scaffold/saas-dashboard/README.md +58 -0
- package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
- package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
- package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
- package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
- package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
- package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
- package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
- package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
- package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
- package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
- package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
- package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
- package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
- package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
- package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
- package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
- package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
- package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
- package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
- package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
- package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
- package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
- package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
- package/framework/schemas/session.schema.json +5 -0
- package/framework/schemas/task.schema.json +9 -0
- package/framework/scripts/visual-qa.js +87 -1
- package/framework/tasks/orchestrator-health.md +4 -4
- package/framework/tasks/qa-impl-verdict.md +11 -5
- package/framework/templates/qa-gate-tmpl.yaml +24 -11
- package/package.json +3 -3
- package/src/config/context-file-generator.js +0 -6
- package/src/dashboard/renderer.js +0 -36
- package/src/executors/runner.js +204 -0
- package/src/installer/core.js +2 -1
- package/src/installer/templates.js +5 -6
- package/src/intelligence/registry-manager.js +1 -1
- package/src/license/client.js +9 -3
- package/src/license/commands.js +12 -2
- package/src/license/machine-id.js +42 -1
- package/src/memory/gotchas.js +58 -40
- package/src/memory/magic-docs.js +1 -1
- package/src/memory/session-digest.js +9 -4
- package/src/orchestrator/cli.js +174 -14
- package/src/orchestrator/doctor.js +98 -16
- package/src/orchestrator/pipeline-manager.js +44 -22
- package/src/orchestrator/session-manager.js +56 -8
- package/src/telemetry/sender.js +7 -19
- package/src/terminal/run-team.js +3 -3
- package/src/upgrade/tracked-files-detector.js +34 -16
- package/src/utils/feature-flags.js +1 -1
- package/src/utils/flatten-entities.js +4 -40
- package/src/utils/schema-validator.js +0 -14
- package/src/wizard/i18n.js +3 -3
- package/src/api/index.js +0 -120
- package/src/autonomy/autonomous-gate.js +0 -294
- package/src/autonomy/build-loop.js +0 -281
- package/src/autonomy/build-state.js +0 -286
- package/src/autonomy/cause-analyzer.js +0 -177
- package/src/autonomy/escalation.js +0 -214
- package/src/autonomy/index.js +0 -51
- package/src/autonomy/mode-manager.js +0 -225
- package/src/autonomy/mode-suggester.js +0 -283
- package/src/autonomy/progress-reporter.js +0 -275
- package/src/autonomy/safety-net.js +0 -370
- package/src/config/agent-customizer.js +0 -231
- package/src/decision/analyzer.js +0 -291
- package/src/decision/engine.js +0 -250
- package/src/decision/index.js +0 -38
- package/src/decision/registry-healer.js +0 -468
- package/src/decision/registry-updater.js +0 -339
- package/src/extensions/loader.js +0 -145
- package/src/extensions/registry.js +0 -134
- package/src/gates/circuit-breaker.js +0 -151
- package/src/gates/g1-planning-complete.js +0 -154
- package/src/gates/g2-qa-planning.js +0 -156
- package/src/gates/g3-implementation.js +0 -215
- package/src/gates/g4-qa-implementation.js +0 -240
- package/src/gates/g5-deploy-ready.js +0 -181
- package/src/gates/gate-base.js +0 -185
- package/src/gates/index.js +0 -46
- package/src/health/auto-fix.js +0 -216
- package/src/health/engine.js +0 -246
- package/src/merger/semantic-merger.js +0 -292
- package/src/preview/detector.js +0 -238
- package/src/preview/index.js +0 -20
- package/src/preview/launcher.js +0 -235
- package/src/preview/log-buffer.js +0 -103
- package/src/quality/metrics-collector.js +0 -281
- package/src/quality/test-runner.js +0 -366
- package/src/tasks/executor.js +0 -195
- package/src/tasks/index.js +0 -4
- package/src/tasks/loader.js +0 -210
- package/src/tasks/router.js +0 -182
- package/src/utils/event-bus.js +0 -126
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Scaffold Premium - saas-dashboard v1.0.0
|
|
2
|
+
#
|
|
3
|
+
# Declarative manifest for the saas-dashboard scaffold preset. Consumed by
|
|
4
|
+
# the scaffold-applier at apply time to resolve placeholders and emit files
|
|
5
|
+
# into the target project. App-shell category: a premium SaaS dashboard with
|
|
6
|
+
# a sidebar, top bar, sortable data tables, KPI cards, an SVG chart, forms,
|
|
7
|
+
# and a Cmd+K command palette. Distinct from the motion-premium presets,
|
|
8
|
+
# which target animated showcase sites.
|
|
9
|
+
#
|
|
10
|
+
# Contract: this schema is STABLE within v1.x. Additions only.
|
|
11
|
+
|
|
12
|
+
id: saas-dashboard
|
|
13
|
+
version: 1.0.0
|
|
14
|
+
description: "Premium SaaS dashboard and app-shell: sidebar nav, top bar, sortable data tables, KPI stat cards, a self-contained SVG chart, accessible forms, and a Cmd+K command palette. Calibrated dark palette, modular type scale, fully token-driven, WCAG AA. Opinionated for Next.js / React 18+ / Tailwind v4."
|
|
15
|
+
|
|
16
|
+
framework:
|
|
17
|
+
chati_dev: ">=4.3.0"
|
|
18
|
+
|
|
19
|
+
stack:
|
|
20
|
+
build_tools: ["nextjs"]
|
|
21
|
+
tailwind: ">=4.0.0"
|
|
22
|
+
typescript: ">=5.0.0"
|
|
23
|
+
node: ">=18.0.0"
|
|
24
|
+
react: ">=18.0.0"
|
|
25
|
+
next: ">=13.0.0"
|
|
26
|
+
# TypeScript dev types. create-next-app --typescript installs these; declared
|
|
27
|
+
# here so a hand-rolled Next.js project knows to add them before applying.
|
|
28
|
+
"@types/react": ">=18.0.0"
|
|
29
|
+
"@types/react-dom": ">=18.0.0"
|
|
30
|
+
# Runtime peer deps imported directly by templates. The chart and command
|
|
31
|
+
# palette are hand-rolled (no chart or cmdk dependency) to keep the footprint small.
|
|
32
|
+
lucide-react: ">=0.400.0"
|
|
33
|
+
"framer-motion": "^11.0.0"
|
|
34
|
+
# Playwright powers the QA-Visual screenshot gate. Without it, visual-qa.js
|
|
35
|
+
# falls back to source analysis (gateway: WEAK).
|
|
36
|
+
playwright: "^1.44.0"
|
|
37
|
+
|
|
38
|
+
# Brandable accent (role 1 interactive affordance). The neutral and semantic
|
|
39
|
+
# scales are the designed system and are not parameterized.
|
|
40
|
+
placeholders:
|
|
41
|
+
ACCENT_HEX:
|
|
42
|
+
source: brand.colors.accent
|
|
43
|
+
default: "#7c5af8"
|
|
44
|
+
type: hex
|
|
45
|
+
ACCENT_HOVER_HEX:
|
|
46
|
+
source: brand.colors.accentHover
|
|
47
|
+
default: "#9070ff"
|
|
48
|
+
type: hex
|
|
49
|
+
|
|
50
|
+
brand_sources:
|
|
51
|
+
- path: lib/brand.ts
|
|
52
|
+
type: typescript
|
|
53
|
+
description: "Existing brand tokens (brownfield or post-install)"
|
|
54
|
+
- path: artifacts/4-UX/brandbook.md
|
|
55
|
+
type: markdown
|
|
56
|
+
description: "UX-authored brandbook (greenfield, post-UX phase)"
|
|
57
|
+
- type: interactive
|
|
58
|
+
prompt: true
|
|
59
|
+
description: "Fallback: ask the user for the accent with default hints"
|
|
60
|
+
|
|
61
|
+
# Files shipped by this scaffold (30 templates).
|
|
62
|
+
files:
|
|
63
|
+
- source: app/dashboard/page.tsx.template
|
|
64
|
+
target: app/dashboard/page.tsx
|
|
65
|
+
phase: sample
|
|
66
|
+
override: full
|
|
67
|
+
notes: "Composed sample dashboard demonstrating the preset. User replaces with real pages."
|
|
68
|
+
- source: app/globals.css.template
|
|
69
|
+
target: app/globals.css
|
|
70
|
+
phase: foundation
|
|
71
|
+
override: partial
|
|
72
|
+
notes: "Design tokens (CSS custom properties). Accent vars synced from brand source; the calibrated neutral and semantic scales are the designed system, user-editable."
|
|
73
|
+
- source: app/shell.css.template
|
|
74
|
+
target: app/shell.css
|
|
75
|
+
phase: shell
|
|
76
|
+
override: partial
|
|
77
|
+
notes: "BEM styles for the app-shell layer (sidebar, topbar, breadcrumb, theme toggle). References the globals.css tokens; imported once by app/layout.tsx."
|
|
78
|
+
- source: app/layout.tsx.template
|
|
79
|
+
target: app/layout.tsx
|
|
80
|
+
phase: shell
|
|
81
|
+
override: partial
|
|
82
|
+
notes: "Ships the shell + providers + fonts. User fills metadata, analytics, chrome."
|
|
83
|
+
- source: components/data/Chart.tsx.template
|
|
84
|
+
target: components/data/Chart.tsx
|
|
85
|
+
phase: data
|
|
86
|
+
override: none
|
|
87
|
+
notes: "Data-display component (table, stat card, chart). Scaffold-owned."
|
|
88
|
+
- source: components/data/DataTable.tsx.template
|
|
89
|
+
target: components/data/DataTable.tsx
|
|
90
|
+
phase: data
|
|
91
|
+
override: none
|
|
92
|
+
notes: "Data-display component (table, stat card, chart). Scaffold-owned."
|
|
93
|
+
- source: components/data/DataTable.types.ts.template
|
|
94
|
+
target: components/data/DataTable.types.ts
|
|
95
|
+
phase: data
|
|
96
|
+
override: none
|
|
97
|
+
notes: "Data-display component (table, stat card, chart). Scaffold-owned."
|
|
98
|
+
- source: components/data/DataTablePagination.tsx.template
|
|
99
|
+
target: components/data/DataTablePagination.tsx
|
|
100
|
+
phase: data
|
|
101
|
+
override: none
|
|
102
|
+
notes: "Data-display component (table, stat card, chart). Scaffold-owned."
|
|
103
|
+
- source: components/data/SkeletonBlock.tsx.template
|
|
104
|
+
target: components/data/SkeletonBlock.tsx
|
|
105
|
+
phase: data
|
|
106
|
+
override: none
|
|
107
|
+
notes: "Data-display component (table, stat card, chart). Scaffold-owned."
|
|
108
|
+
- source: components/data/StatCard.tsx.template
|
|
109
|
+
target: components/data/StatCard.tsx
|
|
110
|
+
phase: data
|
|
111
|
+
override: none
|
|
112
|
+
notes: "Data-display component (table, stat card, chart). Scaffold-owned."
|
|
113
|
+
- source: components/data/StatCardGrid.tsx.template
|
|
114
|
+
target: components/data/StatCardGrid.tsx
|
|
115
|
+
phase: data
|
|
116
|
+
override: none
|
|
117
|
+
notes: "Data-display component (table, stat card, chart). Scaffold-owned."
|
|
118
|
+
- source: components/feedback/EmptyState.tsx.template
|
|
119
|
+
target: components/feedback/EmptyState.tsx
|
|
120
|
+
phase: feedback
|
|
121
|
+
override: partial
|
|
122
|
+
notes: "Feedback component (empty state). User supplies copy and slots."
|
|
123
|
+
- source: components/interaction/CommandPalette.tsx.template
|
|
124
|
+
target: components/interaction/CommandPalette.tsx
|
|
125
|
+
phase: interaction
|
|
126
|
+
override: none
|
|
127
|
+
notes: "Interaction component (command palette, form fields). Scaffold-owned."
|
|
128
|
+
- source: components/interaction/Field.tsx.template
|
|
129
|
+
target: components/interaction/Field.tsx
|
|
130
|
+
phase: interaction
|
|
131
|
+
override: none
|
|
132
|
+
notes: "Interaction component (command palette, form fields). Scaffold-owned."
|
|
133
|
+
- source: components/interaction/Form.tsx.template
|
|
134
|
+
target: components/interaction/Form.tsx
|
|
135
|
+
phase: interaction
|
|
136
|
+
override: none
|
|
137
|
+
notes: "Interaction component (command palette, form fields). Scaffold-owned."
|
|
138
|
+
- source: components/primitives/Badge.tsx.template
|
|
139
|
+
target: components/primitives/Badge.tsx
|
|
140
|
+
phase: primitives
|
|
141
|
+
override: none
|
|
142
|
+
notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
|
|
143
|
+
- source: components/primitives/Button.tsx.template
|
|
144
|
+
target: components/primitives/Button.tsx
|
|
145
|
+
phase: primitives
|
|
146
|
+
override: none
|
|
147
|
+
notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
|
|
148
|
+
- source: components/primitives/Card.tsx.template
|
|
149
|
+
target: components/primitives/Card.tsx
|
|
150
|
+
phase: primitives
|
|
151
|
+
override: none
|
|
152
|
+
notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
|
|
153
|
+
- source: components/primitives/Input.tsx.template
|
|
154
|
+
target: components/primitives/Input.tsx
|
|
155
|
+
phase: primitives
|
|
156
|
+
override: none
|
|
157
|
+
notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
|
|
158
|
+
- source: components/primitives/Spinner.tsx.template
|
|
159
|
+
target: components/primitives/Spinner.tsx
|
|
160
|
+
phase: primitives
|
|
161
|
+
override: none
|
|
162
|
+
notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
|
|
163
|
+
- source: components/primitives/index.ts.template
|
|
164
|
+
target: components/primitives/index.ts
|
|
165
|
+
phase: primitives
|
|
166
|
+
override: none
|
|
167
|
+
notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
|
|
168
|
+
- source: components/shell/AppShell.tsx.template
|
|
169
|
+
target: components/shell/AppShell.tsx
|
|
170
|
+
phase: shell
|
|
171
|
+
override: none
|
|
172
|
+
notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
|
|
173
|
+
- source: components/shell/Breadcrumb.tsx.template
|
|
174
|
+
target: components/shell/Breadcrumb.tsx
|
|
175
|
+
phase: shell
|
|
176
|
+
override: none
|
|
177
|
+
notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
|
|
178
|
+
- source: components/shell/Container.tsx.template
|
|
179
|
+
target: components/shell/Container.tsx
|
|
180
|
+
phase: foundation
|
|
181
|
+
override: none
|
|
182
|
+
notes: "Single authority for max-width + horizontal padding. Never edit."
|
|
183
|
+
- source: components/shell/NavItem.tsx.template
|
|
184
|
+
target: components/shell/NavItem.tsx
|
|
185
|
+
phase: shell
|
|
186
|
+
override: none
|
|
187
|
+
notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
|
|
188
|
+
- source: components/shell/Sidebar.tsx.template
|
|
189
|
+
target: components/shell/Sidebar.tsx
|
|
190
|
+
phase: shell
|
|
191
|
+
override: none
|
|
192
|
+
notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
|
|
193
|
+
- source: components/shell/SidebarContext.tsx.template
|
|
194
|
+
target: components/shell/SidebarContext.tsx
|
|
195
|
+
phase: shell
|
|
196
|
+
override: none
|
|
197
|
+
notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
|
|
198
|
+
- source: components/shell/ThemeToggle.tsx.template
|
|
199
|
+
target: components/shell/ThemeToggle.tsx
|
|
200
|
+
phase: shell
|
|
201
|
+
override: none
|
|
202
|
+
notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
|
|
203
|
+
- source: components/shell/Topbar.tsx.template
|
|
204
|
+
target: components/shell/Topbar.tsx
|
|
205
|
+
phase: shell
|
|
206
|
+
override: none
|
|
207
|
+
notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
|
|
208
|
+
- source: lib/brand.ts.template
|
|
209
|
+
target: lib/brand.ts
|
|
210
|
+
phase: foundation
|
|
211
|
+
override: full
|
|
212
|
+
notes: "User-owned typed brand tokens. Protected from upgrades."
|
|
213
|
+
|
|
214
|
+
# Principles this scaffold encodes. Violating any breaks the premium guarantees.
|
|
215
|
+
principles:
|
|
216
|
+
- "Tokens over values: every color, size, radius, shadow, and duration referenced in a component file must be a CSS custom property or a typed constant from lib/brand.ts. Raw hex strings, raw pixel numbers, and bare ease keywords are linting violations."
|
|
217
|
+
- "Semantic layering: the neutral scale provides raw steps; the semantic layer (--color-bg-*, --color-text-*, --color-border-*) is what components consume. Adding a new theme requires only overriding the semantic layer, never touching component files."
|
|
218
|
+
- "Container is the sole layout authority: max-width and horizontal page padding exist only in Container.tsx. No other component may set max-width or page-level horizontal padding."
|
|
219
|
+
- "Motion must be purposeful: every transition must specify exactly which property it transitions (never transition:all), an explicit duration token, and an explicit easing token. The easing must match the spatial metaphor: ease-out for entering, ease-in for leaving, ease-in-out for toggling."
|
|
220
|
+
- "Accessibility is structural, not an afterthought: semantic HTML elements (<table>, <nav>, <main>, <dialog>, <label>) are used for their meaning. ARIA attributes supplement but never replace semantic HTML. Focus management (trap in modals, restore on close) is implemented, not skipped."
|
|
221
|
+
- "Reduced-motion is first-class: every animation is authored assuming motion is allowed, then a separate @media (prefers-reduced-motion: reduce) block collapses all durations to 0ms or 80ms and removes transform-based animations. This is done in globals.css, not per-component."
|
|
222
|
+
- "Placeholder is never the only label: every input has a real <label> element. Placeholder text may clarify format but the field is fully understandable without it. The Field primitive enforces this structurally."
|
|
223
|
+
- "Performance budget on animation: only transform and opacity are animated. Width, height, top, left, padding, and margin transitions are forbidden. Layout shift is prevented by reserving space for loading and empty states before content arrives."
|
|
224
|
+
- "Dark palette is designed, not inverted: the dark theme is built from a calibrated neutral scale with its own shadow, surface layering, and reduced-contrast accent values. It is not produced by CSS filter or by simply swapping light and dark values."
|
|
225
|
+
- "Primitives are the contract boundary: Button, Card, Input/Field, and Badge are the shared language across all builders. New components compose primitives; they do not reimplement base patterns. Any change to a primitive propagates correctly to all consumers."
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
"type": "string",
|
|
15
15
|
"description": "Legacy framework-version marker on the session object (distinct from schema_version). Kept for backwards compatibility."
|
|
16
16
|
},
|
|
17
|
+
"model_at_last_audit": {
|
|
18
|
+
"type": ["string", "null"],
|
|
19
|
+
"default": null,
|
|
20
|
+
"description": "Normalized active_model recorded when /chati-update last completed. Article XXIV: when active_model differs from this, the orchestrator advises a harness re-audit. The advisory is driven entirely by this comparison; there is no separate flag."
|
|
21
|
+
},
|
|
17
22
|
"mode": {
|
|
18
23
|
"enum": ["discover", "plan", "build", "validate", "deploy", "completed"],
|
|
19
24
|
"default": "discover",
|
|
@@ -66,6 +66,15 @@
|
|
|
66
66
|
"completed_at": {
|
|
67
67
|
"type": ["string", "null"],
|
|
68
68
|
"format": "date-time"
|
|
69
|
+
},
|
|
70
|
+
"execution_kind": {
|
|
71
|
+
"enum": ["agent", "script", "specialist", "human"],
|
|
72
|
+
"default": "agent",
|
|
73
|
+
"description": "How this task executes. 'agent' (default): an LLM agent implements it. 'script': a deterministic zero-LLM executor runs it (see execution_ref). 'specialist': an agent carrying an embedded methodology. 'human': a human decision gate. Omitting the field means 'agent', so existing tasks are unaffected."
|
|
74
|
+
},
|
|
75
|
+
"execution_ref": {
|
|
76
|
+
"type": ["string", "null"],
|
|
77
|
+
"description": "Resolves the executor for non-agent kinds. For 'script': an executor id from chati.dev/executors/registry.yaml, optionally with a colon-suffixed argument (e.g. 'npm-script:lint'). For 'specialist': the methodology id. For 'human': a short description of the decision required. Null or omitted for 'agent'."
|
|
69
78
|
}
|
|
70
79
|
}
|
|
71
80
|
}
|
|
@@ -92,6 +92,43 @@ export function computeReducedMotionViolations(report, reducedMotionMode, primar
|
|
|
92
92
|
}));
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Spring-motion veto: derive visual errors from each page's motion_quality scan.
|
|
97
|
+
* Linear easing on a state transition and transition-property: all are amateur
|
|
98
|
+
* motion tells. ERROR severity so the qa-visual gate factors them into APPROVED
|
|
99
|
+
* (routed to dev via Fault Vector Protocol); not a hard crash.
|
|
100
|
+
*
|
|
101
|
+
* @param {{pages: Array<{path:string, js_checks?:object}>}} report
|
|
102
|
+
* @returns {Array<{severity:string, type:string, page:string, detail:string, samples:object[]}>}
|
|
103
|
+
*/
|
|
104
|
+
export function computeMotionErrors(report) {
|
|
105
|
+
const pages = Array.isArray(report?.pages) ? report.pages : [];
|
|
106
|
+
const errors = [];
|
|
107
|
+
for (const p of pages) {
|
|
108
|
+
const m = p?.js_checks?.motion_quality;
|
|
109
|
+
if (!m) continue;
|
|
110
|
+
if (m.transition_all > 0) {
|
|
111
|
+
errors.push({
|
|
112
|
+
severity: 'error',
|
|
113
|
+
type: 'transition_all',
|
|
114
|
+
page: p.path,
|
|
115
|
+
detail: `${m.transition_all} visible element(s) use transition-property: all, which animates layout properties and janks. Transition specific compositor properties (transform, opacity) instead.`,
|
|
116
|
+
samples: (m.samples || []).filter(s => s.issue && s.issue.includes('all')).slice(0, 3),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (m.linear_transitions > 0) {
|
|
120
|
+
errors.push({
|
|
121
|
+
severity: 'error',
|
|
122
|
+
type: 'linear_easing',
|
|
123
|
+
page: p.path,
|
|
124
|
+
detail: `${m.linear_transitions} visible element(s) use linear easing on a state transition, which feels robotic. Use ease-out, a cubic-bezier, or a spring.`,
|
|
125
|
+
samples: (m.samples || []).filter(s => s.issue && s.issue.includes('linear')).slice(0, 3),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return errors;
|
|
130
|
+
}
|
|
131
|
+
|
|
95
132
|
// ---------------------------------------------------------------------------
|
|
96
133
|
// Args
|
|
97
134
|
// ---------------------------------------------------------------------------
|
|
@@ -551,6 +588,45 @@ async function main() {
|
|
|
551
588
|
}
|
|
552
589
|
checks.custom_properties_count = count;
|
|
553
590
|
|
|
591
|
+
// Motion quality (spring-motion veto). Premium motion uses spring or
|
|
592
|
+
// cubic-bezier easing on specific compositor properties. Linear easing
|
|
593
|
+
// on a state transition feels robotic, and transition-property: all
|
|
594
|
+
// animates layout and janks. Both are strong amateur-motion tells. Scan
|
|
595
|
+
// visible elements that actually declare a transition.
|
|
596
|
+
// Linear easing is a robotic tell for discrete state transitions
|
|
597
|
+
// (transform, opacity, color), but it is the correct, physical choice for
|
|
598
|
+
// continuous or progress motion (a progress bar width, an SVG stroke
|
|
599
|
+
// draw, a parallax offset). Exempt those properties, plus an explicit
|
|
600
|
+
// data-linear-ok opt-out, so a legitimate loader is never falsely flagged.
|
|
601
|
+
const SAFE_LINEAR_PROPS = ['width', 'height', 'max-width', 'max-height', 'min-width', 'min-height', 'background-position', 'background-size', 'stroke-dashoffset', 'stroke-dasharray', 'clip-path', 'left', 'right', 'top', 'bottom'];
|
|
602
|
+
const motion = { linear_transitions: 0, transition_all: 0, samples: [] };
|
|
603
|
+
for (const el of document.querySelectorAll('body *')) {
|
|
604
|
+
const cs = getComputedStyle(el);
|
|
605
|
+
const dur = cs.transitionDuration || '0s';
|
|
606
|
+
if (!dur.split(',').some(d => parseFloat(d) > 0)) continue; // no real transition
|
|
607
|
+
const rect = el.getBoundingClientRect();
|
|
608
|
+
if (rect.width < 4 || rect.height < 4) continue; // not visible
|
|
609
|
+
const prop = (cs.transitionProperty || '').split(',').map(s => s.trim());
|
|
610
|
+
const tf = cs.transitionTimingFunction || '';
|
|
611
|
+
let issue = null;
|
|
612
|
+
if (prop.includes('all')) { motion.transition_all++; issue = 'transition-property: all'; }
|
|
613
|
+
else if (/\blinear\b(?!\s*\()/.test(tf)) {
|
|
614
|
+
const allSafe = prop.length > 0 && prop.every(p => SAFE_LINEAR_PROPS.includes(p));
|
|
615
|
+
if (!allSafe && !el.hasAttribute('data-linear-ok')) { motion.linear_transitions++; issue = 'linear easing'; }
|
|
616
|
+
}
|
|
617
|
+
if (issue && motion.samples.length < 8) {
|
|
618
|
+
motion.samples.push({
|
|
619
|
+
tag: el.tagName.toLowerCase(),
|
|
620
|
+
cls: [...el.classList].slice(0, 4).join(' '),
|
|
621
|
+
issue,
|
|
622
|
+
timing: tf,
|
|
623
|
+
property: cs.transitionProperty,
|
|
624
|
+
duration: dur,
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
checks.motion_quality = motion;
|
|
629
|
+
|
|
554
630
|
// 3D scaffold signals (motion-premium-3d workstream P7). Detects
|
|
555
631
|
// whether the page rendered a Canvas or fell back to SceneFallback.
|
|
556
632
|
// The data-* attributes come from the CanvasProvider + SceneFallback
|
|
@@ -622,6 +698,7 @@ async function main() {
|
|
|
622
698
|
const reducedMotionViolations = computeReducedMotionViolations(
|
|
623
699
|
report, reducedMotionMode, viewports[0]
|
|
624
700
|
);
|
|
701
|
+
const motionErrors = computeMotionErrors(report);
|
|
625
702
|
|
|
626
703
|
report.summary = {
|
|
627
704
|
total_pages: report.pages.length,
|
|
@@ -642,6 +719,8 @@ async function main() {
|
|
|
642
719
|
viewport_profiles: viewports.map(v => v.checkKey),
|
|
643
720
|
layout_errors: allLayoutErrors,
|
|
644
721
|
layout_error_count: allLayoutErrors.filter(e => e.severity === 'error').length,
|
|
722
|
+
motion_errors: motionErrors,
|
|
723
|
+
motion_error_count: motionErrors.length,
|
|
645
724
|
};
|
|
646
725
|
|
|
647
726
|
// 6. Write report
|
|
@@ -660,7 +739,14 @@ async function main() {
|
|
|
660
739
|
}
|
|
661
740
|
}
|
|
662
741
|
|
|
663
|
-
if (
|
|
742
|
+
if (report.summary.motion_error_count > 0) {
|
|
743
|
+
console.log(`\nMotion errors (spring-motion veto): ${report.summary.motion_error_count}`);
|
|
744
|
+
for (const err of report.summary.motion_errors.slice(0, 6)) {
|
|
745
|
+
console.log(` [${err.type}] ${err.page || ''}: ${err.detail}`);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (!report.summary.lenis_active_all || !report.summary.gsap_loaded_all || report.summary.em_dashes_detected || report.summary.layout_error_count > 0 || report.summary.motion_error_count > 0) {
|
|
664
750
|
exitCode = 1;
|
|
665
751
|
}
|
|
666
752
|
|
|
@@ -29,7 +29,7 @@ Validate the chati.dev framework installation, check system dependencies, verify
|
|
|
29
29
|
|
|
30
30
|
### 1. Check Core Framework Files
|
|
31
31
|
Verify essential framework files exist and are valid:
|
|
32
|
-
- `chati.dev/constitution.md` (Article I through
|
|
32
|
+
- `chati.dev/constitution.md` (Article I through XXV)
|
|
33
33
|
- `chati.dev/config.yaml` (framework configuration)
|
|
34
34
|
- `chati.dev/installer/install.js` (installer script)
|
|
35
35
|
- `.chati/` directory structure
|
|
@@ -192,7 +192,7 @@ health_report:
|
|
|
192
192
|
- file: "chati.dev/constitution.md"
|
|
193
193
|
status: "ok"
|
|
194
194
|
size_kb: 45
|
|
195
|
-
articles_count:
|
|
195
|
+
articles_count: 25
|
|
196
196
|
- file: "chati.dev/config.yaml"
|
|
197
197
|
status: "ok"
|
|
198
198
|
valid_yaml: true
|
|
@@ -280,7 +280,7 @@ health_report:
|
|
|
280
280
|
|
|
281
281
|
constitution_validation:
|
|
282
282
|
status: "healthy"
|
|
283
|
-
articles_present:
|
|
283
|
+
articles_present: 25
|
|
284
284
|
article_xi_valid: true
|
|
285
285
|
mode_definitions: ["planning", "build", "deploy"]
|
|
286
286
|
transition_rules_defined: true
|
|
@@ -308,7 +308,7 @@ health_report:
|
|
|
308
308
|
✓ Framework Health: HEALTHY
|
|
309
309
|
|
|
310
310
|
All core components validated successfully:
|
|
311
|
-
- Constitution with
|
|
311
|
+
- Constitution with 25 articles
|
|
312
312
|
- 12 agent definitions
|
|
313
313
|
- 35 task definitions
|
|
314
314
|
- 8 schema files
|
|
@@ -62,11 +62,17 @@ Issue the final QA verdict by synthesizing all QA implementation results (tests,
|
|
|
62
62
|
- Document gate outcome with rationale
|
|
63
63
|
|
|
64
64
|
6. **Calculate Overall Quality Score**
|
|
65
|
-
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
- Use the canonical weighted scoring table from `docs/architecture/quality-gates.md` (single source of truth). Weights:
|
|
66
|
+
- **Tests**: 0.20
|
|
67
|
+
- **Security (SAST)**: 0.20
|
|
68
|
+
- **Adversarial Review**: 0.15
|
|
69
|
+
- **Visual Review**: 0.15
|
|
70
|
+
- **Code Quality**: 0.10
|
|
71
|
+
- **Coverage**: 0.10
|
|
72
|
+
- **Acceptance Criteria**: 0.10
|
|
73
|
+
- Each dimension is scored 0-100; the weighted sum is the overall score (0-100).
|
|
74
|
+
- Verdict thresholds: **>= 95%** APPROVED | **90–94%** NEEDS_REVISION | **< 90%** BLOCKED.
|
|
75
|
+
- Note: the legacy 4-gate 25-point equal-weight table (Tests/SAST/Regressions/Performance = 25/25/25/25) is DEPRECATED — `qa-gate-tmpl.yaml` and `docs/architecture/quality-gates.md` both use the weighted scheme above.
|
|
70
76
|
|
|
71
77
|
7. **Apply Gate Logic**
|
|
72
78
|
- **ALL gates PASS**: Overall verdict = PASS
|
|
@@ -46,28 +46,41 @@ sections:
|
|
|
46
46
|
description: "Each agent defined rigorous, binary criteria"
|
|
47
47
|
penalty_on_fail: -10
|
|
48
48
|
|
|
49
|
+
# Implementation gate weights — single source of truth:
|
|
50
|
+
# `docs/architecture/quality-gates.md` § Weighted Scoring. The legacy 30/20/25/15/10
|
|
51
|
+
# (Test/Coverage/SAST/Review/AC) table was deprecated 2026-05; consumers
|
|
52
|
+
# SHALL use the 7-dimension table below. Verdict thresholds:
|
|
53
|
+
# >= 95% APPROVED | 90-94% NEEDS_REVISION | < 90% BLOCKED.
|
|
49
54
|
- id: implementation_gate
|
|
50
55
|
applicable_to: implementation
|
|
51
56
|
checks:
|
|
52
|
-
- name: "
|
|
57
|
+
- name: "Tests"
|
|
53
58
|
description: "All tests pass"
|
|
54
|
-
weight: 0.30
|
|
55
|
-
threshold: "100% pass rate"
|
|
56
|
-
|
|
57
|
-
- name: "Code Coverage"
|
|
58
|
-
description: "Line and branch coverage"
|
|
59
59
|
weight: 0.20
|
|
60
|
-
threshold: "
|
|
60
|
+
threshold: "100% pass rate"
|
|
61
61
|
|
|
62
|
-
- name: "Security
|
|
62
|
+
- name: "Security (SAST)"
|
|
63
63
|
description: "No critical or high vulnerabilities"
|
|
64
|
-
weight: 0.
|
|
64
|
+
weight: 0.20
|
|
65
65
|
threshold: "0 critical, 0 high"
|
|
66
66
|
|
|
67
|
-
- name: "
|
|
68
|
-
description: "
|
|
67
|
+
- name: "Adversarial Review"
|
|
68
|
+
description: "Devil's-advocate cross-review of risky changes"
|
|
69
|
+
weight: 0.15
|
|
70
|
+
|
|
71
|
+
- name: "Visual Review"
|
|
72
|
+
description: "Playwright screenshots + brandbook token compliance"
|
|
69
73
|
weight: 0.15
|
|
70
74
|
|
|
75
|
+
- name: "Code Quality"
|
|
76
|
+
description: "Architecture adherence, patterns, style"
|
|
77
|
+
weight: 0.10
|
|
78
|
+
|
|
79
|
+
- name: "Coverage"
|
|
80
|
+
description: "Line and branch coverage"
|
|
81
|
+
weight: 0.10
|
|
82
|
+
threshold: ">= 80%"
|
|
83
|
+
|
|
71
84
|
- name: "Acceptance Criteria"
|
|
72
85
|
description: "All Given-When-Then criteria verified"
|
|
73
86
|
weight: 0.10
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chati-dev",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "AI-Powered Multi-Agent Orchestration System - Structured vibe coding for Full Stack Development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
"main": "src/wizard/index.js",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": "./src/wizard/index.js",
|
|
13
|
-
"./api": "./src/api/index.js",
|
|
14
13
|
"./installer": "./src/installer/core.js",
|
|
15
14
|
"./dashboard": "./src/dashboard/renderer.js",
|
|
16
15
|
"./upgrade": "./src/upgrade/checker.js"
|
|
@@ -33,7 +32,8 @@
|
|
|
33
32
|
"test": "node --test test/**/*.test.js",
|
|
34
33
|
"lint": "eslint src/ bin/",
|
|
35
34
|
"lint:fix": "eslint src/ bin/ --fix",
|
|
36
|
-
"verify-v431": "npm test && node scripts/scan-stale.js && npm run sync && node scripts/validate-package.js && node test/fixtures/manual-smoke-v430-upgrade.mjs"
|
|
35
|
+
"verify-v431": "npm test && node scripts/scan-stale.js && npm run sync && node scripts/validate-package.js && node test/fixtures/manual-smoke-v430-upgrade.mjs",
|
|
36
|
+
"smoke:scaffold-build": "node test/fixtures/manual-smoke-scaffold-build.mjs"
|
|
37
37
|
},
|
|
38
38
|
"keywords": [
|
|
39
39
|
"ai",
|
|
@@ -72,12 +72,6 @@ function buildCodexReplacements(frameworkDir = 'chati.dev') {
|
|
|
72
72
|
];
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
/**
|
|
76
|
-
* Text replacements for Codex CLI context file (legacy constant using default 'chati.dev/' prefix).
|
|
77
|
-
* @deprecated Use buildCodexReplacements(frameworkDir) for correct path resolution.
|
|
78
|
-
*/
|
|
79
|
-
const CODEX_REPLACEMENTS = buildCodexReplacements();
|
|
80
|
-
|
|
81
75
|
// ---------------------------------------------------------------------------
|
|
82
76
|
// Generators
|
|
83
77
|
// ---------------------------------------------------------------------------
|
|
@@ -69,39 +69,3 @@ export async function renderDashboardWatch(targetDir, intervalMs = 5000) {
|
|
|
69
69
|
|
|
70
70
|
return timer;
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Render plain text fallback (for terminals without TUI support)
|
|
75
|
-
*/
|
|
76
|
-
export async function renderPlainDashboard(targetDir) {
|
|
77
|
-
const data = await readDashboardData(targetDir);
|
|
78
|
-
|
|
79
|
-
if (!data.session) {
|
|
80
|
-
console.log('No chati.dev session found. Run `npx chati-dev init` first.');
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const session = data.session;
|
|
85
|
-
const project = session.project || {};
|
|
86
|
-
|
|
87
|
-
console.log();
|
|
88
|
-
console.log('=== chati.dev Dashboard ===');
|
|
89
|
-
console.log();
|
|
90
|
-
console.log(`Project: ${project.name || 'unknown'}`);
|
|
91
|
-
console.log(`Type: ${project.type || 'unknown'}`);
|
|
92
|
-
console.log(`Phase: ${project.state || 'unknown'}`);
|
|
93
|
-
console.log(`Mode: ${session.execution_mode || 'interactive'}`);
|
|
94
|
-
console.log(`Language: ${session.language || 'en'}`);
|
|
95
|
-
console.log();
|
|
96
|
-
|
|
97
|
-
console.log('--- Agent Scores ---');
|
|
98
|
-
for (const [name, info] of Object.entries(data.agentScores)) {
|
|
99
|
-
const status = info.status === 'pending' ? '--' : info.status === 'in_progress' ? '...' : String(info.score);
|
|
100
|
-
console.log(` ${name.padEnd(20)} ${status}`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
console.log();
|
|
104
|
-
console.log(`Blockers: ${data.blockers.length || 'None'}`);
|
|
105
|
-
console.log(`Gotchas: ${data.gotchas.length} patterns`);
|
|
106
|
-
console.log();
|
|
107
|
-
}
|