@synergenius/flow-weaver 0.30.0 → 0.30.1

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/README.md CHANGED
@@ -18,15 +18,27 @@ Flow Weaver is a TypeScript workflow compiler. Define workflows with JSDoc annot
18
18
 
19
19
  Build AI agent workflows, data pipelines, or automation scripts through natural language using MCP tools in Claude Code, Cursor, Windsurf, VS Code, JetBrains, Codex, or any MCP-compatible editor. Or write them by hand with annotations the same way you write JSDoc today.
20
20
 
21
- ## Project Status
21
+ ## About me & my vision
22
+
23
+ Hey, I am [Ricardo Morais](https://linkedin.com/in/moraispgsi), the project's founder and owner.
24
+
25
+ I have always wondered why Visual Programming never took off. After understanding why I tried to address most of the concerns from the development community:
26
+ - No lock-in: code is compiled and yours, not dependent on this library. You can remove the annotation after compiling and the file is standalone.
27
+ - The code is the source of truth, visual part runs on top, this allows you to create your workflows visually in the Studio, at the end of the day it is just plain Typescript code that you or any LLM can understand and iterate.
28
+ - It being just code opens a lot of doors for you, like using Git for version control, doing all sort of stuff you already do with code like testing, linting, automating, everything.
29
+ - In the era of LLMs and agents, being able to have that control is crucial, it is not a black box, you can see everything and so can your assistant.
22
30
 
23
- Flow Weaver is in **active alpha**. The compiler, validator, CLI, and MCP tools are stable and thoroughly tested. The test suite covers thousands of cases across parsing, compilation, validation, diffing, and deployment. CI runs on every commit.
31
+ As of now this is a solo project and I am building it in the open. There is a lot to do and rough edges to smooth out. If you run into issues or have questions, the [Discord](https://discord.gg/6Byh3ur2bk) is the best place to reach out. Every issue and question gets a response. I genuinely want to hear from you.
32
+
33
+ If this resonates with what you have been looking for, give it a try and let me know how it goes. Stars, feedback, and honest criticism all help equally.
34
+
35
+ ## Project Status
24
36
 
25
- This started as a curiosity by [Ricardo Morais](https://linkedin.com/in/moraispgsi) into why visual programming never took off and whether code-first and visual editing could actually coexist. It has grown into something real. It is actively maintained, with releases shipping regularly. If you run into issues or have questions, the [Discord](https://discord.gg/6Byh3ur2bk) is the best place to reach out. Every issue and question gets a response, usually within a day.
37
+ Flow Weaver is in **beta**. The compiler, validator, CLI, and MCP tools are stable and thoroughly tested. The test suite covers thousands of cases across parsing, compilation, validation, diffing, and deployment. CI runs on every commit.
26
38
 
27
39
  **Flow Weaver Studio**, the browser-based visual IDE, is the next major milestone and is being actively built. Core editing (canvas, terminal, diagnostics) is live today. The visual debugger, AI chat assistant, version history, and deployment dashboard are in progress. You can follow development on Discord or in the [GitHub releases](https://github.com/synergenius-fw/flow-weaver/releases).
28
40
 
29
- Breaking changes may occur between minor versions during alpha. Pin your version in `package.json` if stability matters for your project.
41
+ Breaking changes may still occur between minor versions during beta. Pin your version in `package.json` if stability matters for your project.
30
42
 
31
43
  ## Capabilities
32
44
 
@@ -224,11 +236,11 @@ export async function supportAgent(
224
236
 
225
237
  Run `fw --help` or `fw <command> --help` for full options.
226
238
 
227
- ## Flow Weaver Studio (Early Beta)
239
+ ## Flow Weaver Studio (Beta)
228
240
 
229
241
  A browser-based visual IDE for building workflows. Canvas editor, integrated terminal, real-time diagnostics, and the full CLI available in the cloud.
230
242
 
231
- Studio is in early beta. Core editing is live. The visual debugger, AI chat assistant, version history, and deployment dashboard are being actively developed and will ship incrementally. The cloud platform is not yet production-ready, and paid plans are not available yet. Use it to explore and experiment, but expect rough edges.
243
+ Studio is in beta. Core editing is live. The visual debugger, AI chat assistant, version history, and deployment dashboard are being actively developed and will ship incrementally. The cloud platform is not yet production-ready, and paid plans are not available yet. Use it to explore and experiment, but expect rough edges.
232
244
 
233
245
  [Open Studio](https://flowweaver.ai/studio) · [Learn more](https://flowweaver.ai/features)
234
246
 
@@ -349,7 +349,7 @@ export async function describeCommand(input, options = {}) {
349
349
  }
350
350
  try {
351
351
  // Parse the workflow
352
- const parseResult = await parseWorkflow(filePath, { workflowName });
352
+ const parseResult = await parseWorkflow(filePath, { workflowName, projectDir: path.dirname(filePath) });
353
353
  if (parseResult.errors.length > 0) {
354
354
  throw new Error(`Parse errors:\n${parseResult.errors.map((err) => ` ${err}`).join('\n')}`);
355
355
  }
@@ -5,6 +5,7 @@
5
5
  import * as fs from 'fs';
6
6
  import * as path from 'path';
7
7
  import { fileToSVG, fileToHTML, fileToASCII } from '../../diagram/index.js';
8
+ import { parser } from '../../parser.js';
8
9
  import { logger } from '../utils/logger.js';
9
10
  import { safeWriteFile } from '../utils/safe-write.js';
10
11
  const ASCII_FORMATS = new Set(['ascii', 'ascii-compact', 'text']);
@@ -14,6 +15,8 @@ export async function diagramCommand(input, options = {}) {
14
15
  if (!fs.existsSync(filePath)) {
15
16
  throw new Error(`File not found: ${filePath}`);
16
17
  }
18
+ // Load marketplace pack tag handlers before parsing
19
+ await parser.loadPackHandlers(path.dirname(filePath));
17
20
  let result;
18
21
  if (ASCII_FORMATS.has(format)) {
19
22
  result = fileToASCII(filePath, { ...diagramOptions, format });
@@ -21,8 +21,8 @@ export async function diffCommand(file1, file2, options = {}) {
21
21
  try {
22
22
  // Parse both workflows
23
23
  const [result1, result2] = await Promise.all([
24
- parseWorkflow(filePath1, { workflowName }),
25
- parseWorkflow(filePath2, { workflowName }),
24
+ parseWorkflow(filePath1, { workflowName, projectDir: path.dirname(filePath1) }),
25
+ parseWorkflow(filePath2, { workflowName, projectDir: path.dirname(filePath2) }),
26
26
  ]);
27
27
  if (result1.errors.length > 0) {
28
28
  throw new Error(`Parse errors in ${file1}:\n${result1.errors.map((err) => ` ${err}`).join('\n')}`);
@@ -184,7 +184,7 @@ async function runCommandInner(input, options) {
184
184
  let executionOrder = resumeExecutionOrder;
185
185
  if (!executionOrder) {
186
186
  const source = fs.readFileSync(filePath, 'utf8');
187
- const parsed = await parseWorkflow(source, { workflowName: options.workflow });
187
+ const parsed = await parseWorkflow(source, { workflowName: options.workflow, projectDir: path.dirname(filePath) });
188
188
  if (parsed.errors.length === 0) {
189
189
  executionOrder = getTopologicalOrder(parsed.ast);
190
190
  }
@@ -427,7 +427,7 @@ export async function validateMockConfig(mocks, filePath, workflowName) {
427
427
  }
428
428
  // Quick-parse the workflow to check which built-in node types are used
429
429
  try {
430
- const result = await parseWorkflow(filePath, { workflowName });
430
+ const result = await parseWorkflow(filePath, { workflowName, projectDir: path.dirname(filePath) });
431
431
  if (result.errors.length > 0 || !result.ast?.instances)
432
432
  return;
433
433
  const usedNodeTypes = new Set(result.ast.instances.map((i) => i.nodeType));
@@ -30,6 +30,17 @@ import { logger } from '../utils/logger.js';
30
30
  * ```
31
31
  */
32
32
  export async function serveCommand(dir, options) {
33
+ // Check fastify is installed before proceeding
34
+ try {
35
+ await import('fastify');
36
+ }
37
+ catch {
38
+ logger.error('The serve command requires fastify. Install it with:');
39
+ logger.newline();
40
+ logger.log(' npm install fastify');
41
+ logger.newline();
42
+ process.exit(1);
43
+ }
33
44
  const workflowDir = path.resolve(dir || '.');
34
45
  // Validate directory exists
35
46
  if (!fs.existsSync(workflowDir)) {
@@ -62,7 +62,7 @@ export async function validateCommand(input, options = {}) {
62
62
  }
63
63
  try {
64
64
  // Parse the workflow
65
- const parseResult = await parseWorkflow(file, { workflowName, projectDir: process.cwd() });
65
+ const parseResult = await parseWorkflow(file, { workflowName, projectDir: path.dirname(path.resolve(file)) });
66
66
  if (parseResult.warnings.length > 0) {
67
67
  if (!json && !quiet) {
68
68
  logger.warn(`Parse warnings in ${fileName}:`);
@@ -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.0";
5990
+ VERSION = "0.30.1";
5991
5991
  }
5992
5992
  });
5993
5993
 
@@ -9844,14 +9844,14 @@ var require_read_wasm = __commonJS({
9844
9844
  var fs49 = __require("fs");
9845
9845
  var path54 = __require("path");
9846
9846
  module.exports = function readWasm() {
9847
- return new Promise((resolve38, reject) => {
9847
+ return new Promise((resolve39, reject) => {
9848
9848
  const wasmPath = path54.join(__dirname, "mappings.wasm");
9849
9849
  fs49.readFile(wasmPath, null, (error2, data) => {
9850
9850
  if (error2) {
9851
9851
  reject(error2);
9852
9852
  return;
9853
9853
  }
9854
- resolve38(data.buffer);
9854
+ resolve39(data.buffer);
9855
9855
  });
9856
9856
  });
9857
9857
  };
@@ -12059,7 +12059,7 @@ is not a problem with esbuild. You need to fix your environment instead.
12059
12059
  let latestResultPromise;
12060
12060
  let provideLatestResult;
12061
12061
  if (isContext)
12062
- requestCallbacks["on-end"] = (id, request2) => new Promise((resolve38) => {
12062
+ requestCallbacks["on-end"] = (id, request2) => new Promise((resolve39) => {
12063
12063
  buildResponseToResult(request2, (err, result, onEndErrors, onEndWarnings) => {
12064
12064
  const response = {
12065
12065
  errors: onEndErrors,
@@ -12069,7 +12069,7 @@ is not a problem with esbuild. You need to fix your environment instead.
12069
12069
  latestResultPromise = void 0;
12070
12070
  provideLatestResult = void 0;
12071
12071
  sendResponse(id, response);
12072
- resolve38();
12072
+ resolve39();
12073
12073
  });
12074
12074
  });
12075
12075
  sendRequest(refs, request, (error2, response) => {
@@ -12086,10 +12086,10 @@ is not a problem with esbuild. You need to fix your environment instead.
12086
12086
  let didDispose = false;
12087
12087
  const result = {
12088
12088
  rebuild: () => {
12089
- if (!latestResultPromise) latestResultPromise = new Promise((resolve38, reject) => {
12089
+ if (!latestResultPromise) latestResultPromise = new Promise((resolve39, reject) => {
12090
12090
  let settlePromise;
12091
12091
  provideLatestResult = (err, result2) => {
12092
- if (!settlePromise) settlePromise = () => err ? reject(err) : resolve38(result2);
12092
+ if (!settlePromise) settlePromise = () => err ? reject(err) : resolve39(result2);
12093
12093
  };
12094
12094
  const triggerAnotherBuild = () => {
12095
12095
  const request2 = {
@@ -12110,7 +12110,7 @@ is not a problem with esbuild. You need to fix your environment instead.
12110
12110
  });
12111
12111
  return latestResultPromise;
12112
12112
  },
12113
- watch: (options2 = {}) => new Promise((resolve38, reject) => {
12113
+ watch: (options2 = {}) => new Promise((resolve39, reject) => {
12114
12114
  if (!streamIn.hasFS) throw new Error(`Cannot use the "watch" API in this environment`);
12115
12115
  const keys = {};
12116
12116
  const delay = getFlag(options2, keys, "delay", mustBeInteger);
@@ -12122,10 +12122,10 @@ is not a problem with esbuild. You need to fix your environment instead.
12122
12122
  if (delay) request2.delay = delay;
12123
12123
  sendRequest(refs, request2, (error22) => {
12124
12124
  if (error22) reject(new Error(error22));
12125
- else resolve38(void 0);
12125
+ else resolve39(void 0);
12126
12126
  });
12127
12127
  }),
12128
- serve: (options2 = {}) => new Promise((resolve38, reject) => {
12128
+ serve: (options2 = {}) => new Promise((resolve39, reject) => {
12129
12129
  if (!streamIn.hasFS) throw new Error(`Cannot use the "serve" API in this environment`);
12130
12130
  const keys = {};
12131
12131
  const port = getFlag(options2, keys, "port", mustBeValidPortNumber);
@@ -12163,28 +12163,28 @@ is not a problem with esbuild. You need to fix your environment instead.
12163
12163
  sendResponse(id, {});
12164
12164
  };
12165
12165
  }
12166
- resolve38(response2);
12166
+ resolve39(response2);
12167
12167
  });
12168
12168
  }),
12169
- cancel: () => new Promise((resolve38) => {
12170
- if (didDispose) return resolve38();
12169
+ cancel: () => new Promise((resolve39) => {
12170
+ if (didDispose) return resolve39();
12171
12171
  const request2 = {
12172
12172
  command: "cancel",
12173
12173
  key: buildKey
12174
12174
  };
12175
12175
  sendRequest(refs, request2, () => {
12176
- resolve38();
12176
+ resolve39();
12177
12177
  });
12178
12178
  }),
12179
- dispose: () => new Promise((resolve38) => {
12180
- if (didDispose) return resolve38();
12179
+ dispose: () => new Promise((resolve39) => {
12180
+ if (didDispose) return resolve39();
12181
12181
  didDispose = true;
12182
12182
  const request2 = {
12183
12183
  command: "dispose",
12184
12184
  key: buildKey
12185
12185
  };
12186
12186
  sendRequest(refs, request2, () => {
12187
- resolve38();
12187
+ resolve39();
12188
12188
  scheduleOnDisposeCallbacks();
12189
12189
  refs.unref();
12190
12190
  });
@@ -12223,7 +12223,7 @@ is not a problem with esbuild. You need to fix your environment instead.
12223
12223
  onLoad: []
12224
12224
  };
12225
12225
  i++;
12226
- let resolve38 = (path310, options = {}) => {
12226
+ let resolve39 = (path310, options = {}) => {
12227
12227
  if (!isSetupDone) throw new Error('Cannot call "resolve" before plugin setup has completed');
12228
12228
  if (typeof path310 !== "string") throw new Error(`The path to resolve must be a string`);
12229
12229
  let keys2 = /* @__PURE__ */ Object.create(null);
@@ -12267,7 +12267,7 @@ is not a problem with esbuild. You need to fix your environment instead.
12267
12267
  };
12268
12268
  let promise = setup({
12269
12269
  initialOptions,
12270
- resolve: resolve38,
12270
+ resolve: resolve39,
12271
12271
  onStart(callback) {
12272
12272
  let registeredText = `This error came from the "onStart" callback registered here:`;
12273
12273
  let registeredNote = extractCallerV8(new Error(registeredText), streamIn, "onStart");
@@ -13145,46 +13145,46 @@ More information: The file containing the code for esbuild's JavaScript API (${_
13145
13145
  }
13146
13146
  };
13147
13147
  longLivedService = {
13148
- build: (options) => new Promise((resolve38, reject) => {
13148
+ build: (options) => new Promise((resolve39, reject) => {
13149
13149
  service.buildOrContext({
13150
13150
  callName: "build",
13151
13151
  refs,
13152
13152
  options,
13153
13153
  isTTY: isTTY2(),
13154
13154
  defaultWD,
13155
- callback: (err, res) => err ? reject(err) : resolve38(res)
13155
+ callback: (err, res) => err ? reject(err) : resolve39(res)
13156
13156
  });
13157
13157
  }),
13158
- context: (options) => new Promise((resolve38, reject) => service.buildOrContext({
13158
+ context: (options) => new Promise((resolve39, reject) => service.buildOrContext({
13159
13159
  callName: "context",
13160
13160
  refs,
13161
13161
  options,
13162
13162
  isTTY: isTTY2(),
13163
13163
  defaultWD,
13164
- callback: (err, res) => err ? reject(err) : resolve38(res)
13164
+ callback: (err, res) => err ? reject(err) : resolve39(res)
13165
13165
  })),
13166
- transform: (input, options) => new Promise((resolve38, reject) => service.transform({
13166
+ transform: (input, options) => new Promise((resolve39, reject) => service.transform({
13167
13167
  callName: "transform",
13168
13168
  refs,
13169
13169
  input,
13170
13170
  options: options || {},
13171
13171
  isTTY: isTTY2(),
13172
13172
  fs: fsAsync,
13173
- callback: (err, res) => err ? reject(err) : resolve38(res)
13173
+ callback: (err, res) => err ? reject(err) : resolve39(res)
13174
13174
  })),
13175
- formatMessages: (messages, options) => new Promise((resolve38, reject) => service.formatMessages({
13175
+ formatMessages: (messages, options) => new Promise((resolve39, reject) => service.formatMessages({
13176
13176
  callName: "formatMessages",
13177
13177
  refs,
13178
13178
  messages,
13179
13179
  options,
13180
- callback: (err, res) => err ? reject(err) : resolve38(res)
13180
+ callback: (err, res) => err ? reject(err) : resolve39(res)
13181
13181
  })),
13182
- analyzeMetafile: (metafile, options) => new Promise((resolve38, reject) => service.analyzeMetafile({
13182
+ analyzeMetafile: (metafile, options) => new Promise((resolve39, reject) => service.analyzeMetafile({
13183
13183
  callName: "analyzeMetafile",
13184
13184
  refs,
13185
13185
  metafile: typeof metafile === "string" ? metafile : JSON.stringify(metafile),
13186
13186
  options,
13187
- callback: (err, res) => err ? reject(err) : resolve38(res)
13187
+ callback: (err, res) => err ? reject(err) : resolve39(res)
13188
13188
  }))
13189
13189
  };
13190
13190
  return longLivedService;
@@ -13262,13 +13262,13 @@ error: ${text}`);
13262
13262
  worker.postMessage(msg);
13263
13263
  let status = Atomics.wait(sharedBufferView, 0, 0);
13264
13264
  if (status !== "ok" && status !== "not-equal") throw new Error("Internal error: Atomics.wait() failed: " + status);
13265
- let { message: { id: id2, resolve: resolve38, reject, properties } } = worker_threads2.receiveMessageOnPort(mainPort);
13265
+ let { message: { id: id2, resolve: resolve39, reject, properties } } = worker_threads2.receiveMessageOnPort(mainPort);
13266
13266
  if (id !== id2) throw new Error(`Internal error: Expected id ${id} but got id ${id2}`);
13267
13267
  if (reject) {
13268
13268
  applyProperties(reject, properties);
13269
13269
  throw reject;
13270
13270
  }
13271
- return resolve38;
13271
+ return resolve39;
13272
13272
  };
13273
13273
  worker.unref();
13274
13274
  return {
@@ -50419,7 +50419,7 @@ async function describeCommand(input, options = {}) {
50419
50419
  throw new Error(`File not found: ${filePath}`);
50420
50420
  }
50421
50421
  try {
50422
- const parseResult = await parseWorkflow(filePath, { workflowName });
50422
+ const parseResult = await parseWorkflow(filePath, { workflowName, projectDir: path12.dirname(filePath) });
50423
50423
  if (parseResult.errors.length > 0) {
50424
50424
  throw new Error(`Parse errors:
50425
50425
  ${parseResult.errors.map((err) => ` ${err}`).join("\n")}`);
@@ -52506,6 +52506,7 @@ async function diagramCommand(input, options = {}) {
52506
52506
  if (!fs14.existsSync(filePath)) {
52507
52507
  throw new Error(`File not found: ${filePath}`);
52508
52508
  }
52509
+ await parser.loadPackHandlers(path13.dirname(filePath));
52509
52510
  let result;
52510
52511
  if (ASCII_FORMATS.has(format)) {
52511
52512
  result = fileToASCII(filePath, { ...diagramOptions, format });
@@ -52527,6 +52528,7 @@ var init_diagram2 = __esm({
52527
52528
  "src/cli/commands/diagram.ts"() {
52528
52529
  "use strict";
52529
52530
  init_diagram();
52531
+ init_parser2();
52530
52532
  init_logger();
52531
52533
  init_safe_write();
52532
52534
  ASCII_FORMATS = /* @__PURE__ */ new Set(["ascii", "ascii-compact", "text"]);
@@ -52570,8 +52572,8 @@ async function diffCommand(file1, file2, options = {}) {
52570
52572
  }
52571
52573
  try {
52572
52574
  const [result1, result2] = await Promise.all([
52573
- parseWorkflow(filePath1, { workflowName }),
52574
- parseWorkflow(filePath2, { workflowName })
52575
+ parseWorkflow(filePath1, { workflowName, projectDir: path14.dirname(filePath1) }),
52576
+ parseWorkflow(filePath2, { workflowName, projectDir: path14.dirname(filePath2) })
52575
52577
  ]);
52576
52578
  if (result1.errors.length > 0) {
52577
52579
  throw new Error(`Parse errors in ${file1}:
@@ -52660,7 +52662,7 @@ async function validateCommand(input, options = {}) {
52660
52662
  logger.progress(i + 1, files.length, fileName);
52661
52663
  }
52662
52664
  try {
52663
- const parseResult = await parseWorkflow(file, { workflowName, projectDir: process.cwd() });
52665
+ const parseResult = await parseWorkflow(file, { workflowName, projectDir: path15.dirname(path15.resolve(file)) });
52664
52666
  if (parseResult.warnings.length > 0) {
52665
52667
  if (!json2 && !quiet) {
52666
52668
  logger.warn(`Parse warnings in ${fileName}:`);
@@ -54396,13 +54398,13 @@ var init_promise_polyfill = __esm({
54396
54398
  // Available starting from Node 22
54397
54399
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
54398
54400
  static withResolver() {
54399
- let resolve38;
54401
+ let resolve39;
54400
54402
  let reject;
54401
54403
  const promise = new Promise((res, rej) => {
54402
- resolve38 = res;
54404
+ resolve39 = res;
54403
54405
  reject = rej;
54404
54406
  });
54405
- return { promise, resolve: resolve38, reject };
54407
+ return { promise, resolve: resolve39, reject };
54406
54408
  }
54407
54409
  };
54408
54410
  }
@@ -54440,7 +54442,7 @@ function createPrompt(view) {
54440
54442
  output
54441
54443
  });
54442
54444
  const screen = new ScreenManager(rl);
54443
- const { promise, resolve: resolve38, reject } = PromisePolyfill.withResolver();
54445
+ const { promise, resolve: resolve39, reject } = PromisePolyfill.withResolver();
54444
54446
  const cancel = () => reject(new CancelPromptError());
54445
54447
  if (signal) {
54446
54448
  const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
@@ -54467,7 +54469,7 @@ function createPrompt(view) {
54467
54469
  cycle(() => {
54468
54470
  try {
54469
54471
  const nextView = view(config2, (value) => {
54470
- setImmediate(() => resolve38(value));
54472
+ setImmediate(() => resolve39(value));
54471
54473
  });
54472
54474
  if (nextView === void 0) {
54473
54475
  const callerFilename = callSites[1]?.getFileName();
@@ -55278,13 +55280,13 @@ var init_promise_polyfill2 = __esm({
55278
55280
  // Available starting from Node 22
55279
55281
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
55280
55282
  static withResolver() {
55281
- let resolve38;
55283
+ let resolve39;
55282
55284
  let reject;
55283
55285
  const promise = new Promise((res, rej) => {
55284
- resolve38 = res;
55286
+ resolve39 = res;
55285
55287
  reject = rej;
55286
55288
  });
55287
- return { promise, resolve: resolve38, reject };
55289
+ return { promise, resolve: resolve39, reject };
55288
55290
  }
55289
55291
  };
55290
55292
  }
@@ -55322,7 +55324,7 @@ function createPrompt2(view) {
55322
55324
  output
55323
55325
  });
55324
55326
  const screen = new ScreenManager2(rl);
55325
- const { promise, resolve: resolve38, reject } = PromisePolyfill2.withResolver();
55327
+ const { promise, resolve: resolve39, reject } = PromisePolyfill2.withResolver();
55326
55328
  const cancel = () => reject(new CancelPromptError2());
55327
55329
  if (signal) {
55328
55330
  const abort = () => reject(new AbortPromptError2({ cause: signal.reason }));
@@ -55349,7 +55351,7 @@ function createPrompt2(view) {
55349
55351
  cycle(() => {
55350
55352
  try {
55351
55353
  const nextView = view(config2, (value) => {
55352
- setImmediate(() => resolve38(value));
55354
+ setImmediate(() => resolve39(value));
55353
55355
  });
55354
55356
  if (nextView === void 0) {
55355
55357
  const callerFilename = callSites[1]?.getFileName();
@@ -56133,13 +56135,13 @@ var init_promise_polyfill3 = __esm({
56133
56135
  // Available starting from Node 22
56134
56136
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
56135
56137
  static withResolver() {
56136
- let resolve38;
56138
+ let resolve39;
56137
56139
  let reject;
56138
56140
  const promise = new Promise((res, rej) => {
56139
- resolve38 = res;
56141
+ resolve39 = res;
56140
56142
  reject = rej;
56141
56143
  });
56142
- return { promise, resolve: resolve38, reject };
56144
+ return { promise, resolve: resolve39, reject };
56143
56145
  }
56144
56146
  };
56145
56147
  }
@@ -56177,7 +56179,7 @@ function createPrompt3(view) {
56177
56179
  output
56178
56180
  });
56179
56181
  const screen = new ScreenManager3(rl);
56180
- const { promise, resolve: resolve38, reject } = PromisePolyfill3.withResolver();
56182
+ const { promise, resolve: resolve39, reject } = PromisePolyfill3.withResolver();
56181
56183
  const cancel = () => reject(new CancelPromptError3());
56182
56184
  if (signal) {
56183
56185
  const abort = () => reject(new AbortPromptError3({ cause: signal.reason }));
@@ -56204,7 +56206,7 @@ function createPrompt3(view) {
56204
56206
  cycle(() => {
56205
56207
  try {
56206
56208
  const nextView = view(config2, (value) => {
56207
- setImmediate(() => resolve38(value));
56209
+ setImmediate(() => resolve39(value));
56208
56210
  });
56209
56211
  if (nextView === void 0) {
56210
56212
  const callerFilename = callSites[1]?.getFileName();
@@ -69583,7 +69585,7 @@ var init_protocol = __esm({
69583
69585
  return;
69584
69586
  }
69585
69587
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
69586
- await new Promise((resolve38) => setTimeout(resolve38, pollInterval));
69588
+ await new Promise((resolve39) => setTimeout(resolve39, pollInterval));
69587
69589
  options?.signal?.throwIfAborted();
69588
69590
  }
69589
69591
  } catch (error2) {
@@ -69600,7 +69602,7 @@ var init_protocol = __esm({
69600
69602
  */
69601
69603
  request(request, resultSchema, options) {
69602
69604
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
69603
- return new Promise((resolve38, reject) => {
69605
+ return new Promise((resolve39, reject) => {
69604
69606
  const earlyReject = (error2) => {
69605
69607
  reject(error2);
69606
69608
  };
@@ -69678,7 +69680,7 @@ var init_protocol = __esm({
69678
69680
  if (!parseResult.success) {
69679
69681
  reject(parseResult.error);
69680
69682
  } else {
69681
- resolve38(parseResult.data);
69683
+ resolve39(parseResult.data);
69682
69684
  }
69683
69685
  } catch (error2) {
69684
69686
  reject(error2);
@@ -69939,12 +69941,12 @@ var init_protocol = __esm({
69939
69941
  }
69940
69942
  } catch {
69941
69943
  }
69942
- return new Promise((resolve38, reject) => {
69944
+ return new Promise((resolve39, reject) => {
69943
69945
  if (signal.aborted) {
69944
69946
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
69945
69947
  return;
69946
69948
  }
69947
- const timeoutId = setTimeout(resolve38, interval);
69949
+ const timeoutId = setTimeout(resolve39, interval);
69948
69950
  signal.addEventListener("abort", () => {
69949
69951
  clearTimeout(timeoutId);
69950
69952
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -72971,7 +72973,7 @@ var require_compile = __commonJS({
72971
72973
  const schOrFunc = root.refs[ref];
72972
72974
  if (schOrFunc)
72973
72975
  return schOrFunc;
72974
- let _sch = resolve38.call(this, root, ref);
72976
+ let _sch = resolve39.call(this, root, ref);
72975
72977
  if (_sch === void 0) {
72976
72978
  const schema2 = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
72977
72979
  const { schemaId } = this.opts;
@@ -72998,7 +73000,7 @@ var require_compile = __commonJS({
72998
73000
  function sameSchemaEnv(s1, s2) {
72999
73001
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
73000
73002
  }
73001
- function resolve38(root, ref) {
73003
+ function resolve39(root, ref) {
73002
73004
  let sch;
73003
73005
  while (typeof (sch = this.refs[ref]) == "string")
73004
73006
  ref = sch;
@@ -73573,7 +73575,7 @@ var require_fast_uri = __commonJS({
73573
73575
  }
73574
73576
  return uri;
73575
73577
  }
73576
- function resolve38(baseURI, relativeURI, options) {
73578
+ function resolve39(baseURI, relativeURI, options) {
73577
73579
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
73578
73580
  const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
73579
73581
  schemelessOptions.skipEscape = true;
@@ -73800,7 +73802,7 @@ var require_fast_uri = __commonJS({
73800
73802
  var fastUri = {
73801
73803
  SCHEMES,
73802
73804
  normalize,
73803
- resolve: resolve38,
73805
+ resolve: resolve39,
73804
73806
  resolveComponent,
73805
73807
  equal,
73806
73808
  serialize,
@@ -77919,7 +77921,7 @@ var init_mcp = __esm({
77919
77921
  let task = createTaskResult.task;
77920
77922
  const pollInterval = task.pollInterval ?? 5e3;
77921
77923
  while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
77922
- await new Promise((resolve38) => setTimeout(resolve38, pollInterval));
77924
+ await new Promise((resolve39) => setTimeout(resolve39, pollInterval));
77923
77925
  const updatedTask = await extra.taskStore.getTask(taskId);
77924
77926
  if (!updatedTask) {
77925
77927
  throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
@@ -78513,12 +78515,12 @@ var init_stdio2 = __esm({
78513
78515
  this.onclose?.();
78514
78516
  }
78515
78517
  send(message) {
78516
- return new Promise((resolve38) => {
78518
+ return new Promise((resolve39) => {
78517
78519
  const json2 = serializeMessage(message);
78518
78520
  if (this._stdout.write(json2)) {
78519
- resolve38();
78521
+ resolve39();
78520
78522
  } else {
78521
- this._stdout.once("drain", resolve38);
78523
+ this._stdout.once("drain", resolve39);
78522
78524
  }
78523
78525
  });
78524
78526
  }
@@ -83249,8 +83251,8 @@ var init_debug_controller = __esm({
83249
83251
  async pause(nodeId, phase, ctx) {
83250
83252
  const state = this.buildState(nodeId, phase, ctx);
83251
83253
  this._pauseResolve?.(state);
83252
- return new Promise((resolve38) => {
83253
- this._gateResolve = (action) => resolve38(action);
83254
+ return new Promise((resolve39) => {
83255
+ this._gateResolve = (action) => resolve39(action);
83254
83256
  });
83255
83257
  }
83256
83258
  applyAction(action) {
@@ -83311,8 +83313,8 @@ var init_debug_controller = __esm({
83311
83313
  return outputs;
83312
83314
  }
83313
83315
  _createPausePromise() {
83314
- return new Promise((resolve38) => {
83315
- this._pauseResolve = resolve38;
83316
+ return new Promise((resolve39) => {
83317
+ this._pauseResolve = resolve39;
83316
83318
  });
83317
83319
  }
83318
83320
  };
@@ -83511,8 +83513,8 @@ var init_agent_channel = __esm({
83511
83513
  */
83512
83514
  async request(agentRequest) {
83513
83515
  this._pauseResolve?.(agentRequest);
83514
- return new Promise((resolve38, reject) => {
83515
- this._resolve = resolve38;
83516
+ return new Promise((resolve39, reject) => {
83517
+ this._resolve = resolve39;
83516
83518
  this._reject = reject;
83517
83519
  });
83518
83520
  }
@@ -83542,8 +83544,8 @@ var init_agent_channel = __esm({
83542
83544
  this._pausePromise = this._createPausePromise();
83543
83545
  }
83544
83546
  _createPausePromise() {
83545
- return new Promise((resolve38) => {
83546
- this._pauseResolve = resolve38;
83547
+ return new Promise((resolve39) => {
83548
+ this._pauseResolve = resolve39;
83547
83549
  });
83548
83550
  }
83549
83551
  };
@@ -84900,7 +84902,7 @@ async function runCommandInner(input, options) {
84900
84902
  let executionOrder = resumeExecutionOrder;
84901
84903
  if (!executionOrder) {
84902
84904
  const source = fs36.readFileSync(filePath, "utf8");
84903
- const parsed = await parseWorkflow(source, { workflowName: options.workflow });
84905
+ const parsed = await parseWorkflow(source, { workflowName: options.workflow, projectDir: path40.dirname(filePath) });
84904
84906
  if (parsed.errors.length === 0) {
84905
84907
  executionOrder = getTopologicalOrder(parsed.ast);
84906
84908
  } else {
@@ -85113,7 +85115,7 @@ async function validateMockConfig(mocks, filePath, workflowName) {
85113
85115
  }
85114
85116
  }
85115
85117
  try {
85116
- const result = await parseWorkflow(filePath, { workflowName });
85118
+ const result = await parseWorkflow(filePath, { workflowName, projectDir: path40.dirname(filePath) });
85117
85119
  if (result.errors.length > 0 || !result.ast?.instances) return;
85118
85120
  const usedNodeTypes = new Set(result.ast.instances.map((i) => i.nodeType));
85119
85121
  for (const [section, nodeType] of Object.entries(MOCK_SECTION_TO_NODE)) {
@@ -85175,13 +85177,13 @@ async function runDebugRepl(controller, execPromise, agentChannel, options) {
85175
85177
  output: process.stderr,
85176
85178
  prompt: "> "
85177
85179
  });
85178
- return new Promise((resolve38, reject) => {
85180
+ return new Promise((resolve39, reject) => {
85179
85181
  let resolved = false;
85180
85182
  function finish(value) {
85181
85183
  if (resolved) return;
85182
85184
  resolved = true;
85183
85185
  rl.close();
85184
- resolve38(value);
85186
+ resolve39(value);
85185
85187
  }
85186
85188
  function fail(err) {
85187
85189
  if (resolved) return;
@@ -85393,7 +85395,7 @@ Workflow completed in ${execResult.executionTime}ms`);
85393
85395
  });
85394
85396
  }
85395
85397
  function promptForInput(question) {
85396
- return new Promise((resolve38) => {
85398
+ return new Promise((resolve39) => {
85397
85399
  const rl = readline8.createInterface({
85398
85400
  input: process.stdin,
85399
85401
  output: process.stderr
@@ -85401,7 +85403,7 @@ function promptForInput(question) {
85401
85403
  });
85402
85404
  rl.question(question, (answer) => {
85403
85405
  rl.close();
85404
- resolve38(answer.trim());
85406
+ resolve39(answer.trim());
85405
85407
  });
85406
85408
  });
85407
85409
  }
@@ -85877,6 +85879,15 @@ __export(serve_exports, {
85877
85879
  import * as path41 from "path";
85878
85880
  import * as fs38 from "fs";
85879
85881
  async function serveCommand(dir, options) {
85882
+ try {
85883
+ await import("fastify");
85884
+ } catch {
85885
+ logger.error("The serve command requires fastify. Install it with:");
85886
+ logger.newline();
85887
+ logger.log(" npm install fastify");
85888
+ logger.newline();
85889
+ process.exit(1);
85890
+ }
85880
85891
  const workflowDir = path41.resolve(dir || ".");
85881
85892
  if (!fs38.existsSync(workflowDir)) {
85882
85893
  throw new Error(`Directory not found: ${workflowDir}`);
@@ -86761,131 +86772,6 @@ var init_implement = __esm({
86761
86772
  }
86762
86773
  });
86763
86774
 
86764
- // src/cli/commands/changelog.ts
86765
- var changelog_exports = {};
86766
- __export(changelog_exports, {
86767
- changelogCommand: () => changelogCommand
86768
- });
86769
- import { execSync as execSync6 } from "child_process";
86770
- function categorize(files) {
86771
- for (const category of CATEGORIES2) {
86772
- if (files.some(category.match)) {
86773
- return category.name;
86774
- }
86775
- }
86776
- return "Other";
86777
- }
86778
- function getGitRange(options) {
86779
- if (options.range) {
86780
- return options.range;
86781
- }
86782
- if (options.lastTag) {
86783
- try {
86784
- const lastTag = execSync6("git describe --tags --abbrev=0", {
86785
- encoding: "utf8"
86786
- }).trim();
86787
- return `${lastTag}..HEAD`;
86788
- } catch {
86789
- logger.warn("No git tags found, showing all commits");
86790
- return "HEAD";
86791
- }
86792
- }
86793
- if (options.since) {
86794
- return `--since="${options.since}"`;
86795
- }
86796
- return "-20";
86797
- }
86798
- function getCommits(rangeArg) {
86799
- const isSinceArg = rangeArg.startsWith("--since");
86800
- const isCountArg = rangeArg.startsWith("-");
86801
- let logCmd;
86802
- if (isSinceArg) {
86803
- logCmd = `git log ${rangeArg} --format="%H %s" --no-merges`;
86804
- } else if (isCountArg) {
86805
- logCmd = `git log ${rangeArg} --format="%H %s" --no-merges`;
86806
- } else {
86807
- logCmd = `git log ${rangeArg} --format="%H %s" --no-merges`;
86808
- }
86809
- const logOutput = execSync6(logCmd, { encoding: "utf8" }).trim();
86810
- if (!logOutput) {
86811
- return [];
86812
- }
86813
- const entries = [];
86814
- for (const line of logOutput.split(/\r?\n/)) {
86815
- if (!line.trim()) continue;
86816
- const spaceIdx = line.indexOf(" ");
86817
- const hash = line.slice(0, spaceIdx);
86818
- const message = line.slice(spaceIdx + 1);
86819
- let files;
86820
- try {
86821
- const filesOutput = execSync6(`git diff-tree --no-commit-id --name-only -r ${hash}`, {
86822
- encoding: "utf8"
86823
- }).trim();
86824
- files = filesOutput ? filesOutput.split(/\r?\n/) : [];
86825
- } catch {
86826
- files = [];
86827
- }
86828
- entries.push({ hash: hash.slice(0, 7), message, files });
86829
- }
86830
- return entries;
86831
- }
86832
- async function changelogCommand(options = {}) {
86833
- const rangeArg = getGitRange(options);
86834
- const rangeLabel = options.range || (options.lastTag ? "last tag" : options.since ? `since ${options.since}` : "recent");
86835
- const commits = getCommits(rangeArg);
86836
- if (commits.length === 0) {
86837
- logger.info("No commits found in the specified range.");
86838
- return;
86839
- }
86840
- const grouped = /* @__PURE__ */ new Map();
86841
- for (const commit of commits) {
86842
- const category = categorize(commit.files);
86843
- if (!grouped.has(category)) {
86844
- grouped.set(category, []);
86845
- }
86846
- grouped.get(category).push(commit);
86847
- }
86848
- console.log(`## Changes (${rangeLabel})
86849
- `);
86850
- const categoryOrder = CATEGORIES2.map((c) => c.name);
86851
- const sortedCategories = [...grouped.keys()].sort((a, b) => {
86852
- const idxA = categoryOrder.indexOf(a);
86853
- const idxB = categoryOrder.indexOf(b);
86854
- if (idxA === -1 && idxB === -1) return a.localeCompare(b);
86855
- if (idxA === -1) return 1;
86856
- if (idxB === -1) return -1;
86857
- return idxA - idxB;
86858
- });
86859
- for (const category of sortedCategories) {
86860
- const categoryCommits = grouped.get(category);
86861
- console.log(`### ${category} (${categoryCommits.length} commit${categoryCommits.length !== 1 ? "s" : ""})
86862
- `);
86863
- for (const commit of categoryCommits) {
86864
- console.log(`- ${commit.hash} ${commit.message}`);
86865
- }
86866
- console.log("");
86867
- }
86868
- }
86869
- var CATEGORIES2;
86870
- var init_changelog = __esm({
86871
- "src/cli/commands/changelog.ts"() {
86872
- "use strict";
86873
- init_logger();
86874
- CATEGORIES2 = [
86875
- { name: "Grammar", match: (f) => /parser|chevrotain|grammar/.test(f) },
86876
- { name: "Code Generation", match: (f) => /generator|body-generator|generate/.test(f) },
86877
- { name: "Differ", match: (f) => f.includes("diff/") },
86878
- { name: "CLI", match: (f) => f.includes("cli/commands/") },
86879
- { name: "MCP Tools", match: (f) => f.includes("mcp/") },
86880
- { name: "Deployment", match: (f) => /deployment|export/.test(f) },
86881
- { name: "Runtime", match: (f) => f.includes("runtime/") },
86882
- { name: "Migration", match: (f) => f.includes("migration/") },
86883
- { name: "Tests", match: (f) => f.includes("tests/") || f.includes(".test.") },
86884
- { name: "Documentation", match: (f) => /doc|readme|changelog/i.test(f) }
86885
- ];
86886
- }
86887
- });
86888
-
86889
86775
  // src/cli/commands/docs.ts
86890
86776
  var docs_exports = {};
86891
86777
  __export(docs_exports, {
@@ -87036,7 +86922,7 @@ __export(market_exports, {
87036
86922
  });
87037
86923
  import * as fs45 from "fs";
87038
86924
  import * as path48 from "path";
87039
- import { execSync as execSync7 } from "child_process";
86925
+ import { execSync as execSync6 } from "child_process";
87040
86926
  async function marketInitCommand(name, options = {}) {
87041
86927
  if (!name.startsWith("flow-weaver-pack-")) {
87042
86928
  const suggested = `flow-weaver-pack-${name}`;
@@ -87265,7 +87151,7 @@ async function marketPublishCommand(directory, options = {}) {
87265
87151
  if (tag) npmArgs.push("--tag", tag);
87266
87152
  try {
87267
87153
  logger.newline();
87268
- execSync7(`npm ${npmArgs.join(" ")}`, { cwd: dir, stdio: "inherit" });
87154
+ execSync6(`npm ${npmArgs.join(" ")}`, { cwd: dir, stdio: "inherit" });
87269
87155
  if (!dryRun) {
87270
87156
  logger.newline();
87271
87157
  logger.success(`Published ${pkg.name}@${pkg.version} to npm`);
@@ -87282,7 +87168,7 @@ async function marketInstallCommand(packageSpec, options = {}) {
87282
87168
  logger.newline();
87283
87169
  }
87284
87170
  try {
87285
- execSync7(`npm install ${packageSpec}`, { stdio: json2 ? "pipe" : "inherit" });
87171
+ execSync6(`npm install ${packageSpec}`, { stdio: json2 ? "pipe" : "inherit" });
87286
87172
  } catch (err) {
87287
87173
  if (json2) {
87288
87174
  console.log(JSON.stringify({ success: false, error: getErrorMessage(err) }));
@@ -87840,15 +87726,15 @@ function readLine(prompt2) {
87840
87726
  return Promise.resolve(null);
87841
87727
  }
87842
87728
  const rl = readline9.createInterface({ input: process.stdin, output: process.stderr });
87843
- return new Promise((resolve38) => {
87729
+ return new Promise((resolve39) => {
87844
87730
  let answered = false;
87845
87731
  rl.question(prompt2, (answer) => {
87846
87732
  answered = true;
87847
87733
  rl.close();
87848
- resolve38(answer.trim());
87734
+ resolve39(answer.trim());
87849
87735
  });
87850
87736
  rl.on("close", () => {
87851
- if (!answered) resolve38(null);
87737
+ if (!answered) resolve39(null);
87852
87738
  });
87853
87739
  });
87854
87740
  }
@@ -88102,7 +87988,7 @@ async function authStatusCommand() {
88102
87988
  }
88103
87989
  function prompt(message, hidden = false) {
88104
87990
  if (hidden && process.stdin.isTTY) {
88105
- return new Promise((resolve38) => {
87991
+ return new Promise((resolve39) => {
88106
87992
  process.stderr.write(message);
88107
87993
  process.stdin.setRawMode(true);
88108
87994
  process.stdin.resume();
@@ -88114,7 +88000,7 @@ function prompt(message, hidden = false) {
88114
88000
  process.stdin.pause();
88115
88001
  process.stdin.removeListener("data", handler);
88116
88002
  process.stderr.write("\n");
88117
- resolve38(input);
88003
+ resolve39(input);
88118
88004
  } else if (ch === "") {
88119
88005
  process.stdin.setRawMode(false);
88120
88006
  process.exit(1);
@@ -88127,11 +88013,11 @@ function prompt(message, hidden = false) {
88127
88013
  process.stdin.on("data", handler);
88128
88014
  });
88129
88015
  }
88130
- return new Promise((resolve38) => {
88016
+ return new Promise((resolve39) => {
88131
88017
  const rl = readline10.createInterface({ input: process.stdin, output: process.stderr });
88132
88018
  rl.question(message, (answer) => {
88133
88019
  rl.close();
88134
- resolve38(answer);
88020
+ resolve39(answer);
88135
88021
  });
88136
88022
  });
88137
88023
  }
@@ -88645,7 +88531,7 @@ var init_device_connection = __esm({
88645
88531
  const wsUrl = this.options.platformUrl.replace(/^http/, "ws").replace(/\/$/, "") + "/ws/device";
88646
88532
  this.log(`Connecting to ${wsUrl}...`);
88647
88533
  this.shouldReconnect = true;
88648
- return new Promise((resolve38, reject) => {
88534
+ return new Promise((resolve39, reject) => {
88649
88535
  try {
88650
88536
  this.ws = new WebSocket(`${wsUrl}?token=${encodeURIComponent(this.options.token)}`);
88651
88537
  } catch (err) {
@@ -88662,7 +88548,7 @@ var init_device_connection = __esm({
88662
88548
  }
88663
88549
  }, 3e4);
88664
88550
  this.options.onConnect?.();
88665
- resolve38();
88551
+ resolve39();
88666
88552
  });
88667
88553
  this.ws.addEventListener("message", async (event) => {
88668
88554
  try {
@@ -88768,12 +88654,12 @@ import * as path52 from "node:path";
88768
88654
  import * as os5 from "node:os";
88769
88655
  import * as readline11 from "node:readline";
88770
88656
  function promptYesNo(message) {
88771
- return new Promise((resolve38) => {
88657
+ return new Promise((resolve39) => {
88772
88658
  const rl = readline11.createInterface({ input: process.stdin, output: process.stderr });
88773
88659
  rl.question(message, (answer) => {
88774
88660
  rl.close();
88775
88661
  const normalized = answer.trim().toLowerCase();
88776
- resolve38(normalized === "" || normalized === "y" || normalized === "yes");
88662
+ resolve39(normalized === "" || normalized === "y" || normalized === "yes");
88777
88663
  });
88778
88664
  });
88779
88665
  }
@@ -88894,15 +88780,15 @@ async function handleConnect(projectDir) {
88894
88780
  try {
88895
88781
  await conn.connect();
88896
88782
  console.log(" \x1B[2mPress Ctrl+C to disconnect.\x1B[0m\n");
88897
- await new Promise((resolve38) => {
88783
+ await new Promise((resolve39) => {
88898
88784
  process.on("SIGINT", () => {
88899
88785
  console.log("\n \x1B[2mDisconnecting...\x1B[0m");
88900
88786
  conn.disconnect();
88901
- resolve38();
88787
+ resolve39();
88902
88788
  });
88903
88789
  process.on("SIGTERM", () => {
88904
88790
  conn.disconnect();
88905
- resolve38();
88791
+ resolve39();
88906
88792
  });
88907
88793
  });
88908
88794
  } catch (err) {
@@ -88960,7 +88846,7 @@ function parseIntStrict(value) {
88960
88846
  // src/cli/index.ts
88961
88847
  init_logger();
88962
88848
  init_error_utils();
88963
- var version2 = true ? "0.30.0" : "0.0.0-dev";
88849
+ var version2 = true ? "0.30.1" : "0.0.0-dev";
88964
88850
  var program2 = new Command();
88965
88851
  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", () => {
88966
88852
  logger.banner(version2);
@@ -89156,10 +89042,6 @@ program2.command("implement <input> [node]").description("Replace a stub node wi
89156
89042
  if (options.workflow) options.workflowName = options.workflow;
89157
89043
  await implementCommand2(input, nodeName, options);
89158
89044
  }));
89159
- program2.command("changelog").description("Generate changelog from git history, categorized by file path").option("--last-tag", "From last git tag to HEAD", false).option("--since <date>", 'Date-based range (e.g., "2024-01-01")').option("-r, --range <range>", 'Custom git range (e.g., "v0.1.0..HEAD")').action(wrapAction(async (options) => {
89160
- const { changelogCommand: changelogCommand2 } = await Promise.resolve().then(() => (init_changelog(), changelog_exports));
89161
- await changelogCommand2(options);
89162
- }));
89163
89045
  program2.command("docs [args...]").description("Browse reference documentation").option("--json", "Output as JSON", false).option("--compact", "Return compact LLM-friendly version", false).action(wrapAction(async (args, options) => {
89164
89046
  const { docsListCommand: docsListCommand2, docsReadCommand: docsReadCommand2, docsSearchCommand: docsSearchCommand2 } = await Promise.resolve().then(() => (init_docs2(), docs_exports));
89165
89047
  if (args.length === 0 || args[0] === "list") {
package/dist/cli/index.js CHANGED
@@ -531,17 +531,6 @@ program
531
531
  options.workflowName = options.workflow;
532
532
  await implementCommand(input, nodeName, options);
533
533
  }));
534
- // Changelog command
535
- program
536
- .command('changelog')
537
- .description('Generate changelog from git history, categorized by file path')
538
- .option('--last-tag', 'From last git tag to HEAD', false)
539
- .option('--since <date>', 'Date-based range (e.g., "2024-01-01")')
540
- .option('-r, --range <range>', 'Custom git range (e.g., "v0.1.0..HEAD")')
541
- .action(wrapAction(async (options) => {
542
- const { changelogCommand } = await import('./commands/changelog.js');
543
- await changelogCommand(options);
544
- }));
545
534
  // Docs command: fw docs [topic] | fw docs search <query>
546
535
  program
547
536
  .command('docs [args...]')
@@ -316,16 +316,6 @@ export const CLI_COMMANDS = [
316
316
  { flags: '--diff', description: 'Show semantic diff before/after' },
317
317
  ],
318
318
  },
319
- {
320
- name: 'changelog',
321
- syntax: 'fw changelog [options]',
322
- description: 'Generate changelog from git history, categorized by file path',
323
- options: [
324
- { flags: '--last-tag', description: 'From last git tag to HEAD', exclusive: 'range' },
325
- { flags: '--since', arg: '<date>', description: 'Date-based range (e.g., "2024-01-01")', exclusive: 'range' },
326
- { flags: '-r, --range', arg: '<range>', description: 'Custom git range (e.g., "v0.1.0..HEAD")', exclusive: 'range' },
327
- ],
328
- },
329
319
  ];
330
320
  /**
331
321
  * Extract CLI command documentation
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.30.0";
1
+ export declare const VERSION = "0.30.1";
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.0';
2
+ export const VERSION = '0.30.1';
3
3
  //# sourceMappingURL=generated-version.js.map
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: CLI Reference
3
3
  description: Complete reference for all Flow Weaver CLI commands, flags, and options
4
- keywords: [cli, commands, compile, validate, strip, run, watch, dev, serve, export, diagram, diff, doctor, init, migrate, marketplace, plugin, grammar, changelog, openapi, pattern, create, templates, context, modify, implement, status]
4
+ keywords: [cli, commands, compile, validate, strip, run, watch, dev, serve, export, diagram, diff, doctor, init, migrate, marketplace, plugin, grammar, openapi, pattern, create, templates, context, modify, implement, status]
5
5
  ---
6
6
 
7
7
  # CLI Reference
@@ -33,7 +33,6 @@ Complete reference for all `fw` CLI commands.
33
33
  | `openapi` | Generate OpenAPI specification |
34
34
  | `migrate` | Migrate to current syntax |
35
35
  | `grammar` | Output annotation grammar |
36
- | `changelog` | Generate changelog from git |
37
36
  | `market` | Marketplace packages |
38
37
  | `plugin` | External plugins |
39
38
  | `modify` | Add/remove/rename nodes, connections, positions, and labels |
@@ -1023,29 +1022,6 @@ fw mcp-server [options]
1023
1022
 
1024
1023
  ---
1025
1024
 
1026
- ### changelog
1027
-
1028
- Generate changelog from git history, categorized by file path.
1029
-
1030
- ```bash
1031
- fw changelog [options]
1032
- ```
1033
-
1034
- | Flag | Description | Default |
1035
- |------|-------------|---------|
1036
- | `--last-tag` | From last git tag to HEAD | `false` |
1037
- | `--since <date>` | Date-based range | — |
1038
- | `-r, --range <range>` | Custom git range | — |
1039
-
1040
- **Examples:**
1041
- ```bash
1042
- fw changelog --last-tag
1043
- fw changelog --range v0.1.0..HEAD
1044
- fw changelog --since 2024-01-01
1045
- ```
1046
-
1047
- ---
1048
-
1049
1025
  ## Global Flag
1050
1026
 
1051
1027
  | Flag | Description |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synergenius/flow-weaver",
3
- "version": "0.30.0",
3
+ "version": "0.30.1",
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",
@@ -1,13 +0,0 @@
1
- /**
2
- * Changelog command - generates changelog from git history
3
- *
4
- * Categorizes commits by changed file paths — no conventional commits needed.
5
- * Works with any commit message style.
6
- */
7
- export interface ChangelogOptions {
8
- lastTag?: boolean;
9
- since?: string;
10
- range?: string;
11
- }
12
- export declare function changelogCommand(options?: ChangelogOptions): Promise<void>;
13
- //# sourceMappingURL=changelog.d.ts.map
@@ -1,135 +0,0 @@
1
- /**
2
- * Changelog command - generates changelog from git history
3
- *
4
- * Categorizes commits by changed file paths — no conventional commits needed.
5
- * Works with any commit message style.
6
- */
7
- import { execSync } from 'child_process';
8
- import { logger } from '../utils/logger.js';
9
- const CATEGORIES = [
10
- { name: 'Grammar', match: (f) => /parser|chevrotain|grammar/.test(f) },
11
- { name: 'Code Generation', match: (f) => /generator|body-generator|generate/.test(f) },
12
- { name: 'Differ', match: (f) => f.includes('diff/') },
13
- { name: 'CLI', match: (f) => f.includes('cli/commands/') },
14
- { name: 'MCP Tools', match: (f) => f.includes('mcp/') },
15
- { name: 'Deployment', match: (f) => /deployment|export/.test(f) },
16
- { name: 'Runtime', match: (f) => f.includes('runtime/') },
17
- { name: 'Migration', match: (f) => f.includes('migration/') },
18
- { name: 'Tests', match: (f) => f.includes('tests/') || f.includes('.test.') },
19
- { name: 'Documentation', match: (f) => /doc|readme|changelog/i.test(f) },
20
- ];
21
- function categorize(files) {
22
- for (const category of CATEGORIES) {
23
- if (files.some(category.match)) {
24
- return category.name;
25
- }
26
- }
27
- return 'Other';
28
- }
29
- function getGitRange(options) {
30
- if (options.range) {
31
- return options.range;
32
- }
33
- if (options.lastTag) {
34
- try {
35
- const lastTag = execSync('git describe --tags --abbrev=0', {
36
- encoding: 'utf8',
37
- }).trim();
38
- return `${lastTag}..HEAD`;
39
- }
40
- catch {
41
- logger.warn('No git tags found, showing all commits');
42
- return 'HEAD';
43
- }
44
- }
45
- if (options.since) {
46
- return `--since="${options.since}"`;
47
- }
48
- // Default: last 20 commits
49
- return '-20';
50
- }
51
- function getCommits(rangeArg) {
52
- const isSinceArg = rangeArg.startsWith('--since');
53
- const isCountArg = rangeArg.startsWith('-');
54
- let logCmd;
55
- if (isSinceArg) {
56
- logCmd = `git log ${rangeArg} --format="%H %s" --no-merges`;
57
- }
58
- else if (isCountArg) {
59
- logCmd = `git log ${rangeArg} --format="%H %s" --no-merges`;
60
- }
61
- else {
62
- logCmd = `git log ${rangeArg} --format="%H %s" --no-merges`;
63
- }
64
- const logOutput = execSync(logCmd, { encoding: 'utf8' }).trim();
65
- if (!logOutput) {
66
- return [];
67
- }
68
- const entries = [];
69
- for (const line of logOutput.split(/\r?\n/)) {
70
- if (!line.trim())
71
- continue;
72
- const spaceIdx = line.indexOf(' ');
73
- const hash = line.slice(0, spaceIdx);
74
- const message = line.slice(spaceIdx + 1);
75
- // Get changed files for this commit
76
- let files;
77
- try {
78
- const filesOutput = execSync(`git diff-tree --no-commit-id --name-only -r ${hash}`, {
79
- encoding: 'utf8',
80
- }).trim();
81
- files = filesOutput ? filesOutput.split(/\r?\n/) : [];
82
- }
83
- catch {
84
- files = [];
85
- }
86
- entries.push({ hash: hash.slice(0, 7), message, files });
87
- }
88
- return entries;
89
- }
90
- export async function changelogCommand(options = {}) {
91
- const rangeArg = getGitRange(options);
92
- const rangeLabel = options.range || (options.lastTag ? 'last tag' : options.since ? `since ${options.since}` : 'recent');
93
- const commits = getCommits(rangeArg);
94
- if (commits.length === 0) {
95
- logger.info('No commits found in the specified range.');
96
- return;
97
- }
98
- // Group by category
99
- const grouped = new Map();
100
- for (const commit of commits) {
101
- const category = categorize(commit.files);
102
- if (!grouped.has(category)) {
103
- grouped.set(category, []);
104
- }
105
- grouped.get(category).push(commit);
106
- }
107
- // Output as markdown
108
- // eslint-disable-next-line no-console
109
- console.log(`## Changes (${rangeLabel})\n`);
110
- // Sort categories: defined order first, then "Other"
111
- const categoryOrder = CATEGORIES.map((c) => c.name);
112
- const sortedCategories = [...grouped.keys()].sort((a, b) => {
113
- const idxA = categoryOrder.indexOf(a);
114
- const idxB = categoryOrder.indexOf(b);
115
- if (idxA === -1 && idxB === -1)
116
- return a.localeCompare(b);
117
- if (idxA === -1)
118
- return 1;
119
- if (idxB === -1)
120
- return -1;
121
- return idxA - idxB;
122
- });
123
- for (const category of sortedCategories) {
124
- const categoryCommits = grouped.get(category);
125
- // eslint-disable-next-line no-console
126
- console.log(`### ${category} (${categoryCommits.length} commit${categoryCommits.length !== 1 ? 's' : ''})\n`);
127
- for (const commit of categoryCommits) {
128
- // eslint-disable-next-line no-console
129
- console.log(`- ${commit.hash} ${commit.message}`);
130
- }
131
- // eslint-disable-next-line no-console
132
- console.log('');
133
- }
134
- }
135
- //# sourceMappingURL=changelog.js.map