@mind-fold/open-flow 0.1.17 → 0.2.2

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 (40) hide show
  1. package/dist/configurators/templates.d.ts.map +1 -1
  2. package/dist/configurators/templates.js +17 -6
  3. package/dist/configurators/templates.js.map +1 -1
  4. package/dist/configurators/workflow.d.ts.map +1 -1
  5. package/dist/configurators/workflow.js +82 -6
  6. package/dist/configurators/workflow.js.map +1 -1
  7. package/dist/templates/commands/break-loop.txt +107 -0
  8. package/dist/templates/commands/check-cross-layer.txt +153 -0
  9. package/dist/templates/commands/finish-work.txt +129 -0
  10. package/dist/templates/commands/index.d.ts +9 -5
  11. package/dist/templates/commands/index.d.ts.map +1 -1
  12. package/dist/templates/commands/index.js +16 -5
  13. package/dist/templates/commands/index.js.map +1 -1
  14. package/dist/templates/commands/init-agent.txt +100 -9
  15. package/dist/templates/commands/sync-from-runtime.txt +140 -0
  16. package/dist/templates/markdown/flow.md.txt +96 -84
  17. package/dist/templates/markdown/index.d.ts +21 -4
  18. package/dist/templates/markdown/index.d.ts.map +1 -1
  19. package/dist/templates/markdown/index.js +27 -4
  20. package/dist/templates/markdown/index.js.map +1 -1
  21. package/dist/templates/markdown/structure/backend/database-guidelines.md.txt +247 -0
  22. package/dist/templates/markdown/structure/backend/directory-structure.md.txt +153 -0
  23. package/dist/templates/markdown/structure/backend/error-handling.md.txt +257 -0
  24. package/dist/templates/markdown/structure/backend/index.md.txt +88 -0
  25. package/dist/templates/markdown/structure/backend/logging-guidelines.md.txt +212 -0
  26. package/dist/templates/markdown/structure/backend/quality-guidelines.md.txt +219 -0
  27. package/dist/templates/markdown/structure/backend/type-safety.md.txt +192 -0
  28. package/dist/templates/markdown/structure/flows/code-reuse-thinking-guide.md.txt +343 -0
  29. package/dist/templates/markdown/structure/flows/cross-layer-thinking-guide.md.txt +283 -0
  30. package/dist/templates/markdown/structure/flows/index.md.txt +133 -0
  31. package/dist/templates/markdown/structure/flows/pre-implementation-checklist.md.txt +182 -0
  32. package/dist/templates/markdown/structure/flows/spec-flow-template.md.txt +145 -0
  33. package/dist/templates/markdown/structure/frontend/component-guidelines.md.txt +335 -0
  34. package/dist/templates/markdown/structure/frontend/directory-structure.md.txt +172 -0
  35. package/dist/templates/markdown/structure/frontend/hook-guidelines.md.txt +287 -0
  36. package/dist/templates/markdown/structure/frontend/index.md.txt +91 -0
  37. package/dist/templates/markdown/structure/frontend/quality-guidelines.md.txt +274 -0
  38. package/dist/templates/markdown/structure/frontend/state-management.md.txt +293 -0
  39. package/dist/templates/markdown/structure/frontend/type-safety.md.txt +275 -0
  40. package/package.json +2 -2
@@ -0,0 +1,293 @@
1
+ # State Management
2
+
3
+ > Local state, server state, and global state patterns
4
+
5
+ ---
6
+
7
+ ## State Types
8
+
9
+ | Type | When to Use | Tool |
10
+ |------|-------------|------|
11
+ | **Local State** | UI state, form inputs | `useState` |
12
+ | **Server State** | Data from API | React Query |
13
+ | **Global State** | App-wide state, auth | Context / Zustand |
14
+ | **URL State** | Filters, pagination | `useSearchParams` |
15
+
16
+ ---
17
+
18
+ ## Local State
19
+
20
+ For component-specific UI state.
21
+
22
+ ```typescript
23
+ function Dialog() {
24
+ const [isOpen, setIsOpen] = useState(false);
25
+
26
+ return (
27
+ <>
28
+ <button onClick={() => setIsOpen(true)}>Open</button>
29
+ {isOpen && <Modal onClose={() => setIsOpen(false)} />}
30
+ </>
31
+ );
32
+ }
33
+ ```
34
+
35
+ ### Complex Local State
36
+
37
+ ```typescript
38
+ // For related state, use useReducer
39
+ type State = {
40
+ status: 'idle' | 'loading' | 'success' | 'error';
41
+ data: User | null;
42
+ error: string | null;
43
+ };
44
+
45
+ type Action =
46
+ | { type: 'loading' }
47
+ | { type: 'success'; data: User }
48
+ | { type: 'error'; error: string };
49
+
50
+ function reducer(state: State, action: Action): State {
51
+ switch (action.type) {
52
+ case 'loading':
53
+ return { ...state, status: 'loading', error: null };
54
+ case 'success':
55
+ return { status: 'success', data: action.data, error: null };
56
+ case 'error':
57
+ return { status: 'error', data: null, error: action.error };
58
+ }
59
+ }
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Server State (React Query)
65
+
66
+ For data fetched from APIs.
67
+
68
+ ### Fetching Data
69
+
70
+ ```typescript
71
+ function UserList() {
72
+ const { data, isLoading, error } = useQuery({
73
+ queryKey: ['users'],
74
+ queryFn: () => api.users.list(),
75
+ staleTime: 5 * 60 * 1000, // Consider fresh for 5 minutes
76
+ });
77
+
78
+ if (isLoading) return <Skeleton />;
79
+ if (error) return <Error message={error.message} />;
80
+
81
+ return <List items={data} />;
82
+ }
83
+ ```
84
+
85
+ ### Mutating Data
86
+
87
+ ```typescript
88
+ function CreateUserForm() {
89
+ const queryClient = useQueryClient();
90
+
91
+ const createUser = useMutation({
92
+ mutationFn: api.users.create,
93
+ onSuccess: () => {
94
+ queryClient.invalidateQueries({ queryKey: ['users'] });
95
+ },
96
+ });
97
+
98
+ const handleSubmit = (data: CreateUserInput) => {
99
+ createUser.mutate(data);
100
+ };
101
+
102
+ return <form onSubmit={handleSubmit}>...</form>;
103
+ }
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Global State (Context)
109
+
110
+ For app-wide state like auth, theme, or locale.
111
+
112
+ ### Auth Context Example
113
+
114
+ ```typescript
115
+ // context/auth-context.tsx
116
+ interface AuthState {
117
+ user: User | null;
118
+ isLoading: boolean;
119
+ }
120
+
121
+ interface AuthContextType extends AuthState {
122
+ login: (credentials: Credentials) => Promise<void>;
123
+ logout: () => Promise<void>;
124
+ }
125
+
126
+ const AuthContext = createContext<AuthContextType | null>(null);
127
+
128
+ export function AuthProvider({ children }: { children: React.ReactNode }) {
129
+ const [state, setState] = useState<AuthState>({
130
+ user: null,
131
+ isLoading: true,
132
+ });
133
+
134
+ useEffect(() => {
135
+ // Check session on mount
136
+ checkSession().then(user => {
137
+ setState({ user, isLoading: false });
138
+ });
139
+ }, []);
140
+
141
+ const login = async (credentials: Credentials) => {
142
+ const user = await api.auth.login(credentials);
143
+ setState({ user, isLoading: false });
144
+ };
145
+
146
+ const logout = async () => {
147
+ await api.auth.logout();
148
+ setState({ user: null, isLoading: false });
149
+ };
150
+
151
+ return (
152
+ <AuthContext.Provider value={{ ...state, login, logout }}>
153
+ {children}
154
+ </AuthContext.Provider>
155
+ );
156
+ }
157
+
158
+ export function useAuth() {
159
+ const context = useContext(AuthContext);
160
+ if (!context) {
161
+ throw new Error('useAuth must be used within AuthProvider');
162
+ }
163
+ return context;
164
+ }
165
+ ```
166
+
167
+ ### Usage
168
+
169
+ ```typescript
170
+ function LoginButton() {
171
+ const { user, login, logout } = useAuth();
172
+
173
+ if (user) {
174
+ return <button onClick={logout}>Logout</button>;
175
+ }
176
+
177
+ return <button onClick={() => login(credentials)}>Login</button>;
178
+ }
179
+ ```
180
+
181
+ ---
182
+
183
+ ## URL State
184
+
185
+ For state that should persist in URL (filters, pagination, search).
186
+
187
+ ```typescript
188
+ import { useSearchParams } from 'next/navigation';
189
+
190
+ function ProductList() {
191
+ const searchParams = useSearchParams();
192
+ const router = useRouter();
193
+
194
+ // Read from URL
195
+ const page = Number(searchParams.get('page')) || 1;
196
+ const category = searchParams.get('category') ?? 'all';
197
+
198
+ // Update URL
199
+ const setPage = (newPage: number) => {
200
+ const params = new URLSearchParams(searchParams);
201
+ params.set('page', String(newPage));
202
+ router.push(`?${params.toString()}`);
203
+ };
204
+
205
+ const { data } = useProducts({ page, category });
206
+
207
+ return (
208
+ <>
209
+ <CategoryFilter value={category} />
210
+ <ProductGrid items={data?.items} />
211
+ <Pagination page={page} onPageChange={setPage} />
212
+ </>
213
+ );
214
+ }
215
+ ```
216
+
217
+ ---
218
+
219
+ ## State Location Decision Tree
220
+
221
+ ```
222
+ Is the state needed by multiple components?
223
+ ├─ No → Local state (useState)
224
+ └─ Yes → Is it from the server?
225
+ ├─ Yes → React Query
226
+ └─ No → Should it persist in URL?
227
+ ├─ Yes → URL state (searchParams)
228
+ └─ No → Context or Zustand
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Anti-Patterns
234
+
235
+ ### Don't Sync Server State to Local State
236
+
237
+ ```typescript
238
+ // ❌ BAD: Duplicating server state
239
+ const { data: users } = useUsers();
240
+ const [localUsers, setLocalUsers] = useState<User[]>([]);
241
+
242
+ useEffect(() => {
243
+ if (users) setLocalUsers(users);
244
+ }, [users]);
245
+
246
+ // ✅ GOOD: Use server state directly
247
+ const { data: users } = useUsers();
248
+ // Use users directly, mutate with mutations
249
+ ```
250
+
251
+ ### Don't Overuse Global State
252
+
253
+ ```typescript
254
+ // ❌ BAD: Everything in global state
255
+ const { isModalOpen, setModalOpen } = useGlobalStore();
256
+
257
+ // ✅ GOOD: Local state for local UI
258
+ const [isModalOpen, setIsModalOpen] = useState(false);
259
+ ```
260
+
261
+ ### Don't Put Derived State in State
262
+
263
+ ```typescript
264
+ // ❌ BAD: Storing derived value
265
+ const [items, setItems] = useState([]);
266
+ const [filteredItems, setFilteredItems] = useState([]);
267
+
268
+ useEffect(() => {
269
+ setFilteredItems(items.filter(i => i.active));
270
+ }, [items]);
271
+
272
+ // ✅ GOOD: Compute derived value
273
+ const [items, setItems] = useState([]);
274
+ const filteredItems = items.filter(i => i.active);
275
+ // Or useMemo for expensive computations
276
+ ```
277
+
278
+ ---
279
+
280
+ ## Summary
281
+
282
+ | State Type | Tool | When to Use |
283
+ |------------|------|-------------|
284
+ | UI toggles | `useState` | Modal, dropdown, tabs |
285
+ | Form input | `useState` or form library | Input values |
286
+ | API data | React Query | Fetched data |
287
+ | Auth/User | Context | App-wide user state |
288
+ | Theme | Context | App-wide theme |
289
+ | Filters | URL params | Shareable filters |
290
+
291
+ ---
292
+
293
+ **Language**: All documentation must be written in **English**.
@@ -0,0 +1,275 @@
1
+ # Type Safety
2
+
3
+ > TypeScript patterns and type inference for frontend
4
+
5
+ ---
6
+
7
+ ## Core Principles
8
+
9
+ 1. **Import from API** - Don't redefine backend types
10
+ 2. **Infer when possible** - Let TypeScript do the work
11
+ 3. **No `any`** - Use `unknown` with type guards
12
+ 4. **No assertions** - Avoid `as` and `!`
13
+
14
+ ---
15
+
16
+ ## Import Types from Backend
17
+
18
+ Never redefine types that exist in your API layer.
19
+
20
+ ```typescript
21
+ // ✅ GOOD: Import from API package
22
+ import type { User, CreateUserInput } from '@/api/types';
23
+
24
+ function UserForm({ onSubmit }: { onSubmit: (data: CreateUserInput) => void }) {
25
+ // ...
26
+ }
27
+
28
+ // ❌ BAD: Redefining types
29
+ interface User {
30
+ id: string;
31
+ name: string;
32
+ email: string;
33
+ }
34
+ ```
35
+
36
+ ### Why?
37
+
38
+ - Single source of truth
39
+ - Types stay in sync with API
40
+ - Less code to maintain
41
+ - Compile-time errors if API changes
42
+
43
+ ---
44
+
45
+ ## Type Inference
46
+
47
+ Let TypeScript infer types when it can.
48
+
49
+ ### State
50
+
51
+ ```typescript
52
+ // ✅ GOOD: Inferred type
53
+ const [count, setCount] = useState(0); // number
54
+ const [name, setName] = useState(''); // string
55
+ const [user, setUser] = useState<User | null>(null); // explicit when needed
56
+
57
+ // ❌ BAD: Redundant type annotation
58
+ const [count, setCount] = useState<number>(0);
59
+ ```
60
+
61
+ ### Functions
62
+
63
+ ```typescript
64
+ // ✅ GOOD: Inferred return type
65
+ function formatDate(date: Date) {
66
+ return date.toISOString(); // returns string
67
+ }
68
+
69
+ // ✅ GOOD: Explicit when complex
70
+ function getUser(id: string): Promise<User | null> {
71
+ return api.users.get(id);
72
+ }
73
+ ```
74
+
75
+ ### Props
76
+
77
+ ```typescript
78
+ // ✅ GOOD: Props interface
79
+ interface ButtonProps {
80
+ children: React.ReactNode;
81
+ onClick: () => void;
82
+ disabled?: boolean;
83
+ }
84
+
85
+ function Button({ children, onClick, disabled }: ButtonProps) {
86
+ return <button onClick={onClick} disabled={disabled}>{children}</button>;
87
+ }
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Handling Nullable Values
93
+
94
+ ### Null Checks
95
+
96
+ ```typescript
97
+ // ✅ GOOD: Explicit null check
98
+ function UserProfile({ userId }: { userId: string }) {
99
+ const { data: user } = useUser(userId);
100
+
101
+ if (!user) {
102
+ return <Skeleton />;
103
+ }
104
+
105
+ // TypeScript knows user is not null
106
+ return <div>{user.name}</div>;
107
+ }
108
+ ```
109
+
110
+ ### Optional Chaining
111
+
112
+ ```typescript
113
+ // ✅ GOOD: Optional chaining for nested access
114
+ const userName = user?.profile?.name ?? 'Anonymous';
115
+
116
+ // ❌ BAD: Non-null assertion
117
+ const userName = user!.profile!.name;
118
+ ```
119
+
120
+ ### Default Values
121
+
122
+ ```typescript
123
+ // ✅ GOOD: Default values with nullish coalescing
124
+ const displayName = user.nickname ?? user.name ?? 'Unknown';
125
+ const items = response.data ?? [];
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Type Guards
131
+
132
+ Use type guards for runtime type checking.
133
+
134
+ ### Type Predicates
135
+
136
+ ```typescript
137
+ function isUser(value: unknown): value is User {
138
+ return (
139
+ typeof value === 'object' &&
140
+ value !== null &&
141
+ 'id' in value &&
142
+ 'email' in value
143
+ );
144
+ }
145
+
146
+ // Usage
147
+ function handleData(data: unknown) {
148
+ if (isUser(data)) {
149
+ // TypeScript knows data is User
150
+ console.log(data.email);
151
+ }
152
+ }
153
+ ```
154
+
155
+ ### Discriminated Unions
156
+
157
+ ```typescript
158
+ type Result<T> =
159
+ | { success: true; data: T }
160
+ | { success: false; error: string };
161
+
162
+ function handleResult(result: Result<User>) {
163
+ if (result.success) {
164
+ // TypeScript knows result.data exists
165
+ console.log(result.data.name);
166
+ } else {
167
+ // TypeScript knows result.error exists
168
+ console.error(result.error);
169
+ }
170
+ }
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Component Props
176
+
177
+ ### Extending HTML Elements
178
+
179
+ ```typescript
180
+ import { type ComponentProps } from 'react';
181
+
182
+ // Extend button props
183
+ interface ButtonProps extends ComponentProps<'button'> {
184
+ variant?: 'primary' | 'secondary';
185
+ isLoading?: boolean;
186
+ }
187
+
188
+ function Button({ variant = 'primary', isLoading, children, ...props }: ButtonProps) {
189
+ return (
190
+ <button className={variant} disabled={isLoading} {...props}>
191
+ {isLoading ? 'Loading...' : children}
192
+ </button>
193
+ );
194
+ }
195
+ ```
196
+
197
+ ### Polymorphic Components
198
+
199
+ ```typescript
200
+ type AsProp<C extends React.ElementType> = {
201
+ as?: C;
202
+ };
203
+
204
+ type PropsToOmit<C extends React.ElementType, P> = keyof (AsProp<C> & P);
205
+
206
+ type PolymorphicProps<C extends React.ElementType, Props = {}> =
207
+ React.PropsWithChildren<Props & AsProp<C>> &
208
+ Omit<React.ComponentPropsWithoutRef<C>, PropsToOmit<C, Props>>;
209
+
210
+ // Usage
211
+ function Text<C extends React.ElementType = 'span'>({
212
+ as,
213
+ children,
214
+ ...props
215
+ }: PolymorphicProps<C>) {
216
+ const Component = as || 'span';
217
+ return <Component {...props}>{children}</Component>;
218
+ }
219
+
220
+ // Can render as different elements
221
+ <Text>Span text</Text>
222
+ <Text as="p">Paragraph text</Text>
223
+ <Text as="h1">Heading text</Text>
224
+ ```
225
+
226
+ ---
227
+
228
+ ## Forbidden Patterns
229
+
230
+ | Pattern | Problem | Solution |
231
+ |---------|---------|----------|
232
+ | `any` | Disables type checking | Use `unknown` + guards |
233
+ | `as User` | Unsafe cast | Use type guards |
234
+ | `user!.name` | Runtime crash | Null check first |
235
+ | Redefine API types | Type drift | Import from API |
236
+
237
+ ---
238
+
239
+ ## Best Practices
240
+
241
+ ### DO
242
+
243
+ ```typescript
244
+ // Import types from API
245
+ import type { User } from '@/api/types';
246
+
247
+ // Use type guards
248
+ if (isUser(data)) { ... }
249
+
250
+ // Handle nullable explicitly
251
+ if (!user) return null;
252
+
253
+ // Infer when possible
254
+ const [value, setValue] = useState(0);
255
+ ```
256
+
257
+ ### DON'T
258
+
259
+ ```typescript
260
+ // Use any
261
+ const data: any = await fetch(...);
262
+
263
+ // Cast without validation
264
+ const user = data as User;
265
+
266
+ // Use non-null assertion
267
+ user!.name;
268
+
269
+ // Redefine API types locally
270
+ interface User { ... }
271
+ ```
272
+
273
+ ---
274
+
275
+ **Language**: All documentation must be written in **English**.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mind-fold/open-flow",
3
- "version": "0.1.17",
3
+ "version": "0.2.2",
4
4
  "description": "AI-assisted development workflow initializer for Cursor, Claude Code and more",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "scripts": {
16
16
  "build": "tsc && npm run copy-templates",
17
- "copy-templates": "cp -r src/templates/commands/*.txt dist/templates/commands/ && cp -r src/templates/scripts/*.txt dist/templates/scripts/ && cp -r src/templates/markdown/*.txt dist/templates/markdown/",
17
+ "copy-templates": "cp -r src/templates/commands/*.txt dist/templates/commands/ && cp -r src/templates/scripts/*.txt dist/templates/scripts/ && cp -r src/templates/markdown/*.txt dist/templates/markdown/ && cp -r src/templates/markdown/structure dist/templates/markdown/",
18
18
  "dev": "tsc --watch",
19
19
  "start": "node ./dist/cli/index.js",
20
20
  "prepublishOnly": "npm run build"