@hai3/react 0.3.0-alpha.0 → 0.4.0-alpha.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.
package/CLAUDE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hai3/react
2
2
 
3
- React bindings and hooks for HAI3 applications. Provides the React integration layer.
3
+ React bindings and hooks for HAI3 applications. Provides the React integration layer with MFE (Microfrontend) support.
4
4
 
5
5
  ## React Layer
6
6
 
@@ -46,7 +46,13 @@ import { useHAI3 } from '@hai3/react';
46
46
 
47
47
  function MyComponent() {
48
48
  const app = useHAI3();
49
- const screensets = app.screensetRegistry.getAll();
49
+
50
+ // Access MFE-enabled registry
51
+ const extensions = app.screensetsRegistry.getRegisteredExtensions();
52
+
53
+ // Access MFE actions
54
+ await app.actions.loadExtension({ extensionId: 'home' });
55
+ await app.actions.mountExtension({ extensionId: 'home', domainId: 'screen', container });
50
56
  }
51
57
  ```
52
58
 
@@ -56,11 +62,10 @@ Type-safe Redux hooks:
56
62
 
57
63
  ```tsx
58
64
  import { useAppDispatch, useAppSelector } from '@hai3/react';
59
- import { selectActiveScreen } from '@hai3/react';
60
65
 
61
66
  function MyComponent() {
62
67
  const dispatch = useAppDispatch();
63
- const activeScreen = useAppSelector(selectActiveScreen);
68
+ const activeScreen = useAppSelector((state) => state.layout.screen.activeScreen);
64
69
  }
65
70
  ```
66
71
 
@@ -105,83 +110,213 @@ function HomeScreen() {
105
110
  }
106
111
  ```
107
112
 
108
- #### useNavigation
113
+ #### useTheme
109
114
 
110
- Navigate between screens:
115
+ Access theme utilities:
111
116
 
112
117
  ```tsx
113
- import { useNavigation } from '@hai3/react';
118
+ import { useTheme } from '@hai3/react';
114
119
 
115
- function MyComponent() {
116
- const { navigateToScreen, navigateToScreenset, currentScreen } = useNavigation();
120
+ function ThemeToggle() {
121
+ const { currentTheme, themes, setTheme } = useTheme();
117
122
 
118
123
  return (
119
- <button onClick={() => navigateToScreen('demo', 'home')}>
120
- Go to Home
121
- </button>
124
+ <select value={currentTheme} onChange={(e) => setTheme(e.target.value)}>
125
+ {themes.map((theme) => (
126
+ <option key={theme.id} value={theme.id}>{theme.name}</option>
127
+ ))}
128
+ </select>
122
129
  );
123
130
  }
124
131
  ```
125
132
 
126
- #### useTheme
133
+ ### MFE Hooks
127
134
 
128
- Access theme utilities:
135
+ #### useMfeBridge
136
+
137
+ Access the MFE bridge for child MFEs:
129
138
 
130
139
  ```tsx
131
- import { useTheme } from '@hai3/react';
140
+ import { useMfeBridge } from '@hai3/react';
141
+ import { HAI3_ACTION_LOAD_EXT, HAI3_SHARED_PROPERTY_THEME } from '@hai3/react';
132
142
 
133
- function ThemeToggle() {
134
- const { currentTheme, themes, setTheme } = useTheme();
143
+ function MyExtension() {
144
+ const bridge = useMfeBridge();
145
+
146
+ // Execute actions chain on parent
147
+ await bridge.executeActionsChain({
148
+ action: { type: HAI3_ACTION_LOAD_EXT, target: 'screen', payload: { extensionId: 'other' } }
149
+ });
150
+
151
+ // Get shared property
152
+ const theme = bridge.getProperty(HAI3_SHARED_PROPERTY_THEME);
153
+ }
154
+ ```
155
+
156
+ #### useSharedProperty
157
+
158
+ Subscribe to shared property changes:
159
+
160
+ ```tsx
161
+ import { useSharedProperty, HAI3_SHARED_PROPERTY_THEME } from '@hai3/react';
162
+
163
+ function ThemedComponent() {
164
+ const theme = useSharedProperty(HAI3_SHARED_PROPERTY_THEME);
165
+
166
+ return <div style={{ backgroundColor: theme?.primaryColor }}>...</div>;
167
+ }
168
+ ```
169
+
170
+ #### useHostAction
171
+
172
+ Invoke actions on the host application:
173
+
174
+ ```tsx
175
+ import { useHostAction, HAI3_ACTION_LOAD_EXT } from '@hai3/react';
176
+
177
+ function MyExtension() {
178
+ const loadExtension = useHostAction(HAI3_ACTION_LOAD_EXT);
179
+
180
+ const handleClick = () => {
181
+ loadExtension({ extensionId: 'other' });
182
+ };
183
+
184
+ return <button onClick={handleClick}>Load Extension</button>;
185
+ }
186
+ ```
187
+
188
+ #### useDomainExtensions
189
+
190
+ Subscribe to extensions in a domain:
191
+
192
+ ```tsx
193
+ import { useDomainExtensions } from '@hai3/react';
194
+
195
+ function ScreenList() {
196
+ const screenExtensions = useDomainExtensions('screen');
135
197
 
136
198
  return (
137
- <select value={currentTheme} onChange={(e) => setTheme(e.target.value)}>
138
- {themes.map((theme) => (
139
- <option key={theme.id} value={theme.id}>{theme.name}</option>
199
+ <ul>
200
+ {screenExtensions.map((ext) => (
201
+ <li key={ext.id}>{ext.title}</li>
140
202
  ))}
141
- </select>
203
+ </ul>
142
204
  );
143
205
  }
144
206
  ```
145
207
 
146
- ### Components
208
+ #### useRegisteredPackages
209
+
210
+ Subscribe to registered GTS packages:
211
+
212
+ ```tsx
213
+ import { useRegisteredPackages } from '@hai3/react';
214
+
215
+ function PackageList() {
216
+ const packages = useRegisteredPackages();
217
+
218
+ return (
219
+ <ul>
220
+ {packages.map((pkg) => (
221
+ <li key={pkg}>{pkg}</li>
222
+ ))}
223
+ </ul>
224
+ );
225
+ }
226
+ ```
147
227
 
148
- #### AppRouter
228
+ #### useActivePackage
149
229
 
150
- Renders screens with lazy loading:
230
+ Subscribe to the active GTS package (the package of the currently mounted screen extension):
151
231
 
152
232
  ```tsx
153
- import { AppRouter } from '@hai3/react';
233
+ import { useActivePackage } from '@hai3/react';
154
234
 
155
- function App() {
235
+ function ActivePackageIndicator() {
236
+ const activePackage = useActivePackage();
237
+
238
+ if (!activePackage) {
239
+ return <div>No active screen</div>;
240
+ }
241
+
242
+ return <div>Active: {activePackage}</div>;
243
+ }
244
+ ```
245
+
246
+ ### MFE Components
247
+
248
+ #### MfeProvider
249
+
250
+ Provide MFE context for child extensions:
251
+
252
+ ```tsx
253
+ import { MfeProvider } from '@hai3/react';
254
+
255
+ function MfeHost() {
156
256
  return (
157
- <HAI3Provider>
158
- <Layout>
159
- <AppRouter
160
- fallback={<Loading />}
161
- errorFallback={(error) => <Error error={error} />}
162
- />
163
- </Layout>
164
- </HAI3Provider>
257
+ <MfeProvider bridge={parentBridge}>
258
+ <ExtensionContainer />
259
+ </MfeProvider>
165
260
  );
166
261
  }
167
262
  ```
168
263
 
264
+ #### ExtensionDomainSlot
265
+
266
+ Render extensions into a domain slot:
267
+
268
+ ```tsx
269
+ import { ExtensionDomainSlot } from '@hai3/react';
270
+
271
+ function LayoutScreen() {
272
+ return (
273
+ <div>
274
+ <ExtensionDomainSlot
275
+ domainId="screen"
276
+ containerRef={screenContainerRef}
277
+ fallback={<Loading />}
278
+ />
279
+ </div>
280
+ );
281
+ }
282
+ ```
283
+
284
+ #### RefContainerProvider
285
+
286
+ Provide container references for MFE mounting:
287
+
288
+ ```tsx
289
+ import { RefContainerProvider } from '@hai3/react';
290
+
291
+ function Layout() {
292
+ return (
293
+ <RefContainerProvider>
294
+ <ScreenContainer />
295
+ <SidebarContainer />
296
+ </RefContainerProvider>
297
+ );
298
+ }
299
+ ```
300
+
301
+ ### Components
302
+
169
303
  ## Key Rules
170
304
 
171
305
  1. **Wrap with HAI3Provider** - Required for all hooks to work
172
- 2. **Use hooks for state access** - Don't import selectors directly from @hai3/layout
306
+ 2. **Use hooks for state access** - Don't import selectors directly from @hai3/framework
173
307
  3. **Lazy load translations** - Use `useScreenTranslations` for screen-level i18n
174
- 4. **NO Layout components here** - Layout and UI components belong in L4 (user's project via CLI scaffolding)
308
+ 4. **Use MFE hooks for extensions** - `useMfeBridge`, `useSharedProperty`, `useHostAction`, `useDomainExtensions`
309
+ 5. **NO Layout components here** - Layout and UI components belong in L4 (user's project via CLI scaffolding)
175
310
 
176
311
  ## Re-exports
177
312
 
178
313
  For convenience, this package re-exports everything from @hai3/framework:
179
314
 
180
315
  - All SDK primitives (eventBus, createStore, etc.)
181
- - All plugins (screensets, themes, layout, etc.)
316
+ - All plugins (screensets, themes, layout, microfrontends, etc.)
182
317
  - All registries and factory functions
183
- - All selectors from @hai3/layout
184
- - All types
318
+ - All types (including MFE types)
319
+ - All MFE actions, selectors, and domain constants
185
320
 
186
321
  This allows users to import everything from `@hai3/react` without needing `@hai3/framework` directly.
187
322
 
@@ -189,7 +324,9 @@ This allows users to import everything from `@hai3/react` without needing `@hai3
189
324
 
190
325
  ### Components
191
326
  - `HAI3Provider` - Main context provider
192
- - `AppRouter` - Screen router
327
+ - `MfeProvider` - MFE context provider
328
+ - `ExtensionDomainSlot` - Domain slot renderer
329
+ - `RefContainerProvider` - Container reference provider
193
330
 
194
331
  ### Hooks
195
332
  - `useHAI3` - Access app instance
@@ -197,13 +334,88 @@ This allows users to import everything from `@hai3/react` without needing `@hai3
197
334
  - `useAppSelector` - Typed selector
198
335
  - `useTranslation` - Translation utilities
199
336
  - `useScreenTranslations` - Screen translation loading
200
- - `useNavigation` - Navigation utilities
201
337
  - `useTheme` - Theme utilities
338
+ - `useMfeBridge` - Access MFE bridge
339
+ - `useSharedProperty` - Subscribe to shared property
340
+ - `useHostAction` - Invoke host action
341
+ - `useDomainExtensions` - Subscribe to domain extensions
342
+ - `useRegisteredPackages` - Subscribe to registered GTS packages
343
+ - `useActivePackage` - Subscribe to active GTS package
202
344
 
203
345
  ### Context
204
346
  - `HAI3Context` - React context (for advanced use)
347
+ - `MfeContext` - MFE context (for advanced use)
205
348
 
206
349
  ### Types
207
- - `HAI3ProviderProps`, `AppRouterProps`
208
- - `UseTranslationReturn`, `UseNavigationReturn`, `UseThemeReturn`
350
+ - `HAI3ProviderProps`
351
+ - `MfeProviderProps`, `ExtensionDomainSlotProps`
352
+ - `UseTranslationReturn`, `UseThemeReturn`
209
353
  - All types from @hai3/framework
354
+
355
+ ## Migration from Legacy API
356
+
357
+ The `useNavigation` hook has been removed. Use MFE hooks and actions instead:
358
+
359
+ ### Removed Hook
360
+ - `useNavigation()` (replaced by MFE actions and hooks)
361
+
362
+ ### Migration Examples
363
+
364
+ **OLD**: Navigate using hook
365
+ ```tsx
366
+ import { useNavigation } from '@hai3/react';
367
+
368
+ function MyComponent() {
369
+ const { navigateToScreen } = useNavigation();
370
+
371
+ return (
372
+ <button onClick={() => navigateToScreen('demo', 'home')}>
373
+ Go Home
374
+ </button>
375
+ );
376
+ }
377
+ ```
378
+
379
+ **NEW**: Mount extension using app actions
380
+ ```tsx
381
+ import { useHAI3 } from '@hai3/react';
382
+
383
+ function MyComponent() {
384
+ const app = useHAI3();
385
+ const containerRef = useRef<HTMLDivElement>(null);
386
+
387
+ const handleNavigate = async () => {
388
+ if (containerRef.current) {
389
+ await app.actions.mountExtension({
390
+ extensionId: 'home',
391
+ domainId: 'screen',
392
+ container: containerRef.current,
393
+ });
394
+ }
395
+ };
396
+
397
+ return (
398
+ <>
399
+ <button onClick={handleNavigate}>Go Home</button>
400
+ <div ref={containerRef} />
401
+ </>
402
+ );
403
+ }
404
+ ```
405
+
406
+ **NEW (Alternative)**: Use ExtensionDomainSlot
407
+ ```tsx
408
+ import { ExtensionDomainSlot } from '@hai3/react';
409
+
410
+ function MyComponent() {
411
+ return (
412
+ <ExtensionDomainSlot
413
+ domainId="screen"
414
+ containerRef={screenContainerRef}
415
+ fallback={<Loading />}
416
+ />
417
+ );
418
+ }
419
+ ```
420
+
421
+ See the MFE migration guide in the project documentation for detailed migration steps.
@@ -5,8 +5,7 @@
5
5
  1) Check if @hai3/uikit has equivalent component first.
6
6
  2) Gather requirements from user.
7
7
  3) Determine type: screenset composite (default) | screenset base (rare).
8
- 4) Create OpenSpec proposal for approval.
9
- 5) After approval, apply implementation.
8
+ 4) Implement.
10
9
 
11
10
  ## CHECK GLOBAL UIKIT FIRST
12
11
  - REQUIRED: Before creating screenset component, verify @hai3/uikit lacks equivalent.
@@ -25,31 +24,9 @@ Ask user for:
25
24
  - uikit/composite/: Screenset-specific composites (theme tokens only).
26
25
  - uikit/base/: Rare primitives needing inline styles (needs strong justification).
27
26
 
28
- ### STEP 1: Create OpenSpec Proposal
29
- Create openspec/changes/add-{screenset}-{component}/ with:
27
+ ### STEP 1: Implementation
30
28
 
31
- #### proposal.md
32
- - Summary: Add new screenset-specific component to {screenset}.
33
- - Details: Screenset, component name, placement (base/composite), description, props.
34
- - Justification (if base/): Why global uikit insufficient, why composite insufficient.
35
- - Implementation: HAI3 patterns (no Redux, no business logic).
36
-
37
- #### tasks.md
38
- - Create component file in uikit/{base|composite}/.
39
- - Implement props interface.
40
- - Add theme token styling (or inline for base/).
41
- - Export from local index if needed.
42
- - Validate: npm run arch:check.
43
- - Test in UI.
44
-
45
- ### STEP 2: Wait for Approval
46
- Tell user: "Review proposal at openspec/changes/add-{screenset}-{component}/."
47
- Tell user: "Run /openspec:apply add-{screenset}-{component} to implement."
48
-
49
- ### STEP 3: Apply Implementation (after approval)
50
- When user runs /openspec:apply:
51
-
52
- #### 3.1 Create Component
29
+ #### 1.1 Create Component
53
30
  File: src/screensets/{screenset}/uikit/{base|composite}/{ComponentName}.tsx
54
31
  - composite/: Use theme tokens only (no inline styles).
55
32
  - base/: May use inline styles (rare, needs justification).
@@ -58,16 +35,13 @@ File: src/screensets/{screenset}/uikit/{base|composite}/{ComponentName}.tsx
58
35
  - NO Redux or state management.
59
36
  - Accept value/onChange pattern for state.
60
37
 
61
- #### 3.2 Export
38
+ #### 1.2 Export
62
39
  Export from local index if needed.
63
40
 
64
- #### 3.3 Validation
41
+ #### 1.3 Validation
65
42
  Run: npm run arch:check && npm run dev
66
43
  Test component in UI.
67
44
 
68
- #### 3.4 Mark Tasks Complete
69
- Update tasks.md to mark all completed tasks.
70
-
71
45
  ## RULES
72
46
  - REQUIRED: Check @hai3/uikit first; screenset uikit only if missing.
73
47
  - REQUIRED: Screenset base components need strong justification.
@@ -0,0 +1,167 @@
1
+ <!-- @standalone -->
2
+ # hai3:new-mfe - Create New Microfrontend Package
3
+
4
+ ## PREREQUISITES (CRITICAL - STOP IF FAILED)
5
+
6
+ 1. MFE must be associated with a screenset
7
+ 2. Screenset must exist (run `hai3-new-screenset` first if needed)
8
+ 3. Vite and Module Federation must be configured
9
+
10
+ ## QUICK START
11
+
12
+ For a screenset named `{screensetName}` with a new MFE:
13
+
14
+ ```bash
15
+ # 1. Create the MFE package in src/mfe_packages/{screensetName}-mfe/
16
+ cp -r packages/cli/template-sources/mfe-package/ src/mfe_packages/{screensetName}-mfe/
17
+
18
+ # 2. Update variables in package.json and vite.config.ts:
19
+ # - Replace {{mfeName}} with your screenset name (camelCase)
20
+ # - Replace {{port}} with available port (3001, 3010, 3020, etc)
21
+ # - IMPORTANT: set preview script to "vite preview --port {{port}}"
22
+
23
+ # 3. Install dependencies
24
+ cd src/mfe_packages/{screensetName}-mfe
25
+ npm install
26
+
27
+ # 4. Create src/lifecycle.tsx that extends ThemeAwareReactLifecycle
28
+
29
+ # 5. Regenerate MFE manifests so bootstrap.ts picks up the new package
30
+ npm run generate:mfe-manifests
31
+ ```
32
+
33
+ ## CONFIGURATION REQUIREMENTS
34
+
35
+ ✅ **Correct preview script** (required for port auto-discovery):
36
+ ```json
37
+ "preview": "vite preview --port {{port}}"
38
+ ```
39
+
40
+ ✅ **Correct dev script** (for hot reload):
41
+ ```json
42
+ "dev": "vite --port {{port}}"
43
+ ```
44
+
45
+ ❌ **WRONG** (don't use this for dev):
46
+ ```json
47
+ "dev": "vite build && vite preview --port {{port}}"
48
+ ```
49
+
50
+ ## PORT ALLOCATION
51
+
52
+ Reserve ports for MFE packages:
53
+ - **3001**: demo-mfe
54
+ - **3010+**: (next available: 3010, 3020, 3030, ...)
55
+ - **5173**: Main app
56
+
57
+ ## LIFECYCLE TEMPLATE
58
+
59
+ Create `src/lifecycle.tsx`:
60
+
61
+ ```typescript
62
+ import React from 'react';
63
+ import type { ChildMfeBridge } from '@hai3/react';
64
+ import { ThemeAwareReactLifecycle } from '@hai3/screensets/mfe/handler';
65
+ import { YourScreen } from './screens/YourScreen';
66
+
67
+ class Lifecycle extends ThemeAwareReactLifecycle {
68
+ constructor() {
69
+ super({
70
+ name: '{screensetName}',
71
+ version: '1.0.0',
72
+ });
73
+ }
74
+
75
+ async mount(shadowRoot: ShadowRoot, bridge: ChildMfeBridge) {
76
+ const div = document.createElement('div');
77
+ shadowRoot.appendChild(div);
78
+
79
+ // Initialize Tailwind/UIKit styles
80
+ const style = document.createElement('style');
81
+ style.textContent = tailwindStyles; // Import from @hai3/uikit
82
+ shadowRoot.appendChild(style);
83
+
84
+ // Render component
85
+ const root = ReactDOM.createRoot(div);
86
+ root.render(<YourScreen bridge={bridge} />);
87
+
88
+ return { root, div };
89
+ }
90
+ }
91
+
92
+ export default new Lifecycle();
93
+ ```
94
+
95
+ ## dev:all INTEGRATION (AUTOMATIC)
96
+
97
+ After creating the MFE and running `npm run generate:mfe-manifests`, the `dev:all`
98
+ script auto-discovers your new package — no manual configuration needed.
99
+
100
+ `dev-all.ts` scans `src/mfe_packages/*/package.json` and reads the port from the
101
+ `preview` (or `dev`) script using `--port NNNN`. The new MFE will automatically
102
+ appear in the next `npm run dev:all` run.
103
+
104
+ ## VALIDATION
105
+
106
+ After creation:
107
+
108
+ ```bash
109
+ # Regenerate manifests (required after adding new MFE)
110
+ npm run generate:mfe-manifests
111
+
112
+ # Validate TypeScript
113
+ npm run type-check
114
+
115
+ # Check architecture compliance
116
+ npm run arch:check
117
+
118
+ # Run the dev server (picks up new MFE automatically)
119
+ npm run dev:all
120
+
121
+ # Verify MFE loads at http://localhost:5173
122
+ # Open Studio Overlay (Ctrl+`) and check screenset
123
+ ```
124
+
125
+ ## TROUBLESHOOTING
126
+
127
+ ### Issue: MFE not appearing in screenset selector
128
+ - Run `npm run generate:mfe-manifests` to regenerate manifests
129
+ - Check mfe.json manifest is properly exported
130
+ - Verify extensions are registered in manifest
131
+ - Check browser console for errors
132
+
133
+ ### Issue: dev:all not picking up MFE port
134
+ - Verify `preview` script has `--port NNNN` (e.g., `"vite preview --port 3010"`)
135
+ - Check port is not in use (`lsof -i :3010`)
136
+ - Restart dev server
137
+
138
+ ### Issue: Hot reload not working
139
+ - Verify dev script uses `vite --port` (not `vite build && vite preview`)
140
+ - Check port is not in use
141
+ - Restart dev server
142
+
143
+ ### Issue: Redux/useSelector errors
144
+ - MFE must use mock data (no Redux Provider in isolation)
145
+ - Use `useState` for local state management
146
+ - Do not import Redux hooks (@hai3/react)
147
+
148
+ ## BEST PRACTICES
149
+
150
+ ✅ **DO:**
151
+ - Set `preview` script with `--port NNNN` for port auto-discovery
152
+ - Use mock data with useState for UI-only MFEs
153
+ - Keep MFE logic isolated and simple
154
+ - Use @hai3/uikit components
155
+ - Run `npm run generate:mfe-manifests` after creating the MFE
156
+
157
+ ❌ **DON'T:**
158
+ - Import Redux hooks directly
159
+ - Use vite build && vite preview in dev mode
160
+ - Create complex state management in MFE
161
+ - Hardcode ports without updating package.json preview script
162
+
163
+ ---
164
+
165
+ See also:
166
+ - `/packages/cli/template-sources/mfe-package/` for templates
167
+ - `hai3-new-screenset.md` for screenset creation
@@ -1,15 +1,10 @@
1
1
  <!-- @standalone -->
2
2
  # hai3:new-screen - Add New Screen
3
3
 
4
- ## PREREQUISITES (CRITICAL - STOP IF FAILED)
5
- FORBIDDEN: Proceeding without proposal.
6
- FORBIDDEN: Creating screen manually without OpenSpec workflow.
7
-
8
4
  ## AI WORKFLOW (REQUIRED)
9
5
  1) Read .ai/targets/SCREENSETS.md and .ai/targets/EVENTS.md before starting.
10
6
  2) Gather requirements from user (including UI sections).
11
- 3) Create OpenSpec proposal via `.claude/commands/openspec-proposal.md` (REQUIRED).
12
- 4) After approval, implement via `.claude/commands/openspec-apply.md` (REQUIRED).
7
+ 3) Implement.
13
8
 
14
9
  ## GATHER REQUIREMENTS
15
10
  Ask user for:
@@ -18,53 +13,7 @@ Ask user for:
18
13
  - UI sections (e.g., "header, form, data table").
19
14
  - Add to menu? (Y/N)
20
15
 
21
- ## STEP 1: Create OpenSpec Proposal (REQUIRED)
22
- Execute openspec:proposal command (see `.claude/commands/openspec-proposal.md`).
23
- Proposal name: `add-{screenset}-{screen}`
24
-
25
- ### proposal.md content
26
- ```
27
- # Proposal: Add {ScreenName} Screen
28
-
29
- ## Summary
30
- Add new screen "{screenName}" to {screenset} screenset.
31
-
32
- ## Details
33
- - Screenset: {screenset}
34
- - Screen name: {screenName}
35
- - Add to menu: {Y/N}
36
-
37
- ## Component Plan
38
- - REQUIRED: Use @hai3/uikit components first; local uikit only if missing.
39
- - uikit/base/: rare primitives (inline styles allowed, needs justification)
40
- - uikit/composite/: screenset composites (theme tokens only)
41
- - screens/{screen}/components/: screen-specific components
42
-
43
- ## Data Flow
44
- - Uses existing screenset events/slices per EVENTS.md
45
- - Screen dispatches actions, never direct slice updates
46
- ```
47
-
48
- ### tasks.md minimum required tasks
49
- NOTE: Proposal may include additional tasks, but MUST include these:
50
- ```
51
- - [ ] Add screen ID to ids.ts
52
- - [ ] Create components per Component Plan (BEFORE screen file)
53
- - [ ] Create screen (orchestrates components, follows EVENTS.md data flow)
54
- - [ ] Add i18n files for all languages
55
- - [ ] Add to menu (if requested)
56
- - [ ] Validate: `npm run type-check && npm run lint`
57
- - [ ] Test via Chrome DevTools MCP
58
- ```
59
-
60
- ## STEP 2: Wait for Approval
61
- Tell user: "Review proposal at `openspec/changes/add-{screenset}-{screen}/`."
62
- Tell user: "Execute openspec:apply command to implement."
63
-
64
- ## STEP 3: Implementation (via openspec:apply)
65
- BEFORE executing openspec:apply, verify tasks.md contains all minimum required tasks above.
66
- Execute openspec:apply command (see `.claude/commands/openspec-apply.md`).
67
- Follow tasks.md strictly:
16
+ ## STEP 1: Implementation
68
17
  1) Add screen ID to ids.ts.
69
18
  2) Create components BEFORE screen file per Component Plan.
70
19
  3) Create screen following data flow rules from .ai/targets/EVENTS.md:
@@ -79,3 +28,13 @@ Follow tasks.md strictly:
79
28
  - Test UI interactions and data flow
80
29
  - Verify translations load correctly
81
30
  - STOP if MCP connection fails
31
+
32
+ ## COMPONENT PLAN
33
+ - REQUIRED: Use @hai3/uikit components first; local uikit only if missing.
34
+ - uikit/base/: rare primitives (inline styles allowed, needs justification)
35
+ - uikit/composite/: screenset composites (theme tokens only)
36
+ - screens/{screen}/components/: screen-specific components
37
+
38
+ ## DATA FLOW
39
+ - Uses existing screenset events/slices per EVENTS.md
40
+ - Screen dispatches actions, never direct slice updates