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.
Files changed (147) hide show
  1. package/README.md +18 -13
  2. package/bin/chati.js +12 -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 +58 -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/orchestrator/chati-router.js +1 -1
  40. package/framework/orchestrator/chati-update.md +19 -3
  41. package/framework/orchestrator/chati.md +19 -1
  42. package/framework/quality-gates/planning-gate.md +2 -0
  43. package/framework/scaffold/motion-premium/scaffold.yaml +2 -1
  44. package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
  45. package/framework/scaffold/saas-dashboard/README.md +58 -0
  46. package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
  47. package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
  48. package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
  49. package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
  50. package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
  51. package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
  52. package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
  53. package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
  54. package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
  55. package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
  56. package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
  57. package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
  58. package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
  59. package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
  60. package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
  61. package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
  62. package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
  63. package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
  64. package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
  65. package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
  66. package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
  67. package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
  68. package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
  69. package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
  70. package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
  71. package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
  72. package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
  73. package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
  74. package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
  75. package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
  76. package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
  77. package/framework/schemas/session.schema.json +5 -0
  78. package/framework/schemas/task.schema.json +9 -0
  79. package/framework/scripts/visual-qa.js +87 -1
  80. package/framework/tasks/orchestrator-health.md +4 -4
  81. package/framework/tasks/qa-impl-verdict.md +11 -5
  82. package/framework/templates/qa-gate-tmpl.yaml +24 -11
  83. package/package.json +3 -3
  84. package/src/config/context-file-generator.js +0 -6
  85. package/src/dashboard/renderer.js +0 -36
  86. package/src/executors/runner.js +204 -0
  87. package/src/installer/core.js +2 -1
  88. package/src/installer/templates.js +5 -6
  89. package/src/intelligence/registry-manager.js +1 -1
  90. package/src/license/client.js +9 -3
  91. package/src/license/commands.js +12 -2
  92. package/src/license/machine-id.js +42 -1
  93. package/src/memory/gotchas.js +58 -40
  94. package/src/memory/magic-docs.js +1 -1
  95. package/src/memory/session-digest.js +9 -4
  96. package/src/orchestrator/cli.js +174 -14
  97. package/src/orchestrator/doctor.js +98 -16
  98. package/src/orchestrator/pipeline-manager.js +44 -22
  99. package/src/orchestrator/session-manager.js +56 -8
  100. package/src/telemetry/sender.js +7 -19
  101. package/src/terminal/run-team.js +3 -3
  102. package/src/upgrade/tracked-files-detector.js +34 -16
  103. package/src/utils/feature-flags.js +1 -1
  104. package/src/utils/flatten-entities.js +4 -40
  105. package/src/utils/schema-validator.js +0 -14
  106. package/src/wizard/i18n.js +3 -3
  107. package/src/api/index.js +0 -120
  108. package/src/autonomy/autonomous-gate.js +0 -294
  109. package/src/autonomy/build-loop.js +0 -281
  110. package/src/autonomy/build-state.js +0 -286
  111. package/src/autonomy/cause-analyzer.js +0 -177
  112. package/src/autonomy/escalation.js +0 -214
  113. package/src/autonomy/index.js +0 -51
  114. package/src/autonomy/mode-manager.js +0 -225
  115. package/src/autonomy/mode-suggester.js +0 -283
  116. package/src/autonomy/progress-reporter.js +0 -275
  117. package/src/autonomy/safety-net.js +0 -370
  118. package/src/config/agent-customizer.js +0 -231
  119. package/src/decision/analyzer.js +0 -291
  120. package/src/decision/engine.js +0 -250
  121. package/src/decision/index.js +0 -38
  122. package/src/decision/registry-healer.js +0 -468
  123. package/src/decision/registry-updater.js +0 -339
  124. package/src/extensions/loader.js +0 -145
  125. package/src/extensions/registry.js +0 -134
  126. package/src/gates/circuit-breaker.js +0 -151
  127. package/src/gates/g1-planning-complete.js +0 -154
  128. package/src/gates/g2-qa-planning.js +0 -156
  129. package/src/gates/g3-implementation.js +0 -215
  130. package/src/gates/g4-qa-implementation.js +0 -240
  131. package/src/gates/g5-deploy-ready.js +0 -181
  132. package/src/gates/gate-base.js +0 -185
  133. package/src/gates/index.js +0 -46
  134. package/src/health/auto-fix.js +0 -216
  135. package/src/health/engine.js +0 -246
  136. package/src/merger/semantic-merger.js +0 -292
  137. package/src/preview/detector.js +0 -238
  138. package/src/preview/index.js +0 -20
  139. package/src/preview/launcher.js +0 -235
  140. package/src/preview/log-buffer.js +0 -103
  141. package/src/quality/metrics-collector.js +0 -281
  142. package/src/quality/test-runner.js +0 -366
  143. package/src/tasks/executor.js +0 -195
  144. package/src/tasks/index.js +0 -4
  145. package/src/tasks/loader.js +0 -210
  146. package/src/tasks/router.js +0 -182
  147. 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;