machinaos 0.0.21 → 0.0.23

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 (60) hide show
  1. package/README.md +32 -6
  2. package/bin/cli.js +0 -0
  3. package/client/dist/assets/index-5BWZnM6b.js +703 -0
  4. package/client/dist/index.html +1 -1
  5. package/client/package.json +1 -1
  6. package/client/src/Dashboard.tsx +12 -5
  7. package/client/src/ParameterPanel.tsx +6 -5
  8. package/client/src/components/AIAgentNode.tsx +35 -16
  9. package/client/src/components/CredentialsModal.tsx +450 -5
  10. package/client/src/components/TeamMonitorNode.tsx +269 -0
  11. package/client/src/components/parameterPanel/InputSection.tsx +25 -0
  12. package/client/src/contexts/WebSocketContext.tsx +38 -0
  13. package/client/src/hooks/useApiKeys.ts +44 -0
  14. package/client/src/nodeDefinitions/specializedAgentNodes.ts +59 -3
  15. package/client/src/nodeDefinitions/twitterNodes.ts +441 -0
  16. package/client/src/nodeDefinitions/utilityNodes.ts +45 -1
  17. package/client/src/nodeDefinitions.ts +7 -1
  18. package/client/src/services/executionService.ts +4 -1
  19. package/install.sh +63 -1
  20. package/package.json +5 -2
  21. package/scripts/build.js +0 -0
  22. package/scripts/clean.js +0 -0
  23. package/scripts/daemon.js +0 -0
  24. package/scripts/docker.js +0 -0
  25. package/scripts/install.js +0 -0
  26. package/scripts/postinstall.js +29 -0
  27. package/scripts/preinstall.js +67 -0
  28. package/scripts/serve-client.js +0 -0
  29. package/scripts/start.js +0 -0
  30. package/scripts/stop.js +0 -0
  31. package/scripts/sync-version.js +0 -0
  32. package/server/Dockerfile +10 -15
  33. package/server/constants.py +20 -0
  34. package/server/core/database.py +443 -3
  35. package/server/main.py +9 -1
  36. package/server/models/database.py +112 -2
  37. package/server/pyproject.toml +3 -0
  38. package/server/requirements.txt +3 -0
  39. package/server/routers/twitter.py +390 -0
  40. package/server/routers/websocket.py +320 -0
  41. package/server/services/agent_team.py +266 -0
  42. package/server/services/ai.py +43 -0
  43. package/server/services/compaction.py +39 -4
  44. package/server/services/event_waiter.py +41 -0
  45. package/server/services/handlers/__init__.py +13 -0
  46. package/server/services/handlers/ai.py +66 -2
  47. package/server/services/handlers/tools.py +84 -0
  48. package/server/services/handlers/twitter.py +297 -0
  49. package/server/services/handlers/utility.py +91 -0
  50. package/server/services/node_executor.py +15 -1
  51. package/server/services/pricing.py +270 -0
  52. package/server/services/status_broadcaster.py +79 -0
  53. package/server/services/twitter_oauth.py +410 -0
  54. package/server/skills/social_agent/twitter-search-skill/SKILL.md +146 -0
  55. package/server/skills/social_agent/twitter-send-skill/SKILL.md +142 -0
  56. package/server/skills/social_agent/twitter-user-skill/SKILL.md +165 -0
  57. package/workflows/Zeenie_full.json +459 -0
  58. package/workflows/Zeenie_small.json +459 -0
  59. package/client/dist/assets/index-YVvAiByx.js +0 -703
  60. package/server/requirements-docker.txt +0 -86
@@ -0,0 +1,441 @@
1
+ // Twitter/X Node Definitions - X API v2 integration via OAuth 2.0
2
+ import {
3
+ INodeTypeDescription,
4
+ NodeConnectionType
5
+ } from '../types/INodeProperties';
6
+
7
+ // ============================================================================
8
+ // TWITTER ICONS (SVG Data URIs) - X Brand black color
9
+ // ============================================================================
10
+
11
+ // Twitter/X Logo - Official X logo (white fill for dark backgrounds)
12
+ export const TWITTER_ICON = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23FFFFFF'%3E%3Cpath d='M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z'/%3E%3C/svg%3E";
13
+
14
+ // All Twitter nodes use the X logo
15
+ const TWITTER_SEND_ICON = TWITTER_ICON;
16
+ const TWITTER_RECEIVE_ICON = TWITTER_ICON;
17
+ const TWITTER_SEARCH_ICON = TWITTER_ICON;
18
+ const TWITTER_USER_ICON = TWITTER_ICON;
19
+
20
+ // ============================================================================
21
+ // TWITTER NODES
22
+ // ============================================================================
23
+
24
+ export const twitterNodes: Record<string, INodeTypeDescription> = {
25
+ // Twitter Send - Post tweets, reply, retweet, like
26
+ twitterSend: {
27
+ displayName: 'Twitter Send',
28
+ name: 'twitterSend',
29
+ icon: TWITTER_SEND_ICON,
30
+ group: ['social', 'tool'],
31
+ version: 1,
32
+ subtitle: 'Post to Twitter/X',
33
+ description: 'Post tweets, reply, retweet, like, or delete tweets on Twitter/X',
34
+ defaults: { name: 'Twitter Send', color: '#000000' },
35
+ inputs: [{
36
+ name: 'main',
37
+ displayName: 'Input',
38
+ type: 'main' as NodeConnectionType,
39
+ description: 'Tweet input'
40
+ }],
41
+ outputs: [
42
+ {
43
+ name: 'main',
44
+ displayName: 'Output',
45
+ type: 'main' as NodeConnectionType,
46
+ description: 'Tweet result'
47
+ },
48
+ {
49
+ name: 'tool',
50
+ displayName: 'Tool',
51
+ type: 'main' as NodeConnectionType,
52
+ description: 'Connect to AI Agent tool handle'
53
+ }
54
+ ],
55
+ properties: [
56
+ // ===== ACTION =====
57
+ {
58
+ displayName: 'Action',
59
+ name: 'action',
60
+ type: 'options',
61
+ options: [
62
+ { name: 'Post Tweet', value: 'tweet' },
63
+ { name: 'Reply to Tweet', value: 'reply' },
64
+ { name: 'Retweet', value: 'retweet' },
65
+ { name: 'Quote Tweet', value: 'quote' },
66
+ { name: 'Like Tweet', value: 'like' },
67
+ { name: 'Unlike Tweet', value: 'unlike' },
68
+ { name: 'Delete Tweet', value: 'delete' }
69
+ ],
70
+ default: 'tweet',
71
+ description: 'Action to perform on Twitter'
72
+ },
73
+
74
+ // ===== TWEET TEXT (for tweet, reply, quote) =====
75
+ {
76
+ displayName: 'Tweet Text',
77
+ name: 'text',
78
+ type: 'string',
79
+ default: '',
80
+ required: true,
81
+ typeOptions: { rows: 4 },
82
+ description: 'Tweet content (max 280 characters)',
83
+ placeholder: "What's happening?",
84
+ displayOptions: {
85
+ show: { action: ['tweet', 'reply', 'quote'] }
86
+ }
87
+ },
88
+
89
+ // ===== TWEET ID (for reply, retweet, quote, like, unlike, delete) =====
90
+ {
91
+ displayName: 'Tweet ID',
92
+ name: 'tweet_id',
93
+ type: 'string',
94
+ default: '',
95
+ required: true,
96
+ placeholder: '1234567890123456789',
97
+ description: 'ID of the tweet to interact with',
98
+ displayOptions: {
99
+ show: { action: ['reply', 'retweet', 'quote', 'like', 'unlike', 'delete'] }
100
+ }
101
+ },
102
+
103
+ // ===== MEDIA (for tweet, reply, quote) =====
104
+ {
105
+ displayName: 'Include Media',
106
+ name: 'include_media',
107
+ type: 'boolean',
108
+ default: false,
109
+ description: 'Attach images or videos to the tweet',
110
+ displayOptions: {
111
+ show: { action: ['tweet', 'reply', 'quote'] }
112
+ }
113
+ },
114
+ {
115
+ displayName: 'Media URLs',
116
+ name: 'media_urls',
117
+ type: 'string',
118
+ default: '',
119
+ placeholder: 'https://example.com/image1.jpg, https://example.com/image2.jpg',
120
+ description: 'Comma-separated URLs of media to attach (max 4 images or 1 video)',
121
+ displayOptions: {
122
+ show: { action: ['tweet', 'reply', 'quote'], include_media: [true] }
123
+ }
124
+ },
125
+
126
+ // ===== POLL (for tweet) =====
127
+ {
128
+ displayName: 'Include Poll',
129
+ name: 'include_poll',
130
+ type: 'boolean',
131
+ default: false,
132
+ description: 'Create a poll with this tweet',
133
+ displayOptions: {
134
+ show: { action: ['tweet'] }
135
+ }
136
+ },
137
+ {
138
+ displayName: 'Poll Options',
139
+ name: 'poll_options',
140
+ type: 'string',
141
+ default: '',
142
+ placeholder: 'Option 1, Option 2, Option 3',
143
+ description: 'Comma-separated poll options (2-4 options, max 25 chars each)',
144
+ displayOptions: {
145
+ show: { action: ['tweet'], include_poll: [true] }
146
+ }
147
+ },
148
+ {
149
+ displayName: 'Poll Duration (minutes)',
150
+ name: 'poll_duration',
151
+ type: 'number',
152
+ default: 1440,
153
+ typeOptions: { minValue: 5, maxValue: 10080 },
154
+ description: 'Poll duration in minutes (5 min - 7 days)',
155
+ displayOptions: {
156
+ show: { action: ['tweet'], include_poll: [true] }
157
+ }
158
+ }
159
+ ]
160
+ },
161
+
162
+ // Twitter Receive - Trigger on mentions, searches, timeline updates
163
+ twitterReceive: {
164
+ displayName: 'Twitter Receive',
165
+ name: 'twitterReceive',
166
+ icon: TWITTER_RECEIVE_ICON,
167
+ group: ['social', 'trigger'],
168
+ version: 1,
169
+ subtitle: 'On Twitter Event',
170
+ description: 'Trigger workflow on Twitter mentions, search results, or timeline updates (polling-based)',
171
+ defaults: { name: 'Twitter Receive', color: '#1DA1F2' },
172
+ inputs: [],
173
+ outputs: [{
174
+ name: 'main',
175
+ displayName: 'Tweet',
176
+ type: 'main' as NodeConnectionType,
177
+ description: 'Received tweet data (tweet_id, text, author_id, author_username, created_at, metrics)'
178
+ }],
179
+ properties: [
180
+ // ===== TRIGGER TYPE =====
181
+ {
182
+ displayName: 'Trigger On',
183
+ name: 'trigger_type',
184
+ type: 'options',
185
+ options: [
186
+ { name: 'Mentions', value: 'mentions' },
187
+ { name: 'Search Results', value: 'search' },
188
+ { name: 'User Timeline', value: 'timeline' }
189
+ ],
190
+ default: 'mentions',
191
+ description: 'What events should trigger this workflow'
192
+ },
193
+
194
+ // ===== SEARCH QUERY (for search trigger) =====
195
+ {
196
+ displayName: 'Search Query',
197
+ name: 'search_query',
198
+ type: 'string',
199
+ default: '',
200
+ required: true,
201
+ placeholder: 'from:elonmusk OR #AI',
202
+ description: 'Twitter search query (supports operators like from:, to:, #, -)',
203
+ displayOptions: {
204
+ show: { trigger_type: ['search'] }
205
+ }
206
+ },
207
+
208
+ // ===== USER ID (for timeline trigger) =====
209
+ {
210
+ displayName: 'User ID',
211
+ name: 'user_id',
212
+ type: 'string',
213
+ default: '',
214
+ placeholder: '12345678',
215
+ description: 'Twitter user ID to monitor (leave empty for authenticated user)',
216
+ displayOptions: {
217
+ show: { trigger_type: ['timeline'] }
218
+ }
219
+ },
220
+
221
+ // ===== OPTIONS =====
222
+ {
223
+ displayName: 'Filter Retweets',
224
+ name: 'filter_retweets',
225
+ type: 'boolean',
226
+ default: true,
227
+ description: 'Exclude retweets from results'
228
+ },
229
+ {
230
+ displayName: 'Filter Replies',
231
+ name: 'filter_replies',
232
+ type: 'boolean',
233
+ default: false,
234
+ description: 'Exclude replies from results'
235
+ },
236
+ {
237
+ displayName: 'Poll Interval (seconds)',
238
+ name: 'poll_interval',
239
+ type: 'number',
240
+ default: 60,
241
+ typeOptions: { minValue: 15, maxValue: 3600 },
242
+ description: 'How often to check for new tweets (15s - 1 hour)'
243
+ }
244
+ ]
245
+ },
246
+
247
+ // Twitter Search - Search recent tweets
248
+ twitterSearch: {
249
+ displayName: 'Twitter Search',
250
+ name: 'twitterSearch',
251
+ icon: TWITTER_SEARCH_ICON,
252
+ group: ['social', 'tool'],
253
+ version: 1,
254
+ subtitle: 'Search Tweets',
255
+ description: 'Search recent tweets on Twitter/X using the Search API',
256
+ defaults: { name: 'Twitter Search', color: '#1DA1F2' },
257
+ inputs: [{
258
+ name: 'main',
259
+ displayName: 'Input',
260
+ type: 'main' as NodeConnectionType,
261
+ description: 'Search input'
262
+ }],
263
+ outputs: [
264
+ {
265
+ name: 'main',
266
+ displayName: 'Output',
267
+ type: 'main' as NodeConnectionType,
268
+ description: 'Search results'
269
+ },
270
+ {
271
+ name: 'tool',
272
+ displayName: 'Tool',
273
+ type: 'main' as NodeConnectionType,
274
+ description: 'Connect to AI Agent tool handle'
275
+ }
276
+ ],
277
+ properties: [
278
+ // ===== SEARCH QUERY =====
279
+ {
280
+ displayName: 'Search Query',
281
+ name: 'query',
282
+ type: 'string',
283
+ default: '',
284
+ required: true,
285
+ placeholder: '#AI lang:en -is:retweet',
286
+ description: 'Twitter search query with operators'
287
+ },
288
+
289
+ // ===== RESULT OPTIONS =====
290
+ {
291
+ displayName: 'Max Results',
292
+ name: 'max_results',
293
+ type: 'number',
294
+ default: 10,
295
+ typeOptions: { minValue: 10, maxValue: 100 },
296
+ description: 'Maximum number of tweets to return (10-100)'
297
+ },
298
+ {
299
+ displayName: 'Sort Order',
300
+ name: 'sort_order',
301
+ type: 'options',
302
+ options: [
303
+ { name: 'Recent', value: 'recency' },
304
+ { name: 'Relevance', value: 'relevancy' }
305
+ ],
306
+ default: 'recency',
307
+ description: 'Sort order for results'
308
+ },
309
+
310
+ // ===== TIME FILTERS =====
311
+ {
312
+ displayName: 'Start Time',
313
+ name: 'start_time',
314
+ type: 'string',
315
+ default: '',
316
+ placeholder: '2024-01-01T00:00:00Z',
317
+ description: 'Start time for search (ISO 8601 format, optional)'
318
+ },
319
+ {
320
+ displayName: 'End Time',
321
+ name: 'end_time',
322
+ type: 'string',
323
+ default: '',
324
+ placeholder: '2024-01-31T23:59:59Z',
325
+ description: 'End time for search (ISO 8601 format, optional)'
326
+ },
327
+
328
+ // ===== INCLUDE OPTIONS =====
329
+ {
330
+ displayName: 'Include Metrics',
331
+ name: 'include_metrics',
332
+ type: 'boolean',
333
+ default: true,
334
+ description: 'Include tweet engagement metrics (likes, retweets, replies)'
335
+ },
336
+ {
337
+ displayName: 'Include Author Info',
338
+ name: 'include_author',
339
+ type: 'boolean',
340
+ default: true,
341
+ description: 'Include author details (username, name, profile)'
342
+ }
343
+ ]
344
+ },
345
+
346
+ // Twitter User - User lookup and profile operations (dual-purpose: workflow + AI tool)
347
+ twitterUser: {
348
+ displayName: 'Twitter User',
349
+ name: 'twitterUser',
350
+ icon: TWITTER_USER_ICON,
351
+ group: ['social', 'tool'],
352
+ version: 1,
353
+ subtitle: 'User Operations',
354
+ description: 'Look up Twitter users, get profile info, followers, following',
355
+ defaults: { name: 'Twitter User', color: '#1DA1F2' },
356
+ inputs: [{
357
+ name: 'main',
358
+ displayName: 'Input',
359
+ type: 'main' as NodeConnectionType,
360
+ description: 'User lookup input'
361
+ }],
362
+ outputs: [
363
+ {
364
+ name: 'main',
365
+ displayName: 'Output',
366
+ type: 'main' as NodeConnectionType,
367
+ description: 'User data'
368
+ },
369
+ {
370
+ name: 'tool',
371
+ displayName: 'Tool',
372
+ type: 'main' as NodeConnectionType,
373
+ description: 'Connect to AI Agent input-tools handle'
374
+ }
375
+ ],
376
+ properties: [
377
+ // ===== OPERATION =====
378
+ {
379
+ displayName: 'Operation',
380
+ name: 'operation',
381
+ type: 'options',
382
+ options: [
383
+ { name: 'Get My Profile', value: 'me' },
384
+ { name: 'Lookup by Username', value: 'by_username' },
385
+ { name: 'Lookup by ID', value: 'by_id' },
386
+ { name: 'Get Followers', value: 'followers' },
387
+ { name: 'Get Following', value: 'following' }
388
+ ],
389
+ default: 'me',
390
+ description: 'User operation to perform'
391
+ },
392
+
393
+ // ===== USERNAME (for by_username) =====
394
+ {
395
+ displayName: 'Username',
396
+ name: 'username',
397
+ type: 'string',
398
+ default: '',
399
+ required: true,
400
+ placeholder: 'elonmusk',
401
+ description: 'Twitter username (without @)',
402
+ displayOptions: {
403
+ show: { operation: ['by_username'] }
404
+ }
405
+ },
406
+
407
+ // ===== USER ID (for by_id, followers, following) =====
408
+ {
409
+ displayName: 'User ID',
410
+ name: 'user_id',
411
+ type: 'string',
412
+ default: '',
413
+ required: true,
414
+ placeholder: '44196397',
415
+ description: 'Twitter user ID',
416
+ displayOptions: {
417
+ show: { operation: ['by_id', 'followers', 'following'] }
418
+ }
419
+ },
420
+
421
+ // ===== PAGINATION (for followers, following) =====
422
+ {
423
+ displayName: 'Max Results',
424
+ name: 'max_results',
425
+ type: 'number',
426
+ default: 100,
427
+ typeOptions: { minValue: 1, maxValue: 1000 },
428
+ description: 'Maximum number of users to return',
429
+ displayOptions: {
430
+ show: { operation: ['followers', 'following'] }
431
+ }
432
+ }
433
+ ]
434
+ }
435
+ };
436
+
437
+ // ============================================================================
438
+ // EXPORTS
439
+ // ============================================================================
440
+
441
+ export const TWITTER_NODE_TYPES = ['twitterSend', 'twitterReceive', 'twitterSearch', 'twitterUser'];
@@ -278,7 +278,51 @@ export const utilityNodes: Record<string, INodeTypeDescription> = {
278
278
  description: 'Output format for the log'
279
279
  }
280
280
  ]
281
+ },
282
+
283
+ teamMonitor: {
284
+ displayName: 'Team Monitor',
285
+ name: 'teamMonitor',
286
+ icon: '📊',
287
+ group: ['utility', 'agent'],
288
+ version: 1,
289
+ description: 'Monitor agent team operations, tasks, and messages in real-time',
290
+ defaults: { name: 'Team Monitor', color: '#8b5cf6' },
291
+ inputs: [{ name: 'team', displayName: 'Team', type: 'main' as NodeConnectionType, description: 'Connect to AI Employee or Orchestrator Agent node' }],
292
+ outputs: [{ name: 'main', displayName: 'Events', type: 'main' as NodeConnectionType, description: 'task_completed, task_failed, message_received, team_status' }],
293
+ properties: [
294
+ {
295
+ displayName: 'Auto-Refresh Interval',
296
+ name: 'refreshInterval',
297
+ type: 'number',
298
+ default: 1000,
299
+ typeOptions: { minValue: 100, maxValue: 10000 },
300
+ description: 'Refresh interval in milliseconds (0 = WebSocket only)'
301
+ },
302
+ {
303
+ displayName: 'Show Task History',
304
+ name: 'showTaskHistory',
305
+ type: 'boolean',
306
+ default: true,
307
+ description: 'Display completed/failed tasks in history'
308
+ },
309
+ {
310
+ displayName: 'Show Messages',
311
+ name: 'showMessages',
312
+ type: 'boolean',
313
+ default: true,
314
+ description: 'Display inter-agent messages'
315
+ },
316
+ {
317
+ displayName: 'Max History Items',
318
+ name: 'maxHistoryItems',
319
+ type: 'number',
320
+ default: 50,
321
+ typeOptions: { minValue: 10, maxValue: 200 },
322
+ description: 'Maximum items to show in history'
323
+ }
324
+ ]
281
325
  }
282
326
  };
283
327
 
284
- export const UTILITY_NODE_TYPES = ['httpRequest', 'webhookTrigger', 'webhookResponse', 'chatTrigger', 'console'];
328
+ export const UTILITY_NODE_TYPES = ['httpRequest', 'webhookTrigger', 'webhookResponse', 'chatTrigger', 'console', 'teamMonitor'];
@@ -17,6 +17,7 @@ import { utilityNodes, UTILITY_NODE_TYPES } from './nodeDefinitions/utilityNodes
17
17
  import { skillNodes, SKILL_NODE_TYPES } from './nodeDefinitions/skillNodes';
18
18
  import { documentNodes, DOCUMENT_NODE_TYPES } from './nodeDefinitions/documentNodes';
19
19
  import { socialNodes, SOCIAL_NODE_TYPES } from './nodeDefinitions/socialNodes';
20
+ import { twitterNodes, TWITTER_NODE_TYPES } from './nodeDefinitions/twitterNodes';
20
21
 
21
22
  // ============================================================================
22
23
  // MAIN NODE REGISTRY - Combining all modular definitions
@@ -38,7 +39,8 @@ export const nodeDefinitions: Record<string, INodeTypeDescription> = {
38
39
  ...utilityNodes,
39
40
  ...skillNodes,
40
41
  ...documentNodes,
41
- ...socialNodes
42
+ ...socialNodes,
43
+ ...twitterNodes
42
44
  };
43
45
 
44
46
  // ============================================================================
@@ -110,5 +112,9 @@ export const SOCIAL_NODES = [
110
112
  ...SOCIAL_NODE_TYPES
111
113
  ];
112
114
 
115
+ export const TWITTER_NODES = [
116
+ ...TWITTER_NODE_TYPES
117
+ ];
118
+
113
119
  // Re-export types and utilities from modular files for external access
114
120
  export { createBaseChatModel } from './nodeDefinitions/aiModelNodes';
@@ -5,6 +5,7 @@ import { CODE_NODE_TYPES } from '../nodeDefinitions/codeNodes';
5
5
  import { UTILITY_NODE_TYPES } from '../nodeDefinitions/utilityNodes';
6
6
  import { DOCUMENT_NODE_TYPES } from '../nodeDefinitions/documentNodes';
7
7
  import { SPECIALIZED_AGENT_TYPES } from '../nodeDefinitions/specializedAgentNodes';
8
+ import { TWITTER_NODE_TYPES } from '../nodeDefinitions/twitterNodes';
8
9
  import { Node, Edge } from 'reactflow';
9
10
  import { INodeExecutionData } from '../types/INodeProperties';
10
11
  import { API_CONFIG } from '../config/api';
@@ -223,7 +224,9 @@ export class ExecutionService {
223
224
  // Utility Nodes (HTTP, Webhooks)
224
225
  ...UTILITY_NODE_TYPES,
225
226
  // Document Processing Nodes
226
- ...DOCUMENT_NODE_TYPES
227
+ ...DOCUMENT_NODE_TYPES,
228
+ // Twitter/X Nodes
229
+ ...TWITTER_NODE_TYPES
227
230
  ];
228
231
 
229
232
  return supportedTypes.includes(nodeType);
package/install.sh CHANGED
@@ -52,11 +52,68 @@ detect_os() {
52
52
 
53
53
  OS=$(detect_os)
54
54
 
55
+ # Detect WSL
56
+ is_wsl() {
57
+ [[ -n "$WSL_DISTRO_NAME" ]] || [[ -n "$WSL_INTEROP" ]] || grep -qi microsoft /proc/version 2>/dev/null
58
+ }
59
+
60
+ # Configure npm for WSL (fix nvm conflicts and Windows paths)
61
+ setup_wsl_npm() {
62
+ if ! is_wsl; then
63
+ return 0
64
+ fi
65
+
66
+ info "WSL detected: Checking npm configuration..."
67
+
68
+ # If using nvm, remove any conflicting prefix from .npmrc
69
+ if [[ -n "$NVM_DIR" ]] || [[ -d "$HOME/.nvm" ]]; then
70
+ if grep -q '^prefix=' "$HOME/.npmrc" 2>/dev/null; then
71
+ info "Removing conflicting npm prefix (nvm detected)..."
72
+ sed -i '/^prefix=/d' "$HOME/.npmrc"
73
+ # Also remove globalconfig if present
74
+ sed -i '/^globalconfig=/d' "$HOME/.npmrc" 2>/dev/null || true
75
+ fi
76
+
77
+ # Source nvm to ensure proper paths
78
+ export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
79
+ if [[ -s "$NVM_DIR/nvm.sh" ]]; then
80
+ source "$NVM_DIR/nvm.sh"
81
+ fi
82
+
83
+ success "npm configured for nvm on WSL"
84
+ return 0
85
+ fi
86
+
87
+ # No nvm - check if npm is using Windows path
88
+ local npm_prefix
89
+ npm_prefix=$(npm config get prefix 2>/dev/null || echo "")
90
+
91
+ if [[ "$npm_prefix" == /mnt/* ]]; then
92
+ info "Configuring npm to use Linux-native path..."
93
+ mkdir -p "$HOME/.npm-global"
94
+ npm config set prefix "$HOME/.npm-global"
95
+ export PATH="$HOME/.npm-global/bin:$PATH"
96
+
97
+ # Add to .bashrc if not already there
98
+ if ! grep -q 'npm-global' "$HOME/.bashrc" 2>/dev/null; then
99
+ echo '' >> "$HOME/.bashrc"
100
+ echo '# npm global packages (WSL)' >> "$HOME/.bashrc"
101
+ echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> "$HOME/.bashrc"
102
+ info "Added npm-global to PATH in ~/.bashrc"
103
+ fi
104
+
105
+ success "npm configured for WSL"
106
+ fi
107
+ }
108
+
55
109
  # =============================================================================
56
110
  # Dependency Checks and Installation
57
111
  # =============================================================================
58
112
 
59
113
  check_node() {
114
+ # Clear command hash to ensure we find the latest node binary
115
+ hash -r 2>/dev/null || true
116
+
60
117
  if command -v node &> /dev/null; then
61
118
  version=$(node --version | tr -d 'v')
62
119
  major=$(echo "$version" | cut -d. -f1)
@@ -76,6 +133,8 @@ install_node() {
76
133
  macos)
77
134
  if command -v brew &> /dev/null; then
78
135
  brew install node@22
136
+ # Add node@22 to PATH (brew doesn't link it by default)
137
+ export PATH="/opt/homebrew/opt/node@22/bin:/usr/local/opt/node@22/bin:$PATH"
79
138
  else
80
139
  error_exit "Please install Homebrew first: https://brew.sh/"
81
140
  fi
@@ -104,7 +163,7 @@ install_node() {
104
163
  check_python() {
105
164
  for cmd in python3 python; do
106
165
  if command -v "$cmd" &> /dev/null; then
107
- version=$($cmd --version 2>&1 | grep -oP '\d+\.\d+' | head -1)
166
+ version=$($cmd --version 2>&1 | sed -n 's/.*Python \([0-9]*\.[0-9]*\).*/\1/p')
108
167
  major=$(echo "$version" | cut -d. -f1)
109
168
  minor=$(echo "$version" | cut -d. -f2)
110
169
  if [ "$major" -ge 3 ] && [ "$minor" -ge "$MIN_PYTHON_VERSION_MINOR" ]; then
@@ -192,6 +251,9 @@ main() {
192
251
  check_python || install_python
193
252
  check_uv || install_uv
194
253
 
254
+ # Configure npm for WSL before installing
255
+ setup_wsl_npm
256
+
195
257
  echo ""
196
258
  info "Installing MachinaOS..."
197
259
  echo ""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "machinaos",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "description": "Open source workflow automation platform with AI agents, React Flow, and n8n-inspired architecture",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -35,6 +35,7 @@
35
35
  "files": [
36
36
  "bin/",
37
37
  "scripts/",
38
+ "workflows/",
38
39
  "client/src/",
39
40
  "client/public/",
40
41
  "client/dist/",
@@ -93,7 +94,9 @@
93
94
  "daemon:restart": "node scripts/daemon.js restart",
94
95
  "version:sync": "node scripts/sync-version.js",
95
96
  "prepublishOnly": "node scripts/sync-version.js && node -e \"const p=require('./package.json'); if(!p.bin||!p.version){process.exit(1)}\"",
96
- "postinstall": "node scripts/postinstall.js"
97
+ "preinstall": "node scripts/preinstall.js",
98
+ "postinstall": "node scripts/postinstall.js",
99
+ "preuninstall": "node scripts/preinstall.js"
97
100
  },
98
101
  "dependencies": {
99
102
  "whatsapp-rpc": "^0.0.10",
package/scripts/build.js CHANGED
File without changes
package/scripts/clean.js CHANGED
File without changes
package/scripts/daemon.js CHANGED
File without changes
package/scripts/docker.js CHANGED
File without changes
File without changes