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.
- package/CHANGELOG.md +132 -0
- package/LLMD/INDEX.md +1 -1
- package/LLMD/MAINTENANCE.md +197 -197
- package/LLMD/MIGRATION.md +44 -1
- package/LLMD/agent.md +20 -7
- package/LLMD/config/declarative-system.md +268 -268
- package/LLMD/config/environment-vars.md +3 -6
- package/LLMD/config/runtime-reload.md +401 -401
- package/LLMD/core/build-system.md +599 -599
- package/LLMD/core/framework-lifecycle.md +249 -229
- package/LLMD/core/plugin-system.md +154 -100
- package/LLMD/patterns/anti-patterns.md +397 -397
- package/LLMD/patterns/project-structure.md +264 -264
- package/LLMD/patterns/type-safety.md +61 -5
- package/LLMD/reference/cli-commands.md +31 -7
- package/LLMD/reference/plugin-hooks.md +4 -2
- package/LLMD/reference/troubleshooting.md +364 -364
- package/LLMD/resources/controllers.md +465 -465
- package/LLMD/resources/live-auth.md +178 -1
- package/LLMD/resources/live-binary-delta.md +3 -1
- package/LLMD/resources/live-components.md +1192 -1041
- package/LLMD/resources/live-logging.md +3 -1
- package/LLMD/resources/live-rooms.md +1 -1
- package/LLMD/resources/live-upload.md +228 -181
- package/LLMD/resources/plugins-external.md +8 -7
- package/LLMD/resources/rest-auth.md +290 -290
- package/LLMD/resources/routes-eden.md +254 -254
- package/app/client/src/App.tsx +7 -7
- package/app/client/src/components/AppLayout.tsx +60 -23
- package/app/client/src/components/ColorWheel.tsx +195 -0
- package/app/client/src/components/DemoPage.tsx +5 -3
- package/app/client/src/components/LiveUploadWidget.tsx +1 -1
- package/app/client/src/components/ThemePicker.tsx +307 -0
- package/app/client/src/config/theme.config.ts +127 -0
- package/app/client/src/hooks/useThemeClock.ts +66 -0
- package/app/client/src/index.css +193 -0
- package/app/client/src/lib/theme-clock.ts +201 -0
- package/app/client/src/live/AuthDemo.tsx +9 -9
- package/app/client/src/live/CounterDemo.tsx +10 -10
- package/app/client/src/live/FormDemo.tsx +8 -8
- package/app/client/src/live/PingPongDemo.tsx +10 -10
- package/app/client/src/live/RoomChatDemo.tsx +10 -10
- package/app/client/src/live/SharedCounterDemo.tsx +5 -5
- package/app/client/src/pages/ApiTestPage.tsx +5 -5
- package/app/client/src/pages/HomePage.tsx +12 -12
- package/app/server/index.ts +8 -0
- package/app/server/live/auto-generated-components.ts +1 -1
- package/core/build/index.ts +1 -1
- package/core/cli/command-registry.ts +1 -1
- package/core/cli/commands/build.ts +25 -6
- package/core/cli/commands/plugin-deps.ts +1 -2
- package/core/cli/generators/plugin.ts +433 -581
- package/core/framework/server.ts +22 -8
- package/core/index.ts +6 -5
- package/core/plugins/index.ts +71 -199
- package/core/plugins/types.ts +76 -461
- package/core/server/index.ts +1 -1
- package/core/utils/logger/startup-banner.ts +26 -4
- package/create-fluxstack.ts +216 -107
- package/package.json +108 -107
- package/tsconfig.json +2 -1
- package/core/plugins/config.ts +0 -356
- package/core/plugins/dependency-manager.ts +0 -481
- package/core/plugins/discovery.ts +0 -379
- package/core/plugins/executor.ts +0 -353
- package/core/plugins/manager.ts +0 -645
- package/core/plugins/module-resolver.ts +0 -227
- package/core/plugins/registry.ts +0 -913
- package/vitest.config.live.ts +0 -69
package/core/plugins/executor.ts
DELETED
|
@@ -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
|
-
}
|