claude-flow-novice 1.5.0 → 1.5.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.
@@ -0,0 +1,134 @@
1
+ ---
2
+ description: "Launch full-stack development team with coordinated consensus validation"
3
+ argument-hint: "<goal description>"
4
+ allowed-tools: ["Task", "TodoWrite", "Read", "Write", "Edit", "Bash", "Glob", "Grep"]
5
+ ---
6
+
7
+ # Full-Stack Development Team
8
+
9
+ Launch a coordinated full-stack development team to accomplish complex features with built-in consensus validation.
10
+
11
+ **Goal**: $ARGUMENTS
12
+
13
+ ## Team Composition
14
+
15
+ The fullstack team includes:
16
+ - **Researcher**: Requirements analysis, pattern detection, architectural planning
17
+ - **Coder**: Implementation of backend and frontend features
18
+ - **Tester**: Comprehensive testing including unit, integration, and E2E tests
19
+ - **Reviewer**: Code quality analysis, security review, performance optimization
20
+ - **Architect** (for complex tasks): System design and architectural decisions
21
+
22
+ ## Execution Pattern
23
+
24
+ ### Phase 1: Execute
25
+ 1. **Launch Primary Swarm** (3-5 agents in parallel using Claude Code's Task tool)
26
+ - All agents execute concurrently in a single message
27
+ - Each agent receives full context and specific responsibilities
28
+ - Agents produce deliverables with confidence scores
29
+
30
+ 2. **Progress Tracking**
31
+ - Use TodoWrite to track all tasks (5-10+ items minimum)
32
+ - Mark tasks as in_progress before starting
33
+ - Complete tasks immediately after finishing (no batching)
34
+
35
+ ### Phase 2: Verify (Only when Primary Swarm believes it's done)
36
+ 1. **Self-Assessment**: Primary swarm evaluates completion (confidence ≥75% required)
37
+ 2. **Launch Consensus Swarm** (2-4 validators in parallel)
38
+ - Independent verification with Byzantine fault tolerance
39
+ - Comprehensive validation: tests, security, performance, architecture
40
+ - Voting mechanism with critical criteria checks
41
+
42
+ ### Phase 3: Decision
43
+ **PASS Criteria** (≥90% agreement + all critical checks):
44
+ - All tests passing (100% for critical paths, ≥80% coverage overall)
45
+ - No security vulnerabilities
46
+ - Performance within acceptable thresholds
47
+ - Architecture review approved
48
+
49
+ **FAIL Criteria**:
50
+ - <90% validator agreement OR critical criteria failed
51
+ - Round counter increments
52
+ - Feedback injected into context
53
+
54
+ ### Phase 4: Action
55
+ - **PASS**: Store results → Move to next task → Report completion
56
+ - **FAIL**:
57
+ - If Round < 10: Inject feedback → Relaunch primary swarm with improvements
58
+ - If Round ≥ 10: Escalate to human with full history + recommendations
59
+
60
+ ### Phase 5: Repeat
61
+ Iterative improvement with accumulated context from all previous rounds until:
62
+ - Success achieved (PASS)
63
+ - Maximum rounds reached (10)
64
+ - Human intervention requested
65
+
66
+ ## Consensus Validation Requirements
67
+
68
+ **Validator Team** (4 agents for Byzantine fault tolerance):
69
+ 1. **Validator 1** - Test Coverage & Quality
70
+ 2. **Validator 2** - Security & Compliance
71
+ 3. **Validator 3** - Performance & Optimization
72
+ 4. **Validator 4** - Architecture & Design
73
+
74
+ **Scoring System**:
75
+ - Overall Score: 0-100 (weighted average)
76
+ - Pass Threshold: ≥90/100 with unanimous approval
77
+ - Tier 2: 85-94 (production-ready with minor issues)
78
+ - Tier 3: 75-84 (needs improvements)
79
+ - Fail: <75 (significant issues)
80
+
81
+ **Critical Criteria** (all must pass):
82
+ - Tests executing and passing
83
+ - No critical security vulnerabilities
84
+ - Code compiles/builds successfully
85
+ - Core functionality working
86
+
87
+ ## Usage Examples
88
+
89
+ ```bash
90
+ # Simple feature
91
+ /fullstack Add user authentication with JWT tokens and password hashing
92
+
93
+ # Complex feature with multiple components
94
+ /fullstack Build a real-time chat system with user presence, typing indicators, message history, and file sharing
95
+
96
+ # Backend API
97
+ /fullstack Create REST API for product catalog with CRUD operations, search, filtering, and pagination
98
+
99
+ # Frontend feature
100
+ /fullstack Implement responsive dashboard with data visualization, real-time updates, and mobile support
101
+
102
+ # Full-stack integration
103
+ /fullstack Develop e-commerce checkout flow with payment processing, order management, and email notifications
104
+ ```
105
+
106
+ ## Execution Instructions
107
+
108
+ When this command is invoked:
109
+
110
+ 1. **Parse the goal** from $ARGUMENTS
111
+ 2. **Create comprehensive task list** using TodoWrite (5-10+ items)
112
+ 3. **Launch primary swarm** using Claude Code's Task tool in a SINGLE message:
113
+ ```
114
+ Task("Research and analyze requirements", "Analyze goal: [goal]. Research patterns, identify requirements, create detailed specifications...", "researcher")
115
+ Task("Implement core features", "Implement goal: [goal]. Write production code following best practices...", "coder")
116
+ Task("Create comprehensive tests", "Test goal: [goal]. Write unit, integration, and E2E tests...", "tester")
117
+ Task("Review and optimize", "Review implementation of goal: [goal]. Check security, performance, architecture...", "reviewer")
118
+ ```
119
+ 4. **Monitor progress** and update TodoWrite in real-time
120
+ 5. **Self-assess** when primary work complete
121
+ 6. **Launch consensus swarm** if confidence ≥75%
122
+ 7. **Process results** according to validation outcome
123
+ 8. **Iterate or complete** based on consensus decision
124
+
125
+ ## Important Notes
126
+
127
+ - **Always use Task tool in parallel** - spawn all agents in ONE message
128
+ - **Update TodoWrite immediately** - never batch completions
129
+ - **Run post-edit hooks** after EVERY file modification
130
+ - **Store results in appropriate directories** - never save to root
131
+ - **Follow file organization** - use /src, /tests, /docs structure
132
+ - **Enable consensus validation** - for production-ready code quality
133
+
134
+ Execute the fullstack development workflow for the specified goal with comprehensive validation.
@@ -43,6 +43,7 @@ export { default as registerClaudeMd } from './register-claude-md.js';
43
43
  export const Commands = {
44
44
  SPARC: 'sparc',
45
45
  SWARM: 'swarm',
46
+ FULLSTACK: 'fullstack',
46
47
  HOOKS: 'hooks',
47
48
  NEURAL: 'neural',
48
49
  PERFORMANCE: 'performance',
@@ -57,6 +58,8 @@ export const Commands = {
57
58
  */
58
59
  export const Aliases = {
59
60
  s: 'swarm',
61
+ fs: 'fullstack',
62
+ full: 'fullstack',
60
63
  h: 'hooks',
61
64
  n: 'neural',
62
65
  p: 'performance',
@@ -91,6 +94,7 @@ export function getQuickHelp() {
91
94
  🚀 **CLAUDE-FLOW SLASH COMMANDS**
92
95
 
93
96
  **Essential Commands:**
97
+ - \`/fullstack "goal"\` - Launch full-stack development team with consensus validation
94
98
  - \`/swarm init mesh 8\` - Initialize agent swarm
95
99
  - \`/hooks enable\` - Enable automation hooks
96
100
  - \`/sparc spec "task"\` - Run SPARC methodology
package/CHANGELOG.md CHANGED
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ### ✨ Added
11
+ - **`/fullstack` Slash Command**: Launch coordinated full-stack development team with consensus validation
12
+ - Automatic team composition (researcher, coder, tester, reviewer, architect)
13
+ - Built-in consensus validation with 4-validator Byzantine fault tolerance
14
+ - Iterative improvement with up to 10 rounds and feedback injection
15
+ - Production-ready code quality (≥90% agreement + critical criteria)
16
+ - User can specify custom goals: `/fullstack "Add authentication with JWT"`
17
+ - Command aliases: `/fs`, `/full`
18
+ - Comprehensive documentation in `docs/commands/fullstack.md`
19
+ - Auto-discovered by Claude Code (no manual registration required)
20
+
8
21
  ## [1.4.1] - 2025-09-29
9
22
 
10
23
  ### 🔧 Fixed
package/CLAUDE.md CHANGED
@@ -1050,3 +1050,941 @@ class TestAPI:
1050
1050
  assert response.json()["status"] == "success"
1051
1051
  ```
1052
1052
 
1053
+
1054
+
1055
+ ## Custom Configuration
1056
+
1057
+ <!-- Preserved from existing CLAUDE.md -->
1058
+ hooks/ # Custom hooks (if React)
1059
+ types/ # Type definitions (if TypeScript)
1060
+ ```
1061
+
1062
+ **Testing Patterns:**
1063
+ ```javascript
1064
+ import { jest } from '@jest/globals';
1065
+
1066
+ describe('Module Tests', () => {
1067
+ beforeEach(() => {
1068
+ jest.clearAllMocks();
1069
+ });
1070
+
1071
+ test('handles async operations correctly', async () => {
1072
+ const mockFn = jest.fn().mockResolvedValue({ success: true });
1073
+ const result = await asyncOperation(mockFn);
1074
+
1075
+ expect(result).toEqual({ success: true });
1076
+ expect(mockFn).toHaveBeenCalledTimes(1);
1077
+ });
1078
+
1079
+ test('handles errors gracefully', async () => {
1080
+ const mockFn = jest.fn().mockRejectedValue(new Error('Test error'));
1081
+
1082
+ await expect(asyncOperation(mockFn)).rejects.toThrow('Test error');
1083
+ });
1084
+ });
1085
+ ```
1086
+
1087
+ **Performance Best Practices:**
1088
+ - Use code splitting for large applications
1089
+ - Implement lazy loading for routes/components
1090
+ - Minimize bundle size with tree shaking
1091
+ - Use Web Workers for heavy computations
1092
+ - Implement proper caching strategies
1093
+
1094
+ **Error Handling:**
1095
+ ```javascript
1096
+ // Global error handler
1097
+ process.on('unhandledRejection', (reason, promise) => {
1098
+ console.error('Unhandled Rejection at:', promise, 'reason:', reason);
1099
+ // Application specific logging logic here
1100
+ });
1101
+
1102
+ // Async error wrapper
1103
+ const asyncHandler = (fn) => (req, res, next) => {
1104
+ Promise.resolve(fn(req, res, next)).catch(next);
1105
+ };
1106
+ ```
1107
+
1108
+ **Environment Configuration:**
1109
+ ```javascript
1110
+ // config/index.js
1111
+ const config = {
1112
+ development: {
1113
+ api: {
1114
+ baseURL: 'http://localhost:3000',
1115
+ timeout: 5000
1116
+ }
1117
+ },
1118
+ production: {
1119
+ api: {
1120
+ baseURL: process.env.API_BASE_URL,
1121
+ timeout: 10000
1122
+ }
1123
+ }
1124
+ };
1125
+
1126
+ export default config[process.env.NODE_ENV || 'development'];
1127
+ ```
1128
+
1129
+
1130
+ hooks/ # Custom hooks (if React)
1131
+ useApi.ts # Generic API hook
1132
+ ```
1133
+
1134
+
1135
+ hooks/ # Custom hooks
1136
+ useApi.js
1137
+ useLocalStorage.js
1138
+ useAuth.js
1139
+ context/ # React context providers
1140
+ AuthContext.jsx
1141
+ ThemeContext.jsx
1142
+ services/ # API services
1143
+ api.js
1144
+ auth.js
1145
+ utils/ # Helper functions
1146
+ validators.js
1147
+ formatters.js
1148
+ styles/ # Global styles
1149
+ globals.css
1150
+ variables.css
1151
+ ```
1152
+
1153
+ **Component Patterns:**
1154
+ ```jsx
1155
+ import React, { useState, useEffect, useCallback, useMemo } from 'react';
1156
+ import PropTypes from 'prop-types';
1157
+
1158
+ // Functional component with hooks
1159
+ const UserProfile = ({ userId, onUpdate }) => {
1160
+ const [user, setUser] = useState(null);
1161
+ const [loading, setLoading] = useState(true);
1162
+ const [error, setError] = useState(null);
1163
+
1164
+ // Memoized expensive calculations
1165
+ const userStats = useMemo(() => {
1166
+ if (!user) return null;
1167
+ return {
1168
+ totalPosts: user.posts?.length || 0,
1169
+ joinedDate: new Date(user.createdAt).toLocaleDateString()
1170
+ };
1171
+ }, [user]);
1172
+
1173
+ // Memoized callbacks to prevent unnecessary re-renders
1174
+ const handleUpdateUser = useCallback(async (updates) => {
1175
+ try {
1176
+ const updatedUser = await updateUser(userId, updates);
1177
+ setUser(updatedUser);
1178
+ onUpdate?.(updatedUser);
1179
+ } catch (err) {
1180
+ setError(err.message);
1181
+ }
1182
+ }, [userId, onUpdate]);
1183
+
1184
+ useEffect(() => {
1185
+ let cancelled = false;
1186
+
1187
+ const fetchUser = async () => {
1188
+ try {
1189
+ setLoading(true);
1190
+ const userData = await getUserById(userId);
1191
+ if (!cancelled) {
1192
+ setUser(userData);
1193
+ }
1194
+ } catch (err) {
1195
+ if (!cancelled) {
1196
+ setError(err.message);
1197
+ }
1198
+ } finally {
1199
+ if (!cancelled) {
1200
+ setLoading(false);
1201
+ }
1202
+ }
1203
+ };
1204
+
1205
+ fetchUser();
1206
+
1207
+ return () => {
1208
+ cancelled = true;
1209
+ };
1210
+ }, [userId]);
1211
+
1212
+ if (loading) return <LoadingSpinner />;
1213
+ if (error) return <ErrorMessage message={error} />;
1214
+ if (!user) return <NotFound />;
1215
+
1216
+ return (
1217
+ <div className="user-profile">
1218
+ <ProfileHeader user={user} stats={userStats} />
1219
+ <ProfileContent user={user} onUpdate={handleUpdateUser} />
1220
+ </div>
1221
+ );
1222
+ };
1223
+
1224
+ UserProfile.propTypes = {
1225
+ userId: PropTypes.string.isRequired,
1226
+ onUpdate: PropTypes.func
1227
+ };
1228
+
1229
+ export default React.memo(UserProfile);
1230
+ ```
1231
+
1232
+ **Custom Hooks Pattern:**
1233
+ ```jsx
1234
+ import { useState, useEffect, useCallback } from 'react';
1235
+
1236
+ // Generic API hook
1237
+ export const useApi = (url, options = {}) => {
1238
+ const [data, setData] = useState(null);
1239
+ const [loading, setLoading] = useState(true);
1240
+ const [error, setError] = useState(null);
1241
+
1242
+ const fetchData = useCallback(async () => {
1243
+ try {
1244
+ setLoading(true);
1245
+ setError(null);
1246
+ const response = await fetch(url, options);
1247
+
1248
+ if (!response.ok) {
1249
+ throw new Error(`HTTP error! status: ${response.status}`);
1250
+ }
1251
+
1252
+ const result = await response.json();
1253
+ setData(result);
1254
+ } catch (err) {
1255
+ setError(err.message);
1256
+ } finally {
1257
+ setLoading(false);
1258
+ }
1259
+ }, [url, options]);
1260
+
1261
+ useEffect(() => {
1262
+ fetchData();
1263
+ }, [fetchData]);
1264
+
1265
+ const refetch = useCallback(() => {
1266
+ fetchData();
1267
+ }, [fetchData]);
1268
+
1269
+ return { data, loading, error, refetch };
1270
+ };
1271
+
1272
+ // Local storage hook
1273
+ export const useLocalStorage = (key, initialValue) => {
1274
+ const [storedValue, setStoredValue] = useState(() => {
1275
+ try {
1276
+ const item = window.localStorage.getItem(key);
1277
+ return item ? JSON.parse(item) : initialValue;
1278
+ } catch (error) {
1279
+ console.error(`Error reading localStorage key "${key}":`, error);
1280
+ return initialValue;
1281
+ }
1282
+ });
1283
+
1284
+ const setValue = useCallback((value) => {
1285
+ try {
1286
+ const valueToStore = value instanceof Function ? value(storedValue) : value;
1287
+ setStoredValue(valueToStore);
1288
+ window.localStorage.setItem(key, JSON.stringify(valueToStore));
1289
+ } catch (error) {
1290
+ console.error(`Error setting localStorage key "${key}":`, error);
1291
+ }
1292
+ }, [key, storedValue]);
1293
+
1294
+ return [storedValue, setValue];
1295
+ };
1296
+ ```
1297
+
1298
+ **Context Pattern:**
1299
+ ```jsx
1300
+ import React, { createContext, useContext, useReducer, useCallback } from 'react';
1301
+
1302
+ // State and actions
1303
+ const initialState = {
1304
+ user: null,
1305
+ isAuthenticated: false,
1306
+ loading: false,
1307
+ error: null
1308
+ };
1309
+
1310
+ const authReducer = (state, action) => {
1311
+ switch (action.type) {
1312
+ case 'LOGIN_START':
1313
+ return { ...state, loading: true, error: null };
1314
+ case 'LOGIN_SUCCESS':
1315
+ return {
1316
+ ...state,
1317
+ user: action.payload,
1318
+ isAuthenticated: true,
1319
+ loading: false,
1320
+ error: null
1321
+ };
1322
+ case 'LOGIN_FAILURE':
1323
+ return {
1324
+ ...state,
1325
+ user: null,
1326
+ isAuthenticated: false,
1327
+ loading: false,
1328
+ error: action.payload
1329
+ };
1330
+ case 'LOGOUT':
1331
+ return initialState;
1332
+ default:
1333
+ return state;
1334
+ }
1335
+ };
1336
+
1337
+ // Context creation
1338
+ const AuthContext = createContext();
1339
+
1340
+ // Provider component
1341
+ export const AuthProvider = ({ children }) => {
1342
+ const [state, dispatch] = useReducer(authReducer, initialState);
1343
+
1344
+ const login = useCallback(async (credentials) => {
1345
+ dispatch({ type: 'LOGIN_START' });
1346
+ try {
1347
+ const user = await authService.login(credentials);
1348
+ dispatch({ type: 'LOGIN_SUCCESS', payload: user });
1349
+ return user;
1350
+ } catch (error) {
1351
+ dispatch({ type: 'LOGIN_FAILURE', payload: error.message });
1352
+ throw error;
1353
+ }
1354
+ }, []);
1355
+
1356
+ const logout = useCallback(() => {
1357
+ authService.logout();
1358
+ dispatch({ type: 'LOGOUT' });
1359
+ }, []);
1360
+
1361
+ const value = {
1362
+ ...state,
1363
+ login,
1364
+ logout
1365
+ };
1366
+
1367
+ return (
1368
+ <AuthContext.Provider value={value}>
1369
+ {children}
1370
+ </AuthContext.Provider>
1371
+ );
1372
+ };
1373
+
1374
+ // Custom hook for using auth context
1375
+ export const useAuth = () => {
1376
+ const context = useContext(AuthContext);
1377
+ if (!context) {
1378
+ throw new Error('useAuth must be used within an AuthProvider');
1379
+ }
1380
+ return context;
1381
+ };
1382
+ ```
1383
+
1384
+ **Testing with React Testing Library:**
1385
+ ```jsx
1386
+ import React from 'react';
1387
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
1388
+ import userEvent from '@testing-library/user-event';
1389
+ import { jest } from '@jest/globals';
1390
+ import UserProfile from '../UserProfile';
1391
+ import * as api from '../../services/api';
1392
+
1393
+ // Mock the API module
1394
+ jest.mock('../../services/api');
1395
+
1396
+ describe('UserProfile', () => {
1397
+ const mockUser = {
1398
+ id: '123',
1399
+ name: 'John Doe',
1400
+ email: 'john@example.com',
1401
+ posts: [{ id: 1, title: 'Test Post' }]
1402
+ };
1403
+
1404
+ beforeEach(() => {
1405
+ jest.clearAllMocks();
1406
+ });
1407
+
1408
+ test('renders user profile after loading', async () => {
1409
+ api.getUserById.mockResolvedValue(mockUser);
1410
+
1411
+ render(<UserProfile userId="123" />);
1412
+
1413
+ // Check loading state
1414
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1415
+
1416
+ // Wait for user data to load
1417
+ await waitFor(() => {
1418
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
1419
+ });
1420
+
1421
+ expect(screen.getByText('john@example.com')).toBeInTheDocument();
1422
+ expect(screen.getByText('1 Posts')).toBeInTheDocument();
1423
+ });
1424
+
1425
+ test('handles update user interaction', async () => {
1426
+ const user = userEvent.setup();
1427
+ const onUpdate = jest.fn();
1428
+
1429
+ api.getUserById.mockResolvedValue(mockUser);
1430
+ api.updateUser.mockResolvedValue({ ...mockUser, name: 'Jane Doe' });
1431
+
1432
+ render(<UserProfile userId="123" onUpdate={onUpdate} />);
1433
+
1434
+ await waitFor(() => {
1435
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
1436
+ });
1437
+
1438
+ const editButton = screen.getByRole('button', { name: /edit/i });
1439
+ await user.click(editButton);
1440
+
1441
+ const nameInput = screen.getByDisplayValue('John Doe');
1442
+ await user.clear(nameInput);
1443
+ await user.type(nameInput, 'Jane Doe');
1444
+
1445
+ const saveButton = screen.getByRole('button', { name: /save/i });
1446
+ await user.click(saveButton);
1447
+
1448
+ await waitFor(() => {
1449
+ expect(onUpdate).toHaveBeenCalledWith({ ...mockUser, name: 'Jane Doe' });
1450
+ });
1451
+ });
1452
+
1453
+ test('displays error message on API failure', async () => {
1454
+ api.getUserById.mockRejectedValue(new Error('Network error'));
1455
+
1456
+ render(<UserProfile userId="123" />);
1457
+
1458
+ await waitFor(() => {
1459
+ expect(screen.getByText(/network error/i)).toBeInTheDocument();
1460
+ });
1461
+ });
1462
+ });
1463
+ ```
1464
+
1465
+ **Performance Optimization:**
1466
+ ```jsx
1467
+ import React, { memo, lazy, Suspense } from 'react';
1468
+
1469
+ // Lazy loading for code splitting
1470
+ const LazyUserProfile = lazy(() => import('./UserProfile'));
1471
+ const LazyUserSettings = lazy(() => import('./UserSettings'));
1472
+
1473
+ // Memoized component to prevent unnecessary re-renders
1474
+ const UserCard = memo(({ user, onUpdate }) => {
1475
+ return (
1476
+ <div className="user-card">
1477
+ <h3>{user.name}</h3>
1478
+ <p>{user.email}</p>
1479
+ <button onClick={() => onUpdate(user.id)}>
1480
+ Update
1481
+ </button>
1482
+ </div>
1483
+ );
1484
+ });
1485
+
1486
+ // Main app with lazy loading
1487
+ const App = () => {
1488
+ return (
1489
+ <div className="app">
1490
+ <Suspense fallback={<div>Loading...</div>}>
1491
+ <Routes>
1492
+ <Route path="/profile" element={<LazyUserProfile />} />
1493
+ <Route path="/settings" element={<LazyUserSettings />} />
1494
+ </Routes>
1495
+ </Suspense>
1496
+ </div>
1497
+ );
1498
+ };
1499
+ ```
1500
+
1501
+ **State Management with Zustand:**
1502
+ ```jsx
1503
+ import { create } from 'zustand';
1504
+ import { devtools, persist } from 'zustand/middleware';
1505
+
1506
+ const useUserStore = create(
1507
+ devtools(
1508
+ persist(
1509
+ (set, get) => ({
1510
+ users: [],
1511
+ currentUser: null,
1512
+ loading: false,
1513
+
1514
+ fetchUsers: async () => {
1515
+ set({ loading: true });
1516
+ try {
1517
+ const users = await api.getUsers();
1518
+ set({ users, loading: false });
1519
+ } catch (error) {
1520
+ set({ loading: false });
1521
+ throw error;
1522
+ }
1523
+ },
1524
+
1525
+ setCurrentUser: (user) => set({ currentUser: user }),
1526
+
1527
+ updateUser: async (userId, updates) => {
1528
+ const updatedUser = await api.updateUser(userId, updates);
1529
+ set((state) => ({
1530
+ users: state.users.map((user) =>
1531
+ user.id === userId ? updatedUser : user
1532
+ ),
1533
+ currentUser: state.currentUser?.id === userId ? updatedUser : state.currentUser
1534
+ }));
1535
+ return updatedUser;
1536
+ }
1537
+ }),
1538
+ { name: 'user-store' }
1539
+ )
1540
+ )
1541
+ );
1542
+
1543
+ // Usage in component
1544
+ const UserList = () => {
1545
+ const { users, loading, fetchUsers } = useUserStore();
1546
+
1547
+ useEffect(() => {
1548
+ fetchUsers();
1549
+ }, [fetchUsers]);
1550
+
1551
+ if (loading) return <LoadingSpinner />;
1552
+
1553
+ return (
1554
+ <div>
1555
+ {users.map((user) => (
1556
+ <UserCard key={user.id} user={user} />
1557
+ ))}
1558
+ </div>
1559
+ );
1560
+ };
1561
+ ```
1562
+
1563
+
1564
+ hooks/ # Custom hooks
1565
+ useApi.js
1566
+ useLocalStorage.js
1567
+ useAuth.js
1568
+ context/ # React context providers
1569
+ AuthContext.jsx
1570
+ ThemeContext.jsx
1571
+ services/ # API services
1572
+ api.js
1573
+ auth.js
1574
+ utils/ # Helper functions
1575
+ validators.js
1576
+ formatters.js
1577
+ styles/ # Global styles
1578
+ globals.css
1579
+ variables.css
1580
+ ```
1581
+
1582
+ **Component Patterns:**
1583
+ ```jsx
1584
+ import React, { useState, useEffect, useCallback, useMemo } from 'react';
1585
+ import PropTypes from 'prop-types';
1586
+
1587
+ // Functional component with hooks
1588
+ const UserProfile = ({ userId, onUpdate }) => {
1589
+ const [user, setUser] = useState(null);
1590
+ const [loading, setLoading] = useState(true);
1591
+ const [error, setError] = useState(null);
1592
+
1593
+ // Memoized expensive calculations
1594
+ const userStats = useMemo(() => {
1595
+ if (!user) return null;
1596
+ return {
1597
+ totalPosts: user.posts?.length || 0,
1598
+ joinedDate: new Date(user.createdAt).toLocaleDateString()
1599
+ };
1600
+ }, [user]);
1601
+
1602
+ // Memoized callbacks to prevent unnecessary re-renders
1603
+ const handleUpdateUser = useCallback(async (updates) => {
1604
+ try {
1605
+ const updatedUser = await updateUser(userId, updates);
1606
+ setUser(updatedUser);
1607
+ onUpdate?.(updatedUser);
1608
+ } catch (err) {
1609
+ setError(err.message);
1610
+ }
1611
+ }, [userId, onUpdate]);
1612
+
1613
+ useEffect(() => {
1614
+ let cancelled = false;
1615
+
1616
+ const fetchUser = async () => {
1617
+ try {
1618
+ setLoading(true);
1619
+ const userData = await getUserById(userId);
1620
+ if (!cancelled) {
1621
+ setUser(userData);
1622
+ }
1623
+ } catch (err) {
1624
+ if (!cancelled) {
1625
+ setError(err.message);
1626
+ }
1627
+ } finally {
1628
+ if (!cancelled) {
1629
+ setLoading(false);
1630
+ }
1631
+ }
1632
+ };
1633
+
1634
+ fetchUser();
1635
+
1636
+ return () => {
1637
+ cancelled = true;
1638
+ };
1639
+ }, [userId]);
1640
+
1641
+ if (loading) return <LoadingSpinner />;
1642
+ if (error) return <ErrorMessage message={error} />;
1643
+ if (!user) return <NotFound />;
1644
+
1645
+ return (
1646
+ <div className="user-profile">
1647
+ <ProfileHeader user={user} stats={userStats} />
1648
+ <ProfileContent user={user} onUpdate={handleUpdateUser} />
1649
+ </div>
1650
+ );
1651
+ };
1652
+
1653
+ UserProfile.propTypes = {
1654
+ userId: PropTypes.string.isRequired,
1655
+ onUpdate: PropTypes.func
1656
+ };
1657
+
1658
+ export default React.memo(UserProfile);
1659
+ ```
1660
+
1661
+ **Custom Hooks Pattern:**
1662
+ ```jsx
1663
+ import { useState, useEffect, useCallback } from 'react';
1664
+
1665
+ // Generic API hook
1666
+ export const useApi = (url, options = {}) => {
1667
+ const [data, setData] = useState(null);
1668
+ const [loading, setLoading] = useState(true);
1669
+ const [error, setError] = useState(null);
1670
+
1671
+ const fetchData = useCallback(async () => {
1672
+ try {
1673
+ setLoading(true);
1674
+ setError(null);
1675
+ const response = await fetch(url, options);
1676
+
1677
+ if (!response.ok) {
1678
+ throw new Error(`HTTP error! status: ${response.status}`);
1679
+ }
1680
+
1681
+ const result = await response.json();
1682
+ setData(result);
1683
+ } catch (err) {
1684
+ setError(err.message);
1685
+ } finally {
1686
+ setLoading(false);
1687
+ }
1688
+ }, [url, options]);
1689
+
1690
+ useEffect(() => {
1691
+ fetchData();
1692
+ }, [fetchData]);
1693
+
1694
+ const refetch = useCallback(() => {
1695
+ fetchData();
1696
+ }, [fetchData]);
1697
+
1698
+ return { data, loading, error, refetch };
1699
+ };
1700
+
1701
+ // Local storage hook
1702
+ export const useLocalStorage = (key, initialValue) => {
1703
+ const [storedValue, setStoredValue] = useState(() => {
1704
+ try {
1705
+ const item = window.localStorage.getItem(key);
1706
+ return item ? JSON.parse(item) : initialValue;
1707
+ } catch (error) {
1708
+ console.error(`Error reading localStorage key "${key}":`, error);
1709
+ return initialValue;
1710
+ }
1711
+ });
1712
+
1713
+ const setValue = useCallback((value) => {
1714
+ try {
1715
+ const valueToStore = value instanceof Function ? value(storedValue) : value;
1716
+ setStoredValue(valueToStore);
1717
+ window.localStorage.setItem(key, JSON.stringify(valueToStore));
1718
+ } catch (error) {
1719
+ console.error(`Error setting localStorage key "${key}":`, error);
1720
+ }
1721
+ }, [key, storedValue]);
1722
+
1723
+ return [storedValue, setValue];
1724
+ };
1725
+ ```
1726
+
1727
+ **Context Pattern:**
1728
+ ```jsx
1729
+ import React, { createContext, useContext, useReducer, useCallback } from 'react';
1730
+
1731
+ // State and actions
1732
+ const initialState = {
1733
+ user: null,
1734
+ isAuthenticated: false,
1735
+ loading: false,
1736
+ error: null
1737
+ };
1738
+
1739
+ const authReducer = (state, action) => {
1740
+ switch (action.type) {
1741
+ case 'LOGIN_START':
1742
+ return { ...state, loading: true, error: null };
1743
+ case 'LOGIN_SUCCESS':
1744
+ return {
1745
+ ...state,
1746
+ user: action.payload,
1747
+ isAuthenticated: true,
1748
+ loading: false,
1749
+ error: null
1750
+ };
1751
+ case 'LOGIN_FAILURE':
1752
+ return {
1753
+ ...state,
1754
+ user: null,
1755
+ isAuthenticated: false,
1756
+ loading: false,
1757
+ error: action.payload
1758
+ };
1759
+ case 'LOGOUT':
1760
+ return initialState;
1761
+ default:
1762
+ return state;
1763
+ }
1764
+ };
1765
+
1766
+ // Context creation
1767
+ const AuthContext = createContext();
1768
+
1769
+ // Provider component
1770
+ export const AuthProvider = ({ children }) => {
1771
+ const [state, dispatch] = useReducer(authReducer, initialState);
1772
+
1773
+ const login = useCallback(async (credentials) => {
1774
+ dispatch({ type: 'LOGIN_START' });
1775
+ try {
1776
+ const user = await authService.login(credentials);
1777
+ dispatch({ type: 'LOGIN_SUCCESS', payload: user });
1778
+ return user;
1779
+ } catch (error) {
1780
+ dispatch({ type: 'LOGIN_FAILURE', payload: error.message });
1781
+ throw error;
1782
+ }
1783
+ }, []);
1784
+
1785
+ const logout = useCallback(() => {
1786
+ authService.logout();
1787
+ dispatch({ type: 'LOGOUT' });
1788
+ }, []);
1789
+
1790
+ const value = {
1791
+ ...state,
1792
+ login,
1793
+ logout
1794
+ };
1795
+
1796
+ return (
1797
+ <AuthContext.Provider value={value}>
1798
+ {children}
1799
+ </AuthContext.Provider>
1800
+ );
1801
+ };
1802
+
1803
+ // Custom hook for using auth context
1804
+ export const useAuth = () => {
1805
+ const context = useContext(AuthContext);
1806
+ if (!context) {
1807
+ throw new Error('useAuth must be used within an AuthProvider');
1808
+ }
1809
+ return context;
1810
+ };
1811
+ ```
1812
+
1813
+ **Testing with React Testing Library:**
1814
+ ```jsx
1815
+ import React from 'react';
1816
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
1817
+ import userEvent from '@testing-library/user-event';
1818
+ import { jest } from '@jest/globals';
1819
+ import UserProfile from '../UserProfile';
1820
+ import * as api from '../../services/api';
1821
+
1822
+ // Mock the API module
1823
+ jest.mock('../../services/api');
1824
+
1825
+ describe('UserProfile', () => {
1826
+ const mockUser = {
1827
+ id: '123',
1828
+ name: 'John Doe',
1829
+ email: 'john@example.com',
1830
+ posts: [{ id: 1, title: 'Test Post' }]
1831
+ };
1832
+
1833
+ beforeEach(() => {
1834
+ jest.clearAllMocks();
1835
+ });
1836
+
1837
+ test('renders user profile after loading', async () => {
1838
+ api.getUserById.mockResolvedValue(mockUser);
1839
+
1840
+ render(<UserProfile userId="123" />);
1841
+
1842
+ // Check loading state
1843
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1844
+
1845
+ // Wait for user data to load
1846
+ await waitFor(() => {
1847
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
1848
+ });
1849
+
1850
+ expect(screen.getByText('john@example.com')).toBeInTheDocument();
1851
+ expect(screen.getByText('1 Posts')).toBeInTheDocument();
1852
+ });
1853
+
1854
+ test('handles update user interaction', async () => {
1855
+ const user = userEvent.setup();
1856
+ const onUpdate = jest.fn();
1857
+
1858
+ api.getUserById.mockResolvedValue(mockUser);
1859
+ api.updateUser.mockResolvedValue({ ...mockUser, name: 'Jane Doe' });
1860
+
1861
+ render(<UserProfile userId="123" onUpdate={onUpdate} />);
1862
+
1863
+ await waitFor(() => {
1864
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
1865
+ });
1866
+
1867
+ const editButton = screen.getByRole('button', { name: /edit/i });
1868
+ await user.click(editButton);
1869
+
1870
+ const nameInput = screen.getByDisplayValue('John Doe');
1871
+ await user.clear(nameInput);
1872
+ await user.type(nameInput, 'Jane Doe');
1873
+
1874
+ const saveButton = screen.getByRole('button', { name: /save/i });
1875
+ await user.click(saveButton);
1876
+
1877
+ await waitFor(() => {
1878
+ expect(onUpdate).toHaveBeenCalledWith({ ...mockUser, name: 'Jane Doe' });
1879
+ });
1880
+ });
1881
+
1882
+ test('displays error message on API failure', async () => {
1883
+ api.getUserById.mockRejectedValue(new Error('Network error'));
1884
+
1885
+ render(<UserProfile userId="123" />);
1886
+
1887
+ await waitFor(() => {
1888
+ expect(screen.getByText(/network error/i)).toBeInTheDocument();
1889
+ });
1890
+ });
1891
+ });
1892
+ ```
1893
+
1894
+ **Performance Optimization:**
1895
+ ```jsx
1896
+ import React, { memo, lazy, Suspense } from 'react';
1897
+
1898
+ // Lazy loading for code splitting
1899
+ const LazyUserProfile = lazy(() => import('./UserProfile'));
1900
+ const LazyUserSettings = lazy(() => import('./UserSettings'));
1901
+
1902
+ // Memoized component to prevent unnecessary re-renders
1903
+ const UserCard = memo(({ user, onUpdate }) => {
1904
+ return (
1905
+ <div className="user-card">
1906
+ <h3>{user.name}</h3>
1907
+ <p>{user.email}</p>
1908
+ <button onClick={() => onUpdate(user.id)}>
1909
+ Update
1910
+ </button>
1911
+ </div>
1912
+ );
1913
+ });
1914
+
1915
+ // Main app with lazy loading
1916
+ const App = () => {
1917
+ return (
1918
+ <div className="app">
1919
+ <Suspense fallback={<div>Loading...</div>}>
1920
+ <Routes>
1921
+ <Route path="/profile" element={<LazyUserProfile />} />
1922
+ <Route path="/settings" element={<LazyUserSettings />} />
1923
+ </Routes>
1924
+ </Suspense>
1925
+ </div>
1926
+ );
1927
+ };
1928
+ ```
1929
+
1930
+ **State Management with Zustand:**
1931
+ ```jsx
1932
+ import { create } from 'zustand';
1933
+ import { devtools, persist } from 'zustand/middleware';
1934
+
1935
+ const useUserStore = create(
1936
+ devtools(
1937
+ persist(
1938
+ (set, get) => ({
1939
+ users: [],
1940
+ currentUser: null,
1941
+ loading: false,
1942
+
1943
+ fetchUsers: async () => {
1944
+ set({ loading: true });
1945
+ try {
1946
+ const users = await api.getUsers();
1947
+ set({ users, loading: false });
1948
+ } catch (error) {
1949
+ set({ loading: false });
1950
+ throw error;
1951
+ }
1952
+ },
1953
+
1954
+ setCurrentUser: (user) => set({ currentUser: user }),
1955
+
1956
+ updateUser: async (userId, updates) => {
1957
+ const updatedUser = await api.updateUser(userId, updates);
1958
+ set((state) => ({
1959
+ users: state.users.map((user) =>
1960
+ user.id === userId ? updatedUser : user
1961
+ ),
1962
+ currentUser: state.currentUser?.id === userId ? updatedUser : state.currentUser
1963
+ }));
1964
+ return updatedUser;
1965
+ }
1966
+ }),
1967
+ { name: 'user-store' }
1968
+ )
1969
+ )
1970
+ );
1971
+
1972
+ // Usage in component
1973
+ const UserList = () => {
1974
+ const { users, loading, fetchUsers } = useUserStore();
1975
+
1976
+ useEffect(() => {
1977
+ fetchUsers();
1978
+ }, [fetchUsers]);
1979
+
1980
+ if (loading) return <LoadingSpinner />;
1981
+
1982
+ return (
1983
+ <div>
1984
+ {users.map((user) => (
1985
+ <UserCard key={user.id} user={user} />
1986
+ ))}
1987
+ </div>
1988
+ );
1989
+ };
1990
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-flow-novice",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Standalone Claude Flow for beginners - AI agent orchestration made easy with enhanced TDD testing pipeline. Enhanced init command creates complete agent system, MCP configuration with 30 essential tools, and automated hooks with single-file testing, real-time coverage analysis, and advanced validation. Fully standalone with zero external dependencies, complete project setup in one command.",
5
5
  "mcpName": "io.github.ruvnet/claude-flow",
6
6
  "main": ".claude-flow-novice/dist/index.js",
@@ -174,7 +174,8 @@ claude mcp add claude-flow-novice npx claude-flow-novice mcp start
174
174
  ## Essential Commands
175
175
  - `npx claude-flow-novice status` - System health
176
176
  - `npx claude-flow-novice --help` - Available commands
177
- - `/swarm`, `/sparc`, `/hooks` - Slash commands (auto-discovered)
177
+ - `/fullstack "goal"` - Launch full-stack development team with consensus validation
178
+ - `/swarm`, `/sparc`, `/hooks` - Other slash commands (auto-discovered)
178
179
 
179
180
  ## DEVELOPMENT FLOW
180
181
  1. Execute - Primary swarm (3-8 agents) produces deliverables with confidence score