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,66 @@
1
+ #!/usr/bin/env node
2
+ // Standalone clean script - no npm dependencies required
3
+ const { existsSync, unlinkSync, readdirSync, rmSync } = require('fs');
4
+ const { join } = require('path');
5
+ const { execSync } = require('child_process');
6
+
7
+ const ROOT = join(__dirname, '..');
8
+ const BIN = process.platform === 'win32' ? 'whatsapp-rpc-server.exe' : 'whatsapp-rpc-server';
9
+ const BIN_DIR = join(ROOT, 'bin');
10
+
11
+ const log = (msg, color) => {
12
+ const colors = { green: '\x1b[32m', blue: '\x1b[34m', yellow: '\x1b[33m', reset: '\x1b[0m' };
13
+ console.log(`${colors[color] || ''}${msg}${colors.reset}`);
14
+ };
15
+
16
+ // Kill process on port
17
+ const killPort = (port, name) => {
18
+ try {
19
+ if (process.platform === 'win32') {
20
+ execSync(`for /f "tokens=5" %a in ('netstat -aon ^| findstr :${port} ^| findstr LISTENING') do taskkill /F /PID %a`, { stdio: 'ignore', shell: 'cmd.exe' });
21
+ } else {
22
+ execSync(`lsof -ti:${port} | xargs kill -9 2>/dev/null || true`, { stdio: 'ignore' });
23
+ }
24
+ log(`${name} stopped`, 'green');
25
+ } catch { log(`${name} not running`, 'yellow'); }
26
+ };
27
+
28
+ log('Stopping all processes...', 'blue');
29
+ killPort(9400, 'API');
30
+ killPort(5000, 'Web');
31
+
32
+ // Remove binary
33
+ const bin = join(BIN_DIR, BIN);
34
+ if (existsSync(bin)) { unlinkSync(bin); log(`Removed ${BIN}`, 'green'); }
35
+
36
+ // Remove bin directory if empty
37
+ if (existsSync(BIN_DIR) && readdirSync(BIN_DIR).length === 0) {
38
+ rmSync(BIN_DIR, { recursive: true }); log('Removed bin/', 'green');
39
+ }
40
+
41
+ // Remove entire data directory (database, QR codes, etc.)
42
+ const dataDir = join(ROOT, 'data');
43
+ if (existsSync(dataDir)) {
44
+ rmSync(dataDir, { recursive: true });
45
+ log('Removed data/', 'green');
46
+ }
47
+
48
+ // Remove any .db files in project root (legacy locations)
49
+ readdirSync(ROOT).filter(f => f.endsWith('.db') || f.endsWith('.db-wal') || f.endsWith('.db-shm')).forEach(f => {
50
+ unlinkSync(join(ROOT, f));
51
+ log(`Removed ${f}`, 'green');
52
+ });
53
+
54
+ // Remove node_modules
55
+ const nodeModules = join(ROOT, 'node_modules');
56
+ if (existsSync(nodeModules)) { rmSync(nodeModules, { recursive: true }); log('Removed node_modules/', 'green'); }
57
+
58
+ // Remove Python cache
59
+ const pycache = join(ROOT, 'web', '__pycache__');
60
+ if (existsSync(pycache)) { rmSync(pycache, { recursive: true }); log('Removed web/__pycache__/', 'green'); }
61
+
62
+ // Remove package-lock.json
63
+ const lockFile = join(ROOT, 'package-lock.json');
64
+ if (existsSync(lockFile)) { unlinkSync(lockFile); log('Removed package-lock.json', 'green'); }
65
+
66
+ log('Clean complete', 'green');
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import chalk from 'chalk';
4
+ import { execa } from 'execa';
5
+ import killPort from 'kill-port';
6
+ import { Socket } from 'net';
7
+ import { execSync, spawn } from 'child_process';
8
+ import { existsSync, statSync, unlinkSync, readdirSync, rmSync } from 'fs';
9
+ import { dirname, join } from 'path';
10
+ import { fileURLToPath } from 'url';
11
+
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const ROOT = join(__dirname, '..');
14
+ const API_PORT = 9400, WEB_PORT = 5000;
15
+ const BIN = process.platform === 'win32' ? 'whatsapp-rpc-server.exe' : 'whatsapp-rpc-server';
16
+ const BIN_DIR = join(ROOT, 'bin');
17
+
18
+ const log = (m, c = 'blue') => console.log(chalk[c](m));
19
+ const sleep = ms => new Promise(r => setTimeout(r, ms));
20
+
21
+ const portUp = port => new Promise(r => {
22
+ const s = new Socket();
23
+ s.setTimeout(2000);
24
+ s.on('connect', () => { s.destroy(); r(true); });
25
+ s.on('timeout', () => { s.destroy(); r(false); });
26
+ s.on('error', () => r(false));
27
+ s.connect(port, '127.0.0.1');
28
+ });
29
+
30
+ const wait = async (port, ms = 10000) => {
31
+ const t = Date.now();
32
+ while (Date.now() - t < ms) { if (await portUp(port)) return true; await sleep(500); }
33
+ return false;
34
+ };
35
+
36
+ const kill = async (port, name) => {
37
+ try { await killPort(port); log(`${name} stopped`, 'green'); }
38
+ catch { log(`${name} not running`, 'yellow'); }
39
+ };
40
+
41
+ const py = () => {
42
+ try { execSync('python --version', { stdio: 'ignore' }); return 'python'; }
43
+ catch { try { execSync('python3 --version', { stdio: 'ignore' }); return 'python3'; } catch { return null; } }
44
+ };
45
+
46
+ const hasGo = () => {
47
+ try { execSync('go version', { stdio: 'ignore' }); return true; }
48
+ catch { return false; }
49
+ };
50
+
51
+ async function api(foreground = false) {
52
+ if (await portUp(API_PORT)) { log(`API already on ${API_PORT}`, 'yellow'); return; }
53
+ const bin = join(BIN_DIR, BIN);
54
+ if (!existsSync(bin)) {
55
+ if (!hasGo()) {
56
+ log('Go is not installed. Please either:', 'red');
57
+ log(' 1. Install Go: https://go.dev/dl/', 'yellow');
58
+ log(' 2. Or run "npm run build" on a machine with Go installed', 'yellow');
59
+ log(' 3. Or copy the pre-built binary to: ' + bin, 'yellow');
60
+ process.exit(1);
61
+ }
62
+ log('Building...', 'yellow');
63
+ await build();
64
+ }
65
+
66
+ if (foreground) {
67
+ // Run in foreground - will receive Ctrl+C signals
68
+ const proc = spawn(bin, [], { cwd: ROOT, stdio: 'inherit' });
69
+ proc.on('close', (code) => process.exit(code || 0));
70
+ process.on('SIGINT', () => { proc.kill('SIGINT'); });
71
+ process.on('SIGTERM', () => { proc.kill('SIGTERM'); });
72
+ log(`API: ws://localhost:${API_PORT}/ws/rpc`, 'green');
73
+ } else {
74
+ // Run detached in background
75
+ spawn(bin, [], { cwd: ROOT, detached: true, stdio: 'ignore' }).unref();
76
+ if (await wait(API_PORT)) log(`API: ws://localhost:${API_PORT}/ws/rpc`, 'green');
77
+ else log('API failed to start', 'red');
78
+ }
79
+ }
80
+
81
+ async function web() {
82
+ if (await portUp(WEB_PORT)) { log(`Web already on ${WEB_PORT}`, 'yellow'); return; }
83
+ const p = py(); if (!p) { log('Python not found', 'red'); return; }
84
+ if (!await portUp(API_PORT)) log('Warning: API not running', 'yellow');
85
+ spawn(p, ['app.py'], { cwd: join(ROOT, 'web'), detached: true, stdio: 'ignore' }).unref();
86
+ if (await wait(WEB_PORT)) log(`Web: http://localhost:${WEB_PORT}`, 'green');
87
+ else log('Web failed to start', 'red');
88
+ }
89
+
90
+ async function start() { await api(); await sleep(1000); await web(); }
91
+ async function stop() { await kill(API_PORT, 'API'); await kill(WEB_PORT, 'Web'); }
92
+
93
+ async function status() {
94
+ const a = await portUp(API_PORT), w = await portUp(WEB_PORT);
95
+ log(`API (${API_PORT}): ${a ? 'UP' : 'DOWN'}`, a ? 'green' : 'red');
96
+ log(`Web (${WEB_PORT}): ${w ? 'UP' : 'DOWN'}`, w ? 'green' : 'red');
97
+ }
98
+
99
+ async function build() {
100
+ if (!hasGo()) {
101
+ log('Go is not installed. Install from: https://go.dev/dl/', 'red');
102
+ process.exit(1);
103
+ }
104
+ const bin = join(BIN_DIR, BIN);
105
+ if (!existsSync(BIN_DIR)) { await execa('mkdir', ['-p', BIN_DIR]); }
106
+ if (existsSync(bin)) unlinkSync(bin);
107
+ await execa('go', ['build', '-o', bin, './src/go/cmd/server'], { cwd: ROOT, stdio: 'inherit' });
108
+ log(`Built: ${BIN} (${(statSync(bin).size / 1024 / 1024).toFixed(1)}MB)`, 'green');
109
+ }
110
+
111
+ async function clean() {
112
+ log('Stopping all processes...', 'blue');
113
+ await stop();
114
+ await sleep(1000);
115
+
116
+ // Remove binary
117
+ const bin = join(BIN_DIR, BIN);
118
+ if (existsSync(bin)) { unlinkSync(bin); log(`Removed ${BIN}`, 'green'); }
119
+
120
+ // Remove bin directory if empty
121
+ if (existsSync(BIN_DIR) && readdirSync(BIN_DIR).length === 0) {
122
+ rmSync(BIN_DIR, { recursive: true }); log('Removed bin/', 'green');
123
+ }
124
+
125
+ // Remove entire data directory (database, QR codes, etc.)
126
+ const dataDir = join(ROOT, 'data');
127
+ if (existsSync(dataDir)) {
128
+ rmSync(dataDir, { recursive: true });
129
+ log('Removed data/', 'green');
130
+ }
131
+
132
+ // Remove any .db files in project root (legacy locations)
133
+ readdirSync(ROOT).filter(f => f.endsWith('.db') || f.endsWith('.db-wal') || f.endsWith('.db-shm')).forEach(f => {
134
+ unlinkSync(join(ROOT, f));
135
+ log(`Removed ${f}`, 'green');
136
+ });
137
+
138
+ // Remove node_modules
139
+ const nodeModules = join(ROOT, 'node_modules');
140
+ if (existsSync(nodeModules)) { rmSync(nodeModules, { recursive: true }); log('Removed node_modules/', 'green'); }
141
+
142
+ // Remove Python cache
143
+ const pycache = join(ROOT, 'web', '__pycache__');
144
+ if (existsSync(pycache)) { rmSync(pycache, { recursive: true }); log('Removed web/__pycache__/', 'green'); }
145
+
146
+ // Remove package-lock.json
147
+ const lockFile = join(ROOT, 'package-lock.json');
148
+ if (existsSync(lockFile)) { unlinkSync(lockFile); log('Removed package-lock.json', 'green'); }
149
+
150
+ log('Clean complete', 'green');
151
+ }
152
+
153
+ program.name('wa').version('1.0.0');
154
+ program.command('start').description('Start all').action(start);
155
+ program.command('stop').description('Stop all').action(stop);
156
+ program.command('restart').description('Restart all').action(async () => { await stop(); await sleep(1000); await start(); });
157
+ program.command('status').description('Status').action(status);
158
+ program.command('api').description('Start API only').option('-f, --foreground', 'Run in foreground (receive signals)').action((opts) => api(opts.foreground));
159
+ program.command('web').description('Start Web only').action(web);
160
+ program.command('build').description('Build binary').action(build);
161
+ program.command('clean').description('Clean artifacts').action(clean);
162
+ program.parse();
@@ -0,0 +1,91 @@
1
+ package main
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+ "net/http"
7
+ "os"
8
+ "os/signal"
9
+ "syscall"
10
+ "time"
11
+
12
+ "github.com/sirupsen/logrus"
13
+
14
+ "whatsapp-rpc/src/go/config"
15
+ server "whatsapp-rpc/src/go/rpc"
16
+ "whatsapp-rpc/src/go/whatsapp"
17
+ )
18
+
19
+ func main() {
20
+ // Initialize logger
21
+ logger := logrus.New()
22
+ logger.SetFormatter(&logrus.TextFormatter{
23
+ FullTimestamp: true,
24
+ })
25
+
26
+ // Load configuration
27
+ cfg, err := config.Load()
28
+ if err != nil {
29
+ logger.Fatalf("Failed to load config: %v", err)
30
+ }
31
+
32
+ // Set log level (5 = Debug, 4 = Info)
33
+ if cfg.LogLevel >= 5 {
34
+ logger.SetLevel(logrus.DebugLevel)
35
+ }
36
+
37
+ logger.Info("Starting WhatsApp WebSocket RPC Server")
38
+
39
+ // Initialize WhatsApp service
40
+ whatsappService, err := whatsapp.NewService(cfg.Database, logger)
41
+ if err != nil {
42
+ logger.Fatalf("Failed to initialize WhatsApp service: %v", err)
43
+ }
44
+
45
+ // Auto-start if there's an existing session (no need to press Start button)
46
+ if whatsappService.HasExistingSession() {
47
+ logger.Info("Existing session found, auto-connecting...")
48
+ if err := whatsappService.Start(); err != nil {
49
+ logger.Warnf("Auto-start failed: %v (user can manually start)", err)
50
+ }
51
+ } else {
52
+ logger.Info("No existing session, waiting for user to start pairing")
53
+ }
54
+
55
+ // Create and start server (WebSocket RPC only)
56
+ srv := server.New(whatsappService, logger)
57
+ router := srv.SetupRoutes()
58
+
59
+ httpServer := &http.Server{
60
+ Addr: fmt.Sprintf(":%d", cfg.Server.Port),
61
+ Handler: router,
62
+ }
63
+
64
+ // Start server in goroutine
65
+ go func() {
66
+ logger.Infof("WebSocket RPC server listening on port %d", cfg.Server.Port)
67
+ logger.Infof("Connect via: ws://localhost:%d/ws/rpc", cfg.Server.Port)
68
+ if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
69
+ logger.Fatalf("Server error: %v", err)
70
+ }
71
+ }()
72
+
73
+ // Wait for interrupt signal
74
+ quit := make(chan os.Signal, 1)
75
+ signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
76
+ <-quit
77
+
78
+ logger.Info("Shutting down server...")
79
+
80
+ // Graceful shutdown
81
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
82
+ defer cancel()
83
+
84
+ whatsappService.Shutdown()
85
+
86
+ if err := httpServer.Shutdown(ctx); err != nil {
87
+ logger.Errorf("Server shutdown error: %v", err)
88
+ }
89
+
90
+ logger.Info("Server stopped")
91
+ }
@@ -0,0 +1,49 @@
1
+ package config
2
+
3
+ import (
4
+ "github.com/spf13/viper"
5
+ )
6
+
7
+ type Config struct {
8
+ Environment string `mapstructure:"environment"`
9
+ LogLevel int `mapstructure:"log_level"`
10
+ Server ServerConfig `mapstructure:"server"`
11
+ Database DatabaseConfig `mapstructure:"database"`
12
+ }
13
+
14
+ type ServerConfig struct {
15
+ Port int `mapstructure:"port"`
16
+ Host string `mapstructure:"host"`
17
+ }
18
+
19
+ type DatabaseConfig struct {
20
+ Path string `mapstructure:"path"`
21
+ }
22
+
23
+ func Load() (*Config, error) {
24
+ viper.SetDefault("environment", "development")
25
+ viper.SetDefault("log_level", 4) // Info level
26
+ viper.SetDefault("server.port", 9400)
27
+ viper.SetDefault("server.host", "0.0.0.0")
28
+ viper.SetDefault("database.path", "data/whatsapp.db")
29
+
30
+ // Environment variables
31
+ viper.SetEnvPrefix("WA")
32
+ viper.AutomaticEnv()
33
+
34
+ // Config file
35
+ viper.SetConfigName("config")
36
+ viper.SetConfigType("yaml")
37
+ viper.AddConfigPath(".")
38
+ viper.AddConfigPath("./configs")
39
+
40
+ // Read config file (optional)
41
+ viper.ReadInConfig()
42
+
43
+ var config Config
44
+ if err := viper.Unmarshal(&config); err != nil {
45
+ return nil, err
46
+ }
47
+
48
+ return &config, nil
49
+ }