create-fluxstack 1.18.1 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LLMD/INDEX.md +1 -1
  3. package/LLMD/MAINTENANCE.md +197 -197
  4. package/LLMD/MIGRATION.md +44 -1
  5. package/LLMD/agent.md +20 -7
  6. package/LLMD/config/declarative-system.md +268 -268
  7. package/LLMD/config/environment-vars.md +3 -6
  8. package/LLMD/config/runtime-reload.md +401 -401
  9. package/LLMD/core/build-system.md +599 -599
  10. package/LLMD/core/framework-lifecycle.md +249 -229
  11. package/LLMD/core/plugin-system.md +154 -100
  12. package/LLMD/patterns/anti-patterns.md +397 -397
  13. package/LLMD/patterns/project-structure.md +264 -264
  14. package/LLMD/patterns/type-safety.md +61 -5
  15. package/LLMD/reference/cli-commands.md +31 -7
  16. package/LLMD/reference/plugin-hooks.md +4 -2
  17. package/LLMD/reference/troubleshooting.md +364 -364
  18. package/LLMD/resources/controllers.md +465 -465
  19. package/LLMD/resources/live-auth.md +178 -1
  20. package/LLMD/resources/live-binary-delta.md +3 -1
  21. package/LLMD/resources/live-components.md +1192 -1041
  22. package/LLMD/resources/live-logging.md +3 -1
  23. package/LLMD/resources/live-rooms.md +1 -1
  24. package/LLMD/resources/live-upload.md +228 -181
  25. package/LLMD/resources/plugins-external.md +8 -7
  26. package/LLMD/resources/rest-auth.md +290 -290
  27. package/LLMD/resources/routes-eden.md +254 -254
  28. package/app/client/src/App.tsx +7 -7
  29. package/app/client/src/components/AppLayout.tsx +60 -23
  30. package/app/client/src/components/ColorWheel.tsx +195 -0
  31. package/app/client/src/components/DemoPage.tsx +5 -3
  32. package/app/client/src/components/LiveUploadWidget.tsx +1 -1
  33. package/app/client/src/components/ThemePicker.tsx +307 -0
  34. package/app/client/src/config/theme.config.ts +127 -0
  35. package/app/client/src/hooks/useThemeClock.ts +66 -0
  36. package/app/client/src/index.css +193 -0
  37. package/app/client/src/lib/theme-clock.ts +201 -0
  38. package/app/client/src/live/AuthDemo.tsx +9 -9
  39. package/app/client/src/live/CounterDemo.tsx +10 -10
  40. package/app/client/src/live/FormDemo.tsx +8 -8
  41. package/app/client/src/live/PingPongDemo.tsx +10 -10
  42. package/app/client/src/live/RoomChatDemo.tsx +10 -10
  43. package/app/client/src/live/SharedCounterDemo.tsx +5 -5
  44. package/app/client/src/pages/ApiTestPage.tsx +5 -5
  45. package/app/client/src/pages/HomePage.tsx +12 -12
  46. package/app/server/index.ts +8 -0
  47. package/app/server/live/auto-generated-components.ts +1 -1
  48. package/core/build/index.ts +1 -1
  49. package/core/cli/command-registry.ts +1 -1
  50. package/core/cli/commands/build.ts +25 -6
  51. package/core/cli/commands/plugin-deps.ts +1 -2
  52. package/core/cli/generators/plugin.ts +433 -581
  53. package/core/framework/server.ts +22 -8
  54. package/core/index.ts +6 -5
  55. package/core/plugins/index.ts +71 -199
  56. package/core/plugins/types.ts +76 -461
  57. package/core/server/index.ts +1 -1
  58. package/core/utils/logger/startup-banner.ts +26 -4
  59. package/create-fluxstack.ts +216 -107
  60. package/package.json +108 -107
  61. package/tsconfig.json +2 -1
  62. package/core/plugins/config.ts +0 -356
  63. package/core/plugins/dependency-manager.ts +0 -481
  64. package/core/plugins/discovery.ts +0 -379
  65. package/core/plugins/executor.ts +0 -353
  66. package/core/plugins/manager.ts +0 -645
  67. package/core/plugins/module-resolver.ts +0 -227
  68. package/core/plugins/registry.ts +0 -913
  69. package/vitest.config.live.ts +0 -69
@@ -1,353 +0,0 @@
1
- /**
2
- * Plugin Executor
3
- * Handles plugin execution with priority and dependency resolution
4
- */
5
-
6
- import type {
7
- FluxStack,
8
- PluginHook,
9
- PluginHookResult,
10
- PluginPriority,
11
- HookExecutionOptions
12
- } from "./types"
13
- import type { Logger } from "@core/utils/logger/index"
14
- import { FluxStackError } from "@core/utils/errors"
15
-
16
- export interface PluginExecutionPlan {
17
- hook: PluginHook
18
- plugins: PluginExecutionStep[]
19
- parallel: boolean
20
- totalPlugins: number
21
- }
22
-
23
- export interface PluginExecutionStep {
24
- plugin: Plugin
25
- priority: number
26
- dependencies: string[]
27
- dependents: string[]
28
- canExecuteInParallel: boolean
29
- }
30
-
31
- type Plugin = FluxStack.Plugin
32
-
33
- export class PluginExecutor {
34
- private logger: Logger
35
-
36
- constructor(logger: Logger) {
37
- this.logger = logger
38
- }
39
-
40
- /**
41
- * Create execution plan for a hook
42
- */
43
- createExecutionPlan(
44
- plugins: Plugin[],
45
- hook: PluginHook,
46
- options: HookExecutionOptions = {}
47
- ): PluginExecutionPlan {
48
- const { parallel = false } = options
49
-
50
- // Filter plugins that implement this hook
51
- const applicablePlugins = plugins.filter(plugin => {
52
- const hookFunction = plugin[hook]
53
- return hookFunction && typeof hookFunction === 'function'
54
- })
55
-
56
- // Create execution steps
57
- const steps = applicablePlugins.map(plugin => this.createExecutionStep(plugin, plugins))
58
-
59
- // Sort by priority and dependencies
60
- const sortedSteps = this.sortExecutionSteps(steps, hook)
61
-
62
- return {
63
- hook,
64
- plugins: sortedSteps,
65
- parallel,
66
- totalPlugins: applicablePlugins.length
67
- }
68
- }
69
-
70
- /**
71
- * Execute plugins according to plan
72
- */
73
- async executePlan(
74
- plan: PluginExecutionPlan,
75
- context: unknown,
76
- executor: (plugin: Plugin, hook: PluginHook, context: unknown) => Promise<PluginHookResult>
77
- ): Promise<PluginHookResult[]> {
78
- const results: PluginHookResult[] = []
79
-
80
- this.logger.debug(`Executing plan for hook '${plan.hook}'`, {
81
- hook: plan.hook,
82
- totalPlugins: plan.totalPlugins,
83
- parallel: plan.parallel
84
- })
85
-
86
- if (plan.parallel) {
87
- // Execute in parallel groups based on dependencies
88
- const groups = this.createParallelGroups(plan.plugins)
89
-
90
- for (const group of groups) {
91
- const groupPromises = group.map(step =>
92
- executor(step.plugin, plan.hook, context)
93
- )
94
-
95
- const groupResults = await Promise.allSettled(groupPromises)
96
-
97
- for (let i = 0; i < groupResults.length; i++) {
98
- const result = groupResults[i]
99
- if (result.status === 'fulfilled') {
100
- results.push(result.value)
101
- } else {
102
- results.push({
103
- success: false,
104
- error: result.reason,
105
- duration: 0,
106
- plugin: group[i].plugin.name,
107
- hook: plan.hook
108
- })
109
- }
110
- }
111
- }
112
- } else {
113
- // Execute sequentially
114
- for (const step of plan.plugins) {
115
- const result = await executor(step.plugin, plan.hook, context)
116
- results.push(result)
117
- }
118
- }
119
-
120
- return results
121
- }
122
-
123
- /**
124
- * Validate execution plan
125
- */
126
- validateExecutionPlan(plan: PluginExecutionPlan): { valid: boolean; errors: string[] } {
127
- const errors: string[] = []
128
-
129
- // Check for circular dependencies
130
- const visited = new Set<string>()
131
- const visiting = new Set<string>()
132
-
133
- const checkCircular = (step: PluginExecutionStep) => {
134
- if (visiting.has(step.plugin.name)) {
135
- errors.push(`Circular dependency detected involving plugin '${step.plugin.name}'`)
136
- return
137
- }
138
-
139
- if (visited.has(step.plugin.name)) {
140
- return
141
- }
142
-
143
- visiting.add(step.plugin.name)
144
-
145
- for (const depName of step.dependencies) {
146
- const depStep = plan.plugins.find(s => s.plugin.name === depName)
147
- if (depStep) {
148
- checkCircular(depStep)
149
- }
150
- }
151
-
152
- visiting.delete(step.plugin.name)
153
- visited.add(step.plugin.name)
154
- }
155
-
156
- for (const step of plan.plugins) {
157
- checkCircular(step)
158
- }
159
-
160
- // Check for missing dependencies
161
- for (const step of plan.plugins) {
162
- for (const depName of step.dependencies) {
163
- const depExists = plan.plugins.some(s => s.plugin.name === depName)
164
- if (!depExists) {
165
- errors.push(`Plugin '${step.plugin.name}' depends on '${depName}' which is not available`)
166
- }
167
- }
168
- }
169
-
170
- return {
171
- valid: errors.length === 0,
172
- errors
173
- }
174
- }
175
-
176
- /**
177
- * Create execution step for a plugin
178
- */
179
- private createExecutionStep(plugin: Plugin, allPlugins: Plugin[]): PluginExecutionStep {
180
- const priority = this.normalizePriority(plugin.priority)
181
- const dependencies = plugin.dependencies || []
182
-
183
- // Find dependents
184
- const dependents = allPlugins
185
- .filter(p => p.dependencies?.includes(plugin.name))
186
- .map(p => p.name)
187
-
188
- // Determine if can execute in parallel
189
- const canExecuteInParallel = dependencies.length === 0
190
-
191
- return {
192
- plugin,
193
- priority,
194
- dependencies,
195
- dependents,
196
- canExecuteInParallel
197
- }
198
- }
199
-
200
- /**
201
- * Sort execution steps by priority and dependencies
202
- */
203
- private sortExecutionSteps(steps: PluginExecutionStep[], hook: PluginHook): PluginExecutionStep[] {
204
- // Topological sort with priority consideration
205
- const sorted: PluginExecutionStep[] = []
206
- const visited = new Set<string>()
207
- const visiting = new Set<string>()
208
-
209
- const visit = (step: PluginExecutionStep) => {
210
- if (visiting.has(step.plugin.name)) {
211
- throw new FluxStackError(
212
- `Circular dependency detected involving plugin '${step.plugin.name}' for hook '${hook}'`,
213
- 'CIRCULAR_DEPENDENCY',
214
- 400
215
- )
216
- }
217
-
218
- if (visited.has(step.plugin.name)) {
219
- return
220
- }
221
-
222
- visiting.add(step.plugin.name)
223
-
224
- // Visit dependencies first
225
- for (const depName of step.dependencies) {
226
- const depStep = steps.find(s => s.plugin.name === depName)
227
- if (depStep) {
228
- visit(depStep)
229
- }
230
- }
231
-
232
- visiting.delete(step.plugin.name)
233
- visited.add(step.plugin.name)
234
- sorted.push(step)
235
- }
236
-
237
- // Sort by priority first, then visit
238
- const prioritySorted = [...steps].sort((a, b) => b.priority - a.priority)
239
-
240
- for (const step of prioritySorted) {
241
- visit(step)
242
- }
243
-
244
- return sorted
245
- }
246
-
247
- /**
248
- * Create parallel execution groups
249
- */
250
- private createParallelGroups(steps: PluginExecutionStep[]): PluginExecutionStep[][] {
251
- const groups: PluginExecutionStep[][] = []
252
- const processed = new Set<string>()
253
-
254
- while (processed.size < steps.length) {
255
- const currentGroup: PluginExecutionStep[] = []
256
-
257
- for (const step of steps) {
258
- if (processed.has(step.plugin.name)) {
259
- continue
260
- }
261
-
262
- // Check if all dependencies are already processed
263
- const canExecute = step.dependencies.every(dep => processed.has(dep))
264
-
265
- if (canExecute) {
266
- currentGroup.push(step)
267
- processed.add(step.plugin.name)
268
- }
269
- }
270
-
271
- if (currentGroup.length === 0) {
272
- // This shouldn't happen if dependencies are valid
273
- const remaining = steps.filter(s => !processed.has(s.plugin.name))
274
- throw new FluxStackError(
275
- `Unable to resolve dependencies for plugins: ${remaining.map(s => s.plugin.name).join(', ')}`,
276
- 'DEPENDENCY_RESOLUTION_ERROR',
277
- 400
278
- )
279
- }
280
-
281
- // Sort group by priority
282
- currentGroup.sort((a, b) => b.priority - a.priority)
283
- groups.push(currentGroup)
284
- }
285
-
286
- return groups
287
- }
288
-
289
- /**
290
- * Normalize plugin priority to numeric value
291
- */
292
- private normalizePriority(priority?: number | PluginPriority): number {
293
- if (typeof priority === 'number') {
294
- return priority
295
- }
296
-
297
- switch (priority) {
298
- case 'highest': return 1000
299
- case 'high': return 750
300
- case 'normal': return 500
301
- case 'low': return 250
302
- case 'lowest': return 0
303
- default: return 500 // default to normal
304
- }
305
- }
306
- }
307
-
308
- /**
309
- * Plugin execution statistics
310
- */
311
- export interface PluginExecutionStats {
312
- totalPlugins: number
313
- successfulPlugins: number
314
- failedPlugins: number
315
- totalDuration: number
316
- averageDuration: number
317
- slowestPlugin: { name: string; duration: number } | null
318
- fastestPlugin: { name: string; duration: number } | null
319
- }
320
-
321
- /**
322
- * Calculate execution statistics
323
- */
324
- export function calculateExecutionStats(results: PluginHookResult[]): PluginExecutionStats {
325
- const totalPlugins = results.length
326
- const successfulPlugins = results.filter(r => r.success).length
327
- const failedPlugins = totalPlugins - successfulPlugins
328
- const totalDuration = results.reduce((sum, r) => sum + r.duration, 0)
329
- const averageDuration = totalPlugins > 0 ? totalDuration / totalPlugins : 0
330
-
331
- let slowestPlugin: { name: string; duration: number } | null = null
332
- let fastestPlugin: { name: string; duration: number } | null = null
333
-
334
- for (const result of results) {
335
- if (!slowestPlugin || result.duration > slowestPlugin.duration) {
336
- slowestPlugin = { name: result.plugin, duration: result.duration }
337
- }
338
-
339
- if (!fastestPlugin || result.duration < fastestPlugin.duration) {
340
- fastestPlugin = { name: result.plugin, duration: result.duration }
341
- }
342
- }
343
-
344
- return {
345
- totalPlugins,
346
- successfulPlugins,
347
- failedPlugins,
348
- totalDuration,
349
- averageDuration,
350
- slowestPlugin,
351
- fastestPlugin
352
- }
353
- }