@synergenius/flow-weaver 0.17.0 → 0.17.2

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 (123) hide show
  1. package/dist/api/index.d.ts +4 -1
  2. package/dist/api/index.js +4 -1
  3. package/dist/api/templates.js +2 -2
  4. package/dist/api/validate.d.ts +2 -2
  5. package/dist/api/validate.js +6 -6
  6. package/dist/api/validation-registry.d.ts +10 -0
  7. package/dist/api/validation-registry.js +10 -0
  8. package/dist/ast/types.d.ts +91 -4
  9. package/dist/built-in-nodes/invoke-workflow.d.ts +1 -1
  10. package/dist/built-in-nodes/invoke-workflow.js +1 -1
  11. package/dist/chevrotain-parser/connect-parser.js +25 -7
  12. package/dist/cli/commands/compile.d.ts +5 -9
  13. package/dist/cli/commands/compile.js +21 -14
  14. package/dist/cli/commands/dev.d.ts +2 -13
  15. package/dist/cli/commands/dev.js +10 -204
  16. package/dist/cli/commands/doctor.js +6 -3
  17. package/dist/cli/commands/export.d.ts +8 -17
  18. package/dist/cli/commands/export.js +8 -17
  19. package/dist/cli/commands/init-personas.d.ts +17 -6
  20. package/dist/cli/commands/init-personas.js +73 -24
  21. package/dist/cli/commands/init.d.ts +5 -2
  22. package/dist/cli/commands/init.js +73 -42
  23. package/dist/cli/commands/mcp-setup.d.ts +7 -0
  24. package/dist/cli/commands/mcp-setup.js +16 -1
  25. package/dist/cli/flow-weaver.mjs +71002 -70385
  26. package/dist/cli/index.d.ts +1 -0
  27. package/dist/cli/index.js +9 -7
  28. package/dist/cli/templates/index.d.ts +20 -1
  29. package/dist/cli/templates/index.js +66 -15
  30. package/dist/cli/templates/nodes/human-approval.js +2 -3
  31. package/dist/cli/templates/nodes/rag-retriever.js +1 -1
  32. package/dist/constants.d.ts +7 -0
  33. package/dist/constants.js +13 -3
  34. package/dist/context/index.js +13 -3
  35. package/dist/deployment/config/loader.js +2 -1
  36. package/dist/deployment/core/adapters.d.ts +1 -25
  37. package/dist/deployment/core/adapters.js +0 -95
  38. package/dist/deployment/core/formatters.d.ts +0 -15
  39. package/dist/deployment/core/formatters.js +0 -24
  40. package/dist/deployment/index.d.ts +7 -5
  41. package/dist/deployment/index.js +8 -5
  42. package/dist/deployment/types.d.ts +2 -45
  43. package/dist/diagram/html-viewer.js +65 -32
  44. package/dist/diagram/renderer.js +9 -6
  45. package/dist/diagram/theme.js +4 -0
  46. package/dist/diagram/types.d.ts +2 -0
  47. package/dist/doc-metadata/extractors/annotations.js +5 -5
  48. package/dist/doc-metadata/extractors/cli-commands.js +1 -1
  49. package/dist/doc-metadata/extractors/mcp-tools.js +1 -2
  50. package/dist/docs/index.d.ts +28 -1
  51. package/dist/docs/index.js +95 -28
  52. package/dist/export/index.d.ts +2 -3
  53. package/dist/{deployment/targets/cicd-base.d.ts → extensions/cicd/base-target.d.ts} +35 -36
  54. package/dist/{deployment/targets/cicd-base.js → extensions/cicd/base-target.js} +97 -57
  55. package/dist/{validation/cicd-detection.d.ts → extensions/cicd/detection.d.ts} +2 -2
  56. package/dist/{validation/cicd-detection.js → extensions/cicd/detection.js} +13 -1
  57. package/dist/extensions/cicd/docs/cicd.md +395 -0
  58. package/dist/extensions/cicd/index.d.ts +10 -0
  59. package/dist/extensions/cicd/index.js +10 -0
  60. package/dist/extensions/cicd/register.d.ts +11 -0
  61. package/dist/extensions/cicd/register.js +62 -0
  62. package/dist/extensions/cicd/rules.d.ts +30 -0
  63. package/dist/{validation/cicd-rules.js → extensions/cicd/rules.js} +60 -56
  64. package/dist/extensions/cicd/tag-handler.d.ts +14 -0
  65. package/dist/extensions/cicd/tag-handler.js +488 -0
  66. package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-docker.d.ts +1 -1
  67. package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-matrix.d.ts +1 -1
  68. package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-multi-env.d.ts +1 -1
  69. package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-test-deploy.d.ts +1 -1
  70. package/dist/extensions/index.d.ts +12 -0
  71. package/dist/extensions/index.js +12 -0
  72. package/dist/extensions/inngest/dev-mode.d.ts +9 -0
  73. package/dist/extensions/inngest/dev-mode.js +213 -0
  74. package/dist/{generator/inngest.d.ts → extensions/inngest/generator.d.ts} +2 -2
  75. package/dist/{generator/inngest.js → extensions/inngest/generator.js} +4 -4
  76. package/dist/extensions/inngest/index.d.ts +2 -0
  77. package/dist/extensions/inngest/index.js +2 -0
  78. package/dist/extensions/inngest/register.d.ts +6 -0
  79. package/dist/extensions/inngest/register.js +23 -0
  80. package/dist/extensions/inngest/templates/ai-agent-durable.d.ts +8 -0
  81. package/dist/{cli/templates/workflows → extensions/inngest/templates}/ai-agent-durable.js +8 -8
  82. package/dist/{cli/templates/workflows → extensions/inngest/templates}/ai-pipeline-durable.d.ts +2 -2
  83. package/dist/{cli/templates/workflows → extensions/inngest/templates}/ai-pipeline-durable.js +7 -7
  84. package/dist/generated-version.d.ts +1 -1
  85. package/dist/generated-version.js +1 -1
  86. package/dist/generator/compile-target-registry.d.ts +20 -0
  87. package/dist/generator/compile-target-registry.js +20 -0
  88. package/dist/generator/dev-mode-registry.d.ts +27 -0
  89. package/dist/generator/dev-mode-registry.js +20 -0
  90. package/dist/index.d.ts +4 -0
  91. package/dist/index.js +3 -0
  92. package/dist/jsdoc-parser.d.ts +12 -114
  93. package/dist/jsdoc-parser.js +57 -362
  94. package/dist/marketplace/index.d.ts +2 -2
  95. package/dist/marketplace/index.js +1 -1
  96. package/dist/marketplace/registry.d.ts +39 -1
  97. package/dist/marketplace/registry.js +77 -0
  98. package/dist/marketplace/types.d.ts +76 -3
  99. package/dist/mcp/server.d.ts +1 -0
  100. package/dist/mcp/server.js +2 -0
  101. package/dist/mcp/tools-export.js +3 -3
  102. package/dist/mcp/tools-query.js +17 -11
  103. package/dist/mcp/tools-template.js +1 -1
  104. package/dist/parser/tag-registry.d.ts +47 -0
  105. package/dist/parser/tag-registry.js +57 -0
  106. package/dist/parser.d.ts +3 -0
  107. package/dist/parser.js +10 -23
  108. package/dist/validation/rule-registry.d.ts +36 -0
  109. package/dist/validation/rule-registry.js +37 -0
  110. package/dist/validator.js +3 -3
  111. package/docs/reference/concepts.md +2 -1
  112. package/docs/reference/deployment.md +21 -0
  113. package/docs/reference/jsdoc-grammar.md +242 -1
  114. package/docs/reference/scaffold.md +0 -6
  115. package/package.json +9 -1
  116. package/dist/cli/templates/workflows/ai-agent-durable.d.ts +0 -8
  117. package/dist/export/templates.d.ts +0 -24
  118. package/dist/export/templates.js +0 -186
  119. package/dist/validation/cicd-rules.d.ts +0 -62
  120. /package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-docker.js +0 -0
  121. /package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-matrix.js +0 -0
  122. /package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-multi-env.js +0 -0
  123. /package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-test-deploy.js +0 -0
@@ -8,7 +8,7 @@ import type { ExecutionTraceEvent } from '../mcp/workflow-executor.js';
8
8
  /**
9
9
  * Source of a workflow execution request
10
10
  */
11
- export type ExecutionSource = 'cli' | 'http' | 'lambda' | 'vercel' | 'cloudflare';
11
+ export type ExecutionSource = 'cli' | 'http' | (string & {});
12
12
  /**
13
13
  * Runtime environment
14
14
  */
@@ -133,51 +133,8 @@ export interface HttpInput {
133
133
  /** Request headers */
134
134
  headers: Record<string, string | string[] | undefined>;
135
135
  }
136
- /**
137
- * Input from AWS Lambda
138
- */
139
- export interface LambdaInput {
140
- /** Raw event body (JSON string or parsed object) */
141
- body?: string | Record<string, unknown>;
142
- /** Path parameters */
143
- pathParameters?: Record<string, string>;
144
- /** Query string parameters */
145
- queryStringParameters?: Record<string, string>;
146
- /** Request headers */
147
- headers?: Record<string, string>;
148
- /** Request context */
149
- requestContext?: {
150
- requestId?: string;
151
- stage?: string;
152
- };
153
- }
154
- /**
155
- * Input from Vercel serverless function
156
- */
157
- export interface VercelInput {
158
- /** Request method */
159
- method: string;
160
- /** Request body (already parsed) */
161
- body: Record<string, unknown>;
162
- /** Query parameters */
163
- query: Record<string, string | string[]>;
164
- /** Request headers */
165
- headers: Record<string, string | string[]>;
166
- }
167
- /**
168
- * Input from Cloudflare Worker
169
- */
170
- export interface CloudflareInput {
171
- /** Request object */
172
- request: {
173
- method: string;
174
- url: string;
175
- headers: Headers;
176
- json: () => Promise<Record<string, unknown>>;
177
- };
178
- }
179
136
  /**
180
137
  * Generic adapter input type
181
138
  */
182
- export type AdapterInput = CliInput | HttpInput | LambdaInput | VercelInput | CloudflareInput;
139
+ export type AdapterInput = CliInput | HttpInput;
183
140
  //# sourceMappingURL=types.d.ts.map
@@ -29,7 +29,7 @@ export function wrapSVGInHTML(svgContent, options = {}) {
29
29
  const { inner, viewBox } = prepareSvgContent(svgContent);
30
30
  const isDark = theme === 'dark';
31
31
  const bg = isDark ? '#202139' : '#f6f7ff';
32
- const dotColor = isDark ? 'rgba(142, 158, 255, 0.6)' : 'rgba(84, 104, 255, 0.6)';
32
+ const dotColor = isDark ? 'rgba(142, 158, 255, 0.5)' : 'rgba(84, 104, 255, 0.45)';
33
33
  const surfaceMain = isDark ? '#1a1a2e' : '#ffffff';
34
34
  const borderSubtle = isDark ? '#313143' : '#e6e6e6';
35
35
  const textHigh = isDark ? '#e8e8ee' : '#1a1a2e';
@@ -96,15 +96,19 @@ path[data-source].port-hover { opacity: 1; }
96
96
  /* Node hover glow + draggable cursor */
97
97
  .nodes g[data-node-id] { cursor: grab; }
98
98
  .nodes g[data-node-id]:active { cursor: grabbing; }
99
- .nodes g[data-node-id]:hover > rect:first-of-type { filter: brightness(1.08); }
99
+ .nodes g[data-node-id]:hover > rect:first-of-type {
100
+ filter: brightness(1.08) drop-shadow(0 0 6px ${isDark ? 'rgba(142,158,255,0.15)' : 'rgba(84,104,255,0.12)'});
101
+ transition: filter 0.15s ease;
102
+ }
100
103
 
101
104
  /* Zoom controls */
102
105
  #controls {
103
106
  position: fixed; bottom: 16px; right: 16px;
104
107
  display: flex; align-items: center; gap: 2px;
105
- background: ${surfaceMain}; border: 1px solid ${borderSubtle};
108
+ background: ${isDark ? 'rgba(26,26,46,0.85)' : 'rgba(255,255,255,0.85)'};
109
+ backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
110
+ border: 1px solid ${isDark ? 'rgba(142,158,255,0.12)' : 'rgba(84,104,255,0.1)'};
106
111
  border-radius: 8px; padding: 4px; z-index: 10;
107
- box-shadow: 0 2px 8px rgba(0,0,0,0.2);
108
112
  }
109
113
  .ctrl-btn {
110
114
  display: flex; align-items: center; justify-content: center;
@@ -113,24 +117,26 @@ path[data-source].port-hover { opacity: 1; }
113
117
  font-size: 16px; font-weight: 600; cursor: pointer;
114
118
  transition: background 0.15s, color 0.15s;
115
119
  }
116
- .ctrl-btn:hover { background: ${surfaceHigh}; color: ${textHigh}; }
120
+ .ctrl-btn:hover { background: ${isDark ? 'rgba(142,158,255,0.08)' : 'rgba(84,104,255,0.06)'}; color: ${textHigh}; }
117
121
  #zoom-label {
118
122
  font-size: 11px; font-family: 'SF Mono', 'Fira Code', monospace;
119
123
  color: ${textLow}; min-width: 36px; text-align: center;
120
124
  }
121
125
 
122
126
  /* Info panel */
127
+ @keyframes panelSlideIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
123
128
  #info-panel {
124
129
  position: fixed; bottom: 52px; left: 16px;
125
130
  max-width: 480px; min-width: 260px;
126
- background: ${surfaceMain}; border: 1px solid ${borderSubtle};
127
- border-radius: 8px; padding: 12px 16px;
131
+ background: ${isDark ? 'rgba(26,26,46,0.85)' : 'rgba(255,255,255,0.85)'};
132
+ backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
133
+ border: 1px solid ${isDark ? 'rgba(142,158,255,0.12)' : 'rgba(84,104,255,0.1)'};
134
+ border-radius: 8px; padding: 0;
128
135
  font-size: 13px; line-height: 1.5;
129
- box-shadow: 0 2px 8px rgba(0,0,0,0.2);
130
136
  z-index: 10; display: none;
131
- max-height: calc(100vh - 120px); overflow-y: auto;
137
+ max-height: calc(100vh - 120px); overflow: hidden;
132
138
  }
133
- #info-panel.visible { display: block; }
139
+ #info-panel.visible { display: block; animation: panelSlideIn 0.2s ease-out; }
134
140
  #info-panel h3 {
135
141
  font-size: 14px; font-weight: 700; margin: 0;
136
142
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
@@ -139,10 +145,10 @@ path[data-source].port-hover { opacity: 1; }
139
145
  #info-panel .info-section { margin-bottom: 6px; }
140
146
  #info-panel .info-label { font-size: 11px; font-weight: 600; color: ${textLow}; text-transform: uppercase; letter-spacing: 0.5px; }
141
147
  #info-panel .info-value { color: ${textMed}; }
142
- #info-panel .port-list { list-style: none; padding: 0; }
143
- #info-panel .port-list li { padding: 1px 0; }
144
- #info-panel .port-list li::before { content: '\\2022'; margin-right: 6px; color: ${textLow}; }
145
- #info-panel .port-type { color: ${textLow}; font-size: 11px; margin-left: 4px; font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; }
148
+ #info-panel .port-list { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 2px; }
149
+ #info-panel .port-list li { padding: 2px 0; display: flex; align-items: center; gap: 6px; }
150
+ #info-panel .port-list li::before { content: '\\2022'; color: ${textLow}; flex-shrink: 0; }
151
+ #info-panel .port-type { color: ${textLow}; font-size: 11px; font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; }
146
152
  #info-panel pre {
147
153
  background: ${isDark ? '#161625' : '#f0f1fa'}; border: 1px solid ${borderSubtle};
148
154
  border-radius: 6px; padding: 10px; overflow-x: auto;
@@ -162,9 +168,11 @@ path[data-source].port-hover { opacity: 1; }
162
168
 
163
169
  /* Info panel header */
164
170
  #info-header {
165
- display: flex; align-items: center; gap: 6px; margin-bottom: 6px;
171
+ display: flex; align-items: center; gap: 6px; padding: 12px 16px;
172
+ border-bottom: 1px solid ${isDark ? 'rgba(142,158,255,0.08)' : 'rgba(84,104,255,0.06)'};
166
173
  }
167
174
  #info-header h3 { flex: 1; margin-bottom: 0; }
175
+ #info-body { padding: 12px 16px; overflow-y: auto; max-height: calc(100vh - 180px); }
168
176
  .panel-btn {
169
177
  display: flex; align-items: center; justify-content: center;
170
178
  width: 24px; height: 24px; border: none; border-radius: 4px;
@@ -174,16 +182,7 @@ path[data-source].port-hover { opacity: 1; }
174
182
  }
175
183
  .panel-btn:hover { background: ${surfaceHigh}; color: ${textHigh}; }
176
184
 
177
- /* Info panel transitions */
178
- #info-panel {
179
- transition: left 0.3s cubic-bezier(0.4,0,0.2,1), bottom 0.3s cubic-bezier(0.4,0,0.2,1),
180
- width 0.3s cubic-bezier(0.4,0,0.2,1), height 0.3s cubic-bezier(0.4,0,0.2,1),
181
- max-width 0.3s cubic-bezier(0.4,0,0.2,1), max-height 0.3s cubic-bezier(0.4,0,0.2,1),
182
- min-width 0.3s cubic-bezier(0.4,0,0.2,1), border-radius 0.3s cubic-bezier(0.4,0,0.2,1),
183
- opacity 0.2s ease, transform 0.3s cubic-bezier(0.4,0,0.2,1);
184
- transform: translateY(8px); opacity: 0;
185
- }
186
- #info-panel.visible { transform: translateY(0); opacity: 1; }
185
+ /* Info panel fullscreen transitions */
187
186
  #info-panel.fullscreen {
188
187
  left: 16px; bottom: 16px; top: 16px; right: 16px;
189
188
  max-width: none; min-width: 0; width: auto; max-height: none;
@@ -206,20 +205,25 @@ path[data-source].port-hover { opacity: 1; }
206
205
  #branding {
207
206
  position: fixed; bottom: 16px; left: 16px;
208
207
  display: flex; align-items: center; gap: 6px;
209
- background: ${surfaceMain}; border: 1px solid ${borderSubtle};
208
+ background: ${isDark ? 'rgba(26,26,46,0.85)' : 'rgba(255,255,255,0.85)'};
209
+ backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
210
+ border: 1px solid ${isDark ? 'rgba(142,158,255,0.12)' : 'rgba(84,104,255,0.1)'};
210
211
  border-radius: 8px; padding: 6px 12px;
211
212
  font-size: 12px; font-weight: 600; color: ${textMed};
212
213
  text-decoration: none; z-index: 9;
213
- box-shadow: 0 2px 8px rgba(0,0,0,0.2);
214
214
  transition: color 0.15s, border-color 0.15s;
215
215
  }
216
216
  #branding:hover { color: ${textHigh}; border-color: ${textLow}; }
217
217
 
218
218
  /* Scroll hint */
219
+ @keyframes hintFade { 0% { opacity: 1; } 80% { opacity: 1; } 100% { opacity: 0; } }
219
220
  #scroll-hint {
220
221
  position: fixed; top: 50%; left: 50%;
221
222
  transform: translate(-50%, -50%);
222
- background: rgba(0,0,0,0.75); color: #fff;
223
+ background: ${isDark ? 'rgba(26,26,46,0.92)' : 'rgba(255,255,255,0.92)'};
224
+ backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
225
+ border: 1px solid ${isDark ? 'rgba(142,158,255,0.12)' : 'rgba(84,104,255,0.1)'};
226
+ color: ${textHigh};
223
227
  padding: 6px 14px; border-radius: 8px;
224
228
  font-size: 13px; pointer-events: none;
225
229
  z-index: 20; opacity: 0; transition: opacity 0.3s;
@@ -227,25 +231,54 @@ path[data-source].port-hover { opacity: 1; }
227
231
  #scroll-hint.visible { opacity: 1; }
228
232
  #scroll-hint kbd {
229
233
  display: inline-block; padding: 1px 5px;
230
- border: 1px solid rgba(255,255,255,0.3);
234
+ border: 1px solid ${isDark ? 'rgba(255,255,255,0.15)' : 'rgba(0,0,0,0.15)'};
231
235
  border-radius: 3px; font-family: 'SF Mono', 'Fira Code', monospace;
232
- font-size: 12px; background: rgba(255,255,255,0.1);
236
+ font-size: 12px; background: ${isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.04)'};
233
237
  }
234
238
 
235
239
  /* Studio nudge toast */
236
240
  #studio-hint {
237
241
  position: fixed; bottom: 60px; left: 50%;
238
242
  transform: translateX(-50%);
239
- background: ${surfaceMain}; border: 1px solid ${borderSubtle};
243
+ background: ${isDark ? 'rgba(26,26,46,0.85)' : 'rgba(255,255,255,0.85)'};
244
+ backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
245
+ border: 1px solid ${isDark ? 'rgba(142,158,255,0.12)' : 'rgba(84,104,255,0.1)'};
240
246
  padding: 8px 16px; border-radius: 8px;
241
247
  font-size: 13px; color: ${textMed};
242
- box-shadow: 0 2px 8px rgba(0,0,0,0.2);
243
248
  z-index: 20; opacity: 0; transition: opacity 0.4s;
244
249
  pointer-events: none;
245
250
  }
246
251
  #studio-hint.visible { opacity: 1; pointer-events: auto; }
247
252
  #studio-hint a { color: ${brandAccent}; text-decoration: none; font-weight: 600; }
248
253
  #studio-hint a:hover { text-decoration: underline; }
254
+
255
+ /* Reduced motion */
256
+ @media (prefers-reduced-motion: reduce) {
257
+ .node-glow { animation: none; opacity: 0.35; stroke-width: 8; }
258
+ #info-panel { animation: none; }
259
+ * { transition-duration: 0s !important; }
260
+ }
261
+
262
+ /* Responsive: mobile */
263
+ @media (max-width: 768px) {
264
+ #controls { bottom: 12px; right: 12px; padding: 3px; }
265
+ .ctrl-btn { width: 24px; height: 24px; font-size: 14px; }
266
+ #zoom-label { font-size: 10px; min-width: 30px; }
267
+ #branding { bottom: 12px; left: 12px; padding: 4px 8px; font-size: 11px; }
268
+ #studio-hint { max-width: 90vw; text-align: center; white-space: normal; }
269
+ #info-panel {
270
+ left: 0 !important; right: 0 !important; bottom: 0 !important;
271
+ max-width: none; min-width: 0; width: 100%;
272
+ border-radius: 12px 12px 0 0;
273
+ max-height: 60vh;
274
+ }
275
+ #info-panel::before {
276
+ content: ''; display: block; width: 32px; height: 4px;
277
+ background: ${isDark ? 'rgba(142,158,255,0.3)' : 'rgba(84,104,255,0.2)'};
278
+ border-radius: 2px; margin: 8px auto 4px;
279
+ }
280
+ #info-body { max-height: calc(60vh - 80px); }
281
+ }
249
282
  </style>
250
283
  </head>
251
284
  <body>
@@ -37,11 +37,14 @@ export function renderSVG(graph, options = {}) {
37
37
  parts.push(` .port-label { font-size: 10px; font-weight: 600; fill: ${theme.labelColor}; }`);
38
38
  parts.push(` .port-type-label { font-size: 10px; font-weight: 600; }`);
39
39
  parts.push(`</style>`);
40
- // Defs (dot grid pattern + connection gradients)
40
+ // Defs (dot grid pattern + node shadow filter + connection gradients)
41
41
  parts.push(`<defs>`);
42
42
  parts.push(` <pattern id="dot-grid" width="20" height="20" patternUnits="userSpaceOnUse">`);
43
- parts.push(` <circle cx="10" cy="10" r="1.5" fill="${theme.dotColor}" opacity="0.6"/>`);
43
+ parts.push(` <circle cx="10" cy="10" r="1.5" fill="${theme.dotColor}" opacity="${theme.dotOpacity}"/>`);
44
44
  parts.push(` </pattern>`);
45
+ parts.push(` <filter id="node-shadow" x="-10%" y="-10%" width="130%" height="140%">`);
46
+ parts.push(` <feDropShadow dx="0" dy="2" stdDeviation="4" flood-opacity="${theme.nodeShadowOpacity}" flood-color="#000"/>`);
47
+ parts.push(` </filter>`);
45
48
  for (let i = 0; i < allConnections.length; i++) {
46
49
  const conn = allConnections[i];
47
50
  parts.push(` <linearGradient id="conn-grad-${i}" x1="0%" y1="0%" x2="100%" y2="0%">`);
@@ -51,8 +54,8 @@ export function renderSVG(graph, options = {}) {
51
54
  }
52
55
  parts.push(`</defs>`);
53
56
  // Background
54
- parts.push(`<rect width="${vbWidth}" height="${vbHeight}" fill="${theme.background}"/>`);
55
- parts.push(`<rect width="${vbWidth}" height="${vbHeight}" fill="url(#dot-grid)"/>`);
57
+ parts.push(`<rect x="${vbX}" y="${vbY}" width="${vbWidth}" height="${vbHeight}" fill="${theme.background}"/>`);
58
+ parts.push(`<rect x="${vbX}" y="${vbY}" width="${vbWidth}" height="${vbHeight}" fill="url(#dot-grid)"/>`);
56
59
  // Connections
57
60
  parts.push(`<g class="connections">`);
58
61
  for (let i = 0; i < graph.connections.length; i++) {
@@ -111,7 +114,7 @@ function renderScopeConnection(parts, conn, allConnections, parentNodeId) {
111
114
  /** Render node body rect + icon */
112
115
  function renderNodeBody(parts, node, theme, indent) {
113
116
  const strokeColor = node.color !== '#334155' ? node.color : theme.nodeIconColor;
114
- parts.push(`${indent}<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2"/>`);
117
+ parts.push(`${indent}<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2" filter="url(#node-shadow)"/>`);
115
118
  const iconPath = NODE_ICON_PATHS[node.icon] ?? NODE_ICON_PATHS.code;
116
119
  const iconColor = node.color !== '#334155' ? node.color : theme.nodeIconColor;
117
120
  const iconSize = 40;
@@ -125,7 +128,7 @@ function renderNode(node, theme, themeName, allConnections) {
125
128
  if (node.scopeChildren && node.scopeChildren.length > 0) {
126
129
  // Scoped node: body rect only (no icon), then scope internals
127
130
  const strokeColor = node.color !== '#334155' ? node.color : theme.nodeIconColor;
128
- parts.push(` <rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2"/>`);
131
+ parts.push(` <rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2" filter="url(#node-shadow)"/>`);
129
132
  renderScopedContent(parts, node, theme, themeName, allConnections);
130
133
  }
131
134
  else {
@@ -50,6 +50,8 @@ const DARK_PALETTE = {
50
50
  labelBadgeBorder: '#313143', // color-surface-lowest = dark-shade-90
51
51
  nodeIconColor: '#a4beff', // secondary-dark-base (matches label color)
52
52
  scopeAreaStroke: '#5f5f6d', // color-border-subtle = dark-shade-70
53
+ nodeShadowOpacity: 0.15,
54
+ dotOpacity: 0.5,
53
55
  };
54
56
  const LIGHT_PALETTE = {
55
57
  background: '#f6f7ff', // color-brand-subtle-bg = primary-extended-tint-95
@@ -63,6 +65,8 @@ const LIGHT_PALETTE = {
63
65
  labelBadgeBorder: '#e6e6e6', // shade-10
64
66
  nodeIconColor: '#5468ff', // primary-base (light)
65
67
  scopeAreaStroke: '#cccccc', // color-border-default
68
+ nodeShadowOpacity: 0.08,
69
+ dotOpacity: 0.45,
66
70
  };
67
71
  export function getTheme(name) {
68
72
  return name === 'light' ? LIGHT_PALETTE : DARK_PALETTE;
@@ -69,5 +69,7 @@ export interface ThemePalette {
69
69
  labelBadgeBorder: string;
70
70
  nodeIconColor: string;
71
71
  scopeAreaStroke: string;
72
+ nodeShadowOpacity: number;
73
+ dotOpacity: number;
72
74
  }
73
75
  //# sourceMappingURL=types.d.ts.map
@@ -309,7 +309,7 @@ targetType ::= "string" | "number" | "boolean" | "json" | "object"`,
309
309
  name: '@trigger',
310
310
  category: 'workflow',
311
311
  syntax: '@trigger event="name" | cron="expr"',
312
- description: 'Declares an event or cron trigger for Inngest deployment. Can specify event, cron, or both.',
312
+ description: 'Declares an event or cron trigger for the workflow. Can specify event, cron, or both.',
313
313
  insertText: '@trigger event="${1:event/name}"',
314
314
  insertTextFormat: 'snippet',
315
315
  ebnf: 'triggerTag ::= "@trigger" ( "event=" STRING | "cron=" STRING )*',
@@ -324,7 +324,7 @@ targetType ::= "string" | "number" | "boolean" | "json" | "object"`,
324
324
  name: '@cancelOn',
325
325
  category: 'workflow',
326
326
  syntax: '@cancelOn event="name" [match="field"] [timeout="duration"]',
327
- description: 'Cancels a running Inngest function when a specified event is received.',
327
+ description: 'Cancels a running workflow execution when a specified event is received.',
328
328
  insertText: '@cancelOn event="${1:event/name}"',
329
329
  insertTextFormat: 'snippet',
330
330
  ebnf: 'cancelOnTag ::= "@cancelOn" "event=" STRING [ "match=" STRING ] [ "timeout=" STRING ]',
@@ -339,7 +339,7 @@ targetType ::= "string" | "number" | "boolean" | "json" | "object"`,
339
339
  name: '@retries',
340
340
  category: 'workflow',
341
341
  syntax: '@retries N',
342
- description: 'Sets the retry count for an Inngest function (overrides default of 3).',
342
+ description: 'Sets the retry count for the deployed function.',
343
343
  insertText: '@retries ${1:3}',
344
344
  insertTextFormat: 'snippet',
345
345
  ebnf: 'retriesTag ::= "@retries" INTEGER',
@@ -350,7 +350,7 @@ targetType ::= "string" | "number" | "boolean" | "json" | "object"`,
350
350
  name: '@timeout',
351
351
  category: 'workflow',
352
352
  syntax: '@timeout "duration"',
353
- description: 'Sets the maximum execution time for an Inngest function.',
353
+ description: 'Sets the maximum execution time for the deployed function.',
354
354
  insertText: '@timeout "${1:30m}"',
355
355
  insertTextFormat: 'snippet',
356
356
  ebnf: 'timeoutTag ::= "@timeout" STRING',
@@ -361,7 +361,7 @@ targetType ::= "string" | "number" | "boolean" | "json" | "object"`,
361
361
  name: '@throttle',
362
362
  category: 'workflow',
363
363
  syntax: '@throttle limit=N [period="duration"]',
364
- description: 'Limits concurrent executions of an Inngest function.',
364
+ description: 'Limits concurrent executions of the deployed function.',
365
365
  insertText: '@throttle limit=${1:10}',
366
366
  insertTextFormat: 'snippet',
367
367
  ebnf: 'throttleTag ::= "@throttle" "limit=" INTEGER [ "period=" STRING ]',
@@ -206,7 +206,7 @@ export const CLI_COMMANDS = [
206
206
  syntax: 'flow-weaver export <file> -t <target> -o <path> [options]',
207
207
  description: 'Export workflow as serverless function',
208
208
  options: [
209
- { flags: '-t, --target', arg: 'lambda|vercel|cloudflare', description: 'Target platform', required: true },
209
+ { flags: '-t, --target', arg: '<target>', description: 'Target platform (provided by installed packs)', required: true },
210
210
  { flags: '-o, --output', arg: '<path>', description: 'Output directory', required: true },
211
211
  { flags: '-w, --workflow', arg: '<name>', description: 'Specific workflow to export' },
212
212
  { flags: '-p, --production', description: 'Production mode', defaultValue: 'true' },
@@ -637,9 +637,8 @@ export const MCP_TOOLS = [
637
637
  {
638
638
  name: 'target',
639
639
  type: 'string',
640
- description: 'Target deployment platform',
640
+ description: 'Target deployment platform (provided by installed packs)',
641
641
  required: true,
642
- enum: ['lambda', 'vercel', 'cloudflare'],
643
642
  },
644
643
  {
645
644
  name: 'outputDir',
@@ -33,11 +33,12 @@ export interface SearchResult {
33
33
  relevance: number;
34
34
  }
35
35
  /**
36
- * List all available documentation topics.
36
+ * List all available documentation topics, including pack-contributed ones.
37
37
  */
38
38
  export declare function listTopics(): DocTopic[];
39
39
  /**
40
40
  * Read a single documentation topic.
41
+ * Checks core docs first, then falls back to pack-contributed topics.
41
42
  * @param slug - Topic slug (filename without .md)
42
43
  * @param compact - If true, return a compact LLM-friendly version
43
44
  */
@@ -51,4 +52,30 @@ export declare function readTopicStructured(slug: string): DocStructured | null;
51
52
  * Returns matching sections with context.
52
53
  */
53
54
  export declare function searchDocs(query: string): SearchResult[];
55
+ /** Registered pack doc topics. Populated by registerPackDocTopics(). */
56
+ declare const packDocTopics: Array<{
57
+ slug: string;
58
+ name: string;
59
+ description: string;
60
+ keywords: string[];
61
+ presets: string[];
62
+ filePath: string;
63
+ }>;
64
+ /**
65
+ * Register doc topics from installed pack manifests.
66
+ * These appear alongside core topics in listTopics() and readTopic().
67
+ */
68
+ export declare function registerPackDocTopics(topics: Array<{
69
+ slug: string;
70
+ name: string;
71
+ description?: string;
72
+ keywords?: string[];
73
+ presets?: string[];
74
+ absoluteFile: string;
75
+ }>): void;
76
+ /**
77
+ * List pack-contributed doc topics. Used internally by listTopics() and readTopic().
78
+ */
79
+ export declare function getPackDocTopics(): typeof packDocTopics;
80
+ export {};
54
81
  //# sourceMappingURL=index.d.ts.map
@@ -86,44 +86,77 @@ function splitSections(body) {
86
86
  // Public API
87
87
  // ---------------------------------------------------------------------------
88
88
  /**
89
- * List all available documentation topics.
89
+ * List all available documentation topics, including pack-contributed ones.
90
90
  */
91
91
  export function listTopics() {
92
92
  const docsDir = getDocsDir();
93
- if (!fs.existsSync(docsDir))
94
- return [];
95
- const files = fs.readdirSync(docsDir).filter((f) => f.endsWith('.md')).sort();
96
- return files.map((file) => {
97
- const raw = fs.readFileSync(path.join(docsDir, file), 'utf-8');
98
- const { frontmatter } = parseFrontmatter(raw);
99
- return {
100
- slug: file.replace(/\.md$/, ''),
101
- name: frontmatter.name,
102
- description: frontmatter.description,
103
- keywords: frontmatter.keywords,
104
- };
105
- });
93
+ const coreTopics = [];
94
+ if (fs.existsSync(docsDir)) {
95
+ const files = fs.readdirSync(docsDir).filter((f) => f.endsWith('.md')).sort();
96
+ for (const file of files) {
97
+ const raw = fs.readFileSync(path.join(docsDir, file), 'utf-8');
98
+ const { frontmatter } = parseFrontmatter(raw);
99
+ coreTopics.push({
100
+ slug: file.replace(/\.md$/, ''),
101
+ name: frontmatter.name,
102
+ description: frontmatter.description,
103
+ keywords: frontmatter.keywords,
104
+ });
105
+ }
106
+ }
107
+ // Append pack-contributed topics (no slug collisions with core)
108
+ const coreSlugs = new Set(coreTopics.map((t) => t.slug));
109
+ for (const packTopic of packDocTopics) {
110
+ if (!coreSlugs.has(packTopic.slug)) {
111
+ coreTopics.push({
112
+ slug: packTopic.slug,
113
+ name: packTopic.name,
114
+ description: packTopic.description,
115
+ keywords: packTopic.keywords,
116
+ });
117
+ }
118
+ }
119
+ return coreTopics;
106
120
  }
107
121
  /**
108
122
  * Read a single documentation topic.
123
+ * Checks core docs first, then falls back to pack-contributed topics.
109
124
  * @param slug - Topic slug (filename without .md)
110
125
  * @param compact - If true, return a compact LLM-friendly version
111
126
  */
112
127
  export function readTopic(slug, compact) {
128
+ // Try core docs first
113
129
  const docsDir = getDocsDir();
114
- const filePath = path.join(docsDir, `${slug}.md`);
115
- if (!fs.existsSync(filePath))
116
- return null;
117
- const raw = fs.readFileSync(filePath, 'utf-8');
118
- const { frontmatter, body } = parseFrontmatter(raw);
119
- const content = compact ? buildCompactContent(frontmatter, body) : body.trim();
120
- return {
121
- slug,
122
- name: frontmatter.name,
123
- description: frontmatter.description,
124
- keywords: frontmatter.keywords,
125
- content,
126
- };
130
+ const coreFilePath = path.join(docsDir, `${slug}.md`);
131
+ if (fs.existsSync(coreFilePath)) {
132
+ const raw = fs.readFileSync(coreFilePath, 'utf-8');
133
+ const { frontmatter, body } = parseFrontmatter(raw);
134
+ const content = compact ? buildCompactContent(frontmatter, body) : body.trim();
135
+ return {
136
+ slug,
137
+ name: frontmatter.name,
138
+ description: frontmatter.description,
139
+ keywords: frontmatter.keywords,
140
+ content,
141
+ };
142
+ }
143
+ // Check pack-contributed topics
144
+ const packTopic = packDocTopics.find((t) => t.slug === slug);
145
+ if (packTopic && fs.existsSync(packTopic.filePath)) {
146
+ const raw = fs.readFileSync(packTopic.filePath, 'utf-8');
147
+ const { frontmatter, body } = parseFrontmatter(raw);
148
+ const content = compact
149
+ ? buildCompactContent({ name: frontmatter.name || packTopic.name, description: frontmatter.description || packTopic.description, keywords: frontmatter.keywords.length > 0 ? frontmatter.keywords : packTopic.keywords }, body)
150
+ : body.trim();
151
+ return {
152
+ slug,
153
+ name: frontmatter.name || packTopic.name,
154
+ description: frontmatter.description || packTopic.description,
155
+ keywords: frontmatter.keywords.length > 0 ? frontmatter.keywords : packTopic.keywords,
156
+ content,
157
+ };
158
+ }
159
+ return null;
127
160
  }
128
161
  /**
129
162
  * Read a topic and return structured sections (for JSON output).
@@ -157,7 +190,11 @@ export function searchDocs(query) {
157
190
  for (const topic of topics) {
158
191
  // Check keywords match
159
192
  const keywordMatch = topic.keywords.some((kw) => queryTerms.some((term) => kw.toLowerCase().includes(term)));
160
- const filePath = path.join(docsDir, `${topic.slug}.md`);
193
+ // Resolve the file path: core topics live in docsDir, pack topics have their own path
194
+ const packTopic = packDocTopics.find((p) => p.slug === topic.slug);
195
+ const filePath = packTopic ? packTopic.filePath : path.join(docsDir, `${topic.slug}.md`);
196
+ if (!fs.existsSync(filePath))
197
+ continue;
161
198
  const raw = fs.readFileSync(filePath, 'utf-8');
162
199
  const { body } = parseFrontmatter(raw);
163
200
  const sections = splitSections(body);
@@ -207,6 +244,36 @@ export function searchDocs(query) {
207
244
  return results;
208
245
  }
209
246
  // ---------------------------------------------------------------------------
247
+ // Pack-contributed doc topics
248
+ // ---------------------------------------------------------------------------
249
+ /** Registered pack doc topics. Populated by registerPackDocTopics(). */
250
+ const packDocTopics = [];
251
+ /**
252
+ * Register doc topics from installed pack manifests.
253
+ * These appear alongside core topics in listTopics() and readTopic().
254
+ */
255
+ export function registerPackDocTopics(topics) {
256
+ for (const t of topics) {
257
+ // Avoid duplicates (same slug)
258
+ if (packDocTopics.some((p) => p.slug === t.slug))
259
+ continue;
260
+ packDocTopics.push({
261
+ slug: t.slug,
262
+ name: t.name,
263
+ description: t.description ?? '',
264
+ keywords: t.keywords ?? [],
265
+ presets: t.presets ?? [],
266
+ filePath: t.absoluteFile,
267
+ });
268
+ }
269
+ }
270
+ /**
271
+ * List pack-contributed doc topics. Used internally by listTopics() and readTopic().
272
+ */
273
+ export function getPackDocTopics() {
274
+ return packDocTopics;
275
+ }
276
+ // ---------------------------------------------------------------------------
210
277
  // Compact mode builder
211
278
  // ---------------------------------------------------------------------------
212
279
  function buildCompactContent(frontmatter, body) {
@@ -6,8 +6,7 @@
6
6
  * Export target identifier.
7
7
  *
8
8
  * Widened to `string` so marketplace packs can register arbitrary targets
9
- * without modifying core. Well-known built-in names (when packs are installed):
10
- * 'lambda', 'vercel', 'cloudflare', 'inngest', 'github-actions', 'gitlab-ci'
9
+ * without modifying core.
11
10
  */
12
11
  export type ExportTarget = string;
13
12
  /**
@@ -34,7 +33,7 @@ export interface ExportOptions {
34
33
  workflows?: string[];
35
34
  /** Include API documentation routes */
36
35
  includeDocs?: boolean;
37
- /** Use deep generator with per-node Inngest steps for durability (inngest target only) */
36
+ /** Use deep generator with per-node durable steps (target-specific) */
38
37
  durableSteps?: boolean;
39
38
  }
40
39
  /**