@synergenius/flow-weaver 0.30.9 → 0.31.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.
@@ -14,6 +14,8 @@ import { generateWorkflowFromTemplate } from './templates.js';
14
14
  import { getNodes, getConnections, getTopologicalOrder, findIsolatedNodes, findDeadEnds, countNodes, countConnections, } from './query.js';
15
15
  import { WorkflowDiffer } from '../diff/WorkflowDiffer.js';
16
16
  import { formatDiff } from '../diff/formatDiff.js';
17
+ import { searchPackages, listInstalledPackages } from '../marketplace/registry.js';
18
+ import { applyMigrations, getRegisteredMigrations } from '../migration/registry.js';
17
19
  function resolveFile(args, cwd) {
18
20
  const file = String(args.file);
19
21
  return cwd ? path.resolve(cwd, file) : path.resolve(file);
@@ -203,6 +205,213 @@ const handlers = {
203
205
  });
204
206
  return { data: result };
205
207
  },
208
+ // ─── status ─────────────────────────────────────────────────────
209
+ status: async (args) => {
210
+ const filePath = resolveFile(args, args.cwd);
211
+ const parseResult = await parseWorkflow(filePath, {
212
+ workflowName: args.workflow,
213
+ });
214
+ if (parseResult.errors.length > 0) {
215
+ return { data: { valid: false, errors: parseResult.errors } };
216
+ }
217
+ const ast = parseResult.ast;
218
+ const nodeTypes = ast.nodeTypes ?? [];
219
+ const stubs = nodeTypes.filter((nt) => nt.variant === 'STUB').map((nt) => nt.name);
220
+ const implemented = nodeTypes.filter((nt) => nt.variant !== 'STUB').map((nt) => nt.name);
221
+ return {
222
+ data: {
223
+ total: nodeTypes.length,
224
+ implemented,
225
+ stubs,
226
+ progress: nodeTypes.length > 0
227
+ ? Math.round((implemented.length / nodeTypes.length) * 100)
228
+ : 100,
229
+ },
230
+ };
231
+ },
232
+ // ─── market-search ──────────────────────────────────────────────
233
+ 'market-search': async (args) => {
234
+ const query = String(args.query ?? '');
235
+ const results = await searchPackages({ query });
236
+ return { data: { results, query } };
237
+ },
238
+ // ─── market-list ────────────────────────────────────────────────
239
+ 'market-list': async (args) => {
240
+ const cwd = args.cwd || process.cwd();
241
+ const packages = await listInstalledPackages(cwd);
242
+ return {
243
+ data: {
244
+ packages: packages.map((p) => ({
245
+ name: p.name,
246
+ version: p.version,
247
+ nodeTypes: p.manifest.nodeTypes?.length ?? 0,
248
+ workflows: p.manifest.workflows?.length ?? 0,
249
+ cliCommands: p.manifest.cliCommands?.length ?? 0,
250
+ })),
251
+ },
252
+ };
253
+ },
254
+ // ─── migrate ────────────────────────────────────────────────────
255
+ migrate: async (args) => {
256
+ const filePath = resolveFile(args, args.cwd);
257
+ const dryRun = Boolean(args.dryRun);
258
+ const source = fs.readFileSync(filePath, 'utf-8');
259
+ const parseResult = await parseWorkflow(filePath);
260
+ if (parseResult.errors.length > 0) {
261
+ return { data: { migrated: false, errors: parseResult.errors } };
262
+ }
263
+ const migrated = applyMigrations(parseResult.ast);
264
+ const genResult = generateInPlace(source, migrated);
265
+ const newSource = genResult.code;
266
+ const changed = newSource !== source;
267
+ if (changed && !dryRun) {
268
+ fs.writeFileSync(filePath, newSource);
269
+ }
270
+ return {
271
+ data: {
272
+ migrated: true,
273
+ changed,
274
+ dryRun,
275
+ file: filePath,
276
+ availableMigrations: getRegisteredMigrations().map((m) => m.name),
277
+ },
278
+ };
279
+ },
280
+ // ─── openapi ────────────────────────────────────────────────────
281
+ openapi: async (args) => {
282
+ const directory = path.resolve(String(args.directory));
283
+ const { generateOpenAPIJson, generateOpenAPIYaml } = await import('../deployment/openapi/generator.js');
284
+ const format = args.format || 'json';
285
+ // Scan directory for .ts files and parse each for workflows
286
+ const files = fs.readdirSync(directory).filter((f) => f.endsWith('.ts'));
287
+ const endpoints = [];
288
+ for (const file of files) {
289
+ const filePath = path.join(directory, file);
290
+ try {
291
+ const parsed = await parseWorkflow(filePath);
292
+ if (parsed.errors.length === 0) {
293
+ endpoints.push({
294
+ name: parsed.ast.name,
295
+ functionName: parsed.ast.name,
296
+ filePath,
297
+ method: 'POST',
298
+ path: `/${parsed.ast.name}`,
299
+ });
300
+ }
301
+ }
302
+ catch {
303
+ // Skip unparseable files
304
+ }
305
+ }
306
+ const genOptions = {
307
+ title: args.title || 'Flow Weaver API',
308
+ version: args.version || '1.0.0',
309
+ };
310
+ const spec = format === 'yaml'
311
+ ? generateOpenAPIYaml(endpoints, genOptions)
312
+ : generateOpenAPIJson(endpoints, genOptions);
313
+ return { data: { spec, format, workflowCount: endpoints.length } };
314
+ },
315
+ // ─── login ──────────────────────────────────────────────────────
316
+ login: async (args) => {
317
+ try {
318
+ const { saveCredentials, loadCredentials, getPlatformUrl } = await import('../cli/config/credentials.js');
319
+ const apiKey = args.apiKey;
320
+ if (apiKey) {
321
+ saveCredentials({
322
+ token: apiKey,
323
+ email: '',
324
+ plan: 'free',
325
+ platformUrl: getPlatformUrl(),
326
+ expiresAt: Date.now() + 365 * 24 * 60 * 60 * 1000,
327
+ });
328
+ return { data: { authenticated: true, method: 'apiKey' } };
329
+ }
330
+ const existing = loadCredentials();
331
+ if (existing) {
332
+ return { data: { authenticated: true, method: 'existing' } };
333
+ }
334
+ return { data: { authenticated: false, message: 'Provide an apiKey parameter or run fw login in the terminal for browser auth.' } };
335
+ }
336
+ catch {
337
+ return { data: { authenticated: false, message: 'Auth module not available' } };
338
+ }
339
+ },
340
+ // ─── account ────────────────────────────────────────────────────
341
+ account: async () => {
342
+ try {
343
+ const { loadCredentials, isLoggedIn } = await import('../cli/config/credentials.js');
344
+ if (!isLoggedIn()) {
345
+ return { data: { authenticated: false, message: 'Not logged in. Use fw login first.' } };
346
+ }
347
+ const creds = loadCredentials();
348
+ const { PlatformClient } = await import('../cli/config/platform-client.js');
349
+ const client = new PlatformClient(creds);
350
+ const user = await client.getUser();
351
+ const usage = await client.getDetailedUsage();
352
+ return { data: { authenticated: true, user, usage } };
353
+ }
354
+ catch (err) {
355
+ return { data: { authenticated: false, message: err instanceof Error ? err.message : String(err) } };
356
+ }
357
+ },
358
+ // ─── deploy ─────────────────────────────────────────────────────
359
+ deploy: async (args) => {
360
+ try {
361
+ const { loadCredentials, isLoggedIn } = await import('../cli/config/credentials.js');
362
+ if (!isLoggedIn()) {
363
+ return { data: { authenticated: false, message: 'Not logged in. Use fw login first.' } };
364
+ }
365
+ const filePath = resolveFile(args, args.cwd);
366
+ const source = fs.readFileSync(filePath, 'utf-8');
367
+ const name = args.name || path.basename(filePath, '.ts');
368
+ const creds = loadCredentials();
369
+ const { PlatformClient } = await import('../cli/config/platform-client.js');
370
+ const client = new PlatformClient(creds);
371
+ const pushed = await client.pushWorkflow(name, source);
372
+ const deployed = await client.deploy(pushed.slug);
373
+ return { data: { authenticated: true, slug: deployed.slug, status: deployed.status } };
374
+ }
375
+ catch (err) {
376
+ return { data: { authenticated: false, message: err instanceof Error ? err.message : String(err) } };
377
+ }
378
+ },
379
+ // ─── undeploy ───────────────────────────────────────────────────
380
+ undeploy: async (args) => {
381
+ try {
382
+ const { loadCredentials, isLoggedIn } = await import('../cli/config/credentials.js');
383
+ if (!isLoggedIn()) {
384
+ return { data: { authenticated: false, message: 'Not logged in. Use fw login first.' } };
385
+ }
386
+ const slug = String(args.slug);
387
+ const creds = loadCredentials();
388
+ const { PlatformClient } = await import('../cli/config/platform-client.js');
389
+ const client = new PlatformClient(creds);
390
+ await client.undeploy(slug);
391
+ return { data: { authenticated: true, slug, removed: true } };
392
+ }
393
+ catch (err) {
394
+ return { data: { authenticated: false, message: err instanceof Error ? err.message : String(err) } };
395
+ }
396
+ },
397
+ // ─── cloud-status ───────────────────────────────────────────────
398
+ 'cloud-status': async () => {
399
+ try {
400
+ const { loadCredentials, isLoggedIn } = await import('../cli/config/credentials.js');
401
+ if (!isLoggedIn()) {
402
+ return { data: { authenticated: false, message: 'Not logged in. Use fw login first.' } };
403
+ }
404
+ const creds = loadCredentials();
405
+ const { PlatformClient } = await import('../cli/config/platform-client.js');
406
+ const client = new PlatformClient(creds);
407
+ const deployments = await client.listDeployments();
408
+ const usage = await client.getUsage();
409
+ return { data: { authenticated: true, deployments, usage } };
410
+ }
411
+ catch (err) {
412
+ return { data: { authenticated: false, message: err instanceof Error ? err.message : String(err) } };
413
+ }
414
+ },
206
415
  };
207
416
  export async function runCommand(name, args) {
208
417
  const handler = handlers[name];
@@ -5987,7 +5987,7 @@ var VERSION;
5987
5987
  var init_generated_version = __esm({
5988
5988
  "src/generated-version.ts"() {
5989
5989
  "use strict";
5990
- VERSION = "0.30.9";
5990
+ VERSION = "0.31.0";
5991
5991
  }
5992
5992
  });
5993
5993
 
@@ -43495,6 +43495,21 @@ var init_formatDiff = __esm({
43495
43495
  }
43496
43496
  });
43497
43497
 
43498
+ // src/migration/registry.ts
43499
+ function applyMigrations(ast) {
43500
+ return migrations.reduce((current2, migration) => migration.apply(current2), ast);
43501
+ }
43502
+ function getRegisteredMigrations() {
43503
+ return migrations.map((m) => ({ name: m.name }));
43504
+ }
43505
+ var migrations;
43506
+ var init_registry2 = __esm({
43507
+ "src/migration/registry.ts"() {
43508
+ "use strict";
43509
+ migrations = [];
43510
+ }
43511
+ });
43512
+
43498
43513
  // src/api/command-runner.ts
43499
43514
  var init_command_runner = __esm({
43500
43515
  "src/api/command-runner.ts"() {
@@ -43508,6 +43523,8 @@ var init_command_runner = __esm({
43508
43523
  init_query();
43509
43524
  init_WorkflowDiffer();
43510
43525
  init_formatDiff();
43526
+ init_registry();
43527
+ init_registry2();
43511
43528
  }
43512
43529
  });
43513
43530
 
@@ -79237,21 +79254,6 @@ var init_tools_template = __esm({
79237
79254
  }
79238
79255
  });
79239
79256
 
79240
- // src/migration/registry.ts
79241
- function applyMigrations(ast) {
79242
- return migrations.reduce((current2, migration) => migration.apply(current2), ast);
79243
- }
79244
- function getRegisteredMigrations() {
79245
- return migrations.map((m) => ({ name: m.name }));
79246
- }
79247
- var migrations;
79248
- var init_registry2 = __esm({
79249
- "src/migration/registry.ts"() {
79250
- "use strict";
79251
- migrations = [];
79252
- }
79253
- });
79254
-
79255
79257
  // src/mcp/tools-pattern.ts
79256
79258
  import * as path24 from "path";
79257
79259
  import * as fs23 from "fs";
@@ -88935,7 +88937,7 @@ function parseIntStrict(value) {
88935
88937
  // src/cli/index.ts
88936
88938
  init_logger();
88937
88939
  init_error_utils();
88938
- var version2 = true ? "0.30.9" : "0.0.0-dev";
88940
+ var version2 = true ? "0.31.0" : "0.0.0-dev";
88939
88941
  var program2 = new Command();
88940
88942
  program2.name("fw").description("Flow Weaver Annotations - Compile and validate workflow files").option("-v, --version", "Output the current version").option("--no-color", "Disable colors").option("--color", "Force colors").on("option:version", () => {
88941
88943
  logger.banner(version2);
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.30.9";
1
+ export declare const VERSION = "0.31.0";
2
2
  //# sourceMappingURL=generated-version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by scripts/generate-version.ts — do not edit manually
2
- export const VERSION = '0.30.9';
2
+ export const VERSION = '0.31.0';
3
3
  //# sourceMappingURL=generated-version.js.map
@@ -151,6 +151,7 @@ function inferNodeTypeFromDtsFunction(fn, packageName) {
151
151
  const dataProps = isObjectLike
152
152
  ? properties.filter(p => p.getName() !== 'onSuccess' && p.getName() !== 'onFailure')
153
153
  : [];
154
+ let dataOutputOrder = 2; // after onSuccess(0) and onFailure(1)
154
155
  if (isObjectLike && dataProps.length <= 8) {
155
156
  for (const prop of dataProps) {
156
157
  const propName = prop.getName();
@@ -161,6 +162,7 @@ function inferNodeTypeFromDtsFunction(fn, packageName) {
161
162
  reference: propName,
162
163
  type: inferDataTypeFromTS(propType.getText()),
163
164
  direction: 'OUTPUT',
165
+ defaultOrder: dataOutputOrder++,
164
166
  });
165
167
  }
166
168
  }
@@ -173,17 +175,18 @@ function inferNodeTypeFromDtsFunction(fn, packageName) {
173
175
  reference: 'result',
174
176
  type: dataType,
175
177
  direction: 'OUTPUT',
178
+ defaultOrder: dataOutputOrder++,
176
179
  });
177
180
  }
178
181
  }
179
- // Add mandatory control flow output ports
182
+ // Add mandatory control flow output ports (before data outputs)
180
183
  ports.push({
181
184
  name: 'onSuccess',
182
185
  defaultLabel: 'On Success',
183
186
  reference: 'onSuccess',
184
187
  type: 'STEP',
185
188
  direction: 'OUTPUT',
186
- defaultOrder: 100,
189
+ defaultOrder: 0,
187
190
  });
188
191
  ports.push({
189
192
  name: 'onFailure',
@@ -191,7 +194,7 @@ function inferNodeTypeFromDtsFunction(fn, packageName) {
191
194
  reference: 'onFailure',
192
195
  type: 'STEP',
193
196
  direction: 'OUTPUT',
194
- defaultOrder: 101,
197
+ defaultOrder: 1,
195
198
  failure: true,
196
199
  });
197
200
  return {
@@ -331,7 +334,16 @@ export function getPackageExports(packageName, workdir, nodeModulesOverride) {
331
334
  if (typeArgs.length > 0)
332
335
  returnType = typeArgs[0];
333
336
  }
334
- let outputOrder = 0;
337
+ // Step output ports first (control flow), then data outputs
338
+ ports.push({
339
+ name: 'onSuccess', defaultLabel: 'On Success', reference: 'onSuccess',
340
+ type: 'STEP', direction: 'OUTPUT', defaultOrder: 0,
341
+ });
342
+ ports.push({
343
+ name: 'onFailure', defaultLabel: 'On Failure', reference: 'onFailure',
344
+ type: 'STEP', direction: 'OUTPUT', defaultOrder: 1, failure: true,
345
+ });
346
+ let outputOrder = 2;
335
347
  const unwrapped = returnType.getText();
336
348
  if (unwrapped !== 'void' && unwrapped !== 'undefined' && unwrapped !== 'never') {
337
349
  const isPrimitive = PRIMITIVE_TYPES.has(unwrapped);
@@ -359,14 +371,6 @@ export function getPackageExports(packageName, workdir, nodeModulesOverride) {
359
371
  });
360
372
  }
361
373
  }
362
- ports.push({
363
- name: 'onSuccess', defaultLabel: 'On Success', reference: 'onSuccess',
364
- type: 'STEP', direction: 'OUTPUT', defaultOrder: 100,
365
- });
366
- ports.push({
367
- name: 'onFailure', defaultLabel: 'On Failure', reference: 'onFailure',
368
- type: 'STEP', direction: 'OUTPUT', defaultOrder: 101, failure: true,
369
- });
370
374
  nodeTypes.push({
371
375
  name: exportName,
372
376
  variant: 'FUNCTION',
@@ -421,12 +425,12 @@ export function getPackageExports(packageName, workdir, nodeModulesOverride) {
421
425
  if (typeArgs.length > 0)
422
426
  returnType = typeArgs[0];
423
427
  }
428
+ ports.push({ name: 'onSuccess', defaultLabel: 'On Success', reference: 'onSuccess', type: 'STEP', direction: 'OUTPUT', defaultOrder: 0 });
429
+ ports.push({ name: 'onFailure', defaultLabel: 'On Failure', reference: 'onFailure', type: 'STEP', direction: 'OUTPUT', defaultOrder: 1, failure: true });
424
430
  const unwrapped = returnType.getText();
425
431
  if (unwrapped !== 'void' && unwrapped !== 'undefined' && unwrapped !== 'never') {
426
- ports.push({ name: 'result', defaultLabel: 'Result', reference: 'result', type: inferDataTypeFromTS(unwrapped), direction: 'OUTPUT', defaultOrder: 0 });
432
+ ports.push({ name: 'result', defaultLabel: 'Result', reference: 'result', type: inferDataTypeFromTS(unwrapped), direction: 'OUTPUT', defaultOrder: 2 });
427
433
  }
428
- ports.push({ name: 'onSuccess', defaultLabel: 'On Success', reference: 'onSuccess', type: 'STEP', direction: 'OUTPUT', defaultOrder: 100 });
429
- ports.push({ name: 'onFailure', defaultLabel: 'On Failure', reference: 'onFailure', type: 'STEP', direction: 'OUTPUT', defaultOrder: 101, failure: true });
430
434
  nodeTypes.push({
431
435
  name: exportName,
432
436
  variant: 'FUNCTION',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synergenius/flow-weaver",
3
- "version": "0.30.9",
3
+ "version": "0.31.0",
4
4
  "description": "Flow Weaver: deterministic TypeScript workflow compiler. Define workflows with JSDoc annotations, compile to standalone functions with zero runtime dependencies.",
5
5
  "private": false,
6
6
  "type": "module",