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,208 @@
1
+ """Pipeline creation commands for HexDAG CLI."""
2
+
3
+ from pathlib import Path
4
+ from typing import Annotated
5
+
6
+ import typer
7
+ import yaml
8
+ from rich.console import Console
9
+ from rich.prompt import Confirm, Prompt
10
+
11
+ app = typer.Typer()
12
+ console = Console()
13
+
14
+
15
+ @app.command("pipeline")
16
+ def create_pipeline(
17
+ name: Annotated[
18
+ str | None,
19
+ typer.Option(
20
+ "--name",
21
+ "-n",
22
+ help="Pipeline name",
23
+ ),
24
+ ] = None,
25
+ output: Annotated[
26
+ Path | None,
27
+ typer.Option(
28
+ "--output",
29
+ "-o",
30
+ help="Output file path (default: <name>.yaml)",
31
+ ),
32
+ ] = None,
33
+ template: Annotated[
34
+ str,
35
+ typer.Option(
36
+ "--template",
37
+ "-t",
38
+ help="Template type (minimal, example, full)",
39
+ ),
40
+ ] = "minimal",
41
+ ) -> None:
42
+ """Create a new pipeline YAML file from a template.
43
+
44
+ Examples
45
+ --------
46
+ hexdag create pipeline
47
+ hexdag create pipeline --name my-pipeline
48
+ hexdag create pipeline --template example --output pipeline.yaml
49
+ """
50
+ # Interactive mode if name not provided
51
+ if name is None:
52
+ name = Prompt.ask("[cyan]Pipeline name[/cyan]", default="my-pipeline")
53
+
54
+ # Determine output path
55
+ if output is None:
56
+ output = Path(f"{name}.yaml")
57
+
58
+ if output.exists():
59
+ if not Confirm.ask(f"[yellow]File {output} already exists. Overwrite?[/yellow]"):
60
+ console.print("[red]Aborted.[/red]")
61
+ raise typer.Exit(1)
62
+
63
+ if template == "minimal":
64
+ pipeline = {
65
+ "apiVersion": "hexdag/v1",
66
+ "kind": "Pipeline",
67
+ "metadata": {
68
+ "name": name,
69
+ "description": "TODO: Add description",
70
+ },
71
+ "spec": {
72
+ "nodes": [
73
+ {
74
+ "kind": "hexdag.builtin.nodes.FunctionNode",
75
+ "metadata": {"name": "step1"},
76
+ "spec": {
77
+ "fn": "my_module.my_function",
78
+ "input_mapping": {"x": "input.value"},
79
+ "dependencies": [],
80
+ },
81
+ }
82
+ ]
83
+ },
84
+ }
85
+ elif template == "example":
86
+ pipeline = {
87
+ "apiVersion": "hexdag/v1",
88
+ "kind": "Pipeline",
89
+ "metadata": {
90
+ "name": name,
91
+ "description": "Example multi-step pipeline",
92
+ "version": "1.0",
93
+ "tags": ["example", "demo"],
94
+ },
95
+ "spec": {
96
+ "ports": {
97
+ "llm": {
98
+ "adapter": "hexdag.builtin.adapters.mock.MockLLM",
99
+ "config": {},
100
+ }
101
+ },
102
+ "nodes": [
103
+ {
104
+ "kind": "hexdag.builtin.nodes.FunctionNode",
105
+ "metadata": {
106
+ "name": "input_processor",
107
+ "annotations": {"description": "Process input data"},
108
+ },
109
+ "spec": {
110
+ "fn": "my_module.process_input",
111
+ "input_mapping": {"data": "input.raw_data"},
112
+ "dependencies": [],
113
+ },
114
+ },
115
+ {
116
+ "kind": "hexdag.builtin.nodes.LLMNode",
117
+ "metadata": {
118
+ "name": "analyzer",
119
+ "annotations": {"description": "Analyze processed data"},
120
+ },
121
+ "spec": {
122
+ "prompt_template": "Analyze this data: {{input_processor}}",
123
+ "dependencies": ["input_processor"],
124
+ },
125
+ },
126
+ {
127
+ "kind": "hexdag.builtin.nodes.FunctionNode",
128
+ "metadata": {
129
+ "name": "output_formatter",
130
+ "annotations": {"description": "Format final output"},
131
+ },
132
+ "spec": {
133
+ "fn": "my_module.format_output",
134
+ "input_mapping": {"result": "analyzer"},
135
+ "dependencies": ["analyzer"],
136
+ },
137
+ },
138
+ ],
139
+ },
140
+ }
141
+ else: # full
142
+ pipeline = {
143
+ "apiVersion": "hexdag/v1",
144
+ "kind": "Pipeline",
145
+ "metadata": {
146
+ "name": name,
147
+ "description": "Full-featured pipeline template",
148
+ "version": "1.0",
149
+ "author": "Your Name",
150
+ "tags": ["production", "template"],
151
+ },
152
+ "spec": {
153
+ "input_schema": {
154
+ "type": "object",
155
+ "properties": {"data": {"type": "string"}},
156
+ "required": ["data"],
157
+ },
158
+ "ports": {
159
+ "llm": {
160
+ "adapter": "hexdag.builtin.adapters.mock.MockLLM",
161
+ "config": {},
162
+ }
163
+ },
164
+ "common_field_mappings": {"default_mapping": {"value": "input.data"}},
165
+ "nodes": [
166
+ {
167
+ "kind": "hexdag.builtin.nodes.FunctionNode",
168
+ "metadata": {
169
+ "name": "validator",
170
+ "annotations": {
171
+ "description": "Validate input",
172
+ "timeout": "5s",
173
+ },
174
+ },
175
+ "spec": {
176
+ "fn": "my_module.validate_input",
177
+ "input_mapping": {"data": "input.data"},
178
+ "output_schema": {
179
+ "type": "object",
180
+ "properties": {"valid": {"type": "boolean"}},
181
+ },
182
+ "dependencies": [],
183
+ },
184
+ },
185
+ {
186
+ "kind": "hexdag.builtin.nodes.LLMNode",
187
+ "metadata": {"name": "processor"},
188
+ "spec": {
189
+ "prompt_template": "Process: {{validator.result}}",
190
+ "output_schema": {
191
+ "type": "object",
192
+ "properties": {"processed": {"type": "string"}},
193
+ },
194
+ "dependencies": ["validator"],
195
+ },
196
+ },
197
+ ],
198
+ },
199
+ }
200
+
201
+ # Write to file
202
+ with Path.open(output, "w") as f:
203
+ yaml.dump(pipeline, f, default_flow_style=False, sort_keys=False)
204
+
205
+ console.print(f"[green]✓[/green] Created pipeline: {output}")
206
+ console.print("\n[cyan]Next steps:[/cyan]")
207
+ console.print(f" 1. Edit {output} to customize your pipeline")
208
+ console.print(f" 2. Validate: [bold]hexdag validate {output}[/bold]")
@@ -0,0 +1,293 @@
1
+ """CLI commands for MkDocs documentation."""
2
+
3
+ import subprocess
4
+ from pathlib import Path
5
+
6
+ import typer
7
+ from rich.console import Console
8
+ from rich.panel import Panel
9
+
10
+ app = typer.Typer(help="Generate and serve documentation with MkDocs")
11
+ console = Console()
12
+
13
+
14
+ @app.command("build")
15
+ def build_docs(
16
+ clean: bool = typer.Option(
17
+ False,
18
+ "--clean",
19
+ "-c",
20
+ help="Clean site directory before building",
21
+ ),
22
+ strict: bool = typer.Option(
23
+ False,
24
+ "--strict",
25
+ "-s",
26
+ help="Enable strict mode (warnings as errors)",
27
+ ),
28
+ config: Path | None = typer.Option(
29
+ None,
30
+ "--config",
31
+ help="Path to TOML configuration file (pyproject.toml or hexdag.toml)",
32
+ ),
33
+ ) -> None:
34
+ """Build documentation site with MkDocs.
35
+
36
+ Generates static HTML documentation from markdown files and the component
37
+ registry. The registry hooks automatically generate reference documentation
38
+ during the build process.
39
+
40
+ You can specify a custom TOML configuration to document your project's
41
+ specific components, plugins, and adapters.
42
+
43
+ Examples:
44
+ hexdag docs build
45
+ hexdag docs build --clean
46
+ hexdag docs build --strict
47
+ hexdag docs build --config /path/to/myproject/pyproject.toml
48
+ """
49
+ import os
50
+
51
+ try:
52
+ if config:
53
+ if not config.exists():
54
+ console.print(f"[red]✗[/red] Config file not found: {config}")
55
+ raise typer.Exit(1)
56
+ os.environ["HEXDAG_CONFIG_PATH"] = str(config.resolve())
57
+ console.print(
58
+ Panel.fit(
59
+ "[bold cyan]Building Documentation[/bold cyan]\n"
60
+ "Using MkDocs with registry hooks\n"
61
+ f"Config: {config}",
62
+ border_style="cyan",
63
+ )
64
+ )
65
+ else:
66
+ console.print(
67
+ Panel.fit(
68
+ "[bold cyan]Building Documentation[/bold cyan]\n"
69
+ "Using MkDocs with registry hooks",
70
+ border_style="cyan",
71
+ )
72
+ )
73
+
74
+ cmd = ["mkdocs", "build"]
75
+ if clean:
76
+ cmd.append("--clean")
77
+ if strict:
78
+ cmd.append("--strict")
79
+
80
+ result = subprocess.run(cmd, capture_output=True, text=True, env=os.environ.copy()) # nosec B603
81
+
82
+ if result.returncode == 0:
83
+ console.print("\n[green]✓[/green] Documentation built successfully!")
84
+ console.print("\n[dim]Site output: ./site/[/dim]")
85
+ console.print("[dim]View locally: hexdag docs serve[/dim]")
86
+ else:
87
+ console.print("\n[red]✗[/red] Build failed:")
88
+ console.print(result.stderr)
89
+ raise typer.Exit(1)
90
+
91
+ except FileNotFoundError:
92
+ console.print("\n[red]✗[/red] MkDocs not found. Install with:")
93
+ console.print(" [cyan]pip install hexdag[docs][/cyan]")
94
+ raise typer.Exit(1)
95
+ except Exception as e:
96
+ console.print(f"\n[red]✗[/red] Error building documentation: {e}")
97
+ raise typer.Exit(1)
98
+
99
+
100
+ @app.command("serve")
101
+ def serve_docs(
102
+ port: int = typer.Option(
103
+ 8000,
104
+ "--port",
105
+ "-p",
106
+ help="Port to serve on",
107
+ ),
108
+ host: str = typer.Option(
109
+ "127.0.0.1",
110
+ "--host",
111
+ "-h",
112
+ help="Host to bind to",
113
+ ),
114
+ watch_theme: bool = typer.Option(
115
+ False,
116
+ "--watch-theme",
117
+ help="Watch theme directory for changes",
118
+ ),
119
+ config: Path | None = typer.Option(
120
+ None,
121
+ "--config",
122
+ help="Path to TOML configuration file (pyproject.toml or hexdag.toml)",
123
+ ),
124
+ ) -> None:
125
+ """Serve documentation with live reload.
126
+
127
+ Starts MkDocs development server with live reload. The server watches for
128
+ changes in markdown files and automatically regenerates registry documentation.
129
+
130
+ You can specify a custom TOML configuration to document your project's
131
+ specific components, plugins, and adapters.
132
+
133
+ Examples:
134
+ hexdag docs serve
135
+ hexdag docs serve --port 8080
136
+ hexdag docs serve --watch-theme
137
+ hexdag docs serve --config /path/to/myproject/pyproject.toml
138
+ """
139
+ import os
140
+
141
+ try:
142
+ if config:
143
+ if not config.exists():
144
+ console.print(f"[red]✗[/red] Config file not found: {config}")
145
+ raise typer.Exit(1)
146
+ os.environ["HEXDAG_CONFIG_PATH"] = str(config.resolve())
147
+ console.print(
148
+ Panel.fit(
149
+ "[bold cyan]MkDocs Development Server[/bold cyan]\n"
150
+ f"URL: http://{host}:{port}\n"
151
+ "Live reload: Enabled\n"
152
+ f"Config: {config}",
153
+ border_style="cyan",
154
+ )
155
+ )
156
+ else:
157
+ console.print(
158
+ Panel.fit(
159
+ "[bold cyan]MkDocs Development Server[/bold cyan]\n"
160
+ f"URL: http://{host}:{port}\n"
161
+ "Live reload: Enabled",
162
+ border_style="cyan",
163
+ )
164
+ )
165
+
166
+ cmd = ["mkdocs", "serve", "--dev-addr", f"{host}:{port}"]
167
+ if watch_theme:
168
+ cmd.append("--watch-theme")
169
+
170
+ console.print(f"\n[green]✓[/green] Starting server at [cyan]http://{host}:{port}[/cyan]")
171
+ console.print("\nPress [red]Ctrl+C[/red] to stop the server\n")
172
+
173
+ # Run mkdocs serve (blocking)
174
+ subprocess.run(cmd, env=os.environ.copy()) # nosec B603
175
+
176
+ except FileNotFoundError:
177
+ console.print("\n[red]✗[/red] MkDocs not found. Install with:")
178
+ console.print(" [cyan]pip install hexdag[docs][/cyan]")
179
+ raise typer.Exit(1)
180
+ except KeyboardInterrupt:
181
+ console.print("\n\n[yellow]Server stopped[/yellow]")
182
+ except Exception as e:
183
+ console.print(f"\n[red]✗[/red] Error starting server: {e}")
184
+ raise typer.Exit(1)
185
+
186
+
187
+ @app.command("deploy")
188
+ def deploy_docs(
189
+ remote_branch: str = typer.Option(
190
+ "gh-pages",
191
+ "--remote-branch",
192
+ "-b",
193
+ help="Remote branch to deploy to",
194
+ ),
195
+ message: str | None = typer.Option(
196
+ None,
197
+ "--message",
198
+ "-m",
199
+ help="Commit message for deploy",
200
+ ),
201
+ ) -> None:
202
+ """Deploy documentation to GitHub Pages.
203
+
204
+ Builds and deploys documentation to the specified remote branch (default: gh-pages).
205
+ Requires git repository with GitHub remote configured.
206
+
207
+ Examples:
208
+ hexdag docs deploy
209
+ hexdag docs deploy --message "Update docs"
210
+ hexdag docs deploy --remote-branch main
211
+ """
212
+ try:
213
+ console.print(
214
+ Panel.fit(
215
+ f"[bold cyan]Deploying Documentation[/bold cyan]\nRemote branch: {remote_branch}",
216
+ border_style="cyan",
217
+ )
218
+ )
219
+
220
+ cmd = ["mkdocs", "gh-deploy", "--remote-branch", remote_branch]
221
+ if message:
222
+ cmd.extend(["--message", message])
223
+
224
+ result = subprocess.run(cmd, capture_output=True, text=True) # nosec B603
225
+
226
+ if result.returncode == 0:
227
+ console.print("\n[green]✓[/green] Documentation deployed successfully!")
228
+ else:
229
+ console.print("\n[red]✗[/red] Deploy failed:")
230
+ console.print(result.stderr)
231
+ raise typer.Exit(1)
232
+
233
+ except FileNotFoundError:
234
+ console.print("\n[red]✗[/red] MkDocs not found. Install with:")
235
+ console.print(" [cyan]pip install hexdag[docs][/cyan]")
236
+ raise typer.Exit(1)
237
+ except Exception as e:
238
+ console.print(f"\n[red]✗[/red] Error deploying documentation: {e}")
239
+ raise typer.Exit(1)
240
+
241
+
242
+ @app.command("new")
243
+ def new_page(
244
+ path: str = typer.Argument(..., help="Path for new page (e.g., guide/my-guide.md)"),
245
+ title: str | None = typer.Option(None, "--title", "-t", help="Page title"),
246
+ ) -> None:
247
+ """Create a new documentation page.
248
+
249
+ Creates a new markdown file with basic frontmatter and adds it to the
250
+ documentation structure.
251
+
252
+ Examples:
253
+ hexdag docs new guide/custom-nodes.md
254
+ hexdag docs new guide/advanced.md --title "Advanced Usage"
255
+ """
256
+ docs_dir = Path("docs")
257
+ if not docs_dir.exists():
258
+ console.print(f"[red]✗[/red] Documentation directory not found: {docs_dir}")
259
+ raise typer.Exit(1)
260
+
261
+ file_path = docs_dir / path
262
+ if file_path.exists():
263
+ console.print(f"[red]✗[/red] File already exists: {file_path}")
264
+ raise typer.Exit(1)
265
+
266
+ file_path.parent.mkdir(parents=True, exist_ok=True)
267
+
268
+ # Generate title from filename if not provided
269
+ if not title:
270
+ title = file_path.stem.replace("-", " ").replace("_", " ").title()
271
+
272
+ content = f"""# {title}
273
+
274
+ Add your content here.
275
+
276
+ ## Overview
277
+
278
+ ...
279
+
280
+ ## Examples
281
+
282
+ ...
283
+
284
+ ## Next Steps
285
+
286
+ ...
287
+ """
288
+
289
+ file_path.write_text(content)
290
+
291
+ console.print(f"[green]✓[/green] Created new page: [cyan]{file_path}[/cyan]")
292
+ console.print("\nRemember to add it to [cyan]mkdocs.yml[/cyan] navigation:")
293
+ console.print(f" - {title}: {path}")