hexdag 0.5.0.dev1__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.
Files changed (261) hide show
  1. hexdag/__init__.py +116 -0
  2. hexdag/__main__.py +30 -0
  3. hexdag/adapters/executors/__init__.py +5 -0
  4. hexdag/adapters/executors/local_executor.py +316 -0
  5. hexdag/builtin/__init__.py +6 -0
  6. hexdag/builtin/adapters/__init__.py +51 -0
  7. hexdag/builtin/adapters/anthropic/__init__.py +5 -0
  8. hexdag/builtin/adapters/anthropic/anthropic_adapter.py +151 -0
  9. hexdag/builtin/adapters/database/__init__.py +6 -0
  10. hexdag/builtin/adapters/database/csv/csv_adapter.py +249 -0
  11. hexdag/builtin/adapters/database/pgvector/__init__.py +5 -0
  12. hexdag/builtin/adapters/database/pgvector/pgvector_adapter.py +478 -0
  13. hexdag/builtin/adapters/database/sqlalchemy/sqlalchemy_adapter.py +252 -0
  14. hexdag/builtin/adapters/database/sqlite/__init__.py +5 -0
  15. hexdag/builtin/adapters/database/sqlite/sqlite_adapter.py +410 -0
  16. hexdag/builtin/adapters/local/README.md +59 -0
  17. hexdag/builtin/adapters/local/__init__.py +7 -0
  18. hexdag/builtin/adapters/local/local_observer_manager.py +696 -0
  19. hexdag/builtin/adapters/memory/__init__.py +47 -0
  20. hexdag/builtin/adapters/memory/file_memory_adapter.py +297 -0
  21. hexdag/builtin/adapters/memory/in_memory_memory.py +216 -0
  22. hexdag/builtin/adapters/memory/schemas.py +57 -0
  23. hexdag/builtin/adapters/memory/session_memory.py +178 -0
  24. hexdag/builtin/adapters/memory/sqlite_memory_adapter.py +215 -0
  25. hexdag/builtin/adapters/memory/state_memory.py +280 -0
  26. hexdag/builtin/adapters/mock/README.md +89 -0
  27. hexdag/builtin/adapters/mock/__init__.py +15 -0
  28. hexdag/builtin/adapters/mock/hexdag.toml +50 -0
  29. hexdag/builtin/adapters/mock/mock_database.py +225 -0
  30. hexdag/builtin/adapters/mock/mock_embedding.py +223 -0
  31. hexdag/builtin/adapters/mock/mock_llm.py +177 -0
  32. hexdag/builtin/adapters/mock/mock_tool_adapter.py +192 -0
  33. hexdag/builtin/adapters/mock/mock_tool_router.py +232 -0
  34. hexdag/builtin/adapters/openai/__init__.py +5 -0
  35. hexdag/builtin/adapters/openai/openai_adapter.py +634 -0
  36. hexdag/builtin/adapters/secret/__init__.py +7 -0
  37. hexdag/builtin/adapters/secret/local_secret_adapter.py +248 -0
  38. hexdag/builtin/adapters/unified_tool_router.py +280 -0
  39. hexdag/builtin/macros/__init__.py +17 -0
  40. hexdag/builtin/macros/conversation_agent.py +390 -0
  41. hexdag/builtin/macros/llm_macro.py +151 -0
  42. hexdag/builtin/macros/reasoning_agent.py +423 -0
  43. hexdag/builtin/macros/tool_macro.py +380 -0
  44. hexdag/builtin/nodes/__init__.py +38 -0
  45. hexdag/builtin/nodes/_discovery.py +123 -0
  46. hexdag/builtin/nodes/agent_node.py +696 -0
  47. hexdag/builtin/nodes/base_node_factory.py +242 -0
  48. hexdag/builtin/nodes/composite_node.py +926 -0
  49. hexdag/builtin/nodes/data_node.py +201 -0
  50. hexdag/builtin/nodes/expression_node.py +487 -0
  51. hexdag/builtin/nodes/function_node.py +454 -0
  52. hexdag/builtin/nodes/llm_node.py +491 -0
  53. hexdag/builtin/nodes/loop_node.py +920 -0
  54. hexdag/builtin/nodes/mapped_input.py +518 -0
  55. hexdag/builtin/nodes/port_call_node.py +269 -0
  56. hexdag/builtin/nodes/tool_call_node.py +195 -0
  57. hexdag/builtin/nodes/tool_utils.py +390 -0
  58. hexdag/builtin/prompts/__init__.py +68 -0
  59. hexdag/builtin/prompts/base.py +422 -0
  60. hexdag/builtin/prompts/chat_prompts.py +303 -0
  61. hexdag/builtin/prompts/error_correction_prompts.py +320 -0
  62. hexdag/builtin/prompts/tool_prompts.py +160 -0
  63. hexdag/builtin/tools/builtin_tools.py +84 -0
  64. hexdag/builtin/tools/database_tools.py +164 -0
  65. hexdag/cli/__init__.py +17 -0
  66. hexdag/cli/__main__.py +7 -0
  67. hexdag/cli/commands/__init__.py +27 -0
  68. hexdag/cli/commands/build_cmd.py +812 -0
  69. hexdag/cli/commands/create_cmd.py +208 -0
  70. hexdag/cli/commands/docs_cmd.py +293 -0
  71. hexdag/cli/commands/generate_types_cmd.py +252 -0
  72. hexdag/cli/commands/init_cmd.py +188 -0
  73. hexdag/cli/commands/pipeline_cmd.py +494 -0
  74. hexdag/cli/commands/plugin_dev_cmd.py +529 -0
  75. hexdag/cli/commands/plugins_cmd.py +441 -0
  76. hexdag/cli/commands/studio_cmd.py +101 -0
  77. hexdag/cli/commands/validate_cmd.py +221 -0
  78. hexdag/cli/main.py +84 -0
  79. hexdag/core/__init__.py +83 -0
  80. hexdag/core/config/__init__.py +20 -0
  81. hexdag/core/config/loader.py +479 -0
  82. hexdag/core/config/models.py +150 -0
  83. hexdag/core/configurable.py +294 -0
  84. hexdag/core/context/__init__.py +37 -0
  85. hexdag/core/context/execution_context.py +378 -0
  86. hexdag/core/docs/__init__.py +26 -0
  87. hexdag/core/docs/extractors.py +678 -0
  88. hexdag/core/docs/generators.py +890 -0
  89. hexdag/core/docs/models.py +120 -0
  90. hexdag/core/domain/__init__.py +10 -0
  91. hexdag/core/domain/dag.py +1225 -0
  92. hexdag/core/exceptions.py +234 -0
  93. hexdag/core/expression_parser.py +569 -0
  94. hexdag/core/logging.py +449 -0
  95. hexdag/core/models/__init__.py +17 -0
  96. hexdag/core/models/base.py +138 -0
  97. hexdag/core/orchestration/__init__.py +46 -0
  98. hexdag/core/orchestration/body_executor.py +481 -0
  99. hexdag/core/orchestration/components/__init__.py +97 -0
  100. hexdag/core/orchestration/components/adapter_lifecycle_manager.py +113 -0
  101. hexdag/core/orchestration/components/checkpoint_manager.py +134 -0
  102. hexdag/core/orchestration/components/execution_coordinator.py +360 -0
  103. hexdag/core/orchestration/components/health_check_manager.py +176 -0
  104. hexdag/core/orchestration/components/input_mapper.py +143 -0
  105. hexdag/core/orchestration/components/lifecycle_manager.py +583 -0
  106. hexdag/core/orchestration/components/node_executor.py +377 -0
  107. hexdag/core/orchestration/components/secret_manager.py +202 -0
  108. hexdag/core/orchestration/components/wave_executor.py +158 -0
  109. hexdag/core/orchestration/constants.py +17 -0
  110. hexdag/core/orchestration/events/README.md +312 -0
  111. hexdag/core/orchestration/events/__init__.py +104 -0
  112. hexdag/core/orchestration/events/batching.py +330 -0
  113. hexdag/core/orchestration/events/decorators.py +139 -0
  114. hexdag/core/orchestration/events/events.py +573 -0
  115. hexdag/core/orchestration/events/observers/__init__.py +30 -0
  116. hexdag/core/orchestration/events/observers/core_observers.py +690 -0
  117. hexdag/core/orchestration/events/observers/models.py +111 -0
  118. hexdag/core/orchestration/events/taxonomy.py +269 -0
  119. hexdag/core/orchestration/hook_context.py +237 -0
  120. hexdag/core/orchestration/hooks.py +437 -0
  121. hexdag/core/orchestration/models.py +418 -0
  122. hexdag/core/orchestration/orchestrator.py +910 -0
  123. hexdag/core/orchestration/orchestrator_factory.py +275 -0
  124. hexdag/core/orchestration/port_wrappers.py +327 -0
  125. hexdag/core/orchestration/prompt/__init__.py +32 -0
  126. hexdag/core/orchestration/prompt/template.py +332 -0
  127. hexdag/core/pipeline_builder/__init__.py +21 -0
  128. hexdag/core/pipeline_builder/component_instantiator.py +386 -0
  129. hexdag/core/pipeline_builder/include_tag.py +265 -0
  130. hexdag/core/pipeline_builder/pipeline_config.py +133 -0
  131. hexdag/core/pipeline_builder/py_tag.py +223 -0
  132. hexdag/core/pipeline_builder/tag_discovery.py +268 -0
  133. hexdag/core/pipeline_builder/yaml_builder.py +1196 -0
  134. hexdag/core/pipeline_builder/yaml_validator.py +569 -0
  135. hexdag/core/ports/__init__.py +65 -0
  136. hexdag/core/ports/api_call.py +133 -0
  137. hexdag/core/ports/database.py +489 -0
  138. hexdag/core/ports/embedding.py +215 -0
  139. hexdag/core/ports/executor.py +237 -0
  140. hexdag/core/ports/file_storage.py +117 -0
  141. hexdag/core/ports/healthcheck.py +87 -0
  142. hexdag/core/ports/llm.py +551 -0
  143. hexdag/core/ports/memory.py +70 -0
  144. hexdag/core/ports/observer_manager.py +130 -0
  145. hexdag/core/ports/secret.py +145 -0
  146. hexdag/core/ports/tool_router.py +94 -0
  147. hexdag/core/ports_builder.py +623 -0
  148. hexdag/core/protocols.py +273 -0
  149. hexdag/core/resolver.py +304 -0
  150. hexdag/core/schema/__init__.py +9 -0
  151. hexdag/core/schema/generator.py +742 -0
  152. hexdag/core/secrets.py +242 -0
  153. hexdag/core/types.py +413 -0
  154. hexdag/core/utils/async_warnings.py +206 -0
  155. hexdag/core/utils/schema_conversion.py +78 -0
  156. hexdag/core/utils/sql_validation.py +86 -0
  157. hexdag/core/validation/secure_json.py +148 -0
  158. hexdag/core/yaml_macro.py +517 -0
  159. hexdag/mcp_server.py +3120 -0
  160. hexdag/studio/__init__.py +10 -0
  161. hexdag/studio/build_ui.py +92 -0
  162. hexdag/studio/server/__init__.py +1 -0
  163. hexdag/studio/server/main.py +100 -0
  164. hexdag/studio/server/routes/__init__.py +9 -0
  165. hexdag/studio/server/routes/execute.py +208 -0
  166. hexdag/studio/server/routes/export.py +558 -0
  167. hexdag/studio/server/routes/files.py +207 -0
  168. hexdag/studio/server/routes/plugins.py +419 -0
  169. hexdag/studio/server/routes/validate.py +220 -0
  170. hexdag/studio/ui/index.html +13 -0
  171. hexdag/studio/ui/package-lock.json +2992 -0
  172. hexdag/studio/ui/package.json +31 -0
  173. hexdag/studio/ui/postcss.config.js +6 -0
  174. hexdag/studio/ui/public/hexdag.svg +5 -0
  175. hexdag/studio/ui/src/App.tsx +251 -0
  176. hexdag/studio/ui/src/components/Canvas.tsx +408 -0
  177. hexdag/studio/ui/src/components/ContextMenu.tsx +187 -0
  178. hexdag/studio/ui/src/components/FileBrowser.tsx +123 -0
  179. hexdag/studio/ui/src/components/Header.tsx +181 -0
  180. hexdag/studio/ui/src/components/HexdagNode.tsx +193 -0
  181. hexdag/studio/ui/src/components/NodeInspector.tsx +512 -0
  182. hexdag/studio/ui/src/components/NodePalette.tsx +262 -0
  183. hexdag/studio/ui/src/components/NodePortsSection.tsx +403 -0
  184. hexdag/studio/ui/src/components/PluginManager.tsx +347 -0
  185. hexdag/studio/ui/src/components/PortsEditor.tsx +481 -0
  186. hexdag/studio/ui/src/components/PythonEditor.tsx +195 -0
  187. hexdag/studio/ui/src/components/ValidationPanel.tsx +105 -0
  188. hexdag/studio/ui/src/components/YamlEditor.tsx +196 -0
  189. hexdag/studio/ui/src/components/index.ts +8 -0
  190. hexdag/studio/ui/src/index.css +92 -0
  191. hexdag/studio/ui/src/main.tsx +10 -0
  192. hexdag/studio/ui/src/types/index.ts +123 -0
  193. hexdag/studio/ui/src/vite-env.d.ts +1 -0
  194. hexdag/studio/ui/tailwind.config.js +29 -0
  195. hexdag/studio/ui/tsconfig.json +37 -0
  196. hexdag/studio/ui/tsconfig.node.json +13 -0
  197. hexdag/studio/ui/vite.config.ts +35 -0
  198. hexdag/visualization/__init__.py +69 -0
  199. hexdag/visualization/dag_visualizer.py +1020 -0
  200. hexdag-0.5.0.dev1.dist-info/METADATA +369 -0
  201. hexdag-0.5.0.dev1.dist-info/RECORD +261 -0
  202. hexdag-0.5.0.dev1.dist-info/WHEEL +4 -0
  203. hexdag-0.5.0.dev1.dist-info/entry_points.txt +4 -0
  204. hexdag-0.5.0.dev1.dist-info/licenses/LICENSE +190 -0
  205. hexdag_plugins/.gitignore +43 -0
  206. hexdag_plugins/README.md +73 -0
  207. hexdag_plugins/__init__.py +1 -0
  208. hexdag_plugins/azure/LICENSE +21 -0
  209. hexdag_plugins/azure/README.md +414 -0
  210. hexdag_plugins/azure/__init__.py +21 -0
  211. hexdag_plugins/azure/azure_blob_adapter.py +450 -0
  212. hexdag_plugins/azure/azure_cosmos_adapter.py +383 -0
  213. hexdag_plugins/azure/azure_keyvault_adapter.py +314 -0
  214. hexdag_plugins/azure/azure_openai_adapter.py +415 -0
  215. hexdag_plugins/azure/pyproject.toml +107 -0
  216. hexdag_plugins/azure/tests/__init__.py +1 -0
  217. hexdag_plugins/azure/tests/test_azure_blob_adapter.py +350 -0
  218. hexdag_plugins/azure/tests/test_azure_cosmos_adapter.py +323 -0
  219. hexdag_plugins/azure/tests/test_azure_keyvault_adapter.py +330 -0
  220. hexdag_plugins/azure/tests/test_azure_openai_adapter.py +329 -0
  221. hexdag_plugins/hexdag_etl/README.md +168 -0
  222. hexdag_plugins/hexdag_etl/__init__.py +53 -0
  223. hexdag_plugins/hexdag_etl/examples/01_simple_pandas_transform.py +270 -0
  224. hexdag_plugins/hexdag_etl/examples/02_simple_pandas_only.py +149 -0
  225. hexdag_plugins/hexdag_etl/examples/03_file_io_pipeline.py +109 -0
  226. hexdag_plugins/hexdag_etl/examples/test_pandas_transform.py +84 -0
  227. hexdag_plugins/hexdag_etl/hexdag.toml +25 -0
  228. hexdag_plugins/hexdag_etl/hexdag_etl/__init__.py +48 -0
  229. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/__init__.py +13 -0
  230. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/api_extract.py +230 -0
  231. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/base_node_factory.py +181 -0
  232. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/file_io.py +415 -0
  233. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/outlook.py +492 -0
  234. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/pandas_transform.py +563 -0
  235. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/sql_extract_load.py +112 -0
  236. hexdag_plugins/hexdag_etl/pyproject.toml +82 -0
  237. hexdag_plugins/hexdag_etl/test_transform.py +54 -0
  238. hexdag_plugins/hexdag_etl/tests/test_plugin_integration.py +62 -0
  239. hexdag_plugins/mysql_adapter/LICENSE +21 -0
  240. hexdag_plugins/mysql_adapter/README.md +224 -0
  241. hexdag_plugins/mysql_adapter/__init__.py +6 -0
  242. hexdag_plugins/mysql_adapter/mysql_adapter.py +408 -0
  243. hexdag_plugins/mysql_adapter/pyproject.toml +93 -0
  244. hexdag_plugins/mysql_adapter/tests/test_mysql_adapter.py +259 -0
  245. hexdag_plugins/storage/README.md +184 -0
  246. hexdag_plugins/storage/__init__.py +19 -0
  247. hexdag_plugins/storage/file/__init__.py +5 -0
  248. hexdag_plugins/storage/file/local.py +325 -0
  249. hexdag_plugins/storage/ports/__init__.py +5 -0
  250. hexdag_plugins/storage/ports/vector_store.py +236 -0
  251. hexdag_plugins/storage/sql/__init__.py +7 -0
  252. hexdag_plugins/storage/sql/base.py +187 -0
  253. hexdag_plugins/storage/sql/mysql.py +27 -0
  254. hexdag_plugins/storage/sql/postgresql.py +27 -0
  255. hexdag_plugins/storage/tests/__init__.py +1 -0
  256. hexdag_plugins/storage/tests/test_local_file_storage.py +161 -0
  257. hexdag_plugins/storage/tests/test_sql_adapters.py +212 -0
  258. hexdag_plugins/storage/vector/__init__.py +7 -0
  259. hexdag_plugins/storage/vector/chromadb.py +223 -0
  260. hexdag_plugins/storage/vector/in_memory.py +285 -0
  261. hexdag_plugins/storage/vector/pgvector.py +502 -0
@@ -0,0 +1,221 @@
1
+ """Pipeline validation command for HexDAG CLI."""
2
+
3
+ from pathlib import Path
4
+ from typing import Annotated, Any
5
+
6
+ import typer
7
+ import yaml
8
+ from rich.console import Console
9
+ from rich.panel import Panel
10
+ from rich.table import Table
11
+
12
+ from hexdag.core.pipeline_builder.yaml_validator import YamlValidator
13
+
14
+ app = typer.Typer()
15
+ console = Console()
16
+
17
+
18
+ @app.command()
19
+ def validate(
20
+ yaml_file: Annotated[
21
+ Path,
22
+ typer.Argument(
23
+ help="Path to YAML pipeline file to validate",
24
+ exists=True,
25
+ file_okay=True,
26
+ dir_okay=False,
27
+ readable=True,
28
+ ),
29
+ ],
30
+ explain: Annotated[
31
+ bool,
32
+ typer.Option(
33
+ "--explain",
34
+ "-e",
35
+ help="Show detailed explanation of validation process",
36
+ ),
37
+ ] = False,
38
+ ) -> None:
39
+ """Validate a YAML pipeline file against node schemas.
40
+
41
+ This command validates:
42
+ - YAML syntax and structure
43
+ - Manifest format (apiVersion, kind, metadata, spec)
44
+ - Node types and their schemas
45
+ - Required fields and constraints
46
+ - Dependency references
47
+
48
+ Examples
49
+ --------
50
+ hexdag validate pipeline.yaml
51
+ hexdag validate pipeline.yaml --explain
52
+ """
53
+
54
+ # Read YAML file
55
+ try:
56
+ with Path.open(yaml_file) as f:
57
+ content = f.read()
58
+ config = yaml.safe_load(content)
59
+ except yaml.YAMLError as e:
60
+ console.print(f"[red]✗ YAML Syntax Error:[/red] {e}")
61
+ raise typer.Exit(1) from e
62
+ except OSError as e:
63
+ console.print(f"[red]✗ File Error:[/red] {e}")
64
+ raise typer.Exit(1) from e
65
+
66
+ # Validate using YamlValidator
67
+ validator = YamlValidator()
68
+ result = validator.validate(config)
69
+
70
+ # Display results
71
+ console.print()
72
+ if result.is_valid:
73
+ console.print(f"[green]✓ Validation successful:[/green] {yaml_file}")
74
+ else:
75
+ console.print(f"[red]✗ Validation failed:[/red] {yaml_file}")
76
+
77
+ # Show warnings
78
+ if result.warnings:
79
+ console.print()
80
+ console.print("[yellow]Warnings:[/yellow]")
81
+ for warning in result.warnings:
82
+ console.print(f" [yellow]⚠[/yellow] {warning}")
83
+
84
+ # Show errors
85
+ if result.errors:
86
+ console.print()
87
+ console.print("[red]Errors:[/red]")
88
+ for error in result.errors:
89
+ console.print(f" [red]✗[/red] {error}")
90
+
91
+ # Show suggestions
92
+ if result.suggestions:
93
+ console.print()
94
+ console.print("[blue]Suggestions:[/blue]")
95
+ for suggestion in result.suggestions:
96
+ console.print(f" [blue]ℹ[/blue] {suggestion}")
97
+
98
+ # Explain mode - show validation details
99
+ if explain:
100
+ console.print()
101
+ _explain_validation(config, result)
102
+
103
+ console.print()
104
+
105
+ # Exit with error code if validation failed
106
+ if not result.is_valid:
107
+ raise typer.Exit(1)
108
+
109
+
110
+ def _explain_validation(config: dict, result: Any) -> None:
111
+ """Show detailed explanation of validation process."""
112
+ console.print(Panel("[bold]Validation Process Explanation[/bold]", border_style="blue"))
113
+
114
+ # Show manifest structure
115
+ console.print("\n[bold cyan]1. Manifest Structure[/bold cyan]")
116
+ manifest_table = Table(show_header=True, border_style="cyan")
117
+ manifest_table.add_column("Field", style="green")
118
+ manifest_table.add_column("Value", style="white")
119
+ manifest_table.add_column("Status", style="yellow")
120
+
121
+ api_version = config.get("apiVersion", "missing")
122
+ kind = config.get("kind", "missing")
123
+ name = config.get("metadata", {}).get("name", "missing")
124
+
125
+ manifest_table.add_row(
126
+ "apiVersion",
127
+ str(api_version),
128
+ "[green]✓[/green]" if api_version != "missing" else "[red]✗[/red]",
129
+ )
130
+ manifest_table.add_row(
131
+ "kind", str(kind), "[green]✓[/green]" if kind != "missing" else "[red]✗[/red]"
132
+ )
133
+ manifest_table.add_row(
134
+ "metadata.name",
135
+ str(name),
136
+ "[green]✓[/green]" if name != "missing" else "[red]✗[/red]",
137
+ )
138
+
139
+ console.print(manifest_table)
140
+
141
+ # Show node validation
142
+ if nodes := config.get("spec", {}).get("nodes", []):
143
+ console.print("\n[bold cyan]2. Node Validation[/bold cyan]")
144
+ node_table = Table(show_header=True, border_style="cyan")
145
+ node_table.add_column("Node", style="green")
146
+ node_table.add_column("Type", style="blue")
147
+ node_table.add_column("Schema", style="white")
148
+ node_table.add_column("Status", style="yellow")
149
+
150
+ for i, node in enumerate(nodes):
151
+ node_name = node.get("metadata", {}).get("name", f"node_{i}")
152
+ node_kind = node.get("kind", "unknown")
153
+
154
+ # Parse namespace and type
155
+ if ":" in node_kind:
156
+ namespace, node_type = node_kind.split(":", 1)
157
+ else:
158
+ namespace = "core"
159
+ node_type = node_kind
160
+
161
+ # Remove _node suffix if present
162
+ if node_type.endswith("_node"):
163
+ node_type = node_type[:-5]
164
+
165
+ # Check if node type is known
166
+ from hexdag.core.pipeline_builder.yaml_validator import KNOWN_NODE_TYPES
167
+
168
+ qualified_type = f"{namespace}:{node_type}"
169
+ if qualified_type in KNOWN_NODE_TYPES or node_type in KNOWN_NODE_TYPES:
170
+ schema_status = "[green]✓[/green] Known type"
171
+ elif "." in node_kind:
172
+ schema_status = "[blue]ℹ[/blue] Module path"
173
+ else:
174
+ schema_status = "[yellow]?[/yellow] Unknown type"
175
+
176
+ node_has_error = any(node_name in str(error) for error in result.errors)
177
+ status = "[red]✗[/red]" if node_has_error else "[green]✓[/green]"
178
+
179
+ node_table.add_row(node_name, f"{namespace}:{node_type}", schema_status, status)
180
+
181
+ console.print(node_table)
182
+
183
+ # Show dependency graph
184
+ if nodes:
185
+ console.print("\n[bold cyan]3. Dependency Graph[/bold cyan]")
186
+ dep_table = Table(show_header=True, border_style="cyan")
187
+ dep_table.add_column("Node", style="green")
188
+ dep_table.add_column("Dependencies", style="blue")
189
+ dep_table.add_column("Status", style="yellow")
190
+
191
+ all_node_names = {node.get("metadata", {}).get("name") for node in nodes}
192
+ all_node_names.discard(None)
193
+
194
+ for node in nodes:
195
+ node_name = node.get("metadata", {}).get("name", "unknown")
196
+ deps = node.get("spec", {}).get("dependencies", [])
197
+
198
+ if not deps:
199
+ dep_str = "-"
200
+ status = "[green]✓[/green]"
201
+ else:
202
+ dep_str = ", ".join(str(d) for d in deps)
203
+ if invalid_deps := [d for d in deps if d not in all_node_names]:
204
+ status = f"[red]✗[/red] Invalid: {', '.join(invalid_deps)}"
205
+ else:
206
+ status = "[green]✓[/green]"
207
+
208
+ dep_table.add_row(node_name, dep_str, status)
209
+
210
+ console.print(dep_table)
211
+
212
+ # Show validation summary
213
+ console.print("\n[bold cyan]4. Summary[/bold cyan]")
214
+ summary_text = f"""
215
+ Total Nodes: {len(nodes)}
216
+ Errors: {len(result.errors)}
217
+ Warnings: {len(result.warnings)}
218
+ Suggestions: {len(result.suggestions)}
219
+ Valid: {"[green]Yes[/green]" if result.is_valid else "[red]No[/red]"}
220
+ """
221
+ console.print(Panel(summary_text.strip(), border_style="blue"))
hexdag/cli/main.py ADDED
@@ -0,0 +1,84 @@
1
+ """HexDAG CLI - Main entrypoint."""
2
+
3
+ import sys
4
+
5
+ try:
6
+ import typer
7
+ from rich.console import Console
8
+ except ImportError:
9
+ print("Error: CLI dependencies not installed.")
10
+ print("Please install with:")
11
+ print(" pip install hexdag[cli]")
12
+ print(" or")
13
+ print(" uv pip install hexdag[cli]")
14
+ sys.exit(1)
15
+
16
+ from hexdag.cli.commands import (
17
+ build_cmd,
18
+ create_cmd,
19
+ docs_cmd,
20
+ generate_types_cmd,
21
+ init_cmd,
22
+ pipeline_cmd,
23
+ plugin_dev_cmd,
24
+ plugins_cmd,
25
+ studio_cmd,
26
+ validate_cmd,
27
+ )
28
+
29
+ app = typer.Typer(
30
+ name="hexdag",
31
+ help="HexDAG - Lightweight DAG orchestration framework with hexagonal architecture.",
32
+ no_args_is_help=True,
33
+ rich_markup_mode="rich",
34
+ pretty_exceptions_enable=False,
35
+ )
36
+
37
+ console = Console()
38
+
39
+ app.add_typer(init_cmd.app, name="init", help="Initialize a new HexDAG project")
40
+ app.add_typer(plugins_cmd.app, name="plugins", help="Manage plugins and adapters")
41
+ app.add_typer(plugin_dev_cmd.app, name="plugin", help="Plugin development commands")
42
+ app.add_typer(pipeline_cmd.app, name="pipeline", help="Pipeline validation and execution")
43
+ app.add_typer(create_cmd.app, name="create", help="Create pipeline templates from schemas")
44
+ app.add_typer(docs_cmd.app, name="docs", help="Generate and serve documentation")
45
+ app.add_typer(studio_cmd.app, name="studio", help="Visual editor for pipelines")
46
+
47
+ app.command(name="build", help="Build Docker containers for pipelines")(build_cmd.build)
48
+ app.command(name="validate", help="Validate YAML pipeline files")(validate_cmd.validate)
49
+ app.command(name="generate-types", help="Generate type stubs from YAML pipelines")(
50
+ generate_types_cmd.generate_types
51
+ )
52
+
53
+
54
+ @app.callback(invoke_without_command=True)
55
+ def callback(
56
+ ctx: typer.Context,
57
+ version: bool = typer.Option(
58
+ False,
59
+ "--version",
60
+ "-v",
61
+ help="Show version and exit",
62
+ ),
63
+ ) -> None:
64
+ """HexDAG CLI - Modular DAG orchestration framework."""
65
+ if version:
66
+ # Read version from package metadata
67
+ try:
68
+ from importlib.metadata import version as get_version
69
+
70
+ pkg_version = get_version("hexdag")
71
+ except Exception:
72
+ pkg_version = "0.1.0" # Fallback
73
+
74
+ console.print(f"[bold blue]HexDAG[/bold blue] version [green]{pkg_version}[/green]")
75
+ raise typer.Exit(code=0)
76
+
77
+
78
+ def main() -> None:
79
+ """Main CLI entrypoint."""
80
+ app()
81
+
82
+
83
+ if __name__ == "__main__":
84
+ main()
@@ -0,0 +1,83 @@
1
+ """HexDAG Core - Hexagonal Architecture for DAG Orchestration.
2
+
3
+ The registry-free architecture uses Python's import system directly:
4
+ - Components are plain Python classes
5
+ - YAML uses full module paths (hexdag.builtin.nodes.LLMNode)
6
+ - resolve() imports classes dynamically
7
+
8
+ Example usage:
9
+ from hexdag.core.resolver import resolve
10
+
11
+ # Resolve component by module path
12
+ NodeClass = resolve("hexdag.builtin.nodes.LLMNode")
13
+ """
14
+
15
+ from hexdag.core.configurable import (
16
+ SecretField,
17
+ )
18
+ from hexdag.core.context import (
19
+ ExecutionContext,
20
+ clear_execution_context,
21
+ get_observer_manager,
22
+ get_port,
23
+ get_ports,
24
+ get_run_id,
25
+ set_observer_manager,
26
+ set_ports,
27
+ set_run_id,
28
+ )
29
+ from hexdag.core.exceptions import (
30
+ ConfigurationError,
31
+ DependencyError,
32
+ HexDAGError,
33
+ OrchestratorError,
34
+ ResourceNotFoundError,
35
+ TypeMismatchError,
36
+ ValidationError,
37
+ )
38
+ from hexdag.core.protocols import (
39
+ ComponentWithExecute,
40
+ ConfigurablePort,
41
+ DictConvertible,
42
+ HealthCheckable,
43
+ SchemaProvider,
44
+ has_execute_method,
45
+ is_dict_convertible,
46
+ is_schema_type,
47
+ )
48
+ from hexdag.core.resolver import resolve, resolve_function
49
+
50
+ __all__ = [
51
+ # Module Resolution
52
+ "resolve",
53
+ "resolve_function",
54
+ # Secret helper
55
+ "SecretField",
56
+ # Execution Context
57
+ "ExecutionContext",
58
+ "clear_execution_context",
59
+ "get_observer_manager",
60
+ "get_port",
61
+ "get_ports",
62
+ "get_run_id",
63
+ "set_observer_manager",
64
+ "set_ports",
65
+ "set_run_id",
66
+ # Exceptions
67
+ "HexDAGError",
68
+ "ConfigurationError",
69
+ "ValidationError",
70
+ "ResourceNotFoundError",
71
+ "DependencyError",
72
+ "TypeMismatchError",
73
+ "OrchestratorError",
74
+ # Protocols
75
+ "ComponentWithExecute",
76
+ "ConfigurablePort",
77
+ "DictConvertible",
78
+ "HealthCheckable",
79
+ "SchemaProvider",
80
+ "has_execute_method",
81
+ "is_dict_convertible",
82
+ "is_schema_type",
83
+ ]
@@ -0,0 +1,20 @@
1
+ """Configuration loading and management for HexDAG."""
2
+
3
+ from hexdag.core.config.loader import (
4
+ ConfigLoader,
5
+ clear_config_cache,
6
+ config_to_manifest_entries,
7
+ get_default_config,
8
+ load_config,
9
+ )
10
+ from hexdag.core.config.models import HexDAGConfig, ManifestEntry
11
+
12
+ __all__ = [
13
+ "ConfigLoader",
14
+ "HexDAGConfig",
15
+ "ManifestEntry",
16
+ "clear_config_cache",
17
+ "config_to_manifest_entries",
18
+ "get_default_config",
19
+ "load_config",
20
+ ]