@synergenius/flow-weaver 0.13.2 → 0.14.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 (57) hide show
  1. package/README.md +41 -2
  2. package/dist/api/validate.js +8 -2
  3. package/dist/ast/types.d.ts +120 -0
  4. package/dist/chevrotain-parser/node-parser.d.ts +4 -0
  5. package/dist/chevrotain-parser/node-parser.js +41 -1
  6. package/dist/chevrotain-parser/port-parser.d.ts +1 -0
  7. package/dist/chevrotain-parser/port-parser.js +22 -2
  8. package/dist/chevrotain-parser/tokens.d.ts +3 -0
  9. package/dist/chevrotain-parser/tokens.js +15 -0
  10. package/dist/cli/commands/export.js +25 -38
  11. package/dist/cli/flow-weaver.mjs +63703 -54297
  12. package/dist/cli/templates/index.js +9 -0
  13. package/dist/cli/templates/workflows/cicd-docker.d.ts +9 -0
  14. package/dist/cli/templates/workflows/cicd-docker.js +110 -0
  15. package/dist/cli/templates/workflows/cicd-matrix.d.ts +9 -0
  16. package/dist/cli/templates/workflows/cicd-matrix.js +112 -0
  17. package/dist/cli/templates/workflows/cicd-multi-env.d.ts +9 -0
  18. package/dist/cli/templates/workflows/cicd-multi-env.js +118 -0
  19. package/dist/cli/templates/workflows/cicd-test-deploy.d.ts +11 -0
  20. package/dist/cli/templates/workflows/cicd-test-deploy.js +149 -0
  21. package/dist/constants.js +7 -0
  22. package/dist/deployment/index.d.ts +14 -7
  23. package/dist/deployment/index.js +29 -17
  24. package/dist/deployment/targets/base.d.ts +27 -2
  25. package/dist/deployment/targets/base.js +38 -6
  26. package/dist/deployment/targets/cicd-base.d.ts +111 -0
  27. package/dist/deployment/targets/cicd-base.js +357 -0
  28. package/dist/deployment/targets/cloudflare.d.ts +6 -0
  29. package/dist/deployment/targets/cloudflare.js +3 -0
  30. package/dist/deployment/targets/github-actions.d.ts +54 -0
  31. package/dist/deployment/targets/github-actions.js +366 -0
  32. package/dist/deployment/targets/gitlab-ci.d.ts +65 -0
  33. package/dist/deployment/targets/gitlab-ci.js +374 -0
  34. package/dist/deployment/targets/inngest.d.ts +25 -0
  35. package/dist/deployment/targets/inngest.js +10 -1
  36. package/dist/deployment/targets/lambda.d.ts +17 -0
  37. package/dist/deployment/targets/lambda.js +5 -0
  38. package/dist/deployment/targets/vercel.d.ts +16 -0
  39. package/dist/deployment/targets/vercel.js +5 -0
  40. package/dist/diagram/geometry.js +13 -5
  41. package/dist/export/index.d.ts +13 -9
  42. package/dist/export/index.js +129 -997
  43. package/dist/generated-version.d.ts +1 -1
  44. package/dist/generated-version.js +1 -1
  45. package/dist/jsdoc-parser.d.ts +130 -0
  46. package/dist/jsdoc-parser.js +408 -4
  47. package/dist/marketplace/index.d.ts +1 -1
  48. package/dist/marketplace/types.d.ts +13 -0
  49. package/dist/marketplace/validator.js +21 -2
  50. package/dist/mcp/tools-export.js +56 -14
  51. package/dist/parser.js +28 -1
  52. package/dist/validation/cicd-detection.d.ts +33 -0
  53. package/dist/validation/cicd-detection.js +76 -0
  54. package/dist/validation/cicd-rules.d.ts +62 -0
  55. package/dist/validation/cicd-rules.js +284 -0
  56. package/docs/reference/scaffold.md +4 -0
  57. package/package.json +4 -3
@@ -0,0 +1,284 @@
1
+ /**
2
+ * CI/CD-Specific Validation Rules
3
+ *
4
+ * Custom TValidationRule implementations for CI/CD pipeline workflows.
5
+ * These run AFTER the built-in validator via the api/validate.ts custom rules injection.
6
+ *
7
+ * Rules:
8
+ * 1. CICD_SECRET_NOT_DECLARED - secret:X referenced but no @secret X declared
9
+ * 2. CICD_SECRET_UNUSED - @secret X declared but never wired
10
+ * 3. CICD_TRIGGER_MISSING - No trigger annotations — pipeline would never run
11
+ * 4. CICD_JOB_MISSING_RUNNER - Job has no runner (uses workflow default or none)
12
+ * 5. CICD_ARTIFACT_CROSS_JOB - Data flows between jobs without @artifact declaration
13
+ * 6. CICD_CIRCULAR_JOB_DEPS - Job dependency cycle detected
14
+ * 7. CICD_MATRIX_WITH_ENVIRONMENT - Matrix + environment = N approval prompts
15
+ */
16
+ import { getDeclaredSecrets, getReferencedSecrets, getJobNames, } from './cicd-detection.js';
17
+ // ---------------------------------------------------------------------------
18
+ // Rule 1: Secret Not Declared
19
+ // ---------------------------------------------------------------------------
20
+ /**
21
+ * A `secret:X` pseudo-node is referenced in @connect but no `@secret X` is declared.
22
+ * This means the export target won't know about the secret and can't generate
23
+ * proper environment variable references.
24
+ */
25
+ export const secretNotDeclaredRule = {
26
+ name: 'CICD_SECRET_NOT_DECLARED',
27
+ validate(ast) {
28
+ const errors = [];
29
+ const declared = new Set(getDeclaredSecrets(ast));
30
+ const referenced = getReferencedSecrets(ast);
31
+ for (const secretName of referenced) {
32
+ if (!declared.has(secretName)) {
33
+ errors.push({
34
+ type: 'error',
35
+ code: 'CICD_SECRET_NOT_DECLARED',
36
+ message: `Secret '${secretName}' is referenced via @connect but not declared with @secret. Add: @secret ${secretName} - description`,
37
+ });
38
+ }
39
+ }
40
+ return errors;
41
+ },
42
+ };
43
+ // ---------------------------------------------------------------------------
44
+ // Rule 2: Secret Unused
45
+ // ---------------------------------------------------------------------------
46
+ /**
47
+ * A `@secret X` is declared but never wired via `@connect secret:X -> ...`.
48
+ * The secret might be intentional (used in a shell-command step) or a leftover.
49
+ */
50
+ export const secretUnusedRule = {
51
+ name: 'CICD_SECRET_UNUSED',
52
+ validate(ast) {
53
+ const errors = [];
54
+ const referenced = new Set(getReferencedSecrets(ast));
55
+ const declared = getDeclaredSecrets(ast);
56
+ for (const secretName of declared) {
57
+ if (!referenced.has(secretName)) {
58
+ errors.push({
59
+ type: 'warning',
60
+ code: 'CICD_SECRET_UNUSED',
61
+ message: `Secret '${secretName}' is declared but not wired to any node. If used in a shell command, this is fine. Otherwise, wire it with: @connect secret:${secretName} -> node.port`,
62
+ });
63
+ }
64
+ }
65
+ return errors;
66
+ },
67
+ };
68
+ // ---------------------------------------------------------------------------
69
+ // Rule 3: Trigger Missing
70
+ // ---------------------------------------------------------------------------
71
+ /**
72
+ * A CI/CD workflow with no trigger annotations would never run automatically.
73
+ * Needs at least one @trigger (push, pull_request, schedule, dispatch, or tag).
74
+ */
75
+ export const triggerMissingRule = {
76
+ name: 'CICD_TRIGGER_MISSING',
77
+ validate(ast) {
78
+ const triggers = ast.options?.cicd?.triggers || [];
79
+ // Also check for FW-style triggers (event=, cron=)
80
+ const fwTrigger = ast.options?.trigger;
81
+ if (triggers.length === 0 && !fwTrigger) {
82
+ return [
83
+ {
84
+ type: 'warning',
85
+ code: 'CICD_TRIGGER_MISSING',
86
+ message: 'No trigger annotations found. The pipeline will never run automatically. Add at least one: @trigger push branches="main" or @trigger dispatch',
87
+ },
88
+ ];
89
+ }
90
+ return [];
91
+ },
92
+ };
93
+ // ---------------------------------------------------------------------------
94
+ // Rule 4: Job Missing Runner
95
+ // ---------------------------------------------------------------------------
96
+ /**
97
+ * A job (group of nodes with same [job: "name"]) has no explicit runner
98
+ * and the workflow has no default @runner. The export target will use a
99
+ * platform default, which may not be what the user expects.
100
+ */
101
+ export const jobMissingRunnerRule = {
102
+ name: 'CICD_JOB_MISSING_RUNNER',
103
+ validate(ast) {
104
+ const errors = [];
105
+ const defaultRunner = ast.options?.cicd?.runner;
106
+ const jobNames = getJobNames(ast);
107
+ // If there's a default runner, all jobs are covered
108
+ if (defaultRunner)
109
+ return [];
110
+ // If there are jobs but no default runner, warn
111
+ if (jobNames.length > 0) {
112
+ errors.push({
113
+ type: 'warning',
114
+ code: 'CICD_JOB_MISSING_RUNNER',
115
+ message: `No @runner annotation found. Jobs (${jobNames.join(', ')}) will use platform defaults. Add: @runner ubuntu-latest`,
116
+ });
117
+ }
118
+ return errors;
119
+ },
120
+ };
121
+ // ---------------------------------------------------------------------------
122
+ // Rule 5: Artifact Cross-Job
123
+ // ---------------------------------------------------------------------------
124
+ /**
125
+ * Data flows between nodes in different jobs via connections, but no @artifact
126
+ * is declared. In CI/CD, each job runs in a fresh environment — data must be
127
+ * explicitly passed via artifacts.
128
+ */
129
+ export const artifactCrossJobRule = {
130
+ name: 'CICD_ARTIFACT_CROSS_JOB',
131
+ validate(ast) {
132
+ const errors = [];
133
+ const artifacts = ast.options?.cicd?.artifacts || [];
134
+ // Build node -> job map
135
+ const nodeJob = new Map();
136
+ for (const inst of ast.instances) {
137
+ if (inst.job)
138
+ nodeJob.set(inst.id, inst.job);
139
+ }
140
+ // Check connections between nodes in different jobs
141
+ const crossJobPairs = new Set();
142
+ for (const conn of ast.connections) {
143
+ // Skip secret: pseudo-nodes and Start/Exit
144
+ if (conn.from.node.startsWith('secret:'))
145
+ continue;
146
+ if (conn.from.node === 'Start' || conn.to.node === 'Exit')
147
+ continue;
148
+ const fromJob = nodeJob.get(conn.from.node);
149
+ const toJob = nodeJob.get(conn.to.node);
150
+ if (fromJob && toJob && fromJob !== toJob) {
151
+ const pairKey = `${fromJob}->${toJob}`;
152
+ if (!crossJobPairs.has(pairKey)) {
153
+ crossJobPairs.add(pairKey);
154
+ }
155
+ }
156
+ }
157
+ // If there are cross-job data flows but no artifacts declared, warn
158
+ if (crossJobPairs.size > 0 && artifacts.length === 0) {
159
+ const pairs = Array.from(crossJobPairs);
160
+ errors.push({
161
+ type: 'warning',
162
+ code: 'CICD_ARTIFACT_CROSS_JOB',
163
+ message: `Data flows between jobs (${pairs.join(', ')}) but no @artifact is declared. In CI/CD, each job runs in a fresh environment. Add @artifact declarations to pass data between jobs.`,
164
+ });
165
+ }
166
+ return errors;
167
+ },
168
+ };
169
+ // ---------------------------------------------------------------------------
170
+ // Rule 6: Circular Job Dependencies
171
+ // ---------------------------------------------------------------------------
172
+ /**
173
+ * Job dependencies (derived from @path connections between jobs) form a cycle.
174
+ * CI/CD platforms reject circular job dependencies.
175
+ */
176
+ export const circularJobDepsRule = {
177
+ name: 'CICD_CIRCULAR_JOB_DEPS',
178
+ validate(ast) {
179
+ const errors = [];
180
+ // Build node -> job map
181
+ const nodeJob = new Map();
182
+ for (const inst of ast.instances) {
183
+ if (inst.job)
184
+ nodeJob.set(inst.id, inst.job);
185
+ }
186
+ // Build job dependency graph from connections
187
+ const jobDeps = new Map();
188
+ for (const conn of ast.connections) {
189
+ if (conn.from.node.startsWith('secret:'))
190
+ continue;
191
+ if (conn.from.node === 'Start' || conn.to.node === 'Exit')
192
+ continue;
193
+ const fromJob = nodeJob.get(conn.from.node);
194
+ const toJob = nodeJob.get(conn.to.node);
195
+ if (fromJob && toJob && fromJob !== toJob) {
196
+ if (!jobDeps.has(toJob))
197
+ jobDeps.set(toJob, new Set());
198
+ jobDeps.get(toJob).add(fromJob);
199
+ }
200
+ }
201
+ // Detect cycles using DFS
202
+ const visited = new Set();
203
+ const inStack = new Set();
204
+ function hasCycle(job) {
205
+ if (inStack.has(job))
206
+ return true;
207
+ if (visited.has(job))
208
+ return false;
209
+ visited.add(job);
210
+ inStack.add(job);
211
+ const deps = jobDeps.get(job);
212
+ if (deps) {
213
+ for (const dep of deps) {
214
+ if (hasCycle(dep))
215
+ return true;
216
+ }
217
+ }
218
+ inStack.delete(job);
219
+ return false;
220
+ }
221
+ const allJobs = getJobNames(ast);
222
+ for (const job of allJobs) {
223
+ if (hasCycle(job)) {
224
+ errors.push({
225
+ type: 'error',
226
+ code: 'CICD_CIRCULAR_JOB_DEPS',
227
+ message: `Circular dependency detected involving job '${job}'. CI/CD platforms require a directed acyclic graph of job dependencies.`,
228
+ });
229
+ break; // Report once
230
+ }
231
+ }
232
+ return errors;
233
+ },
234
+ };
235
+ // ---------------------------------------------------------------------------
236
+ // Rule 7: Matrix with Environment
237
+ // ---------------------------------------------------------------------------
238
+ /**
239
+ * Using @matrix with @environment protection means each matrix combination
240
+ * triggers an approval prompt. For a 3x2 matrix, that's 6 prompts.
241
+ */
242
+ export const matrixWithEnvironmentRule = {
243
+ name: 'CICD_MATRIX_WITH_ENVIRONMENT',
244
+ validate(ast) {
245
+ const errors = [];
246
+ const matrix = ast.options?.cicd?.matrix;
247
+ const environments = ast.options?.cicd?.environments || [];
248
+ if (matrix && environments.length > 0) {
249
+ // Calculate matrix size
250
+ const dimensions = matrix.include
251
+ ? matrix.include.length
252
+ : Object.values(matrix.dimensions || {}).reduce((acc, vals) => acc * vals.length, 1);
253
+ if (dimensions > 1) {
254
+ errors.push({
255
+ type: 'warning',
256
+ code: 'CICD_MATRIX_WITH_ENVIRONMENT',
257
+ message: `Using @matrix (${dimensions} combinations) with @environment protection will trigger ${dimensions} approval prompts per deployment. Consider separating the matrix job from the deploy job.`,
258
+ });
259
+ }
260
+ }
261
+ return errors;
262
+ },
263
+ };
264
+ // ---------------------------------------------------------------------------
265
+ // Public API
266
+ // ---------------------------------------------------------------------------
267
+ /** All CI/CD validation rules */
268
+ export const cicdValidationRules = [
269
+ secretNotDeclaredRule,
270
+ secretUnusedRule,
271
+ triggerMissingRule,
272
+ jobMissingRunnerRule,
273
+ artifactCrossJobRule,
274
+ circularJobDepsRule,
275
+ matrixWithEnvironmentRule,
276
+ ];
277
+ /**
278
+ * Get all CI/CD validation rules.
279
+ * Convenience function for passing to validateWorkflow().
280
+ */
281
+ export function getCICDValidationRules() {
282
+ return cicdValidationRules;
283
+ }
284
+ //# sourceMappingURL=cicd-rules.js.map
@@ -94,6 +94,10 @@ flow-weaver templates [--json]
94
94
  | `error-handler` | Try/catch/retry pattern with error recovery |
95
95
  | `ai-agent-durable` | Linear agent pipeline with durability — classify, tools, approval, respond |
96
96
  | `ai-pipeline-durable` | Sequential data pipeline with durability — fetch, extract, validate, save |
97
+ | `cicd-test-deploy` | Standard test-and-deploy pipeline with checkout, setup, test, build, and deploy stages |
98
+ | `cicd-docker` | Build and push Docker images to a container registry |
99
+ | `cicd-multi-env` | Multi-environment deployment pipeline with staging and production stages |
100
+ | `cicd-matrix` | Test across multiple Node.js versions and operating systems |
97
101
  <!-- AUTO:END workflow_templates_table -->
98
102
 
99
103
  ## Node Templates
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synergenius/flow-weaver",
3
- "version": "0.13.2",
3
+ "version": "0.14.0",
4
4
  "description": "Deterministic workflow compiler for AI agents. Compiles to standalone TypeScript, no runtime dependencies.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -134,6 +134,7 @@
134
134
  "chevrotain": "^11.0.3",
135
135
  "chokidar": "^4.0.0",
136
136
  "commander": "^11.1.0",
137
+ "esbuild": "^0.27.2",
137
138
  "glob": "^10.3.10",
138
139
  "immer": "^10.2.0",
139
140
  "js-yaml": "^4.1.0",
@@ -141,8 +142,8 @@
141
142
  "source-map": "^0.7.6",
142
143
  "ts-morph": "^21.0.1",
143
144
  "ws": "^8.19.0",
144
- "zod": "^3.22.4",
145
- "esbuild": "^0.27.2"
145
+ "yaml": "^2.8.2",
146
+ "zod": "^3.22.4"
146
147
  },
147
148
  "devDependencies": {
148
149
  "@types/js-yaml": "^4.0.9",