machinaos 0.0.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.
Files changed (288) hide show
  1. package/.env.template +71 -0
  2. package/LICENSE +21 -0
  3. package/README.md +87 -0
  4. package/bin/cli.js +159 -0
  5. package/client/.dockerignore +45 -0
  6. package/client/Dockerfile +68 -0
  7. package/client/eslint.config.js +29 -0
  8. package/client/index.html +13 -0
  9. package/client/nginx.conf +66 -0
  10. package/client/package.json +48 -0
  11. package/client/src/App.tsx +27 -0
  12. package/client/src/Dashboard.tsx +1173 -0
  13. package/client/src/ParameterPanel.tsx +301 -0
  14. package/client/src/components/AIAgentNode.tsx +321 -0
  15. package/client/src/components/APIKeyValidator.tsx +118 -0
  16. package/client/src/components/ClaudeChatModelNode.tsx +18 -0
  17. package/client/src/components/ConditionalEdge.tsx +189 -0
  18. package/client/src/components/CredentialsModal.tsx +306 -0
  19. package/client/src/components/EdgeConditionEditor.tsx +443 -0
  20. package/client/src/components/GeminiChatModelNode.tsx +18 -0
  21. package/client/src/components/GenericNode.tsx +357 -0
  22. package/client/src/components/LocationParameterPanel.tsx +154 -0
  23. package/client/src/components/ModelNode.tsx +286 -0
  24. package/client/src/components/OpenAIChatModelNode.tsx +18 -0
  25. package/client/src/components/OutputPanel.tsx +471 -0
  26. package/client/src/components/ParameterRenderer.tsx +1874 -0
  27. package/client/src/components/SkillEditorModal.tsx +417 -0
  28. package/client/src/components/SquareNode.tsx +797 -0
  29. package/client/src/components/StartNode.tsx +250 -0
  30. package/client/src/components/ToolkitNode.tsx +365 -0
  31. package/client/src/components/TriggerNode.tsx +463 -0
  32. package/client/src/components/auth/LoginPage.tsx +247 -0
  33. package/client/src/components/auth/ProtectedRoute.tsx +59 -0
  34. package/client/src/components/base/BaseChatModelNode.tsx +271 -0
  35. package/client/src/components/icons/AIProviderIcons.tsx +50 -0
  36. package/client/src/components/maps/GoogleMapsPicker.tsx +137 -0
  37. package/client/src/components/maps/MapsPreviewPanel.tsx +110 -0
  38. package/client/src/components/maps/index.ts +26 -0
  39. package/client/src/components/parameterPanel/InputSection.tsx +1094 -0
  40. package/client/src/components/parameterPanel/LocationPanelLayout.tsx +65 -0
  41. package/client/src/components/parameterPanel/MapsSection.tsx +92 -0
  42. package/client/src/components/parameterPanel/MiddleSection.tsx +571 -0
  43. package/client/src/components/parameterPanel/OutputSection.tsx +81 -0
  44. package/client/src/components/parameterPanel/ParameterPanelLayout.tsx +82 -0
  45. package/client/src/components/parameterPanel/ToolSchemaEditor.tsx +436 -0
  46. package/client/src/components/parameterPanel/index.ts +42 -0
  47. package/client/src/components/shared/DataPanel.tsx +142 -0
  48. package/client/src/components/shared/JSONTreeRenderer.tsx +106 -0
  49. package/client/src/components/ui/AIResultModal.tsx +204 -0
  50. package/client/src/components/ui/AndroidSettingsPanel.tsx +401 -0
  51. package/client/src/components/ui/CodeEditor.tsx +81 -0
  52. package/client/src/components/ui/CollapsibleSection.tsx +88 -0
  53. package/client/src/components/ui/ComponentItem.tsx +154 -0
  54. package/client/src/components/ui/ComponentPalette.tsx +321 -0
  55. package/client/src/components/ui/ConsolePanel.tsx +1074 -0
  56. package/client/src/components/ui/ErrorBoundary.tsx +196 -0
  57. package/client/src/components/ui/InputNodesPanel.tsx +204 -0
  58. package/client/src/components/ui/MapSelector.tsx +314 -0
  59. package/client/src/components/ui/Modal.tsx +149 -0
  60. package/client/src/components/ui/NodeContextMenu.tsx +192 -0
  61. package/client/src/components/ui/NodeOutputPanel.tsx +1150 -0
  62. package/client/src/components/ui/OutputDisplayPanel.tsx +381 -0
  63. package/client/src/components/ui/SettingsPanel.tsx +243 -0
  64. package/client/src/components/ui/TopToolbar.tsx +736 -0
  65. package/client/src/components/ui/WhatsAppSettingsPanel.tsx +345 -0
  66. package/client/src/components/ui/WorkflowSidebar.tsx +294 -0
  67. package/client/src/config/antdTheme.ts +186 -0
  68. package/client/src/config/api.ts +54 -0
  69. package/client/src/contexts/AuthContext.tsx +221 -0
  70. package/client/src/contexts/ThemeContext.tsx +42 -0
  71. package/client/src/contexts/WebSocketContext.tsx +1971 -0
  72. package/client/src/factories/baseChatModelFactory.ts +256 -0
  73. package/client/src/hooks/useAndroidOperations.ts +164 -0
  74. package/client/src/hooks/useApiKeyValidation.ts +107 -0
  75. package/client/src/hooks/useApiKeys.ts +238 -0
  76. package/client/src/hooks/useAppTheme.ts +17 -0
  77. package/client/src/hooks/useComponentPalette.ts +51 -0
  78. package/client/src/hooks/useCopyPaste.ts +155 -0
  79. package/client/src/hooks/useDragAndDrop.ts +124 -0
  80. package/client/src/hooks/useDragVariable.ts +88 -0
  81. package/client/src/hooks/useExecution.ts +313 -0
  82. package/client/src/hooks/useParameterPanel.ts +176 -0
  83. package/client/src/hooks/useReactFlowNodes.ts +189 -0
  84. package/client/src/hooks/useToolSchema.ts +209 -0
  85. package/client/src/hooks/useWhatsApp.ts +196 -0
  86. package/client/src/hooks/useWorkflowManagement.ts +46 -0
  87. package/client/src/index.css +315 -0
  88. package/client/src/main.tsx +19 -0
  89. package/client/src/nodeDefinitions/aiAgentNodes.ts +336 -0
  90. package/client/src/nodeDefinitions/aiModelNodes.ts +340 -0
  91. package/client/src/nodeDefinitions/androidDeviceNodes.ts +140 -0
  92. package/client/src/nodeDefinitions/androidServiceNodes.ts +383 -0
  93. package/client/src/nodeDefinitions/chatNodes.ts +135 -0
  94. package/client/src/nodeDefinitions/codeNodes.ts +54 -0
  95. package/client/src/nodeDefinitions/documentNodes.ts +379 -0
  96. package/client/src/nodeDefinitions/index.ts +15 -0
  97. package/client/src/nodeDefinitions/locationNodes.ts +463 -0
  98. package/client/src/nodeDefinitions/schedulerNodes.ts +220 -0
  99. package/client/src/nodeDefinitions/skillNodes.ts +211 -0
  100. package/client/src/nodeDefinitions/toolNodes.ts +198 -0
  101. package/client/src/nodeDefinitions/utilityNodes.ts +284 -0
  102. package/client/src/nodeDefinitions/whatsappNodes.ts +865 -0
  103. package/client/src/nodeDefinitions/workflowNodes.ts +41 -0
  104. package/client/src/nodeDefinitions.ts +104 -0
  105. package/client/src/schemas/workflowSchema.ts +264 -0
  106. package/client/src/services/dynamicParameterService.ts +96 -0
  107. package/client/src/services/execution/aiAgentExecutionService.ts +35 -0
  108. package/client/src/services/executionService.ts +232 -0
  109. package/client/src/services/workflowApi.ts +91 -0
  110. package/client/src/store/useAppStore.ts +582 -0
  111. package/client/src/styles/theme.ts +508 -0
  112. package/client/src/styles/zIndex.ts +17 -0
  113. package/client/src/types/ComponentTypes.ts +39 -0
  114. package/client/src/types/EdgeCondition.ts +231 -0
  115. package/client/src/types/INodeProperties.ts +288 -0
  116. package/client/src/types/NodeTypes.ts +28 -0
  117. package/client/src/utils/formatters.ts +33 -0
  118. package/client/src/utils/googleMapsLoader.ts +140 -0
  119. package/client/src/utils/locationUtils.ts +85 -0
  120. package/client/src/utils/nodeUtils.ts +31 -0
  121. package/client/src/utils/workflow.ts +30 -0
  122. package/client/src/utils/workflowExport.ts +120 -0
  123. package/client/src/vite-env.d.ts +12 -0
  124. package/client/tailwind.config.js +60 -0
  125. package/client/tsconfig.json +25 -0
  126. package/client/tsconfig.node.json +11 -0
  127. package/client/vite.config.js +35 -0
  128. package/docker-compose.prod.yml +107 -0
  129. package/docker-compose.yml +104 -0
  130. package/docs-MachinaOs/README.md +85 -0
  131. package/docs-MachinaOs/deployment/docker.mdx +228 -0
  132. package/docs-MachinaOs/deployment/production.mdx +345 -0
  133. package/docs-MachinaOs/docs.json +75 -0
  134. package/docs-MachinaOs/faq.mdx +309 -0
  135. package/docs-MachinaOs/favicon.svg +5 -0
  136. package/docs-MachinaOs/installation.mdx +160 -0
  137. package/docs-MachinaOs/introduction.mdx +114 -0
  138. package/docs-MachinaOs/logo/dark.svg +6 -0
  139. package/docs-MachinaOs/logo/light.svg +6 -0
  140. package/docs-MachinaOs/nodes/ai-agent.mdx +216 -0
  141. package/docs-MachinaOs/nodes/ai-models.mdx +240 -0
  142. package/docs-MachinaOs/nodes/android.mdx +411 -0
  143. package/docs-MachinaOs/nodes/overview.mdx +181 -0
  144. package/docs-MachinaOs/nodes/schedulers.mdx +316 -0
  145. package/docs-MachinaOs/nodes/webhooks.mdx +330 -0
  146. package/docs-MachinaOs/nodes/whatsapp.mdx +305 -0
  147. package/docs-MachinaOs/quickstart.mdx +119 -0
  148. package/docs-MachinaOs/tutorials/ai-agent-workflow.mdx +177 -0
  149. package/docs-MachinaOs/tutorials/android-automation.mdx +242 -0
  150. package/docs-MachinaOs/tutorials/first-workflow.mdx +134 -0
  151. package/docs-MachinaOs/tutorials/whatsapp-automation.mdx +185 -0
  152. package/nul +0 -0
  153. package/package.json +70 -0
  154. package/scripts/build.js +158 -0
  155. package/scripts/check-ports.ps1 +33 -0
  156. package/scripts/clean.js +40 -0
  157. package/scripts/docker.js +93 -0
  158. package/scripts/kill-port.ps1 +154 -0
  159. package/scripts/start.js +210 -0
  160. package/scripts/stop.js +325 -0
  161. package/server/.dockerignore +44 -0
  162. package/server/Dockerfile +45 -0
  163. package/server/constants.py +249 -0
  164. package/server/core/__init__.py +1 -0
  165. package/server/core/cache.py +461 -0
  166. package/server/core/config.py +128 -0
  167. package/server/core/container.py +99 -0
  168. package/server/core/database.py +1211 -0
  169. package/server/core/logging.py +314 -0
  170. package/server/main.py +289 -0
  171. package/server/middleware/__init__.py +5 -0
  172. package/server/middleware/auth.py +89 -0
  173. package/server/models/__init__.py +1 -0
  174. package/server/models/auth.py +52 -0
  175. package/server/models/cache.py +24 -0
  176. package/server/models/database.py +211 -0
  177. package/server/models/nodes.py +455 -0
  178. package/server/package.json +9 -0
  179. package/server/pyproject.toml +72 -0
  180. package/server/requirements.txt +83 -0
  181. package/server/routers/__init__.py +1 -0
  182. package/server/routers/android.py +294 -0
  183. package/server/routers/auth.py +203 -0
  184. package/server/routers/database.py +151 -0
  185. package/server/routers/maps.py +142 -0
  186. package/server/routers/nodejs_compat.py +289 -0
  187. package/server/routers/webhook.py +90 -0
  188. package/server/routers/websocket.py +2127 -0
  189. package/server/routers/whatsapp.py +761 -0
  190. package/server/routers/workflow.py +200 -0
  191. package/server/services/__init__.py +1 -0
  192. package/server/services/ai.py +2415 -0
  193. package/server/services/android/__init__.py +27 -0
  194. package/server/services/android/broadcaster.py +114 -0
  195. package/server/services/android/client.py +608 -0
  196. package/server/services/android/manager.py +78 -0
  197. package/server/services/android/protocol.py +165 -0
  198. package/server/services/android_service.py +588 -0
  199. package/server/services/auth.py +131 -0
  200. package/server/services/chat_client.py +160 -0
  201. package/server/services/deployment/__init__.py +12 -0
  202. package/server/services/deployment/manager.py +706 -0
  203. package/server/services/deployment/state.py +47 -0
  204. package/server/services/deployment/triggers.py +275 -0
  205. package/server/services/event_waiter.py +785 -0
  206. package/server/services/execution/__init__.py +77 -0
  207. package/server/services/execution/cache.py +769 -0
  208. package/server/services/execution/conditions.py +373 -0
  209. package/server/services/execution/dlq.py +132 -0
  210. package/server/services/execution/executor.py +1351 -0
  211. package/server/services/execution/models.py +531 -0
  212. package/server/services/execution/recovery.py +235 -0
  213. package/server/services/handlers/__init__.py +126 -0
  214. package/server/services/handlers/ai.py +355 -0
  215. package/server/services/handlers/android.py +260 -0
  216. package/server/services/handlers/code.py +278 -0
  217. package/server/services/handlers/document.py +598 -0
  218. package/server/services/handlers/http.py +193 -0
  219. package/server/services/handlers/polyglot.py +105 -0
  220. package/server/services/handlers/tools.py +845 -0
  221. package/server/services/handlers/triggers.py +107 -0
  222. package/server/services/handlers/utility.py +822 -0
  223. package/server/services/handlers/whatsapp.py +476 -0
  224. package/server/services/maps.py +289 -0
  225. package/server/services/memory_store.py +103 -0
  226. package/server/services/node_executor.py +375 -0
  227. package/server/services/parameter_resolver.py +218 -0
  228. package/server/services/polyglot_client.py +169 -0
  229. package/server/services/scheduler.py +155 -0
  230. package/server/services/skill_loader.py +417 -0
  231. package/server/services/status_broadcaster.py +826 -0
  232. package/server/services/temporal/__init__.py +23 -0
  233. package/server/services/temporal/activities.py +344 -0
  234. package/server/services/temporal/client.py +76 -0
  235. package/server/services/temporal/executor.py +147 -0
  236. package/server/services/temporal/worker.py +251 -0
  237. package/server/services/temporal/workflow.py +355 -0
  238. package/server/services/temporal/ws_client.py +236 -0
  239. package/server/services/text.py +111 -0
  240. package/server/services/user_auth.py +172 -0
  241. package/server/services/websocket_client.py +29 -0
  242. package/server/services/workflow.py +597 -0
  243. package/server/skills/android-skill/SKILL.md +82 -0
  244. package/server/skills/assistant-personality/SKILL.md +45 -0
  245. package/server/skills/code-skill/SKILL.md +140 -0
  246. package/server/skills/http-skill/SKILL.md +161 -0
  247. package/server/skills/maps-skill/SKILL.md +170 -0
  248. package/server/skills/memory-skill/SKILL.md +154 -0
  249. package/server/skills/scheduler-skill/SKILL.md +84 -0
  250. package/server/skills/whatsapp-skill/SKILL.md +283 -0
  251. package/server/uv.lock +2916 -0
  252. package/server/whatsapp-rpc/.dockerignore +30 -0
  253. package/server/whatsapp-rpc/Dockerfile +44 -0
  254. package/server/whatsapp-rpc/Dockerfile.web +17 -0
  255. package/server/whatsapp-rpc/README.md +139 -0
  256. package/server/whatsapp-rpc/cli.js +95 -0
  257. package/server/whatsapp-rpc/configs/config.yaml +7 -0
  258. package/server/whatsapp-rpc/docker-compose.yml +35 -0
  259. package/server/whatsapp-rpc/docs/API.md +410 -0
  260. package/server/whatsapp-rpc/go.mod +67 -0
  261. package/server/whatsapp-rpc/go.sum +203 -0
  262. package/server/whatsapp-rpc/package.json +30 -0
  263. package/server/whatsapp-rpc/schema.json +1294 -0
  264. package/server/whatsapp-rpc/scripts/clean.cjs +66 -0
  265. package/server/whatsapp-rpc/scripts/cli.js +162 -0
  266. package/server/whatsapp-rpc/src/go/cmd/server/main.go +91 -0
  267. package/server/whatsapp-rpc/src/go/config/config.go +49 -0
  268. package/server/whatsapp-rpc/src/go/rpc/rpc.go +446 -0
  269. package/server/whatsapp-rpc/src/go/rpc/server.go +112 -0
  270. package/server/whatsapp-rpc/src/go/whatsapp/history.go +166 -0
  271. package/server/whatsapp-rpc/src/go/whatsapp/messages.go +390 -0
  272. package/server/whatsapp-rpc/src/go/whatsapp/service.go +2130 -0
  273. package/server/whatsapp-rpc/src/go/whatsapp/types.go +261 -0
  274. package/server/whatsapp-rpc/src/python/pyproject.toml +15 -0
  275. package/server/whatsapp-rpc/src/python/whatsapp_rpc/__init__.py +4 -0
  276. package/server/whatsapp-rpc/src/python/whatsapp_rpc/client.py +427 -0
  277. package/server/whatsapp-rpc/web/app.py +609 -0
  278. package/server/whatsapp-rpc/web/requirements.txt +6 -0
  279. package/server/whatsapp-rpc/web/rpc_client.py +427 -0
  280. package/server/whatsapp-rpc/web/static/openapi.yaml +59 -0
  281. package/server/whatsapp-rpc/web/templates/base.html +150 -0
  282. package/server/whatsapp-rpc/web/templates/contacts.html +240 -0
  283. package/server/whatsapp-rpc/web/templates/dashboard.html +320 -0
  284. package/server/whatsapp-rpc/web/templates/groups.html +328 -0
  285. package/server/whatsapp-rpc/web/templates/messages.html +465 -0
  286. package/server/whatsapp-rpc/web/templates/messaging.html +681 -0
  287. package/server/whatsapp-rpc/web/templates/send.html +259 -0
  288. package/server/whatsapp-rpc/web/templates/settings.html +459 -0
@@ -0,0 +1,140 @@
1
+ // Google Maps API Loader - Singleton pattern to prevent multiple script loads
2
+ // Ensures Google Maps JavaScript API is loaded only once per page
3
+
4
+ interface GoogleMapsLoaderOptions {
5
+ apiKey: string;
6
+ libraries?: string[];
7
+ version?: string;
8
+ }
9
+
10
+ class GoogleMapsLoader {
11
+ private static instance: GoogleMapsLoader;
12
+ private loadPromise: Promise<void> | null = null;
13
+ private isLoaded = false;
14
+ private isLoading = false;
15
+
16
+ private constructor() {}
17
+
18
+ public static getInstance(): GoogleMapsLoader {
19
+ if (!GoogleMapsLoader.instance) {
20
+ GoogleMapsLoader.instance = new GoogleMapsLoader();
21
+ }
22
+ return GoogleMapsLoader.instance;
23
+ }
24
+
25
+ public async loadGoogleMaps(options: GoogleMapsLoaderOptions): Promise<void> {
26
+ // If already loaded, resolve immediately
27
+ if (this.isLoaded) {
28
+ return Promise.resolve();
29
+ }
30
+
31
+ // If currently loading, return the existing promise
32
+ if (this.isLoading && this.loadPromise) {
33
+ return this.loadPromise;
34
+ }
35
+
36
+ // Check if Google Maps is already available (loaded externally)
37
+ if (typeof window !== 'undefined' && window.google?.maps) {
38
+ this.isLoaded = true;
39
+ return Promise.resolve();
40
+ }
41
+
42
+ // Start loading
43
+ this.isLoading = true;
44
+ this.loadPromise = this.createLoadPromise(options);
45
+
46
+ try {
47
+ await this.loadPromise;
48
+ this.isLoaded = true;
49
+ this.isLoading = false;
50
+ } catch (error) {
51
+ this.isLoading = false;
52
+ this.loadPromise = null;
53
+ throw error;
54
+ }
55
+ }
56
+
57
+ private createLoadPromise(options: GoogleMapsLoaderOptions): Promise<void> {
58
+ return new Promise((resolve, reject) => {
59
+ // Check if script already exists
60
+ const existingScript = document.querySelector('script[src*="maps.googleapis.com"]');
61
+ if (existingScript) {
62
+ // Script exists, wait for it to load
63
+ if (window.google?.maps) {
64
+ resolve();
65
+ } else {
66
+ existingScript.addEventListener('load', () => resolve());
67
+ existingScript.addEventListener('error', (error) => reject(error));
68
+ }
69
+ return;
70
+ }
71
+
72
+ // Create new script element
73
+ const script = document.createElement('script');
74
+ script.type = 'text/javascript';
75
+ script.async = true;
76
+ script.defer = true;
77
+
78
+ // Build URL with parameters
79
+ const { apiKey, libraries = ['geometry'], version = 'weekly' } = options;
80
+ const params = new URLSearchParams({
81
+ key: apiKey,
82
+ libraries: libraries.join(','),
83
+ v: version,
84
+ callback: '__googleMapsCallback__'
85
+ });
86
+
87
+ script.src = `https://maps.googleapis.com/maps/api/js?${params.toString()}`;
88
+
89
+ // Set up callback
90
+ (window as any).__googleMapsCallback__ = () => {
91
+ delete (window as any).__googleMapsCallback__;
92
+ resolve();
93
+ };
94
+
95
+ // Handle errors
96
+ script.onerror = (error) => {
97
+ delete (window as any).__googleMapsCallback__;
98
+ reject(new Error(`Failed to load Google Maps API: ${error}`));
99
+ };
100
+
101
+ // Add script to document
102
+ document.head.appendChild(script);
103
+ });
104
+ }
105
+
106
+ public isGoogleMapsLoaded(): boolean {
107
+ return this.isLoaded || (typeof window !== 'undefined' && !!window.google?.maps);
108
+ }
109
+
110
+ public getGoogleMaps(): typeof google.maps | null {
111
+ if (typeof window !== 'undefined' && window.google?.maps) {
112
+ return window.google.maps;
113
+ }
114
+ return null;
115
+ }
116
+ }
117
+
118
+ // Export singleton instance and convenience functions
119
+ export const googleMapsLoader = GoogleMapsLoader.getInstance();
120
+
121
+ export const loadGoogleMaps = (options: GoogleMapsLoaderOptions): Promise<void> => {
122
+ return googleMapsLoader.loadGoogleMaps(options);
123
+ };
124
+
125
+ export const isGoogleMapsLoaded = (): boolean => {
126
+ return googleMapsLoader.isGoogleMapsLoaded();
127
+ };
128
+
129
+ export const getGoogleMaps = (): typeof google.maps | null => {
130
+ return googleMapsLoader.getGoogleMaps();
131
+ };
132
+
133
+ // Type declarations for Google Maps
134
+ declare global {
135
+ interface Window {
136
+ google?: {
137
+ maps: typeof google.maps;
138
+ };
139
+ }
140
+ }
@@ -0,0 +1,85 @@
1
+ import { INodeTypeDescription, INodeProperties } from '../types/INodeProperties';
2
+
3
+ // Location parameter utilities
4
+ export interface LocationParams {
5
+ latParam: INodeProperties | null;
6
+ lngParam: INodeProperties | null;
7
+ }
8
+
9
+ // Find coordinate parameters in node definition
10
+ export const getCoordinateParams = (nodeDefinition: INodeTypeDescription | null): LocationParams => {
11
+ if (!nodeDefinition) return { latParam: null, lngParam: null };
12
+
13
+ const latParam = nodeDefinition.properties?.find((p: any) => {
14
+ const name = p.name.toLowerCase();
15
+ return name.includes('lat') || name === 'latitude';
16
+ });
17
+
18
+ const lngParam = nodeDefinition.properties?.find((p: any) => {
19
+ const name = p.name.toLowerCase();
20
+ return name.includes('lng') || name.includes('lon') || name === 'longitude';
21
+ });
22
+
23
+ return { latParam: latParam || null, lngParam: lngParam || null };
24
+ };
25
+
26
+ // Get current coordinates from parameters
27
+ export const getCurrentCoordinates = (
28
+ parameters: Record<string, any>,
29
+ locationParams: LocationParams
30
+ ) => {
31
+ const { latParam, lngParam } = locationParams;
32
+
33
+ const lat = (latParam && parameters[latParam.name]) || latParam?.default || 40.7128;
34
+ const lng = (lngParam && parameters[lngParam.name]) || lngParam?.default || -74.0060;
35
+
36
+ return { lat, lng };
37
+ };
38
+
39
+ // Get map display parameters
40
+ export const getMapDisplayParams = (parameters: Record<string, any>) => {
41
+ const zoom = parameters.zoom || 13;
42
+ const mapTypeId = parameters.mapTypeId || 'ROADMAP';
43
+
44
+ return { zoom, mapTypeId };
45
+ };
46
+
47
+ // Get Google Maps API key with fallbacks
48
+ export const getGoogleMapsApiKey = (): string | undefined => {
49
+ // Note: For stored API keys, use ApiKeyManagerService.getStoredApiKeyAsync('google_maps')
50
+ // This function now only returns the environment variable fallback
51
+ return (import.meta as any).env?.VITE_GOOGLE_MAPS_API_KEY || undefined;
52
+ };
53
+
54
+ // Create location update handler
55
+ export const createLocationUpdateHandler = (
56
+ locationParams: LocationParams,
57
+ onParameterChange: (paramName: string, value: any) => void
58
+ ) => {
59
+ return (lat: number, lng: number) => {
60
+ const { latParam, lngParam } = locationParams;
61
+
62
+ if (latParam) {
63
+ onParameterChange(latParam.name, lat);
64
+ }
65
+ if (lngParam) {
66
+ onParameterChange(lngParam.name, lng);
67
+ }
68
+ };
69
+ };
70
+
71
+ // Check if a node is location-related
72
+ export const isLocationNode = (nodeDefinition: INodeTypeDescription | null): boolean => {
73
+ if (!nodeDefinition) return false;
74
+
75
+ const isCreateMap = nodeDefinition.name === 'createMap';
76
+ const hasLocationGroup = nodeDefinition.group?.includes('location') ?? false;
77
+ const hasCoordinates = getCoordinateParams(nodeDefinition).latParam !== null;
78
+
79
+ return isCreateMap || hasLocationGroup || hasCoordinates;
80
+ };
81
+
82
+ // Check if node should show maps preview
83
+ export const shouldShowMapsPreview = (nodeDefinition: INodeTypeDescription | null): boolean => {
84
+ return nodeDefinition?.name === 'createMap';
85
+ };
@@ -0,0 +1,31 @@
1
+ // Utility functions for node operations
2
+
3
+ // Generate short node name from nodeType for parameter references
4
+ export const getShortNodeName = (nodeType: string): string => {
5
+ const typeMap: { [key: string]: string } = {
6
+ // AI Chat Models
7
+ 'openaiChatModel': 'openai',
8
+ 'anthropicChatModel': 'claude',
9
+ 'geminiChatModel': 'gemini',
10
+ // AI Agents
11
+ 'aiAgent': 'ai',
12
+ // Location Services
13
+ 'createMap': 'map',
14
+ 'addLocations': 'location',
15
+ 'showNearbyPlaces': 'places'
16
+ };
17
+
18
+ // If we have a specific mapping, use it
19
+ if (typeMap[nodeType]) {
20
+ return typeMap[nodeType];
21
+ }
22
+
23
+ // Otherwise, create a simplified version by removing capitals and common suffixes
24
+ let simplified = nodeType
25
+ .replace(/[A-Z]/g, '') // Remove capital letters
26
+ .replace(/(Get|Set|Stop|Play|Record|Control)$/i, '') // Remove common suffixes
27
+ .toLowerCase();
28
+
29
+ // Return simplified name or fallback to 'node'
30
+ return simplified || 'node';
31
+ };
@@ -0,0 +1,30 @@
1
+ import { Node, Edge } from 'reactflow';
2
+
3
+ export const generateWorkflowId = (): string =>
4
+ `workflow-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
5
+
6
+ export const sanitizeNodesForComparison = (nodes: Node[]): Node[] =>
7
+ nodes.map(n => ({ ...n, selected: undefined, dragging: undefined }));
8
+
9
+ export const sanitizeEdgesForComparison = (edges: Edge[]): Edge[] =>
10
+ edges.map(e => ({ ...e, selected: undefined }));
11
+
12
+ export const serializeDateFields = <T extends { createdAt: Date; lastModified: Date }>(obj: T) => ({
13
+ ...obj,
14
+ createdAt: obj.createdAt.toISOString(),
15
+ lastModified: obj.lastModified.toISOString(),
16
+ });
17
+
18
+ export const deserializeDateFields = <T extends { createdAt: string; lastModified: string }>(obj: T) => ({
19
+ ...obj,
20
+ createdAt: new Date(obj.createdAt),
21
+ lastModified: new Date(obj.lastModified),
22
+ });
23
+
24
+ export const snapToGrid = (position: { x: number; y: number }, gridSize = 20) => ({
25
+ x: Math.round(position.x / gridSize) * gridSize,
26
+ y: Math.round(position.y / gridSize) * gridSize,
27
+ });
28
+
29
+ export const getDefaultNodePosition = (nodeCount: number): { x: number; y: number } =>
30
+ nodeCount === 0 ? { x: 100, y: 200 } : { x: 0, y: 0 };
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Workflow Export/Import Utilities
3
+ * Handles exporting workflows to JSON files and importing from JSON
4
+ */
5
+
6
+ import { WorkflowData } from '../store/useAppStore';
7
+ import { validateWorkflow, serializeWorkflow, deserializeWorkflow } from '../schemas/workflowSchema';
8
+
9
+ /**
10
+ * Export workflow to JSON file
11
+ */
12
+ export function exportWorkflowToFile(workflow: WorkflowData): void {
13
+ const validation = validateWorkflow(workflow);
14
+
15
+ if (!validation.valid) {
16
+ console.error('Workflow validation errors:', validation.errors);
17
+ throw new Error(`Cannot export invalid workflow: ${validation.errors.join(', ')}`);
18
+ }
19
+
20
+ const workflowJSON = {
21
+ ...workflow,
22
+ createdAt: workflow.createdAt.toISOString(),
23
+ lastModified: workflow.lastModified.toISOString(),
24
+ version: '1.0.0'
25
+ };
26
+
27
+ const jsonString = serializeWorkflow(workflowJSON);
28
+ const blob = new Blob([jsonString], { type: 'application/json' });
29
+ const url = URL.createObjectURL(blob);
30
+
31
+ const a = document.createElement('a');
32
+ a.href = url;
33
+ a.download = `${workflow.name || 'workflow'}_${workflow.id}.json`;
34
+ document.body.appendChild(a);
35
+ a.click();
36
+ document.body.removeChild(a);
37
+ URL.revokeObjectURL(url);
38
+ }
39
+
40
+ /**
41
+ * Import workflow from JSON file
42
+ */
43
+ export function importWorkflowFromFile(file: File): Promise<WorkflowData> {
44
+ return new Promise((resolve, reject) => {
45
+ const reader = new FileReader();
46
+
47
+ reader.onload = (event) => {
48
+ try {
49
+ const jsonString = event.target?.result as string;
50
+ const workflow = deserializeWorkflow(jsonString);
51
+
52
+ const validation = validateWorkflow(workflow);
53
+ if (!validation.valid) {
54
+ reject(new Error(`Invalid workflow JSON: ${validation.errors.join(', ')}`));
55
+ return;
56
+ }
57
+
58
+ resolve(workflow);
59
+ } catch (error) {
60
+ reject(error);
61
+ }
62
+ };
63
+
64
+ reader.onerror = () => {
65
+ reject(new Error('Failed to read file'));
66
+ };
67
+
68
+ reader.readAsText(file);
69
+ });
70
+ }
71
+
72
+ /**
73
+ * Export workflow to JSON string
74
+ */
75
+ export function exportWorkflowToJSON(workflow: WorkflowData): string {
76
+ const validation = validateWorkflow(workflow);
77
+
78
+ if (!validation.valid) {
79
+ throw new Error(`Cannot export invalid workflow: ${validation.errors.join(', ')}`);
80
+ }
81
+
82
+ const workflowJSON = {
83
+ ...workflow,
84
+ createdAt: workflow.createdAt.toISOString(),
85
+ lastModified: workflow.lastModified.toISOString(),
86
+ version: '1.0.0'
87
+ };
88
+
89
+ return serializeWorkflow(workflowJSON);
90
+ }
91
+
92
+ /**
93
+ * Import workflow from JSON string
94
+ */
95
+ export function importWorkflowFromJSON(jsonString: string): WorkflowData {
96
+ const workflow = deserializeWorkflow(jsonString);
97
+
98
+ const validation = validateWorkflow(workflow);
99
+ if (!validation.valid) {
100
+ throw new Error(`Invalid workflow JSON: ${validation.errors.join(', ')}`);
101
+ }
102
+
103
+ return workflow;
104
+ }
105
+
106
+ /**
107
+ * Copy workflow to clipboard as JSON
108
+ */
109
+ export async function copyWorkflowToClipboard(workflow: WorkflowData): Promise<void> {
110
+ const jsonString = exportWorkflowToJSON(workflow);
111
+ await navigator.clipboard.writeText(jsonString);
112
+ }
113
+
114
+ /**
115
+ * Paste workflow from clipboard
116
+ */
117
+ export async function pasteWorkflowFromClipboard(): Promise<WorkflowData> {
118
+ const jsonString = await navigator.clipboard.readText();
119
+ return importWorkflowFromJSON(jsonString);
120
+ }
@@ -0,0 +1,12 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ interface ImportMetaEnv {
4
+ readonly VITE_ANDROID_RELAY_URL: string;
5
+ readonly VITE_AUTH_ENABLED: string;
6
+ readonly VITE_CLIENT_PORT: string;
7
+ readonly VITE_PYTHON_BACKEND_URL: string;
8
+ }
9
+
10
+ interface ImportMeta {
11
+ readonly env: ImportMetaEnv;
12
+ }
@@ -0,0 +1,60 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ darkMode: ["class"],
4
+ content: [
5
+ "./index.html",
6
+ "./src/**/*.{js,ts,jsx,tsx}",
7
+ ],
8
+ theme: {
9
+ container: {
10
+ center: true,
11
+ padding: "2rem",
12
+ screens: {
13
+ "2xl": "1400px",
14
+ },
15
+ },
16
+ extend: {
17
+ colors: {
18
+ border: "hsl(var(--border))",
19
+ input: "hsl(var(--input))",
20
+ ring: "hsl(var(--ring))",
21
+ background: "hsl(var(--background))",
22
+ foreground: "hsl(var(--foreground))",
23
+ primary: {
24
+ DEFAULT: "hsl(var(--primary))",
25
+ foreground: "hsl(var(--primary-foreground))",
26
+ },
27
+ secondary: {
28
+ DEFAULT: "hsl(var(--secondary))",
29
+ foreground: "hsl(var(--secondary-foreground))",
30
+ },
31
+ destructive: {
32
+ DEFAULT: "hsl(var(--destructive))",
33
+ foreground: "hsl(var(--destructive-foreground))",
34
+ },
35
+ muted: {
36
+ DEFAULT: "hsl(var(--muted))",
37
+ foreground: "hsl(var(--muted-foreground))",
38
+ },
39
+ accent: {
40
+ DEFAULT: "hsl(var(--accent))",
41
+ foreground: "hsl(var(--accent-foreground))",
42
+ },
43
+ popover: {
44
+ DEFAULT: "hsl(var(--popover))",
45
+ foreground: "hsl(var(--popover-foreground))",
46
+ },
47
+ card: {
48
+ DEFAULT: "hsl(var(--card))",
49
+ foreground: "hsl(var(--card-foreground))",
50
+ },
51
+ },
52
+ borderRadius: {
53
+ lg: "var(--radius)",
54
+ md: "calc(var(--radius) - 2px)",
55
+ sm: "calc(var(--radius) - 4px)",
56
+ },
57
+ },
58
+ },
59
+ plugins: [],
60
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true,
15
+ "jsx": "react-jsx",
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true
22
+ },
23
+ "include": ["src"],
24
+ "references": [{ "path": "./tsconfig.node.json" }]
25
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "skipLibCheck": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "allowSyntheticDefaultImports": true,
8
+ "strict": true
9
+ },
10
+ "include": ["vite.config.js"]
11
+ }
@@ -0,0 +1,35 @@
1
+ import { defineConfig, loadEnv } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import { resolve } from 'path'
4
+
5
+ // https://vite.dev/config/
6
+ export default defineConfig(({ mode }) => {
7
+ // Load env from parent directory (root .env) for local development
8
+ const fileEnv = loadEnv(mode, resolve(process.cwd(), '..'), '')
9
+
10
+ // In Docker, env vars are set via ENV in Dockerfile, accessible via process.env
11
+ // Priority: process.env (Docker) > fileEnv (local .env) > defaults
12
+ const getEnv = (key, defaultValue = '') => {
13
+ return process.env[key] || fileEnv[key] || defaultValue
14
+ }
15
+
16
+ return {
17
+ plugins: [react()],
18
+ // Expose VITE_ prefixed env vars to client code via import.meta.env
19
+ define: {
20
+ 'import.meta.env.VITE_AUTH_ENABLED': JSON.stringify(getEnv('VITE_AUTH_ENABLED', 'true')),
21
+ 'import.meta.env.VITE_PYTHON_SERVICE_URL': JSON.stringify(getEnv('VITE_PYTHON_SERVICE_URL', '')),
22
+ 'import.meta.env.VITE_WHATSAPP_SERVICE_URL': JSON.stringify(getEnv('VITE_WHATSAPP_SERVICE_URL', '')),
23
+ 'import.meta.env.VITE_ANDROID_RELAY_URL': JSON.stringify(getEnv('VITE_ANDROID_RELAY_URL', '')),
24
+ },
25
+ server: {
26
+ port: parseInt(getEnv('VITE_CLIENT_PORT', '3000')),
27
+ strictPort: false,
28
+ host: true
29
+ },
30
+ build: {
31
+ // antd + reactflow are large libraries - this is expected
32
+ chunkSizeWarningLimit: 1500,
33
+ },
34
+ }
35
+ })
@@ -0,0 +1,107 @@
1
+ services:
2
+ # Redis Cache (production performance)
3
+ redis:
4
+ image: redis:7-alpine
5
+ container_name: machina-redis
6
+ volumes:
7
+ - redis-data:/data
8
+ networks:
9
+ - app-network
10
+ restart: always
11
+ healthcheck:
12
+ test: ["CMD", "redis-cli", "ping"]
13
+ interval: 10s
14
+ timeout: 5s
15
+ retries: 3
16
+ command: redis-server --appendonly yes
17
+
18
+ # Python FastAPI Backend
19
+ backend:
20
+ build:
21
+ context: ./server
22
+ dockerfile: Dockerfile
23
+ container_name: machina-backend
24
+ ports:
25
+ - "${PYTHON_BACKEND_PORT:-3010}:${PYTHON_BACKEND_PORT:-3010}"
26
+ volumes:
27
+ - backend-data:/app/data
28
+ networks:
29
+ - app-network
30
+ restart: always
31
+ healthcheck:
32
+ test: ["CMD", "curl", "-f", "http://localhost:${PYTHON_BACKEND_PORT:-3010}/health"]
33
+ interval: 30s
34
+ timeout: 10s
35
+ retries: 3
36
+ start_period: 30s
37
+ env_file:
38
+ - path: ./.env
39
+ required: false
40
+ environment:
41
+ # Production overrides
42
+ - PORT=${PYTHON_BACKEND_PORT:-3010}
43
+ - ENV=production
44
+ - REDIS_ENABLED=true
45
+ - REDIS_URL=redis://redis:6379
46
+ - WHATSAPP_RPC_URL=ws://whatsapp:${WHATSAPP_RPC_PORT:-9400}/ws/rpc
47
+ - TZ=UTC
48
+ depends_on:
49
+ redis:
50
+ condition: service_healthy
51
+ whatsapp:
52
+ condition: service_healthy
53
+
54
+ # React Frontend (Production - Nginx)
55
+ frontend:
56
+ build:
57
+ context: ./client
58
+ dockerfile: Dockerfile
59
+ target: production
60
+ args:
61
+ # Pass env vars to frontend build (baked into static JS at build time)
62
+ VITE_AUTH_ENABLED: ${VITE_AUTH_ENABLED:-true}
63
+ VITE_PYTHON_SERVICE_URL: ${VITE_PYTHON_SERVICE_URL:-}
64
+ VITE_WHATSAPP_SERVICE_URL: ${VITE_WHATSAPP_SERVICE_URL:-}
65
+ VITE_ANDROID_RELAY_URL: ${VITE_ANDROID_RELAY_URL:-}
66
+ container_name: machina-frontend
67
+ ports:
68
+ - "${VITE_CLIENT_PORT:-3000}:80"
69
+ networks:
70
+ - app-network
71
+ restart: always
72
+ depends_on:
73
+ - backend
74
+
75
+ # WhatsApp RPC Service (Go API only)
76
+ whatsapp:
77
+ build:
78
+ context: ./server/whatsapp-rpc
79
+ dockerfile: Dockerfile
80
+ container_name: machina-whatsapp
81
+ volumes:
82
+ - whatsapp-data:/app/data
83
+ networks:
84
+ - app-network
85
+ restart: always
86
+ # Privileged mode for proper SQLite WAL mmap support
87
+ privileged: true
88
+ healthcheck:
89
+ test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9400/health"]
90
+ interval: 30s
91
+ timeout: 10s
92
+ retries: 3
93
+ start_period: 15s
94
+ environment:
95
+ - TZ=UTC
96
+
97
+ networks:
98
+ app-network:
99
+ driver: bridge
100
+
101
+ volumes:
102
+ redis-data:
103
+ driver: local
104
+ backend-data:
105
+ driver: local
106
+ whatsapp-data:
107
+ driver: local