@synergenius/flowweaver-pack-weaver 0.3.0 → 0.4.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.
Files changed (67) hide show
  1. package/dist/bot/run-store.d.ts +11 -0
  2. package/dist/bot/run-store.d.ts.map +1 -1
  3. package/dist/bot/run-store.js +51 -0
  4. package/dist/bot/run-store.js.map +1 -1
  5. package/dist/bot/runner.d.ts.map +1 -1
  6. package/dist/bot/runner.js +6 -0
  7. package/dist/bot/runner.js.map +1 -1
  8. package/dist/cli-bridge.d.ts +2 -0
  9. package/dist/cli-bridge.d.ts.map +1 -0
  10. package/dist/cli-bridge.js +27 -0
  11. package/dist/cli-bridge.js.map +1 -0
  12. package/dist/cli-handlers.d.ts +41 -0
  13. package/dist/cli-handlers.d.ts.map +1 -0
  14. package/dist/{cli.js → cli-handlers.js} +185 -190
  15. package/dist/cli-handlers.js.map +1 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +2 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp-tools.d.ts +13 -0
  21. package/dist/mcp-tools.d.ts.map +1 -0
  22. package/dist/mcp-tools.js +84 -0
  23. package/dist/mcp-tools.js.map +1 -0
  24. package/dist/node-types/detect-provider.d.ts +20 -0
  25. package/dist/node-types/detect-provider.d.ts.map +1 -0
  26. package/dist/node-types/detect-provider.js +72 -0
  27. package/dist/node-types/detect-provider.js.map +1 -0
  28. package/dist/node-types/execute-target.d.ts +26 -0
  29. package/dist/node-types/execute-target.d.ts.map +1 -0
  30. package/dist/node-types/execute-target.js +312 -0
  31. package/dist/node-types/execute-target.js.map +1 -0
  32. package/dist/node-types/index.d.ts +7 -0
  33. package/dist/node-types/index.d.ts.map +1 -0
  34. package/dist/node-types/index.js +7 -0
  35. package/dist/node-types/index.js.map +1 -0
  36. package/dist/node-types/load-config.d.ts +15 -0
  37. package/dist/node-types/load-config.d.ts.map +1 -0
  38. package/dist/node-types/load-config.js +26 -0
  39. package/dist/node-types/load-config.js.map +1 -0
  40. package/dist/node-types/report.d.ts +15 -0
  41. package/dist/node-types/report.d.ts.map +1 -0
  42. package/dist/node-types/report.js +25 -0
  43. package/dist/node-types/report.js.map +1 -0
  44. package/dist/node-types/resolve-target.d.ts +24 -0
  45. package/dist/node-types/resolve-target.d.ts.map +1 -0
  46. package/dist/node-types/resolve-target.js +67 -0
  47. package/dist/node-types/resolve-target.js.map +1 -0
  48. package/dist/node-types/send-notify.d.ts +20 -0
  49. package/dist/node-types/send-notify.d.ts.map +1 -0
  50. package/dist/node-types/send-notify.js +75 -0
  51. package/dist/node-types/send-notify.js.map +1 -0
  52. package/dist/templates/weaver-template.d.ts.map +1 -1
  53. package/dist/templates/weaver-template.js +15 -653
  54. package/dist/templates/weaver-template.js.map +1 -1
  55. package/dist/workflows/index.d.ts +2 -0
  56. package/dist/workflows/index.d.ts.map +1 -0
  57. package/dist/workflows/index.js +2 -0
  58. package/dist/workflows/index.js.map +1 -0
  59. package/dist/workflows/weaver.d.ts +24 -0
  60. package/dist/workflows/weaver.d.ts.map +1 -0
  61. package/dist/workflows/weaver.js +28 -0
  62. package/dist/workflows/weaver.js.map +1 -0
  63. package/flowweaver.manifest.json +286 -2
  64. package/package.json +19 -5
  65. package/dist/cli.d.ts +0 -3
  66. package/dist/cli.d.ts.map +0 -1
  67. package/dist/cli.js.map +0 -1
@@ -8,663 +8,25 @@ export const weaverTemplate = {
8
8
  // flow-weaver compile weaver.ts
9
9
  // flow-weaver run weaver.ts
10
10
  // Or use the CLI directly: npx weaver weaver.ts
11
+ //
12
+ // Node types are provided by @synergenius/flowweaver-pack-weaver.
13
+ // Install it: npm install @synergenius/flowweaver-pack-weaver
11
14
 
12
- import { execSync } from 'node:child_process';
13
- import * as fs from 'node:fs';
14
- import * as path from 'node:path';
15
- import * as os from 'node:os';
16
-
17
- // ============================================================
18
- // Types
19
- // ============================================================
20
-
21
- interface WeaverConfig {
22
- provider?: 'auto' | 'anthropic' | 'claude-cli' | 'copilot-cli' | { name: string; model?: string; maxTokens?: number };
23
- target?: string;
24
- approval?: 'auto' | 'timeout-auto' | { mode: string; timeoutSeconds?: number };
25
- notify?: Array<{ channel: 'discord' | 'slack' | 'webhook'; url: string; events?: string[]; headers?: Record<string, string> }>;
26
- }
27
-
28
- interface ProviderInfo {
29
- type: 'anthropic' | 'claude-cli' | 'copilot-cli';
30
- model?: string;
31
- maxTokens?: number;
32
- apiKey?: string;
33
- }
34
-
35
- // ============================================================
36
- // Helpers
37
- // ============================================================
38
-
39
- function run(cmd: string, cwd: string): string {
40
- return execSync(cmd, { cwd, encoding: 'utf-8', stdio: 'pipe' }).trim();
41
- }
42
-
43
- function runSafe(cmd: string, cwd: string): string {
44
- try { return run(cmd, cwd); } catch { return ''; }
45
- }
46
-
47
- function info(msg: string): void { console.log(\`\\x1b[36m→ \${msg}\\x1b[0m\`); }
48
- function success(msg: string): void { console.log(\`\\x1b[32m✓ \${msg}\\x1b[0m\`); }
49
- function warn(msg: string): void { console.log(\`\\x1b[33m! \${msg}\\x1b[0m\`); }
50
-
51
- function callCli(provider: string, prompt: string): string {
52
- if (provider === 'claude-cli') {
53
- return execSync('claude -p --output-format text', {
54
- input: prompt,
55
- encoding: 'utf-8',
56
- stdio: ['pipe', 'pipe', 'pipe'],
57
- timeout: 120_000,
58
- }).trim();
59
- }
60
- if (provider === 'copilot-cli') {
61
- return execSync('copilot -p --silent --allow-all-tools', {
62
- input: prompt,
63
- encoding: 'utf-8',
64
- stdio: ['pipe', 'pipe', 'pipe'],
65
- timeout: 120_000,
66
- }).trim();
67
- }
68
- throw new Error(\`Unknown CLI provider: \${provider}\`);
69
- }
70
-
71
- async function callApiAsync(
72
- apiKey: string,
73
- model: string,
74
- maxTokens: number,
75
- systemPrompt: string,
76
- userPrompt: string,
77
- ): Promise<string> {
78
- const body = JSON.stringify({
79
- model,
80
- max_tokens: maxTokens,
81
- system: systemPrompt,
82
- messages: [{ role: 'user', content: userPrompt }],
83
- });
84
- const response = await fetch('https://api.anthropic.com/v1/messages', {
85
- method: 'POST',
86
- headers: {
87
- 'x-api-key': apiKey,
88
- 'anthropic-version': '2023-06-01',
89
- 'content-type': 'application/json',
90
- },
91
- body,
92
- });
93
- if (!response.ok) {
94
- const text = await response.text();
95
- throw new Error(\`Anthropic API error \${response.status}: \${text.slice(0, 200)}\`);
96
- }
97
- const json = await response.json() as { content: Array<{ type: string; text: string }> };
98
- return json.content[0]?.text ?? '';
99
- }
100
-
101
- function parseJsonResponse(text: string): Record<string, unknown> {
102
- let cleaned = text.trim();
103
- if (cleaned.startsWith('\\\`\\\`\\\`')) {
104
- cleaned = cleaned.replace(/^\\\`\\\`\\\`(?:json)?\\s*\\n?/, '').replace(/\\n?\\\`\\\`\\\`\\s*$/, '');
105
- }
106
- try { return JSON.parse(cleaned); } catch {}
107
- const match = cleaned.match(/\\{[\\s\\S]*\\}/);
108
- if (match) return JSON.parse(match[0]);
109
- throw new Error(\`Failed to parse AI response as JSON: \${text.slice(0, 200)}\`);
110
- }
111
-
112
- function sendWebhook(
113
- config: { channel: string; url: string; headers?: Record<string, string> },
114
- event: Record<string, unknown>,
115
- ): void {
116
- const headers: Record<string, string> = {
117
- 'content-type': 'application/json',
118
- ...config.headers,
119
- };
120
- let body: string;
121
- if (config.channel === 'discord') {
122
- const color = event.success ? 0x22c55e : 0xef4444;
123
- body = JSON.stringify({
124
- embeds: [{
125
- title: \`Weaver: \${event.outcome ?? 'update'}\`,
126
- description: String(event.summary ?? '').slice(0, 2000),
127
- color,
128
- fields: [
129
- { name: 'Workflow', value: String(event.targetPath ?? 'unknown'), inline: true },
130
- { name: 'Provider', value: String(event.providerType ?? 'unknown'), inline: true },
131
- ],
132
- timestamp: new Date().toISOString(),
133
- }],
134
- });
135
- } else if (config.channel === 'slack') {
136
- const emoji = event.success ? ':white_check_mark:' : ':x:';
137
- body = JSON.stringify({
138
- blocks: [
139
- { type: 'header', text: { type: 'plain_text', text: \`\${emoji} Weaver: \${event.outcome ?? 'update'}\` } },
140
- { type: 'section', text: { type: 'mrkdwn', text: String(event.summary ?? '').slice(0, 2000) } },
141
- ],
142
- });
143
- } else {
144
- body = JSON.stringify(event);
145
- }
146
- const headerFlags = Object.entries(headers).map(([k, v]) => \`-H "\${k}: \${v}"\`).join(' ');
147
- try {
148
- execSync(\`curl -sS -X POST \${headerFlags} -d @- "\${config.url}"\`, {
149
- input: body,
150
- encoding: 'utf-8',
151
- stdio: ['pipe', 'pipe', 'pipe'],
152
- timeout: 10_000,
153
- });
154
- } catch { /* notification failure is non-fatal */ }
155
- }
156
-
157
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
158
- async function buildWeaverPrompt(): Promise<string> {
159
- const FALLBACK = 'You are Weaver, an expert AI companion for Flow Weaver workflows. Respond ONLY with valid JSON. No markdown, no code fences, no explanation outside the JSON structure.';
160
-
161
- try {
162
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
163
- const docMeta: any = await import('@synergenius/flow-weaver/doc-metadata');
164
-
165
- const annotations: Array<{ name: string; syntax: string; description: string; category: string }> = docMeta.ALL_ANNOTATIONS ?? [];
166
- const portMods: Array<{ syntax: string; description: string }> = docMeta.PORT_MODIFIERS ?? [];
167
- const nodeMods: Array<{ syntax: string; description: string }> = docMeta.NODE_MODIFIERS ?? [];
168
- const codes: Array<{ code: string; severity: string; title: string; description: string }> = docMeta.VALIDATION_CODES ?? [];
169
- const commands: Array<{ name: string; description: string; group?: string }> = docMeta.CLI_COMMANDS ?? [];
170
-
171
- // Format annotations grouped by category
172
- const groups = new Map<string, typeof annotations>();
173
- for (const a of annotations) {
174
- const list = groups.get(a.category) ?? [];
175
- list.push(a);
176
- groups.set(a.category, list);
177
- }
178
- const annotationLines: string[] = [];
179
- for (const [category, items] of groups) {
180
- annotationLines.push('[' + category + ']');
181
- for (const item of items) annotationLines.push(' ' + item.syntax + ' -- ' + item.description);
182
- }
183
-
184
- // Format modifiers
185
- const modLines: string[] = [];
186
- if (portMods.length > 0) {
187
- modLines.push('Port modifiers (after port name):');
188
- for (const m of portMods) modLines.push(' ' + m.syntax + ' -- ' + m.description);
189
- }
190
- if (nodeMods.length > 0) {
191
- modLines.push('Node instance modifiers (in @node declaration):');
192
- for (const m of nodeMods) modLines.push(' ' + m.syntax + ' -- ' + m.description);
193
- }
194
-
195
- // Format errors (top 15)
196
- const errors = codes.filter(c => c.severity === 'error').slice(0, 15);
197
- const errorLines = errors.map(c => ' ' + c.code + ': ' + c.title + ' -- ' + c.description);
198
-
199
- // Format top-level CLI commands
200
- const topCmds = commands.filter(c => !c.group);
201
- const cmdLines = topCmds.map(c => ' flow-weaver ' + c.name + ' -- ' + c.description);
202
-
203
- return \`You are Weaver, an expert AI companion for Flow Weaver workflows. You have deep knowledge of the entire Flow Weaver ecosystem: annotation grammar, compilation, CLI tools, node patterns, error diagnosis, and the Genesis self-evolution protocol.
204
-
205
- ## Core Mental Model
206
-
207
- The code IS the workflow. Flow Weaver workflows are plain TypeScript files with JSDoc annotations above functions. The compiler reads annotations and generates deterministic execution code between @flow-weaver-body-start/end markers. Compiled code is standalone with no runtime dependency on flow-weaver.
208
-
209
- Three block types:
210
- - @flowWeaver nodeType: A reusable function (node) with typed inputs/outputs
211
- - @flowWeaver workflow: A DAG orchestration that wires node instances together
212
- - @flowWeaver pattern: A reusable fragment with boundary ports (IN/OUT instead of Start/Exit)
213
-
214
- ## Annotation Grammar
215
-
216
- \${annotationLines.join('\\n')}
217
-
218
- \${modLines.join('\\n')}
219
-
220
- ## Node Execution Model
221
-
222
- Expression nodes (@expression):
223
- - No execute/onSuccess/onFailure params. Just inputs and return value.
224
- - throw = failure path, return = success path
225
- - Synchronous. Use execSync for shell commands.
226
- - Preferred for deterministic operations.
227
-
228
- Standard nodes:
229
- - execute: boolean param gates execution
230
- - Return { onSuccess: boolean, onFailure: boolean, ...outputs }
231
- - Can be async for I/O operations
232
-
233
- Async agent nodes:
234
- - Use (globalThis as any).__fw_agent_channel__ to pause workflow
235
- - Call channel.request({ agentId, context, prompt }) which returns a Promise
236
- - Workflow suspends until agent responds
237
- - NOT @expression (must be async)
238
-
239
- Pass-through pattern:
240
- - FW auto-connects ports by matching names on adjacent nodes
241
- - To forward data through intermediate nodes, declare it as both @input and @output with the same name
242
- - For non-adjacent wiring, use @connect sourceNode.port -> targetNode.port
243
-
244
- Data flow:
245
- - @path A -> B -> C: Linear execution path (sugar for multiple @connect)
246
- - @autoConnect: Auto-wire all nodes in declaration order
247
- - @connect: Explicit port-to-port wiring
248
- - Merge strategies for fan-in: FIRST, LAST, COLLECT, MERGE, CONCAT
249
-
250
- ## CLI Commands
251
-
252
- \${cmdLines.join('\\n')}
253
-
254
- Key workflows:
255
- flow-weaver compile <file> -- Generate executable code (in-place)
256
- flow-weaver validate <file> -- Check for errors without compiling
257
- flow-weaver modify <op> --file <f> -- Structural changes (addNode, removeNode, addConnection, removeConnection)
258
- flow-weaver implement <file> -- Replace declare stubs with implementations
259
- flow-weaver diff <a> <b> -- Semantic diff between two workflow versions
260
- flow-weaver diagram <file> -f ascii-compact -- Generate ASCII diagram
261
-
262
- ## Validation Errors
263
-
264
- \${errorLines.join('\\n')}
265
-
266
- When you encounter validation errors, suggest the specific fix. Common resolutions:
267
- - UNKNOWN_NODE_TYPE: Ensure the referenced function has @flowWeaver nodeType annotation
268
- - MISSING_REQUIRED_INPUT: Add a @connect from a source port or make the input optional with [brackets]
269
- - UNKNOWN_SOURCE_PORT / UNKNOWN_TARGET_PORT: Check port name spelling in @connect
270
- - CYCLE_DETECTED: Break the cycle; use scoped iteration (@scope, @map) instead of circular dependencies
271
-
272
- ## Genesis Protocol
273
-
274
- Genesis is a 17-step self-evolving workflow engine:
275
- 1. Load config (.genesis/config.json with intent, focus, constraints, approval thresholds)
276
- 2. Observe project (fingerprint: files, package.json, git, CI, tests, existing FW workflows)
277
- 3. Load task workflow (genesis-task.ts)
278
- 4. Diff fingerprint against last cycle
279
- 5. Check stabilize mode (3+ rollbacks/rejections = read-only, or explicit flag)
280
- 6. Wait for agent (YOU decide what evolutions to propose)
281
- 7. Propose evolution (map your decisions to FwModifyOperation[])
282
- 8. Validate proposal (budget: max 3 cost units per cycle. addNode=1, removeNode=1, addConnection=1, removeConnection=1, implementNode=2)
283
- 9. Snapshot current task workflow for rollback
284
- 10. Apply changes via flow-weaver CLI
285
- 11. Compile and validate (auto-rollback on failure)
286
- 12. Diff workflow (semantic diff)
287
- 13. Check approval threshold (CRITICAL > BREAKING > MINOR > COSMETIC)
288
- 14. Wait for approval (if impact >= threshold)
289
- 15. Commit or rollback based on approval
290
- 16. Update history (.genesis/history.json)
291
- 17. Report summary
292
-
293
- When stabilize mode is active, only fix-up operations are allowed: removeNode, removeConnection, implementNode. No new nodes or connections.
294
-
295
- ## Response Format
296
-
297
- Return ONLY valid JSON. No markdown, no code fences, no explanation outside the JSON structure. Your response must parse with JSON.parse() directly.\`;
298
- } catch {
299
- return FALLBACK;
300
- }
301
- }
302
-
303
- // ============================================================
304
- // Node Types
305
- // ============================================================
306
-
307
- /**
308
- * @flowWeaver nodeType
309
- * @expression
310
- * @label Load Config
311
- * @input [projectDir] [order:0] - Project root directory (defaults to cwd)
312
- * @output projectDir [order:0] - Project root directory (pass-through)
313
- * @output config [order:1] - Weaver configuration (JSON)
314
- */
315
- function loadConfig(projectDir?: string): { projectDir: string; config: string } {
316
- const dir = projectDir || process.cwd();
317
- const configPath = path.join(dir, '.weaver.json');
318
- let config: WeaverConfig = { provider: 'auto' };
319
- if (fs.existsSync(configPath)) {
320
- config = { ...config, ...JSON.parse(fs.readFileSync(configPath, 'utf-8')) };
321
- info(\`Loaded config from \${configPath}\`);
322
- } else {
323
- info('No .weaver.json found, using defaults (provider: auto)');
324
- }
325
- return { projectDir: dir, config: JSON.stringify(config) };
326
- }
327
-
328
- /**
329
- * @flowWeaver nodeType
330
- * @expression
331
- * @label Detect Provider
332
- * @input projectDir [order:0] - Project root directory
333
- * @input config [order:1] - Weaver configuration (JSON)
334
- * @output projectDir [order:0] - Project root directory (pass-through)
335
- * @output config [order:1] - Config (pass-through)
336
- * @output providerType [order:2] - Resolved provider type
337
- * @output providerInfo [order:3] - Provider details (JSON)
338
- */
339
- function detectProvider(projectDir: string, config: string): {
340
- projectDir: string; config: string;
341
- providerType: string; providerInfo: string;
342
- } {
343
- const cfg: WeaverConfig = JSON.parse(config);
344
- let providerSetting = cfg.provider ?? 'auto';
345
-
346
- let type: string;
347
- let model: string | undefined;
348
- let maxTokens: number | undefined;
349
-
350
- if (typeof providerSetting === 'object') {
351
- type = providerSetting.name;
352
- model = providerSetting.model;
353
- maxTokens = providerSetting.maxTokens;
354
- } else if (providerSetting !== 'auto') {
355
- type = providerSetting;
356
- } else {
357
- // Auto-detection
358
- if (process.env.ANTHROPIC_API_KEY) {
359
- type = 'anthropic';
360
- } else if (runSafe(process.platform === 'win32' ? 'where claude' : 'which claude', projectDir)) {
361
- type = 'claude-cli';
362
- } else if (runSafe(process.platform === 'win32' ? 'where copilot' : 'which copilot', projectDir)) {
363
- type = 'copilot-cli';
364
- } else {
365
- throw new Error(
366
- 'No AI provider found. Options:\\n' +
367
- ' 1. Set ANTHROPIC_API_KEY environment variable\\n' +
368
- ' 2. Install Claude CLI: https://docs.anthropic.com/claude-code\\n' +
369
- ' 3. Install GitHub Copilot CLI: https://github.com/features/copilot'
370
- );
371
- }
372
- }
373
-
374
- const providerInfo: ProviderInfo = {
375
- type: type as ProviderInfo['type'],
376
- model: model ?? (type === 'anthropic' ? 'claude-sonnet-4-6' : undefined),
377
- maxTokens: maxTokens ?? (type === 'anthropic' ? 4096 : undefined),
378
- apiKey: type === 'anthropic' ? process.env.ANTHROPIC_API_KEY : undefined,
379
- };
380
-
381
- if (type === 'anthropic' && !providerInfo.apiKey) {
382
- throw new Error('Provider is "anthropic" but ANTHROPIC_API_KEY is not set');
383
- }
384
-
385
- const label = providerInfo.model ? \`\${type} (\${providerInfo.model})\` : type;
386
- info(\`Provider: \${label}\`);
387
-
388
- return {
389
- projectDir, config,
390
- providerType: type,
391
- providerInfo: JSON.stringify(providerInfo),
392
- };
393
- }
394
-
395
- /**
396
- * @flowWeaver nodeType
397
- * @expression
398
- * @label Resolve Target
399
- * @input projectDir [order:0] - Project root directory
400
- * @input config [order:1] - Config (JSON)
401
- * @input providerType [order:2] - Provider type (pass-through)
402
- * @input providerInfo [order:3] - Provider info (pass-through)
403
- * @output projectDir [order:0] - Project root directory (pass-through)
404
- * @output config [order:1] - Config (pass-through)
405
- * @output providerType [order:2] - Provider type (pass-through)
406
- * @output providerInfo [order:3] - Provider info (pass-through)
407
- * @output targetPath [order:4] - Absolute path to target workflow
408
- */
409
- function resolveTarget(
410
- projectDir: string, config: string, providerType: string, providerInfo: string,
411
- ): {
412
- projectDir: string; config: string; providerType: string; providerInfo: string;
413
- targetPath: string;
414
- } {
415
- const cfg: WeaverConfig = JSON.parse(config);
416
-
417
- if (cfg.target) {
418
- const abs = path.resolve(projectDir, cfg.target);
419
- if (!fs.existsSync(abs)) throw new Error(\`Target workflow not found: \${abs}\`);
420
- info(\`Target: \${abs}\`);
421
- return { projectDir, config, providerType, providerInfo, targetPath: abs };
422
- }
423
-
424
- // Scan for workflow files (depth 2)
425
- const found: string[] = [];
426
- const scan = (dir: string, depth: number): void => {
427
- if (depth > 2) return;
428
- let entries: fs.Dirent[];
429
- try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
430
- for (const entry of entries) {
431
- if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;
432
- const full = path.join(dir, entry.name);
433
- if (entry.isDirectory()) { scan(full, depth + 1); }
434
- else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.d.ts')) {
435
- try {
436
- const content = fs.readFileSync(full, 'utf-8').slice(0, 2000);
437
- if (content.includes('@flowWeaver workflow')) found.push(full);
438
- } catch { /* skip */ }
439
- }
440
- }
441
- };
442
- scan(projectDir, 0);
443
-
444
- if (found.length === 0) {
445
- throw new Error(\`No workflow files found in \${projectDir}. Set "target" in .weaver.json or pass a file path.\`);
446
- }
447
- if (found.length > 1) {
448
- throw new Error(
449
- \`Multiple workflows found. Set "target" in .weaver.json to pick one:\\n\` +
450
- found.map(f => \` - \${path.relative(projectDir, f)}\`).join('\\n')
451
- );
452
- }
453
-
454
- info(\`Target: \${found[0]}\`);
455
- return { projectDir, config, providerType, providerInfo, targetPath: found[0]! };
456
- }
457
-
458
- /**
459
- * @flowWeaver nodeType
460
- * @label Execute Target
461
- * @input projectDir [order:0] - Project root directory
462
- * @input config [order:1] - Config (JSON)
463
- * @input providerType [order:2] - Provider type
464
- * @input providerInfo [order:3] - Provider info (JSON)
465
- * @input targetPath [order:4] - Absolute path to target workflow
466
- * @output projectDir [order:0] - Project root directory (pass-through)
467
- * @output config [order:1] - Config (pass-through)
468
- * @output targetPath [order:2] - Target path (pass-through)
469
- * @output resultJson [order:3] - Workflow execution result (JSON)
470
- * @output onSuccess [order:-2] - On Success
471
- * @output onFailure [order:-1] - On Failure
472
- */
473
- async function executeTarget(
474
- execute: boolean,
475
- projectDir: string,
476
- config: string,
477
- providerType: string,
478
- providerInfo: string,
479
- targetPath: string,
480
- ): Promise<{
481
- onSuccess: boolean; onFailure: boolean;
482
- projectDir: string; config: string; targetPath: string; resultJson: string;
483
- }> {
484
- if (!execute) {
485
- return {
486
- onSuccess: true, onFailure: false,
487
- projectDir, config, targetPath,
488
- resultJson: JSON.stringify({ success: true, summary: 'Dry run', outcome: 'skipped' }),
489
- };
490
- }
491
-
492
- const pInfo: ProviderInfo = JSON.parse(providerInfo);
493
- const cfg: WeaverConfig = JSON.parse(config);
494
-
495
- // Build expert system prompt from flow-weaver's doc-metadata
496
- const systemPrompt = await buildWeaverPrompt();
497
-
498
- // Resolve approval settings
499
- const approvalSetting = cfg.approval ?? 'auto';
500
- const approvalMode = typeof approvalSetting === 'string' ? approvalSetting : approvalSetting.mode;
501
-
502
- // Create agent channel
503
- const agentChannel = {
504
- request: async (req: { agentId: string; context: Record<string, unknown>; prompt: string }) => {
505
- // Handle approval requests
506
- if (req.agentId.includes('approval')) {
507
- if (approvalMode === 'auto') {
508
- info('Auto-approving');
509
- return { approved: true, reason: 'auto-approved' };
510
- }
511
- if (approvalMode === 'timeout-auto') {
512
- const timeout = typeof approvalSetting === 'object' ? (approvalSetting.timeoutSeconds ?? 300) : 300;
513
- info(\`Waiting \${timeout}s before auto-approving...\`);
514
- await new Promise(resolve => setTimeout(resolve, timeout * 1000));
515
- return { approved: true, reason: 'timeout-auto-approved' };
516
- }
517
- return { approved: true, reason: 'default-approved' };
518
- }
519
-
520
- // Regular agent decisions
521
- const contextStr = typeof req.context === 'string'
522
- ? req.context
523
- : JSON.stringify(req.context, null, 2);
524
- const userPrompt = \`Context:\\n\${contextStr}\\n\\nInstructions:\\n\${req.prompt}\`;
525
-
526
- let text: string;
527
- if (pInfo.type === 'anthropic') {
528
- text = await callApiAsync(
529
- pInfo.apiKey!,
530
- pInfo.model ?? 'claude-sonnet-4-6',
531
- pInfo.maxTokens ?? 4096,
532
- systemPrompt,
533
- userPrompt,
534
- );
535
- } else {
536
- text = callCli(pInfo.type, systemPrompt + '\\n\\n' + userPrompt);
537
- }
538
-
539
- return parseJsonResponse(text);
540
- },
541
- onPause: () => new Promise<never>(() => {}),
542
- resume: () => {},
543
- fail: () => {},
544
- };
545
-
546
- try {
547
- info(\`Executing: \${targetPath}\`);
548
- const startTime = Date.now();
549
-
550
- const mod = '@synergenius/flow-weaver/executor';
551
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
552
- const { executeWorkflowFromFile } = await (import(mod) as Promise<any>);
553
- const execResult = await executeWorkflowFromFile(targetPath, {}, {
554
- agentChannel,
555
- includeTrace: false,
556
- production: true,
557
- });
558
-
559
- const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
560
- const result = execResult.result as Record<string, unknown> | null;
561
- const ok = (result?.onSuccess as boolean) ?? false;
562
- // Build summary from result fields, falling back gracefully
563
- let summary: string;
564
- if (typeof result?.summary === 'string') {
565
- summary = result.summary;
566
- } else if (result) {
567
- const parts: string[] = [];
568
- for (const [k, v] of Object.entries(result)) {
569
- if (k === 'onSuccess' || k === 'onFailure' || v == null) continue;
570
- const s = typeof v === 'string' ? v : JSON.stringify(v);
571
- parts.push(k + ': ' + (s.length > 80 ? s.slice(0, 80) + '...' : s));
572
- }
573
- summary = parts.length > 0 ? parts.join(', ') : 'completed';
574
- } else {
575
- summary = 'completed';
576
- }
577
-
578
- if (ok) success(\`Completed in \${elapsed}s: \${summary}\`);
579
- else warn(\`Failed after \${elapsed}s: \${summary}\`);
580
-
581
- const resultObj = {
582
- success: ok,
583
- summary,
584
- outcome: ok ? 'completed' : 'failed',
585
- functionName: execResult.functionName,
586
- executionTime: Number(elapsed),
587
- };
588
-
589
- return {
590
- onSuccess: ok, onFailure: !ok,
591
- projectDir, config, targetPath,
592
- resultJson: JSON.stringify(resultObj),
593
- };
594
- } catch (err: unknown) {
595
- const msg = err instanceof Error ? err.message : String(err);
596
- warn(\`Error: \${msg}\`);
597
- return {
598
- onSuccess: false, onFailure: true,
599
- projectDir, config, targetPath,
600
- resultJson: JSON.stringify({ success: false, summary: msg, outcome: 'error' }),
601
- };
602
- }
603
- }
604
-
605
- /**
606
- * @flowWeaver nodeType
607
- * @expression
608
- * @label Notify Result
609
- * @input projectDir [order:0] - Project root directory
610
- * @input config [order:1] - Config (JSON)
611
- * @input targetPath [order:2] - Target path
612
- * @input resultJson [order:3] - Result (JSON)
613
- * @output projectDir [order:0] - Project root directory (pass-through)
614
- * @output targetPath [order:1] - Target path (pass-through)
615
- * @output resultJson [order:2] - Result (pass-through)
616
- */
617
- function sendNotify(
618
- projectDir: string, config: string, targetPath: string, resultJson: string,
619
- ): { projectDir: string; targetPath: string; resultJson: string } {
620
- const cfg: WeaverConfig = JSON.parse(config);
621
- const result = JSON.parse(resultJson);
622
- const channels = cfg.notify ?? [];
623
-
624
- for (const ch of channels) {
625
- const events = ch.events ?? ['workflow-complete', 'error'];
626
- const eventType = result.success ? 'workflow-complete' : 'error';
627
- if (!events.includes(eventType)) continue;
628
- sendWebhook(ch, { ...result, targetPath, providerType: cfg.provider, projectDir });
629
- }
630
-
631
- if (channels.length > 0) info(\`Sent \${channels.length} notification(s)\`);
632
- return { projectDir, targetPath, resultJson };
633
- }
634
-
635
- /**
636
- * @flowWeaver nodeType
637
- * @expression
638
- * @label Report
639
- * @input projectDir [order:0] - Project root directory
640
- * @input targetPath [order:1] - Target workflow path
641
- * @input resultJson [order:2] - Result (JSON)
642
- * @output summary [order:0] - Summary string
643
- */
644
- function report(projectDir: string, targetPath: string, resultJson: string): { summary: string } {
645
- const result = JSON.parse(resultJson);
646
- const relPath = path.relative(projectDir, targetPath);
647
- const lines = [
648
- \`Weaver: \${result.outcome} (\${relPath})\`,
649
- result.summary,
650
- ];
651
- if (result.executionTime) lines.push(\`Time: \${result.executionTime}s\`);
652
- success(lines[0]!);
653
- return { summary: lines.join('\\n') };
654
- }
655
-
656
- // ============================================================
657
- // Workflow
658
- // ============================================================
15
+ import { weaverLoadConfig } from '@synergenius/flowweaver-pack-weaver/node-types';
16
+ import { weaverDetectProvider } from '@synergenius/flowweaver-pack-weaver/node-types';
17
+ import { weaverResolveTarget } from '@synergenius/flowweaver-pack-weaver/node-types';
18
+ import { weaverExecuteTarget } from '@synergenius/flowweaver-pack-weaver/node-types';
19
+ import { weaverSendNotify } from '@synergenius/flowweaver-pack-weaver/node-types';
20
+ import { weaverReport } from '@synergenius/flowweaver-pack-weaver/node-types';
659
21
 
660
22
  /**
661
23
  * @flowWeaver workflow
662
- * @node cfg loadConfig [color: "teal"] [icon: "settings"] [position: 100 0]
663
- * @node detect detectProvider [color: "cyan"] [icon: "search"] [position: 250 0]
664
- * @node target resolveTarget [color: "blue"] [icon: "code"] [position: 400 0]
665
- * @node exec executeTarget [color: "purple"] [icon: "psychology"] [position: 550 0]
666
- * @node notify sendNotify [color: "yellow"] [icon: "notifications"] [position: 700 0]
667
- * @node rep report [color: "green"] [icon: "description"] [position: 850 0]
24
+ * @node cfg weaverLoadConfig [color: "teal"] [icon: "settings"] [position: 100 0]
25
+ * @node detect weaverDetectProvider [color: "cyan"] [icon: "search"] [position: 250 0]
26
+ * @node target weaverResolveTarget [color: "blue"] [icon: "code"] [position: 400 0]
27
+ * @node exec weaverExecuteTarget [color: "purple"] [icon: "psychology"] [position: 550 0]
28
+ * @node notify weaverSendNotify [color: "yellow"] [icon: "notifications"] [position: 700 0]
29
+ * @node rep weaverReport [color: "green"] [icon: "description"] [position: 850 0]
668
30
  * @path Start -> cfg -> detect -> target -> exec -> notify -> rep -> Exit
669
31
  * @position Start 0 0
670
32
  * @position Exit 1000 0
@@ -1 +1 @@
1
- {"version":3,"file":"weaver-template.js","sourceRoot":"","sources":["../../src/templates/weaver-template.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,cAAc,GAAqB;IAC9C,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,oCAAoC;IAC1C,WAAW,EAAE,8HAA8H;IAC3I,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;QAClB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyqBV,CAAC;IACA,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"weaver-template.js","sourceRoot":"","sources":["../../src/templates/weaver-template.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,cAAc,GAAqB;IAC9C,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,oCAAoC;IAC1C,WAAW,EAAE,8HAA8H;IAC3I,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;QAClB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2CV,CAAC;IACA,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { weaver } from './weaver.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workflows/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}