@flat8n/cli 0.1.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 (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -0
  3. package/dist/src/cli/api.d.ts +10 -0
  4. package/dist/src/cli/api.js +57 -0
  5. package/dist/src/cli/api.js.map +1 -0
  6. package/dist/src/cli/build.d.ts +2 -0
  7. package/dist/src/cli/build.js +162 -0
  8. package/dist/src/cli/build.js.map +1 -0
  9. package/dist/src/cli/compile.d.ts +2 -0
  10. package/dist/src/cli/compile.js +149 -0
  11. package/dist/src/cli/compile.js.map +1 -0
  12. package/dist/src/cli/deploy.d.ts +4 -0
  13. package/dist/src/cli/deploy.js +47 -0
  14. package/dist/src/cli/deploy.js.map +1 -0
  15. package/dist/src/cli/dev.d.ts +2 -0
  16. package/dist/src/cli/dev.js +54 -0
  17. package/dist/src/cli/dev.js.map +1 -0
  18. package/dist/src/cli/init.d.ts +1 -0
  19. package/dist/src/cli/init.js +237 -0
  20. package/dist/src/cli/init.js.map +1 -0
  21. package/dist/src/cli/main.d.ts +2 -0
  22. package/dist/src/cli/main.js +249 -0
  23. package/dist/src/cli/main.js.map +1 -0
  24. package/dist/src/cli/run.d.ts +2 -0
  25. package/dist/src/cli/run.js +84 -0
  26. package/dist/src/cli/run.js.map +1 -0
  27. package/dist/src/cli/server.d.ts +2 -0
  28. package/dist/src/cli/server.js +62 -0
  29. package/dist/src/cli/server.js.map +1 -0
  30. package/dist/src/cli/setup.d.ts +1 -0
  31. package/dist/src/cli/setup.js +62 -0
  32. package/dist/src/cli/setup.js.map +1 -0
  33. package/dist/src/cli/sync.d.ts +4 -0
  34. package/dist/src/cli/sync.js +45 -0
  35. package/dist/src/cli/sync.js.map +1 -0
  36. package/dist/src/cli/ui.d.ts +5 -0
  37. package/dist/src/cli/ui.js +66 -0
  38. package/dist/src/cli/ui.js.map +1 -0
  39. package/dist/src/compiler/analyze.d.ts +15 -0
  40. package/dist/src/compiler/analyze.js +26 -0
  41. package/dist/src/compiler/analyze.js.map +1 -0
  42. package/dist/src/compiler/diagnostics.d.ts +28 -0
  43. package/dist/src/compiler/diagnostics.js +26 -0
  44. package/dist/src/compiler/diagnostics.js.map +1 -0
  45. package/dist/src/compiler/inputs.d.ts +30 -0
  46. package/dist/src/compiler/inputs.js +2 -0
  47. package/dist/src/compiler/inputs.js.map +1 -0
  48. package/dist/src/compiler/json.d.ts +15 -0
  49. package/dist/src/compiler/json.js +83 -0
  50. package/dist/src/compiler/json.js.map +1 -0
  51. package/dist/src/compiler/link.d.ts +18 -0
  52. package/dist/src/compiler/link.js +84 -0
  53. package/dist/src/compiler/link.js.map +1 -0
  54. package/dist/src/compiler/stable-json.d.ts +3 -0
  55. package/dist/src/compiler/stable-json.js +18 -0
  56. package/dist/src/compiler/stable-json.js.map +1 -0
  57. package/dist/src/compiler/validate.d.ts +9 -0
  58. package/dist/src/compiler/validate.js +25 -0
  59. package/dist/src/compiler/validate.js.map +1 -0
  60. package/dist/src/compiler/watch.d.ts +19 -0
  61. package/dist/src/compiler/watch.js +67 -0
  62. package/dist/src/compiler/watch.js.map +1 -0
  63. package/dist/src/compiler/workflow-file.d.ts +2 -0
  64. package/dist/src/compiler/workflow-file.js +27 -0
  65. package/dist/src/compiler/workflow-file.js.map +1 -0
  66. package/dist/src/generator/n8n-generator.d.ts +3 -0
  67. package/dist/src/generator/n8n-generator.js +129 -0
  68. package/dist/src/generator/n8n-generator.js.map +1 -0
  69. package/dist/src/graph/graph.d.ts +11 -0
  70. package/dist/src/graph/graph.js +76 -0
  71. package/dist/src/graph/graph.js.map +1 -0
  72. package/dist/src/index.d.ts +7 -0
  73. package/dist/src/index.js +5 -0
  74. package/dist/src/index.js.map +1 -0
  75. package/dist/src/ir/model.d.ts +58 -0
  76. package/dist/src/ir/model.js +29 -0
  77. package/dist/src/ir/model.js.map +1 -0
  78. package/dist/src/parser/n8n-parser.d.ts +8 -0
  79. package/dist/src/parser/n8n-parser.js +119 -0
  80. package/dist/src/parser/n8n-parser.js.map +1 -0
  81. package/dist/src/parser/n8n-schema.d.ts +60 -0
  82. package/dist/src/parser/n8n-schema.js +35 -0
  83. package/dist/src/parser/n8n-schema.js.map +1 -0
  84. package/dist/src/passes/auto-layout.d.ts +6 -0
  85. package/dist/src/passes/auto-layout.js +52 -0
  86. package/dist/src/passes/auto-layout.js.map +1 -0
  87. package/dist/src/passes/credential-isolation.d.ts +10 -0
  88. package/dist/src/passes/credential-isolation.js +56 -0
  89. package/dist/src/passes/credential-isolation.js.map +1 -0
  90. package/dist/src/passes/deterministic-ids.d.ts +7 -0
  91. package/dist/src/passes/deterministic-ids.js +40 -0
  92. package/dist/src/passes/deterministic-ids.js.map +1 -0
  93. package/dist/src/passes/expression-rewriter.d.ts +7 -0
  94. package/dist/src/passes/expression-rewriter.js +294 -0
  95. package/dist/src/passes/expression-rewriter.js.map +1 -0
  96. package/dist/src/passes/inline-subworkflows.d.ts +11 -0
  97. package/dist/src/passes/inline-subworkflows.js +437 -0
  98. package/dist/src/passes/inline-subworkflows.js.map +1 -0
  99. package/dist/src/passes/pass.d.ts +10 -0
  100. package/dist/src/passes/pass.js +2 -0
  101. package/dist/src/passes/pass.js.map +1 -0
  102. package/dist/src/validation/graph-integrity.d.ts +9 -0
  103. package/dist/src/validation/graph-integrity.js +104 -0
  104. package/dist/src/validation/graph-integrity.js.map +1 -0
  105. package/package.json +60 -0
@@ -0,0 +1,2 @@
1
+ export declare function bootN8n(): Promise<void>;
2
+ export declare function killN8n(): void;
@@ -0,0 +1,62 @@
1
+ import { spawn, execSync } from "node:child_process";
2
+ import { spinner } from "@clack/prompts";
3
+ let n8nProcess = null;
4
+ function killGhostProcess() {
5
+ try {
6
+ if (process.platform === "win32") {
7
+ execSync('for /f "tokens=5" %a in (\'netstat -aon ^| findstr :5678\') do taskkill /F /T /PID %a', { stdio: "ignore", shell: "cmd.exe" });
8
+ }
9
+ else {
10
+ execSync("lsof -t -i:5678 | xargs kill -9", { stdio: "ignore" });
11
+ }
12
+ }
13
+ catch (e) {
14
+ // Ignore errors when no process exists
15
+ }
16
+ }
17
+ export async function bootN8n() {
18
+ const host = process.env.N8N_HOST || "http://localhost:5678";
19
+ // Only attempt local boot if we are targeting localhost
20
+ if (!host.includes("localhost") && !host.includes("127.0.0.1")) {
21
+ return;
22
+ }
23
+ // Quick check if it's already running
24
+ try {
25
+ const res = await fetch(`${host}/`);
26
+ if (res.ok)
27
+ return; // Already running
28
+ }
29
+ catch (e) { }
30
+ killGhostProcess();
31
+ n8nProcess = spawn("npx", ["n8n"], { stdio: ["ignore", "pipe", "pipe"], shell: true });
32
+ let isReady = false;
33
+ n8nProcess.stderr?.on("data", (data) => {
34
+ if (!isReady) {
35
+ const errorString = data.toString();
36
+ if (!errorString.includes("Python") && !errorString.includes("license")) {
37
+ // Silently capture errors during boot
38
+ }
39
+ }
40
+ });
41
+ const s = spinner();
42
+ s.start("Booting local n8n engine...");
43
+ while (!isReady) {
44
+ try {
45
+ const res = await fetch(`${host}/`);
46
+ if (res.ok) {
47
+ isReady = true;
48
+ s.stop("n8n engine is ready!");
49
+ break;
50
+ }
51
+ }
52
+ catch (e) { }
53
+ await new Promise(r => setTimeout(r, 1000));
54
+ }
55
+ }
56
+ export function killN8n() {
57
+ killGhostProcess();
58
+ if (n8nProcess) {
59
+ n8nProcess.kill("SIGINT");
60
+ }
61
+ }
62
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/cli/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAqB,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,IAAI,UAAU,GAAwB,IAAI,CAAC;AAE3C,SAAS,gBAAgB;IACvB,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACjC,QAAQ,CAAC,uFAAuF,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAC3I,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,iCAAiC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,uCAAuC;IACzC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,uBAAuB,CAAC;IAE7D,wDAAwD;IACxD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/D,OAAO;IACT,CAAC;IAED,sCAAsC;IACtC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;QACpC,IAAI,GAAG,CAAC,EAAE;YAAE,OAAO,CAAC,kBAAkB;IACxC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,CAAA,CAAC;IAEd,gBAAgB,EAAE,CAAC;IAEnB,UAAU,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAEvF,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;QAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBACxE,sCAAsC;YACxC,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,OAAO,EAAE,CAAC;IACpB,CAAC,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAEvC,OAAO,CAAC,OAAO,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;YACpC,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACX,OAAO,GAAG,IAAI,CAAC;gBACf,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;gBAC/B,MAAM;YACR,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC,CAAA,CAAC;QACd,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,gBAAgB,EAAE,CAAC;IACnB,IAAI,UAAU,EAAE,CAAC;QACf,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function ensureEnvironment(): Promise<void>;
@@ -0,0 +1,62 @@
1
+ import { select, text, note, log } from "@clack/prompts";
2
+ import pc from "picocolors";
3
+ import { appendFile } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { handleCancel } from "./ui.js";
6
+ export async function ensureEnvironment() {
7
+ // If API key is already present in process.env, skip setup
8
+ if (process.env.N8N_API_KEY) {
9
+ return;
10
+ }
11
+ log.warn("N8N_API_KEY is missing from your environment.");
12
+ // Ask for Host Type
13
+ const hostType = handleCancel(await select({
14
+ message: "Where is your n8n instance hosted?",
15
+ options: [
16
+ { value: "local", label: "Local Desktop (n8n start)" },
17
+ { value: "cloud", label: "n8n Cloud" },
18
+ { value: "self-hosted", label: "Self-Hosted / Docker" },
19
+ ],
20
+ }));
21
+ let hostUrl = "http://localhost:5678";
22
+ if (hostType !== "local") {
23
+ const url = handleCancel(await text({
24
+ message: "Enter your n8n instance URL (e.g. https://n8n.yourdomain.com):",
25
+ placeholder: "https://",
26
+ validate: (value) => {
27
+ if (!value)
28
+ return "URL is required.";
29
+ if (!value.startsWith("http://") && !value.startsWith("https://")) {
30
+ return "URL must start with http:// or https://";
31
+ }
32
+ }
33
+ }));
34
+ hostUrl = url.trim().replace(/\/$/, ""); // Remove trailing slash
35
+ }
36
+ // Provide Instructions
37
+ const settingsUrl = `${hostUrl}/settings/api`;
38
+ note(`1. Open ${pc.cyan(pc.underline(settingsUrl))}\n2. Click "Add API Key" and label it "flat8n"\n3. Set expiration to "Never" and copy the key`, "How to get your API Key:");
39
+ // Ask for API Key
40
+ const apiKey = handleCancel(await text({
41
+ message: "Paste your n8n API Key:",
42
+ placeholder: "n8n_api_key_...",
43
+ validate: (value) => {
44
+ if (!value || value.trim().length === 0)
45
+ return "API Key is required.";
46
+ }
47
+ }));
48
+ // Inject into process.env so current run succeeds
49
+ process.env.N8N_HOST = hostUrl;
50
+ process.env.N8N_API_KEY = apiKey.trim();
51
+ // Save to local .env
52
+ const envPath = join(process.cwd(), ".env");
53
+ const envContent = `\nN8N_HOST=${hostUrl}\nN8N_API_KEY=${apiKey.trim()}\n`;
54
+ try {
55
+ await appendFile(envPath, envContent, "utf8");
56
+ log.success(`Saved API Key to ${pc.dim(envPath)}`);
57
+ }
58
+ catch (error) {
59
+ log.error(`Failed to save to .env file: ${String(error)}`);
60
+ }
61
+ }
62
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/cli/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function runSync(options: {
2
+ host?: string;
3
+ apiKey?: string | undefined;
4
+ }): Promise<number>;
@@ -0,0 +1,45 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { resolve, join } from "node:path";
3
+ import { spinner } from "@clack/prompts";
4
+ import pc from "picocolors";
5
+ import { upsertWorkflow } from "./api.js";
6
+ export async function runSync(options) {
7
+ const cwd = process.cwd();
8
+ const distDir = resolve(cwd, "dist");
9
+ let files;
10
+ try {
11
+ const entries = await readdir(distDir, { withFileTypes: true });
12
+ files = entries.filter(e => e.isFile() && e.name.endsWith(".json")).map(e => e.name);
13
+ }
14
+ catch (error) {
15
+ process.stderr.write(pc.red(`\n⚠ Failed to read dist directory. Have you run 'flat8n build' yet?\n`));
16
+ return 1;
17
+ }
18
+ if (files.length === 0) {
19
+ process.stdout.write(pc.yellow(`\n⚠ No compiled workflows found in dist/\n`));
20
+ return 0;
21
+ }
22
+ const s = spinner();
23
+ s.start(pc.cyan("Synchronizing workflows to n8n database..."));
24
+ let successCount = 0;
25
+ for (const file of files) {
26
+ const filePath = join(distDir, file);
27
+ try {
28
+ const content = await readFile(filePath, "utf8");
29
+ const parsed = JSON.parse(content);
30
+ const result = await upsertWorkflow(options, parsed);
31
+ if (!result.success) {
32
+ s.stop(pc.red(`⚠ Failed to deploy ${parsed.name || file}: ${result.error}`));
33
+ return 1;
34
+ }
35
+ successCount++;
36
+ }
37
+ catch (e) {
38
+ s.stop(pc.red(`⚠ Failed to parse or upload ${file}`));
39
+ return 1;
40
+ }
41
+ }
42
+ s.stop(pc.green(`✔ ${successCount} module(s) successfully deployed!`));
43
+ return 0;
44
+ }
45
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/cli/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAuD;IACnF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAErC,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACvF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC,CAAC;QACtG,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,4CAA4C,CAAC,CAAC,CAAC;QAC9E,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,CAAC,GAAG,OAAO,EAAE,CAAC;IACpB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC,CAAC;IAE/D,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAEnC,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,IAAI,IAAI,IAAI,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAC7E,OAAO,CAAC,CAAC;YACX,CAAC;YACD,YAAY,EAAE,CAAC;QACjB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,+BAA+B,IAAI,EAAE,CAAC,CAAC,CAAC;YACtD,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IAED,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,YAAY,mCAAmC,CAAC,CAAC,CAAC;IACvE,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function printBrand(): void;
2
+ export declare function showBranding(): void;
3
+ export declare function handleCancel<T>(val: T | symbol): T;
4
+ export declare function renderDashboardMenu(): void;
5
+ export declare function startKeyboardListener(onReload: () => Promise<void>, onQuit: () => void): void;
@@ -0,0 +1,66 @@
1
+ import { isCancel, cancel } from "@clack/prompts";
2
+ import pc from "picocolors";
3
+ const ASCII_ART = [
4
+ "███████╗ ██╗ █████╗ ████████╗ ████████╗ █████╗ ███╗ ██╗",
5
+ "██╔════╝ ██║ ██╔══██╗ ╚══██╔══╝ ╚══██╔══╝ ██╔══██╗ ████╗ ██║",
6
+ "█████╗ ██║ ███████║ ██║ ██║ ╚█████╔╝ ██╔██╗ ██║",
7
+ "██╔══╝ ██║ ██╔══██║ ██║ ██║ ██╔══██╗ ██║╚██╗██║",
8
+ "██║ ████████╗ ██║ ██║ ██║ ██║ ╚█████╔╝ ██║ ╚████║",
9
+ "╚═╝ ╚═══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚════╝ ╚═╝ ╚═══╝"
10
+ ];
11
+ export function printBrand() {
12
+ process.stdout.write("\n");
13
+ // Single TrueColor block to prevent cmd.exe mid-line cursor squishing
14
+ const color = "\x1b[38;2;234;75;113m"; // #EA4B71
15
+ const reset = "\x1b[0m";
16
+ process.stdout.write(`${color}${ASCII_ART.join('\n')}${reset}\n`);
17
+ }
18
+ export function showBranding() {
19
+ printBrand();
20
+ const githubUrl = "https://github.com/jvondev";
21
+ const linkText = "by JVON DEV";
22
+ const pad = " ".repeat(59);
23
+ process.stdout.write(`${pad}\x1b[90m\x1b]8;;${githubUrl}\x1b\\${linkText}\x1b]8;;\x1b\\\x1b[0m\n\n`);
24
+ }
25
+ export function handleCancel(val) {
26
+ if (isCancel(val)) {
27
+ cancel("Operation cancelled.");
28
+ process.exit(0);
29
+ }
30
+ return val;
31
+ }
32
+ export function renderDashboardMenu() {
33
+ const host = process.env.N8N_HOST || "http://localhost:5678";
34
+ process.stdout.write("\n=============================================================\n");
35
+ process.stdout.write(` ${pc.bold("FLATT8N DEV SERVER ONLINE")}\n`);
36
+ process.stdout.write("=============================================================\n");
37
+ process.stdout.write(pc.dim("│\n"));
38
+ process.stdout.write(`◇ Dashboard : ${pc.cyan(host)}\n`);
39
+ process.stdout.write(`│ Reload : Press [ R ]\n`);
40
+ process.stdout.write(`│ Quit : Press [ Q ]\n`);
41
+ process.stdout.write(pc.dim("│\n"));
42
+ }
43
+ export function startKeyboardListener(onReload, onQuit) {
44
+ const stdin = process.stdin;
45
+ if (stdin.isTTY) {
46
+ stdin.setRawMode(true);
47
+ }
48
+ stdin.resume();
49
+ stdin.setEncoding("utf8");
50
+ stdin.on("data", async function (key) {
51
+ if (key === "\u0003" || key.toLowerCase() === "q") {
52
+ onQuit();
53
+ }
54
+ if (key.toLowerCase() === "r") {
55
+ process.stdout.write("\n");
56
+ if (stdin.isTTY)
57
+ stdin.setRawMode(false);
58
+ stdin.pause();
59
+ await onReload();
60
+ stdin.resume();
61
+ if (stdin.isTTY)
62
+ stdin.setRawMode(true);
63
+ }
64
+ });
65
+ }
66
+ //# sourceMappingURL=ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/cli/ui.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { CompilerDiagnostic } from "./diagnostics.js";
2
+ import type { AnalyzeInput } from "./inputs.js";
3
+ import type { GraphStats } from "../ir/model.js";
4
+ export interface WorkflowAnalysis {
5
+ readonly id: string;
6
+ readonly name: string;
7
+ readonly path: string;
8
+ readonly stats: GraphStats;
9
+ }
10
+ export interface AnalyzeResult {
11
+ readonly ok: boolean;
12
+ readonly workflows: readonly WorkflowAnalysis[];
13
+ readonly diagnostics: readonly CompilerDiagnostic[];
14
+ }
15
+ export declare function analyze(input: AnalyzeInput): AnalyzeResult;
@@ -0,0 +1,26 @@
1
+ import { parseN8nWorkflow } from "../parser/n8n-parser.js";
2
+ import { collectGraphStats, validateWorkflowIR } from "../validation/graph-integrity.js";
3
+ export function analyze(input) {
4
+ const diagnostics = [];
5
+ const workflows = [];
6
+ const sources = [input.entry, ...Object.values(input.dependencies ?? {})];
7
+ for (const source of sources) {
8
+ const parsed = parseN8nWorkflow(source);
9
+ diagnostics.push(...parsed.diagnostics);
10
+ if (parsed.workflow !== undefined) {
11
+ diagnostics.push(...validateWorkflowIR(parsed.workflow, "analysis"));
12
+ workflows.push({
13
+ id: parsed.workflow.id,
14
+ name: parsed.workflow.name,
15
+ path: parsed.workflow.path,
16
+ stats: collectGraphStats(parsed.workflow)
17
+ });
18
+ }
19
+ }
20
+ return {
21
+ ok: diagnostics.every((item) => item.severity !== "error"),
22
+ workflows,
23
+ diagnostics
24
+ };
25
+ }
26
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../../src/compiler/analyze.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAezF,MAAM,UAAU,OAAO,CAAC,KAAmB;IACzC,MAAM,WAAW,GAAyB,EAAE,CAAC;IAC7C,MAAM,SAAS,GAAuB,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,CAAC;IAE1E,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACxC,WAAW,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAClC,WAAW,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;YACrE,SAAS,CAAC,IAAI,CAAC;gBACb,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;gBACtB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI;gBAC1B,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI;gBAC1B,KAAK,EAAE,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC;aAC1C,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO;QACL,EAAE,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC;QAC1D,SAAS;QACT,WAAW;KACZ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ export type DiagnosticSeverity = "error" | "warning";
2
+ export interface SourceLocation {
3
+ readonly path: string;
4
+ readonly pointer: string;
5
+ }
6
+ export interface CompilerDiagnostic {
7
+ readonly severity: DiagnosticSeverity;
8
+ readonly pass: string;
9
+ readonly workflow: string;
10
+ readonly node?: string;
11
+ readonly location?: SourceLocation;
12
+ readonly cause: string;
13
+ readonly invariant: string;
14
+ readonly suggestion: string;
15
+ }
16
+ export interface DiagnosticInput {
17
+ readonly severity?: DiagnosticSeverity;
18
+ readonly pass: string;
19
+ readonly workflow: string;
20
+ readonly node?: string;
21
+ readonly location?: SourceLocation;
22
+ readonly cause: string;
23
+ readonly invariant: string;
24
+ readonly suggestion: string;
25
+ }
26
+ export declare function diagnostic(input: DiagnosticInput): CompilerDiagnostic;
27
+ export declare function hasErrors(diagnostics: readonly CompilerDiagnostic[]): boolean;
28
+ export declare function formatDiagnostic(item: CompilerDiagnostic): string;
@@ -0,0 +1,26 @@
1
+ export function diagnostic(input) {
2
+ const output = {
3
+ severity: input.severity ?? "error",
4
+ pass: input.pass,
5
+ workflow: input.workflow,
6
+ cause: input.cause,
7
+ invariant: input.invariant,
8
+ suggestion: input.suggestion
9
+ };
10
+ if (input.node !== undefined) {
11
+ output.node = input.node;
12
+ }
13
+ if (input.location !== undefined) {
14
+ output.location = input.location;
15
+ }
16
+ return output;
17
+ }
18
+ export function hasErrors(diagnostics) {
19
+ return diagnostics.some((item) => item.severity === "error");
20
+ }
21
+ export function formatDiagnostic(item) {
22
+ const node = item.node === undefined ? "" : ` node="${item.node}"`;
23
+ const location = item.location === undefined ? "" : ` ${item.location.path}${item.location.pointer}`;
24
+ return `[${item.severity}] ${item.pass} workflow="${item.workflow}"${node}${location}: ${item.cause}. Invariant: ${item.invariant}. Fix: ${item.suggestion}`;
25
+ }
26
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../../src/compiler/diagnostics.ts"],"names":[],"mappings":"AA6BA,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,MAAM,GASR;QACF,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,OAAO;QACnC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAC;IAEF,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IAC3B,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IACnC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,WAA0C;IAClE,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAwB;IACvD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,IAAI,GAAG,CAAC;IACnE,MAAM,QAAQ,GACZ,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;IACtF,OAAO,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI,cAAc,IAAI,CAAC,QAAQ,IAAI,IAAI,GAAG,QAAQ,KAAK,IAAI,CAAC,KAAK,gBAAgB,IAAI,CAAC,SAAS,UAAU,IAAI,CAAC,UAAU,EAAE,CAAC;AAC/J,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { JsonObject } from "./json.js";
2
+ export interface WorkflowSource {
3
+ readonly id: string;
4
+ readonly path: string;
5
+ readonly workflow: JsonObject;
6
+ }
7
+ export interface LinkOptions {
8
+ readonly credentialPolicy?: "stripIds" | "preserveIds";
9
+ readonly credentialIdOverrides?: Readonly<Record<string, string>>;
10
+ readonly layout?: LayoutOptions;
11
+ readonly namespaceSeparator?: string;
12
+ }
13
+ export interface LayoutOptions {
14
+ readonly direction?: "right" | "left" | "down" | "up";
15
+ readonly spacing?: number;
16
+ }
17
+ export interface LinkInput {
18
+ readonly entry: WorkflowSource;
19
+ readonly dependencies?: Readonly<Record<string, WorkflowSource>>;
20
+ readonly options?: LinkOptions;
21
+ }
22
+ export interface ValidateInput {
23
+ readonly workflow: JsonObject;
24
+ readonly id?: string;
25
+ readonly path?: string;
26
+ }
27
+ export interface AnalyzeInput {
28
+ readonly entry: WorkflowSource;
29
+ readonly dependencies?: Readonly<Record<string, WorkflowSource>>;
30
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=inputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputs.js","sourceRoot":"","sources":["../../../src/compiler/inputs.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ export type JsonPrimitive = string | number | boolean | null;
2
+ export type JsonValue = JsonPrimitive | JsonObject | JsonArray;
3
+ export type JsonArray = readonly JsonValue[];
4
+ export type JsonObject = {
5
+ readonly [key: string]: JsonValue;
6
+ };
7
+ export type MutableJsonObject = {
8
+ [key: string]: JsonValue;
9
+ };
10
+ export type MutableJsonArray = JsonValue[];
11
+ export declare function isJsonObject(value: JsonValue | unknown): value is JsonObject;
12
+ export declare function isJsonArray(value: JsonValue | unknown): value is JsonArray;
13
+ export declare function asJsonValue(value: unknown): JsonValue | undefined;
14
+ export declare function cloneJson(value: JsonValue): JsonValue;
15
+ export declare function jsonEquals(left: JsonValue, right: JsonValue): boolean;
@@ -0,0 +1,83 @@
1
+ export function isJsonObject(value) {
2
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3
+ }
4
+ export function isJsonArray(value) {
5
+ return Array.isArray(value);
6
+ }
7
+ export function asJsonValue(value) {
8
+ if (value === null ||
9
+ typeof value === "string" ||
10
+ typeof value === "number" ||
11
+ typeof value === "boolean") {
12
+ return Number.isNaN(value) ? undefined : value;
13
+ }
14
+ if (Array.isArray(value)) {
15
+ const values = [];
16
+ for (const item of value) {
17
+ const parsed = asJsonValue(item);
18
+ if (parsed === undefined) {
19
+ return undefined;
20
+ }
21
+ values.push(parsed);
22
+ }
23
+ return values;
24
+ }
25
+ if (typeof value === "object" && value !== null) {
26
+ const output = {};
27
+ for (const [key, item] of Object.entries(value)) {
28
+ const parsed = asJsonValue(item);
29
+ if (parsed === undefined) {
30
+ return undefined;
31
+ }
32
+ output[key] = parsed;
33
+ }
34
+ return output;
35
+ }
36
+ return undefined;
37
+ }
38
+ export function cloneJson(value) {
39
+ if (Array.isArray(value)) {
40
+ return value.map((item) => cloneJson(item));
41
+ }
42
+ if (isJsonObject(value)) {
43
+ const output = {};
44
+ for (const [key, item] of Object.entries(value)) {
45
+ output[key] = cloneJson(item);
46
+ }
47
+ return output;
48
+ }
49
+ return value;
50
+ }
51
+ export function jsonEquals(left, right) {
52
+ if (left === right) {
53
+ return true;
54
+ }
55
+ if (Array.isArray(left) || Array.isArray(right)) {
56
+ if (!Array.isArray(left) || !Array.isArray(right)) {
57
+ return false;
58
+ }
59
+ if (left.length !== right.length) {
60
+ return false;
61
+ }
62
+ return left.every((item, index) => {
63
+ const other = right[index];
64
+ return other !== undefined && jsonEquals(item, other);
65
+ });
66
+ }
67
+ if (isJsonObject(left) || isJsonObject(right)) {
68
+ if (!isJsonObject(left) || !isJsonObject(right)) {
69
+ return false;
70
+ }
71
+ const leftKeys = Object.keys(left).sort();
72
+ const rightKeys = Object.keys(right).sort();
73
+ if (leftKeys.length !== rightKeys.length) {
74
+ return false;
75
+ }
76
+ return leftKeys.every((key, index) => {
77
+ const otherKey = rightKeys[index];
78
+ return otherKey === key && jsonEquals(left[key], right[key]);
79
+ });
80
+ }
81
+ return false;
82
+ }
83
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../../src/compiler/json.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { type CompilerDiagnostic } from "./diagnostics.js";
2
+ import type { LinkInput } from "./inputs.js";
3
+ import type { JsonObject } from "./json.js";
4
+ import type { WorkflowIR } from "../ir/model.js";
5
+ export type LinkResult = {
6
+ readonly ok: true;
7
+ readonly workflow: JsonObject;
8
+ readonly json: string;
9
+ readonly ir: WorkflowIR;
10
+ readonly diagnostics: readonly CompilerDiagnostic[];
11
+ } | {
12
+ readonly ok: false;
13
+ readonly diagnostics: readonly CompilerDiagnostic[];
14
+ };
15
+ export declare function link(input: LinkInput): LinkResult;
16
+ export declare function linkOrThrow(input: LinkInput): Extract<LinkResult, {
17
+ readonly ok: true;
18
+ }>;
@@ -0,0 +1,84 @@
1
+ import { formatDiagnostic, hasErrors } from "./diagnostics.js";
2
+ import { stableStringify } from "./stable-json.js";
3
+ import { generateN8nWorkflow } from "../generator/n8n-generator.js";
4
+ import { parseN8nWorkflow } from "../parser/n8n-parser.js";
5
+ import { CredentialIsolationPass } from "../passes/credential-isolation.js";
6
+ import { DeterministicIdsPass } from "../passes/deterministic-ids.js";
7
+ import { InlineSubworkflowsPass } from "../passes/inline-subworkflows.js";
8
+ import { AutoLayoutPass } from "../passes/auto-layout.js";
9
+ import { validateWorkflowIR } from "../validation/graph-integrity.js";
10
+ export function link(input) {
11
+ const parsedEntry = parseN8nWorkflow(input.entry);
12
+ const diagnostics = [...parsedEntry.diagnostics];
13
+ const dependencies = new Map();
14
+ for (const [key, source] of Object.entries(input.dependencies ?? {})) {
15
+ const parsed = parseN8nWorkflow(source);
16
+ diagnostics.push(...parsed.diagnostics);
17
+ if (parsed.workflow !== undefined) {
18
+ addDependency(dependencies, key, parsed.workflow, diagnostics);
19
+ addDependency(dependencies, source.id, parsed.workflow, diagnostics);
20
+ addDependency(dependencies, parsed.workflow.name, parsed.workflow, diagnostics);
21
+ }
22
+ }
23
+ if (parsedEntry.workflow === undefined || hasErrors(diagnostics)) {
24
+ return { ok: false, diagnostics };
25
+ }
26
+ let current = parsedEntry.workflow;
27
+ diagnostics.push(...validateWorkflowIR(current, "pre-link-validation"));
28
+ if (hasErrors(diagnostics)) {
29
+ return { ok: false, diagnostics };
30
+ }
31
+ const passes = [
32
+ new InlineSubworkflowsPass(dependencies, input.options ?? {}),
33
+ new CredentialIsolationPass(input.options ?? {}),
34
+ new AutoLayoutPass(),
35
+ new DeterministicIdsPass()
36
+ ];
37
+ for (const pass of passes) {
38
+ const result = pass.run(current);
39
+ diagnostics.push(...result.diagnostics);
40
+ current = result.workflow;
41
+ if (hasErrors(result.diagnostics)) {
42
+ return { ok: false, diagnostics };
43
+ }
44
+ }
45
+ diagnostics.push(...validateWorkflowIR(current, "post-link-validation", {
46
+ requireNodeIds: true,
47
+ forbidBoundaryNodes: true,
48
+ forbidExecuteWorkflowNodes: true
49
+ }));
50
+ if (hasErrors(diagnostics)) {
51
+ return { ok: false, diagnostics };
52
+ }
53
+ const workflow = generateN8nWorkflow(current);
54
+ return {
55
+ ok: true,
56
+ workflow,
57
+ json: stableStringify(workflow),
58
+ ir: current,
59
+ diagnostics
60
+ };
61
+ }
62
+ export function linkOrThrow(input) {
63
+ const result = link(input);
64
+ if (result.ok) {
65
+ return result;
66
+ }
67
+ throw new Error(result.diagnostics.map(formatDiagnostic).join("\n"));
68
+ }
69
+ function addDependency(dependencies, key, workflow, diagnostics) {
70
+ const existing = dependencies.get(key);
71
+ if (existing !== undefined && existing.id !== workflow.id) {
72
+ diagnostics.push({
73
+ severity: "error",
74
+ pass: "dependency-map",
75
+ workflow: workflow.id,
76
+ cause: `dependency key "${key}" maps to both "${existing.id}" and "${workflow.id}"`,
77
+ invariant: "dependency keys must resolve deterministically",
78
+ suggestion: "use unique dependency aliases for workflow references"
79
+ });
80
+ return;
81
+ }
82
+ dependencies.set(key, workflow);
83
+ }
84
+ //# sourceMappingURL=link.js.map