foliko 2.0.5 → 2.0.7

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 (93) hide show
  1. package/.claude/settings.local.json +4 -1
  2. package/.cli_default_systemPrompt.md +291 -0
  3. package/CLAUDE.md +3 -0
  4. package/README.md +20 -3
  5. package/docs/architecture.md +34 -2
  6. package/docs/extensions.md +199 -0
  7. package/docs/migration.md +100 -0
  8. package/docs/public-api.md +280 -24
  9. package/docs/usage.md +122 -30
  10. package/package.json +1 -1
  11. package/plugins/core/audit/index.js +1 -1
  12. package/plugins/core/default/bootstrap.js +44 -19
  13. package/plugins/core/python-loader/index.js +43 -25
  14. package/plugins/core/scheduler/index.js +1 -0
  15. package/plugins/core/skill-manager/PROMPT.md +6 -0
  16. package/plugins/core/skill-manager/index.js +402 -115
  17. package/plugins/core/sub-agent/PROMPT.md +10 -0
  18. package/plugins/core/sub-agent/index.js +36 -3
  19. package/plugins/core/think/index.js +1 -0
  20. package/plugins/core/workflow/context.js +941 -0
  21. package/plugins/core/workflow/engine.js +66 -0
  22. package/plugins/core/workflow/examples/01-basic.js +42 -0
  23. package/plugins/core/workflow/examples/01-basic.json +30 -0
  24. package/plugins/core/workflow/examples/02-choice.js +75 -0
  25. package/plugins/core/workflow/examples/02-choice.json +59 -0
  26. package/plugins/core/workflow/examples/03-chain-style.js +114 -0
  27. package/plugins/core/workflow/examples/03-each.json +41 -0
  28. package/plugins/core/workflow/examples/04-parallel.js +52 -0
  29. package/plugins/core/workflow/examples/04-parallel.json +51 -0
  30. package/plugins/core/workflow/examples/05-chain-style.json +68 -0
  31. package/plugins/core/workflow/examples/05-each.js +65 -0
  32. package/plugins/core/workflow/examples/06-script.js +82 -0
  33. package/plugins/core/workflow/examples/07-module-export.js +43 -0
  34. package/plugins/core/workflow/examples/08-default-export.js +29 -0
  35. package/plugins/core/workflow/examples/09-next-with-args.js +50 -0
  36. package/plugins/core/workflow/examples/10-logger.js +34 -0
  37. package/plugins/core/workflow/examples/11-storage.js +68 -0
  38. package/plugins/core/workflow/examples/simple.js +77 -0
  39. package/plugins/core/workflow/examples/simple.json +75 -0
  40. package/plugins/core/workflow/index.js +204 -78
  41. package/plugins/core/workflow/js-runner.js +318 -0
  42. package/plugins/core/workflow/json-runner.js +323 -0
  43. package/plugins/core/workflow/stages/action.js +211 -0
  44. package/plugins/core/workflow/stages/choice.js +74 -0
  45. package/plugins/core/workflow/stages/delay.js +73 -0
  46. package/plugins/core/workflow/stages/each.js +123 -0
  47. package/plugins/core/workflow/stages/parallel.js +69 -0
  48. package/plugins/core/workflow/stages/try.js +142 -0
  49. package/plugins/executors/data-splitter/PROMPT.md +13 -0
  50. package/plugins/executors/data-splitter/index.js +8 -6
  51. package/plugins/executors/extension/extension-registry.js +145 -0
  52. package/plugins/executors/extension/index.js +405 -437
  53. package/plugins/executors/extension/prompt-builder.js +359 -0
  54. package/plugins/executors/extension/skill-helper.js +143 -0
  55. package/plugins/messaging/feishu/index.js +5 -3
  56. package/plugins/messaging/qq/index.js +6 -4
  57. package/plugins/messaging/telegram/index.js +6 -3
  58. package/plugins/messaging/weixin/index.js +5 -3
  59. package/plugins/tools/PROMPT.md +26 -0
  60. package/plugins/tools/index.js +6 -5
  61. package/sandbox/check-context.js +5 -0
  62. package/sandbox/test-context.js +27 -0
  63. package/sandbox/test-fixes.js +40 -0
  64. package/sandbox/test-hello-js.js +46 -0
  65. package/skills/foliko/AGENTS.md +196 -43
  66. package/skills/foliko/SKILL.md +157 -28
  67. package/skills/mcp/SKILL.md +77 -118
  68. package/skills/plugins/SKILL.md +89 -3
  69. package/skills/python/SKILL.md +57 -39
  70. package/skills/skill-guide/SKILL.md +42 -34
  71. package/skills/workflows/SKILL.md +753 -436
  72. package/src/agent/chat.js +56 -28
  73. package/src/agent/main.js +39 -14
  74. package/src/agent/prompt-registry.js +56 -16
  75. package/src/agent/prompts/PROMPT.md +3 -0
  76. package/src/agent/sub.js +1 -1
  77. package/src/cli/ui/chat-ui-old.js +5 -2
  78. package/src/cli/ui/chat-ui.js +9 -5
  79. package/src/common/constants.js +12 -0
  80. package/src/common/error-capture.js +91 -0
  81. package/src/common/json-safe.js +20 -0
  82. package/src/common/logger.js +2 -2
  83. package/src/context/compressor.js +6 -2
  84. package/src/executors/mcp-executor.js +105 -125
  85. package/src/framework/framework.js +78 -12
  86. package/src/index.js +4 -0
  87. package/src/plugin/base.js +908 -5
  88. package/src/plugin/manager.js +124 -9
  89. package/src/tool/schema.js +32 -9
  90. package/src/utils/sandbox.js +1 -1
  91. package/website/index.html +821 -0
  92. package/skills/workflows/workflow-troubleshooting/DEBUGGING.md +0 -197
  93. package/skills/workflows/workflow-troubleshooting/SKILL.md +0 -391
@@ -0,0 +1,66 @@
1
+ /**
2
+ * FlowEngine v2 - Main entry point for v2 workflow system
3
+ * Supports JSON and JS workflow formats
4
+ */
5
+
6
+ const { JsonRunner } = require('./json-runner');
7
+ const { JsRunner } = require('./js-runner');
8
+
9
+ class FlowEngine {
10
+ constructor(framework) {
11
+ this.framework = framework;
12
+ this._jsonRunner = new JsonRunner(framework);
13
+ this._jsRunner = new JsRunner(framework);
14
+ this._log = require('../../../src/common/logger').logger.child('FlowEngine');
15
+ }
16
+
17
+ /**
18
+ * Execute a workflow
19
+ * @param {Object|string} workflow - Workflow definition
20
+ * @param {Object} input - Input data
21
+ * @param {string} sessionId - Session ID
22
+ * @returns {Promise<Object>} execution result
23
+ */
24
+ async execute(workflow, input = {}, sessionId = null) {
25
+ // Parse workflow if string
26
+ if (typeof workflow === 'string') {
27
+ try {
28
+ workflow = JSON.parse(workflow);
29
+ // It's JSON, use JsonRunner
30
+ return await this._jsonRunner.execute(workflow, input, sessionId);
31
+ } catch {
32
+ // Not JSON, treat as JS workflow
33
+ return await this._jsRunner.execute(workflow, input, sessionId);
34
+ }
35
+ }
36
+
37
+ // Object format detection
38
+ // v2 JSON: has flow + stages
39
+ if (workflow.flow && Array.isArray(workflow.stages)) {
40
+ return await this._jsonRunner.execute(workflow, input, sessionId);
41
+ }
42
+
43
+ // Assume JS format if it's a function (exported)
44
+ if (typeof workflow === 'function') {
45
+ return await this._jsRunner.execute(workflow, input, sessionId);
46
+ }
47
+
48
+ throw new Error(`Invalid workflow format. Expected { flow, stages } or JS function.`);
49
+ }
50
+
51
+ /**
52
+ * Get the JSON runner for direct access
53
+ */
54
+ getJsonRunner() {
55
+ return this._jsonRunner;
56
+ }
57
+
58
+ /**
59
+ * Get the JS runner for direct access
60
+ */
61
+ getJsRunner() {
62
+ return this._jsRunner;
63
+ }
64
+ }
65
+
66
+ module.exports = { FlowEngine };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Basic Sequential Workflow (JS Format)
3
+ * Demonstrates basic tool execution with $.tool
4
+ */
5
+
6
+ FLOW(function($) {
7
+ // Start: Fetch IP
8
+ $.push('start', async function($) {
9
+ const result = await $.tool.execute('fetch', {
10
+ url: 'https://api.ipify.org?format=json'
11
+ });
12
+ $.send({ ipData: result });
13
+ $.next('log');
14
+ });
15
+
16
+ // Log the result
17
+ $.push('log', function($) {
18
+ const ip = $.data.ipData?.body?.ip || 'unknown';
19
+ $.tool.execute('log_event', {
20
+ event: 'ip_fetched',
21
+ ip: ip
22
+ });
23
+ $.next('notify');
24
+ });
25
+
26
+ // Send notification
27
+ $.push('notify', function($) {
28
+ const ip = $.data.ipData?.body?.ip || 'unknown';
29
+ $.tool.execute('notification_send', {
30
+ title: 'IP Fetched',
31
+ message: 'Your public IP is: ' + ip
32
+ });
33
+ $.next('done');
34
+ });
35
+
36
+ // Done
37
+ $.push('done', function($) {
38
+ $.destroy();
39
+ });
40
+
41
+ $.next('start');
42
+ });
@@ -0,0 +1,30 @@
1
+ {
2
+ "flow": "basic-sequential",
3
+ "version": "2.0",
4
+ "description": "Basic sequential workflow - demonstrates tool chain",
5
+ "stages": [
6
+ {
7
+ "name": "fetch-ip",
8
+ "tool": "fetch",
9
+ "args": {
10
+ "url": "https://api.ipify.org?format=json"
11
+ }
12
+ },
13
+ {
14
+ "name": "log-ip",
15
+ "tool": "log_event",
16
+ "args": {
17
+ "event": "ip_fetched",
18
+ "ip": "{{fetch-ip.body.ip}}"
19
+ }
20
+ },
21
+ {
22
+ "name": "notify",
23
+ "tool": "notification_send",
24
+ "args": {
25
+ "title": "IP Fetched",
26
+ "message": "Your public IP is: {{fetch-ip.body.ip}}"
27
+ }
28
+ }
29
+ ]
30
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Status Router Workflow (JS Format)
3
+ * Demonstrates conditional routing with choice logic
4
+ */
5
+
6
+ FLOW(function($) {
7
+ // Stage 1: Check user status
8
+ $.push('check-status', async function($) {
9
+ const result = await $.tool.execute('fetch', {
10
+ url: 'https://api.example.com/users/' + $.input.userId
11
+ });
12
+ $.send({ status: result });
13
+ $.next('route');
14
+ });
15
+
16
+ // Stage 2: Route based on status
17
+ $.push('route', function($) {
18
+ const status = $.data.status?.body?.status || 'unknown';
19
+
20
+ if (status === 'active') {
21
+ $.next('handle-active');
22
+ } else if (status === 'pending') {
23
+ $.next('handle-pending');
24
+ } else if (status === 'inactive') {
25
+ $.next('handle-inactive');
26
+ } else {
27
+ $.next('handle-unknown');
28
+ }
29
+ });
30
+
31
+ // Stage 3a: Handle active user
32
+ $.push('handle-active', function($) {
33
+ $.tool.execute('log_event', {
34
+ event: 'user_active',
35
+ userId: $.input.userId
36
+ });
37
+ $.next('done');
38
+ });
39
+
40
+ // Stage 3b: Handle pending user
41
+ $.push('handle-pending', function($) {
42
+ $.tool.execute('log_event', {
43
+ event: 'user_pending',
44
+ userId: $.input.userId
45
+ });
46
+ $.next('done');
47
+ });
48
+
49
+ // Stage 3c: Handle inactive user
50
+ $.push('handle-inactive', function($) {
51
+ $.tool.execute('log_event', {
52
+ event: 'user_inactive',
53
+ userId: $.input.userId
54
+ });
55
+ $.next('done');
56
+ });
57
+
58
+ // Stage 3d: Handle unknown status
59
+ $.push('handle-unknown', function($) {
60
+ $.tool.execute('notification_send', {
61
+ title: 'Unknown Status',
62
+ message: 'User ' + $.input.userId + ' has unknown status'
63
+ });
64
+ $.next('done');
65
+ });
66
+
67
+ // Done
68
+ $.push('done', function($) {
69
+ $.destroy();
70
+ });
71
+
72
+ // Start with userId from input
73
+ const userId = $.input.userId || 1;
74
+ $.next('check-status');
75
+ });
@@ -0,0 +1,59 @@
1
+ {
2
+ "flow": "status-router",
3
+ "version": "2.0",
4
+ "description": "Choice/conditional workflow - routes based on status",
5
+ "input": {
6
+ "userId": 1,
7
+ "action": "process"
8
+ },
9
+ "stages": [
10
+ {
11
+ "name": "check-status",
12
+ "tool": "fetch",
13
+ "args": {
14
+ "url": "https://api.example.com/users/{{input.userId}}"
15
+ }
16
+ },
17
+ {
18
+ "name": "route",
19
+ "choice": [
20
+ { "when": "check-status.body.status == 'active'", "do": "handle-active" },
21
+ { "when": "check-status.body.status == 'pending'", "do": "handle-pending" },
22
+ { "when": "check-status.body.status == 'inactive'", "do": "handle-inactive" }
23
+ ],
24
+ "default": "handle-unknown"
25
+ },
26
+ {
27
+ "name": "handle-active",
28
+ "tool": "log_event",
29
+ "args": {
30
+ "event": "user_active",
31
+ "userId": "{{input.userId}}"
32
+ }
33
+ },
34
+ {
35
+ "name": "handle-pending",
36
+ "tool": "log_event",
37
+ "args": {
38
+ "event": "user_pending",
39
+ "userId": "{{input.userId}}"
40
+ }
41
+ },
42
+ {
43
+ "name": "handle-inactive",
44
+ "tool": "log_event",
45
+ "args": {
46
+ "event": "user_inactive",
47
+ "userId": "{{input.userId}}"
48
+ }
49
+ },
50
+ {
51
+ "name": "handle-unknown",
52
+ "tool": "notification_send",
53
+ "args": {
54
+ "title": "Unknown Status",
55
+ "message": "User {{input.userId}} has unknown status"
56
+ }
57
+ }
58
+ ]
59
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Chain-Style API Demo (JS Format)
3
+ * Demonstrates all chain-style APIs: tool, extension, workflow, agent, prompt, skill
4
+ */
5
+
6
+ FLOW(function($) {
7
+ // Stage 1: List available tools and extensions
8
+ $.push('list-resources', function($) {
9
+ const tools = $.tool.list();
10
+ const extensions = $.extension.list();
11
+ const workflows = $.workflow.list();
12
+ const skills = $.skill.list();
13
+
14
+ console.log('Available tools:', tools.length);
15
+ console.log('Available extensions:', extensions.length);
16
+ console.log('Available workflows:', workflows);
17
+ console.log('Available skills:', skills);
18
+
19
+ $.send({ resources: { tools: tools.length, extensions: extensions.length } });
20
+ $.next('use-extension');
21
+ });
22
+
23
+ // Stage 2: Use extension.execute()
24
+ $.push('use-extension', async function($) {
25
+ try {
26
+ // Call gate-trading extension
27
+ const balance = await $.extension.execute('gate', 'get_balance', {
28
+ currency: 'USDT'
29
+ });
30
+ console.log('Gate balance:', balance);
31
+ $.send({ balance });
32
+ } catch (err) {
33
+ console.log('Extension call failed:', err.message);
34
+ $.send({ balance: null });
35
+ }
36
+ $.next('use-skill');
37
+ });
38
+
39
+ // Stage 3: Use skill.execute()
40
+ $.push('use-skill', async function($) {
41
+ try {
42
+ // Call ambient skill
43
+ const result = await $.skill.execute('ambient', 'goals', {
44
+ command: '-a list'
45
+ });
46
+ console.log('Skill result:', result);
47
+ $.send({ skillResult: result });
48
+ } catch (err) {
49
+ console.log('Skill call failed:', err.message);
50
+ $.send({ skillResult: null });
51
+ }
52
+ $.next('use-workflow');
53
+ });
54
+
55
+ // Stage 4: Use workflow.execute()
56
+ $.push('use-workflow', async function($) {
57
+ try {
58
+ // Call sub-workflow
59
+ const result = await $.workflow.execute('log_event', {
60
+ input: {
61
+ event: 'chain_js_demo',
62
+ source: 'chain-style-flow.js'
63
+ }
64
+ });
65
+ console.log('Workflow result:', result);
66
+ $.send({ workflowResult: result });
67
+ } catch (err) {
68
+ console.log('Workflow call failed:', err.message);
69
+ $.send({ workflowResult: null });
70
+ }
71
+ $.next('use-agent');
72
+ });
73
+
74
+ // Stage 5: Use agent.chat()
75
+ $.push('use-agent', async function($) {
76
+ try {
77
+ const response = await $.agent.chat({
78
+ message: 'What is 2 + 2? Reply in one word.',
79
+ role: 'assistant'
80
+ });
81
+ console.log('Agent response:', response);
82
+ $.send({ agentResponse: response });
83
+ } catch (err) {
84
+ console.log('Agent call failed:', err.message);
85
+ $.send({ agentResponse: null });
86
+ }
87
+ $.next('use-prompt');
88
+ });
89
+
90
+ // Stage 6: Use prompt.send()
91
+ $.push('use-prompt', async function($) {
92
+ try {
93
+ const response = await $.prompt.send({
94
+ message: 'Say "Workflow Complete" if you receive this.',
95
+ role: 'assistant'
96
+ });
97
+ console.log('Prompt response:', response);
98
+ $.send({ promptResponse: response });
99
+ } catch (err) {
100
+ console.log('Prompt call failed:', err.message);
101
+ $.send({ promptResponse: null });
102
+ }
103
+ $.next('done');
104
+ });
105
+
106
+ // Done
107
+ $.push('done', function($) {
108
+ console.log('Chain-style demo complete!');
109
+ console.log('Final data:', $.data);
110
+ $.destroy();
111
+ });
112
+
113
+ $.next('list-resources');
114
+ });
@@ -0,0 +1,41 @@
1
+ {
2
+ "flow": "process-items",
3
+ "version": "2.0",
4
+ "description": "Each loop workflow - processes multiple items",
5
+ "input": {
6
+ "items": ["item1", "item2", "item3", "item4", "item5"]
7
+ },
8
+ "stages": [
9
+ {
10
+ "name": "initialize",
11
+ "action": "script",
12
+ "script": "return input.items || [];"
13
+ },
14
+ {
15
+ "name": "process-list",
16
+ "each": "{{initialize}}",
17
+ "as": "item",
18
+ "index": "idx",
19
+ "maxIterations": 10,
20
+ "stages": [
21
+ {
22
+ "name": "log-item",
23
+ "tool": "log_event",
24
+ "args": {
25
+ "event": "processing_item",
26
+ "index": "{{idx}}",
27
+ "item": "{{item}}"
28
+ }
29
+ }
30
+ ]
31
+ },
32
+ {
33
+ "name": "complete",
34
+ "tool": "notification_send",
35
+ "args": {
36
+ "title": "Processing Complete",
37
+ "message": "Processed {{initialize.length}} items"
38
+ }
39
+ }
40
+ ]
41
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Parallel Processing Workflow (JS Format)
3
+ * Demonstrates parallel stage execution
4
+ */
5
+
6
+ FLOW(function($) {
7
+ // Start: Fetch multiple sources in parallel
8
+ $.push('start', async function($) {
9
+ // These could be parallel, but JS format runs sequentially
10
+ // The parallel execution is mainly for JSON format
11
+ const [user, config, status] = await Promise.all([
12
+ $.tool.execute('fetch', { url: 'https://api.example.com/user/1' }),
13
+ $.tool.execute('fetch', { url: 'https://api.example.com/config' }),
14
+ $.tool.execute('fetch', { url: 'https://api.example.com/status' })
15
+ ]);
16
+
17
+ $.send({ user, config, status });
18
+ $.next('aggregate');
19
+ });
20
+
21
+ // Aggregate results
22
+ $.push('aggregate', function($) {
23
+ const userId = $.data.user?.body?.id || 'unknown';
24
+ const version = $.data.config?.body?.version || 'unknown';
25
+ const ok = $.data.status?.body?.ok || false;
26
+
27
+ $.tool.execute('log_event', {
28
+ event: 'parallel_fetch_complete',
29
+ userId: userId,
30
+ configVersion: version,
31
+ statusOk: ok
32
+ });
33
+
34
+ $.next('notify');
35
+ });
36
+
37
+ // Send notification
38
+ $.push('notify', function($) {
39
+ $.tool.execute('notification_send', {
40
+ title: 'Parallel Fetch Complete',
41
+ message: 'Fetched 3 sources concurrently. Check logs for details.'
42
+ });
43
+ $.next('done');
44
+ });
45
+
46
+ // Done
47
+ $.push('done', function($) {
48
+ $.destroy();
49
+ });
50
+
51
+ $.next('start');
52
+ });
@@ -0,0 +1,51 @@
1
+ {
2
+ "flow": "parallel-fetch",
3
+ "version": "2.0",
4
+ "description": "Parallel workflow - fetches multiple sources concurrently",
5
+ "stages": [
6
+ {
7
+ "name": "fetch-all",
8
+ "parallel": [
9
+ {
10
+ "name": "fetch-user",
11
+ "tool": "fetch",
12
+ "args": {
13
+ "url": "https://api.example.com/user/1"
14
+ }
15
+ },
16
+ {
17
+ "name": "fetch-config",
18
+ "tool": "fetch",
19
+ "args": {
20
+ "url": "https://api.example.com/config"
21
+ }
22
+ },
23
+ {
24
+ "name": "fetch-status",
25
+ "tool": "fetch",
26
+ "args": {
27
+ "url": "https://api.example.com/status"
28
+ }
29
+ }
30
+ ]
31
+ },
32
+ {
33
+ "name": "aggregate",
34
+ "tool": "log_event",
35
+ "args": {
36
+ "event": "parallel_fetch_complete",
37
+ "userId": "{{fetch-user.body.id}}",
38
+ "configVersion": "{{fetch-config.body.version}}",
39
+ "statusOk": "{{fetch-status.body.ok}}"
40
+ }
41
+ },
42
+ {
43
+ "name": "notify",
44
+ "tool": "notification_send",
45
+ "args": {
46
+ "title": "Parallel Fetch Complete",
47
+ "message": "Fetched 3 sources concurrently"
48
+ }
49
+ }
50
+ ]
51
+ }
@@ -0,0 +1,68 @@
1
+ {
2
+ "flow": "chain-style-demo",
3
+ "version": "2.0",
4
+ "description": "Chain-style workflow - demonstrates extension, skill, workflow calls",
5
+ "stages": [
6
+ {
7
+ "name": "start",
8
+ "tool": "log_event",
9
+ "args": {
10
+ "event": "chain_style_demo_started"
11
+ }
12
+ },
13
+ {
14
+ "name": "use-extension",
15
+ "description": "Using extension.execute() to call gate-trading",
16
+ "extension": "gate",
17
+ "tool": "get_balance",
18
+ "args": {
19
+ "currency": "USDT"
20
+ }
21
+ },
22
+ {
23
+ "name": "use-skill",
24
+ "description": "Using skill.execute() to call ambient agent",
25
+ "skill": "ambient",
26
+ "command": "goals",
27
+ "args": {
28
+ "command": "-a list"
29
+ }
30
+ },
31
+ {
32
+ "name": "use-workflow",
33
+ "description": "Using workflow.execute() to call sub-workflow",
34
+ "workflow": "log_event",
35
+ "args": {
36
+ "input": {
37
+ "event": "called_from_chain_style",
38
+ "source": "chain-style-demo"
39
+ }
40
+ }
41
+ },
42
+ {
43
+ "name": "use-agent",
44
+ "description": "Using agent.chat()",
45
+ "agent": "chat",
46
+ "args": {
47
+ "message": "What is the current time?",
48
+ "role": "assistant"
49
+ }
50
+ },
51
+ {
52
+ "name": "use-prompt",
53
+ "description": "Using prompt.send()",
54
+ "prompt": "send",
55
+ "args": {
56
+ "message": "Say hello in one word",
57
+ "role": "assistant"
58
+ }
59
+ },
60
+ {
61
+ "name": "complete",
62
+ "tool": "log_event",
63
+ "args": {
64
+ "event": "chain_style_demo_completed"
65
+ }
66
+ }
67
+ ]
68
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Each Loop Workflow (JS Format)
3
+ * Demonstrates iteration over items
4
+ */
5
+
6
+ FLOW(function($) {
7
+ // Stage 1: Initialize items
8
+ $.push('init', function($) {
9
+ const items = $.input.items || ['item1', 'item2', 'item3', 'item4', 'item5'];
10
+ $.send({ items, processed: [] });
11
+ $.next('process-loop');
12
+ });
13
+
14
+ // Stage 2: Process items one by one (simulating each loop)
15
+ $.push('process-loop', async function($) {
16
+ const items = $.data.items;
17
+ const processed = $.data.processed || [];
18
+
19
+ for (let i = 0; i < items.length; i++) {
20
+ const item = items[i];
21
+
22
+ // Log each item
23
+ await $.tool.execute('log_event', {
24
+ event: 'processing_item',
25
+ index: i,
26
+ item: item
27
+ });
28
+
29
+ // Add to processed list
30
+ processed.push({ index: i, item: item, status: 'done' });
31
+
32
+ // Small delay between items
33
+ await $.wait(100);
34
+ }
35
+
36
+ $.send({ items, processed });
37
+ $.next('complete');
38
+ });
39
+
40
+ // Stage 3: Complete
41
+ $.push('complete', function($) {
42
+ const count = $.data.processed?.length || 0;
43
+
44
+ $.tool.execute('notification_send', {
45
+ title: 'Processing Complete',
46
+ message: 'Processed ' + count + ' items'
47
+ });
48
+
49
+ $.tool.execute('log_event', {
50
+ event: 'loop_complete',
51
+ totalProcessed: count,
52
+ items: $.data.processed
53
+ });
54
+
55
+ $.next('done');
56
+ });
57
+
58
+ // Done
59
+ $.push('done', function($) {
60
+ $.destroy();
61
+ });
62
+
63
+ // Start
64
+ $.next('init');
65
+ });