@synergenius/flow-weaver 0.16.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.
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Persona-specific logic for the init command.
3
+ * Types, use-case mappings, template selection, and post-scaffold output.
4
+ */
5
+ export type PersonaId = 'nocode' | 'vibecoder' | 'lowcode' | 'expert';
6
+ export type UseCaseId = 'data' | 'ai' | 'api' | 'automation' | 'cicd' | 'minimal';
7
+ export declare const PERSONA_CHOICES: {
8
+ value: PersonaId;
9
+ name: string;
10
+ description: string;
11
+ }[];
12
+ /** One-liner printed after persona selection to set expectations. null = skip. */
13
+ export declare const PERSONA_CONFIRMATIONS: Record<PersonaId, string | null>;
14
+ export declare const USE_CASE_CHOICES: {
15
+ value: UseCaseId;
16
+ name: string;
17
+ description: string;
18
+ }[];
19
+ export interface UseCaseMapping {
20
+ default: string;
21
+ all: string[];
22
+ }
23
+ export declare const USE_CASE_TEMPLATES: Record<UseCaseId, UseCaseMapping>;
24
+ /**
25
+ * Select the template for a given persona and use-case.
26
+ * For lowcode, returns the full list when the category has multiple templates.
27
+ * For nocode/vibecoder, always returns the single default.
28
+ */
29
+ export declare function selectTemplateForPersona(persona: PersonaId, useCase: UseCaseId): {
30
+ template: string;
31
+ choices?: string[];
32
+ };
33
+ /**
34
+ * Build the template sub-choice list for inquirer, when lowcode needs to pick
35
+ * from multiple templates within a use-case category.
36
+ */
37
+ export declare function getTemplateSubChoices(templateIds: string[]): Array<{
38
+ value: string;
39
+ name: string;
40
+ description: string;
41
+ }>;
42
+ /**
43
+ * Extract @path annotations from generated workflow code and format as a
44
+ * visual flow line. Falls back to extracting @node labels if no @path found.
45
+ */
46
+ export declare function extractWorkflowPreview(workflowCode: string): string | null;
47
+ export declare const FILE_DESCRIPTIONS: Record<string, string>;
48
+ export declare function generateReadme(projectName: string, persona: PersonaId, _template: string): string;
49
+ export declare function generateExampleWorkflow(projectName: string): string;
50
+ export interface PrintNextStepsOptions {
51
+ projectName: string;
52
+ persona: PersonaId;
53
+ template: string;
54
+ displayDir: string | null;
55
+ installSkipped: boolean;
56
+ workflowCode: string | null;
57
+ workflowFile: string;
58
+ mcpConfigured?: string[];
59
+ /** When true, skip persona-specific guidance (the agent handles it) */
60
+ agentLaunched?: boolean;
61
+ /** When true, the workflow was auto-compiled and npm start works immediately */
62
+ compiled?: boolean;
63
+ }
64
+ export declare function printNextSteps(opts: PrintNextStepsOptions): void;
65
+ /** Maps each persona to the fw_context preset used for agent knowledge bootstrap. */
66
+ export declare const AGENT_CONTEXT_PRESETS: Record<PersonaId, string>;
67
+ /**
68
+ * Generate the initial prompt for a CLI agent (Claude Code, Codex).
69
+ * Interpolates project name and template into the persona-specific template.
70
+ */
71
+ export declare function generateAgentPrompt(projectName: string, persona: PersonaId, template: string, useCaseDescription?: string): string;
72
+ /**
73
+ * Generate a shorter prompt suitable for pasting into a GUI editor.
74
+ * Persona-aware but more concise than the full agent prompt.
75
+ */
76
+ export declare function generateEditorPrompt(projectName: string, persona: PersonaId, template: string, useCaseDescription?: string): string;
77
+ /**
78
+ * Generate the full content for a PROJECT_SETUP.md file.
79
+ * Includes the agent prompt plus project context.
80
+ */
81
+ export declare function generateSetupPromptFile(projectName: string, persona: PersonaId, template: string, filesCreated: string[], useCaseDescription?: string): string;
82
+ /**
83
+ * Print a copyable prompt in a bordered box.
84
+ * Long lines are word-wrapped to fit within the box.
85
+ */
86
+ export declare function printCopyablePrompt(prompt: string): void;
87
+ /** Default for the "Launch agent?" confirm prompt per persona */
88
+ export declare const AGENT_LAUNCH_DEFAULTS: Record<PersonaId, boolean>;
89
+ //# sourceMappingURL=init-personas.d.ts.map
@@ -0,0 +1,518 @@
1
+ /**
2
+ * Persona-specific logic for the init command.
3
+ * Types, use-case mappings, template selection, and post-scaffold output.
4
+ */
5
+ import { execSync } from 'child_process';
6
+ import { logger } from '../utils/logger.js';
7
+ import { workflowTemplates } from '../templates/index.js';
8
+ import { buildContext } from '../../context/index.js';
9
+ // ── Prompt choices ───────────────────────────────────────────────────────────
10
+ export const PERSONA_CHOICES = [
11
+ { value: 'nocode', name: 'AI does everything', description: 'Describe in plain language, AI builds the workflow. Guided setup included.' },
12
+ { value: 'vibecoder', name: 'AI-assisted coding', description: 'Collaborate with AI, iterate by describing changes. Hands-on setup with AI.' },
13
+ { value: 'lowcode', name: 'Template-based', description: 'Pick a template, customize the code. AI helps with initial setup.' },
14
+ { value: 'expert', name: 'Full TypeScript', description: 'Write workflows from scratch. Minimal setup, full control.' },
15
+ ];
16
+ /** One-liner printed after persona selection to set expectations. null = skip. */
17
+ export const PERSONA_CONFIRMATIONS = {
18
+ nocode: 'AI will handle the code. You describe, it builds.',
19
+ vibecoder: 'You and AI will build this together.',
20
+ lowcode: 'Starting from a template, you customize from there.',
21
+ expert: null,
22
+ };
23
+ export const USE_CASE_CHOICES = [
24
+ { value: 'data', name: 'Data pipeline', description: 'Process, transform, and validate data' },
25
+ { value: 'ai', name: 'AI agent', description: 'LLM with tools, reasoning, or retrieval' },
26
+ { value: 'api', name: 'API / webhook', description: 'HTTP endpoints and integrations' },
27
+ { value: 'automation', name: 'Automation', description: 'Conditional logic, error handling, routing' },
28
+ { value: 'cicd', name: 'CI/CD pipeline', description: 'Test, build, and deploy workflows' },
29
+ { value: 'minimal', name: 'Something else', description: 'Start with a minimal template' },
30
+ ];
31
+ export const USE_CASE_TEMPLATES = {
32
+ data: { default: 'sequential', all: ['sequential', 'foreach', 'aggregator'] },
33
+ ai: { default: 'ai-agent', all: ['ai-agent', 'ai-react', 'ai-rag', 'ai-chat'] },
34
+ api: { default: 'webhook', all: ['webhook'] },
35
+ automation: { default: 'conditional', all: ['conditional', 'error-handler'] },
36
+ cicd: { default: 'cicd-test-deploy', all: ['cicd-test-deploy', 'cicd-docker', 'cicd-multi-env', 'cicd-matrix'] },
37
+ minimal: { default: 'sequential', all: ['sequential'] },
38
+ };
39
+ /**
40
+ * Select the template for a given persona and use-case.
41
+ * For lowcode, returns the full list when the category has multiple templates.
42
+ * For nocode/vibecoder, always returns the single default.
43
+ */
44
+ export function selectTemplateForPersona(persona, useCase) {
45
+ const mapping = USE_CASE_TEMPLATES[useCase];
46
+ if (!mapping) {
47
+ return { template: 'sequential' };
48
+ }
49
+ if (persona === 'lowcode' && mapping.all.length > 1) {
50
+ return { template: mapping.default, choices: mapping.all };
51
+ }
52
+ return { template: mapping.default };
53
+ }
54
+ /**
55
+ * Build the template sub-choice list for inquirer, when lowcode needs to pick
56
+ * from multiple templates within a use-case category.
57
+ */
58
+ export function getTemplateSubChoices(templateIds) {
59
+ return templateIds.map((id) => {
60
+ const tmpl = workflowTemplates.find((t) => t.id === id);
61
+ return {
62
+ value: id,
63
+ name: id,
64
+ description: tmpl?.description ?? '',
65
+ };
66
+ });
67
+ }
68
+ // ── Workflow preview ─────────────────────────────────────────────────────────
69
+ /**
70
+ * Extract @path annotations from generated workflow code and format as a
71
+ * visual flow line. Falls back to extracting @node labels if no @path found.
72
+ */
73
+ export function extractWorkflowPreview(workflowCode) {
74
+ // Try @path first
75
+ const pathMatches = workflowCode.match(/@path\s+(.+)/g);
76
+ if (pathMatches && pathMatches.length > 0) {
77
+ // Use the first (main) path
78
+ const raw = pathMatches[0].replace(/@path\s+/, '').trim();
79
+ // Extract node instance IDs from the path
80
+ const steps = raw.split(/\s*->\s*/);
81
+ // Build a label map from @node annotations: @node instanceId nodeType [...]
82
+ // and from @label annotations on node types
83
+ const labelMap = buildLabelMap(workflowCode);
84
+ const labeled = steps.map((step) => labelMap.get(step) ?? step);
85
+ return labeled.join(' ──▶ ');
86
+ }
87
+ // Fallback: extract @node annotations and show them in order
88
+ const nodeAnnotations = workflowCode.match(/@node\s+(\w+)\s+\w+/g);
89
+ if (nodeAnnotations && nodeAnnotations.length > 0) {
90
+ const labelMap = buildLabelMap(workflowCode);
91
+ const names = nodeAnnotations.map((m) => {
92
+ const id = m.replace(/@node\s+/, '').split(/\s+/)[0];
93
+ return labelMap.get(id) ?? id;
94
+ });
95
+ return ['Start', ...names, 'Exit'].join(' ──▶ ');
96
+ }
97
+ return null;
98
+ }
99
+ /**
100
+ * Build a map from node instance ID to display label.
101
+ * Reads @node annotations to find the nodeType, then scans for @label on that nodeType.
102
+ */
103
+ function buildLabelMap(code) {
104
+ const map = new Map();
105
+ map.set('Start', 'Start');
106
+ map.set('Exit', 'Exit');
107
+ // Parse @node instanceId nodeTypeName [...]
108
+ const nodeRegex = /@node\s+(\w+)\s+(\w+)/g;
109
+ const instanceToType = new Map();
110
+ let match;
111
+ while ((match = nodeRegex.exec(code)) !== null) {
112
+ instanceToType.set(match[1], match[2]);
113
+ }
114
+ // Parse @label annotations from node type definitions
115
+ // Pattern: function functionName(...) preceded by @label LabelText
116
+ const labelRegex = /@label\s+(.+)\n[\s\S]*?function\s+(\w+)/g;
117
+ const typeToLabel = new Map();
118
+ while ((match = labelRegex.exec(code)) !== null) {
119
+ typeToLabel.set(match[2], match[1].trim());
120
+ }
121
+ // Map instance IDs to labels
122
+ for (const [instanceId, typeName] of instanceToType) {
123
+ const label = typeToLabel.get(typeName);
124
+ if (label) {
125
+ map.set(instanceId, label);
126
+ }
127
+ }
128
+ return map;
129
+ }
130
+ // ── File descriptions ────────────────────────────────────────────────────────
131
+ export const FILE_DESCRIPTIONS = {
132
+ 'package.json': 'Dependencies and npm scripts',
133
+ 'tsconfig.json': 'TypeScript configuration',
134
+ '.gitignore': 'Git ignore rules',
135
+ '.flowweaver/config.yaml': 'Flow Weaver project settings',
136
+ 'src/main.ts': 'Runs the workflow with sample input',
137
+ };
138
+ /** Generate a description for a workflow file */
139
+ function workflowFileDesc(persona) {
140
+ if (persona === 'nocode')
141
+ return 'Your workflow (AI will modify this for you)';
142
+ return 'Your workflow definition';
143
+ }
144
+ // ── README generation ────────────────────────────────────────────────────────
145
+ export function generateReadme(projectName, persona, _template) {
146
+ const lines = [`# ${projectName}`, ''];
147
+ if (persona === 'nocode') {
148
+ lines.push('A Flow Weaver workflow project configured for AI-assisted development.', '', '## Working with AI', '', 'Open this project in your AI editor (Claude Code, Cursor, VS Code) and describe', 'what you want to build:', '', '- "Create a workflow that processes customer orders"', '- "Add retry logic to the data pipeline"', '- "Show me a diagram of the current workflow"', '', 'The AI has access to Flow Weaver\'s 48 tools and will create, modify, and validate', 'workflows for you.', '');
149
+ }
150
+ else if (persona === 'vibecoder') {
151
+ lines.push('A Flow Weaver workflow project.', '', '## Development', '', '```sh', 'npm run dev # Compile and run', 'npm run compile # Compile only', 'npm run validate # Check for errors', '```', '', '## AI-Assisted Editing', '', 'With your AI editor connected, you can describe changes in plain language:', '', '- "Add error handling to the pipeline"', '- "Replace the mock LLM with OpenAI"', '- "Add a validation step before processing"', '');
152
+ }
153
+ else if (persona === 'lowcode') {
154
+ lines.push('A Flow Weaver workflow project.', '', '## Development', '', '```sh', 'npm run dev # Compile and run', 'npm run compile # Compile only', 'npm run validate # Check for errors', '```', '', '## Templates', '', 'Browse and add more workflows:', '', '```sh', 'flow-weaver templates # List all templates', 'flow-weaver create workflow <template> <file> # Add a workflow', 'flow-weaver describe src/*.ts --format ascii # See workflow structure', '```', '');
155
+ }
156
+ else {
157
+ // expert: minimal
158
+ lines.push('A Flow Weaver workflow project.', '', '## Commands', '', '```sh', 'npm run dev # Compile and run', 'npm run compile # Compile only', 'npm run validate # Check for errors', '```', '');
159
+ }
160
+ lines.push('## Learn more', '', '- `flow-weaver docs` to browse reference documentation', '- `flow-weaver mcp-setup` to connect AI editors', '');
161
+ return lines.join('\n');
162
+ }
163
+ // ── Example workflow for lowcode persona ──────────────────────────────────────
164
+ export function generateExampleWorkflow(projectName) {
165
+ const name = projectName.replace(/[-_.]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))
166
+ .replace(/^[^a-zA-Z_$]+/, '')
167
+ .replace(/^./, (c) => c.toLowerCase());
168
+ const fnName = (name || 'example') + 'Example';
169
+ return `/**
170
+ * Example: a minimal workflow to study and experiment with.
171
+ * Copy patterns from here into your main workflow.
172
+ */
173
+
174
+ /**
175
+ * @flowWeaver nodeType
176
+ * @expression
177
+ * @label Greet
178
+ * @input name [order:0] - Name to greet
179
+ * @output greeting [order:0] - Greeting message
180
+ */
181
+ function greet(name: string): { greeting: string } {
182
+ return { greeting: \`Hello, \${name}!\` };
183
+ }
184
+
185
+ /**
186
+ * @flowWeaver nodeType
187
+ * @expression
188
+ * @label Uppercase
189
+ * @input text [order:0] - Text to uppercase
190
+ * @output result [order:0] - Uppercased text
191
+ */
192
+ function uppercase(text: string): { result: string } {
193
+ return { result: text.toUpperCase() };
194
+ }
195
+
196
+ /**
197
+ * @flowWeaver workflow
198
+ * @node greeter greet [position: -200 0]
199
+ * @node upper uppercase [position: 100 0]
200
+ * @position Start -500 0
201
+ * @position Exit 400 0
202
+ * @path Start -> greeter -> upper -> Exit
203
+ * @connect greeter.greeting -> upper.text
204
+ * @param execute [order:0] - Execute
205
+ * @param name [order:1] - Name to greet
206
+ * @returns onSuccess [order:0] - On Success
207
+ * @returns onFailure [order:1] - On Failure
208
+ * @returns result [order:2] - Final greeting
209
+ */
210
+ export function ${fnName}(
211
+ execute: boolean,
212
+ params: { name: string }
213
+ ): { onSuccess: boolean; onFailure: boolean; result: string } {
214
+ throw new Error("Compile with: flow-weaver compile <file>");
215
+ }
216
+ `;
217
+ }
218
+ export function printNextSteps(opts) {
219
+ const { projectName, persona, displayDir, installSkipped, workflowCode, workflowFile, agentLaunched, compiled } = opts;
220
+ // Workflow preview
221
+ if (workflowCode) {
222
+ const preview = extractWorkflowPreview(workflowCode);
223
+ if (preview) {
224
+ logger.newline();
225
+ logger.log(` ${logger.bold('Your workflow')}`);
226
+ logger.newline();
227
+ logger.log(` ${logger.dim(preview)}`);
228
+ }
229
+ }
230
+ // File descriptions (non-expert only)
231
+ if (persona !== 'expert') {
232
+ logger.newline();
233
+ logger.log(` ${logger.bold('Project files')}`);
234
+ logger.newline();
235
+ const wfDesc = workflowFileDesc(persona);
236
+ logger.log(` ${logger.highlight(`src/${workflowFile}`)}${pad(`src/${workflowFile}`, 32)}${wfDesc}`);
237
+ logger.log(` ${logger.highlight('src/main.ts')}${pad('src/main.ts', 32)}${FILE_DESCRIPTIONS['src/main.ts']}`);
238
+ logger.log(` ${logger.highlight('package.json')}${pad('package.json', 32)}${FILE_DESCRIPTIONS['package.json']}`);
239
+ logger.log(` ${logger.highlight('tsconfig.json')}${pad('tsconfig.json', 32)}${FILE_DESCRIPTIONS['tsconfig.json']}`);
240
+ }
241
+ // Next steps
242
+ logger.newline();
243
+ logger.log(` ${logger.bold('Next steps')}`);
244
+ logger.newline();
245
+ if (displayDir) {
246
+ logger.log(` cd ${displayDir}`);
247
+ }
248
+ if (installSkipped) {
249
+ logger.log(' npm install');
250
+ }
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
+ }
258
+ // Persona-specific guidance (skip if agent was launched, it handles this)
259
+ if (!agentLaunched) {
260
+ if (persona === 'nocode') {
261
+ printNocodeGuidance(projectName);
262
+ }
263
+ else if (persona === 'vibecoder') {
264
+ printVibecoderGuidance();
265
+ }
266
+ else if (persona === 'lowcode') {
267
+ printLowcodeGuidance();
268
+ }
269
+ else {
270
+ printExpertGuidance();
271
+ }
272
+ }
273
+ logger.newline();
274
+ }
275
+ function printNocodeGuidance(_projectName) {
276
+ logger.newline();
277
+ logger.log(` ${logger.bold('Your project is ready for AI-assisted building.')}`);
278
+ logger.log(' Open it in your AI editor and describe what you want:');
279
+ logger.newline();
280
+ logger.log(` ${logger.dim('"Change this to fetch data from an API and validate the response"')}`);
281
+ logger.log(` ${logger.dim('"Add error handling so failures get logged and retried"')}`);
282
+ logger.log(` ${logger.dim('"Show me a diagram of my workflow"')}`);
283
+ logger.newline();
284
+ logger.log(` ${logger.bold('Useful commands')}`);
285
+ logger.newline();
286
+ logger.log(` flow-weaver run src/*.ts ${logger.dim('Run your workflow')}`);
287
+ logger.log(` flow-weaver diagram src/*.ts ${logger.dim('See a visual diagram')}`);
288
+ logger.log(` flow-weaver mcp-setup ${logger.dim('Connect more AI editors')}`);
289
+ }
290
+ function printVibecoderGuidance() {
291
+ logger.newline();
292
+ logger.log(` ${logger.bold('Describe what you want, AI handles the code.')}`);
293
+ logger.newline();
294
+ logger.log(` ${logger.dim('"Add a retry loop when the model call fails"')}`);
295
+ logger.log(` ${logger.dim('"Connect this to a Postgres database"')}`);
296
+ logger.log(` ${logger.dim('"Show me a diagram of the current workflow"')}`);
297
+ logger.newline();
298
+ logger.log(` ${logger.bold('When you want to see the structure')}`);
299
+ logger.newline();
300
+ logger.log(` npm run diagram ${logger.dim('Visual diagram of your workflow')}`);
301
+ }
302
+ function printLowcodeGuidance() {
303
+ logger.newline();
304
+ logger.log(` ${logger.bold('Explore and customize')}`);
305
+ logger.newline();
306
+ logger.log(` flow-weaver templates ${logger.dim('List all 16 workflow templates')}`);
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')}`);
309
+ logger.newline();
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.`);
312
+ }
313
+ function printExpertGuidance() {
314
+ logger.newline();
315
+ logger.log(` flow-weaver mcp-setup ${logger.dim('Connect AI editors (Claude, Cursor, VS Code)')}`);
316
+ logger.log(` flow-weaver docs ${logger.dim('Browse reference docs')}`);
317
+ }
318
+ /** Pad a filename to align descriptions */
319
+ function pad(displayName, width) {
320
+ const padding = Math.max(1, width - displayName.length);
321
+ return ' '.repeat(padding);
322
+ }
323
+ // ── Agent handoff ─────────────────────────────────────────────────────────────
324
+ /** Maps each persona to the fw_context preset used for agent knowledge bootstrap. */
325
+ export const AGENT_CONTEXT_PRESETS = {
326
+ nocode: 'core',
327
+ vibecoder: 'authoring',
328
+ lowcode: 'authoring',
329
+ expert: 'authoring',
330
+ };
331
+ const AGENT_PROMPTS = {
332
+ nocode: `Before doing anything else, call fw_context(preset="core", profile="assistant") to learn Flow Weaver's annotation syntax and workflow conventions.
333
+
334
+ I just created a new Flow Weaver project called "{name}" using the {template} template.
335
+ Help me set it up step by step:
336
+
337
+ 1. Show the current workflow as a diagram (use fw_diagram, ascii-compact)
338
+ 2. Walk me through what each step does in plain language
339
+ 3. Ask me what I want this workflow to do
340
+ 4. Based on my answer:
341
+ - Customize the workflow (add/remove/rename steps with fw_modify)
342
+ - Implement each step with real working code (fw_implement_node)
343
+ - Set up supporting files if needed (.env template, basic tests)
344
+ 5. Show the final result as a step list and diagram
345
+
346
+ Keep everything in plain language. Don't show code unless I ask.`,
347
+ vibecoder: `Before doing anything else, call fw_context(preset="authoring", profile="assistant") to load Flow Weaver reference.
348
+
349
+ I just created a new Flow Weaver project called "{name}" using the {template} template.
350
+ Let's set it up together:
351
+
352
+ 1. Show the workflow diagram and briefly explain the structure
353
+ 2. Ask what I want to build, then iterate with me
354
+ 3. Customize the workflow, implement the nodes, add supporting files
355
+ 4. Show code when it's relevant, I'm comfortable reading and tweaking it
356
+ 5. Show the final diagram when we're done`,
357
+ lowcode: `Before doing anything else, call fw_context(preset="authoring", profile="assistant") to load Flow Weaver reference.
358
+
359
+ I just created a new Flow Weaver project called "{name}" using the {template} template.
360
+ Help me customize it:
361
+
362
+ 1. Show the workflow diagram and explain what the template gives me
363
+ 2. Ask what I want this workflow to do
364
+ 3. Customize: rename nodes, adjust connections, implement the functions
365
+ 4. Add supporting files if needed (.env, tests)
366
+ 5. Show the final diagram
367
+
368
+ I prefer working from templates and making targeted changes.`,
369
+ expert: `Before doing anything else, call fw_context(preset="authoring", profile="assistant") to load Flow Weaver reference.
370
+
371
+ New Flow Weaver project "{name}" (template: {template}).
372
+ Show the workflow diagram and current implementation status (fw_workflow_status).
373
+ Then ask what I'd like to build.`,
374
+ };
375
+ /**
376
+ * Generate the initial prompt for a CLI agent (Claude Code, Codex).
377
+ * Interpolates project name and template into the persona-specific template.
378
+ */
379
+ export function generateAgentPrompt(projectName, persona, template, useCaseDescription) {
380
+ let prompt = AGENT_PROMPTS[persona]
381
+ .replace(/\{name\}/g, projectName)
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;
388
+ }
389
+ /**
390
+ * Generate a shorter prompt suitable for pasting into a GUI editor.
391
+ * Persona-aware but more concise than the full agent prompt.
392
+ */
393
+ export function generateEditorPrompt(projectName, persona, template, useCaseDescription) {
394
+ const preset = AGENT_CONTEXT_PRESETS[persona];
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}.` : '';
397
+ if (persona === 'nocode') {
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.`;
399
+ }
400
+ if (persona === 'vibecoder') {
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.`;
402
+ }
403
+ if (persona === 'lowcode') {
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.`;
405
+ }
406
+ return `${bootstrap}\nFlow Weaver project "${projectName}" (template: ${template}). Show the workflow diagram and implementation status.`;
407
+ }
408
+ /**
409
+ * Generate the full content for a PROJECT_SETUP.md file.
410
+ * Includes the agent prompt plus project context.
411
+ */
412
+ export function generateSetupPromptFile(projectName, persona, template, filesCreated, useCaseDescription) {
413
+ const prompt = generateAgentPrompt(projectName, persona, template, useCaseDescription);
414
+ // Embed Flow Weaver knowledge directly so the file is self-contained.
415
+ // GUI editors may not have MCP tools configured when first reading this file.
416
+ const contextResult = buildContext({ preset: 'core', profile: 'assistant' });
417
+ const lines = [
418
+ `# ${projectName} Setup`,
419
+ '',
420
+ 'Paste this into your AI editor chat, or ask it to "follow the instructions in PROJECT_SETUP.md".',
421
+ '',
422
+ '---',
423
+ '',
424
+ prompt,
425
+ '',
426
+ '---',
427
+ '',
428
+ '## Flow Weaver Reference',
429
+ '',
430
+ 'The following is embedded Flow Weaver documentation so you can work with this project',
431
+ 'even before MCP tools are connected. For deeper topics, call `fw_docs` once MCP is available.',
432
+ '',
433
+ contextResult.content,
434
+ '',
435
+ '---',
436
+ '',
437
+ '## Project context',
438
+ '',
439
+ `- **Template**: ${template}`,
440
+ `- **Persona**: ${persona}`,
441
+ '',
442
+ '### Files created',
443
+ '',
444
+ ...filesCreated.map((f) => `- \`${f}\``),
445
+ '',
446
+ '### Available Flow Weaver MCP tools',
447
+ '',
448
+ 'Your AI editor has access to 48 Flow Weaver tools including:',
449
+ '- `fw_diagram` - Generate workflow diagrams',
450
+ '- `fw_modify` / `fw_modify_batch` - Add/remove/rename nodes and connections',
451
+ '- `fw_implement_node` - Write function bodies for stub nodes',
452
+ '- `fw_validate` - Check for errors',
453
+ '- `fw_compile` - Generate executable code',
454
+ '- `fw_describe` - Inspect workflow structure',
455
+ '',
456
+ '*Delete this file after your initial setup is complete.*',
457
+ '',
458
+ ];
459
+ return lines.join('\n');
460
+ }
461
+ /**
462
+ * Print a copyable prompt in a bordered box.
463
+ * Long lines are word-wrapped to fit within the box.
464
+ */
465
+ export function printCopyablePrompt(prompt) {
466
+ const maxInner = 70; // content width inside the box
467
+ const wrapped = [];
468
+ for (const raw of prompt.split('\n')) {
469
+ if (raw.length <= maxInner) {
470
+ wrapped.push(raw);
471
+ }
472
+ else {
473
+ // Word-wrap at maxInner
474
+ let remaining = raw;
475
+ while (remaining.length > maxInner) {
476
+ let breakAt = remaining.lastIndexOf(' ', maxInner);
477
+ if (breakAt <= 0)
478
+ breakAt = maxInner;
479
+ wrapped.push(remaining.slice(0, breakAt));
480
+ remaining = remaining.slice(breakAt).replace(/^ /, '');
481
+ }
482
+ if (remaining)
483
+ wrapped.push(remaining);
484
+ }
485
+ }
486
+ const width = maxInner + 2; // +2 for padding inside borders
487
+ logger.newline();
488
+ logger.log(` ${logger.bold('Paste this into your AI editor to get started:')}`);
489
+ logger.newline();
490
+ logger.log(` ${'┌' + '─'.repeat(width) + '┐'}`);
491
+ for (const line of wrapped) {
492
+ const padded = line + ' '.repeat(Math.max(0, maxInner - line.length));
493
+ logger.log(` │ ${padded} │`);
494
+ }
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
+ }
510
+ }
511
+ /** Default for the "Launch agent?" confirm prompt per persona */
512
+ export const AGENT_LAUNCH_DEFAULTS = {
513
+ nocode: true,
514
+ vibecoder: true,
515
+ lowcode: true,
516
+ expert: false,
517
+ };
518
+ //# sourceMappingURL=init-personas.js.map