@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.
- package/dist/cli/commands/init-personas.d.ts +87 -0
- package/dist/cli/commands/init-personas.js +492 -0
- package/dist/cli/commands/init.d.ts +30 -2
- package/dist/cli/commands/init.js +304 -79
- package/dist/cli/commands/mcp-setup.d.ts +17 -0
- package/dist/cli/commands/mcp-setup.js +44 -0
- package/dist/cli/flow-weaver.mjs +1870 -1160
- package/dist/cli/index.js +5 -0
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/package.json +1 -1
package/dist/cli/flow-weaver.mjs
CHANGED
|
@@ -2944,7 +2944,7 @@ var require_brace_expansion = __commonJS({
|
|
|
2944
2944
|
incr *= -1;
|
|
2945
2945
|
test = gte;
|
|
2946
2946
|
}
|
|
2947
|
-
var
|
|
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 (
|
|
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.
|
|
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
|
|
51555
|
+
const pad2 = 7;
|
|
51556
51556
|
const divGap = 4;
|
|
51557
|
-
return
|
|
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
|
|
53244
|
+
const pad2 = 7;
|
|
53245
53245
|
const divGap = 4;
|
|
53246
|
-
const badgeWidth =
|
|
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 -
|
|
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 +
|
|
53263
|
-
const divX = badgeX +
|
|
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
|
|
56437
|
-
import * as
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
56449
|
-
const source =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
56528
|
+
fs20.unlinkSync(tmpFile);
|
|
56529
56529
|
} catch {
|
|
56530
56530
|
}
|
|
56531
56531
|
try {
|
|
56532
|
-
|
|
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
|
|
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 =
|
|
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
|
|
72072
|
-
import * as
|
|
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 =
|
|
72166
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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
|
|
72506
|
-
import * as
|
|
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 =
|
|
72544
|
-
if (
|
|
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 =
|
|
72552
|
-
if (!
|
|
72551
|
+
const absolutePath = path33.resolve(filePath);
|
|
72552
|
+
if (!fs31.existsSync(absolutePath)) {
|
|
72553
72553
|
return null;
|
|
72554
72554
|
}
|
|
72555
|
-
const ext2 =
|
|
72555
|
+
const ext2 = path33.extname(absolutePath);
|
|
72556
72556
|
if (ext2 === ".yaml" || ext2 === ".yml") {
|
|
72557
72557
|
try {
|
|
72558
|
-
const content =
|
|
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
|
|
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:
|
|
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 =
|
|
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
|
|
74338
|
-
import * as
|
|
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 =
|
|
74364
|
-
if (!
|
|
74363
|
+
const nodeModules = path35.join(projectDir, "node_modules");
|
|
74364
|
+
if (!fs32.existsSync(nodeModules)) return [];
|
|
74365
74365
|
const patterns = [
|
|
74366
|
-
|
|
74367
|
-
|
|
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 =
|
|
74374
|
+
const pkgDir = path35.dirname(manifestPath);
|
|
74375
74375
|
const manifest = JSON.parse(
|
|
74376
|
-
|
|
74376
|
+
fs32.readFileSync(manifestPath, "utf-8")
|
|
74377
74377
|
);
|
|
74378
|
-
const pkgJsonPath =
|
|
74378
|
+
const pkgJsonPath = path35.join(pkgDir, "package.json");
|
|
74379
74379
|
let version3 = manifest.version;
|
|
74380
|
-
if (
|
|
74381
|
-
const pkg = JSON.parse(
|
|
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 =
|
|
74398
|
-
const manifestPath =
|
|
74399
|
-
if (!
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
77766
|
-
import * as
|
|
77767
|
-
import { execSync as
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 (
|
|
80819
|
-
|
|
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
|
-
|
|
80822
|
-
|
|
80823
|
-
|
|
80824
|
-
|
|
80825
|
-
|
|
80826
|
-
|
|
80827
|
-
|
|
80828
|
-
|
|
80829
|
-
|
|
80830
|
-
|
|
80831
|
-
|
|
80832
|
-
|
|
80833
|
-
|
|
80834
|
-
|
|
80835
|
-
|
|
80836
|
-
|
|
80837
|
-
|
|
80838
|
-
|
|
80839
|
-
|
|
80840
|
-
|
|
80841
|
-
|
|
80842
|
-
|
|
80843
|
-
|
|
80844
|
-
|
|
80845
|
-
|
|
80846
|
-
|
|
80847
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
81021
|
-
const dir =
|
|
81022
|
-
|
|
81023
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
81054
|
-
if (
|
|
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 =
|
|
82422
|
+
const workflowPath = path18.join(config2.targetDir, "src", workflowFile);
|
|
81078
82423
|
let compileResult;
|
|
81079
|
-
if (!options.json &&
|
|
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
|
-
|
|
81122
|
-
|
|
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
|
-
|
|
81126
|
-
|
|
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 (
|
|
81129
|
-
|
|
82520
|
+
if (agentLaunched) {
|
|
82521
|
+
return;
|
|
81130
82522
|
}
|
|
81131
|
-
|
|
81132
|
-
|
|
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
|
|
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: ${
|
|
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
|
|
81203
|
-
import * as
|
|
81204
|
-
import * as
|
|
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
|
|
82618
|
+
const pad2 = "\u2500".repeat(40);
|
|
81218
82619
|
logger.log(`
|
|
81219
|
-
${logger.dim(`\u2500\u2500\u2500 ${ts5} ${
|
|
82620
|
+
${logger.dim(`\u2500\u2500\u2500 ${ts5} ${pad2}`)}`);
|
|
81220
82621
|
if (file) {
|
|
81221
|
-
logger.log(` ${logger.dim("File changed:")} ${
|
|
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 =
|
|
81234
|
-
if (!
|
|
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 =
|
|
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 = `./${
|
|
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 =
|
|
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 =
|
|
81372
|
-
const inngestOutputPath =
|
|
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 (
|
|
81385
|
-
|
|
82785
|
+
if (fs21.existsSync(sourceOutput2)) {
|
|
82786
|
+
fs21.copyFileSync(sourceOutput2, inngestOutputPath);
|
|
81386
82787
|
try {
|
|
81387
|
-
|
|
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 =
|
|
82799
|
+
const entryPath = path21.join(tmpDir, "dev-server.ts");
|
|
81399
82800
|
const entryCode = generateDevServerEntry(inngestOutputPath, framework, port);
|
|
81400
|
-
|
|
81401
|
-
serverProcess =
|
|
81402
|
-
cwd:
|
|
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: ${
|
|
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(
|
|
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
|
-
|
|
82863
|
+
fs21.rmSync(tmpDir, { recursive: true, force: true });
|
|
81463
82864
|
} catch {
|
|
81464
82865
|
}
|
|
81465
82866
|
try {
|
|
81466
|
-
|
|
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 =
|
|
81478
|
-
if (!
|
|
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: ${
|
|
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
|
|
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
|
|
85066
|
-
import * as
|
|
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
|
|
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 +
|
|
85075
|
-
const resolved2 =
|
|
85076
|
-
if (!resolved2.startsWith(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 =
|
|
85090
|
-
if (!resolved.startsWith(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 =
|
|
86497
|
+
const rel = path22.relative(workspaceRoot, realPath);
|
|
85097
86498
|
if (rel.startsWith("..")) {
|
|
85098
|
-
return "/" +
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
85148
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
85187
|
-
const stat2 = await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
85247
|
-
const raw = await
|
|
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
|
|
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
|
|
85286
|
-
import * as
|
|
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,
|
|
86742
|
+
return resolveNpmNodeTypes(target, path24.dirname(filePath));
|
|
85342
86743
|
}
|
|
85343
86744
|
async function loadAllWorkflowsAST(wsPath) {
|
|
85344
|
-
const entries = await
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
85511
|
-
import * as
|
|
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
|
|
86915
|
+
import * as path25 from "node:path";
|
|
85515
86916
|
var fileMutationLocks = /* @__PURE__ */ new Map();
|
|
85516
86917
|
function withFileLock(filePath, operation) {
|
|
85517
|
-
const normalizedPath =
|
|
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
|
|
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
|
|
85586
|
-
return resolveNpmNodeTypes(updated,
|
|
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
|
|
85797
|
-
import * as
|
|
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
|
|
85890
|
-
await
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
101249
|
-
parseWorkflow(
|
|
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 =
|
|
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 =
|
|
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
|
|
101426
|
-
import * as
|
|
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 =
|
|
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 (
|
|
101485
|
-
|
|
102885
|
+
if (fs28.existsSync(outPath)) {
|
|
102886
|
+
fs28.appendFileSync(outPath, "\n\n" + code, "utf8");
|
|
101486
102887
|
} else {
|
|
101487
|
-
|
|
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 (
|
|
101509
|
-
|
|
102909
|
+
if (fs28.existsSync(outPath)) {
|
|
102910
|
+
fs28.appendFileSync(outPath, "\n\n" + code, "utf8");
|
|
101510
102911
|
} else {
|
|
101511
|
-
|
|
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
|
|
101540
|
-
import * as
|
|
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 =
|
|
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 =
|
|
101768
|
-
const targetFilePath =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
101871
|
-
const sourceCode =
|
|
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
|
-
|
|
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 =
|
|
102164
|
-
const sourceCode =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
102291
|
-
|
|
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 =
|
|
103736
|
+
const filePath = path31.resolve(file);
|
|
102336
103737
|
try {
|
|
102337
|
-
const sourceCode =
|
|
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
|
-
|
|
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
|
|
102384
|
-
import * as
|
|
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 =
|
|
102403
|
-
const 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
|
|
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 ||
|
|
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
|
|
103855
|
+
await fs33.promises.mkdir(outputDir, { recursive: true });
|
|
102455
103856
|
for (const file of artifacts2.files) {
|
|
102456
|
-
const fullPath =
|
|
102457
|
-
await
|
|
102458
|
-
await
|
|
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 ||
|
|
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
|
|
103935
|
+
await fs33.promises.mkdir(outputDir, { recursive: true });
|
|
102535
103936
|
for (const file of artifacts.files) {
|
|
102536
|
-
const fullPath =
|
|
102537
|
-
await
|
|
102538
|
-
await
|
|
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
|
|
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
|
|
102583
|
-
import * as
|
|
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 =
|
|
102655
|
-
if (!
|
|
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(
|
|
102663
|
-
const srcRoot =
|
|
102664
|
-
const pattern =
|
|
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 =
|
|
102678
|
-
const distRelative =
|
|
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 =
|
|
102715
|
-
|
|
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 =
|
|
102720
|
-
if (!
|
|
102721
|
-
return JSON.parse(
|
|
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
|
|
102737
|
-
import * as
|
|
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 (!
|
|
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 =
|
|
104260
|
+
const srcFile = path39.join(
|
|
102860
104261
|
directory,
|
|
102861
104262
|
wf.file.replace(/^dist\//, "src/").replace(/\.js$/, ".ts")
|
|
102862
104263
|
);
|
|
102863
|
-
if (!
|
|
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 =
|
|
102884
|
-
if (!
|
|
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(
|
|
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
|
-
|
|
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
|
|
103034
|
-
import * as
|
|
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 =
|
|
103072
|
-
if (!
|
|
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 =
|
|
103085
|
-
|
|
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
|
|
103384
|
-
import * as
|
|
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 =
|
|
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 =
|
|
103450
|
-
if (!
|
|
103451
|
-
|
|
104639
|
+
const dir = path41.dirname(outputPath);
|
|
104640
|
+
if (!fs37.existsSync(dir)) {
|
|
104641
|
+
fs37.mkdirSync(dir, { recursive: true });
|
|
103452
104642
|
}
|
|
103453
|
-
|
|
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 =
|
|
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 =
|
|
103547
|
-
if (!
|
|
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 =
|
|
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
|
-
|
|
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
|
|
103629
|
-
import * as
|
|
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
|
|
103857
|
-
import * as
|
|
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 =
|
|
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 =
|
|
105105
|
+
this.filePath = path42.resolve(workflowFilePath);
|
|
103916
105106
|
this.workflowName = workflowName;
|
|
103917
105107
|
this.runId = runId;
|
|
103918
105108
|
this.params = params;
|
|
103919
|
-
this.dir =
|
|
103920
|
-
this.checkpointPath =
|
|
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 (
|
|
103937
|
-
|
|
105126
|
+
if (fs38.existsSync(this.checkpointPath)) {
|
|
105127
|
+
fs38.unlinkSync(this.checkpointPath);
|
|
103938
105128
|
}
|
|
103939
|
-
if (
|
|
103940
|
-
const remaining =
|
|
105129
|
+
if (fs38.existsSync(this.dir)) {
|
|
105130
|
+
const remaining = fs38.readdirSync(this.dir);
|
|
103941
105131
|
if (remaining.length === 0) {
|
|
103942
|
-
|
|
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 (!
|
|
103975
|
-
|
|
105164
|
+
if (!fs38.existsSync(this.dir)) {
|
|
105165
|
+
fs38.mkdirSync(this.dir, { recursive: true });
|
|
103976
105166
|
}
|
|
103977
|
-
|
|
105167
|
+
fs38.writeFileSync(this.checkpointPath, JSON.stringify(data, null, 2), "utf8");
|
|
103978
105168
|
}
|
|
103979
105169
|
};
|
|
103980
105170
|
function loadCheckpoint(checkpointPath, workflowFilePath) {
|
|
103981
|
-
const raw =
|
|
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(
|
|
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 =
|
|
104015
|
-
if (!
|
|
104016
|
-
const files =
|
|
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:
|
|
104019
|
-
return
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
105045
|
-
import * as
|
|
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 =
|
|
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 =
|
|
105071
|
-
if (!
|
|
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 =
|
|
105083
|
-
if (!
|
|
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 =
|
|
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 =
|
|
105102
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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
|
|
105684
|
-
import * as
|
|
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
|
|
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 =
|
|
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 =
|
|
106118
|
-
if (!
|
|
107152
|
+
const workflowDir = path45.resolve(dir || ".");
|
|
107153
|
+
if (!fs43.existsSync(workflowDir)) {
|
|
106119
107154
|
throw new Error(`Directory not found: ${workflowDir}`);
|
|
106120
107155
|
}
|
|
106121
|
-
if (!
|
|
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
|
|
106167
|
-
import * as
|
|
106168
|
-
import * as
|
|
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 =
|
|
106180
|
-
const outputDir =
|
|
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 (!
|
|
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 ?
|
|
106233
|
-
|
|
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 =
|
|
107276
|
+
compiledContent = fs44.readFileSync(compiledPath, "utf8");
|
|
106242
107277
|
} finally {
|
|
106243
107278
|
if (isDryRun) {
|
|
106244
107279
|
try {
|
|
106245
|
-
|
|
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:
|
|
107287
|
+
path: path46.join(outputDir, f.relativePath),
|
|
106253
107288
|
content: f.content
|
|
106254
107289
|
}));
|
|
106255
107290
|
if (compiledContent) {
|
|
106256
|
-
const workflowOutputPath =
|
|
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 =
|
|
106262
|
-
|
|
106263
|
-
|
|
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 (!
|
|
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 =
|
|
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:
|
|
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 =
|
|
106324
|
-
|
|
106325
|
-
|
|
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 =
|
|
106337
|
-
|
|
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
|
|
106458
|
-
import * as
|
|
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 =
|
|
106462
|
-
if (!
|
|
107496
|
+
const workflowDir = path47.resolve(dir);
|
|
107497
|
+
if (!fs45.existsSync(workflowDir)) {
|
|
106463
107498
|
throw new Error(`Directory not found: ${workflowDir}`);
|
|
106464
107499
|
}
|
|
106465
|
-
if (!
|
|
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 =
|
|
106487
|
-
|
|
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
|
|
106496
|
-
import * as
|
|
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 =
|
|
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 =
|
|
106628
|
-
const dir =
|
|
106629
|
-
|
|
106630
|
-
if (
|
|
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
|
-
|
|
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
|
|
106656
|
-
import * as
|
|
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 =
|
|
107709
|
+
const filePath = path49.resolve(file);
|
|
106675
107710
|
try {
|
|
106676
|
-
const sourceCode =
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
106843
|
-
import * as
|
|
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 (
|
|
106849
|
-
pattern =
|
|
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
|
|
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 =
|
|
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): ${
|
|
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: ${
|
|
107914
|
+
logger.info(`Would strip: ${path50.relative(process.cwd(), filePath)}`);
|
|
106880
107915
|
stripped++;
|
|
106881
107916
|
continue;
|
|
106882
107917
|
}
|
|
106883
|
-
const outPath = output ?
|
|
107918
|
+
const outPath = output ? path50.join(path50.resolve(output), path50.basename(filePath)) : filePath;
|
|
106884
107919
|
if (output) {
|
|
106885
|
-
|
|
107920
|
+
fs48.mkdirSync(path50.dirname(outPath), { recursive: true });
|
|
106886
107921
|
}
|
|
106887
|
-
|
|
107922
|
+
fs48.writeFileSync(outPath, result);
|
|
106888
107923
|
stripped++;
|
|
106889
107924
|
if (verbose) {
|
|
106890
|
-
logger.success(`Stripped: ${
|
|
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
|
|
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
|
-
|
|
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
|
|
107020
|
-
import * as
|
|
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 =
|
|
107029
|
-
if (!
|
|
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
|
|
107124
|
-
import * as
|
|
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 =
|
|
107148
|
-
if (!
|
|
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 =
|
|
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
|
-
|
|
107194
|
-
logger.success(`Implemented ${stubNodeType.functionName} in ${
|
|
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
|
|
107204
|
-
import * as
|
|
107205
|
-
import { execSync as
|
|
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 =
|
|
107214
|
-
if (
|
|
107215
|
-
const stat2 =
|
|
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 =
|
|
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
|
-
|
|
107233
|
-
|
|
107234
|
-
|
|
107235
|
-
|
|
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
|
-
|
|
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
|
-
|
|
107270
|
-
|
|
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
|
-
|
|
107289
|
-
|
|
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
|
-
|
|
107308
|
-
|
|
107309
|
-
|
|
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
|
-
|
|
107313
|
-
|
|
108347
|
+
fs52.writeFileSync(
|
|
108348
|
+
path53.join(targetDir, "src", "workflows", "index.ts"),
|
|
107314
108349
|
"// Export workflows here\n"
|
|
107315
108350
|
);
|
|
107316
|
-
|
|
107317
|
-
|
|
108351
|
+
fs52.writeFileSync(
|
|
108352
|
+
path53.join(targetDir, "src", "patterns", "index.ts"),
|
|
107318
108353
|
"// Export patterns here\n"
|
|
107319
108354
|
);
|
|
107320
|
-
|
|
107321
|
-
|
|
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
|
-
|
|
107355
|
-
|
|
107356
|
-
|
|
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 =
|
|
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 ${
|
|
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 =
|
|
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 (!
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
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.
|
|
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) => {
|