chati-dev 4.3.1 → 4.4.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 (158) hide show
  1. package/README.md +18 -13
  2. package/bin/chati.js +28 -4
  3. package/framework/agents/build/dev.md +5 -1
  4. package/framework/agents/discover/greenfield-wu.md +16 -1
  5. package/framework/agents/plan/tasks.md +31 -0
  6. package/framework/agents/plan/ux-brand-architect.md +21 -2
  7. package/framework/agents/plan/ux-component-engineer.md +10 -0
  8. package/framework/agents/quality/qa-implementation.md +1 -1
  9. package/framework/agents/quality/qa-planning.md +1 -1
  10. package/framework/agents/quality/qa-visual.md +24 -21
  11. package/framework/config.yaml +5 -4
  12. package/framework/constitution.md +60 -11
  13. package/framework/context/governance.md +12 -10
  14. package/framework/context/root.md +2 -2
  15. package/framework/data/entity-registry.yaml +12 -4
  16. package/framework/data/qa-rubrics.yaml +335 -0
  17. package/framework/domains/constitution.yaml +3 -3
  18. package/framework/executors/json-validate.js +80 -0
  19. package/framework/executors/npm-script.js +72 -0
  20. package/framework/executors/path-check.js +67 -0
  21. package/framework/executors/registry.yaml +36 -0
  22. package/framework/hooks/advance-trigger.js +47 -3
  23. package/framework/hooks/constitution-guard.js +9 -4
  24. package/framework/hooks/git-push-authority.js +113 -0
  25. package/framework/hooks/license-guard.js +59 -9
  26. package/framework/hooks/model-governance.js +40 -17
  27. package/framework/hooks/prism-engine.js +78 -11
  28. package/framework/hooks/session-digest.js +12 -3
  29. package/framework/hooks/settings.json +7 -3
  30. package/framework/hooks/style-guard.js +52 -3
  31. package/framework/hooks/team-quality-gate.js +43 -5
  32. package/framework/i18n/en.yaml +3 -3
  33. package/framework/i18n/es.yaml +3 -3
  34. package/framework/i18n/fr.yaml +3 -3
  35. package/framework/i18n/pt.yaml +3 -3
  36. package/framework/intelligence/confidence.yaml +85 -6
  37. package/framework/intelligence/context-engine.md +9 -5
  38. package/framework/intelligence/decision-engine.md +1 -1
  39. package/framework/manifest.json +1351 -0
  40. package/framework/manifest.sig +1 -0
  41. package/framework/orchestrator/chati-router.js +1 -1
  42. package/framework/orchestrator/chati-update.md +19 -3
  43. package/framework/orchestrator/chati.md +24 -3
  44. package/framework/quality-gates/planning-gate.md +2 -0
  45. package/framework/scaffold/motion-premium/scaffold.yaml +2 -1
  46. package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
  47. package/framework/scaffold/saas-dashboard/README.md +58 -0
  48. package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
  49. package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
  50. package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
  51. package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
  52. package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
  53. package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
  54. package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
  55. package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
  56. package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
  57. package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
  58. package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
  59. package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
  60. package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
  61. package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
  62. package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
  63. package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
  64. package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
  65. package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
  66. package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
  67. package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
  68. package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
  69. package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
  70. package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
  71. package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
  72. package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
  73. package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
  74. package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
  75. package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
  76. package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
  77. package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
  78. package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
  79. package/framework/schemas/session.schema.json +5 -0
  80. package/framework/schemas/task.schema.json +9 -0
  81. package/framework/scripts/visual-qa.js +87 -1
  82. package/framework/tasks/orchestrator-health.md +4 -4
  83. package/framework/tasks/qa-impl-verdict.md +11 -5
  84. package/framework/templates/qa-gate-tmpl.yaml +24 -11
  85. package/package.json +4 -4
  86. package/src/config/claude-settings-generator.js +9 -6
  87. package/src/config/context-file-generator.js +0 -6
  88. package/src/dashboard/renderer.js +0 -36
  89. package/src/executors/runner.js +204 -0
  90. package/src/installer/core.js +35 -4
  91. package/src/installer/manifest.js +30 -4
  92. package/src/installer/signing-public-key.pem +1 -1
  93. package/src/installer/templates.js +5 -6
  94. package/src/installer/validator.js +2 -1
  95. package/src/intelligence/registry-manager.js +3 -2
  96. package/src/license/client.js +9 -3
  97. package/src/license/commands.js +12 -2
  98. package/src/license/machine-id.js +42 -1
  99. package/src/memory/gotchas.js +58 -40
  100. package/src/memory/magic-docs.js +7 -2
  101. package/src/memory/session-digest.js +9 -4
  102. package/src/orchestrator/cli.js +195 -23
  103. package/src/orchestrator/deviation-handler.js +5 -3
  104. package/src/orchestrator/doctor.js +98 -16
  105. package/src/orchestrator/pipeline-manager.js +44 -22
  106. package/src/orchestrator/session-manager.js +56 -8
  107. package/src/telemetry/sender.js +7 -19
  108. package/src/terminal/run-parallel.js +14 -14
  109. package/src/terminal/run-team.js +3 -3
  110. package/src/upgrade/backup.js +22 -44
  111. package/src/upgrade/migrator.js +51 -12
  112. package/src/upgrade/tracked-files-detector.js +34 -16
  113. package/src/utils/constitution-meta.js +12 -0
  114. package/src/utils/feature-flags.js +26 -2
  115. package/src/utils/flatten-entities.js +4 -40
  116. package/src/utils/schema-validator.js +0 -14
  117. package/src/wizard/i18n.js +3 -3
  118. package/src/api/index.js +0 -120
  119. package/src/autonomy/autonomous-gate.js +0 -294
  120. package/src/autonomy/build-loop.js +0 -281
  121. package/src/autonomy/build-state.js +0 -286
  122. package/src/autonomy/cause-analyzer.js +0 -177
  123. package/src/autonomy/escalation.js +0 -214
  124. package/src/autonomy/index.js +0 -51
  125. package/src/autonomy/mode-manager.js +0 -225
  126. package/src/autonomy/mode-suggester.js +0 -283
  127. package/src/autonomy/progress-reporter.js +0 -275
  128. package/src/autonomy/safety-net.js +0 -370
  129. package/src/config/agent-customizer.js +0 -231
  130. package/src/decision/analyzer.js +0 -291
  131. package/src/decision/engine.js +0 -250
  132. package/src/decision/index.js +0 -38
  133. package/src/decision/registry-healer.js +0 -468
  134. package/src/decision/registry-updater.js +0 -339
  135. package/src/extensions/loader.js +0 -145
  136. package/src/extensions/registry.js +0 -134
  137. package/src/gates/circuit-breaker.js +0 -151
  138. package/src/gates/g1-planning-complete.js +0 -154
  139. package/src/gates/g2-qa-planning.js +0 -156
  140. package/src/gates/g3-implementation.js +0 -215
  141. package/src/gates/g4-qa-implementation.js +0 -240
  142. package/src/gates/g5-deploy-ready.js +0 -181
  143. package/src/gates/gate-base.js +0 -185
  144. package/src/gates/index.js +0 -46
  145. package/src/health/auto-fix.js +0 -216
  146. package/src/health/engine.js +0 -246
  147. package/src/merger/semantic-merger.js +0 -292
  148. package/src/preview/detector.js +0 -238
  149. package/src/preview/index.js +0 -20
  150. package/src/preview/launcher.js +0 -235
  151. package/src/preview/log-buffer.js +0 -103
  152. package/src/quality/metrics-collector.js +0 -281
  153. package/src/quality/test-runner.js +0 -366
  154. package/src/tasks/executor.js +0 -195
  155. package/src/tasks/index.js +0 -4
  156. package/src/tasks/loader.js +0 -210
  157. package/src/tasks/router.js +0 -182
  158. package/src/utils/event-bus.js +0 -126
@@ -0,0 +1,351 @@
1
+ /**
2
+ * components/interaction/Field.tsx
3
+ * SaaS Dashboard Preset -- D_interaction phase
4
+ *
5
+ * WHY THIS EXISTS
6
+ * ---------------
7
+ * The Field primitive is the accessibility contract boundary for every input
8
+ * in the dashboard. Two failure modes plague dashboard forms:
9
+ *
10
+ * 1. Placeholder-only labels: placeholder disappears on focus, leaving
11
+ * users with short-term memory limitations (or filling multiple fields
12
+ * rapidly) unable to recall what a field is for. WCAG 1.3.1 requires
13
+ * programmatic labels. This component makes it structurally impossible
14
+ * to render an input without a <label>.
15
+ *
16
+ * 2. Error announced too late: error text that appears only near the
17
+ * submit button is not announced to screen reader users focused inside
18
+ * the form. The `role="alert"` on the error message here fires
19
+ * immediately when error text appears, regardless of focus position.
20
+ *
21
+ * ARCHITECTURE DECISIONS
22
+ * ----------------------
23
+ * 1. Field is the composition root; it renders the <label>, hint, and error.
24
+ * The <Input> sub-component handles only the input element itself.
25
+ * This separation means the Field wrapper can be reused with <textarea>
26
+ * or <select> by passing `as="textarea"` / `as="select"`, without
27
+ * duplicating label/hint/error logic.
28
+ *
29
+ * 2. `labelHidden` prop renders the label text inside a `.sr-only` span
30
+ * so visually minimal forms (e.g., inline search) still have SR labels.
31
+ * The label element is NEVER removed from the DOM.
32
+ *
33
+ * 3. Icon slots use absolute positioning within a `position:relative` wrapper.
34
+ * The input's padding-left / padding-right adjusts via inline style when
35
+ * icons are present. This avoids flexbox-inside-input hacks and keeps
36
+ * the input text baseline aligned regardless of icon presence.
37
+ *
38
+ * 4. The `required` prop adds an asterisk in the label AND sets
39
+ * `aria-required="true"` on the input. Both are needed: the asterisk
40
+ * is a visual convention; aria-required communicates to SR users who
41
+ * may not see the asterisk.
42
+ *
43
+ * 5. Focus ring: implemented globally via `:focus-visible` in globals.css.
44
+ * The input itself does NOT set outline -- it relies on the global rule,
45
+ * which applies the --shadow-focus token that includes a 2px ring with
46
+ * 2px offset.
47
+ *
48
+ * STATE TRANSITIONS
49
+ * -----------------
50
+ * resting -> border: var(--color-border-default)
51
+ * focus -> border: var(--color-border-emphasis); transition duration-normal
52
+ * error -> border: var(--color-danger); bg: var(--color-danger-subtle) tint
53
+ * disabled -> opacity 0.5; cursor: not-allowed
54
+ *
55
+ * TOKEN USAGE
56
+ * -----------
57
+ * All properties reference CSS custom properties from globals.css.
58
+ * No raw hex values, no raw pixel literals.
59
+ */
60
+
61
+ 'use client';
62
+
63
+ import React, {
64
+ forwardRef,
65
+ useId,
66
+ type InputHTMLAttributes,
67
+ type TextareaHTMLAttributes,
68
+ type SelectHTMLAttributes,
69
+ type ReactNode,
70
+ } from 'react';
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // Types
74
+ // ---------------------------------------------------------------------------
75
+
76
+ type InputAs = 'input' | 'textarea' | 'select';
77
+
78
+ export interface FieldProps {
79
+ /** Always rendered as a real <label>. Never omitted. */
80
+ label: string;
81
+ /** Hint text below the input; linked via aria-describedby. */
82
+ hint?: string;
83
+ /** Error message. Overrides hint. Sets aria-invalid and role=alert. */
84
+ error?: string;
85
+ /** Visually hides the label but keeps it in the DOM for screen readers. */
86
+ labelHidden?: boolean;
87
+ /** Lucide icon rendered inside the input on the left. */
88
+ iconLeft?: ReactNode;
89
+ /** Lucide icon or button rendered inside the input on the right. */
90
+ iconRight?: ReactNode;
91
+ /** Adds asterisk and aria-required. */
92
+ required?: boolean;
93
+ /** Element to render. Default: 'input'. */
94
+ as?: InputAs;
95
+ /** Passed to underlying input element. */
96
+ inputProps?: InputHTMLAttributes<HTMLInputElement>;
97
+ /** Passed when as='textarea'. */
98
+ textareaProps?: TextareaHTMLAttributes<HTMLTextAreaElement>;
99
+ /** Passed when as='select'. */
100
+ selectProps?: SelectHTMLAttributes<HTMLSelectElement>;
101
+ /** Children for select options when as='select'. */
102
+ children?: ReactNode;
103
+ /** Additional class on the field wrapper. */
104
+ className?: string;
105
+ }
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // Shared input styles (CSS-in-JS-style object used across all variants)
109
+ // ---------------------------------------------------------------------------
110
+
111
+ function buildInputStyle({
112
+ hasError,
113
+ isDisabled,
114
+ iconLeftPresent,
115
+ iconRightPresent,
116
+ }: {
117
+ hasError: boolean;
118
+ isDisabled: boolean;
119
+ iconLeftPresent: boolean;
120
+ iconRightPresent: boolean;
121
+ }): React.CSSProperties {
122
+ return {
123
+ display: 'block',
124
+ width: '100%',
125
+ minHeight: '40px',
126
+ paddingTop: 'var(--spacing-input-pad-v)',
127
+ paddingBottom: 'var(--spacing-input-pad-v)',
128
+ paddingLeft: iconLeftPresent ? '36px' : 'var(--spacing-input-pad-h)',
129
+ paddingRight: iconRightPresent ? '36px' : 'var(--spacing-input-pad-h)',
130
+ backgroundColor: 'var(--color-bg-sunken)',
131
+ color: hasError ? 'var(--color-text-primary)' : 'var(--color-text-primary)',
132
+ fontSize: 'var(--type-body)',
133
+ lineHeight: 'var(--type-body-lh)',
134
+ fontFamily: 'var(--font-sans)',
135
+ borderRadius: 'var(--radius-default)',
136
+ border: hasError
137
+ ? '1px solid var(--color-danger)'
138
+ : '1px solid var(--color-border-default)',
139
+ outline: 'none',
140
+ opacity: isDisabled ? 0.5 : 1,
141
+ cursor: isDisabled ? 'not-allowed' : 'text',
142
+ transition: `border-color var(--duration-normal) var(--ease-in-out)`,
143
+ // Focus border via CSS :focus-visible in globals.css (:focus-visible + border-color)
144
+ };
145
+ }
146
+
147
+ // ---------------------------------------------------------------------------
148
+ // Icon slot helper
149
+ // ---------------------------------------------------------------------------
150
+
151
+ function IconSlot({
152
+ side,
153
+ children,
154
+ }: {
155
+ side: 'left' | 'right';
156
+ children: ReactNode;
157
+ }) {
158
+ return (
159
+ <span
160
+ aria-hidden="true"
161
+ style={{
162
+ position: 'absolute',
163
+ top: '50%',
164
+ transform: 'translateY(-50%)',
165
+ [side === 'left' ? 'left' : 'right']: '10px',
166
+ display: 'flex',
167
+ alignItems: 'center',
168
+ justifyContent: 'center',
169
+ color: 'var(--color-text-muted)',
170
+ pointerEvents: 'none',
171
+ zIndex: 1,
172
+ }}
173
+ >
174
+ {children}
175
+ </span>
176
+ );
177
+ }
178
+
179
+ // ---------------------------------------------------------------------------
180
+ // Field component
181
+ // ---------------------------------------------------------------------------
182
+
183
+ export const Field = forwardRef<HTMLDivElement, FieldProps>(
184
+ function Field(
185
+ {
186
+ label,
187
+ hint,
188
+ error,
189
+ labelHidden = false,
190
+ iconLeft,
191
+ iconRight,
192
+ required = false,
193
+ as: As = 'input',
194
+ inputProps,
195
+ textareaProps,
196
+ selectProps,
197
+ children,
198
+ className,
199
+ },
200
+ ref,
201
+ ) {
202
+ const inputId = useId();
203
+ const hintId = useId();
204
+ const errorId = useId();
205
+
206
+ const hasError = Boolean(error);
207
+ const isDisabled =
208
+ As === 'input'
209
+ ? Boolean(inputProps?.disabled)
210
+ : As === 'textarea'
211
+ ? Boolean(textareaProps?.disabled)
212
+ : Boolean(selectProps?.disabled);
213
+
214
+ // aria-describedby links input to hint or error message
215
+ const describedBy = hasError ? errorId : hint ? hintId : undefined;
216
+
217
+ const inputStyle = buildInputStyle({
218
+ hasError,
219
+ isDisabled,
220
+ iconLeftPresent: Boolean(iconLeft),
221
+ iconRightPresent: Boolean(iconRight),
222
+ });
223
+
224
+ return (
225
+ <div
226
+ ref={ref}
227
+ className={className}
228
+ style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-2)' }}
229
+ >
230
+ {/* Label */}
231
+ <label
232
+ htmlFor={inputId}
233
+ style={{
234
+ display: 'flex',
235
+ alignItems: 'center',
236
+ gap: 'var(--space-1)',
237
+ fontSize: 'var(--type-small)',
238
+ lineHeight: 'var(--type-small-lh)',
239
+ fontWeight: 500,
240
+ color: 'var(--color-text-primary)',
241
+ }}
242
+ >
243
+ {labelHidden ? (
244
+ <span className="sr-only">{label}</span>
245
+ ) : (
246
+ <span>{label}</span>
247
+ )}
248
+ {required && (
249
+ <span
250
+ aria-hidden="true"
251
+ style={{ color: 'var(--color-danger)', marginLeft: 'var(--space-px)' }}
252
+ >
253
+ *
254
+ </span>
255
+ )}
256
+ </label>
257
+
258
+ {/* Input wrapper (relative for icon slots) */}
259
+ <div style={{ position: 'relative' }}>
260
+ {iconLeft && <IconSlot side="left">{iconLeft}</IconSlot>}
261
+
262
+ {As === 'textarea' ? (
263
+ <textarea
264
+ id={inputId}
265
+ aria-required={required || undefined}
266
+ aria-invalid={hasError || undefined}
267
+ aria-describedby={describedBy}
268
+ disabled={isDisabled}
269
+ {...textareaProps}
270
+ style={{
271
+ ...inputStyle,
272
+ minHeight: '80px',
273
+ resize: 'vertical',
274
+ cursor: isDisabled ? 'not-allowed' : 'auto',
275
+ ...textareaProps?.style,
276
+ }}
277
+ />
278
+ ) : As === 'select' ? (
279
+ <select
280
+ id={inputId}
281
+ aria-required={required || undefined}
282
+ aria-invalid={hasError || undefined}
283
+ aria-describedby={describedBy}
284
+ disabled={isDisabled}
285
+ {...selectProps}
286
+ style={{
287
+ ...inputStyle,
288
+ appearance: 'none',
289
+ cursor: isDisabled ? 'not-allowed' : 'pointer',
290
+ paddingRight: '36px',
291
+ ...selectProps?.style,
292
+ }}
293
+ >
294
+ {children}
295
+ </select>
296
+ ) : (
297
+ <input
298
+ id={inputId}
299
+ aria-required={required || undefined}
300
+ aria-invalid={hasError || undefined}
301
+ aria-describedby={describedBy}
302
+ disabled={isDisabled}
303
+ {...inputProps}
304
+ style={{
305
+ ...inputStyle,
306
+ ...inputProps?.style,
307
+ }}
308
+ />
309
+ )}
310
+
311
+ {iconRight && <IconSlot side="right">{iconRight}</IconSlot>}
312
+ </div>
313
+
314
+ {/* Error message (role=alert for immediate SR announcement) */}
315
+ {hasError && (
316
+ <p
317
+ id={errorId}
318
+ role="alert"
319
+ style={{
320
+ fontSize: 'var(--type-caption)',
321
+ lineHeight: 'var(--type-caption-lh)',
322
+ color: 'var(--color-danger)',
323
+ margin: 0,
324
+ }}
325
+ >
326
+ {error}
327
+ </p>
328
+ )}
329
+
330
+ {/* Hint (shown when no error) */}
331
+ {!hasError && hint && (
332
+ <p
333
+ id={hintId}
334
+ style={{
335
+ fontSize: 'var(--type-caption)',
336
+ lineHeight: 'var(--type-caption-lh)',
337
+ color: 'var(--color-text-muted)',
338
+ margin: 0,
339
+ }}
340
+ >
341
+ {hint}
342
+ </p>
343
+ )}
344
+ </div>
345
+ );
346
+ },
347
+ );
348
+
349
+ Field.displayName = 'Field';
350
+
351
+ export default Field;