@geenius/ai-workflow 0.1.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/.changeset/config.json +11 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +16 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +11 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +10 -0
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/ci.yml +23 -0
- package/.github/workflows/release.yml +29 -0
- package/.nvmrc +1 -0
- package/.project/ACCOUNT.yaml +4 -0
- package/.project/IDEAS.yaml +7 -0
- package/.project/PROJECT.yaml +11 -0
- package/.project/ROADMAP.yaml +15 -0
- package/CHANGELOG.md +11 -0
- package/CODE_OF_CONDUCT.md +16 -0
- package/CONTRIBUTING.md +26 -0
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/SECURITY.md +15 -0
- package/SUPPORT.md +8 -0
- package/package.json +74 -0
- package/packages/convex/README.md +1 -0
- package/packages/convex/package.json +12 -0
- package/packages/convex/src/convex.config.ts +3 -0
- package/packages/convex/src/index.ts +3 -0
- package/packages/convex/src/mutations.ts +36 -0
- package/packages/convex/src/queries.ts +19 -0
- package/packages/convex/src/schema.ts +24 -0
- package/packages/convex/tsconfig.json +25 -0
- package/packages/react/README.md +1 -0
- package/packages/react/package.json +46 -0
- package/packages/react/src/components/ApprovalModal.tsx +47 -0
- package/packages/react/src/components/StepConfigPanel.tsx +67 -0
- package/packages/react/src/components/StepConnector.tsx +47 -0
- package/packages/react/src/components/StepNode.tsx +38 -0
- package/packages/react/src/components/StepPalette.tsx +48 -0
- package/packages/react/src/components/WorkflowCanvas.tsx +42 -0
- package/packages/react/src/components/WorkflowRunPanel.tsx +64 -0
- package/packages/react/src/components/WorkflowToolbar.tsx +43 -0
- package/packages/react/src/components/index.ts +9 -0
- package/packages/react/src/hooks/index.ts +10 -0
- package/packages/react/src/hooks/useApprovalGate.ts +59 -0
- package/packages/react/src/hooks/useWorkflow.ts +39 -0
- package/packages/react/src/hooks/useWorkflowBuilder.ts +121 -0
- package/packages/react/src/hooks/useWorkflowRun.ts +75 -0
- package/packages/react/src/hooks/useWorkflowStep.ts +52 -0
- package/packages/react/src/hooks/useWorkflowTemplates.ts +54 -0
- package/packages/react/src/index.ts +16 -0
- package/packages/react/src/pages/WorkflowBuilderPage.tsx +81 -0
- package/packages/react/src/pages/WorkflowRunsPage.tsx +59 -0
- package/packages/react/src/pages/index.ts +3 -0
- package/packages/react/tsconfig.json +1 -0
- package/packages/react/tsup.config.ts +7 -0
- package/packages/react-css/README.md +1 -0
- package/packages/react-css/package.json +44 -0
- package/packages/react-css/src/components/ApprovalModal.tsx +6 -0
- package/packages/react-css/src/components/StepConfigPanel.tsx +7 -0
- package/packages/react-css/src/components/StepConnector.tsx +6 -0
- package/packages/react-css/src/components/StepNode.tsx +7 -0
- package/packages/react-css/src/components/StepPalette.tsx +6 -0
- package/packages/react-css/src/components/WorkflowCanvas.tsx +6 -0
- package/packages/react-css/src/components/WorkflowRunPanel.tsx +9 -0
- package/packages/react-css/src/components/WorkflowToolbar.tsx +4 -0
- package/packages/react-css/src/components/index.ts +9 -0
- package/packages/react-css/src/hooks/index.ts +3 -0
- package/packages/react-css/src/hooks/useWorkflow.ts +39 -0
- package/packages/react-css/src/hooks/useWorkflowBuilder.ts +121 -0
- package/packages/react-css/src/index.ts +7 -0
- package/packages/react-css/src/pages/WorkflowBuilderPage.tsx +16 -0
- package/packages/react-css/src/pages/WorkflowRunsPage.tsx +6 -0
- package/packages/react-css/src/pages/index.ts +3 -0
- package/packages/react-css/src/styles.css +945 -0
- package/packages/react-css/tsconfig.json +26 -0
- package/packages/react-css/tsup.config.ts +2 -0
- package/packages/shared/README.md +1 -0
- package/packages/shared/package.json +56 -0
- package/packages/shared/src/__tests__/ai-workflow.test.ts +217 -0
- package/packages/shared/src/config.ts +49 -0
- package/packages/shared/src/convex/index.ts +2 -0
- package/packages/shared/src/convex/schemas.ts +42 -0
- package/packages/shared/src/engine.test.ts +1 -0
- package/packages/shared/src/engine.ts +295 -0
- package/packages/shared/src/index.ts +43 -0
- package/packages/shared/src/steps.ts +68 -0
- package/packages/shared/src/templates.ts +172 -0
- package/packages/shared/src/types.ts +237 -0
- package/packages/shared/src/utils/cost.ts +79 -0
- package/packages/shared/src/utils/dag.ts +133 -0
- package/packages/shared/src/utils/index.ts +5 -0
- package/packages/shared/src/utils/interpolation.ts +53 -0
- package/packages/shared/src/validators.ts +215 -0
- package/packages/shared/tsconfig.json +1 -0
- package/packages/shared/tsup.config.ts +5 -0
- package/packages/shared/vitest.config.ts +4 -0
- package/packages/solidjs/README.md +1 -0
- package/packages/solidjs/package.json +45 -0
- package/packages/solidjs/src/components/ApprovalModal.tsx +18 -0
- package/packages/solidjs/src/components/StepConfigPanel.tsx +14 -0
- package/packages/solidjs/src/components/StepConnector.tsx +11 -0
- package/packages/solidjs/src/components/StepNode.tsx +12 -0
- package/packages/solidjs/src/components/StepPalette.tsx +22 -0
- package/packages/solidjs/src/components/WorkflowCanvas.tsx +23 -0
- package/packages/solidjs/src/components/WorkflowRunPanel.tsx +18 -0
- package/packages/solidjs/src/components/WorkflowToolbar.tsx +13 -0
- package/packages/solidjs/src/components/index.ts +9 -0
- package/packages/solidjs/src/index.ts +7 -0
- package/packages/solidjs/src/pages/WorkflowBuilderPage.tsx +37 -0
- package/packages/solidjs/src/pages/WorkflowRunsPage.tsx +20 -0
- package/packages/solidjs/src/pages/index.ts +3 -0
- package/packages/solidjs/src/primitives/createApprovalGate.ts +29 -0
- package/packages/solidjs/src/primitives/createWorkflow.ts +28 -0
- package/packages/solidjs/src/primitives/createWorkflowBuilder.ts +56 -0
- package/packages/solidjs/src/primitives/createWorkflowRun.ts +32 -0
- package/packages/solidjs/src/primitives/createWorkflowStep.ts +23 -0
- package/packages/solidjs/src/primitives/createWorkflowTemplates.ts +28 -0
- package/packages/solidjs/src/primitives/index.ts +8 -0
- package/packages/solidjs/tsconfig.json +1 -0
- package/packages/solidjs/tsup.config.ts +7 -0
- package/packages/solidjs-css/README.md +1 -0
- package/packages/solidjs-css/package.json +43 -0
- package/packages/solidjs-css/src/components/ApprovalModal.tsx +6 -0
- package/packages/solidjs-css/src/components/StepConfigPanel.tsx +7 -0
- package/packages/solidjs-css/src/components/StepConnector.tsx +6 -0
- package/packages/solidjs-css/src/components/StepNode.tsx +7 -0
- package/packages/solidjs-css/src/components/StepPalette.tsx +7 -0
- package/packages/solidjs-css/src/components/WorkflowCanvas.tsx +7 -0
- package/packages/solidjs-css/src/components/WorkflowRunPanel.tsx +8 -0
- package/packages/solidjs-css/src/components/WorkflowToolbar.tsx +5 -0
- package/packages/solidjs-css/src/components/index.ts +9 -0
- package/packages/solidjs-css/src/index.ts +7 -0
- package/packages/solidjs-css/src/pages/WorkflowBuilderPage.tsx +2 -0
- package/packages/solidjs-css/src/pages/WorkflowRunsPage.tsx +7 -0
- package/packages/solidjs-css/src/pages/index.ts +3 -0
- package/packages/solidjs-css/src/primitives/createWorkflow.ts +28 -0
- package/packages/solidjs-css/src/primitives/createWorkflowBuilder.ts +56 -0
- package/packages/solidjs-css/src/primitives/index.ts +1 -0
- package/packages/solidjs-css/src/styles.css +945 -0
- package/packages/solidjs-css/tsconfig.json +27 -0
- package/packages/solidjs-css/tsup.config.ts +2 -0
- package/pnpm-workspace.yaml +2 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// @geenius-ai-workflow/shared — src/validators.ts
|
|
2
|
+
/**
|
|
3
|
+
* Zod schemas for workflow definition and run validation.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod/v4'
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Step Config Schemas
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
export const llmCallConfigSchema = z.object({
|
|
12
|
+
type: z.literal('llm-call'),
|
|
13
|
+
model: z.string().optional(),
|
|
14
|
+
systemPrompt: z.string().min(1, 'System prompt is required'),
|
|
15
|
+
userPromptTemplate: z.string().min(1, 'User prompt template is required'),
|
|
16
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
17
|
+
maxTokens: z.number().int().positive().optional(),
|
|
18
|
+
parseJson: z.boolean().optional(),
|
|
19
|
+
outputVar: z.string().min(1, 'Output variable name is required'),
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export const transformConfigSchema = z.object({
|
|
23
|
+
type: z.literal('transform'),
|
|
24
|
+
expression: z.string().min(1, 'Expression is required'),
|
|
25
|
+
inputVars: z.array(z.string()).min(1, 'At least one input variable is required'),
|
|
26
|
+
outputVar: z.string().min(1),
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
export const conditionConfigSchema = z.object({
|
|
30
|
+
type: z.literal('condition'),
|
|
31
|
+
expression: z.string().min(1),
|
|
32
|
+
trueStepId: z.string().min(1),
|
|
33
|
+
falseStepId: z.string().min(1),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
export const humanApprovalConfigSchema = z.object({
|
|
37
|
+
type: z.literal('human-approval'),
|
|
38
|
+
message: z.string().min(1, 'Approval message is required'),
|
|
39
|
+
approvers: z.array(z.string()).optional(),
|
|
40
|
+
autoApproveAfterMs: z.number().positive().optional(),
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
export const webhookConfigSchema = z.object({
|
|
44
|
+
type: z.literal('webhook'),
|
|
45
|
+
url: z.string().url('Valid URL required'),
|
|
46
|
+
method: z.enum(['GET', 'POST', 'PUT', 'DELETE']),
|
|
47
|
+
headers: z.record(z.string()).optional(),
|
|
48
|
+
bodyTemplate: z.string().optional(),
|
|
49
|
+
outputVar: z.string().min(1),
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
export const delayConfigSchema = z.object({
|
|
53
|
+
type: z.literal('delay'),
|
|
54
|
+
durationMs: z.number().int().positive('Duration must be positive'),
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
export const parallelConfigSchema = z.object({
|
|
58
|
+
type: z.literal('parallel'),
|
|
59
|
+
stepIds: z.array(z.string()).min(2, 'Parallel needs at least 2 steps'),
|
|
60
|
+
failurePolicy: z.enum(['fail-fast', 'continue']),
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
export const loopConfigSchema = z.object({
|
|
64
|
+
type: z.literal('loop'),
|
|
65
|
+
stepIds: z.array(z.string()).min(1),
|
|
66
|
+
iterateVar: z.string().min(1),
|
|
67
|
+
itemVar: z.string().min(1),
|
|
68
|
+
maxIterations: z.number().int().positive().optional(),
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
export const subWorkflowConfigSchema = z.object({
|
|
72
|
+
type: z.literal('sub-workflow'),
|
|
73
|
+
workflowId: z.string().min(1),
|
|
74
|
+
inputMapping: z.record(z.string()),
|
|
75
|
+
outputVar: z.string().min(1),
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
export const customStepConfigSchema = z.object({
|
|
79
|
+
type: z.literal('custom'),
|
|
80
|
+
handler: z.string().min(1, 'Handler name is required'),
|
|
81
|
+
params: z.record(z.unknown()),
|
|
82
|
+
outputVar: z.string().optional(),
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
export const stepConfigSchema = z.discriminatedUnion('type', [
|
|
86
|
+
llmCallConfigSchema,
|
|
87
|
+
transformConfigSchema,
|
|
88
|
+
conditionConfigSchema,
|
|
89
|
+
humanApprovalConfigSchema,
|
|
90
|
+
webhookConfigSchema,
|
|
91
|
+
delayConfigSchema,
|
|
92
|
+
parallelConfigSchema,
|
|
93
|
+
loopConfigSchema,
|
|
94
|
+
subWorkflowConfigSchema,
|
|
95
|
+
customStepConfigSchema,
|
|
96
|
+
])
|
|
97
|
+
|
|
98
|
+
// ============================================================================
|
|
99
|
+
// Step Definition Schema
|
|
100
|
+
// ============================================================================
|
|
101
|
+
|
|
102
|
+
export const workflowStepDefSchema = z.object({
|
|
103
|
+
id: z.string().min(1),
|
|
104
|
+
name: z.string().min(1, 'Step name is required'),
|
|
105
|
+
type: z.enum(['llm-call', 'transform', 'condition', 'human-approval', 'webhook', 'delay', 'parallel', 'loop', 'sub-workflow', 'custom']),
|
|
106
|
+
config: stepConfigSchema,
|
|
107
|
+
position: z.object({ x: z.number(), y: z.number() }).optional(),
|
|
108
|
+
optional: z.boolean().optional(),
|
|
109
|
+
retries: z.object({ maxAttempts: z.number().int().positive(), backoffMs: z.number().positive() }).optional(),
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// ============================================================================
|
|
113
|
+
// Connection Schema
|
|
114
|
+
// ============================================================================
|
|
115
|
+
|
|
116
|
+
export const stepConnectionSchema = z.object({
|
|
117
|
+
fromStepId: z.string().min(1),
|
|
118
|
+
toStepId: z.string().min(1),
|
|
119
|
+
label: z.string().optional(),
|
|
120
|
+
condition: z.string().optional(),
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// ============================================================================
|
|
124
|
+
// Variable Schema
|
|
125
|
+
// ============================================================================
|
|
126
|
+
|
|
127
|
+
export const workflowVariableSchema = z.object({
|
|
128
|
+
name: z.string().min(1),
|
|
129
|
+
type: z.enum(['string', 'number', 'boolean', 'object', 'array']),
|
|
130
|
+
description: z.string().optional(),
|
|
131
|
+
required: z.boolean().optional(),
|
|
132
|
+
default: z.unknown().optional(),
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// ============================================================================
|
|
136
|
+
// Workflow Definition Schema
|
|
137
|
+
// ============================================================================
|
|
138
|
+
|
|
139
|
+
export const workflowDefinitionSchema = z.object({
|
|
140
|
+
id: z.string().min(1),
|
|
141
|
+
name: z.string().min(1, 'Workflow name is required').max(120, 'Name too long'),
|
|
142
|
+
description: z.string().max(2000).optional(),
|
|
143
|
+
version: z.number().int().positive(),
|
|
144
|
+
status: z.enum(['draft', 'active', 'paused', 'archived']),
|
|
145
|
+
steps: z.array(workflowStepDefSchema).min(1, 'At least one step is required'),
|
|
146
|
+
connections: z.array(stepConnectionSchema),
|
|
147
|
+
inputSchema: z.array(workflowVariableSchema).optional(),
|
|
148
|
+
variables: z.record(z.unknown()).optional(),
|
|
149
|
+
tags: z.array(z.string()).optional(),
|
|
150
|
+
createdBy: z.string(),
|
|
151
|
+
createdAt: z.number(),
|
|
152
|
+
updatedAt: z.number(),
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
// ============================================================================
|
|
156
|
+
// Run Schema
|
|
157
|
+
// ============================================================================
|
|
158
|
+
|
|
159
|
+
export const stepResultSchema = z.object({
|
|
160
|
+
stepId: z.string(),
|
|
161
|
+
stepName: z.string(),
|
|
162
|
+
type: z.enum(['llm-call', 'transform', 'condition', 'human-approval', 'webhook', 'delay', 'parallel', 'loop', 'sub-workflow', 'custom']),
|
|
163
|
+
status: z.enum(['pending', 'running', 'completed', 'failed', 'skipped', 'waiting-approval']),
|
|
164
|
+
input: z.record(z.unknown()).optional(),
|
|
165
|
+
output: z.unknown().optional(),
|
|
166
|
+
error: z.string().optional(),
|
|
167
|
+
durationMs: z.number(),
|
|
168
|
+
tokens: z.number().optional(),
|
|
169
|
+
costUsd: z.number().optional(),
|
|
170
|
+
startedAt: z.number(),
|
|
171
|
+
completedAt: z.number().optional(),
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
export const workflowRunSchema = z.object({
|
|
175
|
+
id: z.string(),
|
|
176
|
+
workflowId: z.string(),
|
|
177
|
+
workflowVersion: z.number(),
|
|
178
|
+
status: z.enum(['pending', 'running', 'paused', 'completed', 'failed', 'cancelled']),
|
|
179
|
+
input: z.record(z.unknown()),
|
|
180
|
+
variables: z.record(z.unknown()),
|
|
181
|
+
stepResults: z.array(stepResultSchema),
|
|
182
|
+
currentStepIndex: z.number(),
|
|
183
|
+
error: z.string().optional(),
|
|
184
|
+
triggeredBy: z.string(),
|
|
185
|
+
startedAt: z.number(),
|
|
186
|
+
completedAt: z.number().optional(),
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
// ============================================================================
|
|
190
|
+
// Validation helpers
|
|
191
|
+
// ============================================================================
|
|
192
|
+
|
|
193
|
+
/** Validate a WorkflowDefinition, returning { success, data?, error? } */
|
|
194
|
+
export function validateWorkflow(data: unknown) {
|
|
195
|
+
return workflowDefinitionSchema.safeParse(data)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Validate a WorkflowRun, returning { success, data?, error? } */
|
|
199
|
+
export function validateRun(data: unknown) {
|
|
200
|
+
return workflowRunSchema.safeParse(data)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Validate step connections reference valid step IDs */
|
|
204
|
+
export function validateConnectionIntegrity(
|
|
205
|
+
steps: Array<{ id: string }>,
|
|
206
|
+
connections: Array<{ fromStepId: string; toStepId: string }>,
|
|
207
|
+
): string[] {
|
|
208
|
+
const stepIds = new Set(steps.map(s => s.id))
|
|
209
|
+
const errors: string[] = []
|
|
210
|
+
for (const conn of connections) {
|
|
211
|
+
if (!stepIds.has(conn.fromStepId)) errors.push(`Connection references unknown source step: ${conn.fromStepId}`)
|
|
212
|
+
if (!stepIds.has(conn.toStepId)) errors.push(`Connection references unknown target step: ${conn.toStepId}`)
|
|
213
|
+
}
|
|
214
|
+
return errors
|
|
215
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"compilerOptions":{"target":"ES2022","module":"ESNext","moduleResolution":"bundler","declaration":true,"declarationMap":true,"sourceMap":true,"outDir":"./dist","rootDir":"./src","strict":true,"esModuleInterop":true,"skipLibCheck":true,"forceConsistentCasingInFileNames":true,"resolveJsonModule":true,"isolatedModules":true},"include":["src"],"exclude":["node_modules","dist"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# ✦ @geenius-ai-workflow/solidjs\n\n> Geenius AI Workflow — SolidJS primitives & components\n\n---\n\n## Overview\nBuilt with Steve Jobs-level minimalism and Jony Ive-level craftsmanship, this package is designed to deliver unparalleled developer experience (DX) and rock-solid performance.\n\n## Installation\n\n```bash\npnpm add @geenius-ai-workflow/solidjs\n```\n\n## Usage\n\n```typescript\nimport { init } from '@geenius-ai-workflow/solidjs';\n\n// Initialize the module with absolute precision\ninit({\n mode: 'premium',\n});\n```\n\n## Architecture\n- **Zero-config**: It just works.\n- **Strictly Typed**: Fully written in TypeScript for flawless IntelliSense.\n- **Framework Agnostic**: seamlessly integrates into the Geenius ecosystem.\n\n---\n\n*Designed by Antigravity HQ*\n
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@geenius-ai-workflow/solidjs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Geenius AI Workflow \u2014 SolidJS primitives & components",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"clean": "rm -rf dist",
|
|
23
|
+
"type-check": "tsc --noEmit",
|
|
24
|
+
"prepublishOnly": "pnpm clean && pnpm build"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@geenius-ai-workflow/shared": "workspace:*"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"solid-js": "^1.9.0",
|
|
31
|
+
"tsup": "^8.5.1",
|
|
32
|
+
"typescript": "~5.9.3"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"solid-js": ">=1.8.0"
|
|
36
|
+
},
|
|
37
|
+
"author": "Antigravity HQ",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=20.0.0"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — components/ApprovalModal.tsx
|
|
2
|
+
import { Show, For } from 'solid-js'
|
|
3
|
+
import type { ApprovalRequest } from '../primitives/createApprovalGate'
|
|
4
|
+
|
|
5
|
+
export function ApprovalModal(props: { request: ApprovalRequest | null; onApprove: (id: string) => void; onReject: (id: string) => void }) {
|
|
6
|
+
return (
|
|
7
|
+
<Show when={props.request}>{(req) => (
|
|
8
|
+
<div data-workflow="approval-modal" role="dialog" aria-modal="true">
|
|
9
|
+
<div data-workflow="approval-overlay" />
|
|
10
|
+
<div data-workflow="approval-dialog">
|
|
11
|
+
<div data-workflow="approval-header"><span data-workflow="approval-icon">👤</span><h3 data-workflow="approval-title">Approval Required</h3></div>
|
|
12
|
+
<div data-workflow="approval-body"><p data-workflow="approval-message">{req().message}</p>
|
|
13
|
+
<Show when={req().approvers && req().approvers!.length > 0}><div data-workflow="approval-approvers"><For each={req().approvers!}>{(a) => <span data-workflow="approval-approver-badge">{a}</span>}</For></div></Show></div>
|
|
14
|
+
<div data-workflow="approval-actions"><button data-workflow="approval-reject" onClick={() => props.onReject(req().id)}>✕ Reject</button><button data-workflow="approval-approve" onClick={() => props.onApprove(req().id)}>✓ Approve</button></div>
|
|
15
|
+
</div>
|
|
16
|
+
</div>)}</Show>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — components/StepConfigPanel.tsx
|
|
2
|
+
import { createSignal, Show } from 'solid-js'
|
|
3
|
+
import type { WorkflowStepDef } from '@geenius-ai-workflow/shared'
|
|
4
|
+
|
|
5
|
+
export function StepConfigPanel(props: { step: WorkflowStepDef; onUpdate: (id: string, u: Partial<WorkflowStepDef>) => void; onDelete: (id: string) => void; onClose: () => void }) {
|
|
6
|
+
const [name, setName] = createSignal(props.step.name)
|
|
7
|
+
return (
|
|
8
|
+
<div data-workflow="config-panel" role="complementary"><div data-workflow="config-header"><h3 data-workflow="config-title">Configure Step</h3><button data-workflow="config-close" onClick={props.onClose}>✕</button></div>
|
|
9
|
+
<div data-workflow="config-body"><label data-workflow="config-label">Step Name<input data-workflow="config-input" value={name()} onInput={(e) => setName(e.currentTarget.value)} onBlur={() => { if (name().trim() && name() !== props.step.name) props.onUpdate(props.step.id, { name: name().trim() }) }} /></label>
|
|
10
|
+
<div data-workflow="config-field"><span data-workflow="config-field-label">Type</span><span data-workflow="config-field-value">{props.step.type}</span></div>
|
|
11
|
+
<pre data-workflow="config-json-view">{JSON.stringify(props.step.config, null, 2)}</pre></div>
|
|
12
|
+
<div data-workflow="config-footer"><button data-workflow="config-delete" onClick={() => { props.onDelete(props.step.id); props.onClose() }}>🗑 Delete</button></div></div>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — components/StepConnector.tsx
|
|
2
|
+
const W = 200, H = 80
|
|
3
|
+
export function StepConnector(props: { from: { x: number; y: number }; to: { x: number; y: number }; label?: string; isActive?: boolean }) {
|
|
4
|
+
const x1 = () => props.from.x + W, y1 = () => props.from.y + H / 2, x2 = () => props.to.x, y2 = () => props.to.y + H / 2, mx = () => (x1() + x2()) / 2
|
|
5
|
+
return (
|
|
6
|
+
<g data-workflow="connector" data-active={props.isActive || undefined}>
|
|
7
|
+
<path d={`M ${x1()} ${y1()} C ${mx()} ${y1()}, ${mx()} ${y2()}, ${x2()} ${y2()}`} fill="none" stroke={props.isActive ? 'oklch(0.7 0.2 145)' : 'oklch(0.5 0.02 260)'} stroke-width={props.isActive ? 3 : 2} />
|
|
8
|
+
{props.label && <text x={mx()} y={(y1() + y2()) / 2 - 8} text-anchor="middle" fill="oklch(0.7 0.02 260)" font-size="12">{props.label}</text>}
|
|
9
|
+
</g>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — components/StepNode.tsx
|
|
2
|
+
import type { WorkflowStepDef, StepType } from '@geenius-ai-workflow/shared'
|
|
3
|
+
const ICONS: Record<StepType, string> = { 'llm-call': '🤖', transform: '⚙️', condition: '🔀', 'human-approval': '👤', webhook: '🌐', delay: '⏱️', parallel: '⚡', loop: '🔄', 'sub-workflow': '📋', custom: '🔧' }
|
|
4
|
+
|
|
5
|
+
export function StepNode(props: { step: WorkflowStepDef; isSelected?: boolean; status?: string; onClick?: () => void }) {
|
|
6
|
+
return (
|
|
7
|
+
<div data-workflow="step-node" data-step-type={props.step.type} data-selected={props.isSelected || undefined} data-status={props.status} role="button" tabIndex={0} onClick={props.onClick} style={props.step.position ? { position: 'absolute', left: `${props.step.position.x}px`, top: `${props.step.position.y}px` } : undefined}>
|
|
8
|
+
<div data-workflow="step-header"><span data-workflow="step-icon">{ICONS[props.step.type]}</span><span data-workflow="step-name">{props.step.name}</span></div>
|
|
9
|
+
<div data-workflow="step-type-badge">{props.step.type}</div>
|
|
10
|
+
</div>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — components/StepPalette.tsx
|
|
2
|
+
import { For } from 'solid-js'
|
|
3
|
+
import type { StepType } from '@geenius-ai-workflow/shared'
|
|
4
|
+
const ITEMS: Array<{ type: StepType; label: string; icon: string; desc: string }> = [
|
|
5
|
+
{ type: 'llm-call', label: 'LLM Call', icon: '🤖', desc: 'Call an AI model' },
|
|
6
|
+
{ type: 'transform', label: 'Transform', icon: '⚙️', desc: 'Transform data' },
|
|
7
|
+
{ type: 'condition', label: 'Condition', icon: '🔀', desc: 'If/else branching' },
|
|
8
|
+
{ type: 'human-approval', label: 'Approval', icon: '👤', desc: 'Human approval gate' },
|
|
9
|
+
{ type: 'webhook', label: 'Webhook', icon: '🌐', desc: 'HTTP request' },
|
|
10
|
+
{ type: 'delay', label: 'Delay', icon: '⏱️', desc: 'Wait for duration' },
|
|
11
|
+
{ type: 'parallel', label: 'Parallel', icon: '⚡', desc: 'Run in parallel' },
|
|
12
|
+
{ type: 'loop', label: 'Loop', icon: '🔄', desc: 'Iterate items' },
|
|
13
|
+
{ type: 'sub-workflow', label: 'Sub-workflow', icon: '📋', desc: 'Run another workflow' },
|
|
14
|
+
{ type: 'custom', label: 'Custom', icon: '🔧', desc: 'Custom handler' },
|
|
15
|
+
]
|
|
16
|
+
export function StepPalette(props: { onAddStep: (t: StepType) => void }) {
|
|
17
|
+
return (
|
|
18
|
+
<div data-workflow="step-palette" role="list"><h3 data-workflow="palette-title">Steps</h3>
|
|
19
|
+
<For each={ITEMS}>{(item) => <button data-workflow="palette-item" onClick={() => props.onAddStep(item.type)}><span data-workflow="palette-icon">{item.icon}</span><div data-workflow="palette-info"><span data-workflow="palette-label">{item.label}</span><span data-workflow="palette-desc">{item.desc}</span></div></button>}</For>
|
|
20
|
+
</div>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — components/WorkflowCanvas.tsx
|
|
2
|
+
import { For, Show } from 'solid-js'
|
|
3
|
+
import type { WorkflowDefinition } from '@geenius-ai-workflow/shared'
|
|
4
|
+
import { StepNode } from './StepNode'
|
|
5
|
+
import { StepConnector } from './StepConnector'
|
|
6
|
+
|
|
7
|
+
export function WorkflowCanvas(props: { definition: WorkflowDefinition; selectedStepId: string | null; onSelectStep: (id: string | null) => void }) {
|
|
8
|
+
return (
|
|
9
|
+
<div data-workflow="canvas" role="application" aria-label="Workflow canvas">
|
|
10
|
+
<svg data-workflow="connections-layer" style={{ position: 'absolute', inset: '0', 'pointer-events': 'none' }}>
|
|
11
|
+
<For each={props.definition.connections}>{(conn) => {
|
|
12
|
+
const from = () => props.definition.steps.find(s => s.id === conn.fromStepId)
|
|
13
|
+
const to = () => props.definition.steps.find(s => s.id === conn.toStepId)
|
|
14
|
+
return <Show when={from()?.position && to()?.position}><StepConnector from={from()!.position!} to={to()!.position!} label={conn.label} /></Show>
|
|
15
|
+
}}</For>
|
|
16
|
+
</svg>
|
|
17
|
+
<div data-workflow="nodes-layer">
|
|
18
|
+
<For each={props.definition.steps}>{(step) => <StepNode step={step} isSelected={props.selectedStepId === step.id} onClick={() => props.onSelectStep(step.id === props.selectedStepId ? null : step.id)} />}</For>
|
|
19
|
+
</div>
|
|
20
|
+
<Show when={props.definition.steps.length === 0}><div data-workflow="canvas-empty"><p data-workflow="empty-title">No steps yet</p></div></Show>
|
|
21
|
+
</div>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — components/WorkflowRunPanel.tsx
|
|
2
|
+
import { Show, For } from 'solid-js'
|
|
3
|
+
import type { WorkflowRun } from '@geenius-ai-workflow/shared'
|
|
4
|
+
import { formatCost } from '@geenius-ai-workflow/shared'
|
|
5
|
+
const SI: Record<string, string> = { pending: '⏳', running: '🔄', completed: '✅', failed: '❌', skipped: '⏭️', 'waiting-approval': '👤' }
|
|
6
|
+
|
|
7
|
+
export function WorkflowRunPanel(props: { run: WorkflowRun | null; isRunning: boolean; onCancel?: () => void }) {
|
|
8
|
+
return (
|
|
9
|
+
<div data-workflow="run-panel" data-status={props.run?.status}><Show when={!props.run}><div data-workflow="run-empty"><p>No active run.</p></div></Show>
|
|
10
|
+
<Show when={props.run}>{(r) => { const done = () => r().stepResults.filter(s => s.status === 'completed').length; const total = () => r().stepResults.length; const pct = () => total() > 0 ? Math.round((done() / total()) * 100) : 0; const cost = () => r().stepResults.reduce((s, x) => s + (x.costUsd ?? 0), 0)
|
|
11
|
+
return (<><div data-workflow="run-header"><h3 data-workflow="run-title">{SI[r().status]} Run {r().status}</h3><Show when={props.isRunning && props.onCancel}><button data-workflow="run-cancel" onClick={props.onCancel}>⏹ Cancel</button></Show></div>
|
|
12
|
+
<div data-workflow="run-progress"><div data-workflow="run-progress-bar"><div data-workflow="run-progress-fill" style={{ width: `${pct()}%` }} /></div><span data-workflow="run-progress-text">{done()}/{total()} ({pct()}%)</span></div>
|
|
13
|
+
<Show when={cost() > 0}><span data-workflow="run-stat">💰 {formatCost(cost())}</span></Show>
|
|
14
|
+
<Show when={r().error}><div data-workflow="run-error">{r().error}</div></Show>
|
|
15
|
+
<ul data-workflow="run-steps"><For each={r().stepResults}>{(sr) => <li data-workflow="run-step-item" data-status={sr.status}><span>{SI[sr.status]}</span><span>{sr.stepName}</span><span>{sr.durationMs}ms</span></li>}</For></ul></>)
|
|
16
|
+
}}</Show></div>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — components/WorkflowToolbar.tsx
|
|
2
|
+
import { Show } from 'solid-js'
|
|
3
|
+
|
|
4
|
+
export function WorkflowToolbar(props: { workflowName: string; isDirty: boolean; isRunning: boolean; canUndo: boolean; canRedo: boolean; onSave: () => void; onRun: () => void; onCancel?: () => void; onUndo: () => void; onRedo: () => void; onExport?: () => void }) {
|
|
5
|
+
return (
|
|
6
|
+
<div data-workflow="toolbar" role="toolbar">
|
|
7
|
+
<div data-workflow="toolbar-left"><h2 data-workflow="toolbar-title">{props.workflowName}</h2><Show when={props.isDirty}><span data-workflow="toolbar-dirty">●</span></Show></div>
|
|
8
|
+
<div data-workflow="toolbar-center"><button data-workflow="toolbar-btn" onClick={props.onUndo} disabled={!props.canUndo}>↶</button><button data-workflow="toolbar-btn" onClick={props.onRedo} disabled={!props.canRedo}>↷</button></div>
|
|
9
|
+
<div data-workflow="toolbar-right"><Show when={props.onExport}><button data-workflow="toolbar-btn-secondary" onClick={props.onExport}>📤 Export</button></Show><button data-workflow="toolbar-btn-secondary" onClick={props.onSave} disabled={!props.isDirty}>💾 Save</button>
|
|
10
|
+
<Show when={props.isRunning} fallback={<button data-workflow="toolbar-btn-primary" onClick={props.onRun}>▶ Run</button>}><button data-workflow="toolbar-btn-danger" onClick={props.onCancel}>⏹ Stop</button></Show></div>
|
|
11
|
+
</div>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — components/index.ts
|
|
2
|
+
export { WorkflowCanvas } from './WorkflowCanvas'
|
|
3
|
+
export { StepNode } from './StepNode'
|
|
4
|
+
export { StepConnector } from './StepConnector'
|
|
5
|
+
export { StepConfigPanel } from './StepConfigPanel'
|
|
6
|
+
export { WorkflowRunPanel } from './WorkflowRunPanel'
|
|
7
|
+
export { ApprovalModal } from './ApprovalModal'
|
|
8
|
+
export { WorkflowToolbar } from './WorkflowToolbar'
|
|
9
|
+
export { StepPalette } from './StepPalette'
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — src/index.ts
|
|
2
|
+
export type { WorkflowDefinition, WorkflowStepDef, WorkflowRun, StepResult, WorkflowBuilderState } from '@geenius-ai-workflow/shared'
|
|
3
|
+
export { WorkflowEngine, WORKFLOW_TEMPLATES } from '@geenius-ai-workflow/shared'
|
|
4
|
+
|
|
5
|
+
export * from './primitives'
|
|
6
|
+
export * from './components'
|
|
7
|
+
export * from './pages'
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — pages/WorkflowBuilderPage.tsx
|
|
2
|
+
import type { StepType, WorkflowStepDef } from '@geenius-ai-workflow/shared'
|
|
3
|
+
import { WorkflowEngine } from '@geenius-ai-workflow/shared'
|
|
4
|
+
import type { WorkflowEngineOptions } from '@geenius-ai-workflow/shared'
|
|
5
|
+
import { Show } from 'solid-js'
|
|
6
|
+
import { createWorkflowBuilder } from '../primitives/createWorkflowBuilder'
|
|
7
|
+
import { createWorkflowRun } from '../primitives/createWorkflowRun'
|
|
8
|
+
import { WorkflowCanvas } from '../components/WorkflowCanvas'
|
|
9
|
+
import { WorkflowToolbar } from '../components/WorkflowToolbar'
|
|
10
|
+
import { StepPalette } from '../components/StepPalette'
|
|
11
|
+
import { StepConfigPanel } from '../components/StepConfigPanel'
|
|
12
|
+
import { WorkflowRunPanel } from '../components/WorkflowRunPanel'
|
|
13
|
+
|
|
14
|
+
export function WorkflowBuilderPage(props: { engineOptions: WorkflowEngineOptions; onSave?: (def: any) => void }) {
|
|
15
|
+
const builder = createWorkflowBuilder()
|
|
16
|
+
const runTracker = createWorkflowRun()
|
|
17
|
+
const handleAddStep = (type: StepType) => {
|
|
18
|
+
const step: WorkflowStepDef = { id: `step_${Date.now()}`, name: `New ${type}`, type, config: { type } as any, position: { x: 100 + builder.definition().steps.length * 250, y: 200 } }
|
|
19
|
+
builder.addStep(step)
|
|
20
|
+
}
|
|
21
|
+
const handleRun = async () => {
|
|
22
|
+
const engine = new WorkflowEngine({ ...props.engineOptions, onStepComplete: (r) => runTracker.updateStep(r) })
|
|
23
|
+
const result = await engine.execute(builder.definition())
|
|
24
|
+
runTracker.trackRun(result)
|
|
25
|
+
}
|
|
26
|
+
return (
|
|
27
|
+
<div data-workflow="builder-page">
|
|
28
|
+
<WorkflowToolbar workflowName={builder.definition().name} isDirty={builder.isDirty()} isRunning={runTracker.isRunning()} canUndo={builder.canUndo()} canRedo={builder.canRedo()} onSave={() => props.onSave?.(builder.definition())} onRun={handleRun} onUndo={builder.undo} onRedo={builder.redo} />
|
|
29
|
+
<div data-workflow="builder-layout">
|
|
30
|
+
<StepPalette onAddStep={handleAddStep} />
|
|
31
|
+
<WorkflowCanvas definition={builder.definition()} selectedStepId={builder.selectedStepId()} onSelectStep={builder.selectStep} />
|
|
32
|
+
<Show when={builder.selectedStepId()}>{(id) => { const step = () => builder.definition().steps.find(s => s.id === id()); return <Show when={step()}>{(s) => <StepConfigPanel step={s()} onUpdate={builder.updateStep} onDelete={builder.removeStep} onClose={() => builder.selectStep(null)} />}</Show> }}</Show>
|
|
33
|
+
<Show when={runTracker.run()}>{(r) => <WorkflowRunPanel run={r()} isRunning={runTracker.isRunning()} />}</Show>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — pages/WorkflowRunsPage.tsx
|
|
2
|
+
import { For, Show } from 'solid-js'
|
|
3
|
+
import type { WorkflowRun } from '@geenius-ai-workflow/shared'
|
|
4
|
+
const SI: Record<string, string> = { pending: '⏳', running: '🔄', completed: '✅', failed: '❌', cancelled: '⛔', paused: '⏸️' }
|
|
5
|
+
|
|
6
|
+
export function WorkflowRunsPage(props: { runs: WorkflowRun[]; onSelectRun?: (id: string) => void }) {
|
|
7
|
+
return (
|
|
8
|
+
<div data-workflow="runs-page"><div data-workflow="runs-header"><h1 data-workflow="runs-title">Workflow Runs</h1><span data-workflow="runs-count">{props.runs.length} runs</span></div>
|
|
9
|
+
<Show when={props.runs.length > 0} fallback={<div data-workflow="runs-empty"><p>No runs yet.</p></div>}>
|
|
10
|
+
<div data-workflow="runs-list" role="list"><For each={props.runs}>{(run) => {
|
|
11
|
+
const done = () => run.stepResults.filter(s => s.status === 'completed').length
|
|
12
|
+
return (<div data-workflow="run-card" data-status={run.status} role="listitem" onClick={() => props.onSelectRun?.(run.id)}>
|
|
13
|
+
<div data-workflow="run-card-header"><span data-workflow="run-card-status">{SI[run.status]} {run.status}</span><span data-workflow="run-card-id">{run.id.slice(0, 8)}…</span></div>
|
|
14
|
+
<div data-workflow="run-card-meta"><span>{done()}/{run.stepResults.length} steps</span><span>{new Date(run.startedAt).toLocaleString()}</span></div>
|
|
15
|
+
<Show when={run.error}><p data-workflow="run-card-error">{run.error}</p></Show>
|
|
16
|
+
</div>)
|
|
17
|
+
}}</For></div>
|
|
18
|
+
</Show></div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — src/primitives/createApprovalGate.ts
|
|
2
|
+
import { createSignal } from 'solid-js'
|
|
3
|
+
|
|
4
|
+
export interface ApprovalRequest { id: string; stepId: string; message: string; requestedAt: number; approvers?: string[] }
|
|
5
|
+
|
|
6
|
+
export function createApprovalGate() {
|
|
7
|
+
const [pendingApprovals, setPendingApprovals] = createSignal<ApprovalRequest[]>([])
|
|
8
|
+
const [history, setHistory] = createSignal<Array<ApprovalRequest & { decision: 'approved' | 'rejected'; decidedAt: number }>>([])
|
|
9
|
+
|
|
10
|
+
const requestApproval = (stepId: string, message: string, approvers?: string[]) => {
|
|
11
|
+
const request: ApprovalRequest = { id: `approval_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`, stepId, message, requestedAt: Date.now(), approvers }
|
|
12
|
+
setPendingApprovals(prev => [...prev, request])
|
|
13
|
+
return request.id
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const approve = (id: string) => {
|
|
17
|
+
const req = pendingApprovals().find(a => a.id === id)
|
|
18
|
+
if (req) setHistory(h => [...h, { ...req, decision: 'approved', decidedAt: Date.now() }])
|
|
19
|
+
setPendingApprovals(prev => prev.filter(a => a.id !== id))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const reject = (id: string) => {
|
|
23
|
+
const req = pendingApprovals().find(a => a.id === id)
|
|
24
|
+
if (req) setHistory(h => [...h, { ...req, decision: 'rejected', decidedAt: Date.now() }])
|
|
25
|
+
setPendingApprovals(prev => prev.filter(a => a.id !== id))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return { pendingApprovals, history, hasPending: () => pendingApprovals().length > 0, requestApproval, approve, reject, clearHistory: () => setHistory([]) }
|
|
29
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — src/primitives/createWorkflow.ts
|
|
2
|
+
import { createSignal } from 'solid-js'
|
|
3
|
+
import type { WorkflowDefinition, WorkflowRun, StepResult } from '@geenius-ai-workflow/shared'
|
|
4
|
+
import { WorkflowEngine } from '@geenius-ai-workflow/shared'
|
|
5
|
+
import type { WorkflowEngineOptions } from '@geenius-ai-workflow/shared'
|
|
6
|
+
|
|
7
|
+
export interface CreateWorkflowOptions extends WorkflowEngineOptions { }
|
|
8
|
+
|
|
9
|
+
export function createWorkflow(options: CreateWorkflowOptions) {
|
|
10
|
+
const [run, setRun] = createSignal<WorkflowRun | null>(null)
|
|
11
|
+
const [isRunning, setIsRunning] = createSignal(false)
|
|
12
|
+
const [error, setError] = createSignal<Error | null>(null)
|
|
13
|
+
const [stepResults, setStepResults] = createSignal<StepResult[]>([])
|
|
14
|
+
|
|
15
|
+
const engine = new WorkflowEngine({
|
|
16
|
+
...options,
|
|
17
|
+
onStepComplete: (result) => { setStepResults(prev => [...prev, result]); options.onStepComplete?.(result) },
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const execute = async (definition: WorkflowDefinition, input?: Record<string, unknown>) => {
|
|
21
|
+
setIsRunning(true); setError(null); setStepResults([])
|
|
22
|
+
try { const res = await engine.execute(definition, input); setRun(res); return res }
|
|
23
|
+
catch (err) { const e = err instanceof Error ? err : new Error(String(err)); setError(e); throw e }
|
|
24
|
+
finally { setIsRunning(false) }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return { execute, cancel: () => engine.cancel(), run, isRunning, error, stepResults, reset: () => { setRun(null); setError(null); setStepResults([]) } }
|
|
28
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// @geenius-ai-workflow/solidjs — src/primitives/createWorkflowBuilder.ts
|
|
2
|
+
import { createSignal } from 'solid-js'
|
|
3
|
+
import type { WorkflowDefinition, WorkflowStepDef, StepConnection, WorkflowBuilderState } from '@geenius-ai-workflow/shared'
|
|
4
|
+
|
|
5
|
+
const emptyDef = (): WorkflowDefinition => ({
|
|
6
|
+
id: crypto.randomUUID?.() ?? String(Date.now()), name: 'New Workflow', version: 1, status: 'draft',
|
|
7
|
+
steps: [], connections: [], createdBy: '', createdAt: Date.now(), updatedAt: Date.now(),
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export function createWorkflowBuilder(initial?: Partial<WorkflowDefinition>) {
|
|
11
|
+
const [state, setState] = createSignal<WorkflowBuilderState>({
|
|
12
|
+
definition: { ...emptyDef(), ...initial }, selectedStepId: null, isDirty: false, undoStack: [], redoStack: [],
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const pushUndo = () => setState(prev => ({ ...prev, undoStack: [...prev.undoStack.slice(-20), prev.definition], redoStack: [] }))
|
|
16
|
+
|
|
17
|
+
const addStep = (step: WorkflowStepDef) => {
|
|
18
|
+
pushUndo(); setState(prev => ({ ...prev, isDirty: true, definition: { ...prev.definition, steps: [...prev.definition.steps, step], updatedAt: Date.now() } }))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const removeStep = (stepId: string) => {
|
|
22
|
+
pushUndo(); setState(prev => ({
|
|
23
|
+
...prev, isDirty: true,
|
|
24
|
+
definition: { ...prev.definition, steps: prev.definition.steps.filter(s => s.id !== stepId), connections: prev.definition.connections.filter(c => c.fromStepId !== stepId && c.toStepId !== stepId), updatedAt: Date.now() },
|
|
25
|
+
selectedStepId: prev.selectedStepId === stepId ? null : prev.selectedStepId,
|
|
26
|
+
}))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const updateStep = (stepId: string, updates: Partial<WorkflowStepDef>) => {
|
|
30
|
+
pushUndo(); setState(prev => ({ ...prev, isDirty: true, definition: { ...prev.definition, steps: prev.definition.steps.map(s => s.id === stepId ? { ...s, ...updates } : s), updatedAt: Date.now() } }))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const addConnection = (conn: StepConnection) => {
|
|
34
|
+
pushUndo(); setState(prev => ({ ...prev, isDirty: true, definition: { ...prev.definition, connections: [...prev.definition.connections, conn], updatedAt: Date.now() } }))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const removeConnection = (fromStepId: string, toStepId: string) => {
|
|
38
|
+
pushUndo(); setState(prev => ({ ...prev, isDirty: true, definition: { ...prev.definition, connections: prev.definition.connections.filter(c => !(c.fromStepId === fromStepId && c.toStepId === toStepId)), updatedAt: Date.now() } }))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const selectStep = (stepId: string | null) => setState(prev => ({ ...prev, selectedStepId: stepId }))
|
|
42
|
+
|
|
43
|
+
const undo = () => setState(prev => {
|
|
44
|
+
if (prev.undoStack.length === 0) return prev
|
|
45
|
+
return { ...prev, definition: prev.undoStack[prev.undoStack.length - 1], undoStack: prev.undoStack.slice(0, -1), redoStack: [prev.definition, ...prev.redoStack] }
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const redo = () => setState(prev => {
|
|
49
|
+
if (prev.redoStack.length === 0) return prev
|
|
50
|
+
return { ...prev, definition: prev.redoStack[0], undoStack: [...prev.undoStack, prev.definition], redoStack: prev.redoStack.slice(1) }
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const setDefinition = (def: WorkflowDefinition) => setState({ definition: def, selectedStepId: null, isDirty: false, undoStack: [], redoStack: [] })
|
|
54
|
+
|
|
55
|
+
return { state, addStep, removeStep, updateStep, addConnection, removeConnection, selectStep, undo, redo, setDefinition }
|
|
56
|
+
}
|