blokctl 0.6.21 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/modular-observability.capstone.e2e.test.js +72 -0
- package/dist/commands/create/node.js +46 -66
- package/dist/commands/create/project.js +55 -9
- package/dist/commands/create/utils/Examples.d.ts +8 -20
- package/dist/commands/create/utils/Examples.js +138 -412
- package/dist/commands/dev/index.js +40 -1
- package/dist/commands/generate/NodeGenerator.d.ts +0 -2
- package/dist/commands/generate/NodeGenerator.js +0 -20
- package/dist/commands/generate/RuntimeGenerator.d.ts +0 -2
- package/dist/commands/generate/RuntimeGenerator.js +0 -19
- package/dist/commands/generate/RuntimeGenerator.test.js +0 -29
- package/dist/commands/generate/TriggerGenerator.d.ts +0 -2
- package/dist/commands/generate/TriggerGenerator.js +0 -19
- package/dist/commands/generate/WorkflowGenerator.d.ts +0 -2
- package/dist/commands/generate/WorkflowGenerator.js +0 -19
- package/dist/commands/generate/e2e/NodeGenerator.e2e.test.js +0 -12
- package/dist/commands/generate/e2e/RuntimeGenerator.e2e.test.js +0 -12
- package/dist/commands/generate/e2e/TriggerGenerator.e2e.test.js +0 -14
- package/dist/commands/monitor/monitor-component.js +5 -5
- package/dist/commands/observability/add.d.ts +2 -0
- package/dist/commands/observability/add.js +113 -0
- package/dist/commands/observability/alerting-module.test.js +43 -0
- package/dist/commands/observability/apply.d.ts +10 -0
- package/dist/commands/observability/apply.js +11 -0
- package/dist/commands/observability/descriptor.d.ts +37 -0
- package/dist/commands/observability/descriptor.js +203 -0
- package/dist/commands/observability/descriptor.test.d.ts +1 -0
- package/dist/commands/observability/descriptor.test.js +40 -0
- package/dist/commands/observability/index.d.ts +1 -0
- package/dist/commands/observability/index.js +53 -0
- package/dist/commands/observability/list.d.ts +2 -0
- package/dist/commands/observability/list.js +45 -0
- package/dist/commands/observability/logging-module.test.d.ts +1 -0
- package/dist/commands/observability/logging-module.test.js +43 -0
- package/dist/commands/observability/obs-stack-module.test.d.ts +1 -0
- package/dist/commands/observability/obs-stack-module.test.js +33 -0
- package/dist/commands/observability/remove.d.ts +2 -0
- package/dist/commands/observability/remove.js +62 -0
- package/dist/commands/observability/shared.d.ts +6 -0
- package/dist/commands/observability/shared.js +23 -0
- package/dist/commands/observability/status.d.ts +2 -0
- package/dist/commands/observability/status.js +36 -0
- package/dist/commands/observability/tracing-module.test.d.ts +1 -0
- package/dist/commands/observability/tracing-module.test.js +42 -0
- package/dist/commands/profile/index.js +7 -10
- package/dist/commands/watch/format.d.ts +23 -0
- package/dist/commands/watch/format.js +60 -0
- package/dist/commands/watch/index.d.ts +1 -0
- package/dist/commands/watch/index.js +53 -0
- package/dist/commands/watch/sse.d.ts +16 -0
- package/dist/commands/watch/sse.js +82 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/services/obs-setup.d.ts +5 -0
- package/dist/services/obs-setup.js +68 -0
- package/dist/services/obs-setup.test.d.ts +1 -0
- package/dist/services/obs-setup.test.js +71 -0
- package/dist/services/obs-tiers.d.ts +9 -0
- package/dist/services/obs-tiers.js +16 -0
- package/dist/services/observability-mutations.d.ts +4 -0
- package/dist/services/observability-mutations.js +46 -0
- package/dist/services/observability-mutations.test.d.ts +1 -0
- package/dist/services/observability-mutations.test.js +57 -0
- package/dist/services/runtime-setup.d.ts +12 -1
- package/dist/services/runtime-setup.js +274 -14
- package/dist/studio-dist/assets/{index-BD8_9YPN.js → index-CnFqCRQe.js} +17 -17
- package/dist/studio-dist/index.html +1 -1
- package/package.json +3 -3
- package/dist/commands/generate/GenerationAnalytics.d.ts +0 -61
- package/dist/commands/generate/GenerationAnalytics.js +0 -163
- package/dist/commands/generate/GenerationAnalytics.test.js +0 -407
- package/dist/commands/generate/PromptVersioning.d.ts +0 -25
- package/dist/commands/generate/PromptVersioning.js +0 -71
- package/dist/commands/generate/PromptVersioning.test.js +0 -120
- /package/dist/{commands/generate/GenerationAnalytics.test.d.ts → __tests__/modular-observability.capstone.e2e.test.d.ts} +0 -0
- /package/dist/commands/{generate/PromptVersioning.test.d.ts → observability/alerting-module.test.d.ts} +0 -0
|
@@ -23,13 +23,24 @@ export interface TriggerConfig {
|
|
|
23
23
|
entryPoint: string;
|
|
24
24
|
startCmd: string;
|
|
25
25
|
}
|
|
26
|
+
export interface ObservabilityModuleConfig {
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
addedAt: string;
|
|
29
|
+
version?: string;
|
|
30
|
+
settings?: Record<string, unknown>;
|
|
31
|
+
}
|
|
26
32
|
export interface ProjectConfig {
|
|
27
33
|
triggers?: Record<string, TriggerConfig>;
|
|
28
34
|
runtimes?: Record<string, RuntimeConfig>;
|
|
35
|
+
observability?: Record<string, ObservabilityModuleConfig>;
|
|
29
36
|
}
|
|
30
37
|
export type ProjectRuntimeConfig = ProjectConfig;
|
|
31
38
|
export declare function setupRuntime(runtime: RuntimeInfo, githubRepoLocal: string, projectDir: string, spinner: SpinnerHandler): Promise<RuntimeConfig>;
|
|
32
|
-
export declare function
|
|
39
|
+
export declare function generateGoNodeRegistry(projectDir: string): string;
|
|
40
|
+
export declare function generateRustNodeRegistry(projectDir: string): string;
|
|
41
|
+
export declare function generateJavaNodeRegistry(projectDir: string): string;
|
|
42
|
+
export declare function generateCSharpNodeRegistry(projectDir: string): string;
|
|
43
|
+
export declare function writeProjectConfig(projectDir: string, runtimeConfigs: RuntimeConfig[], triggerConfigs?: TriggerConfig[], observabilityConfigs?: Record<string, ObservabilityModuleConfig>): void;
|
|
33
44
|
export declare function readProjectConfig(projectDir: string): ProjectConfig | null;
|
|
34
45
|
export declare function generateRuntimeEnvVars(runtimeConfigs: RuntimeConfig[]): string;
|
|
35
46
|
export declare function generateSupervisordConfig(runtimeConfigs: RuntimeConfig[]): string;
|
|
@@ -21,7 +21,7 @@ export async function setupRuntime(runtime, githubRepoLocal, projectDir, spinner
|
|
|
21
21
|
let startCmdOverride;
|
|
22
22
|
switch (runtime.kind) {
|
|
23
23
|
case "python3":
|
|
24
|
-
await setupPython3(blokctlRuntimeDir,
|
|
24
|
+
await setupPython3(blokctlRuntimeDir, spinner);
|
|
25
25
|
break;
|
|
26
26
|
case "go":
|
|
27
27
|
await setupGo(blokctlRuntimeDir, spinner);
|
|
@@ -42,6 +42,18 @@ export async function setupRuntime(runtime, githubRepoLocal, projectDir, spinner
|
|
|
42
42
|
startCmdOverride = await setupRuby(blokctlRuntimeDir, spinner, runtime.defaultPort);
|
|
43
43
|
break;
|
|
44
44
|
}
|
|
45
|
+
if (runtime.kind === "go") {
|
|
46
|
+
generateGoNodeRegistry(projectDir);
|
|
47
|
+
}
|
|
48
|
+
else if (runtime.kind === "rust") {
|
|
49
|
+
generateRustNodeRegistry(projectDir);
|
|
50
|
+
}
|
|
51
|
+
else if (runtime.kind === "java") {
|
|
52
|
+
generateJavaNodeRegistry(projectDir);
|
|
53
|
+
}
|
|
54
|
+
else if (runtime.kind === "csharp") {
|
|
55
|
+
generateCSharpNodeRegistry(projectDir);
|
|
56
|
+
}
|
|
45
57
|
spinner.message(`${runtime.label} runtime setup complete.`);
|
|
46
58
|
return {
|
|
47
59
|
port: runtime.defaultPort,
|
|
@@ -56,7 +68,7 @@ export async function setupRuntime(runtime, githubRepoLocal, projectDir, spinner
|
|
|
56
68
|
transport: "grpc",
|
|
57
69
|
};
|
|
58
70
|
}
|
|
59
|
-
async function setupPython3(sdkDir,
|
|
71
|
+
async function setupPython3(sdkDir, spinner) {
|
|
60
72
|
spinner.message("Creating Python3 virtual environment...");
|
|
61
73
|
await createPythonVenv(sdkDir);
|
|
62
74
|
spinner.message("Python3 virtual environment created.");
|
|
@@ -67,16 +79,6 @@ async function setupPython3(sdkDir, projectRuntimeDir, spinner) {
|
|
|
67
79
|
await exec(`"${venvPip}" install -r "${requirementsFile}"`, { cwd: sdkDir });
|
|
68
80
|
}
|
|
69
81
|
spinner.message("Python3 packages installed.");
|
|
70
|
-
const nodesLink = path.join(projectRuntimeDir, "nodes");
|
|
71
|
-
const sdkNodesDir = path.join(sdkDir, "nodes");
|
|
72
|
-
if (fsExtra.existsSync(sdkNodesDir) && !fsExtra.existsSync(nodesLink)) {
|
|
73
|
-
fsExtra.symlinkSync(sdkNodesDir, nodesLink, "junction");
|
|
74
|
-
}
|
|
75
|
-
const coreLink = path.join(projectRuntimeDir, "core");
|
|
76
|
-
const sdkCoreDir = path.join(sdkDir, "core");
|
|
77
|
-
if (fsExtra.existsSync(sdkCoreDir) && !fsExtra.existsSync(coreLink)) {
|
|
78
|
-
fsExtra.symlinkSync(sdkCoreDir, coreLink, "junction");
|
|
79
|
-
}
|
|
80
82
|
}
|
|
81
83
|
async function createPythonVenv(sdkDir) {
|
|
82
84
|
await exec("python3 -m venv python3_runtime", { cwd: sdkDir, timeout: 60000 });
|
|
@@ -86,6 +88,258 @@ async function setupGo(sdkDir, spinner) {
|
|
|
86
88
|
await exec("go mod download", { cwd: sdkDir, timeout: 120000 });
|
|
87
89
|
spinner.message("Go dependencies installed.");
|
|
88
90
|
}
|
|
91
|
+
export function generateGoNodeRegistry(projectDir) {
|
|
92
|
+
const goSdkDir = path.join(projectDir, ".blok", "runtimes", "go");
|
|
93
|
+
const nodesSrcDir = path.join(projectDir, "runtimes", "go", "nodes");
|
|
94
|
+
const usernodesDir = path.join(goSdkDir, "usernodes");
|
|
95
|
+
const registryFile = path.join(goSdkDir, "cmd", "server", "register_user_nodes.go");
|
|
96
|
+
fsExtra.removeSync(usernodesDir);
|
|
97
|
+
const nodes = [];
|
|
98
|
+
if (fsExtra.existsSync(nodesSrcDir)) {
|
|
99
|
+
let i = 0;
|
|
100
|
+
for (const entry of fsExtra.readdirSync(nodesSrcDir, { withFileTypes: true })) {
|
|
101
|
+
if (!entry.isDirectory())
|
|
102
|
+
continue;
|
|
103
|
+
const srcDir = path.join(nodesSrcDir, entry.name);
|
|
104
|
+
const goFiles = fsExtra.readdirSync(srcDir).filter((f) => f.endsWith(".go"));
|
|
105
|
+
if (goFiles.length === 0)
|
|
106
|
+
continue;
|
|
107
|
+
const exportsRegister = goFiles.some((f) => /func\s+Register\s*\(/.test(fsExtra.readFileSync(path.join(srcDir, f), "utf8")));
|
|
108
|
+
if (!exportsRegister) {
|
|
109
|
+
console.warn(`[blokctl] skipping Go node '${entry.name}': no exported Register(registry) found`);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const destDir = path.join(usernodesDir, entry.name);
|
|
113
|
+
fsExtra.ensureDirSync(destDir);
|
|
114
|
+
for (const f of goFiles) {
|
|
115
|
+
fsExtra.copySync(path.join(srcDir, f), path.join(destDir, f));
|
|
116
|
+
}
|
|
117
|
+
nodes.push({
|
|
118
|
+
alias: `usernode${i++}`,
|
|
119
|
+
importPath: `github.com/nickincloud/blok-go/usernodes/${entry.name}`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const importLines = [
|
|
124
|
+
'\tblok "github.com/nickincloud/blok-go"',
|
|
125
|
+
...nodes.map((n) => `\t${n.alias} "${n.importPath}"`),
|
|
126
|
+
];
|
|
127
|
+
const callLines = nodes.map((n) => `\t${n.alias}.Register(registry)`);
|
|
128
|
+
const content = `// Code generated by blokctl. DO NOT EDIT.
|
|
129
|
+
package main
|
|
130
|
+
|
|
131
|
+
import (
|
|
132
|
+
${importLines.join("\n")}
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
// registerUserNodes registers nodes scaffolded under runtimes/go/nodes.
|
|
136
|
+
func registerUserNodes(registry *blok.NodeRegistry) {
|
|
137
|
+
${callLines.join("\n")}
|
|
138
|
+
}
|
|
139
|
+
`;
|
|
140
|
+
fsExtra.ensureDirSync(path.dirname(registryFile));
|
|
141
|
+
fsExtra.writeFileSync(registryFile, content);
|
|
142
|
+
return registryFile;
|
|
143
|
+
}
|
|
144
|
+
export function generateRustNodeRegistry(projectDir) {
|
|
145
|
+
const rustSdkDir = path.join(projectDir, ".blok", "runtimes", "rust");
|
|
146
|
+
const nodesSrcDir = path.join(projectDir, "runtimes", "rust", "nodes");
|
|
147
|
+
const usernodesDir = path.join(rustSdkDir, "src", "user_nodes");
|
|
148
|
+
fsExtra.removeSync(usernodesDir);
|
|
149
|
+
fsExtra.ensureDirSync(usernodesDir);
|
|
150
|
+
const toModIdent = (name) => {
|
|
151
|
+
let id = name.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
152
|
+
if (/^[0-9]/.test(id))
|
|
153
|
+
id = `_${id}`;
|
|
154
|
+
return id;
|
|
155
|
+
};
|
|
156
|
+
const mods = [];
|
|
157
|
+
if (fsExtra.existsSync(nodesSrcDir)) {
|
|
158
|
+
for (const entry of fsExtra.readdirSync(nodesSrcDir, { withFileTypes: true })) {
|
|
159
|
+
if (!entry.isDirectory())
|
|
160
|
+
continue;
|
|
161
|
+
const srcDir = path.join(nodesSrcDir, entry.name);
|
|
162
|
+
const rsFiles = fsExtra.readdirSync(srcDir).filter((f) => f.endsWith(".rs"));
|
|
163
|
+
if (rsFiles.length === 0)
|
|
164
|
+
continue;
|
|
165
|
+
const rootFile = rsFiles.find((f) => /fn\s+register\s*\(/.test(fsExtra.readFileSync(path.join(srcDir, f), "utf8")));
|
|
166
|
+
if (!rootFile) {
|
|
167
|
+
console.warn(`[blokctl] skipping Rust node '${entry.name}': no .rs exporting fn register(registry) found`);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const modIdent = toModIdent(entry.name);
|
|
171
|
+
const destDir = path.join(usernodesDir, modIdent);
|
|
172
|
+
fsExtra.ensureDirSync(destDir);
|
|
173
|
+
const siblings = rsFiles.filter((f) => f !== rootFile);
|
|
174
|
+
for (const f of siblings) {
|
|
175
|
+
fsExtra.copySync(path.join(srcDir, f), path.join(destDir, f));
|
|
176
|
+
}
|
|
177
|
+
let rootSrc = fsExtra.readFileSync(path.join(srcDir, rootFile), "utf8");
|
|
178
|
+
if (siblings.length > 0) {
|
|
179
|
+
const subMods = siblings.map((f) => `mod ${path.basename(f, ".rs")};`).join("\n");
|
|
180
|
+
rootSrc = `${subMods}\n\n${rootSrc}`;
|
|
181
|
+
}
|
|
182
|
+
fsExtra.writeFileSync(path.join(destDir, "mod.rs"), rootSrc);
|
|
183
|
+
mods.push(modIdent);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const modLines = mods.map((m) => `pub mod ${m};`);
|
|
187
|
+
const callLines = mods.map((m) => `\t${m}::register(registry);`);
|
|
188
|
+
const content = `// Code generated by blokctl. DO NOT EDIT.
|
|
189
|
+
use blok::registry::NodeRegistry;
|
|
190
|
+
|
|
191
|
+
${modLines.join("\n")}
|
|
192
|
+
|
|
193
|
+
/// Registers nodes scaffolded under runtimes/rust/nodes.
|
|
194
|
+
pub fn register_user_nodes(${mods.length > 0 ? "registry" : "_registry"}: &mut NodeRegistry) {
|
|
195
|
+
${callLines.join("\n")}
|
|
196
|
+
}
|
|
197
|
+
`;
|
|
198
|
+
const registryFile = path.join(usernodesDir, "mod.rs");
|
|
199
|
+
fsExtra.writeFileSync(registryFile, content);
|
|
200
|
+
return registryFile;
|
|
201
|
+
}
|
|
202
|
+
export function generateJavaNodeRegistry(projectDir) {
|
|
203
|
+
const javaSdkDir = path.join(projectDir, ".blok", "runtimes", "java");
|
|
204
|
+
const nodesSrcDir = path.join(projectDir, "runtimes", "java", "nodes");
|
|
205
|
+
const sdkJavaRoot = path.join(javaSdkDir, "src", "main", "java");
|
|
206
|
+
const usernodesDir = path.join(sdkJavaRoot, "usernodes");
|
|
207
|
+
const registryFile = path.join(sdkJavaRoot, "com", "blok", "blok", "UserNodeRegistry.java");
|
|
208
|
+
fsExtra.removeSync(usernodesDir);
|
|
209
|
+
const registrations = [];
|
|
210
|
+
if (fsExtra.existsSync(nodesSrcDir)) {
|
|
211
|
+
for (const entry of fsExtra.readdirSync(nodesSrcDir, { withFileTypes: true })) {
|
|
212
|
+
if (!entry.isDirectory())
|
|
213
|
+
continue;
|
|
214
|
+
const nodeSrcRoot = path.join(nodesSrcDir, entry.name, "src", "main", "java");
|
|
215
|
+
if (!fsExtra.existsSync(nodeSrcRoot)) {
|
|
216
|
+
console.warn(`[blokctl] skipping Java node '${entry.name}': no src/main/java found`);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const javaFiles = [];
|
|
220
|
+
const walk = (dir) => {
|
|
221
|
+
for (const f of fsExtra.readdirSync(dir, { withFileTypes: true })) {
|
|
222
|
+
const full = path.join(dir, f.name);
|
|
223
|
+
if (f.isDirectory())
|
|
224
|
+
walk(full);
|
|
225
|
+
else if (f.name.endsWith(".java"))
|
|
226
|
+
javaFiles.push(full);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
walk(nodeSrcRoot);
|
|
230
|
+
let fqcn;
|
|
231
|
+
for (const file of javaFiles) {
|
|
232
|
+
const src = fsExtra.readFileSync(file, "utf8");
|
|
233
|
+
const classMatch = src.match(/class\s+(\w+)\s+implements\s+NodeHandler/);
|
|
234
|
+
if (!classMatch)
|
|
235
|
+
continue;
|
|
236
|
+
const pkgMatch = src.match(/package\s+([\w.]+)\s*;/);
|
|
237
|
+
fqcn = pkgMatch ? `${pkgMatch[1]}.${classMatch[1]}` : classMatch[1];
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
if (!fqcn) {
|
|
241
|
+
console.warn(`[blokctl] skipping Java node '${entry.name}': no class implementing NodeHandler found`);
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
fsExtra.copySync(nodeSrcRoot, path.join(usernodesDir, entry.name));
|
|
245
|
+
registrations.push(`\t\tregistry.register("${entry.name}", new ${fqcn}());`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const content = `// Code generated by blokctl. DO NOT EDIT.
|
|
249
|
+
package com.blok.blok;
|
|
250
|
+
|
|
251
|
+
import com.blok.blok.node.NodeRegistry;
|
|
252
|
+
|
|
253
|
+
public final class UserNodeRegistry {
|
|
254
|
+
|
|
255
|
+
\tprivate UserNodeRegistry() {
|
|
256
|
+
\t}
|
|
257
|
+
|
|
258
|
+
\t/** Registers nodes scaffolded under runtimes/java/nodes. */
|
|
259
|
+
\tpublic static void registerUserNodes(NodeRegistry registry) {
|
|
260
|
+
${registrations.join("\n")}
|
|
261
|
+
\t}
|
|
262
|
+
}
|
|
263
|
+
`;
|
|
264
|
+
fsExtra.ensureDirSync(path.dirname(registryFile));
|
|
265
|
+
fsExtra.writeFileSync(registryFile, content);
|
|
266
|
+
return registryFile;
|
|
267
|
+
}
|
|
268
|
+
export function generateCSharpNodeRegistry(projectDir) {
|
|
269
|
+
const csSdkDir = path.join(projectDir, ".blok", "runtimes", "csharp");
|
|
270
|
+
const nodesSrcDir = path.join(projectDir, "runtimes", "csharp", "nodes");
|
|
271
|
+
const usernodesDir = path.join(csSdkDir, "src", "Blok.Core", "Nodes", "UserNodes");
|
|
272
|
+
const registryFile = path.join(csSdkDir, "src", "Blok.Core", "UserNodeRegistry.cs");
|
|
273
|
+
fsExtra.removeSync(usernodesDir);
|
|
274
|
+
const seenClasses = new Set();
|
|
275
|
+
const registrations = [];
|
|
276
|
+
if (fsExtra.existsSync(nodesSrcDir)) {
|
|
277
|
+
for (const entry of fsExtra.readdirSync(nodesSrcDir, { withFileTypes: true })) {
|
|
278
|
+
if (!entry.isDirectory())
|
|
279
|
+
continue;
|
|
280
|
+
const srcDir = path.join(nodesSrcDir, entry.name);
|
|
281
|
+
const csFiles = collectFilesRecursive(srcDir, ".cs");
|
|
282
|
+
if (csFiles.length === 0)
|
|
283
|
+
continue;
|
|
284
|
+
let className;
|
|
285
|
+
for (const file of csFiles) {
|
|
286
|
+
const match = fsExtra.readFileSync(file, "utf8").match(/class\s+(\w+)\s*:\s*INodeHandler\b/);
|
|
287
|
+
if (match) {
|
|
288
|
+
className = match[1];
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (!className) {
|
|
293
|
+
console.warn(`[blokctl] skipping C# node '${entry.name}': no 'class X : INodeHandler' found`);
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (seenClasses.has(className)) {
|
|
297
|
+
console.warn(`[blokctl] skipping C# node '${entry.name}': duplicate class name '${className}' (single namespace Blok.Core.Nodes)`);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
seenClasses.add(className);
|
|
301
|
+
const destDir = path.join(usernodesDir, entry.name);
|
|
302
|
+
fsExtra.ensureDirSync(destDir);
|
|
303
|
+
for (const file of csFiles) {
|
|
304
|
+
fsExtra.copySync(file, path.join(destDir, path.basename(file)));
|
|
305
|
+
}
|
|
306
|
+
registrations.push({ nodeName: entry.name, className });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const callLines = registrations.map((r) => `\t\tregistry.Register("${r.nodeName}", new Blok.Core.Nodes.${r.className}());`);
|
|
310
|
+
const content = `// Code generated by blokctl. DO NOT EDIT.
|
|
311
|
+
using Blok.Core.Node;
|
|
312
|
+
|
|
313
|
+
namespace Blok.Core;
|
|
314
|
+
|
|
315
|
+
/// <summary>
|
|
316
|
+
/// Registers user nodes scaffolded under runtimes/csharp/nodes.
|
|
317
|
+
/// </summary>
|
|
318
|
+
public static class UserNodeRegistry
|
|
319
|
+
{
|
|
320
|
+
public static void RegisterUserNodes(NodeRegistry registry)
|
|
321
|
+
{
|
|
322
|
+
${callLines.join("\n")}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
`;
|
|
326
|
+
fsExtra.ensureDirSync(path.dirname(registryFile));
|
|
327
|
+
fsExtra.writeFileSync(registryFile, content);
|
|
328
|
+
return registryFile;
|
|
329
|
+
}
|
|
330
|
+
function collectFilesRecursive(dir, ext) {
|
|
331
|
+
const out = [];
|
|
332
|
+
for (const entry of fsExtra.readdirSync(dir, { withFileTypes: true })) {
|
|
333
|
+
const full = path.join(dir, entry.name);
|
|
334
|
+
if (entry.isDirectory()) {
|
|
335
|
+
out.push(...collectFilesRecursive(full, ext));
|
|
336
|
+
}
|
|
337
|
+
else if (entry.name.endsWith(ext)) {
|
|
338
|
+
out.push(full);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return out;
|
|
342
|
+
}
|
|
89
343
|
async function setupRust(sdkDir, spinner) {
|
|
90
344
|
spinner.message("Building Rust project (this may take a few minutes on first build)...");
|
|
91
345
|
await exec("cargo build --release", { cwd: sdkDir, timeout: 600000 });
|
|
@@ -140,7 +394,7 @@ async function setupRuby(sdkDir, spinner, port) {
|
|
|
140
394
|
spinner.message("Ruby dependencies installed.");
|
|
141
395
|
return `${resolvedBundle} exec rackup --host 0.0.0.0 -p ${port} config.ru`;
|
|
142
396
|
}
|
|
143
|
-
export function writeProjectConfig(projectDir, runtimeConfigs, triggerConfigs) {
|
|
397
|
+
export function writeProjectConfig(projectDir, runtimeConfigs, triggerConfigs, observabilityConfigs) {
|
|
144
398
|
const config = {};
|
|
145
399
|
if (runtimeConfigs.length > 0) {
|
|
146
400
|
config.runtimes = {};
|
|
@@ -154,6 +408,9 @@ export function writeProjectConfig(projectDir, runtimeConfigs, triggerConfigs) {
|
|
|
154
408
|
config.triggers[tc.kind] = tc;
|
|
155
409
|
}
|
|
156
410
|
}
|
|
411
|
+
if (observabilityConfigs && Object.keys(observabilityConfigs).length > 0) {
|
|
412
|
+
config.observability = observabilityConfigs;
|
|
413
|
+
}
|
|
157
414
|
const configPath = path.join(projectDir, ".blok", "config.json");
|
|
158
415
|
fsExtra.ensureDirSync(path.dirname(configPath));
|
|
159
416
|
fsExtra.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
@@ -185,11 +442,14 @@ export function generateSupervisordConfig(runtimeConfigs) {
|
|
|
185
442
|
for (const rc of runtimeConfigs) {
|
|
186
443
|
const cmd = rc.grpcStartCmd ?? rc.startCmd;
|
|
187
444
|
const grpcPortLine = rc.grpcPort !== undefined ? `,GRPC_PORT="${rc.grpcPort}"` : "";
|
|
445
|
+
const nodesDirLine = rc.kind === "python3" || rc.kind === "ruby" || rc.kind === "php"
|
|
446
|
+
? `,BLOK_NODES_DIR="/app/runtimes/${rc.kind}/nodes"`
|
|
447
|
+
: "";
|
|
188
448
|
config += `
|
|
189
449
|
[program:${rc.kind}_runtime]
|
|
190
450
|
command=${cmd}
|
|
191
451
|
directory=/app/${rc.cwd}
|
|
192
|
-
environment=PORT="${rc.port}"${grpcPortLine},HOST="0.0.0.0",BLOK_TRANSPORT="grpc"
|
|
452
|
+
environment=PORT="${rc.port}"${grpcPortLine}${nodesDirLine},HOST="0.0.0.0",BLOK_TRANSPORT="grpc"
|
|
193
453
|
autostart=true
|
|
194
454
|
autorestart=true
|
|
195
455
|
stderr_logfile=/var/log/${rc.kind}.err.log
|