@synergenius/flow-weaver 0.17.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -58,6 +58,8 @@ export interface PrintNextStepsOptions {
58
58
  mcpConfigured?: string[];
59
59
  /** When true, skip persona-specific guidance (the agent handles it) */
60
60
  agentLaunched?: boolean;
61
+ /** When true, the workflow was auto-compiled and npm start works immediately */
62
+ compiled?: boolean;
61
63
  }
62
64
  export declare function printNextSteps(opts: PrintNextStepsOptions): void;
63
65
  /** Maps each persona to the fw_context preset used for agent knowledge bootstrap. */
@@ -66,17 +68,17 @@ export declare const AGENT_CONTEXT_PRESETS: Record<PersonaId, string>;
66
68
  * Generate the initial prompt for a CLI agent (Claude Code, Codex).
67
69
  * Interpolates project name and template into the persona-specific template.
68
70
  */
69
- export declare function generateAgentPrompt(projectName: string, persona: PersonaId, template: string): string;
71
+ export declare function generateAgentPrompt(projectName: string, persona: PersonaId, template: string, useCaseDescription?: string): string;
70
72
  /**
71
73
  * Generate a shorter prompt suitable for pasting into a GUI editor.
72
74
  * Persona-aware but more concise than the full agent prompt.
73
75
  */
74
- export declare function generateEditorPrompt(projectName: string, persona: PersonaId, template: string): string;
76
+ export declare function generateEditorPrompt(projectName: string, persona: PersonaId, template: string, useCaseDescription?: string): string;
75
77
  /**
76
78
  * Generate the full content for a PROJECT_SETUP.md file.
77
79
  * Includes the agent prompt plus project context.
78
80
  */
79
- export declare function generateSetupPromptFile(projectName: string, persona: PersonaId, template: string, filesCreated: string[]): string;
81
+ export declare function generateSetupPromptFile(projectName: string, persona: PersonaId, template: string, filesCreated: string[], useCaseDescription?: string): string;
80
82
  /**
81
83
  * Print a copyable prompt in a bordered box.
82
84
  * Long lines are word-wrapped to fit within the box.
@@ -2,6 +2,7 @@
2
2
  * Persona-specific logic for the init command.
3
3
  * Types, use-case mappings, template selection, and post-scaffold output.
4
4
  */
5
+ import { execSync } from 'child_process';
5
6
  import { logger } from '../utils/logger.js';
6
7
  import { workflowTemplates } from '../templates/index.js';
7
8
  import { buildContext } from '../../context/index.js';
@@ -215,7 +216,7 @@ export function ${fnName}(
215
216
  `;
216
217
  }
217
218
  export function printNextSteps(opts) {
218
- const { projectName, persona, displayDir, installSkipped, workflowCode, workflowFile, agentLaunched } = opts;
219
+ const { projectName, persona, displayDir, installSkipped, workflowCode, workflowFile, agentLaunched, compiled } = opts;
219
220
  // Workflow preview
220
221
  if (workflowCode) {
221
222
  const preview = extractWorkflowPreview(workflowCode);
@@ -247,7 +248,13 @@ export function printNextSteps(opts) {
247
248
  if (installSkipped) {
248
249
  logger.log(' npm install');
249
250
  }
250
- logger.log(' npm run dev');
251
+ if (compiled) {
252
+ logger.log(` npm start${' '.repeat(14)}${logger.dim('Run your compiled workflow')}`);
253
+ logger.log(` npm run dev${' '.repeat(12)}${logger.dim('Recompile + run (after editing)')}`);
254
+ }
255
+ else {
256
+ logger.log(' npm run dev');
257
+ }
251
258
  // Persona-specific guidance (skip if agent was launched, it handles this)
252
259
  if (!agentLaunched) {
253
260
  if (persona === 'nocode') {
@@ -282,27 +289,26 @@ function printNocodeGuidance(_projectName) {
282
289
  }
283
290
  function printVibecoderGuidance() {
284
291
  logger.newline();
285
- logger.log(' With your AI editor connected, try:');
292
+ logger.log(` ${logger.bold('Describe what you want, AI handles the code.')}`);
286
293
  logger.newline();
287
294
  logger.log(` ${logger.dim('"Add a retry loop when the model call fails"')}`);
288
- logger.log(` ${logger.dim('"Add a tool that searches a knowledge base"')}`);
295
+ logger.log(` ${logger.dim('"Connect this to a Postgres database"')}`);
296
+ logger.log(` ${logger.dim('"Show me a diagram of the current workflow"')}`);
289
297
  logger.newline();
290
- logger.log(` ${logger.bold('Commands you\'ll use')}`);
298
+ logger.log(` ${logger.bold('When you want to see the structure')}`);
291
299
  logger.newline();
292
- logger.log(` flow-weaver diagram src/*.ts ${logger.dim('See a visual diagram')}`);
293
- logger.log(` flow-weaver validate src/*.ts ${logger.dim('Check for errors')}`);
294
- logger.log(` flow-weaver templates ${logger.dim('Browse all templates')}`);
300
+ logger.log(` npm run diagram ${logger.dim('Visual diagram of your workflow')}`);
295
301
  }
296
302
  function printLowcodeGuidance() {
297
303
  logger.newline();
298
- logger.log(` ${logger.bold('Explore and learn')}`);
304
+ logger.log(` ${logger.bold('Explore and customize')}`);
299
305
  logger.newline();
300
306
  logger.log(` flow-weaver templates ${logger.dim('List all 16 workflow templates')}`);
301
- logger.log(` flow-weaver create workflow ... ${logger.dim('Add another workflow')}`);
302
- logger.log(` flow-weaver describe src/*.ts ${logger.dim('See workflow structure')}`);
303
- logger.log(` flow-weaver docs annotations ${logger.dim('Read the annotation reference')}`);
307
+ logger.log(` flow-weaver describe src/*.ts ${logger.dim('See the workflow structure')}`);
308
+ logger.log(` flow-weaver docs annotations ${logger.dim('Annotation reference')}`);
304
309
  logger.newline();
305
310
  logger.log(` Your project includes an example in ${logger.highlight('examples/')} to study.`);
311
+ logger.log(` With MCP connected, AI can help modify nodes and connections.`);
306
312
  }
307
313
  function printExpertGuidance() {
308
314
  logger.newline();
@@ -370,26 +376,32 @@ Then ask what I'd like to build.`,
370
376
  * Generate the initial prompt for a CLI agent (Claude Code, Codex).
371
377
  * Interpolates project name and template into the persona-specific template.
372
378
  */
373
- export function generateAgentPrompt(projectName, persona, template) {
374
- return AGENT_PROMPTS[persona]
379
+ export function generateAgentPrompt(projectName, persona, template, useCaseDescription) {
380
+ let prompt = AGENT_PROMPTS[persona]
375
381
  .replace(/\{name\}/g, projectName)
376
382
  .replace(/\{template\}/g, template);
383
+ if (useCaseDescription) {
384
+ // Insert the user's description after the template mention line
385
+ prompt = prompt.replace(/(using the .+ template\.?\n)/, `$1The user wants to build: ${useCaseDescription}\n`);
386
+ }
387
+ return prompt;
377
388
  }
378
389
  /**
379
390
  * Generate a shorter prompt suitable for pasting into a GUI editor.
380
391
  * Persona-aware but more concise than the full agent prompt.
381
392
  */
382
- export function generateEditorPrompt(projectName, persona, template) {
393
+ export function generateEditorPrompt(projectName, persona, template, useCaseDescription) {
383
394
  const preset = AGENT_CONTEXT_PRESETS[persona];
384
395
  const bootstrap = `Start by calling fw_context(preset="${preset}", profile="assistant") to learn Flow Weaver.`;
396
+ const desc = useCaseDescription ? ` I want to build: ${useCaseDescription}.` : '';
385
397
  if (persona === 'nocode') {
386
- return `${bootstrap}\nThis 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.`;
398
+ return `${bootstrap}\nThis is a Flow Weaver project called "${projectName}" using the ${template} template.${desc} 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.`;
387
399
  }
388
400
  if (persona === 'vibecoder') {
389
- return `${bootstrap}\nThis 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.`;
401
+ return `${bootstrap}\nThis is a Flow Weaver project called "${projectName}" using the ${template} template.${desc} Show me the workflow diagram, then let's iterate on it together. I'll describe what I want and you handle the implementation.`;
390
402
  }
391
403
  if (persona === 'lowcode') {
392
- return `${bootstrap}\nThis 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.`;
404
+ return `${bootstrap}\nThis is a Flow Weaver project called "${projectName}" using the ${template} template.${desc} Show me the workflow diagram and explain the template, then help me customize it for my use case.`;
393
405
  }
394
406
  return `${bootstrap}\nFlow Weaver project "${projectName}" (template: ${template}). Show the workflow diagram and implementation status.`;
395
407
  }
@@ -397,8 +409,8 @@ export function generateEditorPrompt(projectName, persona, template) {
397
409
  * Generate the full content for a PROJECT_SETUP.md file.
398
410
  * Includes the agent prompt plus project context.
399
411
  */
400
- export function generateSetupPromptFile(projectName, persona, template, filesCreated) {
401
- const prompt = generateAgentPrompt(projectName, persona, template);
412
+ export function generateSetupPromptFile(projectName, persona, template, filesCreated, useCaseDescription) {
413
+ const prompt = generateAgentPrompt(projectName, persona, template, useCaseDescription);
402
414
  // Embed Flow Weaver knowledge directly so the file is self-contained.
403
415
  // GUI editors may not have MCP tools configured when first reading this file.
404
416
  const contextResult = buildContext({ preset: 'core', profile: 'assistant' });
@@ -481,6 +493,20 @@ export function printCopyablePrompt(prompt) {
481
493
  logger.log(` │ ${padded} │`);
482
494
  }
483
495
  logger.log(` ${'└' + '─'.repeat(width) + '┘'}`);
496
+ // Auto-copy to clipboard (best-effort)
497
+ try {
498
+ const clipCmd = process.platform === 'darwin' ? 'pbcopy'
499
+ : process.platform === 'linux' ? 'xclip -selection clipboard'
500
+ : null;
501
+ if (clipCmd) {
502
+ execSync(clipCmd, { input: prompt, stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 });
503
+ logger.newline();
504
+ logger.success('Copied to clipboard');
505
+ }
506
+ }
507
+ catch {
508
+ // Clipboard not available, box is still there
509
+ }
484
510
  }
485
511
  /** Default for the "Launch agent?" confirm prompt per persona */
486
512
  export const AGENT_LAUNCH_DEFAULTS = {
@@ -29,6 +29,8 @@ export interface InitConfig {
29
29
  force: boolean;
30
30
  persona: PersonaId;
31
31
  useCase?: UseCaseId;
32
+ /** Free-text description when user picked "Something else" */
33
+ useCaseDescription?: string;
32
34
  mcp: boolean;
33
35
  }
34
36
  export interface InitReport {
@@ -76,6 +78,7 @@ interface AgentHandoffOptions {
76
78
  cliTools: ToolId[];
77
79
  guiTools: ToolId[];
78
80
  filesCreated: string[];
81
+ useCaseDescription?: string;
79
82
  }
80
83
  /**
81
84
  * After init + MCP setup, offer to launch a CLI agent or generate a prompt for GUI editors.
@@ -13,7 +13,7 @@ import { ExitPromptError } from '@inquirer/core';
13
13
  import { getWorkflowTemplate, workflowTemplates } from '../templates/index.js';
14
14
  import { logger } from '../utils/logger.js';
15
15
  import { compileCommand } from './compile.js';
16
- import { runMcpSetupFromInit, CLI_TOOL_BINARY } from './mcp-setup.js';
16
+ import { runMcpSetupFromInit, CLI_TOOL_BINARY, detectCliTools } from './mcp-setup.js';
17
17
  import { PERSONA_CHOICES, PERSONA_CONFIRMATIONS, USE_CASE_CHOICES, selectTemplateForPersona, getTemplateSubChoices, printNextSteps, generateReadme, generateExampleWorkflow, generateAgentPrompt, generateEditorPrompt, generateSetupPromptFile, printCopyablePrompt, AGENT_LAUNCH_DEFAULTS, } from './init-personas.js';
18
18
  // ── Utilities ────────────────────────────────────────────────────────────────
19
19
  const PROJECT_NAME_RE = /^[a-zA-Z0-9][-a-zA-Z0-9_.]*$/;
@@ -172,7 +172,19 @@ export async function resolveInitConfig(dirArg, options) {
172
172
  template = selection.template;
173
173
  }
174
174
  }
175
- // 4. MCP setup (nocode + vibecoder only)
175
+ // 3b. "Something else" follow-up: ask what they're building
176
+ let useCaseDescription;
177
+ if (useCase === 'minimal' && !skipPrompts && persona !== 'expert') {
178
+ useCaseDescription = await input({
179
+ message: 'Briefly describe what you want to build:',
180
+ });
181
+ if (useCaseDescription) {
182
+ useCaseDescription = useCaseDescription.trim();
183
+ }
184
+ if (!useCaseDescription)
185
+ useCaseDescription = undefined;
186
+ }
187
+ // 4. MCP setup (nocode, vibecoder, lowcode: prompt; expert: skip unless --mcp)
176
188
  let mcp;
177
189
  if (options.mcp !== undefined) {
178
190
  mcp = options.mcp;
@@ -180,7 +192,7 @@ export async function resolveInitConfig(dirArg, options) {
180
192
  else if (skipPrompts) {
181
193
  mcp = false;
182
194
  }
183
- else if (persona === 'nocode' || persona === 'vibecoder') {
195
+ else if (persona === 'nocode' || persona === 'vibecoder' || persona === 'lowcode') {
184
196
  mcp = await confirm({
185
197
  message: 'Set up AI editor integration? (Claude Code, Cursor, VS Code, etc.)',
186
198
  default: true,
@@ -242,6 +254,7 @@ export async function resolveInitConfig(dirArg, options) {
242
254
  force,
243
255
  persona,
244
256
  useCase,
257
+ useCaseDescription,
245
258
  mcp,
246
259
  };
247
260
  }
@@ -415,7 +428,7 @@ export function runGitInit(targetDir) {
415
428
  * Returns true if a CLI agent was spawned (init should exit and let the agent take over).
416
429
  */
417
430
  export async function handleAgentHandoff(opts) {
418
- const { projectName, persona, template, targetDir, cliTools, guiTools, filesCreated } = opts;
431
+ const { projectName, persona, template, targetDir, cliTools, guiTools, filesCreated, useCaseDescription } = opts;
419
432
  // Step 1: If CLI agent available, offer to launch it
420
433
  if (cliTools.length > 0) {
421
434
  const toolId = cliTools[0]; // Prefer first (claude > codex)
@@ -427,7 +440,7 @@ export async function handleAgentHandoff(opts) {
427
440
  default: launchDefault,
428
441
  });
429
442
  if (shouldLaunch && binary) {
430
- const prompt = generateAgentPrompt(projectName, persona, template);
443
+ const prompt = generateAgentPrompt(projectName, persona, template, useCaseDescription);
431
444
  logger.newline();
432
445
  logger.log(` ${logger.dim(`Starting ${displayName}...`)}`);
433
446
  logger.newline();
@@ -456,12 +469,12 @@ export async function handleAgentHandoff(opts) {
456
469
  });
457
470
  if (promptAction === 'skip')
458
471
  return false;
459
- const editorPrompt = generateEditorPrompt(projectName, persona, template);
472
+ const editorPrompt = generateEditorPrompt(projectName, persona, template, useCaseDescription);
460
473
  if (promptAction === 'terminal' || promptAction === 'both') {
461
474
  printCopyablePrompt(editorPrompt);
462
475
  }
463
476
  if (promptAction === 'file' || promptAction === 'both') {
464
- const setupContent = generateSetupPromptFile(projectName, persona, template, filesCreated);
477
+ const setupContent = generateSetupPromptFile(projectName, persona, template, filesCreated, useCaseDescription);
465
478
  const setupPath = path.join(targetDir, 'PROJECT_SETUP.md');
466
479
  fs.writeFileSync(setupPath, setupContent, 'utf8');
467
480
  // Add to .gitignore
@@ -526,18 +539,27 @@ export async function initCommand(dirArg, options) {
526
539
  let mcpConfigured;
527
540
  let mcpResult;
528
541
  if (config.mcp && !options.json) {
529
- const spinner = logger.spinner('Configuring AI editors...');
542
+ const spinner = logger.spinner('Detecting AI editors...');
530
543
  try {
531
544
  mcpResult = await runMcpSetupFromInit();
532
545
  mcpConfigured = mcpResult.configured;
533
- if (mcpResult.configured.length > 0) {
534
- spinner.stop(`${mcpResult.configured.join(', ')} configured`);
546
+ spinner.stop();
547
+ // Per-tool status lines
548
+ for (const t of mcpResult.detected) {
549
+ if (!t.detected)
550
+ continue;
551
+ const wasConfigured = mcpConfigured.includes(t.displayName);
552
+ if (wasConfigured) {
553
+ logger.success(`${t.displayName} configured`);
554
+ }
535
555
  }
536
- else if (mcpResult.failed.length > 0) {
537
- spinner.fail('MCP setup failed');
556
+ if (mcpResult.failed.length > 0) {
557
+ for (const name of mcpResult.failed) {
558
+ logger.warn(`${name} failed to configure`);
559
+ }
538
560
  }
539
- else {
540
- spinner.stop('No AI editors detected');
561
+ if (mcpResult.detected.every((t) => !t.detected)) {
562
+ logger.log(` ${logger.dim('No AI editors detected')}`);
541
563
  }
542
564
  }
543
565
  catch {
@@ -604,25 +626,39 @@ export async function initCommand(dirArg, options) {
604
626
  // Persona-specific rich output
605
627
  const relDir = path.relative(process.cwd(), config.targetDir);
606
628
  const displayDir = !relDir || relDir === '.' ? null : relDir.startsWith('../../') ? config.targetDir : relDir;
607
- // Agent handoff: offer to launch CLI agent or generate prompt for GUI editors
629
+ // Agent handoff: offer to launch CLI agent or generate prompt for GUI editors.
630
+ // Decoupled from MCP: even if MCP wasn't run, check for available CLI tools.
608
631
  const skipAgent = options.agent === false || options.yes || isNonInteractive();
609
- if (mcpConfigured && mcpConfigured.length > 0 && !skipAgent) {
610
- try {
611
- agentLaunched = await handleAgentHandoff({
612
- projectName: config.projectName,
613
- persona: config.persona,
614
- template: config.template,
615
- targetDir: config.targetDir,
616
- cliTools: mcpCliTools,
617
- guiTools: mcpGuiTools,
618
- filesCreated,
619
- });
620
- report.agentLaunched = agentLaunched;
632
+ if (!skipAgent) {
633
+ // If MCP didn't run or found no CLI tools, do a quick binary check
634
+ if (mcpCliTools.length === 0) {
635
+ try {
636
+ mcpCliTools = await detectCliTools();
637
+ }
638
+ catch {
639
+ // Non-fatal
640
+ }
621
641
  }
622
- catch (err) {
623
- if (err instanceof ExitPromptError)
624
- return;
625
- // Non-fatal: just skip agent handoff
642
+ const hasTools = mcpCliTools.length > 0 || mcpGuiTools.length > 0;
643
+ if (hasTools) {
644
+ try {
645
+ agentLaunched = await handleAgentHandoff({
646
+ projectName: config.projectName,
647
+ persona: config.persona,
648
+ template: config.template,
649
+ targetDir: config.targetDir,
650
+ cliTools: mcpCliTools,
651
+ guiTools: mcpGuiTools,
652
+ filesCreated,
653
+ useCaseDescription: config.useCaseDescription,
654
+ });
655
+ report.agentLaunched = agentLaunched;
656
+ }
657
+ catch (err) {
658
+ if (err instanceof ExitPromptError)
659
+ return;
660
+ // Non-fatal: just skip agent handoff
661
+ }
626
662
  }
627
663
  }
628
664
  // If an agent was spawned, it takes over. Print minimal output.
@@ -639,6 +675,7 @@ export async function initCommand(dirArg, options) {
639
675
  workflowFile,
640
676
  mcpConfigured,
641
677
  agentLaunched,
678
+ compiled: compileResult?.success,
642
679
  });
643
680
  }
644
681
  catch (err) {
@@ -47,6 +47,8 @@ export declare function detectTools(deps: McpSetupDeps): Promise<DetectedTool[]>
47
47
  export interface McpSetupFromInitResult {
48
48
  configured: string[];
49
49
  failed: string[];
50
+ /** Full detection results for each tool (used by init for transparent feedback) */
51
+ detected: DetectedTool[];
50
52
  /** Tool IDs that can be spawned as interactive CLI sessions (e.g. claude, codex) */
51
53
  cliTools: ToolId[];
52
54
  /** Tool IDs that are GUI-only editors (e.g. cursor, vscode, windsurf) */
@@ -57,6 +59,11 @@ export interface McpSetupFromInitResult {
57
59
  * Used by the init command after the user has already consented.
58
60
  */
59
61
  export declare function runMcpSetupFromInit(deps?: McpSetupDeps): Promise<McpSetupFromInitResult>;
62
+ /**
63
+ * Check which CLI agent tools are available on PATH.
64
+ * Lightweight: only runs `which` for known CLI binaries.
65
+ */
66
+ export declare function detectCliTools(deps?: McpSetupDeps): Promise<ToolId[]>;
60
67
  export declare function mcpSetupCommand(options: McpSetupOptions, deps?: McpSetupDeps): Promise<void>;
61
68
  export {};
62
69
  //# sourceMappingURL=mcp-setup.d.ts.map
@@ -303,7 +303,22 @@ export async function runMcpSetupFromInit(deps) {
303
303
  .map((t) => t.id);
304
304
  const cliTools = allConfiguredIds.filter((id) => CLI_TOOL_IDS.has(id));
305
305
  const guiTools = allConfiguredIds.filter((id) => !CLI_TOOL_IDS.has(id));
306
- return { configured, failed, cliTools, guiTools };
306
+ return { configured, failed, detected, cliTools, guiTools };
307
+ }
308
+ // ── Quick CLI tool detection (no config, just binary check) ──────────────────
309
+ /**
310
+ * Check which CLI agent tools are available on PATH.
311
+ * Lightweight: only runs `which` for known CLI binaries.
312
+ */
313
+ export async function detectCliTools(deps) {
314
+ const d = deps ?? defaultDeps();
315
+ const results = [];
316
+ for (const [id, binary] of Object.entries(CLI_TOOL_BINARY)) {
317
+ if (binary && await binaryExists(binary, d)) {
318
+ results.push(id);
319
+ }
320
+ }
321
+ return results;
307
322
  }
308
323
  // ── Command ──────────────────────────────────────────────────────────────────
309
324
  export async function mcpSetupCommand(options, deps) {
@@ -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.17.0";
9674
+ VERSION = "0.17.1";
9675
9675
  }
9676
9676
  });
9677
9677
 
@@ -77764,7 +77764,7 @@ async function validateCommand(input, options = {}) {
77764
77764
  // src/cli/commands/init.ts
77765
77765
  import * as fs19 from "fs";
77766
77766
  import * as path18 from "path";
77767
- import { execSync as execSync3, spawn } from "child_process";
77767
+ import { execSync as execSync4, 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";
@@ -81038,7 +81038,17 @@ async function runMcpSetupFromInit(deps) {
81038
81038
  const allConfiguredIds = detected.filter((t) => t.detected && (t.configured || configured.includes(t.displayName))).map((t) => t.id);
81039
81039
  const cliTools = allConfiguredIds.filter((id) => CLI_TOOL_IDS.has(id));
81040
81040
  const guiTools = allConfiguredIds.filter((id) => !CLI_TOOL_IDS.has(id));
81041
- return { configured, failed, cliTools, guiTools };
81041
+ return { configured, failed, detected, cliTools, guiTools };
81042
+ }
81043
+ async function detectCliTools(deps) {
81044
+ const d = deps ?? defaultDeps();
81045
+ const results = [];
81046
+ for (const [id, binary2] of Object.entries(CLI_TOOL_BINARY)) {
81047
+ if (binary2 && await binaryExists(binary2, d)) {
81048
+ results.push(id);
81049
+ }
81050
+ }
81051
+ return results;
81042
81052
  }
81043
81053
  async function mcpSetupCommand(options, deps) {
81044
81054
  const d = deps ?? defaultDeps();
@@ -81129,6 +81139,7 @@ async function mcpSetupCommand(options, deps) {
81129
81139
  }
81130
81140
 
81131
81141
  // src/cli/commands/init-personas.ts
81142
+ import { execSync as execSync3 } from "child_process";
81132
81143
  init_templates();
81133
81144
 
81134
81145
  // src/docs/index.ts
@@ -81739,7 +81750,7 @@ export function ${fnName}(
81739
81750
  `;
81740
81751
  }
81741
81752
  function printNextSteps(opts) {
81742
- const { projectName, persona, displayDir, installSkipped, workflowCode, workflowFile, agentLaunched } = opts;
81753
+ const { projectName, persona, displayDir, installSkipped, workflowCode, workflowFile, agentLaunched, compiled } = opts;
81743
81754
  if (workflowCode) {
81744
81755
  const preview = extractWorkflowPreview(workflowCode);
81745
81756
  if (preview) {
@@ -81768,7 +81779,12 @@ function printNextSteps(opts) {
81768
81779
  if (installSkipped) {
81769
81780
  logger.log(" npm install");
81770
81781
  }
81771
- logger.log(" npm run dev");
81782
+ if (compiled) {
81783
+ logger.log(` npm start${" ".repeat(14)}${logger.dim("Run your compiled workflow")}`);
81784
+ logger.log(` npm run dev${" ".repeat(12)}${logger.dim("Recompile + run (after editing)")}`);
81785
+ } else {
81786
+ logger.log(" npm run dev");
81787
+ }
81772
81788
  if (!agentLaunched) {
81773
81789
  if (persona === "nocode") {
81774
81790
  printNocodeGuidance(projectName);
@@ -81799,27 +81815,26 @@ function printNocodeGuidance(_projectName) {
81799
81815
  }
81800
81816
  function printVibecoderGuidance() {
81801
81817
  logger.newline();
81802
- logger.log(" With your AI editor connected, try:");
81818
+ logger.log(` ${logger.bold("Describe what you want, AI handles the code.")}`);
81803
81819
  logger.newline();
81804
81820
  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"')}`);
81821
+ logger.log(` ${logger.dim('"Connect this to a Postgres database"')}`);
81822
+ logger.log(` ${logger.dim('"Show me a diagram of the current workflow"')}`);
81806
81823
  logger.newline();
81807
- logger.log(` ${logger.bold("Commands you'll use")}`);
81824
+ logger.log(` ${logger.bold("When you want to see the structure")}`);
81808
81825
  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")}`);
81826
+ logger.log(` npm run diagram ${logger.dim("Visual diagram of your workflow")}`);
81812
81827
  }
81813
81828
  function printLowcodeGuidance() {
81814
81829
  logger.newline();
81815
- logger.log(` ${logger.bold("Explore and learn")}`);
81830
+ logger.log(` ${logger.bold("Explore and customize")}`);
81816
81831
  logger.newline();
81817
81832
  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")}`);
81833
+ logger.log(` flow-weaver describe src/*.ts ${logger.dim("See the workflow structure")}`);
81834
+ logger.log(` flow-weaver docs annotations ${logger.dim("Annotation reference")}`);
81821
81835
  logger.newline();
81822
81836
  logger.log(` Your project includes an example in ${logger.highlight("examples/")} to study.`);
81837
+ logger.log(` With MCP connected, AI can help modify nodes and connections.`);
81823
81838
  }
81824
81839
  function printExpertGuidance() {
81825
81840
  logger.newline();
@@ -81880,29 +81895,38 @@ New Flow Weaver project "{name}" (template: {template}).
81880
81895
  Show the workflow diagram and current implementation status (fw_workflow_status).
81881
81896
  Then ask what I'd like to build.`
81882
81897
  };
81883
- function generateAgentPrompt(projectName, persona, template) {
81884
- return AGENT_PROMPTS[persona].replace(/\{name\}/g, projectName).replace(/\{template\}/g, template);
81898
+ function generateAgentPrompt(projectName, persona, template, useCaseDescription) {
81899
+ let prompt = AGENT_PROMPTS[persona].replace(/\{name\}/g, projectName).replace(/\{template\}/g, template);
81900
+ if (useCaseDescription) {
81901
+ prompt = prompt.replace(
81902
+ /(using the .+ template\.?\n)/,
81903
+ `$1The user wants to build: ${useCaseDescription}
81904
+ `
81905
+ );
81906
+ }
81907
+ return prompt;
81885
81908
  }
81886
- function generateEditorPrompt(projectName, persona, template) {
81909
+ function generateEditorPrompt(projectName, persona, template, useCaseDescription) {
81887
81910
  const preset = AGENT_CONTEXT_PRESETS[persona];
81888
81911
  const bootstrap = `Start by calling fw_context(preset="${preset}", profile="assistant") to learn Flow Weaver.`;
81912
+ const desc = useCaseDescription ? ` I want to build: ${useCaseDescription}.` : "";
81889
81913
  if (persona === "nocode") {
81890
81914
  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.`;
81915
+ This is a Flow Weaver project called "${projectName}" using the ${template} template.${desc} 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
81916
  }
81893
81917
  if (persona === "vibecoder") {
81894
81918
  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.`;
81919
+ This is a Flow Weaver project called "${projectName}" using the ${template} template.${desc} Show me the workflow diagram, then let's iterate on it together. I'll describe what I want and you handle the implementation.`;
81896
81920
  }
81897
81921
  if (persona === "lowcode") {
81898
81922
  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.`;
81923
+ This is a Flow Weaver project called "${projectName}" using the ${template} template.${desc} Show me the workflow diagram and explain the template, then help me customize it for my use case.`;
81900
81924
  }
81901
81925
  return `${bootstrap}
81902
81926
  Flow Weaver project "${projectName}" (template: ${template}). Show the workflow diagram and implementation status.`;
81903
81927
  }
81904
- function generateSetupPromptFile(projectName, persona, template, filesCreated) {
81905
- const prompt = generateAgentPrompt(projectName, persona, template);
81928
+ function generateSetupPromptFile(projectName, persona, template, filesCreated, useCaseDescription) {
81929
+ const prompt = generateAgentPrompt(projectName, persona, template, useCaseDescription);
81906
81930
  const contextResult = buildContext({ preset: "core", profile: "assistant" });
81907
81931
  const lines = [
81908
81932
  `# ${projectName} Setup`,
@@ -81975,6 +81999,15 @@ function printCopyablePrompt(prompt) {
81975
81999
  logger.log(` \u2502 ${padded} \u2502`);
81976
82000
  }
81977
82001
  logger.log(` ${"\u2514" + "\u2500".repeat(width) + "\u2518"}`);
82002
+ try {
82003
+ const clipCmd = process.platform === "darwin" ? "pbcopy" : process.platform === "linux" ? "xclip -selection clipboard" : null;
82004
+ if (clipCmd) {
82005
+ execSync3(clipCmd, { input: prompt, stdio: ["pipe", "pipe", "pipe"], timeout: 3e3 });
82006
+ logger.newline();
82007
+ logger.success("Copied to clipboard");
82008
+ }
82009
+ } catch {
82010
+ }
81978
82011
  }
81979
82012
  var AGENT_LAUNCH_DEFAULTS = {
81980
82013
  nocode: true,
@@ -82115,12 +82148,22 @@ async function resolveInitConfig(dirArg, options) {
82115
82148
  template = selection.template;
82116
82149
  }
82117
82150
  }
82151
+ let useCaseDescription;
82152
+ if (useCase === "minimal" && !skipPrompts && persona !== "expert") {
82153
+ useCaseDescription = await dist_default4({
82154
+ message: "Briefly describe what you want to build:"
82155
+ });
82156
+ if (useCaseDescription) {
82157
+ useCaseDescription = useCaseDescription.trim();
82158
+ }
82159
+ if (!useCaseDescription) useCaseDescription = void 0;
82160
+ }
82118
82161
  let mcp;
82119
82162
  if (options.mcp !== void 0) {
82120
82163
  mcp = options.mcp;
82121
82164
  } else if (skipPrompts) {
82122
82165
  mcp = false;
82123
- } else if (persona === "nocode" || persona === "vibecoder") {
82166
+ } else if (persona === "nocode" || persona === "vibecoder" || persona === "lowcode") {
82124
82167
  mcp = await dist_default6({
82125
82168
  message: "Set up AI editor integration? (Claude Code, Cursor, VS Code, etc.)",
82126
82169
  default: true
@@ -82172,6 +82215,7 @@ async function resolveInitConfig(dirArg, options) {
82172
82215
  force,
82173
82216
  persona,
82174
82217
  useCase,
82218
+ useCaseDescription,
82175
82219
  mcp
82176
82220
  };
82177
82221
  }
@@ -82316,7 +82360,7 @@ function scaffoldProject(targetDir, files, options) {
82316
82360
  }
82317
82361
  function runNpmInstall(targetDir) {
82318
82362
  try {
82319
- execSync3("npm install", { cwd: targetDir, stdio: "pipe", timeout: 12e4 });
82363
+ execSync4("npm install", { cwd: targetDir, stdio: "pipe", timeout: 12e4 });
82320
82364
  return { success: true };
82321
82365
  } catch (err) {
82322
82366
  const message = err instanceof Error ? err.message : String(err);
@@ -82325,7 +82369,7 @@ function runNpmInstall(targetDir) {
82325
82369
  }
82326
82370
  function runGitInit(targetDir) {
82327
82371
  try {
82328
- execSync3("git init", { cwd: targetDir, stdio: "pipe", timeout: 1e4 });
82372
+ execSync4("git init", { cwd: targetDir, stdio: "pipe", timeout: 1e4 });
82329
82373
  return { success: true };
82330
82374
  } catch (err) {
82331
82375
  const message = err instanceof Error ? err.message : String(err);
@@ -82333,7 +82377,7 @@ function runGitInit(targetDir) {
82333
82377
  }
82334
82378
  }
82335
82379
  async function handleAgentHandoff(opts) {
82336
- const { projectName, persona, template, targetDir, cliTools, guiTools, filesCreated } = opts;
82380
+ const { projectName, persona, template, targetDir, cliTools, guiTools, filesCreated, useCaseDescription } = opts;
82337
82381
  if (cliTools.length > 0) {
82338
82382
  const toolId = cliTools[0];
82339
82383
  const binary2 = CLI_TOOL_BINARY[toolId];
@@ -82344,7 +82388,7 @@ async function handleAgentHandoff(opts) {
82344
82388
  default: launchDefault
82345
82389
  });
82346
82390
  if (shouldLaunch && binary2) {
82347
- const prompt = generateAgentPrompt(projectName, persona, template);
82391
+ const prompt = generateAgentPrompt(projectName, persona, template, useCaseDescription);
82348
82392
  logger.newline();
82349
82393
  logger.log(` ${logger.dim(`Starting ${displayName}...`)}`);
82350
82394
  logger.newline();
@@ -82371,12 +82415,12 @@ async function handleAgentHandoff(opts) {
82371
82415
  default: "terminal"
82372
82416
  });
82373
82417
  if (promptAction === "skip") return false;
82374
- const editorPrompt = generateEditorPrompt(projectName, persona, template);
82418
+ const editorPrompt = generateEditorPrompt(projectName, persona, template, useCaseDescription);
82375
82419
  if (promptAction === "terminal" || promptAction === "both") {
82376
82420
  printCopyablePrompt(editorPrompt);
82377
82421
  }
82378
82422
  if (promptAction === "file" || promptAction === "both") {
82379
- const setupContent = generateSetupPromptFile(projectName, persona, template, filesCreated);
82423
+ const setupContent = generateSetupPromptFile(projectName, persona, template, filesCreated, useCaseDescription);
82380
82424
  const setupPath = path18.join(targetDir, "PROJECT_SETUP.md");
82381
82425
  fs19.writeFileSync(setupPath, setupContent, "utf8");
82382
82426
  const gitignorePath = path18.join(targetDir, ".gitignore");
@@ -82433,16 +82477,25 @@ async function initCommand(dirArg, options) {
82433
82477
  let mcpConfigured;
82434
82478
  let mcpResult;
82435
82479
  if (config2.mcp && !options.json) {
82436
- const spinner = logger.spinner("Configuring AI editors...");
82480
+ const spinner = logger.spinner("Detecting AI editors...");
82437
82481
  try {
82438
82482
  mcpResult = await runMcpSetupFromInit();
82439
82483
  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");
82484
+ spinner.stop();
82485
+ for (const t of mcpResult.detected) {
82486
+ if (!t.detected) continue;
82487
+ const wasConfigured = mcpConfigured.includes(t.displayName);
82488
+ if (wasConfigured) {
82489
+ logger.success(`${t.displayName} configured`);
82490
+ }
82491
+ }
82492
+ if (mcpResult.failed.length > 0) {
82493
+ for (const name of mcpResult.failed) {
82494
+ logger.warn(`${name} failed to configure`);
82495
+ }
82496
+ }
82497
+ if (mcpResult.detected.every((t) => !t.detected)) {
82498
+ logger.log(` ${logger.dim("No AI editors detected")}`);
82446
82499
  }
82447
82500
  } catch {
82448
82501
  spinner.fail("MCP setup failed");
@@ -82501,20 +82554,30 @@ async function initCommand(dirArg, options) {
82501
82554
  const relDir = path18.relative(process.cwd(), config2.targetDir);
82502
82555
  const displayDir = !relDir || relDir === "." ? null : relDir.startsWith("../../") ? config2.targetDir : relDir;
82503
82556
  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;
82557
+ if (!skipAgent) {
82558
+ if (mcpCliTools.length === 0) {
82559
+ try {
82560
+ mcpCliTools = await detectCliTools();
82561
+ } catch {
82562
+ }
82563
+ }
82564
+ const hasTools = mcpCliTools.length > 0 || mcpGuiTools.length > 0;
82565
+ if (hasTools) {
82566
+ try {
82567
+ agentLaunched = await handleAgentHandoff({
82568
+ projectName: config2.projectName,
82569
+ persona: config2.persona,
82570
+ template: config2.template,
82571
+ targetDir: config2.targetDir,
82572
+ cliTools: mcpCliTools,
82573
+ guiTools: mcpGuiTools,
82574
+ filesCreated,
82575
+ useCaseDescription: config2.useCaseDescription
82576
+ });
82577
+ report.agentLaunched = agentLaunched;
82578
+ } catch (err) {
82579
+ if (err instanceof ExitPromptError4) return;
82580
+ }
82518
82581
  }
82519
82582
  }
82520
82583
  if (agentLaunched) {
@@ -82529,7 +82592,8 @@ async function initCommand(dirArg, options) {
82529
82592
  workflowCode,
82530
82593
  workflowFile,
82531
82594
  mcpConfigured,
82532
- agentLaunched
82595
+ agentLaunched,
82596
+ compiled: compileResult?.success
82533
82597
  });
82534
82598
  } catch (err) {
82535
82599
  if (err instanceof ExitPromptError4) {
@@ -103975,7 +104039,7 @@ function registerExportTools(mcp) {
103975
104039
  }
103976
104040
 
103977
104041
  // src/mcp/tools-marketplace.ts
103978
- import { execSync as execSync4 } from "child_process";
104042
+ import { execSync as execSync5 } from "child_process";
103979
104043
 
103980
104044
  // src/marketplace/manifest.ts
103981
104045
  init_esm5();
@@ -104345,7 +104409,7 @@ function registerMarketplaceTools(mcp) {
104345
104409
  },
104346
104410
  async (args) => {
104347
104411
  try {
104348
- execSync4(`npm install ${args.package}`, {
104412
+ execSync5(`npm install ${args.package}`, {
104349
104413
  cwd: process.cwd(),
104350
104414
  stdio: "pipe"
104351
104415
  });
@@ -107758,7 +107822,7 @@ ${file}:`);
107758
107822
  }
107759
107823
 
107760
107824
  // src/cli/commands/changelog.ts
107761
- import { execSync as execSync5 } from "child_process";
107825
+ import { execSync as execSync6 } from "child_process";
107762
107826
  var CATEGORIES2 = [
107763
107827
  { name: "Grammar", match: (f) => /parser|chevrotain|grammar/.test(f) },
107764
107828
  { name: "Code Generation", match: (f) => /generator|body-generator|generate/.test(f) },
@@ -107785,7 +107849,7 @@ function getGitRange(options) {
107785
107849
  }
107786
107850
  if (options.lastTag) {
107787
107851
  try {
107788
- const lastTag = execSync5("git describe --tags --abbrev=0", {
107852
+ const lastTag = execSync6("git describe --tags --abbrev=0", {
107789
107853
  encoding: "utf8"
107790
107854
  }).trim();
107791
107855
  return `${lastTag}..HEAD`;
@@ -107810,7 +107874,7 @@ function getCommits(rangeArg) {
107810
107874
  } else {
107811
107875
  logCmd = `git log ${rangeArg} --format="%H %s" --no-merges`;
107812
107876
  }
107813
- const logOutput = execSync5(logCmd, { encoding: "utf8" }).trim();
107877
+ const logOutput = execSync6(logCmd, { encoding: "utf8" }).trim();
107814
107878
  if (!logOutput) {
107815
107879
  return [];
107816
107880
  }
@@ -107822,7 +107886,7 @@ function getCommits(rangeArg) {
107822
107886
  const message = line.slice(spaceIdx + 1);
107823
107887
  let files;
107824
107888
  try {
107825
- const filesOutput = execSync5(`git diff-tree --no-commit-id --name-only -r ${hash}`, {
107889
+ const filesOutput = execSync6(`git diff-tree --no-commit-id --name-only -r ${hash}`, {
107826
107890
  encoding: "utf8"
107827
107891
  }).trim();
107828
107892
  files = filesOutput ? filesOutput.split(/\r?\n/) : [];
@@ -108237,7 +108301,7 @@ async function implementCommand(input, nodeName, options = {}) {
108237
108301
  // src/cli/commands/market.ts
108238
108302
  import * as fs52 from "fs";
108239
108303
  import * as path53 from "path";
108240
- import { execSync as execSync6 } from "child_process";
108304
+ import { execSync as execSync7 } from "child_process";
108241
108305
  init_error_utils();
108242
108306
  async function marketInitCommand(name, options = {}) {
108243
108307
  if (!name.startsWith("flowweaver-pack-")) {
@@ -108470,7 +108534,7 @@ async function marketPublishCommand(directory, options = {}) {
108470
108534
  if (tag) npmArgs.push("--tag", tag);
108471
108535
  try {
108472
108536
  logger.newline();
108473
- execSync6(`npm ${npmArgs.join(" ")}`, { cwd: dir, stdio: "inherit" });
108537
+ execSync7(`npm ${npmArgs.join(" ")}`, { cwd: dir, stdio: "inherit" });
108474
108538
  if (!dryRun) {
108475
108539
  logger.newline();
108476
108540
  logger.success(`Published ${pkg.name}@${pkg.version} to npm`);
@@ -108488,7 +108552,7 @@ async function marketInstallCommand(packageSpec, options = {}) {
108488
108552
  logger.newline();
108489
108553
  }
108490
108554
  try {
108491
- execSync6(`npm install ${packageSpec}`, { stdio: json2 ? "pipe" : "inherit" });
108555
+ execSync7(`npm install ${packageSpec}`, { stdio: json2 ? "pipe" : "inherit" });
108492
108556
  } catch (err) {
108493
108557
  if (json2) {
108494
108558
  console.log(JSON.stringify({ success: false, error: getErrorMessage(err) }));
@@ -108640,7 +108704,7 @@ function displayInstalledPackage(pkg) {
108640
108704
 
108641
108705
  // src/cli/index.ts
108642
108706
  init_error_utils();
108643
- var version2 = true ? "0.17.0" : "0.0.0-dev";
108707
+ var version2 = true ? "0.17.1" : "0.0.0-dev";
108644
108708
  var program2 = new Command();
108645
108709
  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", () => {
108646
108710
  logger.banner(version2);
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.17.0";
1
+ export declare const VERSION = "0.17.1";
2
2
  //# sourceMappingURL=generated-version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by scripts/generate-version.ts — do not edit manually
2
- export const VERSION = '0.17.0';
2
+ export const VERSION = '0.17.1';
3
3
  //# sourceMappingURL=generated-version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synergenius/flow-weaver",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "description": "Deterministic workflow compiler for AI agents. Compiles to standalone TypeScript, no runtime dependencies.",
5
5
  "private": false,
6
6
  "type": "module",