@hai3/framework 0.2.0-alpha.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/CLAUDE.md ADDED
@@ -0,0 +1,161 @@
1
+ # @hai3/framework
2
+
3
+ Plugin-based application framework for HAI3 applications. Orchestrates SDK packages into cohesive applications.
4
+
5
+ ## Framework Layer
6
+
7
+ This package is part of the **Framework Layer (L2)** - it depends on SDK packages (@hai3/state, @hai3/screensets, @hai3/api, @hai3/i18n). It provides the plugin architecture and **owns the layout slices** (header, footer, menu, sidebar, screen, popup, overlay).
8
+
9
+ > **NOTE:** @hai3/uicore is deprecated. Layout slices are defined in @hai3/framework.
10
+
11
+ ## Core Concepts
12
+
13
+ ### Plugin Architecture
14
+
15
+ Build applications by composing plugins:
16
+
17
+ ```typescript
18
+ import { createHAI3, screensets, themes, layout, navigation, i18n } from '@hai3/framework';
19
+
20
+ const app = createHAI3()
21
+ .use(screensets())
22
+ .use(themes())
23
+ .use(layout())
24
+ .use(navigation())
25
+ .use(i18n())
26
+ .build();
27
+ ```
28
+
29
+ ### Presets
30
+
31
+ Pre-configured plugin combinations:
32
+
33
+ ```typescript
34
+ import { createHAI3App, presets } from '@hai3/framework';
35
+
36
+ // Full preset (default) - all plugins
37
+ const fullApp = createHAI3App();
38
+
39
+ // Or explicitly use presets
40
+ const minimalApp = createHAI3()
41
+ .use(presets.minimal()) // screensets + themes only
42
+ .build();
43
+
44
+ const headlessApp = createHAI3()
45
+ .use(presets.headless()) // screensets only
46
+ .build();
47
+ ```
48
+
49
+ ### Available Plugins
50
+
51
+ | Plugin | Provides | Dependencies |
52
+ |--------|----------|--------------|
53
+ | `screensets()` | screensetRegistry, screenSlice | - |
54
+ | `themes()` | themeRegistry, changeTheme action | - |
55
+ | `layout()` | header, footer, menu, sidebar, popup, overlay slices | screensets |
56
+ | `navigation()` | navigateToScreen, navigateToScreenset actions | screensets, routing |
57
+ | `routing()` | routeRegistry, URL sync | screensets |
58
+ | `i18n()` | i18nRegistry, setLanguage action | - |
59
+ | `effects()` | Core effect coordination | - |
60
+
61
+ ### Built Application
62
+
63
+ After calling `.build()`, access registries and actions:
64
+
65
+ ```typescript
66
+ const app = createHAI3App();
67
+
68
+ // Access registries
69
+ app.screensetRegistry.getAll();
70
+ app.themeRegistry.getCurrent();
71
+ app.routeRegistry.hasScreen('demo', 'home');
72
+ app.i18nRegistry.t('common:title');
73
+
74
+ // Access store
75
+ const state = app.store.getState();
76
+ app.store.dispatch(someAction);
77
+
78
+ // Access actions
79
+ app.actions.navigateToScreen({ screensetId: 'demo', screenId: 'home' });
80
+ app.actions.changeTheme({ themeId: 'dark' });
81
+ app.actions.setLanguage({ language: 'es' });
82
+
83
+ // Cleanup
84
+ app.destroy();
85
+ ```
86
+
87
+ ## Creating Custom Plugins
88
+
89
+ Extend HAI3 with custom functionality:
90
+
91
+ ```typescript
92
+ import type { HAI3Plugin } from '@hai3/framework';
93
+
94
+ export function myPlugin(): HAI3Plugin {
95
+ return {
96
+ name: 'my-plugin',
97
+ dependencies: ['screensets'], // Optional dependencies
98
+ provides: {
99
+ registries: { myRegistry: createMyRegistry() },
100
+ slices: [mySlice],
101
+ effects: [initMyEffects],
102
+ actions: { myAction: myActionHandler },
103
+ },
104
+ onInit(app) {
105
+ // Initialize after app is built
106
+ },
107
+ onDestroy(app) {
108
+ // Cleanup when app is destroyed
109
+ },
110
+ };
111
+ }
112
+ ```
113
+
114
+ ## Key Rules
115
+
116
+ 1. **Use presets for common cases** - `createHAI3App()` for full apps
117
+ 2. **Compose plugins for customization** - Use `createHAI3().use()` pattern
118
+ 3. **Dependencies are auto-resolved** - Plugin order doesn't matter
119
+ 4. **Access via app instance** - All registries and actions on `app.*`
120
+ 5. **NO React in this package** - Framework is headless, use @hai3/react for React bindings
121
+
122
+ ## Re-exports
123
+
124
+ For convenience, this package re-exports from SDK packages:
125
+
126
+ - From @hai3/state: `eventBus`, `createStore`, `getStore`, `registerSlice`, `hasSlice`, `createSlice`
127
+ - From @hai3/screensets: `LayoutDomain`, `ScreensetCategory`, `screensetRegistry`, contracts/types
128
+ - From @hai3/api: `apiRegistry`, `BaseApiService`, `RestProtocol`, `MockPlugin`
129
+ - From @hai3/i18n: `i18nRegistry`, `Language`, `SUPPORTED_LANGUAGES`, `getLanguageMetadata`
130
+
131
+ **Layout Slices (owned by @hai3/framework):**
132
+ - `layoutReducer`, `layoutDomainReducers`, `LAYOUT_SLICE_NAME`
133
+ - Domain slices: `headerSlice`, `footerSlice`, `menuSlice`, `sidebarSlice`, `screenSlice`, `popupSlice`, `overlaySlice`
134
+ - Domain actions: `headerActions`, `footerActions`, `menuActions`, `sidebarActions`, `screenActions`, `popupActions`, `overlayActions`
135
+ - Individual reducer functions: `setMenuCollapsed`, `toggleSidebar`, `setActiveScreen`, etc.
136
+
137
+ **NOTE:** `createAction` is NOT exported to consumers. Actions should be handwritten functions in screensets that contain business logic and emit events via `eventBus.emit()`.
138
+
139
+ **NOTE:** "Selector" is Redux terminology and is not used in HAI3. Access state via `useAppSelector` hook from @hai3/react:
140
+ ```typescript
141
+ const menu = useAppSelector((state: RootStateWithLayout) => state.layout.menu);
142
+ ```
143
+
144
+ ## Exports
145
+
146
+ ### Core
147
+ - `createHAI3` - App builder factory
148
+ - `createHAI3App` - Convenience function (full preset)
149
+ - `presets` - Available presets (full, minimal, headless)
150
+
151
+ ### Plugins
152
+ - `screensets`, `themes`, `layout`, `navigation`, `routing`, `i18n`, `effects`
153
+
154
+ ### Registries
155
+ - `createScreensetRegistry`, `createThemeRegistry`, `createRouteRegistry`
156
+
157
+ ### Types
158
+ - `HAI3Config`, `HAI3Plugin`, `HAI3App`, `HAI3AppBuilder`
159
+ - `PluginFactory`, `PluginProvides`, `PluginLifecycle`
160
+ - `Preset`, `Presets`, `ScreensetsConfig`
161
+ - All re-exported types from SDK packages
@@ -0,0 +1,48 @@
1
+ <!-- @standalone -->
2
+ # hai3:fix-violation - Fix Rule Violation
3
+
4
+ ## AI WORKFLOW (REQUIRED)
5
+ 1) Identify: Location (file:line), rule violated, category.
6
+ 2) Route: Use .ai/GUIDELINES.md to find target file.
7
+ 3) Summarize: Extract 3-7 applicable rules from target.
8
+ 4) Fix: Apply correction.
9
+ 5) Verify: Run checks.
10
+ 6) Report: What violated, rule applied, changes made, results.
11
+
12
+ ## STEP 1: Identify Violation
13
+ - Find violating code location (file:line).
14
+ - Classify category: typing | data flow | styling | registry | imports.
15
+
16
+ ## STEP 2: Route to Target File
17
+ - Data flow/events -> .ai/targets/EVENTS.md
18
+ - API services -> .ai/targets/SCREENSETS.md
19
+ - src/screensets -> .ai/targets/SCREENSETS.md
20
+ - src/themes -> .ai/targets/THEMES.md
21
+ - Styling -> .ai/targets/STYLING.md
22
+
23
+ ## STEP 3: Read and Summarize Rules
24
+ - REQUIRED: Read target file before making any change.
25
+ - Summarize 3-7 applicable rules internally.
26
+
27
+ ## STEP 4: Apply Fix
28
+ Change code to comply with target file rules.
29
+
30
+ ## STEP 5: Verify
31
+ Run: npm run arch:check && npm run lint && npm run type-check
32
+ REQUIRED: All checks must pass.
33
+
34
+ ## STEP 6: Report
35
+ - What violated the rule.
36
+ - Which rule was applied.
37
+ - Changes made.
38
+ - Verification results.
39
+
40
+ ## COMMON FIXES
41
+ - Direct dispatch: BAD dispatch(setMenuItems(items)) -> GOOD navigateToScreen(screenId)
42
+ - Hardcoded colors: BAD style with inline color -> GOOD className="text-primary"
43
+ - Import violations: BAD import from '@hai3/uikit/src/Foo' -> GOOD import from '@hai3/uikit'
44
+ - String literals: BAD screenId: 'dashboard' -> GOOD export const DASHBOARD_SCREEN_ID = 'dashboard'
45
+ - Inline component: Extract to screens/screen/components/ or uikit/ per SCREENSETS.md
46
+ - Inline style: BAD style with inline padding -> GOOD className="p-2" (except in uikit/base/)
47
+ - Inline data: Move to api/domain/mocks.ts, fetch via event-driven flow
48
+ - UIKit impurity: Move component from uikit/ to components/ if needs @hai3/uicore
@@ -0,0 +1,120 @@
1
+ <!-- @standalone -->
2
+ # hai3:new-action - Create New Action
3
+
4
+ ## AI WORKFLOW (REQUIRED)
5
+ 1) Read .ai/targets/EVENTS.md before starting.
6
+ 2) Summarize 3-6 key rules.
7
+ 3) Gather requirements from user.
8
+ 4) Create OpenSpec proposal for approval.
9
+ 5) After approval, apply implementation.
10
+
11
+ ## GATHER REQUIREMENTS
12
+ Ask user for:
13
+ - Action purpose (e.g., "navigate to screen", "load user data").
14
+ - Which screenset and domain (e.g., "chat/threads", "demo/navigation").
15
+ - Event payload data.
16
+
17
+ ## STEP 1: Create OpenSpec Proposal
18
+ Create `openspec/changes/add-{screenset}-{action}/` with:
19
+
20
+ ### proposal.md
21
+ ```markdown
22
+ # Proposal: Add {ActionName} Action
23
+
24
+ ## Summary
25
+ Add new action "{actionName}" to {screenset}/{domain} domain.
26
+
27
+ ## Details
28
+ - Screenset: {screenset}
29
+ - Domain: {domain}
30
+ - Action: {actionName}
31
+ - Event: {eventName}
32
+ - Payload: {payloadFields}
33
+
34
+ ## Implementation
35
+ Follow HAI3 event-driven flux pattern: Action -> Event -> Effect -> Slice.
36
+ ```
37
+
38
+ ### tasks.md
39
+ ```markdown
40
+ # Tasks: Add {ActionName} Action
41
+
42
+ - [ ] Define event in events/{domain}Events.ts
43
+ - [ ] Create action in actions/{domain}Actions.ts
44
+ - [ ] Create effect in effects/{domain}Effects.ts
45
+ - [ ] Validate: `npm run arch:check`
46
+ ```
47
+
48
+ ## STEP 2: Wait for Approval
49
+ Tell user: "I've created an OpenSpec proposal at `openspec/changes/add-{screenset}-{action}/`. Please review and run `/openspec:apply add-{screenset}-{action}` to implement."
50
+
51
+ ## STEP 3: Apply Implementation (after approval)
52
+ When user runs `/openspec:apply`, execute:
53
+
54
+ ### 3.1 Define Event
55
+ In src/screensets/{screenset}/events/{domain}Events.ts:
56
+ ```typescript
57
+ import { SCREENSET_ID } from '../ids';
58
+
59
+ const DOMAIN_ID = '{domain}';
60
+
61
+ export const {Domain}Events = {
62
+ {EventName}: `${SCREENSET_ID}/${DOMAIN_ID}/{eventName}` as const,
63
+ } as const;
64
+
65
+ export type {EventName}Payload = {
66
+ // payload fields
67
+ };
68
+
69
+ declare module '@hai3/state' {
70
+ interface EventPayloadMap {
71
+ [{Domain}Events.{EventName}]: {EventName}Payload;
72
+ }
73
+ }
74
+ ```
75
+
76
+ ### 3.2 Create Action
77
+ In src/screensets/{screenset}/actions/{domain}Actions.ts:
78
+ ```typescript
79
+ import { eventBus } from '@hai3/state';
80
+ import { {Domain}Events } from '../events/{domain}Events';
81
+
82
+ export const {actionName} = (params: ParamsType) => {
83
+ return (): void => {
84
+ eventBus.emit({Domain}Events.{EventName}, {
85
+ // payload
86
+ });
87
+ };
88
+ };
89
+ ```
90
+
91
+ ### 3.3 Create Effect
92
+ In src/screensets/{screenset}/effects/{domain}Effects.ts:
93
+ ```typescript
94
+ import { eventBus, getStore } from '@hai3/state';
95
+ import { {Domain}Events } from '../events/{domain}Events';
96
+
97
+ export function init{Domain}Effects(): void {
98
+ const store = getStore();
99
+ eventBus.on({Domain}Events.{EventName}, (payload) => {
100
+ store.dispatch(set{Something}(payload.{field}));
101
+ });
102
+ }
103
+ ```
104
+
105
+ ### 3.4 Validate
106
+ ```bash
107
+ npm run arch:check
108
+ ```
109
+
110
+ ### 3.5 Mark Tasks Complete
111
+ Update tasks.md to mark all completed tasks.
112
+
113
+ ## RULES
114
+ - Actions use imperative names (selectScreen, changeTheme).
115
+ - Events use past-tense names (screenSelected, themeChanged).
116
+ - Actions are pure functions (no getState, no async thunks).
117
+ - Actions return void (not Promise).
118
+ - Effects update their own slice only.
119
+ - Cross-domain communication only via events.
120
+ - FORBIDDEN: Direct slice dispatch from actions/components.
@@ -0,0 +1,63 @@
1
+ <!-- @standalone -->
2
+ # hai3:quick-ref - Quick Reference
3
+
4
+ ## Event-Driven
5
+ - REQUIRED: Action emits event via eventBus.emit('event/name', payload).
6
+ - REQUIRED: Effect subscribes via eventBus.on('event/name', handler).
7
+ - REQUIRED: Effect updates slice via store.dispatch(setSlice(data)).
8
+ - FORBIDDEN: Direct slice dispatch from actions or components.
9
+
10
+ ## Imports
11
+ - Same package: BAD import from '@hai3/uikit/src/Foo' -> GOOD import from './Foo'.
12
+ - Cross-branch app: BAD import from '../../core/layout' -> GOOD import from '@/core/layout'.
13
+ - Cross-package: BAD import from '@hai3/uikit/src/internal' -> GOOD import from '@hai3/uikit'.
14
+
15
+ ## Components
16
+ - REQUIRED: Check global @hai3/uikit first; screenset uikit only if missing.
17
+ - App/screensets: REQUIRED import { Button } from '@hai3/uikit'.
18
+ - FORBIDDEN: Raw HTML elements for UI.
19
+ - FORBIDDEN: Inline component definitions in *Screen.tsx.
20
+
21
+ ## Component Placement
22
+ - REQUIRED: Screenset uikit/ structure: base/, composite/, icons/.
23
+ - REQUIRED: uikit/base/ for rare primitives (inline styles allowed).
24
+ - REQUIRED: uikit/composite/ for screenset composites (theme tokens only).
25
+ - REQUIRED: Shared components in screensets/{name}/components/.
26
+ - REQUIRED: Screen-local components in screens/{screen}/components/.
27
+ - REQUIRED: Screen files orchestrate components only.
28
+
29
+ ## Registry
30
+ - REQUIRED: export const MY_DOMAIN = 'my-domain'.
31
+ - REQUIRED: class MyService extends BaseApiService.
32
+ - REQUIRED: declare module '@hai3/api' { interface ApiServicesMap }.
33
+ - REQUIRED: apiRegistry.register(MY_DOMAIN, MyService).
34
+
35
+ ## Styling
36
+ - Inline styles ONLY in screensets/*/uikit/base/ (rare local primitives).
37
+ - BAD style={{ backgroundColor: '#fff' }} -> GOOD className="bg-background".
38
+ - BAD style={{ color: '#000' }} -> GOOD className="text-foreground".
39
+ - REQUIRED: Use Tailwind utilities, CSS variables elsewhere.
40
+
41
+ ## i18n
42
+ - REQUIRED: i18nRegistry.registerLoader('screenset.demo', loader).
43
+ - REQUIRED: Use t('screenset.demo:screens.home.title') format.
44
+ - FORBIDDEN: Hardcoded strings in UI.
45
+
46
+ ## Commands
47
+ - npm ci -> Install dependencies.
48
+ - npm run dev -> Start dev server.
49
+ - npm run arch:check -> Validate (CRITICAL before commits).
50
+ - npm run type-check -> TypeScript validation.
51
+ - npm run lint -> ESLint validation.
52
+
53
+ ## Invariants
54
+ - REQUIRED: Event-driven architecture only.
55
+ - REQUIRED: Registries follow Open/Closed principle.
56
+ - REQUIRED: App deps limited to @hai3/react, @hai3/uikit, react, react-dom.
57
+ - REQUIRED: Cross-domain communication via events only.
58
+ - FORBIDDEN: String literals for IDs.
59
+ - FORBIDDEN: any type or unsafe casts.
60
+
61
+ ## Docs
62
+ - .ai/GUIDELINES.md -> Routing table.
63
+ - .ai/targets/*.md -> Area-specific rules.
@@ -0,0 +1,43 @@
1
+ <!-- @standalone -->
2
+ # hai3:rules - Show HAI3 Rules for Specific Area
3
+
4
+ Ask the user which area they want rules for, or detect from context.
5
+
6
+ ## ROUTING TABLE
7
+
8
+ | Area | Target file |
9
+ |------|-------------|
10
+ | Data flow / events | .ai/targets/EVENTS.md |
11
+ | API layer | .ai/targets/API.md |
12
+ | packages/uicore | .ai/targets/UICORE.md |
13
+ | packages/uikit | .ai/targets/UIKIT.md |
14
+ | packages/uikit-contracts | .ai/targets/UIKIT_CONTRACTS.md |
15
+ | src/screensets | .ai/targets/SCREENSETS.md |
16
+ | src/themes | .ai/targets/THEMES.md |
17
+ | Styling anywhere | .ai/targets/STYLING.md |
18
+ | AI documentation | .ai/targets/AI.md |
19
+
20
+ Then:
21
+
22
+ 1. Read the applicable target file
23
+ 2. Summarize the CRITICAL RULES section (3-7 rules)
24
+ 3. List STOP CONDITIONS
25
+ 4. Show PRE-DIFF CHECKLIST items
26
+ 5. Provide common violation examples with fixes
27
+
28
+ Format output as:
29
+
30
+ ## Critical Rules
31
+ [List 3-7 key rules in your own words]
32
+
33
+ ## Stop Conditions
34
+ [When to stop and ask]
35
+
36
+ ## Common Violations
37
+ [Show BAD -> GOOD examples]
38
+
39
+ ## Pre-Diff Checklist
40
+ [Checklist from target file]
41
+
42
+ ## Reference
43
+ Full rules: `.ai/targets/{FILE}.md`
@@ -0,0 +1,49 @@
1
+ <!-- @standalone -->
2
+ # hai3:validate - Validate Changes
3
+
4
+ ## AI WORKFLOW (REQUIRED)
5
+ 1) Read .ai/GUIDELINES.md and identify target file(s) for your changes.
6
+ 2) Summarize 3-7 key rules from applicable target file(s).
7
+ 3) Run validation checks.
8
+ 4) Report results.
9
+
10
+ ## STEP 1: Route to Target Files
11
+ - Use .ai/GUIDELINES.md ROUTING section.
12
+ - Read each applicable target file.
13
+ - Summarize rules internally (not written).
14
+
15
+ ## STEP 2: Run Architecture Check
16
+ ```bash
17
+ npm run arch:check
18
+ ```
19
+ REQUIRED: Must pass with zero errors.
20
+
21
+ ## STEP 3: Check Common Violations
22
+ - Direct slice dispatch (use event-driven actions instead).
23
+ - Inline styles outside base uikit folders (uikit/base/ only).
24
+ - Import violations (package internals, circular dependencies).
25
+ - String literal IDs (must use constants or enums).
26
+ - Inline component definitions in *Screen.tsx files.
27
+ - Inline data arrays (must use API services).
28
+ - @hai3/uicore imports in screensets/*/uikit/ folders.
29
+ - Screenset uikit component when global @hai3/uikit has equivalent.
30
+
31
+ ## STEP 4: Verify Event-Driven Flow
32
+ - Actions emit events (not dispatch slices).
33
+ - Effects listen to events and update slices.
34
+ - No prop drilling or callback-based state mutation.
35
+
36
+ ## STEP 5: Test via Chrome DevTools MCP
37
+ STOP: If MCP WebSocket is closed, fix connection first.
38
+ - Exercise all affected flows and screens.
39
+ - Verify UI uses @hai3/uikit and theme tokens.
40
+ - Verify event-driven behavior (no direct slice dispatch).
41
+ - Check for console errors or missing registrations.
42
+
43
+ ## STEP 6: Report Results
44
+ - List rules verified.
45
+ - List any violations found.
46
+ - Confirm npm run arch:check passed.
47
+
48
+ ## IF VIOLATIONS FOUND
49
+ Use hai3:fix-violation command to correct issues.