@synergenius/flow-weaver 0.16.0 → 0.17.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.
@@ -2944,7 +2944,7 @@ var require_brace_expansion = __commonJS({
2944
2944
  incr *= -1;
2945
2945
  test = gte;
2946
2946
  }
2947
- var pad = n.some(isPadded);
2947
+ var pad2 = n.some(isPadded);
2948
2948
  N = [];
2949
2949
  for (var i = x; test(i, y); i += incr) {
2950
2950
  var c;
@@ -2954,7 +2954,7 @@ var require_brace_expansion = __commonJS({
2954
2954
  c = "";
2955
2955
  } else {
2956
2956
  c = String(i);
2957
- if (pad) {
2957
+ if (pad2) {
2958
2958
  var need = width - c.length;
2959
2959
  if (need > 0) {
2960
2960
  var z = new Array(need + 1).join("0");
@@ -9671,7 +9671,7 @@ var VERSION;
9671
9671
  var init_generated_version = __esm({
9672
9672
  "src/generated-version.ts"() {
9673
9673
  "use strict";
9674
- VERSION = "0.16.0";
9674
+ VERSION = "0.17.0";
9675
9675
  }
9676
9676
  });
9677
9677
 
@@ -51552,9 +51552,9 @@ function portBadgeWidth(port) {
51552
51552
  const abbrev = TYPE_ABBREVIATIONS[port.dataType] ?? port.dataType;
51553
51553
  const typeWidth = measureText(abbrev);
51554
51554
  const labelWidth = measureText(port.label);
51555
- const pad = 7;
51555
+ const pad2 = 7;
51556
51556
  const divGap = 4;
51557
- return pad + typeWidth + divGap + 1 + divGap + labelWidth + pad;
51557
+ return pad2 + typeWidth + divGap + 1 + divGap + labelWidth + pad2;
51558
51558
  }
51559
51559
  function portLabelExtent(port) {
51560
51560
  const badgeGap = 5;
@@ -53241,9 +53241,9 @@ function renderPortLabels(parts2, nodeId, inputs, outputs, theme, themeName) {
53241
53241
  const portLabel = port.label;
53242
53242
  const typeWidth = measureText(abbrev);
53243
53243
  const labelWidth = measureText(portLabel);
53244
- const pad = 7;
53244
+ const pad2 = 7;
53245
53245
  const divGap = 4;
53246
- const badgeWidth = pad + typeWidth + divGap + 1 + divGap + labelWidth + pad;
53246
+ const badgeWidth = pad2 + typeWidth + divGap + 1 + divGap + labelWidth + pad2;
53247
53247
  const badgeHeight = 16;
53248
53248
  const badgeGap = 5;
53249
53249
  const rr = badgeHeight / 2;
@@ -53252,15 +53252,15 @@ function renderPortLabels(parts2, nodeId, inputs, outputs, theme, themeName) {
53252
53252
  parts2.push(` <g data-port-label="${portId}">`);
53253
53253
  parts2.push(` <rect x="${badgeX}" y="${badgeY}" width="${badgeWidth}" height="${badgeHeight}" rx="${rr}" fill="${theme.nodeFill}" stroke="${theme.labelBadgeBorder}" stroke-width="1"/>`);
53254
53254
  if (isInput) {
53255
- const typeX = badgeX + badgeWidth - pad - typeWidth / 2;
53255
+ const typeX = badgeX + badgeWidth - pad2 - typeWidth / 2;
53256
53256
  const divX = typeX - typeWidth / 2 - divGap;
53257
53257
  const nameX = divX - divGap;
53258
53258
  parts2.push(` <line x1="${divX}" y1="${badgeY + 3}" x2="${divX}" y2="${badgeY + badgeHeight - 3}" stroke="${theme.labelBadgeBorder}" stroke-width="1"/>`);
53259
53259
  parts2.push(` <text class="port-label" x="${nameX}" y="${port.cy + 3.5}" text-anchor="end">${escapeXml(portLabel)}</text>`);
53260
53260
  parts2.push(` <text class="port-type-label" x="${typeX}" y="${port.cy + 3.5}" text-anchor="middle" fill="${color}">${escapeXml(abbrev)}</text>`);
53261
53261
  } else {
53262
- const typeX = badgeX + pad + typeWidth / 2;
53263
- const divX = badgeX + pad + typeWidth + divGap;
53262
+ const typeX = badgeX + pad2 + typeWidth / 2;
53263
+ const divX = badgeX + pad2 + typeWidth + divGap;
53264
53264
  const nameX = divX + 1 + divGap;
53265
53265
  parts2.push(` <line x1="${divX}" y1="${badgeY + 3}" x2="${divX}" y2="${badgeY + badgeHeight - 3}" stroke="${theme.labelBadgeBorder}" stroke-width="1"/>`);
53266
53266
  parts2.push(` <text class="port-type-label" x="${typeX}" y="${port.cy + 3.5}" text-anchor="middle" fill="${color}">${escapeXml(abbrev)}</text>`);
@@ -56433,20 +56433,20 @@ __export(workflow_executor_exports, {
56433
56433
  computeTraceSummary: () => computeTraceSummary,
56434
56434
  executeWorkflowFromFile: () => executeWorkflowFromFile
56435
56435
  });
56436
- import * as path18 from "path";
56437
- import * as fs18 from "fs";
56436
+ import * as path20 from "path";
56437
+ import * as fs20 from "fs";
56438
56438
  import { pathToFileURL } from "url";
56439
56439
  import ts4 from "typescript";
56440
56440
  async function executeWorkflowFromFile(filePath, params, options) {
56441
- const resolvedPath = path18.resolve(filePath);
56441
+ const resolvedPath = path20.resolve(filePath);
56442
56442
  const includeTrace = options?.includeTrace !== false;
56443
56443
  const tmpId = `fw-exec-${Date.now()}-${Math.random().toString(36).slice(2)}`;
56444
- const tmpBase = path18.join(path18.dirname(resolvedPath), tmpId);
56444
+ const tmpBase = path20.join(path20.dirname(resolvedPath), tmpId);
56445
56445
  const tmpTsFile = `${tmpBase}.ts`;
56446
56446
  const tmpFile = `${tmpBase}.mjs`;
56447
56447
  try {
56448
- fs18.copyFileSync(resolvedPath, tmpTsFile);
56449
- const source = fs18.readFileSync(resolvedPath, "utf8");
56448
+ fs20.copyFileSync(resolvedPath, tmpTsFile);
56449
+ const source = fs20.readFileSync(resolvedPath, "utf8");
56450
56450
  const allWorkflows = getAvailableWorkflows(source);
56451
56451
  const production = options?.debugController ? false : options?.production ?? !includeTrace;
56452
56452
  for (const wf of allWorkflows) {
@@ -56457,7 +56457,7 @@ async function executeWorkflowFromFile(filePath, params, options) {
56457
56457
  generate: { production }
56458
56458
  });
56459
56459
  }
56460
- let compiledCode = fs18.readFileSync(tmpTsFile, "utf8");
56460
+ let compiledCode = fs20.readFileSync(tmpTsFile, "utf8");
56461
56461
  compiledCode = compiledCode.replace(
56462
56462
  "declare const __flowWeaverDebugger__: TDebugger | undefined;",
56463
56463
  "const __flowWeaverDebugger__ = (globalThis as any).__fw_debugger__;"
@@ -56469,7 +56469,7 @@ async function executeWorkflowFromFile(filePath, params, options) {
56469
56469
  esModuleInterop: true
56470
56470
  }
56471
56471
  });
56472
- fs18.writeFileSync(tmpFile, jsOutput.outputText, "utf8");
56472
+ fs20.writeFileSync(tmpFile, jsOutput.outputText, "utf8");
56473
56473
  const trace = [];
56474
56474
  const debugger_ = includeTrace ? {
56475
56475
  sendEvent: (event) => {
@@ -56525,11 +56525,11 @@ async function executeWorkflowFromFile(filePath, params, options) {
56525
56525
  delete globalThis.__fw_agent_channel__;
56526
56526
  delete globalThis.__fw_debug_controller__;
56527
56527
  try {
56528
- fs18.unlinkSync(tmpFile);
56528
+ fs20.unlinkSync(tmpFile);
56529
56529
  } catch {
56530
56530
  }
56531
56531
  try {
56532
- fs18.unlinkSync(tmpTsFile);
56532
+ fs20.unlinkSync(tmpTsFile);
56533
56533
  } catch {
56534
56534
  }
56535
56535
  }
@@ -56600,7 +56600,7 @@ var require_XMLHttpRequest = __commonJS({
56600
56600
  "node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js"(exports2, module2) {
56601
56601
  var fs53 = __require("fs");
56602
56602
  var Url = __require("url");
56603
- var spawn2 = __require("child_process").spawn;
56603
+ var spawn3 = __require("child_process").spawn;
56604
56604
  module2.exports = XMLHttpRequest3;
56605
56605
  XMLHttpRequest3.XMLHttpRequest = XMLHttpRequest3;
56606
56606
  function XMLHttpRequest3(opts) {
@@ -56896,7 +56896,7 @@ var require_XMLHttpRequest = __commonJS({
56896
56896
  var syncFile = ".node-xmlhttprequest-sync-" + process.pid;
56897
56897
  fs53.writeFileSync(syncFile, "", "utf8");
56898
56898
  var execString = "var http = require('http'), https = require('https'), fs = require('fs');var doRequest = http" + (ssl ? "s" : "") + ".request;var options = " + JSON.stringify(options) + ";var responseText = '';var responseData = Buffer.alloc(0);var req = doRequest(options, function(response) {response.on('data', function(chunk) { var data = Buffer.from(chunk); responseText += data.toString('utf8'); responseData = Buffer.concat([responseData, data]);});response.on('end', function() {fs.writeFileSync('" + contentFile + "', JSON.stringify({err: null, data: {statusCode: response.statusCode, headers: response.headers, text: responseText, data: responseData.toString('base64')}}), 'utf8');fs.unlinkSync('" + syncFile + "');});response.on('error', function(error) {fs.writeFileSync('" + contentFile + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');fs.unlinkSync('" + syncFile + "');});}).on('error', function(error) {fs.writeFileSync('" + contentFile + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');fs.unlinkSync('" + syncFile + "');});" + (data ? "req.write('" + JSON.stringify(data).slice(1, -1).replace(/'/g, "\\'") + "');" : "") + "req.end();";
56899
- var syncProc = spawn2(process.argv[0], ["-e", execString]);
56899
+ var syncProc = spawn3(process.argv[0], ["-e", execString]);
56900
56900
  var statusText;
56901
56901
  while (fs53.existsSync(syncFile)) {
56902
56902
  }
@@ -72068,8 +72068,8 @@ var init_executor = __esm({
72068
72068
  });
72069
72069
 
72070
72070
  // src/deployment/core/adapters.ts
72071
- import * as fs28 from "fs";
72072
- import * as path30 from "path";
72071
+ import * as fs30 from "fs";
72072
+ import * as path32 from "path";
72073
72073
  import { randomUUID as randomUUID2 } from "crypto";
72074
72074
  function createAdapter(source) {
72075
72075
  switch (source) {
@@ -72162,12 +72162,12 @@ var init_adapters = __esm({
72162
72162
  throw new Error(`Invalid JSON in params: ${input.params}`);
72163
72163
  }
72164
72164
  } else if (input.paramsFile) {
72165
- const paramsFilePath = path30.resolve(input.paramsFile);
72166
- if (!fs28.existsSync(paramsFilePath)) {
72165
+ const paramsFilePath = path32.resolve(input.paramsFile);
72166
+ if (!fs30.existsSync(paramsFilePath)) {
72167
72167
  throw new Error(`Params file not found: ${paramsFilePath}`);
72168
72168
  }
72169
72169
  try {
72170
- const content = fs28.readFileSync(paramsFilePath, "utf8");
72170
+ const content = fs30.readFileSync(paramsFilePath, "utf8");
72171
72171
  params = JSON.parse(content);
72172
72172
  } catch {
72173
72173
  throw new Error(`Failed to parse params file: ${input.paramsFile}`);
@@ -72188,7 +72188,7 @@ var init_adapters = __esm({
72188
72188
  * Extract workflow ID from file path (uses filename without extension)
72189
72189
  */
72190
72190
  extractWorkflowId(filePath) {
72191
- const basename20 = path30.basename(filePath, path30.extname(filePath));
72191
+ const basename20 = path32.basename(filePath, path32.extname(filePath));
72192
72192
  return basename20;
72193
72193
  }
72194
72194
  };
@@ -72502,8 +72502,8 @@ var init_defaults2 = __esm({
72502
72502
  });
72503
72503
 
72504
72504
  // src/deployment/config/loader.ts
72505
- import * as fs29 from "fs";
72506
- import * as path31 from "path";
72505
+ import * as fs31 from "fs";
72506
+ import * as path33 from "path";
72507
72507
  async function loadConfig(cliOverrides, configPath) {
72508
72508
  const environment = detectEnvironment(cliOverrides);
72509
72509
  let config2 = getDefaultConfig(environment);
@@ -72540,22 +72540,22 @@ async function loadConfigFile(configPath) {
72540
72540
  }
72541
72541
  const cwd = process.cwd();
72542
72542
  for (const fileName of CONFIG_FILE_NAMES) {
72543
- const configFilePath = path31.join(cwd, fileName);
72544
- if (fs29.existsSync(configFilePath)) {
72543
+ const configFilePath = path33.join(cwd, fileName);
72544
+ if (fs31.existsSync(configFilePath)) {
72545
72545
  return loadConfigFromPath(configFilePath);
72546
72546
  }
72547
72547
  }
72548
72548
  return null;
72549
72549
  }
72550
72550
  async function loadConfigFromPath(filePath) {
72551
- const absolutePath = path31.resolve(filePath);
72552
- if (!fs29.existsSync(absolutePath)) {
72551
+ const absolutePath = path33.resolve(filePath);
72552
+ if (!fs31.existsSync(absolutePath)) {
72553
72553
  return null;
72554
72554
  }
72555
- const ext2 = path31.extname(absolutePath);
72555
+ const ext2 = path33.extname(absolutePath);
72556
72556
  if (ext2 === ".yaml" || ext2 === ".yml") {
72557
72557
  try {
72558
- const content = fs29.readFileSync(absolutePath, "utf8");
72558
+ const content = fs31.readFileSync(absolutePath, "utf8");
72559
72559
  return load(content);
72560
72560
  } catch {
72561
72561
  return null;
@@ -73178,7 +73178,7 @@ var init_generator = __esm({
73178
73178
  });
73179
73179
 
73180
73180
  // src/deployment/targets/base.ts
73181
- import * as path32 from "path";
73181
+ import * as path34 from "path";
73182
73182
  var BaseExportTarget, ExportTargetRegistry;
73183
73183
  var init_base = __esm({
73184
73184
  "src/deployment/targets/base.ts"() {
@@ -73229,7 +73229,7 @@ var init_base = __esm({
73229
73229
  createFile(outputDir, relativePath, content, type2) {
73230
73230
  return {
73231
73231
  relativePath,
73232
- absolutePath: path32.join(outputDir, relativePath),
73232
+ absolutePath: path34.join(outputDir, relativePath),
73233
73233
  content,
73234
73234
  type: type2
73235
73235
  };
@@ -73282,7 +73282,7 @@ var init_base = __esm({
73282
73282
  * Get relative import path for the workflow
73283
73283
  */
73284
73284
  getWorkflowImport(workflowFile) {
73285
- const basename20 = path32.basename(workflowFile, path32.extname(workflowFile));
73285
+ const basename20 = path34.basename(workflowFile, path34.extname(workflowFile));
73286
73286
  return `./${basename20}.js`;
73287
73287
  }
73288
73288
  /**
@@ -74334,8 +74334,8 @@ __export(registry_exports, {
74334
74334
  listInstalledPackages: () => listInstalledPackages,
74335
74335
  searchPackages: () => searchPackages
74336
74336
  });
74337
- import * as fs30 from "fs";
74338
- import * as path33 from "path";
74337
+ import * as fs32 from "fs";
74338
+ import * as path35 from "path";
74339
74339
  async function searchPackages(options = {}) {
74340
74340
  const { query, limit = 20, registryUrl } = options;
74341
74341
  const textParts = [
@@ -74360,25 +74360,25 @@ async function searchPackages(options = {}) {
74360
74360
  }));
74361
74361
  }
74362
74362
  async function listInstalledPackages(projectDir) {
74363
- const nodeModules = path33.join(projectDir, "node_modules");
74364
- if (!fs30.existsSync(nodeModules)) return [];
74363
+ const nodeModules = path35.join(projectDir, "node_modules");
74364
+ if (!fs32.existsSync(nodeModules)) return [];
74365
74365
  const patterns = [
74366
- path33.join(nodeModules, "flowweaver-pack-*", "flowweaver.manifest.json"),
74367
- path33.join(nodeModules, "@*", "flowweaver-pack-*", "flowweaver.manifest.json")
74366
+ path35.join(nodeModules, "flowweaver-pack-*", "flowweaver.manifest.json"),
74367
+ path35.join(nodeModules, "@*", "flowweaver-pack-*", "flowweaver.manifest.json")
74368
74368
  ];
74369
74369
  const results = [];
74370
74370
  for (const pattern of patterns) {
74371
74371
  const manifestPaths = await glob(pattern.replace(/\\/g, "/"), { absolute: true });
74372
74372
  for (const manifestPath of manifestPaths) {
74373
74373
  try {
74374
- const pkgDir = path33.dirname(manifestPath);
74374
+ const pkgDir = path35.dirname(manifestPath);
74375
74375
  const manifest = JSON.parse(
74376
- fs30.readFileSync(manifestPath, "utf-8")
74376
+ fs32.readFileSync(manifestPath, "utf-8")
74377
74377
  );
74378
- const pkgJsonPath = path33.join(pkgDir, "package.json");
74378
+ const pkgJsonPath = path35.join(pkgDir, "package.json");
74379
74379
  let version3 = manifest.version;
74380
- if (fs30.existsSync(pkgJsonPath)) {
74381
- const pkg = JSON.parse(fs30.readFileSync(pkgJsonPath, "utf-8"));
74380
+ if (fs32.existsSync(pkgJsonPath)) {
74381
+ const pkg = JSON.parse(fs32.readFileSync(pkgJsonPath, "utf-8"));
74382
74382
  version3 = pkg.version ?? manifest.version;
74383
74383
  }
74384
74384
  results.push({
@@ -74394,11 +74394,11 @@ async function listInstalledPackages(projectDir) {
74394
74394
  return results;
74395
74395
  }
74396
74396
  function getInstalledPackageManifest(projectDir, packageName) {
74397
- const packageDir = path33.join(projectDir, "node_modules", packageName);
74398
- const manifestPath = path33.join(packageDir, "flowweaver.manifest.json");
74399
- if (!fs30.existsSync(manifestPath)) return null;
74397
+ const packageDir = path35.join(projectDir, "node_modules", packageName);
74398
+ const manifestPath = path35.join(packageDir, "flowweaver.manifest.json");
74399
+ if (!fs32.existsSync(manifestPath)) return null;
74400
74400
  try {
74401
- return JSON.parse(fs30.readFileSync(manifestPath, "utf-8"));
74401
+ return JSON.parse(fs32.readFileSync(manifestPath, "utf-8"));
74402
74402
  } catch {
74403
74403
  return null;
74404
74404
  }
@@ -74450,7 +74450,7 @@ __export(deployment_exports, {
74450
74450
  loadConfigSync: () => loadConfigSync,
74451
74451
  schemaConverter: () => schemaConverter
74452
74452
  });
74453
- import * as path34 from "path";
74453
+ import * as path36 from "path";
74454
74454
  async function createTargetRegistry(projectDir) {
74455
74455
  const registry2 = new ExportTargetRegistry();
74456
74456
  if (projectDir) {
@@ -74458,7 +74458,7 @@ async function createTargetRegistry(projectDir) {
74458
74458
  const packages = await listInstalledPackages2(projectDir);
74459
74459
  for (const pkg of packages) {
74460
74460
  for (const def of pkg.manifest.exportTargets ?? []) {
74461
- const filePath = path34.join(pkg.path, def.file);
74461
+ const filePath = path36.join(pkg.path, def.file);
74462
74462
  const mod = await import(filePath);
74463
74463
  const TargetClass = def.exportName ? mod[def.exportName] : mod.default;
74464
74464
  registry2.register(def.name, () => new TargetClass());
@@ -77762,9 +77762,9 @@ async function validateCommand(input, options = {}) {
77762
77762
  }
77763
77763
 
77764
77764
  // src/cli/commands/init.ts
77765
- import * as fs17 from "fs";
77766
- import * as path16 from "path";
77767
- import { execSync as execSync2 } from "child_process";
77765
+ import * as fs19 from "fs";
77766
+ import * as path18 from "path";
77767
+ import { execSync as execSync3, spawn } from "child_process";
77768
77768
 
77769
77769
  // node_modules/@inquirer/input/node_modules/@inquirer/core/dist/lib/key.js
77770
77770
  var isBackspaceKey = (key) => key.name === "backspace";
@@ -80770,6 +80770,1220 @@ var eraseLine2 = ESC3 + "2K";
80770
80770
 
80771
80771
  // src/cli/commands/init.ts
80772
80772
  init_templates();
80773
+
80774
+ // src/cli/commands/mcp-setup.ts
80775
+ import { execSync as execSync2 } from "child_process";
80776
+ import * as fs17 from "fs";
80777
+ import * as path16 from "path";
80778
+ import * as os from "os";
80779
+ var MCP_COMMAND = "npx";
80780
+ var MCP_ARGS = ["@synergenius/flow-weaver@latest", "mcp-server", "--stdio"];
80781
+ var MCP_ENTRY = { command: MCP_COMMAND, args: [...MCP_ARGS] };
80782
+ var CLI_TOOL_IDS = /* @__PURE__ */ new Set(["claude", "codex"]);
80783
+ var CLI_TOOL_BINARY = {
80784
+ claude: "claude",
80785
+ codex: "codex"
80786
+ };
80787
+ function defaultDeps() {
80788
+ return {
80789
+ execCommand: async (cmd) => {
80790
+ try {
80791
+ const stdout = execSync2(cmd, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
80792
+ return { stdout: stdout.trim(), exitCode: 0 };
80793
+ } catch {
80794
+ return { stdout: "", exitCode: 1 };
80795
+ }
80796
+ },
80797
+ fileExists: async (filePath) => {
80798
+ try {
80799
+ await fs17.promises.access(filePath);
80800
+ return true;
80801
+ } catch {
80802
+ return false;
80803
+ }
80804
+ },
80805
+ readFile: async (filePath) => {
80806
+ try {
80807
+ return await fs17.promises.readFile(filePath, "utf8");
80808
+ } catch {
80809
+ return null;
80810
+ }
80811
+ },
80812
+ writeFile: async (filePath, content) => {
80813
+ await fs17.promises.writeFile(filePath, content, "utf8");
80814
+ },
80815
+ mkdir: async (dirPath) => {
80816
+ await fs17.promises.mkdir(dirPath, { recursive: true });
80817
+ },
80818
+ cwd: () => process.cwd(),
80819
+ homedir: () => os.homedir(),
80820
+ log: (msg) => process.stdout.write(msg + "\n")
80821
+ };
80822
+ }
80823
+ function whichCmd(binary2) {
80824
+ return process.platform === "win32" ? `where ${binary2}` : `which ${binary2}`;
80825
+ }
80826
+ async function binaryExists(binary2, deps) {
80827
+ const result = await deps.execCommand(whichCmd(binary2));
80828
+ return result.exitCode === 0;
80829
+ }
80830
+ async function mergeJsonConfig(deps, filePath, rootKey) {
80831
+ const existing = await deps.readFile(filePath);
80832
+ if (existing === null) {
80833
+ const dir = path16.dirname(filePath);
80834
+ await deps.mkdir(dir);
80835
+ const config3 = { [rootKey]: { "flow-weaver": MCP_ENTRY } };
80836
+ await deps.writeFile(filePath, JSON.stringify(config3, null, 2) + "\n");
80837
+ return { action: "created", detail: `created ${filePath}` };
80838
+ }
80839
+ let config2;
80840
+ try {
80841
+ config2 = JSON.parse(existing);
80842
+ } catch {
80843
+ throw new Error(`invalid JSON in ${filePath}`);
80844
+ }
80845
+ if (!config2[rootKey] || typeof config2[rootKey] !== "object") {
80846
+ config2[rootKey] = {};
80847
+ }
80848
+ const servers = config2[rootKey];
80849
+ if (servers["flow-weaver"]) {
80850
+ return { action: "already-configured", detail: `already in ${filePath}` };
80851
+ }
80852
+ servers["flow-weaver"] = MCP_ENTRY;
80853
+ await deps.writeFile(filePath, JSON.stringify(config2, null, 2) + "\n");
80854
+ return { action: "added", detail: `added to ${filePath}` };
80855
+ }
80856
+ var TOOL_REGISTRY = [
80857
+ // Claude Code
80858
+ {
80859
+ id: "claude",
80860
+ displayName: "Claude Code",
80861
+ detect: (deps) => binaryExists("claude", deps),
80862
+ isConfigured: async (deps) => {
80863
+ const result = await deps.execCommand("claude mcp list");
80864
+ return result.exitCode === 0 && result.stdout.includes("flow-weaver");
80865
+ },
80866
+ configure: async (deps) => {
80867
+ const cmd = `claude mcp add --scope project flow-weaver -- ${MCP_COMMAND} ${MCP_ARGS.join(" ")}`;
80868
+ const result = await deps.execCommand(cmd);
80869
+ if (result.exitCode !== 0) {
80870
+ throw new Error("claude mcp add failed");
80871
+ }
80872
+ return "registered via claude mcp add";
80873
+ }
80874
+ },
80875
+ // Cursor
80876
+ {
80877
+ id: "cursor",
80878
+ displayName: "Cursor",
80879
+ detect: async (deps) => {
80880
+ const dirExists = await deps.fileExists(path16.join(deps.cwd(), ".cursor"));
80881
+ if (dirExists) return true;
80882
+ return binaryExists("cursor", deps);
80883
+ },
80884
+ isConfigured: async (deps) => {
80885
+ const filePath = path16.join(deps.cwd(), ".cursor", "mcp.json");
80886
+ const content = await deps.readFile(filePath);
80887
+ if (!content) return false;
80888
+ try {
80889
+ const config2 = JSON.parse(content);
80890
+ return !!config2?.mcpServers?.["flow-weaver"];
80891
+ } catch {
80892
+ return false;
80893
+ }
80894
+ },
80895
+ configure: async (deps) => {
80896
+ const filePath = path16.join(deps.cwd(), ".cursor", "mcp.json");
80897
+ const result = await mergeJsonConfig(deps, filePath, "mcpServers");
80898
+ return result.detail;
80899
+ }
80900
+ },
80901
+ // VS Code Copilot
80902
+ {
80903
+ id: "vscode",
80904
+ displayName: "VS Code Copilot",
80905
+ detect: (deps) => binaryExists("code", deps),
80906
+ isConfigured: async (deps) => {
80907
+ const filePath = path16.join(deps.cwd(), ".vscode", "mcp.json");
80908
+ const content = await deps.readFile(filePath);
80909
+ if (!content) return false;
80910
+ try {
80911
+ const config2 = JSON.parse(content);
80912
+ return !!config2?.servers?.["flow-weaver"];
80913
+ } catch {
80914
+ return false;
80915
+ }
80916
+ },
80917
+ configure: async (deps) => {
80918
+ const filePath = path16.join(deps.cwd(), ".vscode", "mcp.json");
80919
+ const result = await mergeJsonConfig(deps, filePath, "servers");
80920
+ return result.detail;
80921
+ }
80922
+ },
80923
+ // Windsurf
80924
+ {
80925
+ id: "windsurf",
80926
+ displayName: "Windsurf",
80927
+ detect: async (deps) => {
80928
+ const configDir = path16.join(deps.homedir(), ".codeium", "windsurf");
80929
+ const dirExists = await deps.fileExists(configDir);
80930
+ if (dirExists) return true;
80931
+ return binaryExists("windsurf", deps);
80932
+ },
80933
+ isConfigured: async (deps) => {
80934
+ const filePath = path16.join(deps.homedir(), ".codeium", "windsurf", "mcp_config.json");
80935
+ const content = await deps.readFile(filePath);
80936
+ if (!content) return false;
80937
+ try {
80938
+ const config2 = JSON.parse(content);
80939
+ return !!config2?.mcpServers?.["flow-weaver"];
80940
+ } catch {
80941
+ return false;
80942
+ }
80943
+ },
80944
+ configure: async (deps) => {
80945
+ const filePath = path16.join(deps.homedir(), ".codeium", "windsurf", "mcp_config.json");
80946
+ const result = await mergeJsonConfig(deps, filePath, "mcpServers");
80947
+ return result.detail;
80948
+ }
80949
+ },
80950
+ // Codex (OpenAI)
80951
+ {
80952
+ id: "codex",
80953
+ displayName: "Codex",
80954
+ detect: (deps) => binaryExists("codex", deps),
80955
+ isConfigured: async (deps) => {
80956
+ const result = await deps.execCommand("codex mcp list");
80957
+ return result.exitCode === 0 && result.stdout.includes("flow-weaver");
80958
+ },
80959
+ configure: async (deps) => {
80960
+ const cmd = `codex mcp add flow-weaver -- ${MCP_COMMAND} ${MCP_ARGS.join(" ")}`;
80961
+ const result = await deps.execCommand(cmd);
80962
+ if (result.exitCode !== 0) {
80963
+ throw new Error("codex mcp add failed");
80964
+ }
80965
+ return "registered via codex mcp add";
80966
+ }
80967
+ },
80968
+ // OpenClaw
80969
+ {
80970
+ id: "openclaw",
80971
+ displayName: "OpenClaw",
80972
+ detect: async (deps) => {
80973
+ return deps.fileExists(path16.join(deps.cwd(), "openclaw.json"));
80974
+ },
80975
+ isConfigured: async (deps) => {
80976
+ const filePath = path16.join(deps.cwd(), "openclaw.json");
80977
+ const content = await deps.readFile(filePath);
80978
+ if (!content) return false;
80979
+ try {
80980
+ const config2 = JSON.parse(content);
80981
+ return !!config2?.mcpServers?.["flow-weaver"];
80982
+ } catch {
80983
+ return false;
80984
+ }
80985
+ },
80986
+ configure: async (deps) => {
80987
+ const filePath = path16.join(deps.cwd(), "openclaw.json");
80988
+ const result = await mergeJsonConfig(deps, filePath, "mcpServers");
80989
+ return result.detail;
80990
+ }
80991
+ }
80992
+ ];
80993
+ async function detectTools(deps) {
80994
+ const results = await Promise.all(
80995
+ TOOL_REGISTRY.map(async (tool) => {
80996
+ const detected = await tool.detect(deps);
80997
+ const configured = detected ? await tool.isConfigured(deps) : false;
80998
+ return { id: tool.id, displayName: tool.displayName, detected, configured };
80999
+ })
81000
+ );
81001
+ return results;
81002
+ }
81003
+ async function configureTool(tool, deps) {
81004
+ try {
81005
+ const already = await tool.isConfigured(deps);
81006
+ if (already) {
81007
+ return { id: tool.id, displayName: tool.displayName, action: "already-configured", detail: "already configured" };
81008
+ }
81009
+ const detail = await tool.configure(deps);
81010
+ return { id: tool.id, displayName: tool.displayName, action: "configured", detail };
81011
+ } catch (err) {
81012
+ const msg = err instanceof Error ? err.message : String(err);
81013
+ return { id: tool.id, displayName: tool.displayName, action: "failed", detail: msg };
81014
+ }
81015
+ }
81016
+ async function runMcpSetupFromInit(deps) {
81017
+ const d = deps ?? defaultDeps();
81018
+ const detected = await detectTools(d);
81019
+ const toConfig = detected.filter((t) => t.detected && !t.configured);
81020
+ const configured = [];
81021
+ const failed = [];
81022
+ const toolMap = new Map(TOOL_REGISTRY.map((t) => [t.id, t]));
81023
+ for (const t of toConfig) {
81024
+ const tool = toolMap.get(t.id);
81025
+ if (!tool) continue;
81026
+ const result = await configureTool(tool, d);
81027
+ if (result.action === "configured") {
81028
+ configured.push(result.displayName);
81029
+ } else if (result.action === "failed") {
81030
+ failed.push(result.displayName);
81031
+ }
81032
+ }
81033
+ for (const t of detected) {
81034
+ if (t.configured) {
81035
+ configured.push(t.displayName);
81036
+ }
81037
+ }
81038
+ const allConfiguredIds = detected.filter((t) => t.detected && (t.configured || configured.includes(t.displayName))).map((t) => t.id);
81039
+ const cliTools = allConfiguredIds.filter((id) => CLI_TOOL_IDS.has(id));
81040
+ const guiTools = allConfiguredIds.filter((id) => !CLI_TOOL_IDS.has(id));
81041
+ return { configured, failed, cliTools, guiTools };
81042
+ }
81043
+ async function mcpSetupCommand(options, deps) {
81044
+ const d = deps ?? defaultDeps();
81045
+ const detected = await detectTools(d);
81046
+ if (options.list) {
81047
+ d.log("");
81048
+ for (const t of detected) {
81049
+ const status = t.detected ? t.configured ? "detected, configured" : "detected" : "not found";
81050
+ const icon = t.detected ? t.configured ? "\u25CF" : "\u25CB" : "\xB7";
81051
+ d.log(` ${icon} ${t.displayName.padEnd(18)} ${status}`);
81052
+ }
81053
+ d.log("");
81054
+ return;
81055
+ }
81056
+ let toolIds;
81057
+ if (options.tool && options.tool.length > 0) {
81058
+ const valid = new Set(TOOL_REGISTRY.map((t) => t.id));
81059
+ for (const name of options.tool) {
81060
+ if (!valid.has(name)) {
81061
+ d.log(`Unknown tool: "${name}". Valid tools: ${[...valid].join(", ")}`);
81062
+ return;
81063
+ }
81064
+ }
81065
+ toolIds = options.tool;
81066
+ } else if (options.all) {
81067
+ toolIds = detected.filter((t) => t.detected).map((t) => t.id);
81068
+ } else if (isNonInteractive()) {
81069
+ toolIds = detected.filter((t) => t.detected).map((t) => t.id);
81070
+ } else {
81071
+ const detectedTools = detected.filter((t) => t.detected);
81072
+ if (detectedTools.length === 0) {
81073
+ d.log("No AI coding tools detected. You can specify tools manually with --tool.");
81074
+ return;
81075
+ }
81076
+ d.log("");
81077
+ d.log("Detected tools:");
81078
+ for (const t of detected) {
81079
+ const icon = t.detected ? "\u2713" : "\u2717";
81080
+ d.log(` ${icon} ${t.displayName}`);
81081
+ }
81082
+ d.log("");
81083
+ toolIds = [];
81084
+ try {
81085
+ for (const t of detectedTools) {
81086
+ if (t.configured) {
81087
+ d.log(` ${t.displayName}: already configured, skipping`);
81088
+ continue;
81089
+ }
81090
+ const yes = await dist_default6({
81091
+ message: `Configure ${t.displayName}?`,
81092
+ default: true
81093
+ });
81094
+ if (yes) toolIds.push(t.id);
81095
+ }
81096
+ } catch (err) {
81097
+ if (err instanceof ExitPromptError4) return;
81098
+ throw err;
81099
+ }
81100
+ d.log("");
81101
+ }
81102
+ if (toolIds.length === 0) {
81103
+ const anyDetected = detected.some((t) => t.detected);
81104
+ if (!anyDetected) {
81105
+ d.log("No AI coding tools detected. You can specify tools manually with --tool.");
81106
+ } else {
81107
+ d.log("No tools selected.");
81108
+ }
81109
+ return;
81110
+ }
81111
+ const toolMap = new Map(TOOL_REGISTRY.map((t) => [t.id, t]));
81112
+ const results = [];
81113
+ for (const id of toolIds) {
81114
+ const tool = toolMap.get(id);
81115
+ const result = await configureTool(tool, d);
81116
+ results.push(result);
81117
+ const icon = result.action === "configured" ? "\u2713" : result.action === "already-configured" ? "\u25CF" : "\u2717";
81118
+ d.log(`${icon} ${result.displayName}: ${result.detail}`);
81119
+ }
81120
+ const configured = results.filter((r) => r.action === "configured").length;
81121
+ const alreadyDone = results.filter((r) => r.action === "already-configured").length;
81122
+ const failed = results.filter((r) => r.action === "failed").length;
81123
+ const parts2 = [];
81124
+ if (configured > 0) parts2.push(`${configured} configured`);
81125
+ if (alreadyDone > 0) parts2.push(`${alreadyDone} already configured`);
81126
+ if (failed > 0) parts2.push(`${failed} failed`);
81127
+ d.log("");
81128
+ d.log(`Done. ${parts2.join(", ")}.`);
81129
+ }
81130
+
81131
+ // src/cli/commands/init-personas.ts
81132
+ init_templates();
81133
+
81134
+ // src/docs/index.ts
81135
+ import * as fs18 from "fs";
81136
+ import * as path17 from "path";
81137
+ import { fileURLToPath as fileURLToPath3 } from "url";
81138
+ function getDocsDir() {
81139
+ const thisFile = fileURLToPath3(import.meta.url);
81140
+ const packageRoot = path17.resolve(path17.dirname(thisFile), "..", "..");
81141
+ return path17.join(packageRoot, "docs", "reference");
81142
+ }
81143
+ function parseFrontmatter(raw) {
81144
+ const fmMatch = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
81145
+ if (!fmMatch) {
81146
+ return {
81147
+ frontmatter: { name: "", description: "", keywords: [] },
81148
+ body: raw
81149
+ };
81150
+ }
81151
+ const fmBlock = fmMatch[1];
81152
+ const body = fmMatch[2];
81153
+ let name = "";
81154
+ let description = "";
81155
+ let keywords = [];
81156
+ for (const line of fmBlock.split("\n")) {
81157
+ const nameMatch = line.match(/^name:\s*(.+)$/);
81158
+ if (nameMatch) {
81159
+ name = nameMatch[1].trim();
81160
+ continue;
81161
+ }
81162
+ const descMatch = line.match(/^description:\s*(.+)$/);
81163
+ if (descMatch) {
81164
+ description = descMatch[1].trim();
81165
+ continue;
81166
+ }
81167
+ const kwMatch = line.match(/^keywords:\s*\[(.+)\]$/);
81168
+ if (kwMatch) {
81169
+ keywords = kwMatch[1].split(",").map((k) => k.trim().replace(/^['"]|['"]$/g, ""));
81170
+ continue;
81171
+ }
81172
+ }
81173
+ return { frontmatter: { name, description, keywords }, body };
81174
+ }
81175
+ function splitSections(body) {
81176
+ const lines = body.split("\n");
81177
+ const sections = [];
81178
+ let currentHeading = "";
81179
+ let currentLevel = 0;
81180
+ let currentLines = [];
81181
+ function flush() {
81182
+ if (currentHeading || currentLines.length > 0) {
81183
+ const content = currentLines.join("\n").trim();
81184
+ const codeBlocks = [];
81185
+ const codeRe = /```[\s\S]*?```/g;
81186
+ let m;
81187
+ while ((m = codeRe.exec(content)) !== null) {
81188
+ codeBlocks.push(m[0]);
81189
+ }
81190
+ sections.push({
81191
+ heading: currentHeading,
81192
+ level: currentLevel,
81193
+ content,
81194
+ codeBlocks
81195
+ });
81196
+ }
81197
+ }
81198
+ for (const line of lines) {
81199
+ const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
81200
+ if (headingMatch) {
81201
+ flush();
81202
+ currentLevel = headingMatch[1].length;
81203
+ currentHeading = headingMatch[2];
81204
+ currentLines = [];
81205
+ } else {
81206
+ currentLines.push(line);
81207
+ }
81208
+ }
81209
+ flush();
81210
+ return sections;
81211
+ }
81212
+ function listTopics() {
81213
+ const docsDir = getDocsDir();
81214
+ if (!fs18.existsSync(docsDir)) return [];
81215
+ const files = fs18.readdirSync(docsDir).filter((f) => f.endsWith(".md")).sort();
81216
+ return files.map((file) => {
81217
+ const raw = fs18.readFileSync(path17.join(docsDir, file), "utf-8");
81218
+ const { frontmatter } = parseFrontmatter(raw);
81219
+ return {
81220
+ slug: file.replace(/\.md$/, ""),
81221
+ name: frontmatter.name,
81222
+ description: frontmatter.description,
81223
+ keywords: frontmatter.keywords
81224
+ };
81225
+ });
81226
+ }
81227
+ function readTopic(slug, compact2) {
81228
+ const docsDir = getDocsDir();
81229
+ const filePath = path17.join(docsDir, `${slug}.md`);
81230
+ if (!fs18.existsSync(filePath)) return null;
81231
+ const raw = fs18.readFileSync(filePath, "utf-8");
81232
+ const { frontmatter, body } = parseFrontmatter(raw);
81233
+ const content = compact2 ? buildCompactContent(frontmatter, body) : body.trim();
81234
+ return {
81235
+ slug,
81236
+ name: frontmatter.name,
81237
+ description: frontmatter.description,
81238
+ keywords: frontmatter.keywords,
81239
+ content
81240
+ };
81241
+ }
81242
+ function readTopicStructured(slug) {
81243
+ const docsDir = getDocsDir();
81244
+ const filePath = path17.join(docsDir, `${slug}.md`);
81245
+ if (!fs18.existsSync(filePath)) return null;
81246
+ const raw = fs18.readFileSync(filePath, "utf-8");
81247
+ const { frontmatter, body } = parseFrontmatter(raw);
81248
+ const sections = splitSections(body);
81249
+ return {
81250
+ slug,
81251
+ name: frontmatter.name,
81252
+ description: frontmatter.description,
81253
+ keywords: frontmatter.keywords,
81254
+ sections
81255
+ };
81256
+ }
81257
+ function searchDocs(query) {
81258
+ const topics = listTopics();
81259
+ const docsDir = getDocsDir();
81260
+ const queryLower = query.toLowerCase();
81261
+ const queryTerms = queryLower.split(/\s+/).filter(Boolean);
81262
+ const results = [];
81263
+ for (const topic of topics) {
81264
+ const keywordMatch = topic.keywords.some(
81265
+ (kw) => queryTerms.some((term) => kw.toLowerCase().includes(term))
81266
+ );
81267
+ const filePath = path17.join(docsDir, `${topic.slug}.md`);
81268
+ const raw = fs18.readFileSync(filePath, "utf-8");
81269
+ const { body } = parseFrontmatter(raw);
81270
+ const sections = splitSections(body);
81271
+ for (const section of sections) {
81272
+ const sectionLower = section.content.toLowerCase();
81273
+ const headingLower = section.heading.toLowerCase();
81274
+ let relevance = 0;
81275
+ if (sectionLower.includes(queryLower)) {
81276
+ relevance += 10;
81277
+ }
81278
+ for (const term of queryTerms) {
81279
+ if (headingLower.includes(term)) relevance += 5;
81280
+ if (sectionLower.includes(term)) relevance += 2;
81281
+ }
81282
+ if (keywordMatch) relevance += 3;
81283
+ if (relevance > 0) {
81284
+ const lines = section.content.split("\n");
81285
+ const matchingLines = [];
81286
+ for (const line of lines) {
81287
+ if (queryTerms.some((term) => line.toLowerCase().includes(term))) {
81288
+ matchingLines.push(line.trim());
81289
+ if (matchingLines.length >= 3) break;
81290
+ }
81291
+ }
81292
+ results.push({
81293
+ topic: topic.name,
81294
+ slug: topic.slug,
81295
+ section: section.heading,
81296
+ heading: section.heading,
81297
+ excerpt: matchingLines.join("\n") || section.content.slice(0, 200),
81298
+ relevance
81299
+ });
81300
+ }
81301
+ }
81302
+ }
81303
+ results.sort((a, b) => b.relevance - a.relevance);
81304
+ return results;
81305
+ }
81306
+ function buildCompactContent(frontmatter, body) {
81307
+ const lines = body.split("\n");
81308
+ const output = [];
81309
+ output.push(`# ${frontmatter.name}`);
81310
+ output.push(frontmatter.description);
81311
+ output.push("");
81312
+ let inCodeBlock = false;
81313
+ let inTable = false;
81314
+ for (const line of lines) {
81315
+ if (line.trimStart().startsWith("```")) {
81316
+ inCodeBlock = !inCodeBlock;
81317
+ output.push(line);
81318
+ continue;
81319
+ }
81320
+ if (inCodeBlock) {
81321
+ output.push(line);
81322
+ continue;
81323
+ }
81324
+ if (line.match(/^#{1,6}\s/)) {
81325
+ output.push("");
81326
+ output.push(line);
81327
+ continue;
81328
+ }
81329
+ if (line.trim().startsWith("|")) {
81330
+ inTable = true;
81331
+ output.push(line);
81332
+ continue;
81333
+ }
81334
+ if (inTable && !line.trim().startsWith("|")) {
81335
+ inTable = false;
81336
+ }
81337
+ if (line.trim().startsWith("- ") || line.trim().startsWith("* ") || line.trim().startsWith("> ")) {
81338
+ output.push(line);
81339
+ continue;
81340
+ }
81341
+ }
81342
+ return output.join("\n").replace(/\n{3,}/g, "\n\n").trim();
81343
+ }
81344
+
81345
+ // src/context/index.ts
81346
+ init_grammar_diagrams();
81347
+ var PRESETS = {
81348
+ core: ["concepts", "jsdoc-grammar", "tutorial"],
81349
+ authoring: [
81350
+ "concepts",
81351
+ "jsdoc-grammar",
81352
+ "advanced-annotations",
81353
+ "built-in-nodes",
81354
+ "scaffold",
81355
+ "node-conversion",
81356
+ "patterns"
81357
+ ],
81358
+ ops: [
81359
+ "cli-reference",
81360
+ "compilation",
81361
+ "deployment",
81362
+ "export-interface",
81363
+ "debugging",
81364
+ "error-codes"
81365
+ ],
81366
+ full: [
81367
+ "concepts",
81368
+ "tutorial",
81369
+ "jsdoc-grammar",
81370
+ "advanced-annotations",
81371
+ "built-in-nodes",
81372
+ "cli-reference",
81373
+ "compilation",
81374
+ "debugging",
81375
+ "deployment",
81376
+ "error-codes",
81377
+ "export-interface",
81378
+ "iterative-development",
81379
+ "marketplace",
81380
+ "node-conversion",
81381
+ "patterns",
81382
+ "scaffold"
81383
+ ]
81384
+ };
81385
+ var PRESET_NAMES = Object.keys(PRESETS);
81386
+ var STANDALONE_PREAMBLE = `# Flow Weaver Reference
81387
+
81388
+ Flow Weaver is a TypeScript workflow compiler. You write plain .ts files with
81389
+ JSDoc annotations (@flowWeaver nodeType, @flowWeaver workflow, @input, @output,
81390
+ @connect, @node, @scope). The compiler parses these annotations, validates the
81391
+ graph, and generates executable code inline. The source file is the workflow:
81392
+ no JSON configs, no YAML, no separate graph files.
81393
+
81394
+ Key concepts: node types define reusable processing steps with typed input/output
81395
+ ports. Workflows instantiate nodes and connect their ports. Start and Exit are
81396
+ implicit boundary nodes. The compiler handles execution ordering, type checking,
81397
+ and code generation.`;
81398
+ function buildAssistantPreamble() {
81399
+ const allSlugs = listTopics().map((t) => t.slug);
81400
+ return `# Flow Weaver Context
81401
+
81402
+ You have Flow Weaver MCP tools available (fw_ prefix). Use them to create,
81403
+ modify, validate, compile, and inspect workflows without manual file editing.
81404
+
81405
+ For documentation not included below, call fw_docs(action="read", topic="<slug>").
81406
+ Available topic slugs: ${allSlugs.join(", ")}.
81407
+
81408
+ Tool quick reference:
81409
+ - fw_create_model: Build workflow from structured description (steps + flow path)
81410
+ - fw_implement_node: Replace a declare stub with a real function body
81411
+ - fw_modify / fw_modify_batch: Add/remove nodes, connections, rename, reposition
81412
+ - fw_validate: Check for errors after any change
81413
+ - fw_describe: Inspect structure. Use format "text" for readable, "json" for data
81414
+ - fw_diagram: Visualize. Prefer format "ascii-compact" in chat contexts
81415
+ - fw_compile: Generate executable TypeScript from annotations
81416
+ - fw_docs: Look up reference docs by topic slug
81417
+ - fw_scaffold: Create from templates (sequential, foreach, ai-agent, etc.)
81418
+
81419
+ File conventions: .ts extension, camelCase node names, PascalCase workflow names.`;
81420
+ }
81421
+ function resolveTopics(preset, explicit, add) {
81422
+ const base = explicit ?? PRESETS[preset];
81423
+ const combined = add ? [...base, ...add] : base;
81424
+ return [...new Set(combined)];
81425
+ }
81426
+ function buildGrammarSection() {
81427
+ const grammars = getAllGrammars();
81428
+ const allProductions = [
81429
+ ...grammars.port,
81430
+ ...grammars.node,
81431
+ ...grammars.connect,
81432
+ ...grammars.position,
81433
+ ...grammars.scope
81434
+ ];
81435
+ const ebnf = serializedToEBNF(allProductions);
81436
+ return `## JSDoc Annotation Grammar (EBNF)
81437
+
81438
+ \`\`\`ebnf
81439
+ ${ebnf}
81440
+ \`\`\``;
81441
+ }
81442
+ function buildContext(options = {}) {
81443
+ const profile = options.profile ?? "standalone";
81444
+ const preset = options.preset ?? "core";
81445
+ const includeGrammar = options.includeGrammar ?? true;
81446
+ const topicSlugs = resolveTopics(preset, options.topics, options.addTopics);
81447
+ const sections = [];
81448
+ if (profile === "standalone") {
81449
+ sections.push(STANDALONE_PREAMBLE);
81450
+ } else {
81451
+ sections.push(buildAssistantPreamble());
81452
+ }
81453
+ if (includeGrammar) {
81454
+ sections.push(buildGrammarSection());
81455
+ }
81456
+ let topicCount = 0;
81457
+ const includedSlugs = [];
81458
+ for (const slug of topicSlugs) {
81459
+ const doc = readTopic(slug, true);
81460
+ if (!doc) continue;
81461
+ let body = doc.content;
81462
+ if (body.startsWith("# ")) {
81463
+ const lines = body.split("\n");
81464
+ let startLine = 1;
81465
+ if (lines.length > 1 && lines[1].trim() && !lines[1].startsWith("#")) {
81466
+ startLine = 2;
81467
+ }
81468
+ body = lines.slice(startLine).join("\n").replace(/^\n+/, "");
81469
+ }
81470
+ const bodyLines = body.split("\n");
81471
+ let inCode = false;
81472
+ for (let i = 0; i < bodyLines.length; i++) {
81473
+ if (bodyLines[i].trimStart().startsWith("```")) {
81474
+ inCode = !inCode;
81475
+ continue;
81476
+ }
81477
+ if (!inCode && bodyLines[i].match(/^#{1,5}\s/)) {
81478
+ bodyLines[i] = "##" + bodyLines[i];
81479
+ }
81480
+ }
81481
+ body = bodyLines.join("\n");
81482
+ const heading = doc.name || slug;
81483
+ sections.push(`## ${heading}
81484
+
81485
+ ${body}`);
81486
+ topicCount++;
81487
+ includedSlugs.push(slug);
81488
+ }
81489
+ const content = sections.join("\n\n---\n\n");
81490
+ const lineCount = content.split("\n").length;
81491
+ return {
81492
+ content,
81493
+ topicCount,
81494
+ lineCount,
81495
+ topicSlugs: includedSlugs,
81496
+ profile
81497
+ };
81498
+ }
81499
+
81500
+ // src/cli/commands/init-personas.ts
81501
+ var PERSONA_CHOICES = [
81502
+ { value: "nocode", name: "AI does everything", description: "Describe in plain language, AI builds the workflow. Guided setup included." },
81503
+ { value: "vibecoder", name: "AI-assisted coding", description: "Collaborate with AI, iterate by describing changes. Hands-on setup with AI." },
81504
+ { value: "lowcode", name: "Template-based", description: "Pick a template, customize the code. AI helps with initial setup." },
81505
+ { value: "expert", name: "Full TypeScript", description: "Write workflows from scratch. Minimal setup, full control." }
81506
+ ];
81507
+ var PERSONA_CONFIRMATIONS = {
81508
+ nocode: "AI will handle the code. You describe, it builds.",
81509
+ vibecoder: "You and AI will build this together.",
81510
+ lowcode: "Starting from a template, you customize from there.",
81511
+ expert: null
81512
+ };
81513
+ var USE_CASE_CHOICES = [
81514
+ { value: "data", name: "Data pipeline", description: "Process, transform, and validate data" },
81515
+ { value: "ai", name: "AI agent", description: "LLM with tools, reasoning, or retrieval" },
81516
+ { value: "api", name: "API / webhook", description: "HTTP endpoints and integrations" },
81517
+ { value: "automation", name: "Automation", description: "Conditional logic, error handling, routing" },
81518
+ { value: "cicd", name: "CI/CD pipeline", description: "Test, build, and deploy workflows" },
81519
+ { value: "minimal", name: "Something else", description: "Start with a minimal template" }
81520
+ ];
81521
+ var USE_CASE_TEMPLATES = {
81522
+ data: { default: "sequential", all: ["sequential", "foreach", "aggregator"] },
81523
+ ai: { default: "ai-agent", all: ["ai-agent", "ai-react", "ai-rag", "ai-chat"] },
81524
+ api: { default: "webhook", all: ["webhook"] },
81525
+ automation: { default: "conditional", all: ["conditional", "error-handler"] },
81526
+ cicd: { default: "cicd-test-deploy", all: ["cicd-test-deploy", "cicd-docker", "cicd-multi-env", "cicd-matrix"] },
81527
+ minimal: { default: "sequential", all: ["sequential"] }
81528
+ };
81529
+ function selectTemplateForPersona(persona, useCase) {
81530
+ const mapping = USE_CASE_TEMPLATES[useCase];
81531
+ if (!mapping) {
81532
+ return { template: "sequential" };
81533
+ }
81534
+ if (persona === "lowcode" && mapping.all.length > 1) {
81535
+ return { template: mapping.default, choices: mapping.all };
81536
+ }
81537
+ return { template: mapping.default };
81538
+ }
81539
+ function getTemplateSubChoices(templateIds) {
81540
+ return templateIds.map((id) => {
81541
+ const tmpl = workflowTemplates.find((t) => t.id === id);
81542
+ return {
81543
+ value: id,
81544
+ name: id,
81545
+ description: tmpl?.description ?? ""
81546
+ };
81547
+ });
81548
+ }
81549
+ function extractWorkflowPreview(workflowCode) {
81550
+ const pathMatches = workflowCode.match(/@path\s+(.+)/g);
81551
+ if (pathMatches && pathMatches.length > 0) {
81552
+ const raw = pathMatches[0].replace(/@path\s+/, "").trim();
81553
+ const steps = raw.split(/\s*->\s*/);
81554
+ const labelMap = buildLabelMap(workflowCode);
81555
+ const labeled = steps.map((step) => labelMap.get(step) ?? step);
81556
+ return labeled.join(" \u2500\u2500\u25B6 ");
81557
+ }
81558
+ const nodeAnnotations = workflowCode.match(/@node\s+(\w+)\s+\w+/g);
81559
+ if (nodeAnnotations && nodeAnnotations.length > 0) {
81560
+ const labelMap = buildLabelMap(workflowCode);
81561
+ const names = nodeAnnotations.map((m) => {
81562
+ const id = m.replace(/@node\s+/, "").split(/\s+/)[0];
81563
+ return labelMap.get(id) ?? id;
81564
+ });
81565
+ return ["Start", ...names, "Exit"].join(" \u2500\u2500\u25B6 ");
81566
+ }
81567
+ return null;
81568
+ }
81569
+ function buildLabelMap(code) {
81570
+ const map3 = /* @__PURE__ */ new Map();
81571
+ map3.set("Start", "Start");
81572
+ map3.set("Exit", "Exit");
81573
+ const nodeRegex = /@node\s+(\w+)\s+(\w+)/g;
81574
+ const instanceToType = /* @__PURE__ */ new Map();
81575
+ let match2;
81576
+ while ((match2 = nodeRegex.exec(code)) !== null) {
81577
+ instanceToType.set(match2[1], match2[2]);
81578
+ }
81579
+ const labelRegex = /@label\s+(.+)\n[\s\S]*?function\s+(\w+)/g;
81580
+ const typeToLabel = /* @__PURE__ */ new Map();
81581
+ while ((match2 = labelRegex.exec(code)) !== null) {
81582
+ typeToLabel.set(match2[2], match2[1].trim());
81583
+ }
81584
+ for (const [instanceId, typeName] of instanceToType) {
81585
+ const label = typeToLabel.get(typeName);
81586
+ if (label) {
81587
+ map3.set(instanceId, label);
81588
+ }
81589
+ }
81590
+ return map3;
81591
+ }
81592
+ var FILE_DESCRIPTIONS = {
81593
+ "package.json": "Dependencies and npm scripts",
81594
+ "tsconfig.json": "TypeScript configuration",
81595
+ ".gitignore": "Git ignore rules",
81596
+ ".flowweaver/config.yaml": "Flow Weaver project settings",
81597
+ "src/main.ts": "Runs the workflow with sample input"
81598
+ };
81599
+ function workflowFileDesc(persona) {
81600
+ if (persona === "nocode") return "Your workflow (AI will modify this for you)";
81601
+ return "Your workflow definition";
81602
+ }
81603
+ function generateReadme(projectName, persona, _template) {
81604
+ const lines = [`# ${projectName}`, ""];
81605
+ if (persona === "nocode") {
81606
+ lines.push(
81607
+ "A Flow Weaver workflow project configured for AI-assisted development.",
81608
+ "",
81609
+ "## Working with AI",
81610
+ "",
81611
+ "Open this project in your AI editor (Claude Code, Cursor, VS Code) and describe",
81612
+ "what you want to build:",
81613
+ "",
81614
+ '- "Create a workflow that processes customer orders"',
81615
+ '- "Add retry logic to the data pipeline"',
81616
+ '- "Show me a diagram of the current workflow"',
81617
+ "",
81618
+ "The AI has access to Flow Weaver's 48 tools and will create, modify, and validate",
81619
+ "workflows for you.",
81620
+ ""
81621
+ );
81622
+ } else if (persona === "vibecoder") {
81623
+ lines.push(
81624
+ "A Flow Weaver workflow project.",
81625
+ "",
81626
+ "## Development",
81627
+ "",
81628
+ "```sh",
81629
+ "npm run dev # Compile and run",
81630
+ "npm run compile # Compile only",
81631
+ "npm run validate # Check for errors",
81632
+ "```",
81633
+ "",
81634
+ "## AI-Assisted Editing",
81635
+ "",
81636
+ "With your AI editor connected, you can describe changes in plain language:",
81637
+ "",
81638
+ '- "Add error handling to the pipeline"',
81639
+ '- "Replace the mock LLM with OpenAI"',
81640
+ '- "Add a validation step before processing"',
81641
+ ""
81642
+ );
81643
+ } else if (persona === "lowcode") {
81644
+ lines.push(
81645
+ "A Flow Weaver workflow project.",
81646
+ "",
81647
+ "## Development",
81648
+ "",
81649
+ "```sh",
81650
+ "npm run dev # Compile and run",
81651
+ "npm run compile # Compile only",
81652
+ "npm run validate # Check for errors",
81653
+ "```",
81654
+ "",
81655
+ "## Templates",
81656
+ "",
81657
+ "Browse and add more workflows:",
81658
+ "",
81659
+ "```sh",
81660
+ "flow-weaver templates # List all templates",
81661
+ "flow-weaver create workflow <template> <file> # Add a workflow",
81662
+ "flow-weaver describe src/*.ts --format ascii # See workflow structure",
81663
+ "```",
81664
+ ""
81665
+ );
81666
+ } else {
81667
+ lines.push(
81668
+ "A Flow Weaver workflow project.",
81669
+ "",
81670
+ "## Commands",
81671
+ "",
81672
+ "```sh",
81673
+ "npm run dev # Compile and run",
81674
+ "npm run compile # Compile only",
81675
+ "npm run validate # Check for errors",
81676
+ "```",
81677
+ ""
81678
+ );
81679
+ }
81680
+ lines.push(
81681
+ "## Learn more",
81682
+ "",
81683
+ "- `flow-weaver docs` to browse reference documentation",
81684
+ "- `flow-weaver mcp-setup` to connect AI editors",
81685
+ ""
81686
+ );
81687
+ return lines.join("\n");
81688
+ }
81689
+ function generateExampleWorkflow(projectName) {
81690
+ const name = projectName.replace(/[-_.]+(.)?/g, (_, c) => c ? c.toUpperCase() : "").replace(/^[^a-zA-Z_$]+/, "").replace(/^./, (c) => c.toLowerCase());
81691
+ const fnName = (name || "example") + "Example";
81692
+ return `/**
81693
+ * Example: a minimal workflow to study and experiment with.
81694
+ * Copy patterns from here into your main workflow.
81695
+ */
81696
+
81697
+ /**
81698
+ * @flowWeaver nodeType
81699
+ * @expression
81700
+ * @label Greet
81701
+ * @input name [order:0] - Name to greet
81702
+ * @output greeting [order:0] - Greeting message
81703
+ */
81704
+ function greet(name: string): { greeting: string } {
81705
+ return { greeting: \`Hello, \${name}!\` };
81706
+ }
81707
+
81708
+ /**
81709
+ * @flowWeaver nodeType
81710
+ * @expression
81711
+ * @label Uppercase
81712
+ * @input text [order:0] - Text to uppercase
81713
+ * @output result [order:0] - Uppercased text
81714
+ */
81715
+ function uppercase(text: string): { result: string } {
81716
+ return { result: text.toUpperCase() };
81717
+ }
81718
+
81719
+ /**
81720
+ * @flowWeaver workflow
81721
+ * @node greeter greet [position: -200 0]
81722
+ * @node upper uppercase [position: 100 0]
81723
+ * @position Start -500 0
81724
+ * @position Exit 400 0
81725
+ * @path Start -> greeter -> upper -> Exit
81726
+ * @connect greeter.greeting -> upper.text
81727
+ * @param execute [order:0] - Execute
81728
+ * @param name [order:1] - Name to greet
81729
+ * @returns onSuccess [order:0] - On Success
81730
+ * @returns onFailure [order:1] - On Failure
81731
+ * @returns result [order:2] - Final greeting
81732
+ */
81733
+ export function ${fnName}(
81734
+ execute: boolean,
81735
+ params: { name: string }
81736
+ ): { onSuccess: boolean; onFailure: boolean; result: string } {
81737
+ throw new Error("Compile with: flow-weaver compile <file>");
81738
+ }
81739
+ `;
81740
+ }
81741
+ function printNextSteps(opts) {
81742
+ const { projectName, persona, displayDir, installSkipped, workflowCode, workflowFile, agentLaunched } = opts;
81743
+ if (workflowCode) {
81744
+ const preview = extractWorkflowPreview(workflowCode);
81745
+ if (preview) {
81746
+ logger.newline();
81747
+ logger.log(` ${logger.bold("Your workflow")}`);
81748
+ logger.newline();
81749
+ logger.log(` ${logger.dim(preview)}`);
81750
+ }
81751
+ }
81752
+ if (persona !== "expert") {
81753
+ logger.newline();
81754
+ logger.log(` ${logger.bold("Project files")}`);
81755
+ logger.newline();
81756
+ const wfDesc = workflowFileDesc(persona);
81757
+ logger.log(` ${logger.highlight(`src/${workflowFile}`)}${pad(`src/${workflowFile}`, 32)}${wfDesc}`);
81758
+ logger.log(` ${logger.highlight("src/main.ts")}${pad("src/main.ts", 32)}${FILE_DESCRIPTIONS["src/main.ts"]}`);
81759
+ logger.log(` ${logger.highlight("package.json")}${pad("package.json", 32)}${FILE_DESCRIPTIONS["package.json"]}`);
81760
+ logger.log(` ${logger.highlight("tsconfig.json")}${pad("tsconfig.json", 32)}${FILE_DESCRIPTIONS["tsconfig.json"]}`);
81761
+ }
81762
+ logger.newline();
81763
+ logger.log(` ${logger.bold("Next steps")}`);
81764
+ logger.newline();
81765
+ if (displayDir) {
81766
+ logger.log(` cd ${displayDir}`);
81767
+ }
81768
+ if (installSkipped) {
81769
+ logger.log(" npm install");
81770
+ }
81771
+ logger.log(" npm run dev");
81772
+ if (!agentLaunched) {
81773
+ if (persona === "nocode") {
81774
+ printNocodeGuidance(projectName);
81775
+ } else if (persona === "vibecoder") {
81776
+ printVibecoderGuidance();
81777
+ } else if (persona === "lowcode") {
81778
+ printLowcodeGuidance();
81779
+ } else {
81780
+ printExpertGuidance();
81781
+ }
81782
+ }
81783
+ logger.newline();
81784
+ }
81785
+ function printNocodeGuidance(_projectName) {
81786
+ logger.newline();
81787
+ logger.log(` ${logger.bold("Your project is ready for AI-assisted building.")}`);
81788
+ logger.log(" Open it in your AI editor and describe what you want:");
81789
+ logger.newline();
81790
+ logger.log(` ${logger.dim('"Change this to fetch data from an API and validate the response"')}`);
81791
+ logger.log(` ${logger.dim('"Add error handling so failures get logged and retried"')}`);
81792
+ logger.log(` ${logger.dim('"Show me a diagram of my workflow"')}`);
81793
+ logger.newline();
81794
+ logger.log(` ${logger.bold("Useful commands")}`);
81795
+ logger.newline();
81796
+ logger.log(` flow-weaver run src/*.ts ${logger.dim("Run your workflow")}`);
81797
+ logger.log(` flow-weaver diagram src/*.ts ${logger.dim("See a visual diagram")}`);
81798
+ logger.log(` flow-weaver mcp-setup ${logger.dim("Connect more AI editors")}`);
81799
+ }
81800
+ function printVibecoderGuidance() {
81801
+ logger.newline();
81802
+ logger.log(" With your AI editor connected, try:");
81803
+ logger.newline();
81804
+ logger.log(` ${logger.dim('"Add a retry loop when the model call fails"')}`);
81805
+ logger.log(` ${logger.dim('"Add a tool that searches a knowledge base"')}`);
81806
+ logger.newline();
81807
+ logger.log(` ${logger.bold("Commands you'll use")}`);
81808
+ logger.newline();
81809
+ logger.log(` flow-weaver diagram src/*.ts ${logger.dim("See a visual diagram")}`);
81810
+ logger.log(` flow-weaver validate src/*.ts ${logger.dim("Check for errors")}`);
81811
+ logger.log(` flow-weaver templates ${logger.dim("Browse all templates")}`);
81812
+ }
81813
+ function printLowcodeGuidance() {
81814
+ logger.newline();
81815
+ logger.log(` ${logger.bold("Explore and learn")}`);
81816
+ logger.newline();
81817
+ logger.log(` flow-weaver templates ${logger.dim("List all 16 workflow templates")}`);
81818
+ logger.log(` flow-weaver create workflow ... ${logger.dim("Add another workflow")}`);
81819
+ logger.log(` flow-weaver describe src/*.ts ${logger.dim("See workflow structure")}`);
81820
+ logger.log(` flow-weaver docs annotations ${logger.dim("Read the annotation reference")}`);
81821
+ logger.newline();
81822
+ logger.log(` Your project includes an example in ${logger.highlight("examples/")} to study.`);
81823
+ }
81824
+ function printExpertGuidance() {
81825
+ logger.newline();
81826
+ logger.log(` flow-weaver mcp-setup ${logger.dim("Connect AI editors (Claude, Cursor, VS Code)")}`);
81827
+ logger.log(` flow-weaver docs ${logger.dim("Browse reference docs")}`);
81828
+ }
81829
+ function pad(displayName, width) {
81830
+ const padding = Math.max(1, width - displayName.length);
81831
+ return " ".repeat(padding);
81832
+ }
81833
+ var AGENT_CONTEXT_PRESETS = {
81834
+ nocode: "core",
81835
+ vibecoder: "authoring",
81836
+ lowcode: "authoring",
81837
+ expert: "authoring"
81838
+ };
81839
+ var AGENT_PROMPTS = {
81840
+ nocode: `Before doing anything else, call fw_context(preset="core", profile="assistant") to learn Flow Weaver's annotation syntax and workflow conventions.
81841
+
81842
+ I just created a new Flow Weaver project called "{name}" using the {template} template.
81843
+ Help me set it up step by step:
81844
+
81845
+ 1. Show the current workflow as a diagram (use fw_diagram, ascii-compact)
81846
+ 2. Walk me through what each step does in plain language
81847
+ 3. Ask me what I want this workflow to do
81848
+ 4. Based on my answer:
81849
+ - Customize the workflow (add/remove/rename steps with fw_modify)
81850
+ - Implement each step with real working code (fw_implement_node)
81851
+ - Set up supporting files if needed (.env template, basic tests)
81852
+ 5. Show the final result as a step list and diagram
81853
+
81854
+ Keep everything in plain language. Don't show code unless I ask.`,
81855
+ vibecoder: `Before doing anything else, call fw_context(preset="authoring", profile="assistant") to load Flow Weaver reference.
81856
+
81857
+ I just created a new Flow Weaver project called "{name}" using the {template} template.
81858
+ Let's set it up together:
81859
+
81860
+ 1. Show the workflow diagram and briefly explain the structure
81861
+ 2. Ask what I want to build, then iterate with me
81862
+ 3. Customize the workflow, implement the nodes, add supporting files
81863
+ 4. Show code when it's relevant, I'm comfortable reading and tweaking it
81864
+ 5. Show the final diagram when we're done`,
81865
+ lowcode: `Before doing anything else, call fw_context(preset="authoring", profile="assistant") to load Flow Weaver reference.
81866
+
81867
+ I just created a new Flow Weaver project called "{name}" using the {template} template.
81868
+ Help me customize it:
81869
+
81870
+ 1. Show the workflow diagram and explain what the template gives me
81871
+ 2. Ask what I want this workflow to do
81872
+ 3. Customize: rename nodes, adjust connections, implement the functions
81873
+ 4. Add supporting files if needed (.env, tests)
81874
+ 5. Show the final diagram
81875
+
81876
+ I prefer working from templates and making targeted changes.`,
81877
+ expert: `Before doing anything else, call fw_context(preset="authoring", profile="assistant") to load Flow Weaver reference.
81878
+
81879
+ New Flow Weaver project "{name}" (template: {template}).
81880
+ Show the workflow diagram and current implementation status (fw_workflow_status).
81881
+ Then ask what I'd like to build.`
81882
+ };
81883
+ function generateAgentPrompt(projectName, persona, template) {
81884
+ return AGENT_PROMPTS[persona].replace(/\{name\}/g, projectName).replace(/\{template\}/g, template);
81885
+ }
81886
+ function generateEditorPrompt(projectName, persona, template) {
81887
+ const preset = AGENT_CONTEXT_PRESETS[persona];
81888
+ const bootstrap = `Start by calling fw_context(preset="${preset}", profile="assistant") to learn Flow Weaver.`;
81889
+ if (persona === "nocode") {
81890
+ return `${bootstrap}
81891
+ This is a Flow Weaver project called "${projectName}" using the ${template} template. Show me the workflow diagram, walk me through what each step does in plain language, then ask me what I want to build. Keep it simple, no code.`;
81892
+ }
81893
+ if (persona === "vibecoder") {
81894
+ return `${bootstrap}
81895
+ This is a Flow Weaver project called "${projectName}" using the ${template} template. Show me the workflow diagram, then let's iterate on it together. I'll describe what I want and you handle the implementation.`;
81896
+ }
81897
+ if (persona === "lowcode") {
81898
+ return `${bootstrap}
81899
+ This is a Flow Weaver project called "${projectName}" using the ${template} template. Show me the workflow diagram and explain the template, then help me customize it for my use case.`;
81900
+ }
81901
+ return `${bootstrap}
81902
+ Flow Weaver project "${projectName}" (template: ${template}). Show the workflow diagram and implementation status.`;
81903
+ }
81904
+ function generateSetupPromptFile(projectName, persona, template, filesCreated) {
81905
+ const prompt = generateAgentPrompt(projectName, persona, template);
81906
+ const contextResult = buildContext({ preset: "core", profile: "assistant" });
81907
+ const lines = [
81908
+ `# ${projectName} Setup`,
81909
+ "",
81910
+ 'Paste this into your AI editor chat, or ask it to "follow the instructions in PROJECT_SETUP.md".',
81911
+ "",
81912
+ "---",
81913
+ "",
81914
+ prompt,
81915
+ "",
81916
+ "---",
81917
+ "",
81918
+ "## Flow Weaver Reference",
81919
+ "",
81920
+ "The following is embedded Flow Weaver documentation so you can work with this project",
81921
+ "even before MCP tools are connected. For deeper topics, call `fw_docs` once MCP is available.",
81922
+ "",
81923
+ contextResult.content,
81924
+ "",
81925
+ "---",
81926
+ "",
81927
+ "## Project context",
81928
+ "",
81929
+ `- **Template**: ${template}`,
81930
+ `- **Persona**: ${persona}`,
81931
+ "",
81932
+ "### Files created",
81933
+ "",
81934
+ ...filesCreated.map((f) => `- \`${f}\``),
81935
+ "",
81936
+ "### Available Flow Weaver MCP tools",
81937
+ "",
81938
+ "Your AI editor has access to 48 Flow Weaver tools including:",
81939
+ "- `fw_diagram` - Generate workflow diagrams",
81940
+ "- `fw_modify` / `fw_modify_batch` - Add/remove/rename nodes and connections",
81941
+ "- `fw_implement_node` - Write function bodies for stub nodes",
81942
+ "- `fw_validate` - Check for errors",
81943
+ "- `fw_compile` - Generate executable code",
81944
+ "- `fw_describe` - Inspect workflow structure",
81945
+ "",
81946
+ "*Delete this file after your initial setup is complete.*",
81947
+ ""
81948
+ ];
81949
+ return lines.join("\n");
81950
+ }
81951
+ function printCopyablePrompt(prompt) {
81952
+ const maxInner = 70;
81953
+ const wrapped = [];
81954
+ for (const raw of prompt.split("\n")) {
81955
+ if (raw.length <= maxInner) {
81956
+ wrapped.push(raw);
81957
+ } else {
81958
+ let remaining = raw;
81959
+ while (remaining.length > maxInner) {
81960
+ let breakAt = remaining.lastIndexOf(" ", maxInner);
81961
+ if (breakAt <= 0) breakAt = maxInner;
81962
+ wrapped.push(remaining.slice(0, breakAt));
81963
+ remaining = remaining.slice(breakAt).replace(/^ /, "");
81964
+ }
81965
+ if (remaining) wrapped.push(remaining);
81966
+ }
81967
+ }
81968
+ const width = maxInner + 2;
81969
+ logger.newline();
81970
+ logger.log(` ${logger.bold("Paste this into your AI editor to get started:")}`);
81971
+ logger.newline();
81972
+ logger.log(` ${"\u250C" + "\u2500".repeat(width) + "\u2510"}`);
81973
+ for (const line of wrapped) {
81974
+ const padded = line + " ".repeat(Math.max(0, maxInner - line.length));
81975
+ logger.log(` \u2502 ${padded} \u2502`);
81976
+ }
81977
+ logger.log(` ${"\u2514" + "\u2500".repeat(width) + "\u2518"}`);
81978
+ }
81979
+ var AGENT_LAUNCH_DEFAULTS = {
81980
+ nocode: true,
81981
+ vibecoder: true,
81982
+ lowcode: true,
81983
+ expert: false
81984
+ };
81985
+
81986
+ // src/cli/commands/init.ts
80773
81987
  var PROJECT_NAME_RE = /^[a-zA-Z0-9][-a-zA-Z0-9_.]*$/;
80774
81988
  function validateProjectName(name) {
80775
81989
  if (!name) return "Project name cannot be empty";
@@ -80787,14 +82001,17 @@ function isNonInteractive() {
80787
82001
  return !process.stdin.isTTY;
80788
82002
  }
80789
82003
  var VALID_TEMPLATES = workflowTemplates.map((t) => t.id);
82004
+ var VALID_PERSONAS = ["nocode", "vibecoder", "lowcode", "expert"];
82005
+ var VALID_USE_CASES = ["data", "ai", "api", "automation", "cicd", "minimal"];
80790
82006
  async function resolveInitConfig(dirArg, options) {
80791
82007
  const skipPrompts = options.yes || isNonInteractive();
80792
82008
  const force = options.force ?? false;
82009
+ const hasExplicitTemplate = !!options.template;
80793
82010
  let projectName;
80794
82011
  if (options.name) {
80795
82012
  projectName = options.name;
80796
82013
  } else if (dirArg) {
80797
- projectName = path16.basename(dirArg);
82014
+ projectName = path18.basename(dirArg);
80798
82015
  } else if (skipPrompts) {
80799
82016
  projectName = "my-project";
80800
82017
  } else {
@@ -80808,49 +82025,113 @@ async function resolveInitConfig(dirArg, options) {
80808
82025
  if (valid !== true) {
80809
82026
  throw new Error(valid);
80810
82027
  }
80811
- const targetDir = path16.resolve(dirArg ?? projectName);
82028
+ const targetDir = path18.resolve(dirArg ?? projectName);
82029
+ let persona;
82030
+ if (options.preset) {
82031
+ if (!VALID_PERSONAS.includes(options.preset)) {
82032
+ throw new Error(`Unknown preset "${options.preset}". Available: ${VALID_PERSONAS.join(", ")}`);
82033
+ }
82034
+ persona = options.preset;
82035
+ } else if (skipPrompts || hasExplicitTemplate) {
82036
+ persona = "expert";
82037
+ } else {
82038
+ persona = await dist_default5({
82039
+ message: "How do you plan to build?",
82040
+ choices: PERSONA_CHOICES,
82041
+ default: "vibecoder"
82042
+ });
82043
+ }
82044
+ if (!skipPrompts) {
82045
+ const confirmation = PERSONA_CONFIRMATIONS[persona];
82046
+ if (confirmation) {
82047
+ logger.log(` ${logger.dim(confirmation)}`);
82048
+ logger.newline();
82049
+ }
82050
+ }
80812
82051
  let template;
80813
- if (options.template) {
82052
+ let useCase;
82053
+ if (hasExplicitTemplate) {
80814
82054
  template = options.template;
80815
82055
  if (!VALID_TEMPLATES.includes(template)) {
80816
82056
  throw new Error(`Unknown template "${template}". Available: ${VALID_TEMPLATES.join(", ")}`);
80817
82057
  }
80818
- } else if (skipPrompts) {
80819
- template = "sequential";
82058
+ } else if (persona === "expert") {
82059
+ if (skipPrompts) {
82060
+ template = "sequential";
82061
+ } else {
82062
+ template = await dist_default5({
82063
+ message: "Workflow template:",
82064
+ choices: [
82065
+ new Separator("\u2500\u2500 Data Processing \u2500\u2500"),
82066
+ { value: "sequential", name: "sequential", description: "Linear pipeline" },
82067
+ { value: "foreach", name: "foreach", description: "Batch iteration" },
82068
+ { value: "aggregator", name: "aggregator", description: "Collect and aggregate results" },
82069
+ new Separator("\u2500\u2500 Automation \u2500\u2500"),
82070
+ { value: "conditional", name: "conditional", description: "Route by condition" },
82071
+ new Separator("\u2500\u2500 AI \u2500\u2500"),
82072
+ { value: "ai-agent", name: "ai-agent", description: "LLM agent with tool calling" },
82073
+ { value: "ai-react", name: "ai-react", description: "ReAct pattern" },
82074
+ { value: "ai-rag", name: "ai-rag", description: "Retrieval-Augmented Generation" },
82075
+ { value: "ai-chat", name: "ai-chat", description: "Conversational AI" },
82076
+ new Separator("\u2500\u2500 Durable \u2500\u2500"),
82077
+ { value: "ai-agent-durable", name: "ai-agent-durable", description: "Durable agent with approval gate" },
82078
+ { value: "ai-pipeline-durable", name: "ai-pipeline-durable", description: "Durable data pipeline" },
82079
+ new Separator("\u2500\u2500 Integration \u2500\u2500"),
82080
+ { value: "webhook", name: "webhook", description: "HTTP webhook handler" },
82081
+ new Separator("\u2500\u2500 Utility \u2500\u2500"),
82082
+ { value: "error-handler", name: "error-handler", description: "Error handling and recovery" },
82083
+ new Separator("\u2500\u2500 CI/CD \u2500\u2500"),
82084
+ { value: "cicd-test-deploy", name: "cicd-test-deploy", description: "Test and deploy pipeline" },
82085
+ { value: "cicd-docker", name: "cicd-docker", description: "Docker build and push" },
82086
+ { value: "cicd-multi-env", name: "cicd-multi-env", description: "Multi-environment deploy" },
82087
+ { value: "cicd-matrix", name: "cicd-matrix", description: "Matrix build strategy" }
82088
+ ],
82089
+ default: "sequential"
82090
+ });
82091
+ }
80820
82092
  } else {
80821
- template = await dist_default5({
80822
- message: "Workflow template:",
80823
- choices: [
80824
- new Separator("\u2500\u2500 Data Processing \u2500\u2500"),
80825
- { value: "sequential", name: "sequential", description: "Linear pipeline" },
80826
- { value: "foreach", name: "foreach", description: "Batch iteration" },
80827
- { value: "aggregator", name: "aggregator", description: "Collect and aggregate results" },
80828
- new Separator("\u2500\u2500 Automation \u2500\u2500"),
80829
- { value: "conditional", name: "conditional", description: "Route by condition" },
80830
- new Separator("\u2500\u2500 AI \u2500\u2500"),
80831
- { value: "ai-agent", name: "ai-agent", description: "LLM agent with tool calling" },
80832
- { value: "ai-react", name: "ai-react", description: "ReAct pattern" },
80833
- { value: "ai-rag", name: "ai-rag", description: "Retrieval-Augmented Generation" },
80834
- { value: "ai-chat", name: "ai-chat", description: "Conversational AI" },
80835
- new Separator("\u2500\u2500 Durable \u2500\u2500"),
80836
- { value: "ai-agent-durable", name: "ai-agent-durable", description: "Durable agent with approval gate" },
80837
- { value: "ai-pipeline-durable", name: "ai-pipeline-durable", description: "Durable data pipeline" },
80838
- new Separator("\u2500\u2500 Integration \u2500\u2500"),
80839
- { value: "webhook", name: "webhook", description: "HTTP webhook handler" },
80840
- new Separator("\u2500\u2500 Utility \u2500\u2500"),
80841
- {
80842
- value: "error-handler",
80843
- name: "error-handler",
80844
- description: "Error handling and recovery"
80845
- }
80846
- ],
80847
- default: "sequential"
82093
+ if (options.useCase) {
82094
+ if (!VALID_USE_CASES.includes(options.useCase)) {
82095
+ throw new Error(`Unknown use case "${options.useCase}". Available: ${VALID_USE_CASES.join(", ")}`);
82096
+ }
82097
+ useCase = options.useCase;
82098
+ } else if (skipPrompts) {
82099
+ useCase = "data";
82100
+ } else {
82101
+ useCase = await dist_default5({
82102
+ message: "What are you building?",
82103
+ choices: USE_CASE_CHOICES,
82104
+ default: "data"
82105
+ });
82106
+ }
82107
+ const selection = selectTemplateForPersona(persona, useCase);
82108
+ if (selection.choices && !skipPrompts) {
82109
+ template = await dist_default5({
82110
+ message: "Pick a template:",
82111
+ choices: getTemplateSubChoices(selection.choices),
82112
+ default: selection.template
82113
+ });
82114
+ } else {
82115
+ template = selection.template;
82116
+ }
82117
+ }
82118
+ let mcp;
82119
+ if (options.mcp !== void 0) {
82120
+ mcp = options.mcp;
82121
+ } else if (skipPrompts) {
82122
+ mcp = false;
82123
+ } else if (persona === "nocode" || persona === "vibecoder") {
82124
+ mcp = await dist_default6({
82125
+ message: "Set up AI editor integration? (Claude Code, Cursor, VS Code, etc.)",
82126
+ default: true
80848
82127
  });
82128
+ } else {
82129
+ mcp = false;
80849
82130
  }
80850
82131
  let installDeps;
80851
82132
  if (options.install !== void 0) {
80852
82133
  installDeps = options.install;
80853
- } else if (skipPrompts) {
82134
+ } else if (skipPrompts || persona !== "expert") {
80854
82135
  installDeps = true;
80855
82136
  } else {
80856
82137
  installDeps = await dist_default6({ message: "Install dependencies (npm install)?", default: true });
@@ -80858,7 +82139,7 @@ async function resolveInitConfig(dirArg, options) {
80858
82139
  let gitInit;
80859
82140
  if (options.git !== void 0) {
80860
82141
  gitInit = options.git;
80861
- } else if (skipPrompts) {
82142
+ } else if (skipPrompts || persona !== "expert") {
80862
82143
  gitInit = true;
80863
82144
  } else {
80864
82145
  gitInit = await dist_default6({ message: "Initialize a git repository?", default: true });
@@ -80869,22 +82150,14 @@ async function resolveInitConfig(dirArg, options) {
80869
82150
  if (format !== "esm" && format !== "cjs") {
80870
82151
  throw new Error(`Invalid format "${format}". Use "esm" or "cjs".`);
80871
82152
  }
80872
- } else if (skipPrompts) {
82153
+ } else if (skipPrompts || persona !== "expert") {
80873
82154
  format = "esm";
80874
82155
  } else {
80875
82156
  format = await dist_default5({
80876
82157
  message: "Module format:",
80877
82158
  choices: [
80878
- {
80879
- value: "esm",
80880
- name: "ESM (Recommended)",
80881
- description: "ECMAScript modules (import/export)"
80882
- },
80883
- {
80884
- value: "cjs",
80885
- name: "CommonJS",
80886
- description: "CommonJS modules (require/module.exports)"
80887
- }
82159
+ { value: "esm", name: "ESM (Recommended)", description: "ECMAScript modules (import/export)" },
82160
+ { value: "cjs", name: "CommonJS", description: "CommonJS modules (require/module.exports)" }
80888
82161
  ],
80889
82162
  default: "esm"
80890
82163
  });
@@ -80896,10 +82169,13 @@ async function resolveInitConfig(dirArg, options) {
80896
82169
  format,
80897
82170
  install: installDeps,
80898
82171
  git: gitInit,
80899
- force
82172
+ force,
82173
+ persona,
82174
+ useCase,
82175
+ mcp
80900
82176
  };
80901
82177
  }
80902
- function generateProjectFiles(projectName, template, format = "esm") {
82178
+ function generateProjectFiles(projectName, template, format = "esm", persona = "expert") {
80903
82179
  const workflowName = toWorkflowName(projectName);
80904
82180
  const workflowFile = `${projectName}-workflow.ts`;
80905
82181
  const tmpl = getWorkflowTemplate(template);
@@ -80907,16 +82183,20 @@ function generateProjectFiles(projectName, template, format = "esm") {
80907
82183
  throw new Error(`Unknown template "${template}"`);
80908
82184
  }
80909
82185
  const workflowCode = tmpl.generate({ workflowName });
82186
+ const scripts = {
82187
+ dev: `npx flow-weaver compile src/${workflowFile} -o src && npx tsx src/main.ts`,
82188
+ start: "npx tsx src/main.ts",
82189
+ compile: `npx flow-weaver compile src/${workflowFile} -o src`,
82190
+ validate: `npx flow-weaver validate src/${workflowFile}`,
82191
+ doctor: "npx flow-weaver doctor"
82192
+ };
82193
+ if (persona !== "expert") {
82194
+ scripts.diagram = `npx flow-weaver diagram src/${workflowFile} --format ascii-compact`;
82195
+ }
80910
82196
  const packageJsonContent = {
80911
82197
  name: projectName,
80912
82198
  version: "1.0.0",
80913
- scripts: {
80914
- dev: `npx flow-weaver compile src/${workflowFile} -o src && npx tsx src/main.ts`,
80915
- start: "npx tsx src/main.ts",
80916
- compile: `npx flow-weaver compile src/${workflowFile} -o src`,
80917
- validate: `npx flow-weaver validate src/${workflowFile}`,
80918
- doctor: "npx flow-weaver doctor"
80919
- },
82199
+ scripts,
80920
82200
  dependencies: {
80921
82201
  "@synergenius/flow-weaver": "latest"
80922
82202
  },
@@ -81004,7 +82284,7 @@ dist/
81004
82284
  `;
81005
82285
  const configYaml = `defaultFileType: ts
81006
82286
  `;
81007
- return {
82287
+ const files = {
81008
82288
  "package.json": packageJson,
81009
82289
  "tsconfig.json": tsconfigJson,
81010
82290
  [`src/${workflowFile}`]: workflowCode,
@@ -81012,26 +82292,31 @@ dist/
81012
82292
  ".gitignore": gitignore,
81013
82293
  ".flowweaver/config.yaml": configYaml
81014
82294
  };
82295
+ files["README.md"] = generateReadme(projectName, persona, template);
82296
+ if (persona === "lowcode") {
82297
+ files["examples/example-workflow.ts"] = generateExampleWorkflow(projectName);
82298
+ }
82299
+ return files;
81015
82300
  }
81016
82301
  function scaffoldProject(targetDir, files, options) {
81017
82302
  const filesCreated = [];
81018
82303
  const filesSkipped = [];
81019
82304
  for (const [relativePath, content] of Object.entries(files)) {
81020
- const absPath = path16.join(targetDir, relativePath);
81021
- const dir = path16.dirname(absPath);
81022
- fs17.mkdirSync(dir, { recursive: true });
81023
- if (fs17.existsSync(absPath) && !options.force) {
82305
+ const absPath = path18.join(targetDir, relativePath);
82306
+ const dir = path18.dirname(absPath);
82307
+ fs19.mkdirSync(dir, { recursive: true });
82308
+ if (fs19.existsSync(absPath) && !options.force) {
81024
82309
  filesSkipped.push(relativePath);
81025
82310
  continue;
81026
82311
  }
81027
- fs17.writeFileSync(absPath, content, "utf8");
82312
+ fs19.writeFileSync(absPath, content, "utf8");
81028
82313
  filesCreated.push(relativePath);
81029
82314
  }
81030
82315
  return { filesCreated, filesSkipped };
81031
82316
  }
81032
82317
  function runNpmInstall(targetDir) {
81033
82318
  try {
81034
- execSync2("npm install", { cwd: targetDir, stdio: "pipe", timeout: 12e4 });
82319
+ execSync3("npm install", { cwd: targetDir, stdio: "pipe", timeout: 12e4 });
81035
82320
  return { success: true };
81036
82321
  } catch (err) {
81037
82322
  const message = err instanceof Error ? err.message : String(err);
@@ -81040,23 +82325,83 @@ function runNpmInstall(targetDir) {
81040
82325
  }
81041
82326
  function runGitInit(targetDir) {
81042
82327
  try {
81043
- execSync2("git init", { cwd: targetDir, stdio: "pipe", timeout: 1e4 });
82328
+ execSync3("git init", { cwd: targetDir, stdio: "pipe", timeout: 1e4 });
81044
82329
  return { success: true };
81045
82330
  } catch (err) {
81046
82331
  const message = err instanceof Error ? err.message : String(err);
81047
82332
  return { success: false, error: message };
81048
82333
  }
81049
82334
  }
82335
+ async function handleAgentHandoff(opts) {
82336
+ const { projectName, persona, template, targetDir, cliTools, guiTools, filesCreated } = opts;
82337
+ if (cliTools.length > 0) {
82338
+ const toolId = cliTools[0];
82339
+ const binary2 = CLI_TOOL_BINARY[toolId];
82340
+ const displayName = toolId === "claude" ? "Claude Code" : "Codex";
82341
+ const launchDefault = AGENT_LAUNCH_DEFAULTS[persona];
82342
+ const shouldLaunch = await dist_default6({
82343
+ message: `Launch ${displayName} to set up your project?`,
82344
+ default: launchDefault
82345
+ });
82346
+ if (shouldLaunch && binary2) {
82347
+ const prompt = generateAgentPrompt(projectName, persona, template);
82348
+ logger.newline();
82349
+ logger.log(` ${logger.dim(`Starting ${displayName}...`)}`);
82350
+ logger.newline();
82351
+ const child = spawn(binary2, [prompt], {
82352
+ cwd: targetDir,
82353
+ stdio: "inherit",
82354
+ env: { ...process.env }
82355
+ });
82356
+ child.on("error", (err) => {
82357
+ logger.error(`Failed to start ${displayName}: ${err.message}`);
82358
+ });
82359
+ return true;
82360
+ }
82361
+ }
82362
+ if (guiTools.length > 0 || cliTools.length > 0) {
82363
+ const promptAction = await dist_default5({
82364
+ message: "Generate a setup prompt for your editor?",
82365
+ choices: [
82366
+ { value: "terminal", name: "Print to terminal", description: "Copy and paste into your editor" },
82367
+ { value: "file", name: "Save as file", description: "Write PROJECT_SETUP.md to your project" },
82368
+ { value: "both", name: "Both" },
82369
+ { value: "skip", name: "Skip" }
82370
+ ],
82371
+ default: "terminal"
82372
+ });
82373
+ if (promptAction === "skip") return false;
82374
+ const editorPrompt = generateEditorPrompt(projectName, persona, template);
82375
+ if (promptAction === "terminal" || promptAction === "both") {
82376
+ printCopyablePrompt(editorPrompt);
82377
+ }
82378
+ if (promptAction === "file" || promptAction === "both") {
82379
+ const setupContent = generateSetupPromptFile(projectName, persona, template, filesCreated);
82380
+ const setupPath = path18.join(targetDir, "PROJECT_SETUP.md");
82381
+ fs19.writeFileSync(setupPath, setupContent, "utf8");
82382
+ const gitignorePath = path18.join(targetDir, ".gitignore");
82383
+ if (fs19.existsSync(gitignorePath)) {
82384
+ const existing = fs19.readFileSync(gitignorePath, "utf8");
82385
+ if (!existing.includes("PROJECT_SETUP.md")) {
82386
+ fs19.appendFileSync(gitignorePath, "PROJECT_SETUP.md\n", "utf8");
82387
+ }
82388
+ }
82389
+ logger.newline();
82390
+ logger.success(`Wrote ${logger.highlight("PROJECT_SETUP.md")} ${logger.dim("(delete after first setup)")}`);
82391
+ }
82392
+ }
82393
+ return false;
82394
+ }
81050
82395
  async function initCommand(dirArg, options) {
81051
82396
  try {
81052
82397
  const config2 = await resolveInitConfig(dirArg, options);
81053
- const pkgPath = path16.join(config2.targetDir, "package.json");
81054
- if (fs17.existsSync(pkgPath) && !config2.force) {
82398
+ const pkgPath = path18.join(config2.targetDir, "package.json");
82399
+ if (fs19.existsSync(pkgPath) && !config2.force) {
81055
82400
  throw new Error(
81056
82401
  `${config2.targetDir} already contains a package.json. Use --force to overwrite.`
81057
82402
  );
81058
82403
  }
81059
- const files = generateProjectFiles(config2.projectName, config2.template, config2.format);
82404
+ const files = generateProjectFiles(config2.projectName, config2.template, config2.format, config2.persona);
81060
82405
  const { filesCreated, filesSkipped } = scaffoldProject(config2.targetDir, files, {
81061
82406
  force: config2.force
81062
82407
  });
@@ -81074,9 +82419,9 @@ async function initCommand(dirArg, options) {
81074
82419
  gitResult = runGitInit(config2.targetDir);
81075
82420
  }
81076
82421
  const workflowFile = `${config2.projectName}-workflow.ts`;
81077
- const workflowPath = path16.join(config2.targetDir, "src", workflowFile);
82422
+ const workflowPath = path18.join(config2.targetDir, "src", workflowFile);
81078
82423
  let compileResult;
81079
- if (!options.json && fs17.existsSync(workflowPath)) {
82424
+ if (!options.json && fs19.existsSync(workflowPath)) {
81080
82425
  try {
81081
82426
  await compileCommand(workflowPath, { format: config2.format });
81082
82427
  compileResult = { success: true };
@@ -81085,14 +82430,42 @@ async function initCommand(dirArg, options) {
81085
82430
  compileResult = { success: false, error: message };
81086
82431
  }
81087
82432
  }
82433
+ let mcpConfigured;
82434
+ let mcpResult;
82435
+ if (config2.mcp && !options.json) {
82436
+ const spinner = logger.spinner("Configuring AI editors...");
82437
+ try {
82438
+ mcpResult = await runMcpSetupFromInit();
82439
+ mcpConfigured = mcpResult.configured;
82440
+ if (mcpResult.configured.length > 0) {
82441
+ spinner.stop(`${mcpResult.configured.join(", ")} configured`);
82442
+ } else if (mcpResult.failed.length > 0) {
82443
+ spinner.fail("MCP setup failed");
82444
+ } else {
82445
+ spinner.stop("No AI editors detected");
82446
+ }
82447
+ } catch {
82448
+ spinner.fail("MCP setup failed");
82449
+ }
82450
+ }
82451
+ let agentLaunched = false;
82452
+ let mcpCliTools = [];
82453
+ let mcpGuiTools = [];
82454
+ if (mcpResult) {
82455
+ mcpCliTools = mcpResult.cliTools;
82456
+ mcpGuiTools = mcpResult.guiTools;
82457
+ }
81088
82458
  const report = {
81089
82459
  projectDir: config2.targetDir,
81090
82460
  filesCreated,
81091
82461
  filesSkipped,
81092
82462
  template: config2.template,
81093
82463
  format: config2.format,
82464
+ persona: config2.persona,
81094
82465
  installResult,
81095
- gitResult
82466
+ gitResult,
82467
+ mcpConfigured,
82468
+ agentLaunched: false
81096
82469
  };
81097
82470
  if (options.json) {
81098
82471
  console.log(JSON.stringify(report, null, 2));
@@ -81100,10 +82473,16 @@ async function initCommand(dirArg, options) {
81100
82473
  }
81101
82474
  logger.newline();
81102
82475
  logger.success(`Created ${logger.highlight(config2.projectName)} ${logger.dim(`(${config2.template}, ${config2.format.toUpperCase()})`)}`);
81103
- logger.log(` ${filesCreated.join(", ")}`);
81104
82476
  if (filesSkipped.length > 0) {
81105
82477
  logger.warn(`Skipped ${filesSkipped.length} existing file(s)`);
81106
82478
  }
82479
+ if (installResult) {
82480
+ if (installResult.success) {
82481
+ logger.success("Dependencies installed");
82482
+ } else {
82483
+ logger.warn(`npm install failed: ${installResult.error}`);
82484
+ }
82485
+ }
81107
82486
  if (gitResult) {
81108
82487
  if (gitResult.success) {
81109
82488
  logger.success("Git initialized");
@@ -81118,18 +82497,40 @@ async function initCommand(dirArg, options) {
81118
82497
  logger.warn(`Compile failed: ${compileResult.error}`);
81119
82498
  }
81120
82499
  }
81121
- logger.newline();
81122
- logger.log(` ${logger.bold("Next steps")}`);
81123
- const relDir = path16.relative(process.cwd(), config2.targetDir);
82500
+ const workflowCode = files[`src/${workflowFile}`] ?? null;
82501
+ const relDir = path18.relative(process.cwd(), config2.targetDir);
81124
82502
  const displayDir = !relDir || relDir === "." ? null : relDir.startsWith("../../") ? config2.targetDir : relDir;
81125
- if (displayDir) {
81126
- logger.log(` cd ${displayDir}`);
82503
+ const skipAgent = options.agent === false || options.yes || isNonInteractive();
82504
+ if (mcpConfigured && mcpConfigured.length > 0 && !skipAgent) {
82505
+ try {
82506
+ agentLaunched = await handleAgentHandoff({
82507
+ projectName: config2.projectName,
82508
+ persona: config2.persona,
82509
+ template: config2.template,
82510
+ targetDir: config2.targetDir,
82511
+ cliTools: mcpCliTools,
82512
+ guiTools: mcpGuiTools,
82513
+ filesCreated
82514
+ });
82515
+ report.agentLaunched = agentLaunched;
82516
+ } catch (err) {
82517
+ if (err instanceof ExitPromptError4) return;
82518
+ }
81127
82519
  }
81128
- if (!config2.install) {
81129
- logger.log(" npm install");
82520
+ if (agentLaunched) {
82521
+ return;
81130
82522
  }
81131
- logger.log(compileResult?.success ? " npm start" : " npm run dev");
81132
- logger.newline();
82523
+ printNextSteps({
82524
+ projectName: config2.projectName,
82525
+ persona: config2.persona,
82526
+ template: config2.template,
82527
+ displayDir,
82528
+ installSkipped: !config2.install,
82529
+ workflowCode,
82530
+ workflowFile,
82531
+ mcpConfigured,
82532
+ agentLaunched
82533
+ });
81133
82534
  } catch (err) {
81134
82535
  if (err instanceof ExitPromptError4) {
81135
82536
  return;
@@ -81140,7 +82541,7 @@ async function initCommand(dirArg, options) {
81140
82541
 
81141
82542
  // src/cli/commands/watch.ts
81142
82543
  init_esm5();
81143
- import * as path17 from "path";
82544
+ import * as path19 from "path";
81144
82545
  init_error_utils();
81145
82546
  function timestamp2() {
81146
82547
  const now = /* @__PURE__ */ new Date();
@@ -81166,7 +82567,7 @@ async function watchCommand(input, options = {}) {
81166
82567
  });
81167
82568
  watcher.on("change", async (file) => {
81168
82569
  logger.newline();
81169
- logger.info(`${timestamp2()} File changed: ${path17.basename(file)}`);
82570
+ logger.info(`${timestamp2()} File changed: ${path19.basename(file)}`);
81170
82571
  logger.info(`${timestamp2()} Recompiling...`);
81171
82572
  logger.newline();
81172
82573
  try {
@@ -81199,10 +82600,10 @@ async function watchCommand(input, options = {}) {
81199
82600
 
81200
82601
  // src/cli/commands/dev.ts
81201
82602
  init_esm5();
81202
- import * as path19 from "path";
81203
- import * as fs19 from "fs";
81204
- import * as os from "os";
81205
- import { spawn } from "child_process";
82603
+ import * as path21 from "path";
82604
+ import * as fs21 from "fs";
82605
+ import * as os2 from "os";
82606
+ import { spawn as spawn2 } from "child_process";
81206
82607
  init_workflow_executor();
81207
82608
  init_error_utils();
81208
82609
  function timestamp3() {
@@ -81214,11 +82615,11 @@ function timestamp3() {
81214
82615
  }
81215
82616
  function cycleSeparator(file) {
81216
82617
  const ts5 = timestamp3();
81217
- const pad = "\u2500".repeat(40);
82618
+ const pad2 = "\u2500".repeat(40);
81218
82619
  logger.log(`
81219
- ${logger.dim(`\u2500\u2500\u2500 ${ts5} ${pad}`)}`);
82620
+ ${logger.dim(`\u2500\u2500\u2500 ${ts5} ${pad2}`)}`);
81220
82621
  if (file) {
81221
- logger.log(` ${logger.dim("File changed:")} ${path19.basename(file)}`);
82622
+ logger.log(` ${logger.dim("File changed:")} ${path21.basename(file)}`);
81222
82623
  }
81223
82624
  }
81224
82625
  function parseParams(options) {
@@ -81230,12 +82631,12 @@ function parseParams(options) {
81230
82631
  }
81231
82632
  }
81232
82633
  if (options.paramsFile) {
81233
- const paramsFilePath = path19.resolve(options.paramsFile);
81234
- if (!fs19.existsSync(paramsFilePath)) {
82634
+ const paramsFilePath = path21.resolve(options.paramsFile);
82635
+ if (!fs21.existsSync(paramsFilePath)) {
81235
82636
  throw new Error(`Params file not found: ${paramsFilePath}`);
81236
82637
  }
81237
82638
  try {
81238
- const content = fs19.readFileSync(paramsFilePath, "utf8");
82639
+ const content = fs21.readFileSync(paramsFilePath, "utf8");
81239
82640
  return JSON.parse(content);
81240
82641
  } catch {
81241
82642
  throw new Error(`Failed to parse params file: ${options.paramsFile}`);
@@ -81318,7 +82719,7 @@ function checkDependency(pkg, cwd) {
81318
82719
  }
81319
82720
  }
81320
82721
  function generateDevServerEntry(inngestOutputPath, framework, port) {
81321
- const relImport = `./${path19.basename(inngestOutputPath).replace(/\.ts$/, ".js")}`;
82722
+ const relImport = `./${path21.basename(inngestOutputPath).replace(/\.ts$/, ".js")}`;
81322
82723
  if (framework === "express") {
81323
82724
  return `import express from 'express';
81324
82725
  import { handler } from '${relImport}';
@@ -81357,7 +82758,7 @@ serve({ fetch: app.fetch, port: ${port} }, () => {
81357
82758
  async function runInngestDevMode(filePath, options) {
81358
82759
  const framework = options.framework ?? "express";
81359
82760
  const port = options.port ?? 3e3;
81360
- const cwd = path19.dirname(filePath);
82761
+ const cwd = path21.dirname(filePath);
81361
82762
  const missingDeps = [];
81362
82763
  if (!checkDependency("inngest", cwd)) missingDeps.push("inngest");
81363
82764
  if (framework === "express" && !checkDependency("express", cwd)) missingDeps.push("express");
@@ -81368,8 +82769,8 @@ async function runInngestDevMode(filePath, options) {
81368
82769
  if (missingDeps.length > 0) {
81369
82770
  throw new Error(`Missing dependencies: ${missingDeps.join(", ")}. Install them with: npm install ${missingDeps.join(" ")}`);
81370
82771
  }
81371
- const tmpDir = fs19.mkdtempSync(path19.join(os.tmpdir(), "fw-inngest-dev-"));
81372
- const inngestOutputPath = path19.join(tmpDir, path19.basename(filePath).replace(/\.ts$/, ".inngest.ts"));
82772
+ const tmpDir = fs21.mkdtempSync(path21.join(os2.tmpdir(), "fw-inngest-dev-"));
82773
+ const inngestOutputPath = path21.join(tmpDir, path21.basename(filePath).replace(/\.ts$/, ".inngest.ts"));
81373
82774
  let serverProcess = null;
81374
82775
  const compileInngest = async () => {
81375
82776
  try {
@@ -81381,10 +82782,10 @@ async function runInngestDevMode(filePath, options) {
81381
82782
  typedEvents: true
81382
82783
  });
81383
82784
  const sourceOutput2 = filePath.replace(/\.ts$/, ".inngest.ts");
81384
- if (fs19.existsSync(sourceOutput2)) {
81385
- fs19.copyFileSync(sourceOutput2, inngestOutputPath);
82785
+ if (fs21.existsSync(sourceOutput2)) {
82786
+ fs21.copyFileSync(sourceOutput2, inngestOutputPath);
81386
82787
  try {
81387
- fs19.unlinkSync(sourceOutput2);
82788
+ fs21.unlinkSync(sourceOutput2);
81388
82789
  } catch {
81389
82790
  }
81390
82791
  }
@@ -81395,11 +82796,11 @@ async function runInngestDevMode(filePath, options) {
81395
82796
  }
81396
82797
  };
81397
82798
  const startServer = () => {
81398
- const entryPath = path19.join(tmpDir, "dev-server.ts");
82799
+ const entryPath = path21.join(tmpDir, "dev-server.ts");
81399
82800
  const entryCode = generateDevServerEntry(inngestOutputPath, framework, port);
81400
- fs19.writeFileSync(entryPath, entryCode, "utf8");
81401
- serverProcess = spawn("npx", ["tsx", entryPath], {
81402
- cwd: path19.dirname(filePath),
82801
+ fs21.writeFileSync(entryPath, entryCode, "utf8");
82802
+ serverProcess = spawn2("npx", ["tsx", entryPath], {
82803
+ cwd: path21.dirname(filePath),
81403
82804
  stdio: "inherit",
81404
82805
  shell: true
81405
82806
  });
@@ -81427,7 +82828,7 @@ async function runInngestDevMode(filePath, options) {
81427
82828
  }
81428
82829
  };
81429
82830
  logger.section("Inngest Dev Mode");
81430
- logger.info(`File: ${path19.basename(filePath)}`);
82831
+ logger.info(`File: ${path21.basename(filePath)}`);
81431
82832
  logger.info(`Framework: ${framework}`);
81432
82833
  logger.info(`Port: ${port}`);
81433
82834
  logger.newline();
@@ -81441,7 +82842,7 @@ async function runInngestDevMode(filePath, options) {
81441
82842
  }
81442
82843
  logger.newline();
81443
82844
  logger.success("Watching for file changes... (Ctrl+C to stop)");
81444
- const files = await glob(path19.resolve(filePath), { absolute: true });
82845
+ const files = await glob(path21.resolve(filePath), { absolute: true });
81445
82846
  const chokidar = await import("chokidar");
81446
82847
  const watcher = chokidar.watch(files, {
81447
82848
  persistent: true,
@@ -81459,11 +82860,11 @@ async function runInngestDevMode(filePath, options) {
81459
82860
  stopServer();
81460
82861
  watcher.close();
81461
82862
  try {
81462
- fs19.rmSync(tmpDir, { recursive: true, force: true });
82863
+ fs21.rmSync(tmpDir, { recursive: true, force: true });
81463
82864
  } catch {
81464
82865
  }
81465
82866
  try {
81466
- fs19.unlinkSync(sourceOutput);
82867
+ fs21.unlinkSync(sourceOutput);
81467
82868
  } catch {
81468
82869
  }
81469
82870
  process.exit(0);
@@ -81474,8 +82875,8 @@ async function runInngestDevMode(filePath, options) {
81474
82875
  });
81475
82876
  }
81476
82877
  async function devCommand(input, options = {}) {
81477
- const filePath = path19.resolve(input);
81478
- if (!fs19.existsSync(filePath)) {
82878
+ const filePath = path21.resolve(input);
82879
+ if (!fs21.existsSync(filePath)) {
81479
82880
  throw new Error(`File not found: ${filePath}`);
81480
82881
  }
81481
82882
  if (options.target === "inngest") {
@@ -81484,7 +82885,7 @@ async function devCommand(input, options = {}) {
81484
82885
  const params = parseParams(options);
81485
82886
  if (!options.json) {
81486
82887
  logger.section("Dev Mode");
81487
- logger.info(`File: ${path19.basename(filePath)}`);
82888
+ logger.info(`File: ${path21.basename(filePath)}`);
81488
82889
  if (Object.keys(params).length > 0) {
81489
82890
  logger.info(`Params: ${JSON.stringify(params)}`);
81490
82891
  }
@@ -85051,7 +86452,7 @@ async function listenCommand(options) {
85051
86452
  }
85052
86453
 
85053
86454
  // src/cli/commands/tunnel.ts
85054
- import * as path26 from "node:path";
86455
+ import * as path28 from "node:path";
85055
86456
 
85056
86457
  // node_modules/ws/wrapper.mjs
85057
86458
  var import_stream2 = __toESM(require_stream2(), 1);
@@ -85062,18 +86463,18 @@ var import_websocket_server2 = __toESM(require_websocket_server2(), 1);
85062
86463
  var wrapper_default = import_websocket4.default;
85063
86464
 
85064
86465
  // src/cli/tunnel/handlers/file-ops.ts
85065
- import * as fs20 from "node:fs/promises";
85066
- import * as path21 from "node:path";
86466
+ import * as fs22 from "node:fs/promises";
86467
+ import * as path23 from "node:path";
85067
86468
 
85068
86469
  // src/cli/tunnel/path-resolver.ts
85069
- import * as path20 from "node:path";
86470
+ import * as path22 from "node:path";
85070
86471
  function resolvePath(workspaceRoot, studioPath) {
85071
86472
  if (studioPath.includes("\0")) {
85072
86473
  throw new Error("Path traversal blocked");
85073
86474
  }
85074
- if (studioPath.startsWith(workspaceRoot + path20.sep) || studioPath === workspaceRoot) {
85075
- const resolved2 = path20.resolve(studioPath);
85076
- if (!resolved2.startsWith(workspaceRoot + path20.sep) && resolved2 !== workspaceRoot) {
86475
+ if (studioPath.startsWith(workspaceRoot + path22.sep) || studioPath === workspaceRoot) {
86476
+ const resolved2 = path22.resolve(studioPath);
86477
+ if (!resolved2.startsWith(workspaceRoot + path22.sep) && resolved2 !== workspaceRoot) {
85077
86478
  throw new Error("Path traversal blocked");
85078
86479
  }
85079
86480
  return resolved2;
@@ -85086,16 +86487,16 @@ function resolvePath(workspaceRoot, studioPath) {
85086
86487
  if (!normalized) {
85087
86488
  return workspaceRoot;
85088
86489
  }
85089
- const resolved = path20.resolve(workspaceRoot, normalized);
85090
- if (!resolved.startsWith(workspaceRoot + path20.sep) && resolved !== workspaceRoot) {
86490
+ const resolved = path22.resolve(workspaceRoot, normalized);
86491
+ if (!resolved.startsWith(workspaceRoot + path22.sep) && resolved !== workspaceRoot) {
85091
86492
  throw new Error("Path traversal blocked");
85092
86493
  }
85093
86494
  return resolved;
85094
86495
  }
85095
86496
  function toVirtualPath(workspaceRoot, realPath) {
85096
- const rel = path20.relative(workspaceRoot, realPath);
86497
+ const rel = path22.relative(workspaceRoot, realPath);
85097
86498
  if (rel.startsWith("..")) {
85098
- return "/" + path20.basename(realPath);
86499
+ return "/" + path22.basename(realPath);
85099
86500
  }
85100
86501
  return "/" + rel;
85101
86502
  }
@@ -85108,14 +86509,14 @@ async function collectFileInfos(dir, root2) {
85108
86509
  async function walk(currentDir) {
85109
86510
  let entries;
85110
86511
  try {
85111
- entries = await fs20.readdir(currentDir, { withFileTypes: true });
86512
+ entries = await fs22.readdir(currentDir, { withFileTypes: true });
85112
86513
  } catch {
85113
86514
  return;
85114
86515
  }
85115
86516
  for (const entry of entries) {
85116
86517
  if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(".")) continue;
85117
86518
  if (SKIP_FILES.has(entry.name)) continue;
85118
- const fullPath = path21.join(currentDir, entry.name);
86519
+ const fullPath = path23.join(currentDir, entry.name);
85119
86520
  const isDir = entry.isDirectory();
85120
86521
  results.push({
85121
86522
  path: toVirtualPath(root2, fullPath),
@@ -85136,7 +86537,7 @@ var fileOpsHandlers = {
85136
86537
  const filePath = params.filePath;
85137
86538
  if (!filePath) throw new Error("filePath is required");
85138
86539
  const resolved = resolvePath(ctx.workspaceRoot, filePath);
85139
- return fs20.readFile(resolved, "utf-8");
86540
+ return fs22.readFile(resolved, "utf-8");
85140
86541
  },
85141
86542
  writeFile: async (params, ctx) => {
85142
86543
  const filePath = params.filePath || params.path;
@@ -85144,8 +86545,8 @@ var fileOpsHandlers = {
85144
86545
  if (!filePath) throw new Error("filePath is required");
85145
86546
  if (content === void 0 || content === null) throw new Error("content is required");
85146
86547
  const resolved = resolvePath(ctx.workspaceRoot, filePath);
85147
- await fs20.mkdir(path21.dirname(resolved), { recursive: true });
85148
- await fs20.writeFile(resolved, content, "utf-8");
86548
+ await fs22.mkdir(path23.dirname(resolved), { recursive: true });
86549
+ await fs22.writeFile(resolved, content, "utf-8");
85149
86550
  return { saved: true };
85150
86551
  },
85151
86552
  saveFile: async (params, ctx) => {
@@ -85156,7 +86557,7 @@ var fileOpsHandlers = {
85156
86557
  if (!filePath) return false;
85157
86558
  const resolved = resolvePath(ctx.workspaceRoot, filePath);
85158
86559
  try {
85159
- await fs20.access(resolved);
86560
+ await fs22.access(resolved);
85160
86561
  return true;
85161
86562
  } catch {
85162
86563
  return false;
@@ -85166,7 +86567,7 @@ var fileOpsHandlers = {
85166
86567
  const filePath = params.filePath;
85167
86568
  if (!filePath) throw new Error("filePath is required");
85168
86569
  const resolved = resolvePath(ctx.workspaceRoot, filePath);
85169
- await fs20.unlink(resolved);
86570
+ await fs22.unlink(resolved);
85170
86571
  return { deleted: true };
85171
86572
  },
85172
86573
  getFilesStructure: async (_params, ctx) => {
@@ -85179,12 +86580,12 @@ var fileOpsHandlers = {
85179
86580
  let dirPath = params.dirPath || params.path || params.directory;
85180
86581
  if (dirPath?.startsWith("/cloud")) dirPath = dirPath.slice("/cloud".length) || void 0;
85181
86582
  const resolved = dirPath && dirPath !== "/" && dirPath !== "" ? resolvePath(ctx.workspaceRoot, dirPath) : ctx.workspaceRoot;
85182
- const entries = await fs20.readdir(resolved, { withFileTypes: true });
86583
+ const entries = await fs22.readdir(resolved, { withFileTypes: true });
85183
86584
  const results = [];
85184
86585
  for (const entry of entries) {
85185
86586
  if (entry.name === "node_modules" || entry.name === "package-lock.json") continue;
85186
- const fullPath = path21.join(resolved, entry.name);
85187
- const stat2 = await fs20.stat(fullPath);
86587
+ const fullPath = path23.join(resolved, entry.name);
86588
+ const stat2 = await fs22.stat(fullPath);
85188
86589
  const isDir = entry.isDirectory();
85189
86590
  results.push({
85190
86591
  name: entry.name,
@@ -85198,7 +86599,7 @@ var fileOpsHandlers = {
85198
86599
  return results;
85199
86600
  },
85200
86601
  findWorkflows: async (_params, ctx) => {
85201
- const entries = await fs20.readdir(ctx.workspaceRoot, { withFileTypes: true });
86602
+ const entries = await fs22.readdir(ctx.workspaceRoot, { withFileTypes: true });
85202
86603
  const paths = [];
85203
86604
  for (const entry of entries) {
85204
86605
  if (entry.isFile() && entry.name.endsWith(".ts")) {
@@ -85211,7 +86612,7 @@ var fileOpsHandlers = {
85211
86612
  const dirPath = params.dirPath;
85212
86613
  if (!dirPath) throw new Error("dirPath is required");
85213
86614
  const resolved = resolvePath(ctx.workspaceRoot, dirPath);
85214
- await fs20.mkdir(resolved, { recursive: true });
86615
+ await fs22.mkdir(resolved, { recursive: true });
85215
86616
  return { created: true };
85216
86617
  },
85217
86618
  renameFile: async (params, ctx) => {
@@ -85220,14 +86621,14 @@ var fileOpsHandlers = {
85220
86621
  if (!oldPath || !newPath) throw new Error("oldPath and newPath are required");
85221
86622
  const resolvedOld = resolvePath(ctx.workspaceRoot, oldPath);
85222
86623
  const resolvedNew = resolvePath(ctx.workspaceRoot, newPath);
85223
- await fs20.rename(resolvedOld, resolvedNew);
86624
+ await fs22.rename(resolvedOld, resolvedNew);
85224
86625
  return { renamed: true };
85225
86626
  },
85226
86627
  getFileStats: async (params, ctx) => {
85227
86628
  const filePath = params.filePath;
85228
86629
  if (!filePath) throw new Error("filePath is required");
85229
86630
  const resolved = resolvePath(ctx.workspaceRoot, filePath);
85230
- const stat2 = await fs20.stat(resolved);
86631
+ const stat2 = await fs22.stat(resolved);
85231
86632
  return {
85232
86633
  size: stat2.size,
85233
86634
  created: stat2.birthtime.toISOString(),
@@ -85243,8 +86644,8 @@ var fileOpsHandlers = {
85243
86644
  copyDirectory: async () => ({ success: true }),
85244
86645
  checkLibraryStatus: async (_params, ctx) => {
85245
86646
  try {
85246
- const pkgPath = path21.join(ctx.workspaceRoot, "node_modules", "@synergenius", "flow-weaver", "package.json");
85247
- const raw = await fs20.readFile(pkgPath, "utf-8");
86647
+ const pkgPath = path23.join(ctx.workspaceRoot, "node_modules", "@synergenius", "flow-weaver", "package.json");
86648
+ const raw = await fs22.readFile(pkgPath, "utf-8");
85248
86649
  const pkg = JSON.parse(raw);
85249
86650
  return {
85250
86651
  installed: true,
@@ -85269,7 +86670,7 @@ var fileOpsHandlers = {
85269
86670
  },
85270
86671
  getPackages: async (_params, ctx) => {
85271
86672
  try {
85272
- const raw = await fs20.readFile(path21.join(ctx.workspaceRoot, "package.json"), "utf-8");
86673
+ const raw = await fs22.readFile(path23.join(ctx.workspaceRoot, "package.json"), "utf-8");
85273
86674
  const pkg = JSON.parse(raw);
85274
86675
  const deps = pkg.dependencies || {};
85275
86676
  return Object.entries(deps).map(([name, version3]) => ({ name, version: version3 }));
@@ -85282,8 +86683,8 @@ var fileOpsHandlers = {
85282
86683
  // src/cli/tunnel/handlers/ast-ops.ts
85283
86684
  init_parser2();
85284
86685
  init_validate();
85285
- import * as fs21 from "node:fs/promises";
85286
- import * as path22 from "node:path";
86686
+ import * as fs23 from "node:fs/promises";
86687
+ import * as path24 from "node:path";
85287
86688
  function ensureASTDefaults(ast) {
85288
86689
  return {
85289
86690
  ...ast,
@@ -85338,15 +86739,15 @@ async function loadWorkflowAST(filePath, functionName) {
85338
86739
  if (!target) {
85339
86740
  throw new Error(`Workflow "${functionName}" not found in ${filePath}`);
85340
86741
  }
85341
- return resolveNpmNodeTypes(target, path22.dirname(filePath));
86742
+ return resolveNpmNodeTypes(target, path24.dirname(filePath));
85342
86743
  }
85343
86744
  async function loadAllWorkflowsAST(wsPath) {
85344
- const entries = await fs21.readdir(wsPath, { withFileTypes: true });
86745
+ const entries = await fs23.readdir(wsPath, { withFileTypes: true });
85345
86746
  const results = [];
85346
86747
  for (const entry of entries) {
85347
86748
  if (!entry.isFile() || !entry.name.endsWith(".ts")) continue;
85348
86749
  if (entry.name === "tsconfig.json" || entry.name === "package.json") continue;
85349
- const fullPath = path22.join(wsPath, entry.name);
86750
+ const fullPath = path24.join(wsPath, entry.name);
85350
86751
  try {
85351
86752
  const parsed = parser.parse(fullPath);
85352
86753
  const workflows = parsed.workflows || [];
@@ -85431,7 +86832,7 @@ var astOpsHandlers = {
85431
86832
  if (!filePath) return { availableWorkflows: [] };
85432
86833
  try {
85433
86834
  const resolved = resolvePath(ctx.workspaceRoot, filePath);
85434
- const source = await fs21.readFile(resolved, "utf-8");
86835
+ const source = await fs23.readFile(resolved, "utf-8");
85435
86836
  const results = parseWorkflowFromContent(source);
85436
86837
  return {
85437
86838
  availableWorkflows: results.map((w) => ({
@@ -85454,7 +86855,7 @@ var astOpsHandlers = {
85454
86855
  source = params.content;
85455
86856
  } else if (filePath) {
85456
86857
  const resolved = resolvePath(ctx.workspaceRoot, filePath);
85457
- source = await fs21.readFile(resolved, "utf-8");
86858
+ source = await fs23.readFile(resolved, "utf-8");
85458
86859
  }
85459
86860
  if (!source) throw new Error("No source provided for diagnostics");
85460
86861
  const { errors: errors2, warnings } = getDiagnostics(source);
@@ -85507,14 +86908,14 @@ init_nodes();
85507
86908
  init_connections();
85508
86909
  init_node_types();
85509
86910
  init_ports();
85510
- import * as fs22 from "node:fs/promises";
85511
- import * as path24 from "node:path";
86911
+ import * as fs24 from "node:fs/promises";
86912
+ import * as path26 from "node:path";
85512
86913
 
85513
86914
  // src/cli/tunnel/file-lock.ts
85514
- import * as path23 from "node:path";
86915
+ import * as path25 from "node:path";
85515
86916
  var fileMutationLocks = /* @__PURE__ */ new Map();
85516
86917
  function withFileLock(filePath, operation) {
85517
- const normalizedPath = path23.resolve(filePath);
86918
+ const normalizedPath = path25.resolve(filePath);
85518
86919
  const existingChain = fileMutationLocks.get(normalizedPath) || Promise.resolve();
85519
86920
  let resolve37;
85520
86921
  let reject2;
@@ -85546,7 +86947,7 @@ async function mutateWorkflowFile({
85546
86947
  mutator
85547
86948
  }) {
85548
86949
  return withFileLock(filePath, async () => {
85549
- const sourceCode = await fs22.readFile(filePath, "utf-8");
86950
+ const sourceCode = await fs24.readFile(filePath, "utf-8");
85550
86951
  const parsed = parser.parse(filePath);
85551
86952
  const workflows = parsed.workflows || [];
85552
86953
  if (workflows.length === 0) {
@@ -85582,8 +86983,8 @@ async function mutateWorkflowFile({
85582
86983
  nodeTypes: [...updatedNodeTypes, ...missingTypes]
85583
86984
  };
85584
86985
  const result = generateInPlace(sourceCode, workflowForGeneration);
85585
- await fs22.writeFile(filePath, result.code, "utf-8");
85586
- return resolveNpmNodeTypes(updated, path24.dirname(filePath));
86986
+ await fs24.writeFile(filePath, result.code, "utf-8");
86987
+ return resolveNpmNodeTypes(updated, path26.dirname(filePath));
85587
86988
  });
85588
86989
  }
85589
86990
  function makeMutationHandler(extractMutator) {
@@ -85793,8 +87194,8 @@ var mutationHandlers = {
85793
87194
  // src/cli/tunnel/handlers/templates.ts
85794
87195
  init_parser2();
85795
87196
  init_templates();
85796
- import * as fs23 from "node:fs/promises";
85797
- import * as path25 from "node:path";
87197
+ import * as fs25 from "node:fs/promises";
87198
+ import * as path27 from "node:path";
85798
87199
  function mapTemplate(t) {
85799
87200
  return {
85800
87201
  id: t.id,
@@ -85886,15 +87287,15 @@ var templateHandlers = {
85886
87287
  const code = template.generate(genOpts);
85887
87288
  const targetFileName = fileName || `${workflowName}.ts`;
85888
87289
  const resolved = resolvePath(ctx.workspaceRoot, targetFileName);
85889
- await fs23.mkdir(path25.dirname(resolved), { recursive: true });
85890
- await fs23.writeFile(resolved, code, "utf-8");
87290
+ await fs25.mkdir(path27.dirname(resolved), { recursive: true });
87291
+ await fs25.writeFile(resolved, code, "utf-8");
85891
87292
  return { success: true, filePath: "/" + targetFileName };
85892
87293
  }
85893
87294
  };
85894
87295
 
85895
87296
  // src/cli/tunnel/handlers/execution.ts
85896
87297
  init_compile();
85897
- import * as fs24 from "node:fs/promises";
87298
+ import * as fs26 from "node:fs/promises";
85898
87299
  var sourceToSVG2;
85899
87300
  async function loadDiagram() {
85900
87301
  if (sourceToSVG2) return sourceToSVG2;
@@ -85945,7 +87346,7 @@ var executionHandlers = {
85945
87346
  source = content;
85946
87347
  } else if (filePath) {
85947
87348
  const resolved = resolvePath(ctx.workspaceRoot, filePath);
85948
- source = await fs24.readFile(resolved, "utf-8");
87349
+ source = await fs26.readFile(resolved, "utf-8");
85949
87350
  } else {
85950
87351
  throw new Error("filePath or content is required");
85951
87352
  }
@@ -86131,7 +87532,7 @@ async function dispatch(method, params, ctx) {
86131
87532
  // src/cli/commands/tunnel.ts
86132
87533
  async function tunnelCommand(options) {
86133
87534
  const cloudUrl = options.cloud || "https://flowweaver.dev";
86134
- const workspaceRoot = path26.resolve(options.dir || process.cwd());
87535
+ const workspaceRoot = path28.resolve(options.dir || process.cwd());
86135
87536
  const createWs = options.createWs ?? ((url2) => new wrapper_default(url2));
86136
87537
  logger.section("Flow Weaver Tunnel");
86137
87538
  logger.info(`Cloud: ${cloudUrl}`);
@@ -100266,7 +101667,7 @@ var StdioServerTransport = class {
100266
101667
  };
100267
101668
 
100268
101669
  // src/mcp/event-buffer.ts
100269
- import * as fs25 from "fs";
101670
+ import * as fs27 from "fs";
100270
101671
 
100271
101672
  // src/mcp/types.ts
100272
101673
  var DEFAULT_EVENT_FILTER = {
@@ -100366,7 +101767,7 @@ var EventBuffer = class {
100366
101767
  appendToFile(entry) {
100367
101768
  if (!this.eventsFilePath) return;
100368
101769
  try {
100369
- fs25.appendFileSync(this.eventsFilePath, JSON.stringify(entry) + "\n");
101770
+ fs27.appendFileSync(this.eventsFilePath, JSON.stringify(entry) + "\n");
100370
101771
  } catch {
100371
101772
  }
100372
101773
  }
@@ -101019,7 +102420,7 @@ function registerEditorTools(mcp, connection, buffer) {
101019
102420
  // src/mcp/tools-query.ts
101020
102421
  init_api6();
101021
102422
  init_query();
101022
- import * as path27 from "path";
102423
+ import * as path29 from "path";
101023
102424
  init_inngest();
101024
102425
  init_parser2();
101025
102426
  function parseErrorCode(errors2) {
@@ -101040,7 +102441,7 @@ function registerQueryTools(mcp) {
101040
102441
  },
101041
102442
  async (args) => {
101042
102443
  try {
101043
- const filePath = path27.resolve(args.filePath);
102444
+ const filePath = path29.resolve(args.filePath);
101044
102445
  const parseResult = await parseWorkflow(filePath, { workflowName: args.workflowName });
101045
102446
  if (parseResult.errors.length > 0 && parseResult.errors.some((e) => typeof e === "string" && e.includes("No workflows found"))) {
101046
102447
  try {
@@ -101089,7 +102490,7 @@ ${parseResult.errors.join("\n")}`
101089
102490
  },
101090
102491
  async (args) => {
101091
102492
  try {
101092
- const filePath = path27.resolve(args.filePath);
102493
+ const filePath = path29.resolve(args.filePath);
101093
102494
  const parseResult = await parseWorkflow(filePath, { workflowName: args.workflowName });
101094
102495
  if (parseResult.errors.length > 0 && parseResult.errors.some((e) => typeof e === "string" && e.includes("No workflows found"))) {
101095
102496
  try {
@@ -101169,7 +102570,7 @@ ${parseResult.errors.join("\n")}`
101169
102570
  },
101170
102571
  async (args) => {
101171
102572
  try {
101172
- const filePath = path27.resolve(args.filePath);
102573
+ const filePath = path29.resolve(args.filePath);
101173
102574
  if (args.target === "inngest") {
101174
102575
  const parser3 = new AnnotationParser();
101175
102576
  const parseResult = parser3.parse(filePath);
@@ -101245,8 +102646,8 @@ ${parseResult.errors.join("\n")}`);
101245
102646
  async (args) => {
101246
102647
  try {
101247
102648
  const [result1, result2] = await Promise.all([
101248
- parseWorkflow(path27.resolve(args.file1), { workflowName: args.workflowName }),
101249
- parseWorkflow(path27.resolve(args.file2), { workflowName: args.workflowName })
102649
+ parseWorkflow(path29.resolve(args.file1), { workflowName: args.workflowName }),
102650
+ parseWorkflow(path29.resolve(args.file2), { workflowName: args.workflowName })
101250
102651
  ]);
101251
102652
  if (result1.errors.length > 0) {
101252
102653
  return makeErrorResult(
@@ -101308,7 +102709,7 @@ Query types:
101308
102709
  },
101309
102710
  async (args) => {
101310
102711
  try {
101311
- const filePath = path27.resolve(args.filePath);
102712
+ const filePath = path29.resolve(args.filePath);
101312
102713
  let parseResult = await parseWorkflow(filePath, { workflowName: args.workflowName });
101313
102714
  if (parseResult.errors.length > 0 && args.query === "node-types" && parseResult.errors.some((e) => typeof e === "string" && e.includes("No workflows found"))) {
101314
102715
  try {
@@ -101407,7 +102808,7 @@ ${parseResult.errors.join("\n")}`
101407
102808
  },
101408
102809
  async (args) => {
101409
102810
  try {
101410
- const dir = path27.resolve(args.directory ?? process.cwd());
102811
+ const dir = path29.resolve(args.directory ?? process.cwd());
101411
102812
  const report = runDoctorChecks(dir);
101412
102813
  return makeToolResult(report);
101413
102814
  } catch (err) {
@@ -101422,8 +102823,8 @@ ${parseResult.errors.join("\n")}`
101422
102823
 
101423
102824
  // src/mcp/tools-template.ts
101424
102825
  init_templates2();
101425
- import * as path28 from "path";
101426
- import * as fs26 from "fs";
102826
+ import * as path30 from "path";
102827
+ import * as fs28 from "fs";
101427
102828
  function registerTemplateTools(mcp) {
101428
102829
  mcp.tool(
101429
102830
  "fw_list_templates",
@@ -101465,7 +102866,7 @@ function registerTemplateTools(mcp) {
101465
102866
  },
101466
102867
  async (args) => {
101467
102868
  try {
101468
- const outPath = path28.resolve(args.filePath);
102869
+ const outPath = path30.resolve(args.filePath);
101469
102870
  const wt = getWorkflowTemplate2(args.template);
101470
102871
  if (wt) {
101471
102872
  const code = generateWorkflowFromTemplate(args.template, {
@@ -101481,10 +102882,10 @@ function registerTemplateTools(mcp) {
101481
102882
  code
101482
102883
  });
101483
102884
  }
101484
- if (fs26.existsSync(outPath)) {
101485
- fs26.appendFileSync(outPath, "\n\n" + code, "utf8");
102885
+ if (fs28.existsSync(outPath)) {
102886
+ fs28.appendFileSync(outPath, "\n\n" + code, "utf8");
101486
102887
  } else {
101487
- fs26.writeFileSync(outPath, code, "utf8");
102888
+ fs28.writeFileSync(outPath, code, "utf8");
101488
102889
  }
101489
102890
  return makeToolResult({
101490
102891
  success: true,
@@ -101505,10 +102906,10 @@ function registerTemplateTools(mcp) {
101505
102906
  code
101506
102907
  });
101507
102908
  }
101508
- if (fs26.existsSync(outPath)) {
101509
- fs26.appendFileSync(outPath, "\n\n" + code, "utf8");
102909
+ if (fs28.existsSync(outPath)) {
102910
+ fs28.appendFileSync(outPath, "\n\n" + code, "utf8");
101510
102911
  } else {
101511
- fs26.writeFileSync(outPath, code, "utf8");
102912
+ fs28.writeFileSync(outPath, code, "utf8");
101512
102913
  }
101513
102914
  return makeToolResult({
101514
102915
  success: true,
@@ -101536,8 +102937,8 @@ init_esm5();
101536
102937
  init_api6();
101537
102938
  init_patterns();
101538
102939
  init_generate_in_place();
101539
- import * as path29 from "path";
101540
- import * as fs27 from "fs";
102940
+ import * as path31 from "path";
102941
+ import * as fs29 from "fs";
101541
102942
 
101542
102943
  // src/migration/registry.ts
101543
102944
  var migrations = [];
@@ -101741,7 +103142,7 @@ function registerPatternTools(mcp) {
101741
103142
  },
101742
103143
  async (args) => {
101743
103144
  try {
101744
- const filePath = path29.resolve(args.filePath);
103145
+ const filePath = path31.resolve(args.filePath);
101745
103146
  const patterns = listPatterns(filePath);
101746
103147
  return makeToolResult(patterns);
101747
103148
  } catch (err) {
@@ -101764,8 +103165,8 @@ function registerPatternTools(mcp) {
101764
103165
  },
101765
103166
  async (args) => {
101766
103167
  try {
101767
- const patternFilePath = path29.resolve(args.patternFile);
101768
- const targetFilePath = path29.resolve(args.targetFile);
103168
+ const patternFilePath = path31.resolve(args.patternFile);
103169
+ const targetFilePath = path31.resolve(args.targetFile);
101769
103170
  const annotationParser = new AnnotationParser();
101770
103171
  const patternResult = annotationParser.parse(patternFilePath);
101771
103172
  if (patternResult.patterns.length === 0) {
@@ -101783,7 +103184,7 @@ function registerPatternTools(mcp) {
101783
103184
  } else {
101784
103185
  pattern = patternResult.patterns[0];
101785
103186
  }
101786
- const targetContent = fs27.readFileSync(targetFilePath, "utf8");
103187
+ const targetContent = fs29.readFileSync(targetFilePath, "utf8");
101787
103188
  const targetResult = annotationParser.parse(targetFilePath);
101788
103189
  const existingNodeTypes = new Set(targetResult.nodeTypes.map((nt) => nt.name));
101789
103190
  const result = applyPattern({
@@ -101804,7 +103205,7 @@ function registerPatternTools(mcp) {
101804
103205
  content: result.modifiedContent
101805
103206
  });
101806
103207
  }
101807
- fs27.writeFileSync(targetFilePath, result.modifiedContent, "utf8");
103208
+ fs29.writeFileSync(targetFilePath, result.modifiedContent, "utf8");
101808
103209
  return makeToolResult({
101809
103210
  success: true,
101810
103211
  nodesAdded: result.nodesAdded,
@@ -101830,7 +103231,7 @@ function registerPatternTools(mcp) {
101830
103231
  },
101831
103232
  async (args) => {
101832
103233
  try {
101833
- const dir = path29.resolve(args.directory);
103234
+ const dir = path31.resolve(args.directory);
101834
103235
  const results = await findWorkflows(dir, args.pattern);
101835
103236
  return makeToolResult(results);
101836
103237
  } catch (err) {
@@ -101867,8 +103268,8 @@ function registerPatternTools(mcp) {
101867
103268
  if (!paramValidation.success) {
101868
103269
  return makeErrorResult("INVALID_PARAMS", paramValidation.error);
101869
103270
  }
101870
- const filePath = path29.resolve(args.filePath);
101871
- const sourceCode = fs27.readFileSync(filePath, "utf8");
103271
+ const filePath = path31.resolve(args.filePath);
103272
+ const sourceCode = fs29.readFileSync(filePath, "utf8");
101872
103273
  const parseResult = await parseWorkflow(filePath, { workflowName: args.workflowName });
101873
103274
  if (parseResult.errors.length > 0) {
101874
103275
  return makeErrorResult("PARSE_ERROR", `Parse errors:
@@ -102057,7 +103458,7 @@ ${parseResult.errors.join("\n")}`);
102057
103458
  });
102058
103459
  }
102059
103460
  if (genResult.hasChanges) {
102060
- fs27.writeFileSync(filePath, genResult.code, "utf8");
103461
+ fs29.writeFileSync(filePath, genResult.code, "utf8");
102061
103462
  }
102062
103463
  let validation;
102063
103464
  let description;
@@ -102160,8 +103561,8 @@ ${parseResult.errors.join("\n")}`);
102160
103561
  );
102161
103562
  }
102162
103563
  }
102163
- const filePath = path29.resolve(args.filePath);
102164
- const sourceCode = fs27.readFileSync(filePath, "utf8");
103564
+ const filePath = path31.resolve(args.filePath);
103565
+ const sourceCode = fs29.readFileSync(filePath, "utf8");
102165
103566
  const parseResult = await parseWorkflow(filePath, { workflowName: args.workflowName });
102166
103567
  if (parseResult.errors.length > 0) {
102167
103568
  return makeErrorResult("PARSE_ERROR", `Parse errors:
@@ -102195,7 +103596,7 @@ ${parseResult.errors.join("\n")}`);
102195
103596
  });
102196
103597
  }
102197
103598
  if (genResult.hasChanges) {
102198
- fs27.writeFileSync(filePath, genResult.code, "utf8");
103599
+ fs29.writeFileSync(filePath, genResult.code, "utf8");
102199
103600
  }
102200
103601
  let validation;
102201
103602
  let description;
@@ -102271,7 +103672,7 @@ ${parseResult.errors.join("\n")}`);
102271
103672
  },
102272
103673
  async (args) => {
102273
103674
  try {
102274
- const filePath = path29.resolve(args.sourceFile);
103675
+ const filePath = path31.resolve(args.sourceFile);
102275
103676
  const parseResult = await parseWorkflow(filePath);
102276
103677
  if (parseResult.errors.length > 0) {
102277
103678
  return makeErrorResult("PARSE_ERROR", `Parse errors:
@@ -102287,8 +103688,8 @@ ${parseResult.errors.join("\n")}`);
102287
103688
  name: args.name
102288
103689
  });
102289
103690
  if (args.outputFile) {
102290
- const outPath = path29.resolve(args.outputFile);
102291
- fs27.writeFileSync(outPath, result.patternCode, "utf8");
103691
+ const outPath = path31.resolve(args.outputFile);
103692
+ fs29.writeFileSync(outPath, result.patternCode, "utf8");
102292
103693
  return makeToolResult({
102293
103694
  success: true,
102294
103695
  filePath: outPath,
@@ -102332,9 +103733,9 @@ ${parseResult.errors.join("\n")}`);
102332
103733
  }
102333
103734
  const results = [];
102334
103735
  for (const file of files) {
102335
- const filePath = path29.resolve(file);
103736
+ const filePath = path31.resolve(file);
102336
103737
  try {
102337
- const sourceCode = fs27.readFileSync(filePath, "utf8");
103738
+ const sourceCode = fs29.readFileSync(filePath, "utf8");
102338
103739
  const parseResult = await parseWorkflow(filePath);
102339
103740
  if (parseResult.errors.length > 0) {
102340
103741
  results.push({ file, status: "error", error: parseResult.errors.join("; ") });
@@ -102350,7 +103751,7 @@ ${parseResult.errors.join("\n")}`);
102350
103751
  continue;
102351
103752
  }
102352
103753
  if (!args.dryRun) {
102353
- fs27.writeFileSync(filePath, genResult.code, "utf8");
103754
+ fs29.writeFileSync(filePath, genResult.code, "utf8");
102354
103755
  }
102355
103756
  results.push({ file, status: "migrated" });
102356
103757
  } catch (err) {
@@ -102380,8 +103781,8 @@ ${parseResult.errors.join("\n")}`);
102380
103781
  // src/mcp/tools-export.ts
102381
103782
  init_api6();
102382
103783
  init_deployment();
102383
- import * as path35 from "path";
102384
- import * as fs31 from "fs";
103784
+ import * as path37 from "path";
103785
+ import * as fs33 from "fs";
102385
103786
  function registerExportTools(mcp) {
102386
103787
  mcp.tool(
102387
103788
  "fw_export",
@@ -102399,12 +103800,12 @@ function registerExportTools(mcp) {
102399
103800
  },
102400
103801
  async (args) => {
102401
103802
  try {
102402
- const filePath = path35.resolve(args.filePath);
102403
- const outputDir = path35.resolve(args.outputDir);
103803
+ const filePath = path37.resolve(args.filePath);
103804
+ const outputDir = path37.resolve(args.outputDir);
102404
103805
  const preview = args.preview ?? false;
102405
103806
  const includeDocs = args.includeDocs ?? true;
102406
103807
  try {
102407
- await fs31.promises.access(filePath);
103808
+ await fs33.promises.access(filePath);
102408
103809
  } catch {
102409
103810
  return makeErrorResult("FILE_NOT_FOUND", `File not found: ${filePath}`);
102410
103811
  }
@@ -102442,7 +103843,7 @@ function registerExportTools(mcp) {
102442
103843
  }
102443
103844
  }
102444
103845
  if (!exportTarget.generateBundle) {
102445
- const serviceName2 = args.serviceName || path35.basename(filePath, ".ts").replace(/[^a-zA-Z0-9-]/g, "-");
103846
+ const serviceName2 = args.serviceName || path37.basename(filePath, ".ts").replace(/[^a-zA-Z0-9-]/g, "-");
102446
103847
  const artifacts2 = await exportTarget.generate({
102447
103848
  sourceFile: filePath,
102448
103849
  workflowName: args.workflows?.[0] || serviceName2,
@@ -102451,11 +103852,11 @@ function registerExportTools(mcp) {
102451
103852
  production: true
102452
103853
  });
102453
103854
  if (!preview) {
102454
- await fs31.promises.mkdir(outputDir, { recursive: true });
103855
+ await fs33.promises.mkdir(outputDir, { recursive: true });
102455
103856
  for (const file of artifacts2.files) {
102456
- const fullPath = path35.join(outputDir, file.relativePath);
102457
- await fs31.promises.mkdir(path35.dirname(fullPath), { recursive: true });
102458
- await fs31.promises.writeFile(fullPath, file.content, "utf-8");
103857
+ const fullPath = path37.join(outputDir, file.relativePath);
103858
+ await fs33.promises.mkdir(path37.dirname(fullPath), { recursive: true });
103859
+ await fs33.promises.writeFile(fullPath, file.content, "utf-8");
102459
103860
  }
102460
103861
  }
102461
103862
  const instructions2 = exportTarget.getDeployInstructions(artifacts2);
@@ -102482,7 +103883,7 @@ function registerExportTools(mcp) {
102482
103883
  const uniqueNodeTypes = [
102483
103884
  ...new Map(allNodeTypes.map((nt) => [nt.name, nt])).values()
102484
103885
  ];
102485
- const serviceName = args.serviceName || path35.basename(filePath, ".ts").replace(/[^a-zA-Z0-9-]/g, "-");
103886
+ const serviceName = args.serviceName || path37.basename(filePath, ".ts").replace(/[^a-zA-Z0-9-]/g, "-");
102486
103887
  const bundleWorkflows = allWorkflows.filter((w) => args.workflows ? args.workflows.includes(w.name) : true).map((w) => ({
102487
103888
  name: w.name,
102488
103889
  functionName: w.functionName,
@@ -102531,11 +103932,11 @@ function registerExportTools(mcp) {
102531
103932
  }
102532
103933
  );
102533
103934
  if (!preview) {
102534
- await fs31.promises.mkdir(outputDir, { recursive: true });
103935
+ await fs33.promises.mkdir(outputDir, { recursive: true });
102535
103936
  for (const file of artifacts.files) {
102536
- const fullPath = path35.join(outputDir, file.relativePath);
102537
- await fs31.promises.mkdir(path35.dirname(fullPath), { recursive: true });
102538
- await fs31.promises.writeFile(fullPath, file.content, "utf-8");
103937
+ const fullPath = path37.join(outputDir, file.relativePath);
103938
+ await fs33.promises.mkdir(path37.dirname(fullPath), { recursive: true });
103939
+ await fs33.promises.writeFile(fullPath, file.content, "utf-8");
102539
103940
  }
102540
103941
  }
102541
103942
  const instructions = exportTarget.getDeployInstructions(artifacts);
@@ -102574,13 +103975,13 @@ function registerExportTools(mcp) {
102574
103975
  }
102575
103976
 
102576
103977
  // src/mcp/tools-marketplace.ts
102577
- import { execSync as execSync3 } from "child_process";
103978
+ import { execSync as execSync4 } from "child_process";
102578
103979
 
102579
103980
  // src/marketplace/manifest.ts
102580
103981
  init_esm5();
102581
103982
  init_parser2();
102582
- import * as fs32 from "fs";
102583
- import * as path36 from "path";
103983
+ import * as fs34 from "fs";
103984
+ import * as path38 from "path";
102584
103985
  function toManifestPort(port) {
102585
103986
  return {
102586
103987
  dataType: port.dataType,
@@ -102651,17 +104052,17 @@ function patternToManifest(pat, relativeFile) {
102651
104052
  }
102652
104053
  async function generateManifest(options) {
102653
104054
  const { directory, srcDir = "src", distDir = "dist" } = options;
102654
- const pkgPath = path36.join(directory, "package.json");
102655
- if (!fs32.existsSync(pkgPath)) {
104055
+ const pkgPath = path38.join(directory, "package.json");
104056
+ if (!fs34.existsSync(pkgPath)) {
102656
104057
  return {
102657
104058
  manifest: emptyManifest("unknown", "0.0.0"),
102658
104059
  parsedFiles: [],
102659
104060
  errors: ["package.json not found"]
102660
104061
  };
102661
104062
  }
102662
- const pkg = JSON.parse(fs32.readFileSync(pkgPath, "utf-8"));
102663
- const srcRoot = path36.join(directory, srcDir);
102664
- const pattern = path36.join(srcRoot, "**/*.ts").replace(/\\/g, "/");
104063
+ const pkg = JSON.parse(fs34.readFileSync(pkgPath, "utf-8"));
104064
+ const srcRoot = path38.join(directory, srcDir);
104065
+ const pattern = path38.join(srcRoot, "**/*.ts").replace(/\\/g, "/");
102665
104066
  const files = await glob(pattern, { absolute: true });
102666
104067
  const tsFiles = files.filter((f) => !f.endsWith(".d.ts") && !f.includes("node_modules"));
102667
104068
  const parser3 = new AnnotationParser();
@@ -102674,8 +104075,8 @@ async function generateManifest(options) {
102674
104075
  try {
102675
104076
  const result = parser3.parse(file);
102676
104077
  parsedFiles.push(file);
102677
- const relFromSrc = path36.relative(srcRoot, file);
102678
- const distRelative = path36.join(distDir, relFromSrc.replace(/\.ts$/, ".js"));
104078
+ const relFromSrc = path38.relative(srcRoot, file);
104079
+ const distRelative = path38.join(distDir, relFromSrc.replace(/\.ts$/, ".js"));
102679
104080
  for (const nt of result.nodeTypes) {
102680
104081
  allNodeTypes.push(nodeTypeToManifest(nt, distRelative));
102681
104082
  }
@@ -102711,14 +104112,14 @@ async function generateManifest(options) {
102711
104112
  return { manifest, parsedFiles, errors: errors2 };
102712
104113
  }
102713
104114
  function writeManifest(directory, manifest) {
102714
- const outPath = path36.join(directory, "flowweaver.manifest.json");
102715
- fs32.writeFileSync(outPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
104115
+ const outPath = path38.join(directory, "flowweaver.manifest.json");
104116
+ fs34.writeFileSync(outPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
102716
104117
  return outPath;
102717
104118
  }
102718
104119
  function readManifest(directory) {
102719
- const manifestPath = path36.join(directory, "flowweaver.manifest.json");
102720
- if (!fs32.existsSync(manifestPath)) return null;
102721
- return JSON.parse(fs32.readFileSync(manifestPath, "utf-8"));
104120
+ const manifestPath = path38.join(directory, "flowweaver.manifest.json");
104121
+ if (!fs34.existsSync(manifestPath)) return null;
104122
+ return JSON.parse(fs34.readFileSync(manifestPath, "utf-8"));
102722
104123
  }
102723
104124
  function emptyManifest(name, version3) {
102724
104125
  return {
@@ -102733,8 +104134,8 @@ function emptyManifest(name, version3) {
102733
104134
 
102734
104135
  // src/marketplace/validator.ts
102735
104136
  init_api6();
102736
- import * as fs33 from "fs";
102737
- import * as path37 from "path";
104137
+ import * as fs35 from "fs";
104138
+ import * as path39 from "path";
102738
104139
  function issue2(code, severity, message) {
102739
104140
  return { code, severity, message };
102740
104141
  }
@@ -102781,7 +104182,7 @@ function validatePackageJson(pkg, directory) {
102781
104182
  if (pkg.private === true) {
102782
104183
  issues.push(issue2("PKG-004", "error", 'Package must not be "private: true"'));
102783
104184
  }
102784
- if (!fs33.existsSync(path37.join(directory, "README.md"))) {
104185
+ if (!fs35.existsSync(path39.join(directory, "README.md"))) {
102785
104186
  issues.push(issue2("PKG-007", "warning", "README.md should exist"));
102786
104187
  }
102787
104188
  return issues;
@@ -102856,11 +104257,11 @@ function validateManifestContents(manifest) {
102856
104257
  async function validateWorkflows(manifest, directory) {
102857
104258
  const issues = [];
102858
104259
  for (const wf of manifest.workflows) {
102859
- const srcFile = path37.join(
104260
+ const srcFile = path39.join(
102860
104261
  directory,
102861
104262
  wf.file.replace(/^dist\//, "src/").replace(/\.js$/, ".ts")
102862
104263
  );
102863
- if (!fs33.existsSync(srcFile)) continue;
104264
+ if (!fs35.existsSync(srcFile)) continue;
102864
104265
  try {
102865
104266
  const parseResult = await parseWorkflow(srcFile, { workflowName: wf.functionName });
102866
104267
  if (parseResult.errors.length > 0) continue;
@@ -102880,14 +104281,14 @@ async function validateWorkflows(manifest, directory) {
102880
104281
  return issues;
102881
104282
  }
102882
104283
  async function validatePackage(directory, manifest) {
102883
- const pkgPath = path37.join(directory, "package.json");
102884
- if (!fs33.existsSync(pkgPath)) {
104284
+ const pkgPath = path39.join(directory, "package.json");
104285
+ if (!fs35.existsSync(pkgPath)) {
102885
104286
  return {
102886
104287
  valid: false,
102887
104288
  issues: [issue2("PKG-000", "error", "package.json not found")]
102888
104289
  };
102889
104290
  }
102890
- const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf-8"));
104291
+ const pkg = JSON.parse(fs35.readFileSync(pkgPath, "utf-8"));
102891
104292
  const issues = [
102892
104293
  ...validatePackageJson(pkg, directory),
102893
104294
  ...validateManifestContents(manifest),
@@ -102944,7 +104345,7 @@ function registerMarketplaceTools(mcp) {
102944
104345
  },
102945
104346
  async (args) => {
102946
104347
  try {
102947
- execSync3(`npm install ${args.package}`, {
104348
+ execSync4(`npm install ${args.package}`, {
102948
104349
  cwd: process.cwd(),
102949
104350
  stdio: "pipe"
102950
104351
  });
@@ -103030,8 +104431,8 @@ function resolvePackageName(spec) {
103030
104431
 
103031
104432
  // src/mcp/tools-diagram.ts
103032
104433
  init_diagram();
103033
- import * as fs34 from "fs";
103034
- import * as path38 from "path";
104434
+ import * as fs36 from "fs";
104435
+ import * as path40 from "path";
103035
104436
  var ASCII_FORMATS2 = /* @__PURE__ */ new Set(["ascii", "ascii-compact", "text"]);
103036
104437
  function registerDiagramTools(mcp) {
103037
104438
  mcp.tool(
@@ -103068,8 +104469,8 @@ function registerDiagramTools(mcp) {
103068
104469
  result = sourceToSVG(args.source, diagramOptions);
103069
104470
  }
103070
104471
  } else {
103071
- const resolvedPath = path38.resolve(args.filePath);
103072
- if (!fs34.existsSync(resolvedPath)) {
104472
+ const resolvedPath = path40.resolve(args.filePath);
104473
+ if (!fs36.existsSync(resolvedPath)) {
103073
104474
  return makeErrorResult("FILE_NOT_FOUND", `File not found: ${resolvedPath}`);
103074
104475
  }
103075
104476
  if (ASCII_FORMATS2.has(format)) {
@@ -103081,8 +104482,8 @@ function registerDiagramTools(mcp) {
103081
104482
  }
103082
104483
  }
103083
104484
  if (args.outputPath) {
103084
- const outputResolved = path38.resolve(args.outputPath);
103085
- fs34.writeFileSync(outputResolved, result, "utf-8");
104485
+ const outputResolved = path40.resolve(args.outputPath);
104486
+ fs36.writeFileSync(outputResolved, result, "utf-8");
103086
104487
  return makeToolResult({ written: outputResolved, size: result.length });
103087
104488
  }
103088
104489
  return makeToolResult(result);
@@ -103096,217 +104497,6 @@ function registerDiagramTools(mcp) {
103096
104497
  );
103097
104498
  }
103098
104499
 
103099
- // src/docs/index.ts
103100
- import * as fs35 from "fs";
103101
- import * as path39 from "path";
103102
- import { fileURLToPath as fileURLToPath3 } from "url";
103103
- function getDocsDir() {
103104
- const thisFile = fileURLToPath3(import.meta.url);
103105
- const packageRoot = path39.resolve(path39.dirname(thisFile), "..", "..");
103106
- return path39.join(packageRoot, "docs", "reference");
103107
- }
103108
- function parseFrontmatter(raw) {
103109
- const fmMatch = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
103110
- if (!fmMatch) {
103111
- return {
103112
- frontmatter: { name: "", description: "", keywords: [] },
103113
- body: raw
103114
- };
103115
- }
103116
- const fmBlock = fmMatch[1];
103117
- const body = fmMatch[2];
103118
- let name = "";
103119
- let description = "";
103120
- let keywords = [];
103121
- for (const line of fmBlock.split("\n")) {
103122
- const nameMatch = line.match(/^name:\s*(.+)$/);
103123
- if (nameMatch) {
103124
- name = nameMatch[1].trim();
103125
- continue;
103126
- }
103127
- const descMatch = line.match(/^description:\s*(.+)$/);
103128
- if (descMatch) {
103129
- description = descMatch[1].trim();
103130
- continue;
103131
- }
103132
- const kwMatch = line.match(/^keywords:\s*\[(.+)\]$/);
103133
- if (kwMatch) {
103134
- keywords = kwMatch[1].split(",").map((k) => k.trim().replace(/^['"]|['"]$/g, ""));
103135
- continue;
103136
- }
103137
- }
103138
- return { frontmatter: { name, description, keywords }, body };
103139
- }
103140
- function splitSections(body) {
103141
- const lines = body.split("\n");
103142
- const sections = [];
103143
- let currentHeading = "";
103144
- let currentLevel = 0;
103145
- let currentLines = [];
103146
- function flush() {
103147
- if (currentHeading || currentLines.length > 0) {
103148
- const content = currentLines.join("\n").trim();
103149
- const codeBlocks = [];
103150
- const codeRe = /```[\s\S]*?```/g;
103151
- let m;
103152
- while ((m = codeRe.exec(content)) !== null) {
103153
- codeBlocks.push(m[0]);
103154
- }
103155
- sections.push({
103156
- heading: currentHeading,
103157
- level: currentLevel,
103158
- content,
103159
- codeBlocks
103160
- });
103161
- }
103162
- }
103163
- for (const line of lines) {
103164
- const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
103165
- if (headingMatch) {
103166
- flush();
103167
- currentLevel = headingMatch[1].length;
103168
- currentHeading = headingMatch[2];
103169
- currentLines = [];
103170
- } else {
103171
- currentLines.push(line);
103172
- }
103173
- }
103174
- flush();
103175
- return sections;
103176
- }
103177
- function listTopics() {
103178
- const docsDir = getDocsDir();
103179
- if (!fs35.existsSync(docsDir)) return [];
103180
- const files = fs35.readdirSync(docsDir).filter((f) => f.endsWith(".md")).sort();
103181
- return files.map((file) => {
103182
- const raw = fs35.readFileSync(path39.join(docsDir, file), "utf-8");
103183
- const { frontmatter } = parseFrontmatter(raw);
103184
- return {
103185
- slug: file.replace(/\.md$/, ""),
103186
- name: frontmatter.name,
103187
- description: frontmatter.description,
103188
- keywords: frontmatter.keywords
103189
- };
103190
- });
103191
- }
103192
- function readTopic(slug, compact2) {
103193
- const docsDir = getDocsDir();
103194
- const filePath = path39.join(docsDir, `${slug}.md`);
103195
- if (!fs35.existsSync(filePath)) return null;
103196
- const raw = fs35.readFileSync(filePath, "utf-8");
103197
- const { frontmatter, body } = parseFrontmatter(raw);
103198
- const content = compact2 ? buildCompactContent(frontmatter, body) : body.trim();
103199
- return {
103200
- slug,
103201
- name: frontmatter.name,
103202
- description: frontmatter.description,
103203
- keywords: frontmatter.keywords,
103204
- content
103205
- };
103206
- }
103207
- function readTopicStructured(slug) {
103208
- const docsDir = getDocsDir();
103209
- const filePath = path39.join(docsDir, `${slug}.md`);
103210
- if (!fs35.existsSync(filePath)) return null;
103211
- const raw = fs35.readFileSync(filePath, "utf-8");
103212
- const { frontmatter, body } = parseFrontmatter(raw);
103213
- const sections = splitSections(body);
103214
- return {
103215
- slug,
103216
- name: frontmatter.name,
103217
- description: frontmatter.description,
103218
- keywords: frontmatter.keywords,
103219
- sections
103220
- };
103221
- }
103222
- function searchDocs(query) {
103223
- const topics = listTopics();
103224
- const docsDir = getDocsDir();
103225
- const queryLower = query.toLowerCase();
103226
- const queryTerms = queryLower.split(/\s+/).filter(Boolean);
103227
- const results = [];
103228
- for (const topic of topics) {
103229
- const keywordMatch = topic.keywords.some(
103230
- (kw) => queryTerms.some((term) => kw.toLowerCase().includes(term))
103231
- );
103232
- const filePath = path39.join(docsDir, `${topic.slug}.md`);
103233
- const raw = fs35.readFileSync(filePath, "utf-8");
103234
- const { body } = parseFrontmatter(raw);
103235
- const sections = splitSections(body);
103236
- for (const section of sections) {
103237
- const sectionLower = section.content.toLowerCase();
103238
- const headingLower = section.heading.toLowerCase();
103239
- let relevance = 0;
103240
- if (sectionLower.includes(queryLower)) {
103241
- relevance += 10;
103242
- }
103243
- for (const term of queryTerms) {
103244
- if (headingLower.includes(term)) relevance += 5;
103245
- if (sectionLower.includes(term)) relevance += 2;
103246
- }
103247
- if (keywordMatch) relevance += 3;
103248
- if (relevance > 0) {
103249
- const lines = section.content.split("\n");
103250
- const matchingLines = [];
103251
- for (const line of lines) {
103252
- if (queryTerms.some((term) => line.toLowerCase().includes(term))) {
103253
- matchingLines.push(line.trim());
103254
- if (matchingLines.length >= 3) break;
103255
- }
103256
- }
103257
- results.push({
103258
- topic: topic.name,
103259
- slug: topic.slug,
103260
- section: section.heading,
103261
- heading: section.heading,
103262
- excerpt: matchingLines.join("\n") || section.content.slice(0, 200),
103263
- relevance
103264
- });
103265
- }
103266
- }
103267
- }
103268
- results.sort((a, b) => b.relevance - a.relevance);
103269
- return results;
103270
- }
103271
- function buildCompactContent(frontmatter, body) {
103272
- const lines = body.split("\n");
103273
- const output = [];
103274
- output.push(`# ${frontmatter.name}`);
103275
- output.push(frontmatter.description);
103276
- output.push("");
103277
- let inCodeBlock = false;
103278
- let inTable = false;
103279
- for (const line of lines) {
103280
- if (line.trimStart().startsWith("```")) {
103281
- inCodeBlock = !inCodeBlock;
103282
- output.push(line);
103283
- continue;
103284
- }
103285
- if (inCodeBlock) {
103286
- output.push(line);
103287
- continue;
103288
- }
103289
- if (line.match(/^#{1,6}\s/)) {
103290
- output.push("");
103291
- output.push(line);
103292
- continue;
103293
- }
103294
- if (line.trim().startsWith("|")) {
103295
- inTable = true;
103296
- output.push(line);
103297
- continue;
103298
- }
103299
- if (inTable && !line.trim().startsWith("|")) {
103300
- inTable = false;
103301
- }
103302
- if (line.trim().startsWith("- ") || line.trim().startsWith("* ") || line.trim().startsWith("> ")) {
103303
- output.push(line);
103304
- continue;
103305
- }
103306
- }
103307
- return output.join("\n").replace(/\n{3,}/g, "\n\n").trim();
103308
- }
103309
-
103310
104500
  // src/mcp/tools-docs.ts
103311
104501
  function registerDocsTools(mcp) {
103312
104502
  mcp.tool(
@@ -103380,8 +104570,8 @@ function registerDocsTools(mcp) {
103380
104570
  // src/mcp/tools-model.ts
103381
104571
  init_api6();
103382
104572
  init_annotation_generator();
103383
- import * as fs36 from "fs";
103384
- import * as path40 from "path";
104573
+ import * as fs37 from "fs";
104574
+ import * as path41 from "path";
103385
104575
  var stepSchema = external_exports.object({
103386
104576
  name: external_exports.string().describe("Function name for this node"),
103387
104577
  description: external_exports.string().optional().describe("Brief description of what this node does"),
@@ -103418,7 +104608,7 @@ function registerModelTools(mcp) {
103418
104608
  },
103419
104609
  async (args) => {
103420
104610
  try {
103421
- const outputPath = path40.resolve(args.filePath);
104611
+ const outputPath = path41.resolve(args.filePath);
103422
104612
  const lines = [];
103423
104613
  for (const step of args.steps) {
103424
104614
  lines.push("/** @flowWeaver node */");
@@ -103446,11 +104636,11 @@ function registerModelTools(mcp) {
103446
104636
  lines.push(...jsdocLines);
103447
104637
  lines.push("");
103448
104638
  const content = lines.join("\n");
103449
- const dir = path40.dirname(outputPath);
103450
- if (!fs36.existsSync(dir)) {
103451
- fs36.mkdirSync(dir, { recursive: true });
104639
+ const dir = path41.dirname(outputPath);
104640
+ if (!fs37.existsSync(dir)) {
104641
+ fs37.mkdirSync(dir, { recursive: true });
103452
104642
  }
103453
- fs36.writeFileSync(outputPath, content, "utf8");
104643
+ fs37.writeFileSync(outputPath, content, "utf8");
103454
104644
  return makeToolResult({
103455
104645
  filePath: outputPath,
103456
104646
  workflowName: args.name,
@@ -103474,7 +104664,7 @@ function registerModelTools(mcp) {
103474
104664
  },
103475
104665
  async (args) => {
103476
104666
  try {
103477
- const filePath = path40.resolve(args.filePath);
104667
+ const filePath = path41.resolve(args.filePath);
103478
104668
  const parseResult = await parseWorkflow(filePath, { workflowName: args.workflowName });
103479
104669
  if (parseResult.errors.length > 0) {
103480
104670
  return makeErrorResult("PARSE_ERROR", `Parse errors:
@@ -103543,8 +104733,8 @@ ${parseResult.errors.join("\n")}`);
103543
104733
  },
103544
104734
  async (args) => {
103545
104735
  try {
103546
- const filePath = path40.resolve(args.filePath);
103547
- if (!fs36.existsSync(filePath)) {
104736
+ const filePath = path41.resolve(args.filePath);
104737
+ if (!fs37.existsSync(filePath)) {
103548
104738
  return makeErrorResult("FILE_NOT_FOUND", `File not found: ${args.filePath}`);
103549
104739
  }
103550
104740
  const parseResult = await parseWorkflow(filePath, { workflowName: args.workflowName });
@@ -103569,7 +104759,7 @@ ${parseResult.errors.join("\n")}`);
103569
104759
  `Stub "${args.nodeName}" not found. Available stubs: ${stubs.join(", ") || "none"}`
103570
104760
  );
103571
104761
  }
103572
- const source = fs36.readFileSync(filePath, "utf8");
104762
+ const source = fs37.readFileSync(filePath, "utf8");
103573
104763
  const found = findDeclareFunction(source, stubNt.functionName);
103574
104764
  if (!found) {
103575
104765
  return makeErrorResult(
@@ -103586,7 +104776,7 @@ ${parseResult.errors.join("\n")}`);
103586
104776
  replacement = signatureLines.map((line) => found.indent + line).join("\n");
103587
104777
  }
103588
104778
  const updated = source.replace(found.match, replacement);
103589
- fs36.writeFileSync(filePath, updated, "utf8");
104779
+ fs37.writeFileSync(filePath, updated, "utf8");
103590
104780
  return makeToolResult({
103591
104781
  nodeName: stubNt.functionName,
103592
104782
  filePath,
@@ -103625,8 +104815,8 @@ function escapeRegex2(str2) {
103625
104815
  // src/mcp/tools-debug.ts
103626
104816
  init_api6();
103627
104817
  init_query();
103628
- import * as path42 from "path";
103629
- import * as fs38 from "fs";
104818
+ import * as path43 from "path";
104819
+ import * as fs39 from "fs";
103630
104820
 
103631
104821
  // src/runtime/debug-controller.ts
103632
104822
  var DebugController = class {
@@ -103853,8 +105043,8 @@ var DebugController = class {
103853
105043
  };
103854
105044
 
103855
105045
  // src/runtime/checkpoint.ts
103856
- import * as fs37 from "fs";
103857
- import * as path41 from "path";
105046
+ import * as fs38 from "fs";
105047
+ import * as path42 from "path";
103858
105048
  import * as crypto from "crypto";
103859
105049
  function isUnserializableMarker(value2) {
103860
105050
  return typeof value2 === "object" && value2 !== null && value2.__fw_unserializable__ === true;
@@ -103899,7 +105089,7 @@ function serializeValue(key, value2, unsafeNodes) {
103899
105089
  }
103900
105090
  }
103901
105091
  function hashFile(filePath) {
103902
- const content = fs37.readFileSync(filePath, "utf8");
105092
+ const content = fs38.readFileSync(filePath, "utf8");
103903
105093
  return crypto.createHash("sha256").update(content).digest("hex");
103904
105094
  }
103905
105095
  var CheckpointWriter = class {
@@ -103912,12 +105102,12 @@ var CheckpointWriter = class {
103912
105102
  checkpointPath;
103913
105103
  writeLock = Promise.resolve();
103914
105104
  constructor(workflowFilePath, workflowName, runId, params = {}) {
103915
- this.filePath = path41.resolve(workflowFilePath);
105105
+ this.filePath = path42.resolve(workflowFilePath);
103916
105106
  this.workflowName = workflowName;
103917
105107
  this.runId = runId;
103918
105108
  this.params = params;
103919
- this.dir = path41.join(path41.dirname(this.filePath), ".fw-checkpoints");
103920
- this.checkpointPath = path41.join(this.dir, `${workflowName}-${runId}.json`);
105109
+ this.dir = path42.join(path42.dirname(this.filePath), ".fw-checkpoints");
105110
+ this.checkpointPath = path42.join(this.dir, `${workflowName}-${runId}.json`);
103921
105111
  this.workflowHash = hashFile(this.filePath);
103922
105112
  }
103923
105113
  /**
@@ -103933,13 +105123,13 @@ var CheckpointWriter = class {
103933
105123
  /** Clean up checkpoint file after successful completion */
103934
105124
  cleanup() {
103935
105125
  try {
103936
- if (fs37.existsSync(this.checkpointPath)) {
103937
- fs37.unlinkSync(this.checkpointPath);
105126
+ if (fs38.existsSync(this.checkpointPath)) {
105127
+ fs38.unlinkSync(this.checkpointPath);
103938
105128
  }
103939
- if (fs37.existsSync(this.dir)) {
103940
- const remaining = fs37.readdirSync(this.dir);
105129
+ if (fs38.existsSync(this.dir)) {
105130
+ const remaining = fs38.readdirSync(this.dir);
103941
105131
  if (remaining.length === 0) {
103942
- fs37.rmdirSync(this.dir);
105132
+ fs38.rmdirSync(this.dir);
103943
105133
  }
103944
105134
  }
103945
105135
  } catch {
@@ -103971,21 +105161,21 @@ var CheckpointWriter = class {
103971
105161
  nodeExecutionCounts: serialized.nodeExecutionCounts,
103972
105162
  unsafeNodes: [...unsafeNodes]
103973
105163
  };
103974
- if (!fs37.existsSync(this.dir)) {
103975
- fs37.mkdirSync(this.dir, { recursive: true });
105164
+ if (!fs38.existsSync(this.dir)) {
105165
+ fs38.mkdirSync(this.dir, { recursive: true });
103976
105166
  }
103977
- fs37.writeFileSync(this.checkpointPath, JSON.stringify(data, null, 2), "utf8");
105167
+ fs38.writeFileSync(this.checkpointPath, JSON.stringify(data, null, 2), "utf8");
103978
105168
  }
103979
105169
  };
103980
105170
  function loadCheckpoint(checkpointPath, workflowFilePath) {
103981
- const raw = fs37.readFileSync(checkpointPath, "utf8");
105171
+ const raw = fs38.readFileSync(checkpointPath, "utf8");
103982
105172
  const data = JSON.parse(raw);
103983
105173
  if (data.version !== 1) {
103984
105174
  throw new Error(`Unsupported checkpoint version: ${data.version}`);
103985
105175
  }
103986
105176
  let stale = false;
103987
105177
  if (workflowFilePath) {
103988
- const currentHash = hashFile(path41.resolve(workflowFilePath));
105178
+ const currentHash = hashFile(path42.resolve(workflowFilePath));
103989
105179
  stale = currentHash !== data.workflowHash;
103990
105180
  }
103991
105181
  const unsafeSet = new Set(data.unsafeNodes);
@@ -104011,12 +105201,12 @@ function loadCheckpoint(checkpointPath, workflowFilePath) {
104011
105201
  return { data, stale, rerunNodes, skipNodes };
104012
105202
  }
104013
105203
  function findLatestCheckpoint(workflowFilePath, workflowName) {
104014
- const dir = path41.join(path41.dirname(path41.resolve(workflowFilePath)), ".fw-checkpoints");
104015
- if (!fs37.existsSync(dir)) return null;
104016
- const files = fs37.readdirSync(dir).filter((f) => f.endsWith(".json")).filter((f) => !workflowName || f.startsWith(`${workflowName}-`));
105204
+ const dir = path42.join(path42.dirname(path42.resolve(workflowFilePath)), ".fw-checkpoints");
105205
+ if (!fs38.existsSync(dir)) return null;
105206
+ const files = fs38.readdirSync(dir).filter((f) => f.endsWith(".json")).filter((f) => !workflowName || f.startsWith(`${workflowName}-`));
104017
105207
  if (files.length === 0) return null;
104018
- const sorted = files.map((f) => ({ name: f, mtime: fs37.statSync(path41.join(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
104019
- return path41.join(dir, sorted[0].name);
105208
+ const sorted = files.map((f) => ({ name: f, mtime: fs38.statSync(path42.join(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
105209
+ return path42.join(dir, sorted[0].name);
104020
105210
  }
104021
105211
 
104022
105212
  // src/mcp/tools-debug.ts
@@ -104045,7 +105235,7 @@ function listDebugSessions() {
104045
105235
 
104046
105236
  // src/mcp/tools-debug.ts
104047
105237
  async function getExecutionOrder(filePath, workflowName) {
104048
- const source = fs38.readFileSync(path42.resolve(filePath), "utf8");
105238
+ const source = fs39.readFileSync(path43.resolve(filePath), "utf8");
104049
105239
  const parsed = await parseWorkflow(source, { workflowName });
104050
105240
  if (parsed.errors.length > 0) {
104051
105241
  throw new Error(`Failed to parse workflow: ${parsed.errors.join(", ")}`);
@@ -104080,7 +105270,7 @@ function cleanupDebugSession(debugId) {
104080
105270
  if (!session) return;
104081
105271
  for (const tmpFile of session.tmpFiles) {
104082
105272
  try {
104083
- fs38.unlinkSync(tmpFile);
105273
+ fs39.unlinkSync(tmpFile);
104084
105274
  } catch {
104085
105275
  }
104086
105276
  }
@@ -104496,161 +105686,6 @@ function registerDebugTools(mcp) {
104496
105686
  );
104497
105687
  }
104498
105688
 
104499
- // src/context/index.ts
104500
- init_grammar_diagrams();
104501
- var PRESETS = {
104502
- core: ["concepts", "jsdoc-grammar", "tutorial"],
104503
- authoring: [
104504
- "concepts",
104505
- "jsdoc-grammar",
104506
- "advanced-annotations",
104507
- "built-in-nodes",
104508
- "scaffold",
104509
- "node-conversion",
104510
- "patterns"
104511
- ],
104512
- ops: [
104513
- "cli-reference",
104514
- "compilation",
104515
- "deployment",
104516
- "export-interface",
104517
- "debugging",
104518
- "error-codes"
104519
- ],
104520
- full: [
104521
- "concepts",
104522
- "tutorial",
104523
- "jsdoc-grammar",
104524
- "advanced-annotations",
104525
- "built-in-nodes",
104526
- "cli-reference",
104527
- "compilation",
104528
- "debugging",
104529
- "deployment",
104530
- "error-codes",
104531
- "export-interface",
104532
- "iterative-development",
104533
- "marketplace",
104534
- "node-conversion",
104535
- "patterns",
104536
- "scaffold"
104537
- ]
104538
- };
104539
- var PRESET_NAMES = Object.keys(PRESETS);
104540
- var STANDALONE_PREAMBLE = `# Flow Weaver Reference
104541
-
104542
- Flow Weaver is a TypeScript workflow compiler. You write plain .ts files with
104543
- JSDoc annotations (@flowWeaver nodeType, @flowWeaver workflow, @input, @output,
104544
- @connect, @node, @scope). The compiler parses these annotations, validates the
104545
- graph, and generates executable code inline. The source file is the workflow:
104546
- no JSON configs, no YAML, no separate graph files.
104547
-
104548
- Key concepts: node types define reusable processing steps with typed input/output
104549
- ports. Workflows instantiate nodes and connect their ports. Start and Exit are
104550
- implicit boundary nodes. The compiler handles execution ordering, type checking,
104551
- and code generation.`;
104552
- function buildAssistantPreamble() {
104553
- const allSlugs = listTopics().map((t) => t.slug);
104554
- return `# Flow Weaver Context
104555
-
104556
- You have Flow Weaver MCP tools available (fw_ prefix). Use them to create,
104557
- modify, validate, compile, and inspect workflows without manual file editing.
104558
-
104559
- For documentation not included below, call fw_docs(action="read", topic="<slug>").
104560
- Available topic slugs: ${allSlugs.join(", ")}.
104561
-
104562
- Tool quick reference:
104563
- - fw_create_model: Build workflow from structured description (steps + flow path)
104564
- - fw_implement_node: Replace a declare stub with a real function body
104565
- - fw_modify / fw_modify_batch: Add/remove nodes, connections, rename, reposition
104566
- - fw_validate: Check for errors after any change
104567
- - fw_describe: Inspect structure. Use format "text" for readable, "json" for data
104568
- - fw_diagram: Visualize. Prefer format "ascii-compact" in chat contexts
104569
- - fw_compile: Generate executable TypeScript from annotations
104570
- - fw_docs: Look up reference docs by topic slug
104571
- - fw_scaffold: Create from templates (sequential, foreach, ai-agent, etc.)
104572
-
104573
- File conventions: .ts extension, camelCase node names, PascalCase workflow names.`;
104574
- }
104575
- function resolveTopics(preset, explicit, add) {
104576
- const base = explicit ?? PRESETS[preset];
104577
- const combined = add ? [...base, ...add] : base;
104578
- return [...new Set(combined)];
104579
- }
104580
- function buildGrammarSection() {
104581
- const grammars = getAllGrammars();
104582
- const allProductions = [
104583
- ...grammars.port,
104584
- ...grammars.node,
104585
- ...grammars.connect,
104586
- ...grammars.position,
104587
- ...grammars.scope
104588
- ];
104589
- const ebnf = serializedToEBNF(allProductions);
104590
- return `## JSDoc Annotation Grammar (EBNF)
104591
-
104592
- \`\`\`ebnf
104593
- ${ebnf}
104594
- \`\`\``;
104595
- }
104596
- function buildContext(options = {}) {
104597
- const profile = options.profile ?? "standalone";
104598
- const preset = options.preset ?? "core";
104599
- const includeGrammar = options.includeGrammar ?? true;
104600
- const topicSlugs = resolveTopics(preset, options.topics, options.addTopics);
104601
- const sections = [];
104602
- if (profile === "standalone") {
104603
- sections.push(STANDALONE_PREAMBLE);
104604
- } else {
104605
- sections.push(buildAssistantPreamble());
104606
- }
104607
- if (includeGrammar) {
104608
- sections.push(buildGrammarSection());
104609
- }
104610
- let topicCount = 0;
104611
- const includedSlugs = [];
104612
- for (const slug of topicSlugs) {
104613
- const doc = readTopic(slug, true);
104614
- if (!doc) continue;
104615
- let body = doc.content;
104616
- if (body.startsWith("# ")) {
104617
- const lines = body.split("\n");
104618
- let startLine = 1;
104619
- if (lines.length > 1 && lines[1].trim() && !lines[1].startsWith("#")) {
104620
- startLine = 2;
104621
- }
104622
- body = lines.slice(startLine).join("\n").replace(/^\n+/, "");
104623
- }
104624
- const bodyLines = body.split("\n");
104625
- let inCode = false;
104626
- for (let i = 0; i < bodyLines.length; i++) {
104627
- if (bodyLines[i].trimStart().startsWith("```")) {
104628
- inCode = !inCode;
104629
- continue;
104630
- }
104631
- if (!inCode && bodyLines[i].match(/^#{1,5}\s/)) {
104632
- bodyLines[i] = "##" + bodyLines[i];
104633
- }
104634
- }
104635
- body = bodyLines.join("\n");
104636
- const heading = doc.name || slug;
104637
- sections.push(`## ${heading}
104638
-
104639
- ${body}`);
104640
- topicCount++;
104641
- includedSlugs.push(slug);
104642
- }
104643
- const content = sections.join("\n\n---\n\n");
104644
- const lineCount = content.split("\n").length;
104645
- return {
104646
- content,
104647
- topicCount,
104648
- lineCount,
104649
- topicSlugs: includedSlugs,
104650
- profile
104651
- };
104652
- }
104653
-
104654
105689
  // src/mcp/tools-context.ts
104655
105690
  function registerContextTools(mcp) {
104656
105691
  mcp.tool(
@@ -105007,7 +106042,7 @@ async function uiBatch(json2, options) {
105007
106042
 
105008
106043
  // src/cli/commands/grammar.ts
105009
106044
  init_grammar_diagrams();
105010
- import * as fs39 from "fs";
106045
+ import * as fs40 from "fs";
105011
106046
  init_error_utils();
105012
106047
  async function grammarCommand(options = {}) {
105013
106048
  const defaultFormat = options.output ? "html" : process.stdout.isTTY ? "ebnf" : "html";
@@ -105028,7 +106063,7 @@ async function grammarCommand(options = {}) {
105028
106063
  content = generateGrammarDiagrams();
105029
106064
  }
105030
106065
  if (output) {
105031
- fs39.writeFileSync(output, content, "utf-8");
106066
+ fs40.writeFileSync(output, content, "utf-8");
105032
106067
  logger.success(`Grammar written to ${output}`);
105033
106068
  } else {
105034
106069
  process.stdout.write(content);
@@ -105041,14 +106076,14 @@ async function grammarCommand(options = {}) {
105041
106076
 
105042
106077
  // src/cli/commands/run.ts
105043
106078
  init_workflow_executor();
105044
- import * as path43 from "path";
105045
- import * as fs40 from "fs";
106079
+ import * as path44 from "path";
106080
+ import * as fs41 from "fs";
105046
106081
  import * as readline8 from "readline";
105047
106082
  init_query();
105048
106083
  init_error_utils();
105049
106084
  init_api6();
105050
106085
  function displayPath2(filePath) {
105051
- const rel = path43.relative(process.cwd(), filePath);
106086
+ const rel = path44.relative(process.cwd(), filePath);
105052
106087
  if (rel && !rel.startsWith("..") && rel.length < filePath.length) {
105053
106088
  return rel;
105054
106089
  }
@@ -105067,8 +106102,8 @@ async function runCommand(input, options) {
105067
106102
  await runCommandInner(input, options);
105068
106103
  }
105069
106104
  async function runCommandInner(input, options) {
105070
- const filePath = path43.resolve(input);
105071
- if (!fs40.existsSync(filePath)) {
106105
+ const filePath = path44.resolve(input);
106106
+ if (!fs41.existsSync(filePath)) {
105072
106107
  throw new Error(`File not found: ${displayPath2(filePath)}`);
105073
106108
  }
105074
106109
  let params = {};
@@ -105079,12 +106114,12 @@ async function runCommandInner(input, options) {
105079
106114
  throw new Error(`Invalid JSON in --params: ${options.params}`);
105080
106115
  }
105081
106116
  } else if (options.paramsFile) {
105082
- const paramsFilePath = path43.resolve(options.paramsFile);
105083
- if (!fs40.existsSync(paramsFilePath)) {
106117
+ const paramsFilePath = path44.resolve(options.paramsFile);
106118
+ if (!fs41.existsSync(paramsFilePath)) {
105084
106119
  throw new Error(`Params file not found: ${paramsFilePath}`);
105085
106120
  }
105086
106121
  try {
105087
- const content = fs40.readFileSync(paramsFilePath, "utf8");
106122
+ const content = fs41.readFileSync(paramsFilePath, "utf8");
105088
106123
  params = JSON.parse(content);
105089
106124
  } catch {
105090
106125
  throw new Error(`Failed to parse params file: ${options.paramsFile}`);
@@ -105098,12 +106133,12 @@ async function runCommandInner(input, options) {
105098
106133
  throw new Error(`Invalid JSON in --mocks: ${options.mocks}`);
105099
106134
  }
105100
106135
  } else if (options.mocksFile) {
105101
- const mocksFilePath = path43.resolve(options.mocksFile);
105102
- if (!fs40.existsSync(mocksFilePath)) {
106136
+ const mocksFilePath = path44.resolve(options.mocksFile);
106137
+ if (!fs41.existsSync(mocksFilePath)) {
105103
106138
  throw new Error(`Mocks file not found: ${mocksFilePath}`);
105104
106139
  }
105105
106140
  try {
105106
- const content = fs40.readFileSync(mocksFilePath, "utf8");
106141
+ const content = fs41.readFileSync(mocksFilePath, "utf8");
105107
106142
  mocks = JSON.parse(content);
105108
106143
  } catch {
105109
106144
  throw new Error(`Failed to parse mocks file: ${options.mocksFile}`);
@@ -105173,7 +106208,7 @@ async function runCommandInner(input, options) {
105173
106208
  if (useDebug) {
105174
106209
  let executionOrder = resumeExecutionOrder;
105175
106210
  if (!executionOrder) {
105176
- const source = fs40.readFileSync(filePath, "utf8");
106211
+ const source = fs41.readFileSync(filePath, "utf8");
105177
106212
  const parsed = await parseWorkflow(source, { workflowName: options.workflow });
105178
106213
  if (parsed.errors.length === 0) {
105179
106214
  executionOrder = getTopologicalOrder(parsed.ast);
@@ -105680,13 +106715,13 @@ function promptForInput(question) {
105680
106715
  }
105681
106716
 
105682
106717
  // src/cli/commands/serve.ts
105683
- import * as path44 from "path";
105684
- import * as fs42 from "fs";
106718
+ import * as path45 from "path";
106719
+ import * as fs43 from "fs";
105685
106720
 
105686
106721
  // src/server/workflow-registry.ts
105687
106722
  init_esm5();
105688
106723
  init_parser2();
105689
- import * as fs41 from "fs";
106724
+ import * as fs42 from "fs";
105690
106725
  var WorkflowRegistry = class {
105691
106726
  constructor(workflowDir, options = {}) {
105692
106727
  this.workflowDir = workflowDir;
@@ -105721,7 +106756,7 @@ var WorkflowRegistry = class {
105721
106756
  this.endpoints.clear();
105722
106757
  for (const file of files) {
105723
106758
  try {
105724
- const content = fs41.readFileSync(file, "utf8");
106759
+ const content = fs42.readFileSync(file, "utf8");
105725
106760
  if (!content.includes("@flowWeaver")) {
105726
106761
  continue;
105727
106762
  }
@@ -106114,11 +107149,11 @@ var WebhookServer = class {
106114
107149
 
106115
107150
  // src/cli/commands/serve.ts
106116
107151
  async function serveCommand(dir, options) {
106117
- const workflowDir = path44.resolve(dir || ".");
106118
- if (!fs42.existsSync(workflowDir)) {
107152
+ const workflowDir = path45.resolve(dir || ".");
107153
+ if (!fs43.existsSync(workflowDir)) {
106119
107154
  throw new Error(`Directory not found: ${workflowDir}`);
106120
107155
  }
106121
- if (!fs42.statSync(workflowDir).isDirectory()) {
107156
+ if (!fs43.statSync(workflowDir).isDirectory()) {
106122
107157
  throw new Error(`Not a directory: ${workflowDir}`);
106123
107158
  }
106124
107159
  const port = options.port ?? 3e3;
@@ -106163,9 +107198,9 @@ async function serveCommand(dir, options) {
106163
107198
  // src/export/index.ts
106164
107199
  init_compile();
106165
107200
  init_parser2();
106166
- import * as path45 from "path";
106167
- import * as fs43 from "fs";
106168
- import * as os2 from "os";
107201
+ import * as path46 from "path";
107202
+ import * as fs44 from "fs";
107203
+ import * as os3 from "os";
106169
107204
  async function exportWorkflow(options) {
106170
107205
  const { createTargetRegistry: createTargetRegistry2 } = await Promise.resolve().then(() => (init_deployment(), deployment_exports));
106171
107206
  const registry2 = await createTargetRegistry2(process.cwd());
@@ -106176,8 +107211,8 @@ async function exportWorkflow(options) {
106176
107211
  available.length === 0 ? `No export targets installed. Install a target pack (e.g. npm install flowweaver-pack-${options.target})` : `Unknown target "${options.target}". Installed: ${available.join(", ")}`
106177
107212
  );
106178
107213
  }
106179
- const inputPath = path45.resolve(options.input);
106180
- const outputDir = path45.resolve(options.output);
107214
+ const inputPath = path46.resolve(options.input);
107215
+ const outputDir = path46.resolve(options.output);
106181
107216
  const isDryRun = options.dryRun ?? false;
106182
107217
  if (options.multi) {
106183
107218
  return exportMultiWorkflowViaRegistry(
@@ -106197,7 +107232,7 @@ async function exportWorkflow(options) {
106197
107232
  );
106198
107233
  }
106199
107234
  async function exportSingleWorkflowViaRegistry(target, inputPath, outputDir, isDryRun, options) {
106200
- if (!fs43.existsSync(inputPath)) {
107235
+ if (!fs44.existsSync(inputPath)) {
106201
107236
  throw new Error(`Input file not found: ${inputPath}`);
106202
107237
  }
106203
107238
  const parser3 = new AnnotationParser();
@@ -106229,8 +107264,8 @@ async function exportSingleWorkflowViaRegistry(target, inputPath, outputDir, isD
106229
107264
  );
106230
107265
  let compiledContent;
106231
107266
  if (needsCompiledWorkflow) {
106232
- const workDir = isDryRun ? path45.join(os2.tmpdir(), `fw-export-dryrun-${Date.now()}`) : outputDir;
106233
- fs43.mkdirSync(workDir, { recursive: true });
107267
+ const workDir = isDryRun ? path46.join(os3.tmpdir(), `fw-export-dryrun-${Date.now()}`) : outputDir;
107268
+ fs44.mkdirSync(workDir, { recursive: true });
106234
107269
  try {
106235
107270
  const compiledPath = await compileToOutput(
106236
107271
  inputPath,
@@ -106238,29 +107273,29 @@ async function exportSingleWorkflowViaRegistry(target, inputPath, outputDir, isD
106238
107273
  workDir,
106239
107274
  options.production
106240
107275
  );
106241
- compiledContent = fs43.readFileSync(compiledPath, "utf8");
107276
+ compiledContent = fs44.readFileSync(compiledPath, "utf8");
106242
107277
  } finally {
106243
107278
  if (isDryRun) {
106244
107279
  try {
106245
- fs43.rmSync(workDir, { recursive: true, force: true });
107280
+ fs44.rmSync(workDir, { recursive: true, force: true });
106246
107281
  } catch {
106247
107282
  }
106248
107283
  }
106249
107284
  }
106250
107285
  }
106251
107286
  const files = artifacts.files.map((f) => ({
106252
- path: path45.join(outputDir, f.relativePath),
107287
+ path: path46.join(outputDir, f.relativePath),
106253
107288
  content: f.content
106254
107289
  }));
106255
107290
  if (compiledContent) {
106256
- const workflowOutputPath = path45.join(outputDir, "workflow.ts");
107291
+ const workflowOutputPath = path46.join(outputDir, "workflow.ts");
106257
107292
  files.push({ path: workflowOutputPath, content: compiledContent });
106258
107293
  }
106259
107294
  if (!isDryRun) {
106260
107295
  for (const file of files) {
106261
- const dirPath = path45.dirname(file.path);
106262
- fs43.mkdirSync(dirPath, { recursive: true });
106263
- fs43.writeFileSync(file.path, file.content, "utf-8");
107296
+ const dirPath = path46.dirname(file.path);
107297
+ fs44.mkdirSync(dirPath, { recursive: true });
107298
+ fs44.writeFileSync(file.path, file.content, "utf-8");
106264
107299
  }
106265
107300
  }
106266
107301
  return {
@@ -106271,7 +107306,7 @@ async function exportSingleWorkflowViaRegistry(target, inputPath, outputDir, isD
106271
107306
  };
106272
107307
  }
106273
107308
  async function exportMultiWorkflowViaRegistry(target, inputPath, outputDir, isDryRun, options) {
106274
- if (!fs43.existsSync(inputPath)) {
107309
+ if (!fs44.existsSync(inputPath)) {
106275
107310
  throw new Error(`Input file not found: ${inputPath}`);
106276
107311
  }
106277
107312
  const parser3 = new AnnotationParser();
@@ -106289,7 +107324,7 @@ async function exportMultiWorkflowViaRegistry(target, inputPath, outputDir, isDr
106289
107324
  throw new Error(`None of the requested workflows found. Available: ${available}`);
106290
107325
  }
106291
107326
  }
106292
- const serviceName = path45.basename(options.input, path45.extname(options.input)) + "-service";
107327
+ const serviceName = path46.basename(options.input, path46.extname(options.input)) + "-service";
106293
107328
  const bundleWorkflows = selectedWorkflows.map((w) => ({
106294
107329
  name: w.name,
106295
107330
  functionName: w.functionName,
@@ -106314,15 +107349,15 @@ async function exportMultiWorkflowViaRegistry(target, inputPath, outputDir, isDr
106314
107349
  });
106315
107350
  const files = artifacts.files.map(
106316
107351
  (f) => ({
106317
- path: path45.join(outputDir, f.relativePath),
107352
+ path: path46.join(outputDir, f.relativePath),
106318
107353
  content: f.content
106319
107354
  })
106320
107355
  );
106321
107356
  if (!isDryRun) {
106322
107357
  for (const file of files) {
106323
- const dirPath = path45.dirname(file.path);
106324
- fs43.mkdirSync(dirPath, { recursive: true });
106325
- fs43.writeFileSync(file.path, file.content, "utf-8");
107358
+ const dirPath = path46.dirname(file.path);
107359
+ fs44.mkdirSync(dirPath, { recursive: true });
107360
+ fs44.writeFileSync(file.path, file.content, "utf-8");
106326
107361
  }
106327
107362
  }
106328
107363
  return {
@@ -106333,8 +107368,8 @@ async function exportMultiWorkflowViaRegistry(target, inputPath, outputDir, isDr
106333
107368
  };
106334
107369
  }
106335
107370
  async function compileToOutput(inputPath, functionName, outputDir, production) {
106336
- const outputPath = path45.join(outputDir, "workflow.ts");
106337
- fs43.copyFileSync(inputPath, outputPath);
107371
+ const outputPath = path46.join(outputDir, "workflow.ts");
107372
+ fs44.copyFileSync(inputPath, outputPath);
106338
107373
  await compileWorkflow(outputPath, {
106339
107374
  write: true,
106340
107375
  inPlace: true,
@@ -106454,15 +107489,15 @@ async function exportCommand(input, options) {
106454
107489
  }
106455
107490
 
106456
107491
  // src/cli/commands/openapi.ts
106457
- import * as path46 from "path";
106458
- import * as fs44 from "fs";
107492
+ import * as path47 from "path";
107493
+ import * as fs45 from "fs";
106459
107494
  init_generator();
106460
107495
  async function openapiCommand(dir, options) {
106461
- const workflowDir = path46.resolve(dir);
106462
- if (!fs44.existsSync(workflowDir)) {
107496
+ const workflowDir = path47.resolve(dir);
107497
+ if (!fs45.existsSync(workflowDir)) {
106463
107498
  throw new Error(`Directory not found: ${workflowDir}`);
106464
107499
  }
106465
- if (!fs44.statSync(workflowDir).isDirectory()) {
107500
+ if (!fs45.statSync(workflowDir).isDirectory()) {
106466
107501
  throw new Error(`Not a directory: ${workflowDir}`);
106467
107502
  }
106468
107503
  const registry2 = new WorkflowRegistry(workflowDir);
@@ -106483,8 +107518,8 @@ async function openapiCommand(dir, options) {
106483
107518
  const format = options.format || "json";
106484
107519
  const spec = format === "yaml" ? generateOpenAPIYaml(endpoints, generatorOptions) : generateOpenAPIJson(endpoints, generatorOptions);
106485
107520
  if (options.output) {
106486
- const outputPath = path46.resolve(options.output);
106487
- fs44.writeFileSync(outputPath, spec);
107521
+ const outputPath = path47.resolve(options.output);
107522
+ fs45.writeFileSync(outputPath, spec);
106488
107523
  logger.success(`OpenAPI specification written to ${outputPath}`);
106489
107524
  } else {
106490
107525
  process.stdout.write(spec + "\n");
@@ -106492,8 +107527,8 @@ async function openapiCommand(dir, options) {
106492
107527
  }
106493
107528
 
106494
107529
  // src/cli/commands/plugin.ts
106495
- import * as fs45 from "fs";
106496
- import * as path47 from "path";
107530
+ import * as fs46 from "fs";
107531
+ import * as path48 from "path";
106497
107532
  var PLUGIN_NAME_RE = /^[a-zA-Z0-9][-a-zA-Z0-9_.]*$/;
106498
107533
  var VALID_AREAS = ["sidebar", "main", "toolbar", "modal", "panel"];
106499
107534
  function validatePluginName(name) {
@@ -106620,18 +107655,18 @@ async function pluginInitCommand(name, options) {
106620
107655
  }
106621
107656
  return;
106622
107657
  }
106623
- const targetDir = path47.resolve("plugins", name);
107658
+ const targetDir = path48.resolve("plugins", name);
106624
107659
  const filesCreated = [];
106625
107660
  const filesSkipped = [];
106626
107661
  for (const [relativePath, content] of Object.entries(files)) {
106627
- const absPath = path47.join(targetDir, relativePath);
106628
- const dir = path47.dirname(absPath);
106629
- fs45.mkdirSync(dir, { recursive: true });
106630
- if (fs45.existsSync(absPath) && !force) {
107662
+ const absPath = path48.join(targetDir, relativePath);
107663
+ const dir = path48.dirname(absPath);
107664
+ fs46.mkdirSync(dir, { recursive: true });
107665
+ if (fs46.existsSync(absPath) && !force) {
106631
107666
  filesSkipped.push(relativePath);
106632
107667
  continue;
106633
107668
  }
106634
- fs45.writeFileSync(absPath, content, "utf8");
107669
+ fs46.writeFileSync(absPath, content, "utf8");
106635
107670
  filesCreated.push(relativePath);
106636
107671
  }
106637
107672
  logger.section("Plugin scaffolded");
@@ -106652,8 +107687,8 @@ async function pluginInitCommand(name, options) {
106652
107687
  init_esm5();
106653
107688
  init_api6();
106654
107689
  init_generate_in_place();
106655
- import * as fs46 from "fs";
106656
- import * as path48 from "path";
107690
+ import * as fs47 from "fs";
107691
+ import * as path49 from "path";
106657
107692
  init_error_utils();
106658
107693
  async function migrateCommand(globPattern, options = {}) {
106659
107694
  const { dryRun = false, diff = false } = options;
@@ -106671,9 +107706,9 @@ async function migrateCommand(globPattern, options = {}) {
106671
107706
  let skippedCount = 0;
106672
107707
  let errorCount = 0;
106673
107708
  for (const file of files) {
106674
- const filePath = path48.resolve(file);
107709
+ const filePath = path49.resolve(file);
106675
107710
  try {
106676
- const sourceCode = fs46.readFileSync(filePath, "utf8");
107711
+ const sourceCode = fs47.readFileSync(filePath, "utf8");
106677
107712
  const parseResult = await parseWorkflow(filePath);
106678
107713
  if (parseResult.errors.length > 0) {
106679
107714
  logger.error(` ${file}: parse errors \u2014 skipping`);
@@ -106706,7 +107741,7 @@ ${file}:`);
106706
107741
  migratedCount++;
106707
107742
  continue;
106708
107743
  }
106709
- fs46.writeFileSync(filePath, genResult.code, "utf8");
107744
+ fs47.writeFileSync(filePath, genResult.code, "utf8");
106710
107745
  logger.success(` ${file}: migrated`);
106711
107746
  migratedCount++;
106712
107747
  } catch (error2) {
@@ -106723,7 +107758,7 @@ ${file}:`);
106723
107758
  }
106724
107759
 
106725
107760
  // src/cli/commands/changelog.ts
106726
- import { execSync as execSync4 } from "child_process";
107761
+ import { execSync as execSync5 } from "child_process";
106727
107762
  var CATEGORIES2 = [
106728
107763
  { name: "Grammar", match: (f) => /parser|chevrotain|grammar/.test(f) },
106729
107764
  { name: "Code Generation", match: (f) => /generator|body-generator|generate/.test(f) },
@@ -106750,7 +107785,7 @@ function getGitRange(options) {
106750
107785
  }
106751
107786
  if (options.lastTag) {
106752
107787
  try {
106753
- const lastTag = execSync4("git describe --tags --abbrev=0", {
107788
+ const lastTag = execSync5("git describe --tags --abbrev=0", {
106754
107789
  encoding: "utf8"
106755
107790
  }).trim();
106756
107791
  return `${lastTag}..HEAD`;
@@ -106775,7 +107810,7 @@ function getCommits(rangeArg) {
106775
107810
  } else {
106776
107811
  logCmd = `git log ${rangeArg} --format="%H %s" --no-merges`;
106777
107812
  }
106778
- const logOutput = execSync4(logCmd, { encoding: "utf8" }).trim();
107813
+ const logOutput = execSync5(logCmd, { encoding: "utf8" }).trim();
106779
107814
  if (!logOutput) {
106780
107815
  return [];
106781
107816
  }
@@ -106787,7 +107822,7 @@ function getCommits(rangeArg) {
106787
107822
  const message = line.slice(spaceIdx + 1);
106788
107823
  let files;
106789
107824
  try {
106790
- const filesOutput = execSync4(`git diff-tree --no-commit-id --name-only -r ${hash}`, {
107825
+ const filesOutput = execSync5(`git diff-tree --no-commit-id --name-only -r ${hash}`, {
106791
107826
  encoding: "utf8"
106792
107827
  }).trim();
106793
107828
  files = filesOutput ? filesOutput.split(/\r?\n/) : [];
@@ -106839,21 +107874,21 @@ async function changelogCommand(options = {}) {
106839
107874
  // src/cli/commands/strip.ts
106840
107875
  init_esm5();
106841
107876
  init_generate_in_place();
106842
- import * as fs47 from "fs";
106843
- import * as path49 from "path";
107877
+ import * as fs48 from "fs";
107878
+ import * as path50 from "path";
106844
107879
  async function stripCommand(input, options = {}) {
106845
107880
  const { output, dryRun = false, verbose = false } = options;
106846
107881
  let pattern = input;
106847
107882
  try {
106848
- if (fs47.existsSync(input) && fs47.statSync(input).isDirectory()) {
106849
- pattern = path49.join(input, "**/*.ts");
107883
+ if (fs48.existsSync(input) && fs48.statSync(input).isDirectory()) {
107884
+ pattern = path50.join(input, "**/*.ts");
106850
107885
  }
106851
107886
  } catch {
106852
107887
  }
106853
107888
  const allFiles = await glob(pattern, { absolute: true });
106854
107889
  const files = allFiles.filter((f) => {
106855
107890
  try {
106856
- return fs47.statSync(f).isFile();
107891
+ return fs48.statSync(f).isFile();
106857
107892
  } catch {
106858
107893
  return false;
106859
107894
  }
@@ -106866,28 +107901,28 @@ async function stripCommand(input, options = {}) {
106866
107901
  let stripped = 0;
106867
107902
  let skipped = 0;
106868
107903
  for (const filePath of files) {
106869
- const content = fs47.readFileSync(filePath, "utf-8");
107904
+ const content = fs48.readFileSync(filePath, "utf-8");
106870
107905
  if (!hasInPlaceMarkers(content)) {
106871
107906
  skipped++;
106872
107907
  if (verbose) {
106873
- logger.info(`Skipped (no markers): ${path49.relative(process.cwd(), filePath)}`);
107908
+ logger.info(`Skipped (no markers): ${path50.relative(process.cwd(), filePath)}`);
106874
107909
  }
106875
107910
  continue;
106876
107911
  }
106877
107912
  const result = stripGeneratedSections(content);
106878
107913
  if (dryRun) {
106879
- logger.info(`Would strip: ${path49.relative(process.cwd(), filePath)}`);
107914
+ logger.info(`Would strip: ${path50.relative(process.cwd(), filePath)}`);
106880
107915
  stripped++;
106881
107916
  continue;
106882
107917
  }
106883
- const outPath = output ? path49.join(path49.resolve(output), path49.basename(filePath)) : filePath;
107918
+ const outPath = output ? path50.join(path50.resolve(output), path50.basename(filePath)) : filePath;
106884
107919
  if (output) {
106885
- fs47.mkdirSync(path49.dirname(outPath), { recursive: true });
107920
+ fs48.mkdirSync(path50.dirname(outPath), { recursive: true });
106886
107921
  }
106887
- fs47.writeFileSync(outPath, result);
107922
+ fs48.writeFileSync(outPath, result);
106888
107923
  stripped++;
106889
107924
  if (verbose) {
106890
- logger.success(`Stripped: ${path49.relative(process.cwd(), outPath)}`);
107925
+ logger.success(`Stripped: ${path50.relative(process.cwd(), outPath)}`);
106891
107926
  }
106892
107927
  }
106893
107928
  const verb = dryRun ? "would be stripped" : "stripped";
@@ -106968,7 +108003,7 @@ async function docsSearchCommand(query, options) {
106968
108003
  }
106969
108004
 
106970
108005
  // src/cli/commands/context.ts
106971
- import * as fs48 from "fs";
108006
+ import * as fs49 from "fs";
106972
108007
  async function contextCommand(preset, options) {
106973
108008
  if (options.list) {
106974
108009
  logger.section("Context Presets");
@@ -107003,7 +108038,7 @@ async function contextCommand(preset, options) {
107003
108038
  includeGrammar: options.grammar !== false
107004
108039
  });
107005
108040
  if (options.output) {
107006
- fs48.writeFileSync(options.output, result.content, "utf-8");
108041
+ fs49.writeFileSync(options.output, result.content, "utf-8");
107007
108042
  logger.success(`Context written to ${options.output}`);
107008
108043
  } else {
107009
108044
  process.stdout.write(result.content);
@@ -107016,8 +108051,8 @@ async function contextCommand(preset, options) {
107016
108051
  // src/cli/commands/status.ts
107017
108052
  init_api6();
107018
108053
  init_validator();
107019
- import * as fs49 from "fs";
107020
- import * as path50 from "path";
108054
+ import * as fs50 from "fs";
108055
+ import * as path51 from "path";
107021
108056
  init_error_utils();
107022
108057
  function formatPortList(ports) {
107023
108058
  return Object.entries(ports).filter(([name]) => name !== "execute" && name !== "onSuccess" && name !== "onFailure").map(([name, port]) => `${name}(${port.dataType.toLowerCase()})`);
@@ -107025,8 +108060,8 @@ function formatPortList(ports) {
107025
108060
  async function statusCommand(input, options = {}) {
107026
108061
  const { workflowName, json: json2 = false } = options;
107027
108062
  try {
107028
- const filePath = path50.resolve(input);
107029
- if (!fs49.existsSync(filePath)) {
108063
+ const filePath = path51.resolve(input);
108064
+ if (!fs50.existsSync(filePath)) {
107030
108065
  if (json2) {
107031
108066
  console.log(JSON.stringify({ error: `File not found: ${input}` }));
107032
108067
  } else {
@@ -107120,8 +108155,8 @@ async function statusCommand(input, options = {}) {
107120
108155
  // src/cli/commands/implement.ts
107121
108156
  init_api6();
107122
108157
  init_annotation_generator();
107123
- import * as fs50 from "fs";
107124
- import * as path51 from "path";
108158
+ import * as fs51 from "fs";
108159
+ import * as path52 from "path";
107125
108160
  init_error_utils();
107126
108161
  function findDeclareFunction2(source, functionName) {
107127
108162
  const lines = source.split("\n");
@@ -107144,8 +108179,8 @@ function findDeclareFunction2(source, functionName) {
107144
108179
  async function implementCommand(input, nodeName, options = {}) {
107145
108180
  const { workflowName, preview = false } = options;
107146
108181
  try {
107147
- const filePath = path51.resolve(input);
107148
- if (!fs50.existsSync(filePath)) {
108182
+ const filePath = path52.resolve(input);
108183
+ if (!fs51.existsSync(filePath)) {
107149
108184
  logger.error(`File not found: ${input}`);
107150
108185
  process.exit(1);
107151
108186
  }
@@ -107175,7 +108210,7 @@ async function implementCommand(input, nodeName, options = {}) {
107175
108210
  }
107176
108211
  process.exit(1);
107177
108212
  }
107178
- const source = fs50.readFileSync(filePath, "utf8");
108213
+ const source = fs51.readFileSync(filePath, "utf8");
107179
108214
  const found = findDeclareFunction2(source, stubNodeType.functionName);
107180
108215
  if (!found) {
107181
108216
  logger.error(`Could not find "declare function ${stubNodeType.functionName}" in source file.`);
@@ -107190,8 +108225,8 @@ async function implementCommand(input, nodeName, options = {}) {
107190
108225
  console.log(replacement);
107191
108226
  } else {
107192
108227
  const updated = source.replace(found.match, replacement);
107193
- fs50.writeFileSync(filePath, updated, "utf8");
107194
- logger.success(`Implemented ${stubNodeType.functionName} in ${path51.basename(filePath)}`);
108228
+ fs51.writeFileSync(filePath, updated, "utf8");
108229
+ logger.success(`Implemented ${stubNodeType.functionName} in ${path52.basename(filePath)}`);
107195
108230
  }
107196
108231
  } catch (error2) {
107197
108232
  logger.error(`Implement failed: ${getErrorMessage(error2)}`);
@@ -107200,9 +108235,9 @@ async function implementCommand(input, nodeName, options = {}) {
107200
108235
  }
107201
108236
 
107202
108237
  // src/cli/commands/market.ts
107203
- import * as fs51 from "fs";
107204
- import * as path52 from "path";
107205
- import { execSync as execSync5 } from "child_process";
108238
+ import * as fs52 from "fs";
108239
+ import * as path53 from "path";
108240
+ import { execSync as execSync6 } from "child_process";
107206
108241
  init_error_utils();
107207
108242
  async function marketInitCommand(name, options = {}) {
107208
108243
  if (!name.startsWith("flowweaver-pack-")) {
@@ -107210,11 +108245,11 @@ async function marketInitCommand(name, options = {}) {
107210
108245
  logger.warn(`Name should follow "flowweaver-pack-*" convention, using "${suggested}"`);
107211
108246
  name = suggested;
107212
108247
  }
107213
- const targetDir = path52.resolve(name);
107214
- if (fs51.existsSync(targetDir)) {
107215
- const stat2 = fs51.statSync(targetDir);
108248
+ const targetDir = path53.resolve(name);
108249
+ if (fs52.existsSync(targetDir)) {
108250
+ const stat2 = fs52.statSync(targetDir);
107216
108251
  if (stat2.isDirectory()) {
107217
- const contents = fs51.readdirSync(targetDir);
108252
+ const contents = fs52.readdirSync(targetDir);
107218
108253
  if (contents.length > 0) {
107219
108254
  logger.error(`Directory "${name}" already exists and is not empty`);
107220
108255
  process.exit(1);
@@ -107229,13 +108264,13 @@ async function marketInitCommand(name, options = {}) {
107229
108264
  logger.newline();
107230
108265
  const dirs = [
107231
108266
  targetDir,
107232
- path52.join(targetDir, "src"),
107233
- path52.join(targetDir, "src", "node-types"),
107234
- path52.join(targetDir, "src", "workflows"),
107235
- path52.join(targetDir, "src", "patterns")
108267
+ path53.join(targetDir, "src"),
108268
+ path53.join(targetDir, "src", "node-types"),
108269
+ path53.join(targetDir, "src", "workflows"),
108270
+ path53.join(targetDir, "src", "patterns")
107236
108271
  ];
107237
108272
  for (const dir of dirs) {
107238
- fs51.mkdirSync(dir, { recursive: true });
108273
+ fs52.mkdirSync(dir, { recursive: true });
107239
108274
  }
107240
108275
  const shortName = name.replace(/^flowweaver-pack-/, "");
107241
108276
  const pkg = {
@@ -107266,8 +108301,8 @@ async function marketInitCommand(name, options = {}) {
107266
108301
  },
107267
108302
  files: ["dist", "flowweaver.manifest.json", "README.md", "LICENSE"]
107268
108303
  };
107269
- fs51.writeFileSync(
107270
- path52.join(targetDir, "package.json"),
108304
+ fs52.writeFileSync(
108305
+ path53.join(targetDir, "package.json"),
107271
108306
  JSON.stringify(pkg, null, 2) + "\n"
107272
108307
  );
107273
108308
  const tsconfig = {
@@ -107285,8 +108320,8 @@ async function marketInitCommand(name, options = {}) {
107285
108320
  include: ["src"],
107286
108321
  exclude: ["node_modules", "dist"]
107287
108322
  };
107288
- fs51.writeFileSync(
107289
- path52.join(targetDir, "tsconfig.json"),
108323
+ fs52.writeFileSync(
108324
+ path53.join(targetDir, "tsconfig.json"),
107290
108325
  JSON.stringify(tsconfig, null, 2) + "\n"
107291
108326
  );
107292
108327
  const sampleNodeType = `/**
@@ -107304,21 +108339,21 @@ export function sample(execute: () => void, data: string): { result: string } {
107304
108339
  return { result: data.toUpperCase() };
107305
108340
  }
107306
108341
  `;
107307
- fs51.writeFileSync(path52.join(targetDir, "src", "node-types", "sample.ts"), sampleNodeType);
107308
- fs51.writeFileSync(
107309
- path52.join(targetDir, "src", "node-types", "index.ts"),
108342
+ fs52.writeFileSync(path53.join(targetDir, "src", "node-types", "sample.ts"), sampleNodeType);
108343
+ fs52.writeFileSync(
108344
+ path53.join(targetDir, "src", "node-types", "index.ts"),
107310
108345
  "export { sample } from './sample.js';\n"
107311
108346
  );
107312
- fs51.writeFileSync(
107313
- path52.join(targetDir, "src", "workflows", "index.ts"),
108347
+ fs52.writeFileSync(
108348
+ path53.join(targetDir, "src", "workflows", "index.ts"),
107314
108349
  "// Export workflows here\n"
107315
108350
  );
107316
- fs51.writeFileSync(
107317
- path52.join(targetDir, "src", "patterns", "index.ts"),
108351
+ fs52.writeFileSync(
108352
+ path53.join(targetDir, "src", "patterns", "index.ts"),
107318
108353
  "// Export patterns here\n"
107319
108354
  );
107320
- fs51.writeFileSync(
107321
- path52.join(targetDir, "src", "index.ts"),
108355
+ fs52.writeFileSync(
108356
+ path53.join(targetDir, "src", "index.ts"),
107322
108357
  [
107323
108358
  "export * from './node-types/index.js';",
107324
108359
  "export * from './workflows/index.js';",
@@ -107351,9 +108386,9 @@ npm run pack # Generate flowweaver.manifest.json
107351
108386
  npm publish # Publish to npm
107352
108387
  \`\`\`
107353
108388
  `;
107354
- fs51.writeFileSync(path52.join(targetDir, "README.md"), readme);
107355
- fs51.writeFileSync(
107356
- path52.join(targetDir, ".gitignore"),
108389
+ fs52.writeFileSync(path53.join(targetDir, "README.md"), readme);
108390
+ fs52.writeFileSync(
108391
+ path53.join(targetDir, ".gitignore"),
107357
108392
  ["node_modules", "dist", "*.tgz", ""].join("\n")
107358
108393
  );
107359
108394
  logger.success("Created package.json");
@@ -107373,7 +108408,7 @@ npm publish # Publish to npm
107373
108408
  logger.newline();
107374
108409
  }
107375
108410
  async function marketPackCommand(directory, options = {}) {
107376
- const dir = path52.resolve(directory ?? ".");
108411
+ const dir = path53.resolve(directory ?? ".");
107377
108412
  const { json: json2 = false, verbose = false } = options;
107378
108413
  if (!json2) {
107379
108414
  logger.section("Packing Marketplace Package");
@@ -107414,28 +108449,28 @@ async function marketPackCommand(directory, options = {}) {
107414
108449
  }
107415
108450
  const outPath = writeManifest(dir, manifest);
107416
108451
  logger.newline();
107417
- logger.success(`Manifest written to ${path52.relative(dir, outPath)}`);
108452
+ logger.success(`Manifest written to ${path53.relative(dir, outPath)}`);
107418
108453
  if (warnings.length > 0) {
107419
108454
  logger.warn(`${warnings.length} warning(s) \u2014 consider fixing before publishing`);
107420
108455
  }
107421
108456
  logger.newline();
107422
108457
  }
107423
108458
  async function marketPublishCommand(directory, options = {}) {
107424
- const dir = path52.resolve(directory ?? ".");
108459
+ const dir = path53.resolve(directory ?? ".");
107425
108460
  const { dryRun = false, tag } = options;
107426
108461
  logger.section("Publishing Marketplace Package");
107427
108462
  await marketPackCommand(dir, { json: false });
107428
- if (!fs51.existsSync(path52.join(dir, "LICENSE"))) {
108463
+ if (!fs52.existsSync(path53.join(dir, "LICENSE"))) {
107429
108464
  logger.warn("LICENSE file not found \u2014 consider adding one");
107430
108465
  }
107431
- const pkg = JSON.parse(fs51.readFileSync(path52.join(dir, "package.json"), "utf-8"));
108466
+ const pkg = JSON.parse(fs52.readFileSync(path53.join(dir, "package.json"), "utf-8"));
107432
108467
  logger.info(`Publishing ${pkg.name}@${pkg.version}`);
107433
108468
  const npmArgs = ["publish"];
107434
108469
  if (dryRun) npmArgs.push("--dry-run");
107435
108470
  if (tag) npmArgs.push("--tag", tag);
107436
108471
  try {
107437
108472
  logger.newline();
107438
- execSync5(`npm ${npmArgs.join(" ")}`, { cwd: dir, stdio: "inherit" });
108473
+ execSync6(`npm ${npmArgs.join(" ")}`, { cwd: dir, stdio: "inherit" });
107439
108474
  if (!dryRun) {
107440
108475
  logger.newline();
107441
108476
  logger.success(`Published ${pkg.name}@${pkg.version} to npm`);
@@ -107453,7 +108488,7 @@ async function marketInstallCommand(packageSpec, options = {}) {
107453
108488
  logger.newline();
107454
108489
  }
107455
108490
  try {
107456
- execSync5(`npm install ${packageSpec}`, { stdio: json2 ? "pipe" : "inherit" });
108491
+ execSync6(`npm install ${packageSpec}`, { stdio: json2 ? "pipe" : "inherit" });
107457
108492
  } catch (err) {
107458
108493
  if (json2) {
107459
108494
  console.log(JSON.stringify({ success: false, error: getErrorMessage(err) }));
@@ -107464,7 +108499,7 @@ async function marketInstallCommand(packageSpec, options = {}) {
107464
108499
  return;
107465
108500
  }
107466
108501
  const packageName = resolvePackageName2(packageSpec);
107467
- const manifest = readManifest(path52.join(process.cwd(), "node_modules", packageName));
108502
+ const manifest = readManifest(path53.join(process.cwd(), "node_modules", packageName));
107468
108503
  if (json2) {
107469
108504
  console.log(JSON.stringify({
107470
108505
  success: true,
@@ -107555,7 +108590,7 @@ async function marketListCommand(options = {}) {
107555
108590
  }
107556
108591
  function resolvePackageName2(spec) {
107557
108592
  if (spec.endsWith(".tgz") || spec.endsWith(".tar.gz")) {
107558
- const base = path52.basename(spec, spec.endsWith(".tar.gz") ? ".tar.gz" : ".tgz");
108593
+ const base = path53.basename(spec, spec.endsWith(".tar.gz") ? ".tar.gz" : ".tgz");
107559
108594
  const match2 = base.match(/^(.+)-\d+\.\d+\.\d+/);
107560
108595
  return match2 ? match2[1] : base;
107561
108596
  }
@@ -107603,334 +108638,9 @@ function displayInstalledPackage(pkg) {
107603
108638
  logger.newline();
107604
108639
  }
107605
108640
 
107606
- // src/cli/commands/mcp-setup.ts
107607
- import { execSync as execSync6 } from "child_process";
107608
- import * as fs52 from "fs";
107609
- import * as path53 from "path";
107610
- import * as os3 from "os";
107611
- var MCP_COMMAND = "npx";
107612
- var MCP_ARGS = ["@synergenius/flow-weaver@latest", "mcp-server", "--stdio"];
107613
- var MCP_ENTRY = { command: MCP_COMMAND, args: [...MCP_ARGS] };
107614
- function defaultDeps() {
107615
- return {
107616
- execCommand: async (cmd) => {
107617
- try {
107618
- const stdout = execSync6(cmd, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
107619
- return { stdout: stdout.trim(), exitCode: 0 };
107620
- } catch {
107621
- return { stdout: "", exitCode: 1 };
107622
- }
107623
- },
107624
- fileExists: async (filePath) => {
107625
- try {
107626
- await fs52.promises.access(filePath);
107627
- return true;
107628
- } catch {
107629
- return false;
107630
- }
107631
- },
107632
- readFile: async (filePath) => {
107633
- try {
107634
- return await fs52.promises.readFile(filePath, "utf8");
107635
- } catch {
107636
- return null;
107637
- }
107638
- },
107639
- writeFile: async (filePath, content) => {
107640
- await fs52.promises.writeFile(filePath, content, "utf8");
107641
- },
107642
- mkdir: async (dirPath) => {
107643
- await fs52.promises.mkdir(dirPath, { recursive: true });
107644
- },
107645
- cwd: () => process.cwd(),
107646
- homedir: () => os3.homedir(),
107647
- log: (msg) => process.stdout.write(msg + "\n")
107648
- };
107649
- }
107650
- function whichCmd(binary2) {
107651
- return process.platform === "win32" ? `where ${binary2}` : `which ${binary2}`;
107652
- }
107653
- async function binaryExists(binary2, deps) {
107654
- const result = await deps.execCommand(whichCmd(binary2));
107655
- return result.exitCode === 0;
107656
- }
107657
- async function mergeJsonConfig(deps, filePath, rootKey) {
107658
- const existing = await deps.readFile(filePath);
107659
- if (existing === null) {
107660
- const dir = path53.dirname(filePath);
107661
- await deps.mkdir(dir);
107662
- const config3 = { [rootKey]: { "flow-weaver": MCP_ENTRY } };
107663
- await deps.writeFile(filePath, JSON.stringify(config3, null, 2) + "\n");
107664
- return { action: "created", detail: `created ${filePath}` };
107665
- }
107666
- let config2;
107667
- try {
107668
- config2 = JSON.parse(existing);
107669
- } catch {
107670
- throw new Error(`invalid JSON in ${filePath}`);
107671
- }
107672
- if (!config2[rootKey] || typeof config2[rootKey] !== "object") {
107673
- config2[rootKey] = {};
107674
- }
107675
- const servers = config2[rootKey];
107676
- if (servers["flow-weaver"]) {
107677
- return { action: "already-configured", detail: `already in ${filePath}` };
107678
- }
107679
- servers["flow-weaver"] = MCP_ENTRY;
107680
- await deps.writeFile(filePath, JSON.stringify(config2, null, 2) + "\n");
107681
- return { action: "added", detail: `added to ${filePath}` };
107682
- }
107683
- var TOOL_REGISTRY = [
107684
- // Claude Code
107685
- {
107686
- id: "claude",
107687
- displayName: "Claude Code",
107688
- detect: (deps) => binaryExists("claude", deps),
107689
- isConfigured: async (deps) => {
107690
- const result = await deps.execCommand("claude mcp list");
107691
- return result.exitCode === 0 && result.stdout.includes("flow-weaver");
107692
- },
107693
- configure: async (deps) => {
107694
- const cmd = `claude mcp add --scope project flow-weaver -- ${MCP_COMMAND} ${MCP_ARGS.join(" ")}`;
107695
- const result = await deps.execCommand(cmd);
107696
- if (result.exitCode !== 0) {
107697
- throw new Error("claude mcp add failed");
107698
- }
107699
- return "registered via claude mcp add";
107700
- }
107701
- },
107702
- // Cursor
107703
- {
107704
- id: "cursor",
107705
- displayName: "Cursor",
107706
- detect: async (deps) => {
107707
- const dirExists = await deps.fileExists(path53.join(deps.cwd(), ".cursor"));
107708
- if (dirExists) return true;
107709
- return binaryExists("cursor", deps);
107710
- },
107711
- isConfigured: async (deps) => {
107712
- const filePath = path53.join(deps.cwd(), ".cursor", "mcp.json");
107713
- const content = await deps.readFile(filePath);
107714
- if (!content) return false;
107715
- try {
107716
- const config2 = JSON.parse(content);
107717
- return !!config2?.mcpServers?.["flow-weaver"];
107718
- } catch {
107719
- return false;
107720
- }
107721
- },
107722
- configure: async (deps) => {
107723
- const filePath = path53.join(deps.cwd(), ".cursor", "mcp.json");
107724
- const result = await mergeJsonConfig(deps, filePath, "mcpServers");
107725
- return result.detail;
107726
- }
107727
- },
107728
- // VS Code Copilot
107729
- {
107730
- id: "vscode",
107731
- displayName: "VS Code Copilot",
107732
- detect: (deps) => binaryExists("code", deps),
107733
- isConfigured: async (deps) => {
107734
- const filePath = path53.join(deps.cwd(), ".vscode", "mcp.json");
107735
- const content = await deps.readFile(filePath);
107736
- if (!content) return false;
107737
- try {
107738
- const config2 = JSON.parse(content);
107739
- return !!config2?.servers?.["flow-weaver"];
107740
- } catch {
107741
- return false;
107742
- }
107743
- },
107744
- configure: async (deps) => {
107745
- const filePath = path53.join(deps.cwd(), ".vscode", "mcp.json");
107746
- const result = await mergeJsonConfig(deps, filePath, "servers");
107747
- return result.detail;
107748
- }
107749
- },
107750
- // Windsurf
107751
- {
107752
- id: "windsurf",
107753
- displayName: "Windsurf",
107754
- detect: async (deps) => {
107755
- const configDir = path53.join(deps.homedir(), ".codeium", "windsurf");
107756
- const dirExists = await deps.fileExists(configDir);
107757
- if (dirExists) return true;
107758
- return binaryExists("windsurf", deps);
107759
- },
107760
- isConfigured: async (deps) => {
107761
- const filePath = path53.join(deps.homedir(), ".codeium", "windsurf", "mcp_config.json");
107762
- const content = await deps.readFile(filePath);
107763
- if (!content) return false;
107764
- try {
107765
- const config2 = JSON.parse(content);
107766
- return !!config2?.mcpServers?.["flow-weaver"];
107767
- } catch {
107768
- return false;
107769
- }
107770
- },
107771
- configure: async (deps) => {
107772
- const filePath = path53.join(deps.homedir(), ".codeium", "windsurf", "mcp_config.json");
107773
- const result = await mergeJsonConfig(deps, filePath, "mcpServers");
107774
- return result.detail;
107775
- }
107776
- },
107777
- // Codex (OpenAI)
107778
- {
107779
- id: "codex",
107780
- displayName: "Codex",
107781
- detect: (deps) => binaryExists("codex", deps),
107782
- isConfigured: async (deps) => {
107783
- const result = await deps.execCommand("codex mcp list");
107784
- return result.exitCode === 0 && result.stdout.includes("flow-weaver");
107785
- },
107786
- configure: async (deps) => {
107787
- const cmd = `codex mcp add flow-weaver -- ${MCP_COMMAND} ${MCP_ARGS.join(" ")}`;
107788
- const result = await deps.execCommand(cmd);
107789
- if (result.exitCode !== 0) {
107790
- throw new Error("codex mcp add failed");
107791
- }
107792
- return "registered via codex mcp add";
107793
- }
107794
- },
107795
- // OpenClaw
107796
- {
107797
- id: "openclaw",
107798
- displayName: "OpenClaw",
107799
- detect: async (deps) => {
107800
- return deps.fileExists(path53.join(deps.cwd(), "openclaw.json"));
107801
- },
107802
- isConfigured: async (deps) => {
107803
- const filePath = path53.join(deps.cwd(), "openclaw.json");
107804
- const content = await deps.readFile(filePath);
107805
- if (!content) return false;
107806
- try {
107807
- const config2 = JSON.parse(content);
107808
- return !!config2?.mcpServers?.["flow-weaver"];
107809
- } catch {
107810
- return false;
107811
- }
107812
- },
107813
- configure: async (deps) => {
107814
- const filePath = path53.join(deps.cwd(), "openclaw.json");
107815
- const result = await mergeJsonConfig(deps, filePath, "mcpServers");
107816
- return result.detail;
107817
- }
107818
- }
107819
- ];
107820
- async function detectTools(deps) {
107821
- const results = await Promise.all(
107822
- TOOL_REGISTRY.map(async (tool) => {
107823
- const detected = await tool.detect(deps);
107824
- const configured = detected ? await tool.isConfigured(deps) : false;
107825
- return { id: tool.id, displayName: tool.displayName, detected, configured };
107826
- })
107827
- );
107828
- return results;
107829
- }
107830
- async function configureTool(tool, deps) {
107831
- try {
107832
- const already = await tool.isConfigured(deps);
107833
- if (already) {
107834
- return { id: tool.id, displayName: tool.displayName, action: "already-configured", detail: "already configured" };
107835
- }
107836
- const detail = await tool.configure(deps);
107837
- return { id: tool.id, displayName: tool.displayName, action: "configured", detail };
107838
- } catch (err) {
107839
- const msg = err instanceof Error ? err.message : String(err);
107840
- return { id: tool.id, displayName: tool.displayName, action: "failed", detail: msg };
107841
- }
107842
- }
107843
- async function mcpSetupCommand(options, deps) {
107844
- const d = deps ?? defaultDeps();
107845
- const detected = await detectTools(d);
107846
- if (options.list) {
107847
- d.log("");
107848
- for (const t of detected) {
107849
- const status = t.detected ? t.configured ? "detected, configured" : "detected" : "not found";
107850
- const icon = t.detected ? t.configured ? "\u25CF" : "\u25CB" : "\xB7";
107851
- d.log(` ${icon} ${t.displayName.padEnd(18)} ${status}`);
107852
- }
107853
- d.log("");
107854
- return;
107855
- }
107856
- let toolIds;
107857
- if (options.tool && options.tool.length > 0) {
107858
- const valid = new Set(TOOL_REGISTRY.map((t) => t.id));
107859
- for (const name of options.tool) {
107860
- if (!valid.has(name)) {
107861
- d.log(`Unknown tool: "${name}". Valid tools: ${[...valid].join(", ")}`);
107862
- return;
107863
- }
107864
- }
107865
- toolIds = options.tool;
107866
- } else if (options.all) {
107867
- toolIds = detected.filter((t) => t.detected).map((t) => t.id);
107868
- } else if (isNonInteractive()) {
107869
- toolIds = detected.filter((t) => t.detected).map((t) => t.id);
107870
- } else {
107871
- const detectedTools = detected.filter((t) => t.detected);
107872
- if (detectedTools.length === 0) {
107873
- d.log("No AI coding tools detected. You can specify tools manually with --tool.");
107874
- return;
107875
- }
107876
- d.log("");
107877
- d.log("Detected tools:");
107878
- for (const t of detected) {
107879
- const icon = t.detected ? "\u2713" : "\u2717";
107880
- d.log(` ${icon} ${t.displayName}`);
107881
- }
107882
- d.log("");
107883
- toolIds = [];
107884
- try {
107885
- for (const t of detectedTools) {
107886
- if (t.configured) {
107887
- d.log(` ${t.displayName}: already configured, skipping`);
107888
- continue;
107889
- }
107890
- const yes = await dist_default6({
107891
- message: `Configure ${t.displayName}?`,
107892
- default: true
107893
- });
107894
- if (yes) toolIds.push(t.id);
107895
- }
107896
- } catch (err) {
107897
- if (err instanceof ExitPromptError4) return;
107898
- throw err;
107899
- }
107900
- d.log("");
107901
- }
107902
- if (toolIds.length === 0) {
107903
- const anyDetected = detected.some((t) => t.detected);
107904
- if (!anyDetected) {
107905
- d.log("No AI coding tools detected. You can specify tools manually with --tool.");
107906
- } else {
107907
- d.log("No tools selected.");
107908
- }
107909
- return;
107910
- }
107911
- const toolMap = new Map(TOOL_REGISTRY.map((t) => [t.id, t]));
107912
- const results = [];
107913
- for (const id of toolIds) {
107914
- const tool = toolMap.get(id);
107915
- const result = await configureTool(tool, d);
107916
- results.push(result);
107917
- const icon = result.action === "configured" ? "\u2713" : result.action === "already-configured" ? "\u25CF" : "\u2717";
107918
- d.log(`${icon} ${result.displayName}: ${result.detail}`);
107919
- }
107920
- const configured = results.filter((r) => r.action === "configured").length;
107921
- const alreadyDone = results.filter((r) => r.action === "already-configured").length;
107922
- const failed = results.filter((r) => r.action === "failed").length;
107923
- const parts2 = [];
107924
- if (configured > 0) parts2.push(`${configured} configured`);
107925
- if (alreadyDone > 0) parts2.push(`${alreadyDone} already configured`);
107926
- if (failed > 0) parts2.push(`${failed} failed`);
107927
- d.log("");
107928
- d.log(`Done. ${parts2.join(", ")}.`);
107929
- }
107930
-
107931
108641
  // src/cli/index.ts
107932
108642
  init_error_utils();
107933
- var version2 = true ? "0.16.0" : "0.0.0-dev";
108643
+ var version2 = true ? "0.17.0" : "0.0.0-dev";
107934
108644
  var program2 = new Command();
107935
108645
  program2.name("flow-weaver").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", () => {
107936
108646
  logger.banner(version2);
@@ -107990,7 +108700,7 @@ program2.command("validate <input>").description("Validate workflow files withou
107990
108700
  program2.command("doctor").description("Check project environment and configuration for flow-weaver compatibility").option("--json", "Output results as JSON", false).action(wrapAction(async (options) => {
107991
108701
  await doctorCommand(options);
107992
108702
  }));
107993
- program2.command("init [directory]").description("Create a new flow-weaver project").option("-n, --name <name>", "Project name (defaults to directory name)").option("-t, --template <template>", "Workflow template (default: sequential)").option("-f, --format <format>", "Module format: esm or cjs (default: esm)").option("-y, --yes", "Skip prompts and use defaults", false).option("--install", "Run npm install after scaffolding").option("--no-install", "Skip npm install").option("--git", "Initialize a git repository").option("--no-git", "Skip git init").option("--force", "Overwrite existing files", false).option("--json", "Output results as JSON", false).action(wrapAction(async (directory, options) => {
108703
+ program2.command("init [directory]").description("Create a new flow-weaver project").option("-n, --name <name>", "Project name (defaults to directory name)").option("-t, --template <template>", "Workflow template (default: sequential)").option("-f, --format <format>", "Module format: esm or cjs (default: esm)").option("-y, --yes", "Skip prompts and use defaults", false).option("--preset <persona>", "User preset: nocode, vibecoder, lowcode, expert").option("--use-case <category>", "Use case: data, ai, api, automation, cicd, minimal").option("--mcp", "Auto-configure MCP for AI editors after scaffolding").option("--no-mcp", "Skip MCP setup prompt").option("--no-agent", "Skip post-init agent launch prompt").option("--install", "Run npm install after scaffolding").option("--no-install", "Skip npm install").option("--git", "Initialize a git repository").option("--no-git", "Skip git init").option("--force", "Overwrite existing files", false).option("--json", "Output results as JSON", false).action(wrapAction(async (directory, options) => {
107994
108704
  await initCommand(directory, options);
107995
108705
  }));
107996
108706
  program2.command("watch <input>").description("Watch workflow files and recompile on changes").option("-o, --output <path>", "Output file or directory").option("-p, --production", "Generate production code (no debug events)", false).option("-s, --source-map", "Generate source maps", false).option("--verbose", "Verbose output", false).option("-w, --workflow <name>", "Specific workflow name to compile").option("-f, --format <format>", "Module format: esm, cjs, or auto", "auto").action(wrapAction(async (input, options) => {