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,158 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Cross-platform build script for MachinaOS.
4
+ * Works on: Windows, macOS, Linux, WSL, Git Bash
5
+ */
6
+ import { execSync } from 'child_process';
7
+ import { existsSync, copyFileSync } from 'fs';
8
+ import { resolve, dirname } from 'path';
9
+ import { fileURLToPath } from 'url';
10
+
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const ROOT = resolve(__dirname, '..');
13
+
14
+ // Ensure Python UTF-8 encoding
15
+ process.env.PYTHONUTF8 = '1';
16
+
17
+ function run(cmd, cwd = ROOT) {
18
+ execSync(cmd, { cwd, stdio: 'inherit', shell: true });
19
+ }
20
+
21
+ function check(cmd) {
22
+ try {
23
+ execSync(cmd, { stdio: 'pipe', shell: true });
24
+ return true;
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+
30
+ function getVersion(cmd) {
31
+ try {
32
+ return execSync(cmd, { encoding: 'utf-8', shell: true }).trim();
33
+ } catch {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ function log(step, msg) {
39
+ console.log(`[${step}] ${msg}`);
40
+ }
41
+
42
+ function npmInstall(cwd = ROOT) {
43
+ // Try npm ci first (fast), fall back to npm install if lock file out of sync
44
+ try {
45
+ execSync('npm ci', { cwd, stdio: 'pipe', shell: true });
46
+ } catch {
47
+ execSync('npm install', { cwd, stdio: 'inherit', shell: true });
48
+ }
49
+ }
50
+
51
+ // ============================================================================
52
+ // Check Dependencies
53
+ // ============================================================================
54
+
55
+ console.log('Checking dependencies...\n');
56
+
57
+ const missing = [];
58
+
59
+ // Node.js
60
+ const nodeVersion = getVersion('node --version');
61
+ if (nodeVersion) {
62
+ console.log(` Node.js: ${nodeVersion}`);
63
+ } else {
64
+ missing.push('Node.js - https://nodejs.org/');
65
+ }
66
+
67
+ // npm
68
+ const npmVersion = getVersion('npm --version');
69
+ if (npmVersion) {
70
+ console.log(` npm: ${npmVersion}`);
71
+ } else {
72
+ missing.push('npm - comes with Node.js');
73
+ }
74
+
75
+ // Python
76
+ let pyCmd = null;
77
+ if (check('python --version')) {
78
+ pyCmd = 'python';
79
+ } else if (check('python3 --version')) {
80
+ pyCmd = 'python3';
81
+ }
82
+ if (pyCmd) {
83
+ const pyVersion = getVersion(`${pyCmd} --version`);
84
+ console.log(` ${pyVersion}`);
85
+ } else {
86
+ missing.push('Python 3.11+ - https://python.org/');
87
+ }
88
+
89
+ // uv (Python package manager)
90
+ const uvVersion = getVersion('uv --version');
91
+ if (uvVersion) {
92
+ console.log(` uv: ${uvVersion}`);
93
+ } else {
94
+ missing.push('uv - https://docs.astral.sh/uv/getting-started/installation/');
95
+ }
96
+
97
+ // Go (required for WhatsApp server)
98
+ const goVersionFull = getVersion('go version');
99
+ if (goVersionFull) {
100
+ const goVersion = goVersionFull.match(/go\d+\.\d+(\.\d+)?/)?.[0] || 'go';
101
+ console.log(` Go: ${goVersion}`);
102
+ } else {
103
+ missing.push('Go - https://go.dev/dl/');
104
+ }
105
+
106
+ if (missing.length > 0) {
107
+ console.error('\nMissing required dependencies:\n');
108
+ for (const dep of missing) {
109
+ console.error(` - ${dep}`);
110
+ }
111
+ console.error('\nPlease install the missing dependencies and try again.');
112
+ process.exit(1);
113
+ }
114
+
115
+ console.log('\nAll dependencies found.\n');
116
+
117
+ // ============================================================================
118
+ // Build
119
+ // ============================================================================
120
+
121
+ try {
122
+ // Step 0: Create .env if not exists
123
+ const envPath = resolve(ROOT, '.env');
124
+ const templatePath = resolve(ROOT, '.env.template');
125
+ if (!existsSync(envPath) && existsSync(templatePath)) {
126
+ copyFileSync(templatePath, envPath);
127
+ log('0/5', 'Created .env from template');
128
+ }
129
+
130
+ // Step 1: Install root dependencies
131
+ log('1/5', 'Installing root dependencies...');
132
+ npmInstall(ROOT);
133
+
134
+ // Step 2: Build client
135
+ log('2/5', 'Building client...');
136
+ run('npm run build', resolve(ROOT, 'client'));
137
+
138
+ // Step 3: Install Python dependencies
139
+ log('3/5', 'Installing Python dependencies...');
140
+ const serverDir = resolve(ROOT, 'server');
141
+ run('uv venv', serverDir);
142
+ run('uv sync', serverDir);
143
+
144
+ // Step 4: Install WhatsApp dependencies
145
+ log('4/5', 'Installing WhatsApp dependencies...');
146
+ const whatsappDir = resolve(ROOT, 'server/whatsapp-rpc');
147
+ npmInstall(whatsappDir);
148
+
149
+ // Step 5: Build WhatsApp server (Go binary)
150
+ log('5/5', 'Building WhatsApp server...');
151
+ run('npm run build', whatsappDir);
152
+
153
+ console.log('\nBuild complete.');
154
+
155
+ } catch (err) {
156
+ console.error('\nBuild failed:', err.message);
157
+ process.exit(1);
158
+ }
@@ -0,0 +1,33 @@
1
+ # Check port status - shows real vs orphaned TCP entries
2
+ param(
3
+ [int[]]$Ports = @(3000, 3010, 9400)
4
+ )
5
+
6
+ Write-Host "Checking port status...`n"
7
+
8
+ foreach ($port in $Ports) {
9
+ Write-Host "=== Port $port ===" -ForegroundColor Cyan
10
+ $connections = Get-NetTCPConnection -LocalPort $port -ErrorAction SilentlyContinue
11
+
12
+ if (-not $connections) {
13
+ Write-Host " No connections" -ForegroundColor Green
14
+ continue
15
+ }
16
+
17
+ $grouped = $connections | Group-Object State
18
+ foreach ($group in $grouped) {
19
+ Write-Host " $($group.Name): $($group.Count) connection(s)"
20
+ }
21
+
22
+ $processIds = $connections | Select-Object -ExpandProperty OwningProcess -Unique | Where-Object { $_ -ne 0 }
23
+ foreach ($procId in $processIds) {
24
+ $proc = Get-Process -Id $procId -ErrorAction SilentlyContinue
25
+ if ($proc) {
26
+ Write-Host " REAL: PID $procId ($($proc.ProcessName))" -ForegroundColor Yellow
27
+ } else {
28
+ Write-Host " ORPHAN: PID $procId (process dead, TCP entry will timeout)" -ForegroundColor DarkGray
29
+ }
30
+ }
31
+ }
32
+
33
+ Write-Host "`nNote: Orphaned entries auto-clear in 30-120 seconds. They don't block new processes."
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Cross-platform clean script using Node.js native APIs.
4
+ * Works on: Windows, macOS, Linux, WSL, Git Bash
5
+ */
6
+ import { rmSync, existsSync } from 'fs';
7
+ import { resolve, dirname } from 'path';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+ const ROOT = resolve(__dirname, '..');
12
+
13
+ const targets = [
14
+ 'node_modules',
15
+ 'client/node_modules',
16
+ 'client/dist',
17
+ 'client/.vite',
18
+ 'server/whatsapp-rpc/node_modules',
19
+ 'server/whatsapp-rpc/bin',
20
+ 'server/whatsapp-rpc/data',
21
+ 'server/data',
22
+ 'server/.venv',
23
+ ];
24
+
25
+ console.log('Cleaning...');
26
+
27
+ for (const target of targets) {
28
+ const fullPath = resolve(ROOT, target);
29
+ if (existsSync(fullPath)) {
30
+ console.log(` Removing: ${target}`);
31
+ try {
32
+ // Node.js native rmSync - works cross-platform
33
+ rmSync(fullPath, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
34
+ } catch (err) {
35
+ console.log(` Warning: Could not remove ${target}: ${err.message}`);
36
+ }
37
+ }
38
+ }
39
+
40
+ console.log('Done.');
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Docker compose wrapper that auto-enables Redis profile based on REDIS_ENABLED in .env
4
+ * Usage: node scripts/docker.js <command> [args...]
5
+ * Commands: up, down, build, logs, restart
6
+ */
7
+
8
+ import { spawn } from 'child_process';
9
+ import { readFileSync, existsSync, copyFileSync } from 'fs';
10
+ import { fileURLToPath } from 'url';
11
+ import { dirname, resolve } from 'path';
12
+
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const ROOT = resolve(__dirname, '..');
15
+
16
+ // Create .env from template if it doesn't exist
17
+ function ensureEnvFile() {
18
+ const envPath = resolve(ROOT, '.env');
19
+ if (existsSync(envPath)) return true;
20
+
21
+ const templatePath = resolve(ROOT, '.env.template');
22
+ if (existsSync(templatePath)) {
23
+ console.log('[Docker] Creating .env from .env.template');
24
+ copyFileSync(templatePath, envPath);
25
+ return true;
26
+ }
27
+
28
+ console.warn('[Docker] Warning: No .env or .env.template found');
29
+ return false;
30
+ }
31
+
32
+ // Read .env file and check REDIS_ENABLED
33
+ function isRedisEnabled() {
34
+ const envPath = resolve(ROOT, '.env');
35
+ if (!existsSync(envPath)) return false;
36
+
37
+ const content = readFileSync(envPath, 'utf8');
38
+ const match = content.match(/^REDIS_ENABLED\s*=\s*(.+)$/m);
39
+ if (!match) return false;
40
+
41
+ const value = match[1].trim().toLowerCase();
42
+ return value === 'true' || value === '1' || value === 'yes';
43
+ }
44
+
45
+ // Get command and args
46
+ const [,, command, ...args] = process.argv;
47
+
48
+ if (!command) {
49
+ console.error('Usage: node scripts/docker.js <command> [args...]');
50
+ console.error('Commands: up, down, build, logs, restart');
51
+ process.exit(1);
52
+ }
53
+
54
+ // Ensure .env exists (create from template if needed)
55
+ ensureEnvFile();
56
+
57
+ // Build docker-compose command
58
+ const composeArgs = [];
59
+
60
+ // Add Redis profile if enabled in .env
61
+ if (isRedisEnabled()) {
62
+ composeArgs.push('--profile', 'redis');
63
+ console.log('[Docker] Redis profile enabled (REDIS_ENABLED=true in .env)');
64
+ } else {
65
+ console.log('[Docker] Redis profile disabled (REDIS_ENABLED=false in .env)');
66
+ }
67
+
68
+ // Add command
69
+ composeArgs.push(command);
70
+
71
+ // Add command-specific defaults
72
+ if (command === 'up') {
73
+ composeArgs.push('-d'); // detached by default
74
+ }
75
+ if (command === 'logs') {
76
+ composeArgs.push('-f'); // follow by default
77
+ }
78
+
79
+ // Add any additional args
80
+ composeArgs.push(...args);
81
+
82
+ console.log(`[Docker] Running: docker-compose ${composeArgs.join(' ')}`);
83
+
84
+ // Run docker-compose
85
+ const proc = spawn('docker-compose', composeArgs, {
86
+ cwd: ROOT,
87
+ stdio: 'inherit',
88
+ shell: true
89
+ });
90
+
91
+ proc.on('exit', (code) => {
92
+ process.exit(code || 0);
93
+ });
@@ -0,0 +1,154 @@
1
+ # Kill all processes using the specified ports (Windows)
2
+ # Usage: .\kill-port.ps1 [-Ports] 3000,3010,9400
3
+ # If no ports specified, uses default MachinaOs ports: 3000, 3010, 9400
4
+
5
+ param(
6
+ [int[]]$Ports = @(3000, 3010, 9400)
7
+ )
8
+
9
+ $ErrorActionPreference = 'SilentlyContinue'
10
+
11
+ function Get-ProcessTree {
12
+ param([int]$ParentId)
13
+
14
+ $children = @()
15
+ $childProcesses = Get-CimInstance Win32_Process -Filter "ParentProcessId=$ParentId" -ErrorAction SilentlyContinue
16
+
17
+ foreach ($child in $childProcesses) {
18
+ if ($child.ProcessId -and $child.ProcessId -ne 0) {
19
+ $children += $child.ProcessId
20
+ # Recursively get grandchildren
21
+ $children += Get-ProcessTree -ParentId $child.ProcessId
22
+ }
23
+ }
24
+
25
+ return $children
26
+ }
27
+
28
+ function Get-PortProcesses {
29
+ param([int]$Port)
30
+
31
+ $pids = @()
32
+
33
+ # Method 1: Get-NetTCPConnection (preferred)
34
+ $connections = Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue |
35
+ Where-Object { $_.State -eq 'Listen' -or $_.State -eq 'Established' }
36
+
37
+ if ($connections) {
38
+ $pids += $connections | Select-Object -ExpandProperty OwningProcess -Unique | Where-Object { $_ -ne 0 }
39
+ }
40
+
41
+ # Method 2: netstat fallback
42
+ if ($pids.Count -eq 0) {
43
+ $netstatOutput = netstat -ano 2>$null | Select-String ":$Port\s" | Select-String "LISTENING|ESTABLISHED"
44
+ foreach ($line in $netstatOutput) {
45
+ if ($line -match '\s+(\d+)\s*$') {
46
+ $pid = [int]$Matches[1]
47
+ if ($pid -ne 0 -and $pids -notcontains $pid) {
48
+ $pids += $pid
49
+ }
50
+ }
51
+ }
52
+ }
53
+
54
+ return $pids | Select-Object -Unique
55
+ }
56
+
57
+ function Stop-ProcessSafely {
58
+ param([int]$ProcessId)
59
+
60
+ $proc = Get-Process -Id $ProcessId -ErrorAction SilentlyContinue
61
+ if (-not $proc) {
62
+ return $false
63
+ }
64
+
65
+ $procName = $proc.ProcessName
66
+
67
+ # Try graceful stop first
68
+ Stop-Process -Id $ProcessId -ErrorAction SilentlyContinue
69
+ Start-Sleep -Milliseconds 200
70
+
71
+ # Check if still running
72
+ $proc = Get-Process -Id $ProcessId -ErrorAction SilentlyContinue
73
+ if ($proc) {
74
+ # Force kill
75
+ Stop-Process -Id $ProcessId -Force -ErrorAction SilentlyContinue
76
+ Start-Sleep -Milliseconds 200
77
+ }
78
+
79
+ # Verify killed
80
+ $proc = Get-Process -Id $ProcessId -ErrorAction SilentlyContinue
81
+ return (-not $proc)
82
+ }
83
+
84
+ Write-Host "Stopping MachinaOs services..." -ForegroundColor Cyan
85
+ Write-Host "Platform: Windows"
86
+ Write-Host "Ports: $($Ports -join ', ')`n"
87
+
88
+ $allStopped = $true
89
+
90
+ foreach ($port in $Ports) {
91
+ $portPids = Get-PortProcesses -Port $port
92
+
93
+ if ($portPids.Count -eq 0) {
94
+ Write-Host "[OK] Port $port`: Free" -ForegroundColor Green
95
+ continue
96
+ }
97
+
98
+ # Collect all PIDs including child processes
99
+ $allPids = @()
100
+ foreach ($pid in $portPids) {
101
+ $allPids += $pid
102
+ $children = Get-ProcessTree -ParentId $pid
103
+ $allPids += $children
104
+ }
105
+ $allPids = $allPids | Select-Object -Unique | Where-Object { $_ -ne 0 }
106
+
107
+ $killedPids = @()
108
+ $failedPids = @()
109
+
110
+ # Kill all processes (children first, then parents)
111
+ $sortedPids = $allPids | Sort-Object -Descending
112
+
113
+ foreach ($pid in $sortedPids) {
114
+ $proc = Get-Process -Id $pid -ErrorAction SilentlyContinue
115
+ if ($proc) {
116
+ $procName = $proc.ProcessName
117
+ $killed = Stop-ProcessSafely -ProcessId $pid
118
+ if ($killed) {
119
+ $killedPids += "$pid ($procName)"
120
+ } else {
121
+ $failedPids += "$pid ($procName)"
122
+ }
123
+ }
124
+ }
125
+
126
+ # Verify port is free
127
+ Start-Sleep -Milliseconds 500
128
+ $remainingPids = Get-PortProcesses -Port $port
129
+
130
+ if ($remainingPids.Count -eq 0) {
131
+ if ($killedPids.Count -gt 0) {
132
+ Write-Host "[OK] Port $port`: Killed $($killedPids.Count) process(es)" -ForegroundColor Green
133
+ Write-Host " PIDs: $($killedPids -join ', ')" -ForegroundColor DarkGray
134
+ } else {
135
+ Write-Host "[OK] Port $port`: Free" -ForegroundColor Green
136
+ }
137
+ } else {
138
+ Write-Host "[!!] Port $port`: Warning - still in use" -ForegroundColor Yellow
139
+ if ($killedPids.Count -gt 0) {
140
+ Write-Host " Killed: $($killedPids -join ', ')" -ForegroundColor DarkGray
141
+ }
142
+ Write-Host " Still running: $($remainingPids -join ', ')" -ForegroundColor Red
143
+ $allStopped = $false
144
+ }
145
+ }
146
+
147
+ Write-Host ""
148
+ if ($allStopped) {
149
+ Write-Host "All services stopped successfully." -ForegroundColor Green
150
+ } else {
151
+ Write-Host "Warning: Some ports may still be in use." -ForegroundColor Yellow
152
+ Write-Host "Try running as Administrator or manually kill the processes." -ForegroundColor Yellow
153
+ exit 1
154
+ }
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Cross-platform start script for MachinaOS services.
4
+ * Works on: Windows, macOS, Linux, WSL, Git Bash
5
+ */
6
+ import { execSync, spawn } from 'child_process';
7
+ import { readFileSync, existsSync, copyFileSync } from 'fs';
8
+ import { resolve, dirname } from 'path';
9
+ import { fileURLToPath } from 'url';
10
+
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const ROOT = resolve(__dirname, '..');
13
+ const START_TIME = Date.now();
14
+
15
+ // ============================================================================
16
+ // Platform Detection
17
+ // ============================================================================
18
+ const isWindows = process.platform === 'win32';
19
+ const isGitBash = isWindows && (process.env.MSYSTEM || process.env.SHELL?.includes('bash'));
20
+ const isMac = process.platform === 'darwin';
21
+ const useUnixCommands = !isWindows || isGitBash;
22
+
23
+ function getPlatformName() {
24
+ if (isGitBash) return 'Git Bash';
25
+ if (isWindows) return 'Windows';
26
+ if (isMac) return 'macOS';
27
+ return 'Linux';
28
+ }
29
+
30
+ // ============================================================================
31
+ // Utilities
32
+ // ============================================================================
33
+
34
+ const elapsed = () => `${((Date.now() - START_TIME) / 1000).toFixed(2)}s`;
35
+ const log = (msg) => console.log(`[${elapsed()}] ${msg}`);
36
+
37
+ function exec(cmd, options = {}) {
38
+ try {
39
+ return execSync(cmd, {
40
+ encoding: 'utf-8',
41
+ stdio: ['pipe', 'pipe', 'pipe'],
42
+ timeout: options.timeout || 10000,
43
+ cwd: ROOT,
44
+ ...options
45
+ }).trim();
46
+ } catch {
47
+ return '';
48
+ }
49
+ }
50
+
51
+ function sleep(ms) {
52
+ try {
53
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
54
+ } catch {
55
+ const end = Date.now() + ms;
56
+ while (Date.now() < end) { /* spin */ }
57
+ }
58
+ }
59
+
60
+ function loadConfig() {
61
+ const envPath = existsSync(resolve(ROOT, '.env'))
62
+ ? resolve(ROOT, '.env')
63
+ : resolve(ROOT, '.env.template');
64
+
65
+ const env = {};
66
+ if (existsSync(envPath)) {
67
+ for (const line of readFileSync(envPath, 'utf-8').split('\n')) {
68
+ const match = line.match(/^([^#=]+)=(.*)$/);
69
+ if (match) {
70
+ env[match[1].trim()] = match[2].trim().replace(/^["']|["']$/g, '');
71
+ }
72
+ }
73
+ }
74
+
75
+ return {
76
+ ports: [
77
+ parseInt(env.VITE_CLIENT_PORT) || 3000,
78
+ parseInt(env.PYTHON_BACKEND_PORT) || 3010,
79
+ parseInt(env.WHATSAPP_RPC_PORT) || 9400
80
+ ],
81
+ temporalEnabled: env.TEMPORAL_ENABLED?.toLowerCase() === 'true'
82
+ };
83
+ }
84
+
85
+ // ============================================================================
86
+ // Port Management
87
+ // ============================================================================
88
+
89
+ function getPidsOnPort(port) {
90
+ const pids = new Set();
91
+
92
+ if (useUnixCommands) {
93
+ const output = exec(`lsof -ti:${port} -sTCP:LISTEN 2>/dev/null`);
94
+ for (const pid of output.split('\n')) {
95
+ if (pid.trim() && /^\d+$/.test(pid.trim())) {
96
+ pids.add(pid.trim());
97
+ }
98
+ }
99
+ if (pids.size === 0 && !isMac && !isGitBash) {
100
+ const ssOutput = exec(`ss -tlnp 2>/dev/null | grep :${port}`);
101
+ for (const match of ssOutput.matchAll(/pid=(\d+)/g)) {
102
+ pids.add(match[1]);
103
+ }
104
+ }
105
+ } else {
106
+ const output = exec(`netstat -ano | findstr :${port} | findstr LISTENING`);
107
+ for (const line of output.split('\n')) {
108
+ const parts = line.trim().split(/\s+/);
109
+ const pid = parts[parts.length - 1];
110
+ if (pid && /^\d+$/.test(pid) && pid !== '0') {
111
+ pids.add(pid);
112
+ }
113
+ }
114
+ }
115
+
116
+ return Array.from(pids);
117
+ }
118
+
119
+ function killPid(pid) {
120
+ if (useUnixCommands) {
121
+ exec(`kill -15 ${pid} 2>/dev/null`);
122
+ sleep(100);
123
+ exec(`kill -9 ${pid} 2>/dev/null`);
124
+ } else {
125
+ exec(`taskkill /PID ${pid} /F 2>nul`);
126
+ }
127
+ }
128
+
129
+ function freePort(port) {
130
+ const pids = getPidsOnPort(port);
131
+ if (pids.length === 0) return true;
132
+
133
+ for (const pid of pids) {
134
+ killPid(pid);
135
+ }
136
+ sleep(500);
137
+
138
+ return getPidsOnPort(port).length === 0;
139
+ }
140
+
141
+ // ============================================================================
142
+ // Main
143
+ // ============================================================================
144
+
145
+ const config = loadConfig();
146
+
147
+ // Ensure Python UTF-8 encoding
148
+ process.env.PYTHONUTF8 = '1';
149
+
150
+ console.log('\n=== MachinaOS Starting ===\n');
151
+ log(`Platform: ${getPlatformName()}`);
152
+ log(`Ports: ${config.ports.join(', ')}`);
153
+ log(`Temporal: ${config.temporalEnabled ? 'enabled' : 'disabled'}`);
154
+
155
+ // Create .env if not exists
156
+ const envPath = resolve(ROOT, '.env');
157
+ const templatePath = resolve(ROOT, '.env.template');
158
+ if (!existsSync(envPath) && existsSync(templatePath)) {
159
+ copyFileSync(templatePath, envPath);
160
+ log('Created .env from template');
161
+ }
162
+
163
+ // Free ports
164
+ log('Freeing ports...');
165
+ let allFree = true;
166
+ for (const port of config.ports) {
167
+ const pids = getPidsOnPort(port);
168
+ if (pids.length > 0) {
169
+ const freed = freePort(port);
170
+ if (freed) {
171
+ log(` Port ${port}: Freed (killed PIDs: ${pids.join(', ')})`);
172
+ } else {
173
+ log(` Port ${port}: Warning - could not free`);
174
+ allFree = false;
175
+ }
176
+ } else {
177
+ log(` Port ${port}: Already free`);
178
+ }
179
+ }
180
+
181
+ if (!allFree) {
182
+ log('Warning: Some ports could not be freed. Services may fail to start.');
183
+ }
184
+
185
+ // Start dev server
186
+ log('Starting services...');
187
+ log('Press Ctrl+C to stop (use npm run stop to kill all services)\n');
188
+
189
+ const devCommand = config.temporalEnabled ? 'dev:temporal' : 'dev';
190
+
191
+ // Use spawn with shell:true for cross-platform compatibility
192
+ const proc = spawn('npm', ['run', devCommand], {
193
+ cwd: ROOT,
194
+ stdio: 'inherit',
195
+ shell: true,
196
+ env: { ...process.env, FORCE_COLOR: '1' }
197
+ });
198
+
199
+ // Handle Ctrl+C gracefully
200
+ process.on('SIGINT', () => {
201
+ proc.kill('SIGINT');
202
+ });
203
+ process.on('SIGTERM', () => {
204
+ proc.kill('SIGTERM');
205
+ });
206
+
207
+ proc.on('close', (code) => {
208
+ console.log('\nDev server stopped.');
209
+ process.exit(code || 0);
210
+ });