hexdag 0.5.0.dev1__py3-none-any.whl → 0.5.0.dev2__py3-none-any.whl
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.
- hexdag/studio/ui/src/components/Canvas.tsx +1 -1
- hexdag/studio/ui/src/components/NodeInspector.tsx +12 -12
- hexdag/studio/ui/src/components/NodePalette.tsx +4 -3
- hexdag/studio/ui/src/components/PluginManager.tsx +2 -2
- hexdag/studio/ui/src/components/ValidationPanel.tsx +4 -3
- hexdag/studio/ui/src/components/YamlEditor.tsx +2 -1
- hexdag/studio/ui/src/lib/api.ts +216 -0
- hexdag/studio/ui/src/lib/nodeTemplates.ts +207 -0
- hexdag/studio/ui/src/lib/store.ts +247 -0
- {hexdag-0.5.0.dev1.dist-info → hexdag-0.5.0.dev2.dist-info}/METADATA +1 -1
- {hexdag-0.5.0.dev1.dist-info → hexdag-0.5.0.dev2.dist-info}/RECORD +14 -11
- {hexdag-0.5.0.dev1.dist-info → hexdag-0.5.0.dev2.dist-info}/WHEEL +0 -0
- {hexdag-0.5.0.dev1.dist-info → hexdag-0.5.0.dev2.dist-info}/entry_points.txt +0 -0
- {hexdag-0.5.0.dev1.dist-info → hexdag-0.5.0.dev2.dist-info}/licenses/LICENSE +0 -0
|
@@ -92,7 +92,7 @@ export default function Canvas({ onNodeSelect, selectedNodeId }: CanvasProps) {
|
|
|
92
92
|
setTimeout(() => {
|
|
93
93
|
const currentNodes = useStudioStore.getState().nodes
|
|
94
94
|
const deletedIds = deletions.map((d) => d.id)
|
|
95
|
-
const newNodes = currentNodes.filter((n) => !deletedIds.includes(n.id))
|
|
95
|
+
const newNodes = currentNodes.filter((n: HexdagNodeType) => !deletedIds.includes(n.id))
|
|
96
96
|
setStoreNodes(newNodes)
|
|
97
97
|
syncCanvasToYaml()
|
|
98
98
|
|
|
@@ -5,7 +5,7 @@ import { getNodeTemplate, nodeTemplates } from '../lib/nodeTemplates'
|
|
|
5
5
|
import PythonEditor from './PythonEditor'
|
|
6
6
|
import PortsEditor from './PortsEditor'
|
|
7
7
|
import NodePortsSection from './NodePortsSection'
|
|
8
|
-
import type { HexdagNode } from '../types'
|
|
8
|
+
import type { HexdagNode, HexdagEdge, NodeTemplate } from '../types'
|
|
9
9
|
|
|
10
10
|
interface NodeInspectorProps {
|
|
11
11
|
nodeId: string | null
|
|
@@ -16,7 +16,7 @@ export default function NodeInspector({ nodeId, onClose }: NodeInspectorProps) {
|
|
|
16
16
|
const { nodes, setNodes, edges, setEdges, syncCanvasToYaml } = useStudioStore()
|
|
17
17
|
const [expandedSections, setExpandedSections] = useState<Set<string>>(new Set(['general', 'spec']))
|
|
18
18
|
|
|
19
|
-
const node = nodes.find((n) => n.id === nodeId)
|
|
19
|
+
const node = nodes.find((n: HexdagNode) => n.id === nodeId)
|
|
20
20
|
const template = node ? getNodeTemplate(node.data.kind) : null
|
|
21
21
|
|
|
22
22
|
// Show PortsEditor when no node is selected
|
|
@@ -36,7 +36,7 @@ export default function NodeInspector({ nodeId, onClose }: NodeInspectorProps) {
|
|
|
36
36
|
|
|
37
37
|
const updateNode = (updates: Partial<HexdagNode['data']>) => {
|
|
38
38
|
setNodes(
|
|
39
|
-
nodes.map((n) =>
|
|
39
|
+
nodes.map((n: HexdagNode) =>
|
|
40
40
|
n.id === nodeId
|
|
41
41
|
? { ...n, data: { ...n.data, ...updates } }
|
|
42
42
|
: n
|
|
@@ -60,14 +60,14 @@ export default function NodeInspector({ nodeId, onClose }: NodeInspectorProps) {
|
|
|
60
60
|
if (!newName || newName === nodeId) return
|
|
61
61
|
|
|
62
62
|
// Check for duplicates
|
|
63
|
-
if (nodes.some((n) => n.id === newName)) {
|
|
63
|
+
if (nodes.some((n: HexdagNode) => n.id === newName)) {
|
|
64
64
|
alert('A node with this name already exists')
|
|
65
65
|
return
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
// Update node id
|
|
69
69
|
setNodes(
|
|
70
|
-
nodes.map((n) =>
|
|
70
|
+
nodes.map((n: HexdagNode) =>
|
|
71
71
|
n.id === nodeId
|
|
72
72
|
? { ...n, id: newName, data: { ...n.data, label: newName } }
|
|
73
73
|
: n
|
|
@@ -76,7 +76,7 @@ export default function NodeInspector({ nodeId, onClose }: NodeInspectorProps) {
|
|
|
76
76
|
|
|
77
77
|
// Update edges
|
|
78
78
|
setEdges(
|
|
79
|
-
edges.map((e) => ({
|
|
79
|
+
edges.map((e: HexdagEdge) => ({
|
|
80
80
|
...e,
|
|
81
81
|
id: e.id.replace(nodeId, newName),
|
|
82
82
|
source: e.source === nodeId ? newName : e.source,
|
|
@@ -100,8 +100,8 @@ export default function NodeInspector({ nodeId, onClose }: NodeInspectorProps) {
|
|
|
100
100
|
const deleteNode = () => {
|
|
101
101
|
if (!confirm(`Delete node "${nodeId}"?`)) return
|
|
102
102
|
|
|
103
|
-
setNodes(nodes.filter((n) => n.id !== nodeId))
|
|
104
|
-
setEdges(edges.filter((e) => e.source !== nodeId && e.target !== nodeId))
|
|
103
|
+
setNodes(nodes.filter((n: HexdagNode) => n.id !== nodeId))
|
|
104
|
+
setEdges(edges.filter((e: HexdagEdge) => e.source !== nodeId && e.target !== nodeId))
|
|
105
105
|
syncCanvasToYaml()
|
|
106
106
|
onClose()
|
|
107
107
|
}
|
|
@@ -109,7 +109,7 @@ export default function NodeInspector({ nodeId, onClose }: NodeInspectorProps) {
|
|
|
109
109
|
const duplicateNode = () => {
|
|
110
110
|
let newName = `${nodeId}_copy`
|
|
111
111
|
let counter = 1
|
|
112
|
-
while (nodes.some((n) => n.id === newName)) {
|
|
112
|
+
while (nodes.some((n: HexdagNode) => n.id === newName)) {
|
|
113
113
|
newName = `${nodeId}_copy_${counter}`
|
|
114
114
|
counter++
|
|
115
115
|
}
|
|
@@ -132,7 +132,7 @@ export default function NodeInspector({ nodeId, onClose }: NodeInspectorProps) {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
// Get dependencies (incoming edges)
|
|
135
|
-
const dependencies = edges.filter((e) => e.target === nodeId).map((e) => e.source)
|
|
135
|
+
const dependencies = edges.filter((e: HexdagEdge) => e.target === nodeId).map((e: HexdagEdge) => e.source)
|
|
136
136
|
|
|
137
137
|
return (
|
|
138
138
|
<div className="h-full flex flex-col bg-hex-surface">
|
|
@@ -198,7 +198,7 @@ export default function NodeInspector({ nodeId, onClose }: NodeInspectorProps) {
|
|
|
198
198
|
onChange={(e) => changeNodeKind(e.target.value)}
|
|
199
199
|
className="w-full bg-hex-bg border border-hex-border rounded px-2 py-1.5 text-xs text-hex-text focus:border-hex-accent focus:outline-none"
|
|
200
200
|
>
|
|
201
|
-
{nodeTemplates.map((t) => (
|
|
201
|
+
{nodeTemplates.map((t: NodeTemplate) => (
|
|
202
202
|
<option key={t.kind} value={t.kind}>
|
|
203
203
|
{t.label}
|
|
204
204
|
</option>
|
|
@@ -211,7 +211,7 @@ export default function NodeInspector({ nodeId, onClose }: NodeInspectorProps) {
|
|
|
211
211
|
{dependencies.length === 0 ? (
|
|
212
212
|
<div className="text-[10px] text-hex-text-muted italic">No dependencies</div>
|
|
213
213
|
) : (
|
|
214
|
-
dependencies.map((dep) => (
|
|
214
|
+
dependencies.map((dep: string) => (
|
|
215
215
|
<div
|
|
216
216
|
key={dep}
|
|
217
217
|
className="flex items-center gap-2 text-xs bg-hex-bg rounded px-2 py-1"
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from 'lucide-react'
|
|
24
24
|
import { nodeTemplates } from '../lib/nodeTemplates'
|
|
25
25
|
import { getAllPluginNodes, type PluginNode } from '../lib/api'
|
|
26
|
+
import type { NodeTemplate } from '../types'
|
|
26
27
|
|
|
27
28
|
const iconMap: Record<string, typeof Code> = {
|
|
28
29
|
Code,
|
|
@@ -60,7 +61,7 @@ export default function NodePalette() {
|
|
|
60
61
|
|
|
61
62
|
// Group nodes by plugin
|
|
62
63
|
const groupedNodes = nodes.reduce(
|
|
63
|
-
(acc, node) => {
|
|
64
|
+
(acc: Record<string, PluginNode[]>, node: PluginNode) => {
|
|
64
65
|
const plugin = node.plugin || 'unknown'
|
|
65
66
|
if (!acc[plugin]) {
|
|
66
67
|
acc[plugin] = []
|
|
@@ -72,7 +73,7 @@ export default function NodePalette() {
|
|
|
72
73
|
)
|
|
73
74
|
|
|
74
75
|
setPluginNodeSections(
|
|
75
|
-
Object.entries(groupedNodes).map(([plugin, nodes]) => ({
|
|
76
|
+
Object.entries(groupedNodes).map(([plugin, nodes]: [string, PluginNode[]]) => ({
|
|
76
77
|
plugin,
|
|
77
78
|
nodes,
|
|
78
79
|
expanded: true,
|
|
@@ -134,7 +135,7 @@ export default function NodePalette() {
|
|
|
134
135
|
</button>
|
|
135
136
|
{builtinExpanded && (
|
|
136
137
|
<div className="px-2 pb-2 space-y-1">
|
|
137
|
-
{nodeTemplates.map((template) => {
|
|
138
|
+
{nodeTemplates.map((template: NodeTemplate) => {
|
|
138
139
|
const Icon = iconMap[template.icon] || Box
|
|
139
140
|
return (
|
|
140
141
|
<div
|
|
@@ -247,7 +247,7 @@ function PluginCard({
|
|
|
247
247
|
Adapters ({plugin.adapters.length})
|
|
248
248
|
</h4>
|
|
249
249
|
<div className="grid grid-cols-2 gap-2">
|
|
250
|
-
{plugin.adapters.map((adapter, idx) => {
|
|
250
|
+
{plugin.adapters.map((adapter: PluginAdapter, idx: number) => {
|
|
251
251
|
const Icon = getAdapterIcon(adapter)
|
|
252
252
|
const color = getPortTypeColor(adapter.port_type)
|
|
253
253
|
return (
|
|
@@ -300,7 +300,7 @@ function PluginCard({
|
|
|
300
300
|
Nodes ({plugin.nodes.length})
|
|
301
301
|
</h4>
|
|
302
302
|
<div className="grid grid-cols-2 gap-2">
|
|
303
|
-
{plugin.nodes.map((node, idx) => (
|
|
303
|
+
{plugin.nodes.map((node: PluginNode, idx: number) => (
|
|
304
304
|
<NodeCard key={idx} node={node} />
|
|
305
305
|
))}
|
|
306
306
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CheckCircle, XCircle, AlertTriangle, Info } from 'lucide-react'
|
|
2
2
|
import { useStudioStore } from '../lib/store'
|
|
3
|
+
import type { ValidationError } from '../types'
|
|
3
4
|
|
|
4
5
|
export default function ValidationPanel() {
|
|
5
6
|
const { validation } = useStudioStore()
|
|
@@ -15,8 +16,8 @@ export default function ValidationPanel() {
|
|
|
15
16
|
)
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
const errorCount = validation.errors.filter((e) => e.severity === 'error').length
|
|
19
|
-
const warningCount = validation.errors.filter((e) => e.severity === 'warning').length
|
|
19
|
+
const errorCount = validation.errors.filter((e: ValidationError) => e.severity === 'error').length
|
|
20
|
+
const warningCount = validation.errors.filter((e: ValidationError) => e.severity === 'warning').length
|
|
20
21
|
|
|
21
22
|
return (
|
|
22
23
|
<div className="h-full flex flex-col">
|
|
@@ -68,7 +69,7 @@ export default function ValidationPanel() {
|
|
|
68
69
|
</div>
|
|
69
70
|
)}
|
|
70
71
|
|
|
71
|
-
{validation.errors.map((error, index) => (
|
|
72
|
+
{validation.errors.map((error: ValidationError, index: number) => (
|
|
72
73
|
<div
|
|
73
74
|
key={index}
|
|
74
75
|
className={`
|
|
@@ -3,6 +3,7 @@ import Editor, { type OnMount, type OnChange } from '@monaco-editor/react'
|
|
|
3
3
|
import type * as Monaco from 'monaco-editor'
|
|
4
4
|
import { useStudioStore } from '../lib/store'
|
|
5
5
|
import { validateYaml } from '../lib/api'
|
|
6
|
+
import type { ValidationError } from '../types'
|
|
6
7
|
|
|
7
8
|
export default function YamlEditor() {
|
|
8
9
|
const editorRef = useRef<Monaco.editor.IStandaloneCodeEditor | null>(null)
|
|
@@ -124,7 +125,7 @@ export default function YamlEditor() {
|
|
|
124
125
|
if (monacoRef.current && editorRef.current) {
|
|
125
126
|
const model = editorRef.current.getModel()
|
|
126
127
|
if (model) {
|
|
127
|
-
const markers: Monaco.editor.IMarkerData[] = result.errors.map((err) => ({
|
|
128
|
+
const markers: Monaco.editor.IMarkerData[] = result.errors.map((err: ValidationError) => ({
|
|
128
129
|
severity: err.severity === 'error'
|
|
129
130
|
? monacoRef.current!.MarkerSeverity.Error
|
|
130
131
|
: err.severity === 'warning'
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import type { FileInfo, FileContent, ValidationResult } from '../types'
|
|
2
|
+
|
|
3
|
+
const API_BASE = '/api'
|
|
4
|
+
|
|
5
|
+
// Plugin types
|
|
6
|
+
export interface PluginNode {
|
|
7
|
+
kind: string
|
|
8
|
+
name: string
|
|
9
|
+
description?: string
|
|
10
|
+
plugin: string
|
|
11
|
+
color: string
|
|
12
|
+
defaultSpec?: Record<string, unknown>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface PluginAdapter {
|
|
16
|
+
name: string
|
|
17
|
+
port_type: string
|
|
18
|
+
plugin: string
|
|
19
|
+
description?: string
|
|
20
|
+
config_schema?: Record<string, unknown>
|
|
21
|
+
secrets: string[]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface PluginInfo {
|
|
25
|
+
name: string
|
|
26
|
+
version: string
|
|
27
|
+
description?: string
|
|
28
|
+
author?: string
|
|
29
|
+
adapters: PluginAdapter[]
|
|
30
|
+
nodes: PluginNode[]
|
|
31
|
+
enabled: boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Execution types
|
|
35
|
+
export interface ExecutionResult {
|
|
36
|
+
success: boolean
|
|
37
|
+
outputs?: Record<string, unknown>
|
|
38
|
+
error?: string
|
|
39
|
+
execution_time?: number
|
|
40
|
+
duration_ms: number
|
|
41
|
+
node_results?: Record<string, unknown>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Helper function for API requests
|
|
45
|
+
async function apiRequest<T>(
|
|
46
|
+
endpoint: string,
|
|
47
|
+
options: RequestInit = {}
|
|
48
|
+
): Promise<T> {
|
|
49
|
+
const url = `${API_BASE}${endpoint}`
|
|
50
|
+
const response = await fetch(url, {
|
|
51
|
+
...options,
|
|
52
|
+
headers: {
|
|
53
|
+
'Content-Type': 'application/json',
|
|
54
|
+
...options.headers,
|
|
55
|
+
},
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
const error = await response.text()
|
|
60
|
+
throw new Error(`API error: ${response.status} - ${error}`)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return response.json()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// File operations
|
|
67
|
+
export async function listFiles(path: string = '.'): Promise<FileInfo[]> {
|
|
68
|
+
return apiRequest<FileInfo[]>(`/files?path=${encodeURIComponent(path)}`)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function readFile(path: string): Promise<FileContent> {
|
|
72
|
+
return apiRequest<FileContent>(`/files/${encodeURIComponent(path)}`)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function saveFile(path: string, content: string): Promise<void> {
|
|
76
|
+
await apiRequest(`/files/${encodeURIComponent(path)}`, {
|
|
77
|
+
method: 'PUT',
|
|
78
|
+
body: JSON.stringify({ content }),
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function deleteFile(path: string): Promise<void> {
|
|
83
|
+
await apiRequest(`/files/${encodeURIComponent(path)}`, {
|
|
84
|
+
method: 'DELETE',
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Validation
|
|
89
|
+
export async function validateYaml(
|
|
90
|
+
content: string,
|
|
91
|
+
filePath?: string
|
|
92
|
+
): Promise<ValidationResult> {
|
|
93
|
+
return apiRequest<ValidationResult>('/validate', {
|
|
94
|
+
method: 'POST',
|
|
95
|
+
body: JSON.stringify({ content, file_path: filePath }),
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Execution
|
|
100
|
+
export async function executePipeline(
|
|
101
|
+
yaml: string,
|
|
102
|
+
inputs: Record<string, unknown> = {},
|
|
103
|
+
dryRun: boolean = false
|
|
104
|
+
): Promise<ExecutionResult> {
|
|
105
|
+
return apiRequest<ExecutionResult>('/execute', {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
yaml,
|
|
109
|
+
inputs,
|
|
110
|
+
dry_run: dryRun,
|
|
111
|
+
}),
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Project operations
|
|
116
|
+
export async function downloadProject(
|
|
117
|
+
yamlContent?: string,
|
|
118
|
+
filename?: string,
|
|
119
|
+
includeAssets?: boolean
|
|
120
|
+
): Promise<void> {
|
|
121
|
+
const response = await fetch(`${API_BASE}/project/download`, {
|
|
122
|
+
method: 'POST',
|
|
123
|
+
headers: { 'Content-Type': 'application/json' },
|
|
124
|
+
body: JSON.stringify({
|
|
125
|
+
yaml: yamlContent,
|
|
126
|
+
filename,
|
|
127
|
+
include_assets: includeAssets,
|
|
128
|
+
}),
|
|
129
|
+
})
|
|
130
|
+
if (!response.ok) {
|
|
131
|
+
throw new Error(`Failed to download project: ${response.status}`)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const blob = await response.blob()
|
|
135
|
+
const url = window.URL.createObjectURL(blob)
|
|
136
|
+
const a = document.createElement('a')
|
|
137
|
+
a.href = url
|
|
138
|
+
a.download = filename || 'hexdag-project.zip'
|
|
139
|
+
document.body.appendChild(a)
|
|
140
|
+
a.click()
|
|
141
|
+
document.body.removeChild(a)
|
|
142
|
+
window.URL.revokeObjectURL(url)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Plugin discovery
|
|
146
|
+
export async function getAllPluginNodes(): Promise<PluginNode[]> {
|
|
147
|
+
try {
|
|
148
|
+
const plugins = await listPlugins()
|
|
149
|
+
const nodes: PluginNode[] = []
|
|
150
|
+
|
|
151
|
+
plugins.forEach((plugin) => {
|
|
152
|
+
plugin.nodes.forEach((node) => {
|
|
153
|
+
nodes.push({
|
|
154
|
+
...node,
|
|
155
|
+
plugin: plugin.name,
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
return nodes
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error('Failed to get plugin nodes:', error)
|
|
163
|
+
return []
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export async function getAllPluginAdapters(): Promise<PluginAdapter[]> {
|
|
168
|
+
try {
|
|
169
|
+
const plugins = await listPlugins()
|
|
170
|
+
const adapters: PluginAdapter[] = []
|
|
171
|
+
|
|
172
|
+
plugins.forEach((plugin) => {
|
|
173
|
+
plugin.adapters.forEach((adapter) => {
|
|
174
|
+
adapters.push({
|
|
175
|
+
...adapter,
|
|
176
|
+
plugin: plugin.name,
|
|
177
|
+
})
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
return adapters
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error('Failed to get plugin adapters:', error)
|
|
184
|
+
return []
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export async function listPlugins(): Promise<PluginInfo[]> {
|
|
189
|
+
try {
|
|
190
|
+
return await apiRequest<PluginInfo[]>('/plugins')
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error('Failed to list plugins:', error)
|
|
193
|
+
return []
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Registry endpoints
|
|
198
|
+
export async function getRegisteredNodes(): Promise<
|
|
199
|
+
Array<{ kind: string; name: string; namespace: string }>
|
|
200
|
+
> {
|
|
201
|
+
try {
|
|
202
|
+
return await apiRequest('/registry/nodes')
|
|
203
|
+
} catch {
|
|
204
|
+
return []
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export async function getRegisteredAdapters(): Promise<
|
|
209
|
+
Array<{ name: string; port_type: string; namespace: string }>
|
|
210
|
+
> {
|
|
211
|
+
try {
|
|
212
|
+
return await apiRequest('/registry/adapters')
|
|
213
|
+
} catch {
|
|
214
|
+
return []
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import type { NodeTemplate } from '../types'
|
|
2
|
+
|
|
3
|
+
// Built-in hexDAG node templates
|
|
4
|
+
export const nodeTemplates: NodeTemplate[] = [
|
|
5
|
+
{
|
|
6
|
+
kind: 'function_node',
|
|
7
|
+
label: 'Function',
|
|
8
|
+
description: 'Execute Python functions',
|
|
9
|
+
icon: 'Code',
|
|
10
|
+
color: '#3b82f6', // blue-500
|
|
11
|
+
defaultSpec: {
|
|
12
|
+
fn: '',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
kind: 'llm_node',
|
|
17
|
+
label: 'LLM',
|
|
18
|
+
description: 'Language model interactions',
|
|
19
|
+
icon: 'Brain',
|
|
20
|
+
color: '#8b5cf6', // violet-500
|
|
21
|
+
defaultSpec: {
|
|
22
|
+
prompt_template: '',
|
|
23
|
+
},
|
|
24
|
+
requiredPorts: ['llm'],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
kind: 'agent_node',
|
|
28
|
+
label: 'Agent',
|
|
29
|
+
description: 'ReAct agent with tools',
|
|
30
|
+
icon: 'Bot',
|
|
31
|
+
color: '#ec4899', // pink-500
|
|
32
|
+
defaultSpec: {
|
|
33
|
+
initial_prompt_template: '',
|
|
34
|
+
max_steps: 5,
|
|
35
|
+
},
|
|
36
|
+
requiredPorts: ['llm', 'tool_router'],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
kind: 'conditional_node',
|
|
40
|
+
label: 'Conditional',
|
|
41
|
+
description: 'Conditional branching',
|
|
42
|
+
icon: 'GitBranch',
|
|
43
|
+
color: '#f59e0b', // amber-500
|
|
44
|
+
defaultSpec: {
|
|
45
|
+
condition: '',
|
|
46
|
+
if_true: null,
|
|
47
|
+
if_false: null,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
kind: 'loop_node',
|
|
52
|
+
label: 'Loop',
|
|
53
|
+
description: 'Iterative processing',
|
|
54
|
+
icon: 'Repeat',
|
|
55
|
+
color: '#10b981', // emerald-500
|
|
56
|
+
defaultSpec: {
|
|
57
|
+
iterations: 1,
|
|
58
|
+
body: null,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
kind: 'input_node',
|
|
63
|
+
label: 'Input',
|
|
64
|
+
description: 'Pipeline input',
|
|
65
|
+
icon: 'FileText',
|
|
66
|
+
color: '#06b6d4', // cyan-500
|
|
67
|
+
defaultSpec: {
|
|
68
|
+
schema: {},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
kind: 'output_node',
|
|
73
|
+
label: 'Output',
|
|
74
|
+
description: 'Pipeline output',
|
|
75
|
+
icon: 'FileText',
|
|
76
|
+
color: '#14b8a6', // teal-500
|
|
77
|
+
defaultSpec: {
|
|
78
|
+
schema: {},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
kind: 'transform_node',
|
|
83
|
+
label: 'Transform',
|
|
84
|
+
description: 'Data transformation',
|
|
85
|
+
icon: 'Scissors',
|
|
86
|
+
color: '#f97316', // orange-500
|
|
87
|
+
defaultSpec: {
|
|
88
|
+
transform_fn: '',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
kind: 'parallel_node',
|
|
93
|
+
label: 'Parallel',
|
|
94
|
+
description: 'Parallel execution',
|
|
95
|
+
icon: 'Cpu',
|
|
96
|
+
color: '#6366f1', // indigo-500
|
|
97
|
+
defaultSpec: {
|
|
98
|
+
branches: [],
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
// Map of kind to template for quick lookup
|
|
104
|
+
const templateMap = new Map<string, NodeTemplate>(
|
|
105
|
+
nodeTemplates.map((t) => [t.kind, t])
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
// Default colors for unknown node kinds
|
|
109
|
+
const defaultColors: Record<string, string> = {
|
|
110
|
+
function: '#3b82f6',
|
|
111
|
+
llm: '#8b5cf6',
|
|
112
|
+
agent: '#ec4899',
|
|
113
|
+
conditional: '#f59e0b',
|
|
114
|
+
loop: '#10b981',
|
|
115
|
+
input: '#06b6d4',
|
|
116
|
+
output: '#14b8a6',
|
|
117
|
+
transform: '#f97316',
|
|
118
|
+
parallel: '#6366f1',
|
|
119
|
+
default: '#6b7280',
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get a node template by kind
|
|
124
|
+
*/
|
|
125
|
+
export function getNodeTemplate(kind: string): NodeTemplate | undefined {
|
|
126
|
+
// Direct lookup
|
|
127
|
+
if (templateMap.has(kind)) {
|
|
128
|
+
return templateMap.get(kind)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Try with _node suffix
|
|
132
|
+
if (templateMap.has(`${kind}_node`)) {
|
|
133
|
+
return templateMap.get(`${kind}_node`)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Handle namespaced kinds (e.g., 'etl:file_reader_node')
|
|
137
|
+
if (kind.includes(':')) {
|
|
138
|
+
const baseName = kind.split(':').pop()
|
|
139
|
+
if (baseName && templateMap.has(baseName)) {
|
|
140
|
+
return templateMap.get(baseName)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return undefined
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get the color for a node kind
|
|
149
|
+
*/
|
|
150
|
+
export function getNodeColor(kind: string): string {
|
|
151
|
+
// Try to get from template
|
|
152
|
+
const template = getNodeTemplate(kind)
|
|
153
|
+
if (template) {
|
|
154
|
+
return template.color
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Try to match based on kind name
|
|
158
|
+
const kindLower = kind.toLowerCase()
|
|
159
|
+
for (const [key, color] of Object.entries(defaultColors)) {
|
|
160
|
+
if (kindLower.includes(key)) {
|
|
161
|
+
return color
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return defaultColors.default
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Get the icon name for a node kind
|
|
170
|
+
*/
|
|
171
|
+
export function getNodeIcon(kind: string): string {
|
|
172
|
+
const template = getNodeTemplate(kind)
|
|
173
|
+
if (template) {
|
|
174
|
+
return template.icon
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Default icons based on kind name
|
|
178
|
+
const kindLower = kind.toLowerCase()
|
|
179
|
+
if (kindLower.includes('function')) return 'Code'
|
|
180
|
+
if (kindLower.includes('llm')) return 'Brain'
|
|
181
|
+
if (kindLower.includes('agent')) return 'Bot'
|
|
182
|
+
if (kindLower.includes('conditional') || kindLower.includes('branch'))
|
|
183
|
+
return 'GitBranch'
|
|
184
|
+
if (kindLower.includes('loop') || kindLower.includes('repeat')) return 'Repeat'
|
|
185
|
+
if (kindLower.includes('input') || kindLower.includes('output'))
|
|
186
|
+
return 'FileText'
|
|
187
|
+
if (kindLower.includes('transform')) return 'Scissors'
|
|
188
|
+
if (kindLower.includes('parallel')) return 'Cpu'
|
|
189
|
+
|
|
190
|
+
return 'Box'
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get the default spec for a node kind
|
|
195
|
+
*/
|
|
196
|
+
export function getDefaultSpec(kind: string): Record<string, unknown> {
|
|
197
|
+
const template = getNodeTemplate(kind)
|
|
198
|
+
return template?.defaultSpec || {}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Get required ports for a node kind
|
|
203
|
+
*/
|
|
204
|
+
export function getRequiredPorts(kind: string): string[] {
|
|
205
|
+
const template = getNodeTemplate(kind)
|
|
206
|
+
return template?.requiredPorts || []
|
|
207
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { create } from 'zustand'
|
|
2
|
+
import yaml from 'yaml'
|
|
3
|
+
import type {
|
|
4
|
+
FileInfo,
|
|
5
|
+
HexdagNode,
|
|
6
|
+
HexdagEdge,
|
|
7
|
+
ValidationResult,
|
|
8
|
+
StudioState,
|
|
9
|
+
Pipeline,
|
|
10
|
+
NodeSpec,
|
|
11
|
+
} from '../types'
|
|
12
|
+
|
|
13
|
+
// Helper to calculate node positions in a DAG layout
|
|
14
|
+
function calculateNodePositions(
|
|
15
|
+
nodes: NodeSpec[]
|
|
16
|
+
): Map<string, { x: number; y: number }> {
|
|
17
|
+
const positions = new Map<string, { x: number; y: number }>()
|
|
18
|
+
|
|
19
|
+
// Build dependency graph
|
|
20
|
+
const dependencyMap = new Map<string, string[]>()
|
|
21
|
+
const dependentMap = new Map<string, string[]>()
|
|
22
|
+
|
|
23
|
+
nodes.forEach((node) => {
|
|
24
|
+
dependencyMap.set(node.metadata.name, node.dependencies || [])
|
|
25
|
+
dependentMap.set(node.metadata.name, [])
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// Build reverse dependency map
|
|
29
|
+
nodes.forEach((node) => {
|
|
30
|
+
;(node.dependencies || []).forEach((dep) => {
|
|
31
|
+
const dependents = dependentMap.get(dep) || []
|
|
32
|
+
dependents.push(node.metadata.name)
|
|
33
|
+
dependentMap.set(dep, dependents)
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// Calculate levels (topological sort with levels)
|
|
38
|
+
const levels = new Map<string, number>()
|
|
39
|
+
const visited = new Set<string>()
|
|
40
|
+
|
|
41
|
+
function calculateLevel(nodeName: string): number {
|
|
42
|
+
if (levels.has(nodeName)) {
|
|
43
|
+
return levels.get(nodeName)!
|
|
44
|
+
}
|
|
45
|
+
if (visited.has(nodeName)) {
|
|
46
|
+
return 0 // Cycle detected, return 0
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
visited.add(nodeName)
|
|
50
|
+
const deps = dependencyMap.get(nodeName) || []
|
|
51
|
+
let maxDepLevel = -1
|
|
52
|
+
|
|
53
|
+
deps.forEach((dep) => {
|
|
54
|
+
const depLevel = calculateLevel(dep)
|
|
55
|
+
maxDepLevel = Math.max(maxDepLevel, depLevel)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const level = maxDepLevel + 1
|
|
59
|
+
levels.set(nodeName, level)
|
|
60
|
+
return level
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
nodes.forEach((node) => calculateLevel(node.metadata.name))
|
|
64
|
+
|
|
65
|
+
// Group nodes by level
|
|
66
|
+
const levelGroups = new Map<number, string[]>()
|
|
67
|
+
levels.forEach((level, nodeName) => {
|
|
68
|
+
const group = levelGroups.get(level) || []
|
|
69
|
+
group.push(nodeName)
|
|
70
|
+
levelGroups.set(level, group)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Calculate positions
|
|
74
|
+
const nodeWidth = 200
|
|
75
|
+
const nodeHeight = 80
|
|
76
|
+
const horizontalGap = 100
|
|
77
|
+
const verticalGap = 50
|
|
78
|
+
|
|
79
|
+
levelGroups.forEach((nodesAtLevel, level) => {
|
|
80
|
+
const totalWidth =
|
|
81
|
+
nodesAtLevel.length * nodeWidth + (nodesAtLevel.length - 1) * horizontalGap
|
|
82
|
+
const startX = -totalWidth / 2
|
|
83
|
+
|
|
84
|
+
nodesAtLevel.forEach((nodeName, index) => {
|
|
85
|
+
positions.set(nodeName, {
|
|
86
|
+
x: startX + index * (nodeWidth + horizontalGap) + 100,
|
|
87
|
+
y: level * (nodeHeight + verticalGap) + 50,
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
return positions
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const useStudioStore = create<StudioState>((set, get) => ({
|
|
96
|
+
// Files
|
|
97
|
+
files: [],
|
|
98
|
+
currentFile: null,
|
|
99
|
+
yamlContent: '',
|
|
100
|
+
|
|
101
|
+
// Canvas
|
|
102
|
+
nodes: [],
|
|
103
|
+
edges: [],
|
|
104
|
+
|
|
105
|
+
// Validation
|
|
106
|
+
validation: null,
|
|
107
|
+
|
|
108
|
+
// UI state
|
|
109
|
+
isLoading: false,
|
|
110
|
+
isSaving: false,
|
|
111
|
+
isDirty: false,
|
|
112
|
+
|
|
113
|
+
// Actions
|
|
114
|
+
setFiles: (files: FileInfo[]) => set({ files }),
|
|
115
|
+
setCurrentFile: (path: string | null) => set({ currentFile: path }),
|
|
116
|
+
setYamlContent: (content: string) => set({ yamlContent: content, isDirty: true }),
|
|
117
|
+
setNodes: (nodes: HexdagNode[]) => set({ nodes }),
|
|
118
|
+
setEdges: (edges: HexdagEdge[]) => set({ edges }),
|
|
119
|
+
setValidation: (result: ValidationResult | null) => set({ validation: result }),
|
|
120
|
+
setIsLoading: (loading: boolean) => set({ isLoading: loading }),
|
|
121
|
+
setIsSaving: (saving: boolean) => set({ isSaving: saving }),
|
|
122
|
+
setIsDirty: (dirty: boolean) => set({ isDirty: dirty }),
|
|
123
|
+
|
|
124
|
+
// Complex actions
|
|
125
|
+
syncYamlToCanvas: () => {
|
|
126
|
+
const { yamlContent } = get()
|
|
127
|
+
|
|
128
|
+
if (!yamlContent.trim()) {
|
|
129
|
+
set({ nodes: [], edges: [] })
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const parsed = yaml.parse(yamlContent) as Pipeline | null
|
|
135
|
+
|
|
136
|
+
if (!parsed || !parsed.spec || !parsed.spec.nodes) {
|
|
137
|
+
set({ nodes: [], edges: [] })
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const pipelineNodes = parsed.spec.nodes
|
|
142
|
+
const positions = calculateNodePositions(pipelineNodes)
|
|
143
|
+
const existingNodes = get().nodes
|
|
144
|
+
const existingPositions = new Map(
|
|
145
|
+
existingNodes.map((n) => [n.id, n.position])
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
// Convert pipeline nodes to canvas nodes
|
|
149
|
+
const canvasNodes: HexdagNode[] = pipelineNodes.map((node) => {
|
|
150
|
+
const existingPos = existingPositions.get(node.metadata.name)
|
|
151
|
+
const calculatedPos = positions.get(node.metadata.name) || { x: 0, y: 0 }
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
id: node.metadata.name,
|
|
155
|
+
type: 'hexdagNode',
|
|
156
|
+
position: existingPos || calculatedPos,
|
|
157
|
+
data: {
|
|
158
|
+
kind: node.kind,
|
|
159
|
+
label: node.metadata.name,
|
|
160
|
+
spec: node.spec || {},
|
|
161
|
+
isValid: true,
|
|
162
|
+
errors: [],
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
// Build edges from dependencies
|
|
168
|
+
const canvasEdges: HexdagEdge[] = []
|
|
169
|
+
pipelineNodes.forEach((node) => {
|
|
170
|
+
;(node.dependencies || []).forEach((dep) => {
|
|
171
|
+
canvasEdges.push({
|
|
172
|
+
id: `${dep}-${node.metadata.name}`,
|
|
173
|
+
source: dep,
|
|
174
|
+
target: node.metadata.name,
|
|
175
|
+
type: 'smoothstep',
|
|
176
|
+
animated: false,
|
|
177
|
+
})
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
set({ nodes: canvasNodes, edges: canvasEdges })
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error('Failed to parse YAML:', error)
|
|
184
|
+
// Keep existing nodes/edges on parse error
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
syncCanvasToYaml: () => {
|
|
189
|
+
const { nodes, edges, yamlContent } = get()
|
|
190
|
+
|
|
191
|
+
if (nodes.length === 0) {
|
|
192
|
+
// Don't clear YAML if there are no nodes - could be a parse error state
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
// Parse existing YAML to preserve metadata and ports
|
|
198
|
+
let existingPipeline: Pipeline | null = null
|
|
199
|
+
try {
|
|
200
|
+
existingPipeline = yaml.parse(yamlContent) as Pipeline | null
|
|
201
|
+
} catch {
|
|
202
|
+
// If YAML is invalid, start fresh
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Build dependency map from edges
|
|
206
|
+
const dependencyMap = new Map<string, string[]>()
|
|
207
|
+
edges.forEach((edge) => {
|
|
208
|
+
const deps = dependencyMap.get(edge.target) || []
|
|
209
|
+
deps.push(edge.source)
|
|
210
|
+
dependencyMap.set(edge.target, deps)
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
// Convert canvas nodes to pipeline nodes
|
|
214
|
+
const pipelineNodes: NodeSpec[] = nodes.map((node) => ({
|
|
215
|
+
kind: node.data.kind,
|
|
216
|
+
metadata: {
|
|
217
|
+
name: node.id,
|
|
218
|
+
},
|
|
219
|
+
spec: node.data.spec || {},
|
|
220
|
+
dependencies: dependencyMap.get(node.id) || [],
|
|
221
|
+
}))
|
|
222
|
+
|
|
223
|
+
// Build the pipeline object
|
|
224
|
+
const pipeline: Pipeline = {
|
|
225
|
+
apiVersion: existingPipeline?.apiVersion || 'hexdag/v1',
|
|
226
|
+
kind: existingPipeline?.kind || 'Pipeline',
|
|
227
|
+
metadata: existingPipeline?.metadata || {
|
|
228
|
+
name: 'untitled-pipeline',
|
|
229
|
+
},
|
|
230
|
+
spec: {
|
|
231
|
+
ports: existingPipeline?.spec?.ports,
|
|
232
|
+
nodes: pipelineNodes,
|
|
233
|
+
},
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Serialize to YAML
|
|
237
|
+
const newYamlContent = yaml.stringify(pipeline, {
|
|
238
|
+
indent: 2,
|
|
239
|
+
lineWidth: 120,
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
set({ yamlContent: newYamlContent, isDirty: true })
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.error('Failed to serialize to YAML:', error)
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
}))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hexdag
|
|
3
|
-
Version: 0.5.0.
|
|
3
|
+
Version: 0.5.0.dev2
|
|
4
4
|
Summary: Lightweight DAG orchestration framework with enterprise pipeline capabilities
|
|
5
5
|
Project-URL: Homepage, https://hexdag.ai
|
|
6
6
|
Project-URL: Repository, https://github.com/omniviser/hexdag
|
|
@@ -180,20 +180,23 @@ hexdag/studio/ui/src/App.tsx,sha256=xBnZsJTFh3WvZWIGjmjb5ghoXruY61H_wjNEnuXQCb8,
|
|
|
180
180
|
hexdag/studio/ui/src/index.css,sha256=akRMqCLDkxXGpoDXOoQ5dk87goJwqIdAuadxf2l_INY,1393
|
|
181
181
|
hexdag/studio/ui/src/main.tsx,sha256=X0nc5ubMS11njPUp74kq8Kt9-mr7MAsRrVWSJAGbiwU,232
|
|
182
182
|
hexdag/studio/ui/src/vite-env.d.ts,sha256=ZZlpNvuwQpFfe3SiAPzd5-QQ8ypmmxq5WXz6pLD63bU,38
|
|
183
|
-
hexdag/studio/ui/src/components/Canvas.tsx,sha256=
|
|
183
|
+
hexdag/studio/ui/src/components/Canvas.tsx,sha256=ijgR3aNKv5BUARcOsEZRgq74M_dH0hzCfh_XPoBA_7g,11853
|
|
184
184
|
hexdag/studio/ui/src/components/ContextMenu.tsx,sha256=3IcJdG3oeaeeicxa3FXiYQAc52W7A5dGWwwKce3yrwI,4671
|
|
185
185
|
hexdag/studio/ui/src/components/FileBrowser.tsx,sha256=ejsBKjktPL7vKQpkf7rnbNkaKy_M4DdLfwdzN9IKyJY,3836
|
|
186
186
|
hexdag/studio/ui/src/components/Header.tsx,sha256=zQSXsjUzV13KbenjEh_A35_TuuqN5Fnu6JoAAYJ6T8c,5702
|
|
187
187
|
hexdag/studio/ui/src/components/HexdagNode.tsx,sha256=HmeNEoxUzQzAzTb3AHMjsQrYC_4QYFiywO96rSboRJ8,6419
|
|
188
|
-
hexdag/studio/ui/src/components/NodeInspector.tsx,sha256=
|
|
189
|
-
hexdag/studio/ui/src/components/NodePalette.tsx,sha256=
|
|
188
|
+
hexdag/studio/ui/src/components/NodeInspector.tsx,sha256=15gW-Xz6BkYJYB4zYooKl_l0qSgbBYiklCCs0rgTqPU,16503
|
|
189
|
+
hexdag/studio/ui/src/components/NodePalette.tsx,sha256=yLhfN4CvfNkwqQXG2heStAyiiGm0v8ejVnA9jMLHqLc,9761
|
|
190
190
|
hexdag/studio/ui/src/components/NodePortsSection.tsx,sha256=nkUaVEJ4oIAfpwYTQYuHNr6jDb-OaxD_FD5D3d0amWw,12474
|
|
191
|
-
hexdag/studio/ui/src/components/PluginManager.tsx,sha256=
|
|
191
|
+
hexdag/studio/ui/src/components/PluginManager.tsx,sha256=CzMzUKnwHW7W65nnwbaU899U6yWFzSkZ2ZQ9A-iKDnU,12489
|
|
192
192
|
hexdag/studio/ui/src/components/PortsEditor.tsx,sha256=h3b8GCKVeiT7DY99oEKm9HowtCG5xau3akzDZl_Owbc,15039
|
|
193
193
|
hexdag/studio/ui/src/components/PythonEditor.tsx,sha256=vJ7sgZ6s75651EI7Y-GTv2s5sODlNi2ay9XDtmL2Xww,6770
|
|
194
|
-
hexdag/studio/ui/src/components/ValidationPanel.tsx,sha256=
|
|
195
|
-
hexdag/studio/ui/src/components/YamlEditor.tsx,sha256=
|
|
194
|
+
hexdag/studio/ui/src/components/ValidationPanel.tsx,sha256=lzRIgwso2j-_NLFOu8j9GCQWkn6KB-d-6eWG9x4nmHs,4157
|
|
195
|
+
hexdag/studio/ui/src/components/YamlEditor.tsx,sha256=naD2dSq9rw6hxbA6Fkj9-8fmU0vRF1Rk1_FfpPqksfU,6781
|
|
196
196
|
hexdag/studio/ui/src/components/index.ts,sha256=fjXeu-PS5GD5m-My52619toCqWqQRuZHDPfJ_rQ4ZIk,428
|
|
197
|
+
hexdag/studio/ui/src/lib/api.ts,sha256=s6pO1mzmNR7EpLHdHrrjXHwP2pCMyHKBUCwXvhF8y0c,4960
|
|
198
|
+
hexdag/studio/ui/src/lib/nodeTemplates.ts,sha256=s8zOfsQGhpCG7foPdrsFtQ_CGwN6jcZTXe_fCbTno5M,4743
|
|
199
|
+
hexdag/studio/ui/src/lib/store.ts,sha256=aynI_K5oioi7Zq0WhC_oIrhSNximBSnD54xPe6JTgi4,6902
|
|
197
200
|
hexdag/studio/ui/src/types/index.ts,sha256=ZWKo_eHfPnMGVXqMa0SZuB5VSOdDDLQy7RkhkVA1qPo,2592
|
|
198
201
|
hexdag/visualization/__init__.py,sha256=B7pF_eVt6ompQUometQK0EA3ARZItzguNZbYmEiVxu4,1889
|
|
199
202
|
hexdag/visualization/dag_visualizer.py,sha256=MsLL7CuOC-iC5-xm5doKk6iH0n1CDMklqZn35nZaigU,38790
|
|
@@ -254,8 +257,8 @@ hexdag_plugins/storage/vector/__init__.py,sha256=uMI7dYdgMpm5b-Kay3Z9OehTC8kfqvJ
|
|
|
254
257
|
hexdag_plugins/storage/vector/chromadb.py,sha256=CZBtp4EAw6WGwJ4M8WYc0KYVdbTJLiP74pF3JxSZIgI,7103
|
|
255
258
|
hexdag_plugins/storage/vector/in_memory.py,sha256=j_7FAXj8nQPxPAIksaeOyU5yFJijOXxYEJCRibwttB8,8390
|
|
256
259
|
hexdag_plugins/storage/vector/pgvector.py,sha256=830TWR4JrwbpzYultCIfb7Tll_D0te3xJM3PXCHyH94,18262
|
|
257
|
-
hexdag-0.5.0.
|
|
258
|
-
hexdag-0.5.0.
|
|
259
|
-
hexdag-0.5.0.
|
|
260
|
-
hexdag-0.5.0.
|
|
261
|
-
hexdag-0.5.0.
|
|
260
|
+
hexdag-0.5.0.dev2.dist-info/METADATA,sha256=3xMVd05Np-dSbZNKwCrpqni03ZoRS0f6r0ons3_p3aM,13940
|
|
261
|
+
hexdag-0.5.0.dev2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
262
|
+
hexdag-0.5.0.dev2.dist-info/entry_points.txt,sha256=HVVYo840xI_sDh7Ld4V6JikuEKykjCv-hdB8lND48FU,144
|
|
263
|
+
hexdag-0.5.0.dev2.dist-info/licenses/LICENSE,sha256=ha-Tqaxjm6OqBpizGHUnQk1XxuU9_M9xMFTSz_kJzxk,10760
|
|
264
|
+
hexdag-0.5.0.dev2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|