@synergenius/flow-weaver 0.17.1 → 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.
- package/dist/api/index.d.ts +4 -1
- package/dist/api/index.js +4 -1
- package/dist/api/templates.js +2 -2
- package/dist/api/validate.d.ts +2 -2
- package/dist/api/validate.js +6 -6
- package/dist/api/validation-registry.d.ts +10 -0
- package/dist/api/validation-registry.js +10 -0
- package/dist/ast/types.d.ts +91 -4
- package/dist/built-in-nodes/invoke-workflow.d.ts +1 -1
- package/dist/built-in-nodes/invoke-workflow.js +1 -1
- package/dist/chevrotain-parser/connect-parser.js +25 -7
- package/dist/cli/commands/compile.d.ts +5 -9
- package/dist/cli/commands/compile.js +21 -14
- package/dist/cli/commands/dev.d.ts +2 -13
- package/dist/cli/commands/dev.js +10 -204
- package/dist/cli/commands/doctor.js +6 -3
- package/dist/cli/commands/export.d.ts +8 -17
- package/dist/cli/commands/export.js +8 -17
- package/dist/cli/commands/init-personas.d.ts +12 -3
- package/dist/cli/commands/init-personas.js +27 -4
- package/dist/cli/commands/init.d.ts +2 -2
- package/dist/cli/commands/init.js +5 -11
- package/dist/cli/flow-weaver.mjs +61463 -60910
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +9 -7
- package/dist/cli/templates/index.d.ts +20 -1
- package/dist/cli/templates/index.js +66 -15
- package/dist/cli/templates/nodes/human-approval.js +2 -3
- package/dist/cli/templates/nodes/rag-retriever.js +1 -1
- package/dist/constants.d.ts +7 -0
- package/dist/constants.js +13 -3
- package/dist/context/index.js +13 -3
- package/dist/deployment/config/loader.js +2 -1
- package/dist/deployment/core/adapters.d.ts +1 -25
- package/dist/deployment/core/adapters.js +0 -95
- package/dist/deployment/core/formatters.d.ts +0 -15
- package/dist/deployment/core/formatters.js +0 -24
- package/dist/deployment/index.d.ts +7 -5
- package/dist/deployment/index.js +8 -5
- package/dist/deployment/types.d.ts +2 -45
- package/dist/diagram/html-viewer.js +65 -32
- package/dist/diagram/renderer.js +9 -6
- package/dist/diagram/theme.js +4 -0
- package/dist/diagram/types.d.ts +2 -0
- package/dist/doc-metadata/extractors/annotations.js +5 -5
- package/dist/doc-metadata/extractors/cli-commands.js +1 -1
- package/dist/doc-metadata/extractors/mcp-tools.js +1 -2
- package/dist/docs/index.d.ts +28 -1
- package/dist/docs/index.js +95 -28
- package/dist/export/index.d.ts +2 -3
- package/dist/{deployment/targets/cicd-base.d.ts → extensions/cicd/base-target.d.ts} +35 -36
- package/dist/{deployment/targets/cicd-base.js → extensions/cicd/base-target.js} +97 -57
- package/dist/{validation/cicd-detection.d.ts → extensions/cicd/detection.d.ts} +2 -2
- package/dist/{validation/cicd-detection.js → extensions/cicd/detection.js} +13 -1
- package/dist/extensions/cicd/docs/cicd.md +395 -0
- package/dist/extensions/cicd/index.d.ts +10 -0
- package/dist/extensions/cicd/index.js +10 -0
- package/dist/extensions/cicd/register.d.ts +11 -0
- package/dist/extensions/cicd/register.js +62 -0
- package/dist/extensions/cicd/rules.d.ts +30 -0
- package/dist/{validation/cicd-rules.js → extensions/cicd/rules.js} +60 -56
- package/dist/extensions/cicd/tag-handler.d.ts +14 -0
- package/dist/extensions/cicd/tag-handler.js +488 -0
- package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-docker.d.ts +1 -1
- package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-matrix.d.ts +1 -1
- package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-multi-env.d.ts +1 -1
- package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-test-deploy.d.ts +1 -1
- package/dist/extensions/index.d.ts +12 -0
- package/dist/extensions/index.js +12 -0
- package/dist/extensions/inngest/dev-mode.d.ts +9 -0
- package/dist/extensions/inngest/dev-mode.js +213 -0
- package/dist/{generator/inngest.d.ts → extensions/inngest/generator.d.ts} +2 -2
- package/dist/{generator/inngest.js → extensions/inngest/generator.js} +4 -4
- package/dist/extensions/inngest/index.d.ts +2 -0
- package/dist/extensions/inngest/index.js +2 -0
- package/dist/extensions/inngest/register.d.ts +6 -0
- package/dist/extensions/inngest/register.js +23 -0
- package/dist/extensions/inngest/templates/ai-agent-durable.d.ts +8 -0
- package/dist/{cli/templates/workflows → extensions/inngest/templates}/ai-agent-durable.js +8 -8
- package/dist/{cli/templates/workflows → extensions/inngest/templates}/ai-pipeline-durable.d.ts +2 -2
- package/dist/{cli/templates/workflows → extensions/inngest/templates}/ai-pipeline-durable.js +7 -7
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/dist/generator/compile-target-registry.d.ts +20 -0
- package/dist/generator/compile-target-registry.js +20 -0
- package/dist/generator/dev-mode-registry.d.ts +27 -0
- package/dist/generator/dev-mode-registry.js +20 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/jsdoc-parser.d.ts +12 -114
- package/dist/jsdoc-parser.js +57 -362
- package/dist/marketplace/index.d.ts +2 -2
- package/dist/marketplace/index.js +1 -1
- package/dist/marketplace/registry.d.ts +39 -1
- package/dist/marketplace/registry.js +77 -0
- package/dist/marketplace/types.d.ts +76 -3
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/tools-export.js +3 -3
- package/dist/mcp/tools-query.js +17 -11
- package/dist/mcp/tools-template.js +1 -1
- package/dist/parser/tag-registry.d.ts +47 -0
- package/dist/parser/tag-registry.js +57 -0
- package/dist/parser.d.ts +3 -0
- package/dist/parser.js +10 -23
- package/dist/validation/rule-registry.d.ts +36 -0
- package/dist/validation/rule-registry.js +37 -0
- package/dist/validator.js +3 -3
- package/docs/reference/concepts.md +2 -1
- package/docs/reference/deployment.md +21 -0
- package/docs/reference/jsdoc-grammar.md +242 -1
- package/docs/reference/scaffold.md +0 -6
- package/package.json +9 -1
- package/dist/cli/templates/workflows/ai-agent-durable.d.ts +0 -8
- package/dist/export/templates.d.ts +0 -24
- package/dist/export/templates.js +0 -186
- package/dist/validation/cicd-rules.d.ts +0 -62
- /package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-docker.js +0 -0
- /package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-matrix.js +0 -0
- /package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-multi-env.js +0 -0
- /package/dist/{cli/templates/workflows → extensions/cicd/templates}/cicd-test-deploy.js +0 -0
|
@@ -97,4 +97,81 @@ export function getInstalledPackageManifest(projectDir, packageName) {
|
|
|
97
97
|
return null;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Discover all tag handlers from installed pack manifests.
|
|
102
|
+
*/
|
|
103
|
+
export async function discoverTagHandlers(projectDir) {
|
|
104
|
+
const packages = await listInstalledPackages(projectDir);
|
|
105
|
+
const handlers = [];
|
|
106
|
+
for (const pkg of packages) {
|
|
107
|
+
const manifest = pkg.manifest;
|
|
108
|
+
if (!manifest.tagHandlers)
|
|
109
|
+
continue;
|
|
110
|
+
for (const handler of manifest.tagHandlers) {
|
|
111
|
+
handlers.push({
|
|
112
|
+
...handler,
|
|
113
|
+
absoluteFile: path.join(pkg.path, handler.file),
|
|
114
|
+
packageName: pkg.name,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return handlers;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Discover all validation rule sets from installed pack manifests.
|
|
122
|
+
*/
|
|
123
|
+
export async function discoverValidationRuleSets(projectDir) {
|
|
124
|
+
const packages = await listInstalledPackages(projectDir);
|
|
125
|
+
const ruleSets = [];
|
|
126
|
+
for (const pkg of packages) {
|
|
127
|
+
const manifest = pkg.manifest;
|
|
128
|
+
if (!manifest.validationRuleSets)
|
|
129
|
+
continue;
|
|
130
|
+
for (const ruleSet of manifest.validationRuleSets) {
|
|
131
|
+
ruleSets.push({
|
|
132
|
+
...ruleSet,
|
|
133
|
+
absoluteFile: path.join(pkg.path, ruleSet.file),
|
|
134
|
+
packageName: pkg.name,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return ruleSets;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Discover all doc topics from installed pack manifests.
|
|
142
|
+
*/
|
|
143
|
+
export async function discoverDocTopics(projectDir) {
|
|
144
|
+
const packages = await listInstalledPackages(projectDir);
|
|
145
|
+
const topics = [];
|
|
146
|
+
for (const pkg of packages) {
|
|
147
|
+
const manifest = pkg.manifest;
|
|
148
|
+
if (!manifest.docs)
|
|
149
|
+
continue;
|
|
150
|
+
for (const doc of manifest.docs) {
|
|
151
|
+
topics.push({
|
|
152
|
+
...doc,
|
|
153
|
+
absoluteFile: path.join(pkg.path, doc.file),
|
|
154
|
+
packageName: pkg.name,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return topics;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Discover all init contributions from installed pack manifests.
|
|
162
|
+
*/
|
|
163
|
+
export async function discoverInitContributions(projectDir) {
|
|
164
|
+
const packages = await listInstalledPackages(projectDir);
|
|
165
|
+
const contributions = [];
|
|
166
|
+
for (const pkg of packages) {
|
|
167
|
+
const manifest = pkg.manifest;
|
|
168
|
+
if (!manifest.initContributions)
|
|
169
|
+
continue;
|
|
170
|
+
contributions.push({
|
|
171
|
+
...manifest.initContributions,
|
|
172
|
+
packageName: pkg.name,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
return contributions;
|
|
176
|
+
}
|
|
100
177
|
//# sourceMappingURL=registry.js.map
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
import type { TDataType } from '../ast/types.js';
|
|
9
9
|
/** Auto-generated manifest describing a marketplace package's contents. */
|
|
10
10
|
export type TMarketplaceManifest = {
|
|
11
|
-
/** Manifest schema version
|
|
12
|
-
manifestVersion: 1;
|
|
11
|
+
/** Manifest schema version */
|
|
12
|
+
manifestVersion: 1 | 2;
|
|
13
13
|
/** npm package name */
|
|
14
14
|
name: string;
|
|
15
15
|
/** Semver version */
|
|
@@ -28,6 +28,14 @@ export type TMarketplaceManifest = {
|
|
|
28
28
|
patterns: TManifestPattern[];
|
|
29
29
|
/** Export targets provided by this package */
|
|
30
30
|
exportTargets?: TManifestExportTarget[];
|
|
31
|
+
/** Tag handlers contributed by this pack (v2) */
|
|
32
|
+
tagHandlers?: TManifestTagHandler[];
|
|
33
|
+
/** Validation rule sets contributed by this pack (v2) */
|
|
34
|
+
validationRuleSets?: TManifestValidationRuleSet[];
|
|
35
|
+
/** Documentation topics contributed by this pack (v2) */
|
|
36
|
+
docs?: TManifestDocTopic[];
|
|
37
|
+
/** Init contributions: use cases and templates (v2) */
|
|
38
|
+
initContributions?: TManifestInitContribution;
|
|
31
39
|
/** External dependency information */
|
|
32
40
|
dependencies?: {
|
|
33
41
|
/** Flow Weaver peer dependency constraints */
|
|
@@ -38,7 +46,7 @@ export type TMarketplaceManifest = {
|
|
|
38
46
|
};
|
|
39
47
|
/** An export target provided by a marketplace package. */
|
|
40
48
|
export type TManifestExportTarget = {
|
|
41
|
-
/** Target identifier
|
|
49
|
+
/** Target identifier */
|
|
42
50
|
name: string;
|
|
43
51
|
/** Human-readable description */
|
|
44
52
|
description?: string;
|
|
@@ -152,6 +160,71 @@ export type TInstalledPackage = {
|
|
|
152
160
|
/** Absolute path to the package in node_modules */
|
|
153
161
|
path: string;
|
|
154
162
|
};
|
|
163
|
+
/**
|
|
164
|
+
* A tag handler contributed by a pack. Declares which JSDoc tags the pack handles,
|
|
165
|
+
* the deploy namespace to store results in, and the JS file exporting the handler.
|
|
166
|
+
*/
|
|
167
|
+
export type TManifestTagHandler = {
|
|
168
|
+
/** Tag name(s) this handler processes (e.g., "secret", "runner") */
|
|
169
|
+
tags: string[];
|
|
170
|
+
/** Deploy namespace for storing parsed data (e.g., "cicd") */
|
|
171
|
+
namespace: string;
|
|
172
|
+
/** Applicable scope: workflow-level tags, nodeType-level tags, or both */
|
|
173
|
+
scope: 'workflow' | 'nodeType' | 'both';
|
|
174
|
+
/** Relative path to the compiled JS file exporting the handler function */
|
|
175
|
+
file: string;
|
|
176
|
+
/** Named export from the file (default: "default") */
|
|
177
|
+
exportName?: string;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* A validation rule set contributed by a pack. Declares a detect function
|
|
181
|
+
* and rules export for conditional validation.
|
|
182
|
+
*/
|
|
183
|
+
export type TManifestValidationRuleSet = {
|
|
184
|
+
/** Human-readable name for this rule set */
|
|
185
|
+
name: string;
|
|
186
|
+
/** Deploy namespace this rule set applies to (e.g., "cicd") */
|
|
187
|
+
namespace: string;
|
|
188
|
+
/** Relative path to the compiled JS file exporting detect and getRules */
|
|
189
|
+
file: string;
|
|
190
|
+
/** Named export for the detect function (default: "detect") */
|
|
191
|
+
detectExport?: string;
|
|
192
|
+
/** Named export for the getRules function (default: "getRules") */
|
|
193
|
+
rulesExport?: string;
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* A documentation topic contributed by a pack.
|
|
197
|
+
*/
|
|
198
|
+
export type TManifestDocTopic = {
|
|
199
|
+
/** Topic slug (used in fw_docs read) */
|
|
200
|
+
slug: string;
|
|
201
|
+
/** Human-readable topic name */
|
|
202
|
+
name: string;
|
|
203
|
+
/** Topic description */
|
|
204
|
+
description?: string;
|
|
205
|
+
/** Search keywords */
|
|
206
|
+
keywords?: string[];
|
|
207
|
+
/** Context presets this topic should be included in */
|
|
208
|
+
presets?: string[];
|
|
209
|
+
/** Relative path to the markdown file */
|
|
210
|
+
file: string;
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Init contributions from a pack: use case entries and template IDs.
|
|
214
|
+
*/
|
|
215
|
+
export type TManifestInitContribution = {
|
|
216
|
+
/** Use case entry for fw init prompts */
|
|
217
|
+
useCase?: {
|
|
218
|
+
/** Use case ID (must be unique across all packs) */
|
|
219
|
+
id: string;
|
|
220
|
+
/** Display name */
|
|
221
|
+
name: string;
|
|
222
|
+
/** Brief description */
|
|
223
|
+
description: string;
|
|
224
|
+
};
|
|
225
|
+
/** Template IDs this pack provides (must match IDs in the template registry) */
|
|
226
|
+
templates?: string[];
|
|
227
|
+
};
|
|
155
228
|
export type TMarketInitConfig = {
|
|
156
229
|
/** Package name (e.g., flowweaver-pack-openai) */
|
|
157
230
|
name: string;
|
package/dist/mcp/server.d.ts
CHANGED
package/dist/mcp/server.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Load built-in extensions (CI/CD, etc.) before tool registration
|
|
2
|
+
import '../extensions/index.js';
|
|
1
3
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
4
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
5
|
import { DEFAULT_SERVER_URL } from '../defaults.js';
|
package/dist/mcp/tools-export.js
CHANGED
|
@@ -11,11 +11,11 @@ import { parseWorkflow } from '../api/index.js';
|
|
|
11
11
|
import { createTargetRegistry } from '../deployment/index.js';
|
|
12
12
|
import { makeToolResult, makeErrorResult } from './response-utils.js';
|
|
13
13
|
export function registerExportTools(mcp) {
|
|
14
|
-
mcp.tool('fw_export', 'Export workflows as serverless deployments. Generates
|
|
14
|
+
mcp.tool('fw_export', 'Export workflows as serverless deployments. Generates platform-native config files and deploy instructions. Available targets depend on installed packs.', {
|
|
15
15
|
filePath: z.string().describe('Path to the workflow .ts file'),
|
|
16
16
|
target: z
|
|
17
17
|
.string()
|
|
18
|
-
.describe('Deployment target platform
|
|
18
|
+
.describe('Deployment target platform. Run with --list-targets to see installed targets.'),
|
|
19
19
|
outputDir: z.string().describe('Output directory for generated files'),
|
|
20
20
|
serviceName: z
|
|
21
21
|
.string()
|
|
@@ -40,7 +40,7 @@ export function registerExportTools(mcp) {
|
|
|
40
40
|
durableSteps: z
|
|
41
41
|
.boolean()
|
|
42
42
|
.optional()
|
|
43
|
-
.describe('Use deep generator with per-node
|
|
43
|
+
.describe('Use deep generator with per-node durable steps'),
|
|
44
44
|
}, async (args) => {
|
|
45
45
|
try {
|
|
46
46
|
const filePath = path.resolve(args.filePath);
|
package/dist/mcp/tools-query.js
CHANGED
|
@@ -8,7 +8,7 @@ import { WorkflowDiffer } from '../diff/WorkflowDiffer.js';
|
|
|
8
8
|
import { formatDiff } from '../diff/formatDiff.js';
|
|
9
9
|
import { makeToolResult, makeErrorResult, addHintsToItems } from './response-utils.js';
|
|
10
10
|
import { getFriendlyError } from '../friendly-errors.js';
|
|
11
|
-
import {
|
|
11
|
+
import { compileTargetRegistry } from '../generator/compile-target-registry.js';
|
|
12
12
|
import { AnnotationParser } from '../parser.js';
|
|
13
13
|
/** Detect MULTIPLE_WORKFLOWS_FOUND marker in parse errors and return the right error code */
|
|
14
14
|
function parseErrorCode(errors) {
|
|
@@ -130,7 +130,7 @@ export function registerQueryTools(mcp) {
|
|
|
130
130
|
});
|
|
131
131
|
mcp.tool('fw_compile', 'Compile a workflow to executable code. Only regenerates code inside @flow-weaver-runtime ' +
|
|
132
132
|
'and @flow-weaver-body marker sections — user code outside markers is preserved. ' +
|
|
133
|
-
'Set production: true to strip debug instrumentation.
|
|
133
|
+
'Set production: true to strip debug instrumentation. Custom targets are available via registered extensions.', {
|
|
134
134
|
filePath: z.string().describe('Path to the workflow file'),
|
|
135
135
|
write: z.boolean().optional().describe('Whether to write the output file (default: true)'),
|
|
136
136
|
production: z
|
|
@@ -139,9 +139,9 @@ export function registerQueryTools(mcp) {
|
|
|
139
139
|
.describe('Production mode — no debug events (default: false)'),
|
|
140
140
|
workflowName: z.string().optional().describe('Specific workflow name'),
|
|
141
141
|
target: z
|
|
142
|
-
.
|
|
142
|
+
.string()
|
|
143
143
|
.optional()
|
|
144
|
-
.describe('Compilation target: typescript (default) or
|
|
144
|
+
.describe('Compilation target: typescript (default) or a registered extension target'),
|
|
145
145
|
cron: z.string().optional().describe('Cron schedule expression (e.g. "0 9 * * *"). Overrides @trigger annotation.'),
|
|
146
146
|
serve: z.boolean().optional().describe('Generate serve() handler for HTTP framework integration'),
|
|
147
147
|
framework: z.enum(['next', 'express', 'hono', 'fastify', 'remix']).optional().describe('Framework adapter for serve handler (requires serve=true)'),
|
|
@@ -151,10 +151,16 @@ export function registerQueryTools(mcp) {
|
|
|
151
151
|
}, async (args) => {
|
|
152
152
|
try {
|
|
153
153
|
const filePath = path.resolve(args.filePath);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
const customTarget = args.target && args.target !== 'typescript'
|
|
155
|
+
? compileTargetRegistry.get(args.target)
|
|
156
|
+
: undefined;
|
|
157
|
+
if (args.target && args.target !== 'typescript') {
|
|
158
|
+
if (!customTarget) {
|
|
159
|
+
const available = compileTargetRegistry.getNames();
|
|
160
|
+
return makeErrorResult('COMPILE_ERROR', `Unknown compile target: ${args.target}. Available: typescript${available.length ? ', ' + available.join(', ') : ''}`);
|
|
161
|
+
}
|
|
162
|
+
const annotationParser = new AnnotationParser();
|
|
163
|
+
const parseResult = annotationParser.parse(filePath);
|
|
158
164
|
if (parseResult.errors.length > 0) {
|
|
159
165
|
return makeErrorResult('PARSE_ERROR', `Parse errors:\n${parseResult.errors.join('\n')}`);
|
|
160
166
|
}
|
|
@@ -182,19 +188,19 @@ export function registerQueryTools(mcp) {
|
|
|
182
188
|
workflow.options = workflow.options || {};
|
|
183
189
|
workflow.options.timeout = args.timeout;
|
|
184
190
|
}
|
|
185
|
-
const code =
|
|
191
|
+
const code = customTarget.compile(workflow, allNodeTypes, {
|
|
186
192
|
production: args.production ?? false,
|
|
187
193
|
typedEvents: args.typedEvents,
|
|
188
194
|
serveHandler: args.serve,
|
|
189
195
|
framework: args.framework,
|
|
190
196
|
});
|
|
191
|
-
const outputFile = filePath.replace(/\.ts$/,
|
|
197
|
+
const outputFile = filePath.replace(/\.ts$/, `.${args.target}.ts`);
|
|
192
198
|
if (args.write !== false) {
|
|
193
199
|
const fs = await import('fs');
|
|
194
200
|
fs.writeFileSync(outputFile, code, 'utf8');
|
|
195
201
|
}
|
|
196
202
|
return makeToolResult({
|
|
197
|
-
target:
|
|
203
|
+
target: args.target,
|
|
198
204
|
outputFile,
|
|
199
205
|
workflowName: workflow.name,
|
|
200
206
|
code: args.write === false ? code : undefined,
|
|
@@ -38,7 +38,7 @@ export function registerTemplateTools(mcp) {
|
|
|
38
38
|
return makeToolResult(result);
|
|
39
39
|
});
|
|
40
40
|
mcp.tool('fw_scaffold', 'Create a workflow or node from a template.', {
|
|
41
|
-
template: z.string().describe('Template name (e.g. "sequential", "validator")'),
|
|
41
|
+
template: z.string().describe('Template name (e.g. "sequential", "validator", "ai-agent")'),
|
|
42
42
|
filePath: z.string().describe('Output file path'),
|
|
43
43
|
name: z.string().optional().describe('Workflow/node function name'),
|
|
44
44
|
preview: z
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TagHandlerRegistry: dispatch table for pack-contributed JSDoc tag handlers.
|
|
3
|
+
*
|
|
4
|
+
* Packs declare tag handlers in their manifest. The parser populates this
|
|
5
|
+
* registry at startup and delegates unknown tags to it before emitting
|
|
6
|
+
* "unknown tag" warnings.
|
|
7
|
+
*/
|
|
8
|
+
export type TTagHandlerContext = {
|
|
9
|
+
/** The deploy map for this handler's namespace. Handlers mutate this directly. */
|
|
10
|
+
deploy: Record<string, unknown>;
|
|
11
|
+
/** Accumulator for parser warnings. */
|
|
12
|
+
warnings: string[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* A handler function for a pack-contributed tag.
|
|
16
|
+
* Receives the tag name, the comment text after the tag, and a context
|
|
17
|
+
* object with the deploy map for the handler's namespace.
|
|
18
|
+
*/
|
|
19
|
+
export type TTagHandlerFn = (tagName: string, comment: string, ctx: TTagHandlerContext) => void;
|
|
20
|
+
export type TRegisteredTagHandler = {
|
|
21
|
+
namespace: string;
|
|
22
|
+
scope: 'workflow' | 'nodeType' | 'both';
|
|
23
|
+
handler: TTagHandlerFn;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Registry mapping tag names to pack-provided handler functions.
|
|
27
|
+
* Used by the JSDoc parser to delegate tags it doesn't natively handle.
|
|
28
|
+
*/
|
|
29
|
+
export declare class TagHandlerRegistry {
|
|
30
|
+
private handlers;
|
|
31
|
+
/** Register a handler for one or more tag names. */
|
|
32
|
+
register(tags: string[], namespace: string, scope: 'workflow' | 'nodeType' | 'both', handler: TTagHandlerFn): void;
|
|
33
|
+
/** Check if a handler is registered for the given tag. */
|
|
34
|
+
has(tagName: string): boolean;
|
|
35
|
+
/** Get all registered tag names. */
|
|
36
|
+
getRegisteredTags(): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Handle a tag by delegating to the registered handler.
|
|
39
|
+
* The handler writes parsed data into `deployMap[namespace]`.
|
|
40
|
+
*
|
|
41
|
+
* @returns true if the tag was handled, false if no handler was found.
|
|
42
|
+
*/
|
|
43
|
+
handle(tagName: string, comment: string, blockScope: 'workflow' | 'nodeType', deployMap: Record<string, Record<string, unknown>>, warnings: string[]): boolean;
|
|
44
|
+
}
|
|
45
|
+
/** Global tag handler registry singleton. Extensions register handlers here at startup. */
|
|
46
|
+
export declare const tagHandlerRegistry: TagHandlerRegistry;
|
|
47
|
+
//# sourceMappingURL=tag-registry.d.ts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TagHandlerRegistry: dispatch table for pack-contributed JSDoc tag handlers.
|
|
3
|
+
*
|
|
4
|
+
* Packs declare tag handlers in their manifest. The parser populates this
|
|
5
|
+
* registry at startup and delegates unknown tags to it before emitting
|
|
6
|
+
* "unknown tag" warnings.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Registry mapping tag names to pack-provided handler functions.
|
|
10
|
+
* Used by the JSDoc parser to delegate tags it doesn't natively handle.
|
|
11
|
+
*/
|
|
12
|
+
export class TagHandlerRegistry {
|
|
13
|
+
handlers = new Map();
|
|
14
|
+
/** Register a handler for one or more tag names. */
|
|
15
|
+
register(tags, namespace, scope, handler) {
|
|
16
|
+
const entry = { namespace, scope, handler };
|
|
17
|
+
for (const tag of tags) {
|
|
18
|
+
this.handlers.set(tag, entry);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Check if a handler is registered for the given tag. */
|
|
22
|
+
has(tagName) {
|
|
23
|
+
return this.handlers.has(tagName);
|
|
24
|
+
}
|
|
25
|
+
/** Get all registered tag names. */
|
|
26
|
+
getRegisteredTags() {
|
|
27
|
+
return [...this.handlers.keys()];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Handle a tag by delegating to the registered handler.
|
|
31
|
+
* The handler writes parsed data into `deployMap[namespace]`.
|
|
32
|
+
*
|
|
33
|
+
* @returns true if the tag was handled, false if no handler was found.
|
|
34
|
+
*/
|
|
35
|
+
handle(tagName, comment, blockScope, deployMap, warnings) {
|
|
36
|
+
const entry = this.handlers.get(tagName);
|
|
37
|
+
if (!entry)
|
|
38
|
+
return false;
|
|
39
|
+
// Check scope compatibility
|
|
40
|
+
if (entry.scope !== 'both' && entry.scope !== blockScope) {
|
|
41
|
+
warnings.push(`@${tagName} is registered for ${entry.scope} blocks, not ${blockScope} blocks.`);
|
|
42
|
+
return true; // consumed, but with a warning
|
|
43
|
+
}
|
|
44
|
+
// Ensure the namespace slot exists
|
|
45
|
+
if (!deployMap[entry.namespace]) {
|
|
46
|
+
deployMap[entry.namespace] = {};
|
|
47
|
+
}
|
|
48
|
+
entry.handler(tagName, comment, {
|
|
49
|
+
deploy: deployMap[entry.namespace],
|
|
50
|
+
warnings,
|
|
51
|
+
});
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Global tag handler registry singleton. Extensions register handlers here at startup. */
|
|
56
|
+
export const tagHandlerRegistry = new TagHandlerRegistry();
|
|
57
|
+
//# sourceMappingURL=tag-registry.js.map
|
package/dist/parser.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Project } from 'ts-morph';
|
|
2
2
|
import type { TNodeTypeAST, TWorkflowAST, TPatternAST } from './ast/types.js';
|
|
3
|
+
import { type TagHandlerRegistry } from './parser/tag-registry.js';
|
|
3
4
|
export interface ParseResult {
|
|
4
5
|
workflows: TWorkflowAST[];
|
|
5
6
|
nodeTypes: TNodeTypeAST[];
|
|
@@ -29,6 +30,8 @@ export declare class AnnotationParser {
|
|
|
29
30
|
private importCache;
|
|
30
31
|
private importStack;
|
|
31
32
|
private parseCache;
|
|
33
|
+
/** Tag handler registry. Defaults to the global singleton (pre-populated by extensions). */
|
|
34
|
+
tagRegistry: TagHandlerRegistry;
|
|
32
35
|
constructor();
|
|
33
36
|
private computeHash;
|
|
34
37
|
private detectMinorEdit;
|
package/dist/parser.js
CHANGED
|
@@ -14,6 +14,7 @@ import { getPackageExports } from './npm-packages.js';
|
|
|
14
14
|
import { getSharedProject } from './shared-project.js';
|
|
15
15
|
import { LRUCache } from './utils/lru-cache.js';
|
|
16
16
|
import { COERCION_NODE_TYPES, COERCE_TYPE_MAP } from './built-in-nodes/coercion-types.js';
|
|
17
|
+
import { tagHandlerRegistry } from './parser/tag-registry.js';
|
|
17
18
|
/**
|
|
18
19
|
* Convert a TExternalNodeType to a TNodeTypeAST with sensible defaults.
|
|
19
20
|
* Used to merge runtime-loaded node types into the parser's available types.
|
|
@@ -73,6 +74,8 @@ export class AnnotationParser {
|
|
|
73
74
|
importCache = new LRUCache(200);
|
|
74
75
|
importStack = new Set();
|
|
75
76
|
parseCache = new LRUCache(100);
|
|
77
|
+
/** Tag handler registry. Defaults to the global singleton (pre-populated by extensions). */
|
|
78
|
+
tagRegistry = tagHandlerRegistry;
|
|
76
79
|
constructor() {
|
|
77
80
|
this.project = getSharedProject();
|
|
78
81
|
}
|
|
@@ -591,7 +594,7 @@ export class AnnotationParser {
|
|
|
591
594
|
const nodeTypes = [];
|
|
592
595
|
extractFunctionLikes(sourceFile).forEach((fn) => {
|
|
593
596
|
// Parse JSDoc comments
|
|
594
|
-
const config = jsdocParser.parseNodeType(fn, warnings);
|
|
597
|
+
const config = jsdocParser.parseNodeType(fn, warnings, this.tagRegistry);
|
|
595
598
|
if (!config) {
|
|
596
599
|
const jsdocText = fn.getJsDocs().map((d) => d.getFullText()).join('');
|
|
597
600
|
if (jsdocText.includes('@flowWeaver nodeType')) {
|
|
@@ -765,7 +768,7 @@ export class AnnotationParser {
|
|
|
765
768
|
extractWorkflowSignatures(sourceFile, filePath, warnings) {
|
|
766
769
|
const workflows = [];
|
|
767
770
|
extractFunctionLikes(sourceFile).forEach((fn) => {
|
|
768
|
-
const config = jsdocParser.parseWorkflow(fn, warnings);
|
|
771
|
+
const config = jsdocParser.parseWorkflow(fn, warnings, this.tagRegistry);
|
|
769
772
|
if (!config)
|
|
770
773
|
return;
|
|
771
774
|
const functionName = fn.getName() || 'anonymous';
|
|
@@ -823,7 +826,7 @@ export class AnnotationParser {
|
|
|
823
826
|
.filter((name) => !!name);
|
|
824
827
|
allFunctions.forEach((fn) => {
|
|
825
828
|
// Parse JSDoc comments
|
|
826
|
-
const config = jsdocParser.parseWorkflow(fn, warnings);
|
|
829
|
+
const config = jsdocParser.parseWorkflow(fn, warnings, this.tagRegistry);
|
|
827
830
|
if (!config) {
|
|
828
831
|
const jsdocText = fn.getJsDocs().map((d) => d.getFullText()).join('');
|
|
829
832
|
if (jsdocText.includes('@flowWeaver workflow')) {
|
|
@@ -990,11 +993,7 @@ export class AnnotationParser {
|
|
|
990
993
|
...(Object.keys(ui).length > 0 && { ui }),
|
|
991
994
|
...((config.strictTypes !== undefined || config.autoConnect ||
|
|
992
995
|
config.trigger || config.cancelOn || config.retries !== undefined ||
|
|
993
|
-
config.timeout || config.throttle ||
|
|
994
|
-
config.secrets || config.runner || config.caches || config.artifacts ||
|
|
995
|
-
config.environments || config.matrix || config.services ||
|
|
996
|
-
config.concurrency || config.cicdTriggers ||
|
|
997
|
-
config.deploy) && {
|
|
996
|
+
config.timeout || config.throttle || config.deploy) && {
|
|
998
997
|
options: {
|
|
999
998
|
...(config.strictTypes !== undefined && { strictTypes: config.strictTypes }),
|
|
1000
999
|
...(config.autoConnect && { autoConnect: true }),
|
|
@@ -1003,21 +1002,9 @@ export class AnnotationParser {
|
|
|
1003
1002
|
...(config.retries !== undefined && { retries: config.retries }),
|
|
1004
1003
|
...(config.timeout && { timeout: config.timeout }),
|
|
1005
1004
|
...(config.throttle && { throttle: config.throttle }),
|
|
1006
|
-
// CI/CD
|
|
1007
|
-
...(
|
|
1008
|
-
|
|
1009
|
-
config.concurrency || config.cicdTriggers) && {
|
|
1010
|
-
cicd: {
|
|
1011
|
-
...(config.secrets && { secrets: config.secrets }),
|
|
1012
|
-
...(config.runner && { runner: config.runner }),
|
|
1013
|
-
...(config.caches && { caches: config.caches }),
|
|
1014
|
-
...(config.artifacts && { artifacts: config.artifacts }),
|
|
1015
|
-
...(config.environments && { environments: config.environments }),
|
|
1016
|
-
...(config.matrix && { matrix: config.matrix }),
|
|
1017
|
-
...(config.services && { services: config.services }),
|
|
1018
|
-
...(config.concurrency && { concurrency: config.concurrency }),
|
|
1019
|
-
...(config.cicdTriggers && { triggers: config.cicdTriggers }),
|
|
1020
|
-
},
|
|
1005
|
+
// CI/CD data comes from deploy['cicd'] (populated by extension tag handler)
|
|
1006
|
+
...(config.deploy?.['cicd'] && {
|
|
1007
|
+
cicd: config.deploy['cicd'],
|
|
1021
1008
|
}),
|
|
1022
1009
|
// Per-target deployment config
|
|
1023
1010
|
...(config.deploy && { deploy: config.deploy }),
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ValidationRuleRegistry: dynamic dispatch for pack-contributed validation rules.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the hardcoded `isCICDWorkflow() ? getCICDValidationRules() : []`
|
|
5
|
+
* pattern. Each registered rule set has a detect predicate and a lazy rule loader.
|
|
6
|
+
* The validate API calls `getApplicableRules(ast)` and merges results.
|
|
7
|
+
*/
|
|
8
|
+
import type { TValidationRule, TWorkflowAST } from '../ast/types.js';
|
|
9
|
+
export type TValidationRuleSet = {
|
|
10
|
+
/** Human-readable name for this rule set */
|
|
11
|
+
name: string;
|
|
12
|
+
/** Deploy namespace this rule set applies to */
|
|
13
|
+
namespace: string;
|
|
14
|
+
/** Predicate: should these rules run for this workflow? */
|
|
15
|
+
detect: (ast: TWorkflowAST) => boolean;
|
|
16
|
+
/** Lazy loader for the actual rules. Called only when detect returns true. */
|
|
17
|
+
getRules: () => TValidationRule[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Registry for dynamically contributed validation rule sets.
|
|
21
|
+
* Core rule sets (like CI/CD) register themselves at startup.
|
|
22
|
+
* Pack-contributed rule sets are loaded from manifests.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ValidationRuleRegistry {
|
|
25
|
+
private ruleSets;
|
|
26
|
+
/** Register a validation rule set. */
|
|
27
|
+
register(ruleSet: TValidationRuleSet): void;
|
|
28
|
+
/**
|
|
29
|
+
* Get all validation rules applicable to the given workflow AST.
|
|
30
|
+
* Runs each registered detect predicate and collects rules from matching sets.
|
|
31
|
+
*/
|
|
32
|
+
getApplicableRules(ast: TWorkflowAST): TValidationRule[];
|
|
33
|
+
/** Get the number of registered rule sets. */
|
|
34
|
+
get size(): number;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=rule-registry.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ValidationRuleRegistry: dynamic dispatch for pack-contributed validation rules.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the hardcoded `isCICDWorkflow() ? getCICDValidationRules() : []`
|
|
5
|
+
* pattern. Each registered rule set has a detect predicate and a lazy rule loader.
|
|
6
|
+
* The validate API calls `getApplicableRules(ast)` and merges results.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Registry for dynamically contributed validation rule sets.
|
|
10
|
+
* Core rule sets (like CI/CD) register themselves at startup.
|
|
11
|
+
* Pack-contributed rule sets are loaded from manifests.
|
|
12
|
+
*/
|
|
13
|
+
export class ValidationRuleRegistry {
|
|
14
|
+
ruleSets = [];
|
|
15
|
+
/** Register a validation rule set. */
|
|
16
|
+
register(ruleSet) {
|
|
17
|
+
this.ruleSets.push(ruleSet);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get all validation rules applicable to the given workflow AST.
|
|
21
|
+
* Runs each registered detect predicate and collects rules from matching sets.
|
|
22
|
+
*/
|
|
23
|
+
getApplicableRules(ast) {
|
|
24
|
+
const rules = [];
|
|
25
|
+
for (const ruleSet of this.ruleSets) {
|
|
26
|
+
if (ruleSet.detect(ast)) {
|
|
27
|
+
rules.push(...ruleSet.getRules());
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return rules;
|
|
31
|
+
}
|
|
32
|
+
/** Get the number of registered rule sets. */
|
|
33
|
+
get size() {
|
|
34
|
+
return this.ruleSets.length;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=rule-registry.js.map
|
package/dist/validator.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RESERVED_NODE_NAMES, isStartNode, isExitNode, isExecutePort, isReservedNodeName, VALID_NODE_COLORS, EXECUTION_STRATEGIES, } from './constants.js';
|
|
1
|
+
import { RESERVED_NODE_NAMES, isStartNode, isExitNode, isPseudoNode, isExecutePort, isReservedNodeName, VALID_NODE_COLORS, EXECUTION_STRATEGIES, } from './constants.js';
|
|
2
2
|
import { findClosestMatches } from './utils/string-distance.js';
|
|
3
3
|
import { parseFunctionSignature } from './jsdoc-port-sync/signature-parser.js';
|
|
4
4
|
import { checkTypeCompatibilityFromStrings } from './type-checker.js';
|
|
@@ -316,7 +316,7 @@ export class WorkflowValidator {
|
|
|
316
316
|
const fromNode = conn.from.node;
|
|
317
317
|
const fromPort = conn.from.port;
|
|
318
318
|
const connLocation = this.getConnectionLocation(conn);
|
|
319
|
-
if (!isStartNode(fromNode) && !instanceMap.has(fromNode)) {
|
|
319
|
+
if (!isStartNode(fromNode) && !isPseudoNode(fromNode) && !instanceMap.has(fromNode)) {
|
|
320
320
|
const instanceIds = [...instanceMap.keys()];
|
|
321
321
|
const suggestions = findClosestMatches(fromNode, instanceIds);
|
|
322
322
|
const suggestion = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
|
|
@@ -627,7 +627,7 @@ export class WorkflowValidator {
|
|
|
627
627
|
workflow.connections.forEach((conn) => {
|
|
628
628
|
const fromNode = conn.from.node;
|
|
629
629
|
const toNode = conn.to.node;
|
|
630
|
-
if (!isStartNode(fromNode) && !isExitNode(fromNode)) {
|
|
630
|
+
if (!isStartNode(fromNode) && !isExitNode(fromNode) && !isPseudoNode(fromNode)) {
|
|
631
631
|
referencedNodes.add(fromNode);
|
|
632
632
|
}
|
|
633
633
|
if (!isStartNode(toNode) && !isExitNode(toNode)) {
|
|
@@ -78,6 +78,7 @@ That is it. Two expression-mode functions, one workflow annotation, zero boilerp
|
|
|
78
78
|
| Pull execution, merge strategies | `advanced-annotations` | jsdoc-grammar |
|
|
79
79
|
| Compile to Inngest | `compilation` | cli-reference |
|
|
80
80
|
| Deploy to cloud | `deployment` | compilation |
|
|
81
|
+
| Build a CI/CD pipeline | `cicd` | deployment, scaffold |
|
|
81
82
|
| Use delay/waitForEvent/mocks | `built-in-nodes` | debugging |
|
|
82
83
|
| Publish marketplace packages | `marketplace` | — |
|
|
83
84
|
|
|
@@ -98,7 +99,7 @@ flow-weaver watch <file> # Watch mode
|
|
|
98
99
|
flow-weaver dev <file> # Watch + compile + run in one command
|
|
99
100
|
flow-weaver serve [dir] # HTTP server exposing workflows as endpoints
|
|
100
101
|
flow-weaver diagram <file> # Generate SVG diagram
|
|
101
|
-
flow-weaver export <file> # Export as serverless function
|
|
102
|
+
flow-weaver export <file> # Export as serverless function or CI/CD pipeline
|
|
102
103
|
flow-weaver docs # Browse documentation
|
|
103
104
|
flow-weaver docs <topic> # Read a specific topic
|
|
104
105
|
flow-weaver docs search <q> # Search across all docs
|