blokctl 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/dist/commands/build/index.d.ts +2 -0
  2. package/dist/commands/build/index.js +210 -0
  3. package/dist/commands/config/index.d.ts +1 -0
  4. package/dist/commands/config/index.js +46 -0
  5. package/dist/commands/cost/index.d.ts +1 -0
  6. package/dist/commands/cost/index.js +74 -0
  7. package/dist/commands/create/node.d.ts +2 -0
  8. package/dist/commands/create/node.js +541 -0
  9. package/dist/commands/create/project.d.ts +2 -0
  10. package/dist/commands/create/project.js +941 -0
  11. package/dist/commands/create/utils/Examples.d.ts +39 -0
  12. package/dist/commands/create/utils/Examples.js +983 -0
  13. package/dist/commands/create/workflow.d.ts +2 -0
  14. package/dist/commands/create/workflow.js +109 -0
  15. package/dist/commands/deploy/index.d.ts +2 -0
  16. package/dist/commands/deploy/index.js +176 -0
  17. package/dist/commands/dev/index.d.ts +2 -0
  18. package/dist/commands/dev/index.js +190 -0
  19. package/dist/commands/generate/GenerationAnalytics.d.ts +61 -0
  20. package/dist/commands/generate/GenerationAnalytics.js +162 -0
  21. package/dist/commands/generate/GenerationAnalytics.test.d.ts +1 -0
  22. package/dist/commands/generate/GenerationAnalytics.test.js +407 -0
  23. package/dist/commands/generate/NodeFileWriter.d.ts +5 -0
  24. package/dist/commands/generate/NodeFileWriter.js +240 -0
  25. package/dist/commands/generate/NodeGenerator.d.ts +20 -0
  26. package/dist/commands/generate/NodeGenerator.js +181 -0
  27. package/dist/commands/generate/NodeGenerator.test.d.ts +1 -0
  28. package/dist/commands/generate/NodeGenerator.test.js +101 -0
  29. package/dist/commands/generate/PromptVersioning.d.ts +25 -0
  30. package/dist/commands/generate/PromptVersioning.js +71 -0
  31. package/dist/commands/generate/PromptVersioning.test.d.ts +1 -0
  32. package/dist/commands/generate/PromptVersioning.test.js +120 -0
  33. package/dist/commands/generate/RegisterNode.d.ts +3 -0
  34. package/dist/commands/generate/RegisterNode.js +37 -0
  35. package/dist/commands/generate/RuntimeGenerator.d.ts +40 -0
  36. package/dist/commands/generate/RuntimeGenerator.js +369 -0
  37. package/dist/commands/generate/RuntimeGenerator.test.d.ts +1 -0
  38. package/dist/commands/generate/RuntimeGenerator.test.js +553 -0
  39. package/dist/commands/generate/TriggerGenerator.d.ts +22 -0
  40. package/dist/commands/generate/TriggerGenerator.js +220 -0
  41. package/dist/commands/generate/TriggerGenerator.test.d.ts +1 -0
  42. package/dist/commands/generate/TriggerGenerator.test.js +209 -0
  43. package/dist/commands/generate/WorkflowGenerator.d.ts +20 -0
  44. package/dist/commands/generate/WorkflowGenerator.js +131 -0
  45. package/dist/commands/generate/WorkflowGenerator.test.d.ts +1 -0
  46. package/dist/commands/generate/WorkflowGenerator.test.js +77 -0
  47. package/dist/commands/generate/e2e/NodeGenerator.e2e.test.d.ts +1 -0
  48. package/dist/commands/generate/e2e/NodeGenerator.e2e.test.js +216 -0
  49. package/dist/commands/generate/e2e/RuntimeGenerator.e2e.test.d.ts +1 -0
  50. package/dist/commands/generate/e2e/RuntimeGenerator.e2e.test.js +759 -0
  51. package/dist/commands/generate/e2e/TriggerGenerator.e2e.test.d.ts +1 -0
  52. package/dist/commands/generate/e2e/TriggerGenerator.e2e.test.js +295 -0
  53. package/dist/commands/generate/e2e/WorkflowGenerator.e2e.test.d.ts +1 -0
  54. package/dist/commands/generate/e2e/WorkflowGenerator.e2e.test.js +353 -0
  55. package/dist/commands/generate/index.d.ts +1 -0
  56. package/dist/commands/generate/index.js +418 -0
  57. package/dist/commands/generate/prompts/create-fn-node.system.d.ts +5 -0
  58. package/dist/commands/generate/prompts/create-fn-node.system.js +256 -0
  59. package/dist/commands/generate/prompts/create-node-manifest.system.d.ts +4 -0
  60. package/dist/commands/generate/prompts/create-node-manifest.system.js +41 -0
  61. package/dist/commands/generate/prompts/create-node.system.d.ts +5 -0
  62. package/dist/commands/generate/prompts/create-node.system.js +114 -0
  63. package/dist/commands/generate/prompts/create-readme.system.d.ts +4 -0
  64. package/dist/commands/generate/prompts/create-readme.system.js +83 -0
  65. package/dist/commands/generate/prompts/create-runtime.system.d.ts +5 -0
  66. package/dist/commands/generate/prompts/create-runtime.system.js +284 -0
  67. package/dist/commands/generate/prompts/create-trigger.system.d.ts +5 -0
  68. package/dist/commands/generate/prompts/create-trigger.system.js +293 -0
  69. package/dist/commands/generate/prompts/create-workflow.system.d.ts +5 -0
  70. package/dist/commands/generate/prompts/create-workflow.system.js +476 -0
  71. package/dist/commands/generate/prompts/register-node.system.d.ts +4 -0
  72. package/dist/commands/generate/prompts/register-node.system.js +26 -0
  73. package/dist/commands/generate/validators/CompilationValidator.d.ts +9 -0
  74. package/dist/commands/generate/validators/CompilationValidator.js +86 -0
  75. package/dist/commands/generate/validators/CompilationValidator.test.d.ts +1 -0
  76. package/dist/commands/generate/validators/CompilationValidator.test.js +161 -0
  77. package/dist/commands/generate/validators/NodeValidator.d.ts +18 -0
  78. package/dist/commands/generate/validators/NodeValidator.js +217 -0
  79. package/dist/commands/generate/validators/NodeValidator.test.d.ts +1 -0
  80. package/dist/commands/generate/validators/NodeValidator.test.js +281 -0
  81. package/dist/commands/generate/validators/WorkflowValidator.d.ts +6 -0
  82. package/dist/commands/generate/validators/WorkflowValidator.js +301 -0
  83. package/dist/commands/generate/validators/WorkflowValidator.test.d.ts +1 -0
  84. package/dist/commands/generate/validators/WorkflowValidator.test.js +647 -0
  85. package/dist/commands/generate/validators/index.d.ts +4 -0
  86. package/dist/commands/generate/validators/index.js +2 -0
  87. package/dist/commands/graph/index.d.ts +1 -0
  88. package/dist/commands/graph/index.js +69 -0
  89. package/dist/commands/install/index.d.ts +1 -0
  90. package/dist/commands/install/index.js +4 -0
  91. package/dist/commands/install/node.d.ts +4 -0
  92. package/dist/commands/install/node.js +136 -0
  93. package/dist/commands/install/workflow.d.ts +4 -0
  94. package/dist/commands/install/workflow.js +62 -0
  95. package/dist/commands/login/index.d.ts +2 -0
  96. package/dist/commands/login/index.js +77 -0
  97. package/dist/commands/logout/index.d.ts +2 -0
  98. package/dist/commands/logout/index.js +20 -0
  99. package/dist/commands/marketplace/runtime.d.ts +54 -0
  100. package/dist/commands/marketplace/runtime.js +350 -0
  101. package/dist/commands/migrate/index.d.ts +1 -0
  102. package/dist/commands/migrate/index.js +14 -0
  103. package/dist/commands/migrate/node.d.ts +2 -0
  104. package/dist/commands/migrate/node.js +110 -0
  105. package/dist/commands/monitor/index.d.ts +1 -0
  106. package/dist/commands/monitor/index.js +28 -0
  107. package/dist/commands/monitor/monitor-component.d.ts +1 -0
  108. package/dist/commands/monitor/monitor-component.js +271 -0
  109. package/dist/commands/monitor/static/index.html +2124 -0
  110. package/dist/commands/monitor/static-web-server.d.ts +1 -0
  111. package/dist/commands/monitor/static-web-server.js +89 -0
  112. package/dist/commands/profile/index.d.ts +1 -0
  113. package/dist/commands/profile/index.js +112 -0
  114. package/dist/commands/publish/index.d.ts +1 -0
  115. package/dist/commands/publish/index.js +4 -0
  116. package/dist/commands/publish/node.d.ts +4 -0
  117. package/dist/commands/publish/node.js +231 -0
  118. package/dist/commands/publish/workflow.d.ts +4 -0
  119. package/dist/commands/publish/workflow.js +165 -0
  120. package/dist/commands/search/docs.d.ts +17 -0
  121. package/dist/commands/search/docs.js +179 -0
  122. package/dist/commands/search/index.d.ts +1 -0
  123. package/dist/commands/search/index.js +5 -0
  124. package/dist/commands/search/indexer.d.ts +10 -0
  125. package/dist/commands/search/indexer.js +265 -0
  126. package/dist/commands/search/nodes.d.ts +4 -0
  127. package/dist/commands/search/nodes.js +101 -0
  128. package/dist/commands/search/workflow.d.ts +4 -0
  129. package/dist/commands/search/workflow.js +100 -0
  130. package/dist/commands/trace/index.d.ts +1 -0
  131. package/dist/commands/trace/index.js +26 -0
  132. package/dist/commands/trace/startStudio.d.ts +8 -0
  133. package/dist/commands/trace/startStudio.js +116 -0
  134. package/dist/index.d.ts +17 -0
  135. package/dist/index.js +186 -0
  136. package/dist/services/commander.d.ts +9 -0
  137. package/dist/services/commander.js +20 -0
  138. package/dist/services/constants.d.ts +1 -0
  139. package/dist/services/constants.js +3 -0
  140. package/dist/services/local-token-manager.d.ts +14 -0
  141. package/dist/services/local-token-manager.js +99 -0
  142. package/dist/services/non-interactive.d.ts +5 -0
  143. package/dist/services/non-interactive.js +30 -0
  144. package/dist/services/package-manager.d.ts +35 -0
  145. package/dist/services/package-manager.js +111 -0
  146. package/dist/services/posthog.d.ts +31 -0
  147. package/dist/services/posthog.js +159 -0
  148. package/dist/services/registry-manager.d.ts +9 -0
  149. package/dist/services/registry-manager.js +26 -0
  150. package/dist/services/runtime-detector.d.ts +23 -0
  151. package/dist/services/runtime-detector.js +181 -0
  152. package/dist/services/runtime-setup.d.ts +36 -0
  153. package/dist/services/runtime-setup.js +250 -0
  154. package/dist/services/utils.d.ts +2 -0
  155. package/dist/services/utils.js +29 -0
  156. package/dist/services/workflow-loader.d.ts +30 -0
  157. package/dist/services/workflow-loader.js +46 -0
  158. package/dist/studio-dist/assets/charts-Dso0hPUR.js +68 -0
  159. package/dist/studio-dist/assets/graph-CsV2nWGn.js +23 -0
  160. package/dist/studio-dist/assets/icons-zP8LLgPh.js +311 -0
  161. package/dist/studio-dist/assets/index-CLyEkXMx.css +1 -0
  162. package/dist/studio-dist/assets/index-CNXFX_ar.js +27 -0
  163. package/dist/studio-dist/assets/react-vendor--Eh9ivFN.js +17 -0
  164. package/dist/studio-dist/assets/tanstack-query-CiM1U6F5.js +1 -0
  165. package/dist/studio-dist/assets/tanstack-router-Btjy0MKq.js +25 -0
  166. package/dist/studio-dist/assets/tanstack-table-DhwRvuH2.js +22 -0
  167. package/dist/studio-dist/favicon.svg +5 -0
  168. package/dist/studio-dist/index.html +21 -0
  169. package/package.json +75 -0
@@ -0,0 +1,983 @@
1
+ const node_file = `import ApiCall from "@blok/api-call";
2
+ import IfElse from "@blok/if-else";
3
+ import type { NodeBase } from "@blok/shared";
4
+ import ChainInit from "./nodes/chain-init/index";
5
+ import ChainVerify from "./nodes/chain-verify/index";
6
+ import ExampleNodes from "./nodes/examples/index";
7
+ import RuntimeBridge from "./nodes/runtime-bridge/index";
8
+
9
+ const nodes: {
10
+ [key: string]: NodeBase;
11
+ } = {
12
+ "@blok/api-call": ApiCall,
13
+ "@blok/if-else": IfElse,
14
+ "chain-init": ChainInit,
15
+ "chain-verify": ChainVerify,
16
+ "runtime-bridge": RuntimeBridge,
17
+ ...ExampleNodes,
18
+ };
19
+
20
+ export default nodes;
21
+ `;
22
+ const package_dependencies = {
23
+ ai: "^4.1.50",
24
+ "@ai-sdk/openai": "^1.2.0",
25
+ ejs: "^3.1.10",
26
+ pg: "^8.13.3",
27
+ mongodb: "^6.14.2",
28
+ };
29
+ const package_dev_dependencies = {
30
+ "@types/ejs": "^3.1.5",
31
+ "@types/pg": "^8.11.11",
32
+ };
33
+ const python3_file = `
34
+ from core.blok import BlokService
35
+ from core.types.context import Context
36
+ from core.types.blok_response import BlokResponse
37
+ from core.types.global_error import GlobalError
38
+ from typing import Any, Dict
39
+ import traceback
40
+
41
+ class Node(BlokService):
42
+ def __init__(self):
43
+ BlokService.__init__(self)
44
+ self.input_schema = {}
45
+ self.output_schema = {}
46
+
47
+ async def handle(self, ctx: Context, inputs: Dict[str, Any]) -> BlokResponse:
48
+ response = BlokResponse()
49
+
50
+ try:
51
+ response.setSuccess({ "message": "Hello World from Python3!" })
52
+ except Exception as error:
53
+ err = GlobalError(error)
54
+ err.setCode(500)
55
+ err.setName(self.name)
56
+
57
+ stack_trace = traceback.format_exc()
58
+ err.setStack(stack_trace)
59
+ response.success = False
60
+ response.setError(err)
61
+
62
+ return response
63
+ `;
64
+ const examples_url = `
65
+ Examples:
66
+ 1- Open "workflow-docs.json" in your browser at http://localhost:4000/workflow-docs
67
+ 2- Open "db-manager.json" in your browser at http://localhost:4000/db-manager
68
+ 3- Open "dashboard-gen.json" in your browser at http://localhost:4000/dashboard-gen
69
+ 4- Open "countries.json" in your browser at http://localhost:4000/countries
70
+
71
+ For more documentation, visit src/nodes/examples/README.md. The first three examples require a PostgreSQL database to function.
72
+ `;
73
+ const workflow_template = `
74
+ {
75
+ "name": "",
76
+ "description": "",
77
+ "version": "1.0.0",
78
+ "trigger": {
79
+ "http": {
80
+ "method": "GET",
81
+ "path": "/",
82
+ "accept": "application/json"
83
+ }
84
+ },
85
+ "steps": [
86
+ {
87
+ "name": "node-name",
88
+ "node": "node-module-name",
89
+ "type": "module"
90
+ }
91
+ ],
92
+ "nodes": {
93
+ "name": {
94
+ "inputs": {
95
+
96
+ }
97
+ }
98
+ }
99
+ }
100
+ `;
101
+ const supervisord_nodejs = `
102
+ [supervisord]
103
+ nodaemon=true
104
+
105
+ [program:nodejs_app]
106
+ command=npm start
107
+ directory=/app
108
+ autostart=true
109
+ autorestart=true
110
+ stderr_logfile=/var/log/nodejs.err.log
111
+ stdout_logfile=/var/log/nodejs.out.log
112
+ `;
113
+ const supervisord_python = `
114
+ [program:python_app]
115
+ command=python3 /app/.blok/runtimes/python3/server.py
116
+ directory=/app
117
+ autostart=true
118
+ autorestart=true
119
+ stderr_logfile=/var/log/python.err.log
120
+ stdout_logfile=/var/log/python.out.log
121
+ `;
122
+ const go_node_file = `package main
123
+
124
+ import (
125
+ "github.com/blok/sdk"
126
+ )
127
+
128
+ type HelloWorldNode struct{}
129
+
130
+ func (n *HelloWorldNode) Execute(ctx *sdk.Context, config map[string]interface{}) (*sdk.ExecutionResult, error) {
131
+ // Access request body
132
+ name := "World"
133
+ if body, ok := ctx.Request.Body.(map[string]interface{}); ok {
134
+ if nameVal, ok := body["name"].(string); ok {
135
+ name = nameVal
136
+ }
137
+ }
138
+
139
+ // Access configuration
140
+ prefix := "Hello"
141
+ if prefixVal, ok := config["prefix"].(string); ok {
142
+ prefix = prefixVal
143
+ }
144
+
145
+ // Store result in context for downstream nodes
146
+ ctx.Vars["greeting"] = prefix + ", " + name + "!"
147
+
148
+ // Return successful result
149
+ return &sdk.ExecutionResult{
150
+ Success: true,
151
+ Data: map[string]interface{}{
152
+ "message": prefix + ", " + name + "!",
153
+ "timestamp": sdk.GetCurrentTimestamp(),
154
+ "language": "Go",
155
+ },
156
+ Errors: nil,
157
+ }, nil
158
+ }
159
+
160
+ func main() {
161
+ // Register node
162
+ registry := sdk.NewNodeRegistry()
163
+ registry.Register("{{NODE_NAME}}", &HelloWorldNode{})
164
+
165
+ // Start HTTP server
166
+ server := sdk.NewHTTPServer(registry, ":8080")
167
+ if err := server.Start(); err != nil {
168
+ panic(err)
169
+ }
170
+ }
171
+ `;
172
+ const go_mod_file = `module github.com/blok/nodes/{{NODE_NAME}}
173
+
174
+ go 1.21
175
+
176
+ require github.com/blok/sdk v1.0.0
177
+ `;
178
+ const go_dockerfile = `FROM golang:1.21-alpine AS builder
179
+
180
+ WORKDIR /app
181
+ COPY go.mod go.sum ./
182
+ RUN go mod download
183
+
184
+ COPY . .
185
+ RUN CGO_ENABLED=0 GOOS=linux go build -o /node main.go
186
+
187
+ FROM alpine:latest
188
+ RUN apk --no-cache add ca-certificates
189
+ WORKDIR /root/
190
+ COPY --from=builder /node .
191
+
192
+ EXPOSE 8080
193
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
194
+ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
195
+
196
+ CMD ["./node"]
197
+ `;
198
+ const java_node_file = `package com.blok.nodes;
199
+
200
+ import com.blok.runtime.Blok;
201
+ import com.blok.runtime.NodeRegistry;
202
+ import com.blok.server.RuntimeServer;
203
+ import java.util.HashMap;
204
+ import java.util.Map;
205
+
206
+ public class HelloWorldNode implements Blok.NodeHandler {
207
+ @Override
208
+ public Blok.ExecutionResult execute(Blok.Context ctx, Map<String, Object> config) {
209
+ try {
210
+ // Access request body
211
+ String name = "World";
212
+ if (ctx.request.body != null && ctx.request.body.containsKey("name")) {
213
+ name = (String) ctx.request.body.get("name");
214
+ }
215
+
216
+ // Access configuration
217
+ String prefix = "Hello";
218
+ if (config != null && config.containsKey("prefix")) {
219
+ prefix = (String) config.get("prefix");
220
+ }
221
+
222
+ // Store result in context for downstream nodes
223
+ String greeting = prefix + ", " + name + "!";
224
+ ctx.vars.put("greeting", greeting);
225
+
226
+ // Build response data
227
+ Map<String, Object> data = new HashMap<>();
228
+ data.put("message", greeting);
229
+ data.put("timestamp", System.currentTimeMillis());
230
+ data.put("language", "Java");
231
+
232
+ // Return successful result
233
+ return new Blok.ExecutionResult(true, data, null, null, null);
234
+ } catch (Exception e) {
235
+ return new Blok.ExecutionResult(false, null, e.getMessage(), null, null);
236
+ }
237
+ }
238
+
239
+ public static void main(String[] args) {
240
+ try {
241
+ // Register node
242
+ NodeRegistry registry = new NodeRegistry();
243
+ registry.register("{{NODE_NAME}}", new HelloWorldNode());
244
+
245
+ // Start HTTP server
246
+ RuntimeServer server = new RuntimeServer(registry, 8080);
247
+ server.start();
248
+ } catch (Exception e) {
249
+ e.printStackTrace();
250
+ System.exit(1);
251
+ }
252
+ }
253
+ }
254
+ `;
255
+ const java_pom_file = `<?xml version="1.0" encoding="UTF-8"?>
256
+ <project xmlns="http://maven.apache.org/POM/4.0.0"
257
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
258
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
259
+ http://maven.apache.org/xsd/maven-4.0.0.xsd">
260
+ <modelVersion>4.0.0</modelVersion>
261
+
262
+ <groupId>com.blok</groupId>
263
+ <artifactId>{{NODE_NAME}}</artifactId>
264
+ <version>1.0.0</version>
265
+
266
+ <properties>
267
+ <maven.compiler.source>17</maven.compiler.source>
268
+ <maven.compiler.target>17</maven.compiler.target>
269
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
270
+ </properties>
271
+
272
+ <dependencies>
273
+ <dependency>
274
+ <groupId>com.google.code.gson</groupId>
275
+ <artifactId>gson</artifactId>
276
+ <version>2.10.1</version>
277
+ </dependency>
278
+ </dependencies>
279
+
280
+ <build>
281
+ <plugins>
282
+ <plugin>
283
+ <groupId>org.apache.maven.plugins</groupId>
284
+ <artifactId>maven-shade-plugin</artifactId>
285
+ <version>3.5.0</version>
286
+ <executions>
287
+ <execution>
288
+ <phase>package</phase>
289
+ <goals>
290
+ <goal>shade</goal>
291
+ </goals>
292
+ <configuration>
293
+ <transformers>
294
+ <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
295
+ <mainClass>com.blok.nodes.HelloWorldNode</mainClass>
296
+ </transformer>
297
+ </transformers>
298
+ </configuration>
299
+ </execution>
300
+ </executions>
301
+ </plugin>
302
+ </plugins>
303
+ </build>
304
+ </project>
305
+ `;
306
+ const java_dockerfile = `FROM maven:3.9-eclipse-temurin-17 AS builder
307
+
308
+ WORKDIR /app
309
+ COPY pom.xml .
310
+ RUN mvn dependency:go-offline
311
+
312
+ COPY src ./src
313
+ RUN mvn clean package -DskipTests
314
+
315
+ FROM eclipse-temurin:17-jre-alpine
316
+
317
+ WORKDIR /root/
318
+ COPY --from=builder /app/target/{{NODE_NAME}}-1.0.0.jar ./app.jar
319
+
320
+ EXPOSE 8080
321
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
322
+ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
323
+
324
+ CMD ["java", "-jar", "app.jar"]
325
+ `;
326
+ const rust_node_file = `use async_trait::async_trait;
327
+ use blok::{NodeHandler, NodeRegistry, Context};
328
+ use std::collections::HashMap;
329
+
330
+ /// {{NODE_NAME}} - A Blok node implemented in Rust
331
+ struct {{NODE_NAME_PASCAL}};
332
+
333
+ #[async_trait]
334
+ impl NodeHandler for {{NODE_NAME_PASCAL}} {
335
+ async fn execute(
336
+ &self,
337
+ ctx: &mut Context,
338
+ config: &HashMap<String, serde_json::Value>,
339
+ ) -> Result<serde_json::Value, Box<dyn std::error::Error + Send + Sync>> {
340
+ // Access request body
341
+ let name = ctx.request.body
342
+ .get("name")
343
+ .and_then(|v| v.as_str())
344
+ .unwrap_or("World");
345
+
346
+ // Access configuration
347
+ let prefix = config
348
+ .get("prefix")
349
+ .and_then(|v| v.as_str())
350
+ .unwrap_or("Hello");
351
+
352
+ let message = format!("{}, {}!", prefix, name);
353
+
354
+ // Store in context vars for downstream nodes
355
+ ctx.vars.insert(
356
+ "greeting".to_string(),
357
+ serde_json::Value::String(message.clone()),
358
+ );
359
+
360
+ // Return response
361
+ Ok(serde_json::json!({
362
+ "message": message,
363
+ "language": "Rust"
364
+ }))
365
+ }
366
+ }
367
+
368
+ #[tokio::main]
369
+ async fn main() {
370
+ // Initialize tracing
371
+ tracing_subscriber::fmt::init();
372
+
373
+ // Register nodes
374
+ let mut registry = NodeRegistry::new("1.0.0");
375
+ registry.register("{{NODE_NAME}}", {{NODE_NAME_PASCAL}});
376
+
377
+ // Start HTTP server
378
+ blok::server::serve(registry, 8080).await.unwrap();
379
+ }
380
+ `;
381
+ const rust_cargo_file = `[package]
382
+ name = "{{NODE_NAME}}"
383
+ version = "1.0.0"
384
+ edition = "2021"
385
+
386
+ [[bin]]
387
+ name = "{{NODE_NAME}}"
388
+ path = "src/main.rs"
389
+
390
+ [dependencies]
391
+ blok = { path = "../../sdk" }
392
+ tokio = { version = "1", features = ["full"] }
393
+ serde = { version = "1", features = ["derive"] }
394
+ serde_json = "1"
395
+ async-trait = "0.1"
396
+ tracing = "0.1"
397
+ tracing-subscriber = "0.3"
398
+ `;
399
+ const rust_dockerfile = `FROM rust:1.77-alpine AS builder
400
+
401
+ RUN apk add --no-cache musl-dev
402
+
403
+ WORKDIR /app
404
+ COPY Cargo.toml Cargo.lock ./
405
+ RUN mkdir -p src && echo 'fn main() {}' > src/main.rs && \\
406
+ cargo build --release 2>/dev/null || true && rm -rf src
407
+
408
+ COPY . .
409
+ RUN cargo build --release
410
+
411
+ FROM alpine:latest
412
+ RUN apk --no-cache add ca-certificates
413
+ WORKDIR /root/
414
+ COPY --from=builder /app/target/release/{{NODE_NAME}} .
415
+
416
+ EXPOSE 8080
417
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
418
+ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
419
+
420
+ CMD ["./{{NODE_NAME}}"]
421
+ `;
422
+ const csharp_node_file = `using System.Text.Json;
423
+ using Blok.Runtime;
424
+
425
+ namespace Blok.Runtime.Nodes;
426
+
427
+ public class {{NODE_NAME_PASCAL}}Node : INodeHandler
428
+ {
429
+ public Task<JsonElement> ExecuteAsync(Context ctx, Dictionary<string, JsonElement> config)
430
+ {
431
+ // Access request body
432
+ var name = "World";
433
+ if (ctx.Request.Body.ValueKind == JsonValueKind.Object &&
434
+ ctx.Request.Body.TryGetProperty("name", out var nameEl) &&
435
+ nameEl.ValueKind == JsonValueKind.String)
436
+ {
437
+ name = nameEl.GetString() ?? "World";
438
+ }
439
+
440
+ // Access configuration
441
+ var prefix = "Hello";
442
+ if (config.TryGetValue("prefix", out var prefixEl) &&
443
+ prefixEl.ValueKind == JsonValueKind.String)
444
+ {
445
+ prefix = prefixEl.GetString() ?? "Hello";
446
+ }
447
+
448
+ var message = $"{prefix}, {name}!";
449
+
450
+ // Store in context for downstream nodes
451
+ ctx.Vars["greeting"] = JsonSerializer.SerializeToElement(message);
452
+
453
+ // Return response
454
+ var result = JsonSerializer.SerializeToElement(new
455
+ {
456
+ message,
457
+ timestamp = DateTime.UtcNow.ToString("o"),
458
+ language = "C#"
459
+ });
460
+
461
+ return Task.FromResult(result);
462
+ }
463
+ }
464
+ `;
465
+ const csharp_csproj_file = `<Project Sdk="Microsoft.NET.Sdk.Web">
466
+ <PropertyGroup>
467
+ <TargetFramework>net8.0</TargetFramework>
468
+ <RootNamespace>Blok.Runtime</RootNamespace>
469
+ <ImplicitUsings>enable</ImplicitUsings>
470
+ <Nullable>enable</Nullable>
471
+ </PropertyGroup>
472
+ </Project>
473
+ `;
474
+ const csharp_dockerfile = `FROM mcr.microsoft.com/dotnet/sdk:8.0 AS builder
475
+ WORKDIR /app
476
+ COPY *.csproj .
477
+ RUN dotnet restore
478
+ COPY . .
479
+ RUN dotnet publish -c Release -o /out
480
+
481
+ FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
482
+ WORKDIR /app
483
+ COPY --from=builder /out .
484
+
485
+ EXPOSE 8080
486
+ ENV PORT=8080
487
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
488
+ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
489
+
490
+ CMD ["dotnet", "BlokRuntime.dll"]
491
+ `;
492
+ const php_node_file = `<?php
493
+
494
+ namespace Blok\\Nodes;
495
+
496
+ use Blok\\NodeHandler;
497
+ use Blok\\Context;
498
+
499
+ class {{NODE_NAME_PASCAL}}Node implements NodeHandler
500
+ {
501
+ public function execute(Context $ctx, array $config): mixed
502
+ {
503
+ // Access request body
504
+ $name = $ctx->request->body['name'] ?? 'World';
505
+
506
+ // Access configuration
507
+ $prefix = $config['prefix'] ?? 'Hello';
508
+
509
+ $message = "$prefix, $name!";
510
+
511
+ // Store in context for downstream nodes
512
+ $ctx->vars['greeting'] = $message;
513
+
514
+ // Return response
515
+ return [
516
+ 'message' => $message,
517
+ 'timestamp' => date('c'),
518
+ 'language' => 'PHP',
519
+ ];
520
+ }
521
+ }
522
+ `;
523
+ const php_composer_file = `{
524
+ "name": "blok/{{NODE_NAME}}",
525
+ "type": "project",
526
+ "require": {
527
+ "php": ">=8.2",
528
+ "react/http": "^1.9",
529
+ "react/socket": "^1.15"
530
+ },
531
+ "autoload": {
532
+ "psr-4": {
533
+ "Blok\\\\": "src/"
534
+ }
535
+ }
536
+ }
537
+ `;
538
+ const php_dockerfile = `FROM php:8.2-cli-alpine AS builder
539
+ WORKDIR /app
540
+ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
541
+ COPY composer.json .
542
+ RUN composer install --no-dev --optimize-autoloader
543
+ COPY . .
544
+
545
+ FROM php:8.2-cli-alpine
546
+ WORKDIR /app
547
+ COPY --from=builder /app .
548
+
549
+ EXPOSE 8080
550
+ ENV PORT=8080
551
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
552
+ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
553
+
554
+ CMD ["php", "index.php"]
555
+ `;
556
+ const ruby_node_file = `require_relative '../../lib/blok'
557
+
558
+ module Blok
559
+ module Nodes
560
+ class {{NODE_NAME_PASCAL}}Node < Blok::NodeHandler
561
+ def execute(ctx, config)
562
+ # Access request body
563
+ name = ctx.request.body.is_a?(Hash) ? ctx.request.body['name'] : nil
564
+ name ||= 'World'
565
+
566
+ # Access configuration
567
+ prefix = config['prefix'] || 'Hello'
568
+
569
+ message = "#{prefix}, #{name}!"
570
+
571
+ # Store in context for downstream nodes
572
+ ctx.vars['greeting'] = message
573
+
574
+ # Return response
575
+ {
576
+ 'message' => message,
577
+ 'timestamp' => Time.now.utc.iso8601,
578
+ 'language' => 'Ruby'
579
+ }
580
+ end
581
+ end
582
+ end
583
+ end
584
+ `;
585
+ const ruby_gemfile = `source 'https://rubygems.org'
586
+
587
+ ruby '>= 3.1'
588
+
589
+ gem 'sinatra', '~> 4.0'
590
+ gem 'puma', '~> 6.4'
591
+ gem 'rackup', '~> 2.1'
592
+ `;
593
+ const ruby_dockerfile = `FROM ruby:3.2-alpine AS builder
594
+ RUN apk add --no-cache build-base
595
+ WORKDIR /app
596
+ COPY Gemfile Gemfile.lock ./
597
+ RUN bundle install --without development test
598
+
599
+ FROM ruby:3.2-alpine
600
+ RUN apk --no-cache add ca-certificates wget
601
+ WORKDIR /app
602
+ COPY --from=builder /usr/local/bundle /usr/local/bundle
603
+ COPY . .
604
+
605
+ EXPOSE 8080
606
+ ENV PORT=8080
607
+ ENV RACK_ENV=production
608
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
609
+ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
610
+
611
+ CMD ["bundle", "exec", "puma", "-b", "tcp://0.0.0.0:8080"]
612
+ `;
613
+ const agents_md = `# Blok Project
614
+
615
+ Blok is a TypeScript-first workflow orchestration framework. It executes declarative workflows (JSON or TypeScript DSL) composed of steps (nodes) that run across 8 language runtimes: NodeJS, Python3, Go, Rust, Java, C#, PHP, and Ruby.
616
+
617
+ ## Project Structure
618
+
619
+ \`\`\`
620
+ ├── src/
621
+ │ └── nodes/ # TypeScript node implementations
622
+ ├── runtimes/ # Non-NodeJS runtime nodes (Go, Python3, etc.)
623
+ │ └── {lang}/nodes/ # Language-specific node implementations
624
+ ├── workflows/
625
+ │ ├── json/ # Workflow definitions (JSON)
626
+ │ ├── yaml/ # Workflow definitions (YAML)
627
+ │ └── toml/ # Workflow definitions (TOML)
628
+ ├── .blok/
629
+ │ ├── config.json # Runtime configuration (ports, start commands)
630
+ │ └── runtimes/ # Auto-generated runtime scaffolds
631
+ ├── .env.local # Environment variables (ports, paths)
632
+ └── supervisord.conf # Process management config
633
+ \`\`\`
634
+
635
+ ## Commands
636
+
637
+ \`\`\`bash
638
+ npm run dev # Start dev server (or blokctl dev for multi-runtime)
639
+ npm run build # Build project
640
+ npm test # Run tests
641
+ blokctl create node <name> # Scaffold a new node
642
+ blokctl create workflow <n># Scaffold a new workflow
643
+ blokctl trace # Open Blok Studio (trace visualization)
644
+ blokctl studio # Alias for blokctl trace
645
+ \`\`\`
646
+
647
+ ## Context — Critical Data Flow
648
+
649
+ The Context type is the central execution state passed through every step.
650
+
651
+ \`\`\`typescript
652
+ type Context = {
653
+ id: string; // Unique request ID
654
+ request: RequestContext; // Incoming request (body, headers, params, query)
655
+ response: ResponseContext; // Current step output — OVERWRITTEN every step
656
+ vars?: VarsContext; // Persistent variables — PERSISTS across workflow
657
+ config: ConfigContext; // Node config (inputs resolved by Mapper)
658
+ env?: EnvContext; // process.env access
659
+ logger: LoggerContext;
660
+ error: ErrorContext;
661
+ };
662
+ \`\`\`
663
+
664
+ ### The Two Critical Rules
665
+
666
+ **Rule 1: \\\`ctx.response.data\\\` is OVERWRITTEN after every step.**
667
+ Each step's output replaces the previous \\\`ctx.response.data\\\`. If you need a step's output later, store it in \\\`ctx.vars\\\`.
668
+
669
+ **Rule 2: \\\`ctx.vars\\\` PERSISTS across the entire workflow.**
670
+ Use \\\`set_var: true\\\` on a step to auto-store its output in \\\`ctx.vars[stepName]\\\`. Downstream steps access it via \\\`ctx.vars['step-name']\\\`.
671
+
672
+ ### Data Flow Example
673
+
674
+ \`\`\`
675
+ Step 1: "fetch-user" (set_var: true)
676
+ → ctx.response.data = { id: "123", name: "Alice" }
677
+ → ctx.vars["fetch-user"] = { id: "123", name: "Alice" }
678
+
679
+ Step 2: "transform"
680
+ → ctx.response.data = { result: "done" } ← Step 1 output GONE from response
681
+ → ctx.vars["fetch-user"] still available
682
+
683
+ Step 3: "output"
684
+ → Can read ctx.vars["fetch-user"].name ← still "Alice"
685
+ \`\`\`
686
+
687
+ ### Blueprint Mapper — Expression Resolution
688
+
689
+ Node inputs support dynamic expressions resolved BEFORE node execution:
690
+
691
+ \`\`\`json
692
+ {
693
+ "inputs": {
694
+ "userId": "js/ctx.request.body.userId",
695
+ "chain": "js/ctx.vars['previous-step'].chain",
696
+ "previous": "js/ctx.response.data.result"
697
+ }
698
+ }
699
+ \`\`\`
700
+
701
+ Available in js/ expressions: \\\`ctx\\\`, \\\`data\\\` (ctx.response.data), \\\`func\\\` (ctx.func), \\\`vars\\\` (ctx.vars)
702
+
703
+ ---
704
+
705
+ ## Creating Nodes with defineNode
706
+
707
+ Use \\\`defineNode()\\\` for all new nodes. Never use the legacy class-based pattern.
708
+
709
+ \`\`\`typescript
710
+ import { defineNode } from "@blok/runner";
711
+ import { z } from "zod";
712
+
713
+ export default defineNode({
714
+ name: "fetch-user",
715
+ description: "Fetches user by ID",
716
+
717
+ input: z.object({
718
+ userId: z.string().uuid(),
719
+ }),
720
+
721
+ output: z.object({
722
+ user: z.object({
723
+ id: z.string(),
724
+ name: z.string(),
725
+ email: z.string().email(),
726
+ }),
727
+ }),
728
+
729
+ async execute(ctx, input) {
730
+ const user = await fetchUser(input.userId);
731
+ return { user };
732
+ },
733
+ });
734
+ \`\`\`
735
+
736
+ ### Key Behaviors
737
+
738
+ - Zod input/output validation runs automatically
739
+ - ZodError is mapped to GlobalError with HTTP 400
740
+ - \\\`flow: true\\\` nodes return NodeBase[] for conditional execution
741
+ - \\\`contentType\\\` sets response Content-Type (e.g., "text/html")
742
+ - Always \\\`export default defineNode(...)\\\`
743
+
744
+ ---
745
+
746
+ ## Workflow Structure (JSON)
747
+
748
+ \`\`\`json
749
+ {
750
+ "name": "My Workflow",
751
+ "version": "1.0.0",
752
+ "trigger": {
753
+ "http": { "method": "POST", "path": "/api/process", "accept": "application/json" }
754
+ },
755
+ "steps": [
756
+ { "name": "fetch", "node": "@blok/api-call", "type": "module" },
757
+ { "name": "process", "node": "my-node", "type": "module", "set_var": true },
758
+ { "name": "go-step", "node": "chain-test", "type": "runtime.go" }
759
+ ],
760
+ "nodes": {
761
+ "fetch": { "inputs": { "url": "https://api.example.com", "method": "GET" } },
762
+ "process": { "inputs": { "data": "js/ctx.response.data" } },
763
+ "go-step": { "inputs": { "processed": "js/ctx.vars['process']" } }
764
+ }
765
+ }
766
+ \`\`\`
767
+
768
+ ### Step Types
769
+
770
+ | Type | Description |
771
+ |------|-------------|
772
+ | \\\`module\\\` | TypeScript node from registered modules |
773
+ | \\\`local\\\` | TypeScript node from filesystem (NODES_PATH) |
774
+ | \\\`runtime.python3\\\` | Python3 SDK container (port 9007) |
775
+ | \\\`runtime.go\\\` | Go SDK container (port 9001) |
776
+ | \\\`runtime.rust\\\` | Rust SDK container (port 9002) |
777
+ | \\\`runtime.java\\\` | Java SDK container (port 9003) |
778
+ | \\\`runtime.csharp\\\` | C# SDK container (port 9004) |
779
+ | \\\`runtime.php\\\` | PHP SDK container (port 9005) |
780
+ | \\\`runtime.ruby\\\` | Ruby SDK container (port 9006) |
781
+
782
+ ### Conditional Workflow (if-else)
783
+
784
+ \`\`\`json
785
+ {
786
+ "nodes": {
787
+ "filter": {
788
+ "conditions": [
789
+ {
790
+ "type": "if",
791
+ "condition": "ctx.request.query.active === \\\\"true\\\\"",
792
+ "steps": [{ "name": "active-path", "node": "handle-active", "type": "module" }]
793
+ },
794
+ {
795
+ "type": "else",
796
+ "steps": [{ "name": "default-path", "node": "handle-default", "type": "module" }]
797
+ }
798
+ ]
799
+ }
800
+ }
801
+ }
802
+ \`\`\`
803
+
804
+ ---
805
+
806
+ ## Trigger Types
807
+
808
+ | Trigger | Example Config |
809
+ |---------|---------------|
810
+ | \\\`http\\\` | \\\`{ "method": "GET", "path": "/", "accept": "application/json" }\\\` |
811
+ | \\\`grpc\\\` | \\\`{ "service": "UserService", "method": "GetUser" }\\\` |
812
+ | \\\`cron\\\` | \\\`{ "schedule": "0 * * * *", "timezone": "UTC" }\\\` |
813
+ | \\\`queue\\\` | \\\`{ "provider": "kafka", "topic": "events" }\\\` |
814
+ | \\\`pubsub\\\` | \\\`{ "provider": "gcp", "topic": "updates" }\\\` |
815
+ | \\\`webhook\\\` | \\\`{ "source": "github", "events": ["push"] }\\\` |
816
+ | \\\`websocket\\\` | \\\`{ "events": ["message"], "path": "/ws" }\\\` |
817
+ | \\\`sse\\\` | \\\`{ "events": ["update"], "path": "/stream" }\\\` |
818
+ | \\\`worker\\\` | \\\`{ "queue": "jobs", "concurrency": 5 }\\\` |
819
+
820
+ ---
821
+
822
+ ## Runtime Adapter System
823
+
824
+ All non-NodeJS SDKs communicate via HTTP:
825
+ - **POST /execute** — Execute node with context
826
+ - **GET /health** — Health check
827
+
828
+ Environment variables: \\\`RUNTIME_{LANG}_HOST\\\` / \\\`RUNTIME_{LANG}_PORT\\\`
829
+
830
+ Runtime nodes auto-save \\\`result.data\\\` to \\\`ctx.vars[stepName]\\\`.
831
+
832
+ ---
833
+
834
+ ## Blok Studio
835
+
836
+ Real-time workflow trace visualization UI.
837
+
838
+ - Launch: \\\`blokctl trace\\\` or \\\`blokctl studio\\\`
839
+ - API: \\\`/__blok/runs\\\`, \\\`/__blok/runs/:id\\\`, \\\`/__blok/runs/:id/stream\\\` (SSE)
840
+ - Disable: \\\`BLOK_TRACE_ENABLED=false\\\`
841
+
842
+ ---
843
+
844
+ ## Do NOT
845
+
846
+ - Do NOT rely on \\\`ctx.response.data\\\` for data from non-previous steps — it gets overwritten
847
+ - Do NOT create class-based nodes — use \\\`defineNode()\\\` instead
848
+ - Do NOT use \\\`any\\\` type — use \\\`unknown\\\` and narrow with Zod
849
+ - Do NOT hardcode runtime ports — use environment variables
850
+ - Do NOT skip Zod input/output schemas
851
+ - Do NOT edit files in \\\`.blok/runtimes/\\\` — they are auto-generated
852
+
853
+ ## Do
854
+
855
+ - Use \\\`ctx.vars\\\` with \\\`set_var: true\\\` to pass data between non-adjacent steps
856
+ - Use \\\`js/ctx.vars['step-name'].field\\\` in workflow inputs for data flow
857
+ - Use Zod schemas for all input/output validation
858
+ - Use \\\`defineNode()\\\` for all new nodes
859
+ - Handle errors via GlobalError with appropriate HTTP status codes
860
+ - Keep nodes focused — one responsibility per node
861
+ `;
862
+ const claude_md = `# Blok Project — Claude Code Guide
863
+
864
+ Read \\\`AGENTS.md\\\` for full architecture and API details. This file contains Claude-specific guidance.
865
+
866
+ ## Quick Commands
867
+
868
+ \\\`\\\`\\\`bash
869
+ npm run dev # Start dev server
870
+ blokctl dev # Multi-runtime dev server
871
+ blokctl create node <name> # Scaffold new node
872
+ blokctl create workflow <name> # Scaffold new workflow
873
+ blokctl trace # Open Blok Studio
874
+ npm test # Run tests
875
+ \\\`\\\`\\\`
876
+
877
+ ## Context Rules (Memorize These)
878
+
879
+ 1. **\\\`ctx.response.data\\\` is OVERWRITTEN every step.** Previous output GONE unless stored in vars.
880
+ 2. **\\\`ctx.vars\\\` PERSISTS across the workflow.** Use \\\`set_var: true\\\` or \\\`js/ctx.vars['step']\\\`.
881
+ 3. **Blueprint Mapper resolves \\\`js/\\\` expressions BEFORE node execution.**
882
+
883
+ When users have data flow issues, check these three things first.
884
+
885
+ ## Debugging Workflows
886
+
887
+ 1. **Verify structure**: Every \\\`steps[].name\\\` must match a key in \\\`nodes\\\`
888
+ 2. **Trace data flow**: Which steps have \\\`set_var: true\\\`? Do \\\`js/\\\` expressions reference correct step names?
889
+ 3. **Check runtimes**: SDK containers running? \\\`GET http://localhost:{port}/health\\\`
890
+ 4. **Check Studio traces**: \\\`/__blok/runs/:id\\\` shows step-by-step inputs/outputs/errors
891
+
892
+ ### Common Errors
893
+
894
+ | Error | Fix |
895
+ |-------|-----|
896
+ | \\\`Node type X not found\\\` | Wrong \\\`type\\\` in step — use module, local, or runtime.* |
897
+ | \\\`Validation failed\\\` | Zod schema mismatch — check input schema vs actual data |
898
+ | \\\`Runtime execution error\\\` | SDK container not running — check health endpoint |
899
+ | \\\`ctx.vars['X'] undefined\\\` | Source step missing \\\`set_var: true\\\` or name mismatch |
900
+
901
+ ## Generating Code
902
+
903
+ Always use \\\`defineNode()\\\`. Never class-based BlokService.
904
+
905
+ \\\`\\\`\\\`typescript
906
+ import { defineNode } from "@blok/runner";
907
+ import { z } from "zod";
908
+
909
+ export default defineNode({
910
+ name: "node-name",
911
+ description: "What this node does",
912
+ input: z.object({ /* Zod schema */ }),
913
+ output: z.object({ /* Zod schema */ }),
914
+ async execute(ctx, input) {
915
+ return { /* must match output schema */ };
916
+ },
917
+ });
918
+ \\\`\\\`\\\`
919
+
920
+ ### Checklist:
921
+ - Zod input schema covers all inputs
922
+ - Zod output schema matches execute() return
923
+ - Node name matches workflow references
924
+ - No \\\`any\\\` types — use \\\`z.unknown()\\\` if dynamic
925
+ - \\\`export default defineNode(...)\\\`
926
+
927
+ ## Blok Studio Help
928
+
929
+ - Launch: \\\`blokctl trace\\\` or navigate to \\\`/__blok\\\`
930
+ - "No output" → Node not returning data or Zod output validation failed
931
+ - "Step error" → Expand error — check if 400 (validation) or 500 (runtime)
932
+ - "Vars not passing" → Source step needs \\\`set_var: true\\\`, target needs \\\`js/ctx.vars['name']\\\`
933
+
934
+ ## Do NOT
935
+
936
+ - Do NOT suggest class-based BlokService for new nodes
937
+ - Do NOT generate code with \\\`any\\\` types
938
+ - Do NOT assume \\\`ctx.response.data\\\` persists across steps
939
+ - Do NOT skip Zod schemas when creating nodes
940
+ - Do NOT edit files in \\\`.blok/runtimes/\\\`
941
+ `;
942
+ const function_first_node_file = `import { defineNode } from "@blok/runner";
943
+ import { z } from "zod";
944
+
945
+ /**
946
+ * A function-first node that demonstrates the modern defineNode pattern.
947
+ * This node is type-safe, validated, and requires 60% less boilerplate.
948
+ */
949
+ export default defineNode({
950
+ name: "{{NODE_NAME}}",
951
+ description: "A function-first node with Zod validation",
952
+
953
+ // Input schema using Zod - automatically validated
954
+ input: z.object({
955
+ message: z.string().optional().default("Hello World"),
956
+ }),
957
+
958
+ // Output schema using Zod - automatically validated
959
+ output: z.object({
960
+ message: z.string(),
961
+ timestamp: z.string(),
962
+ }),
963
+
964
+ // Execute function - type-safe with inferred types from Zod schemas
965
+ async execute(ctx, input) {
966
+ // Your business logic here
967
+ // - ctx.vars: Access workflow variables
968
+ // - ctx.request: Access HTTP request data
969
+ // - ctx.logger: Log messages
970
+ // - ctx.env: Access environment variables
971
+
972
+ // Example: Store data for downstream nodes
973
+ ctx.vars["processed-message"] = input.message;
974
+
975
+ // Return type-safe output (validated automatically)
976
+ return {
977
+ message: \`Processed: \${input.message}\`,
978
+ timestamp: new Date().toISOString(),
979
+ };
980
+ },
981
+ });
982
+ `;
983
+ export { node_file, package_dependencies, package_dev_dependencies, python3_file, examples_url, workflow_template, supervisord_nodejs, supervisord_python, go_node_file, go_mod_file, go_dockerfile, java_node_file, java_pom_file, java_dockerfile, rust_node_file, rust_cargo_file, rust_dockerfile, csharp_node_file, csharp_csproj_file, csharp_dockerfile, php_node_file, php_composer_file, php_dockerfile, ruby_node_file, ruby_gemfile, ruby_dockerfile, function_first_node_file, agents_md, claude_md, };