machinaos 0.0.7 → 0.0.9

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "machinaos",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "Open source workflow automation platform with AI agents, React Flow, and n8n-inspired architecture",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -71,7 +71,7 @@
71
71
  "deploy": "bash deploy.sh",
72
72
  "deploy:gcp": "bash deploy.sh",
73
73
  "prepublishOnly": "node -e \"const p=require('./package.json'); if(!p.bin||!p.version){process.exit(1)}\"",
74
- "postinstall": "node scripts/build.js"
74
+ "postinstall": "node scripts/postinstall.js"
75
75
  },
76
76
  "dependencies": {
77
77
  "concurrently": "^9.2.1",
package/scripts/build.js CHANGED
@@ -26,18 +26,20 @@ const isMac = process.platform === 'darwin';
26
26
  const isPostInstall = process.env.npm_lifecycle_event === 'postinstall';
27
27
  const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
28
28
 
29
+ // Ensure Python UTF-8 encoding
30
+ process.env.PYTHONUTF8 = '1';
31
+
32
+ // Use stderr for all output so npm shows it during postinstall
33
+ const print = (msg) => process.stderr.write(msg + '\n');
34
+
29
35
  // Skip build entirely in CI (workflows handle this)
30
36
  if (isCI && isPostInstall) {
31
- console.log('CI environment detected, skipping postinstall build.');
37
+ print('CI environment detected, skipping postinstall build.');
32
38
  process.exit(0);
33
39
  }
34
40
 
35
-
36
- // Ensure Python UTF-8 encoding
37
- process.env.PYTHONUTF8 = '1';
38
-
39
41
  function run(cmd, cwd = ROOT) {
40
- execSync(cmd, { cwd, stdio: 'inherit', shell: true });
42
+ execSync(cmd, { cwd, stdio: ['inherit', process.stderr, process.stderr], shell: true });
41
43
  }
42
44
 
43
45
  function runSilent(cmd) {
@@ -58,13 +60,13 @@ function getVersion(cmd) {
58
60
  }
59
61
 
60
62
  function log(step, msg) {
61
- console.log(`[${step}] ${msg}`);
63
+ print(`[${step}] ${msg}`);
62
64
  }
63
65
 
64
66
  function npmInstall(cwd = ROOT) {
65
- // Use npm install directly with visible output
67
+ // Use npm install directly with visible output via stderr
66
68
  // npm ci requires package-lock.json which may not exist in all directories
67
- execSync('npm install', { cwd, stdio: 'inherit', shell: true });
69
+ execSync('npm install', { cwd, stdio: ['inherit', process.stderr, process.stderr], shell: true });
68
70
  }
69
71
 
70
72
  // ============================================================================
@@ -72,7 +74,7 @@ function npmInstall(cwd = ROOT) {
72
74
  // ============================================================================
73
75
 
74
76
  function installPython() {
75
- console.log(' Installing Python 3.11+...');
77
+ print(' Installing Python 3.11+...');
76
78
  if (isWindows) {
77
79
  // Try winget first, then choco
78
80
  if (runSilent('winget --version')) {
@@ -80,15 +82,15 @@ function installPython() {
80
82
  } else if (runSilent('choco --version')) {
81
83
  run('choco install python312 -y');
82
84
  } else {
83
- console.error(' Error: Please install Python manually from https://python.org/');
84
- console.error(' Or install winget/chocolatey first.');
85
+ print(' Error: Please install Python manually from https://python.org/');
86
+ print(' Or install winget/chocolatey first.');
85
87
  process.exit(1);
86
88
  }
87
89
  } else if (isMac) {
88
90
  if (runSilent('brew --version')) {
89
91
  run('brew install python@3.12');
90
92
  } else {
91
- console.error(' Error: Please install Homebrew first: https://brew.sh/');
93
+ print(' Error: Please install Homebrew first: https://brew.sh/');
92
94
  process.exit(1);
93
95
  }
94
96
  } else {
@@ -100,14 +102,14 @@ function installPython() {
100
102
  } else if (runSilent('pacman --version')) {
101
103
  run('sudo pacman -S --noconfirm python');
102
104
  } else {
103
- console.error(' Error: Please install Python manually from https://python.org/');
105
+ print(' Error: Please install Python manually from https://python.org/');
104
106
  process.exit(1);
105
107
  }
106
108
  }
107
109
  }
108
110
 
109
111
  function installUv() {
110
- console.log(' Installing uv...');
112
+ print(' Installing uv...');
111
113
  if (isWindows) {
112
114
  run('powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"');
113
115
  } else {
@@ -122,21 +124,21 @@ function installUv() {
122
124
  }
123
125
 
124
126
  function installGo() {
125
- console.log(' Installing Go...');
127
+ print(' Installing Go...');
126
128
  if (isWindows) {
127
129
  if (runSilent('winget --version')) {
128
130
  run('winget install GoLang.Go --accept-package-agreements --accept-source-agreements');
129
131
  } else if (runSilent('choco --version')) {
130
132
  run('choco install golang -y');
131
133
  } else {
132
- console.error(' Error: Please install Go manually from https://go.dev/dl/');
134
+ print(' Error: Please install Go manually from https://go.dev/dl/');
133
135
  process.exit(1);
134
136
  }
135
137
  } else if (isMac) {
136
138
  if (runSilent('brew --version')) {
137
139
  run('brew install go');
138
140
  } else {
139
- console.error(' Error: Please install Homebrew first: https://brew.sh/');
141
+ print(' Error: Please install Homebrew first: https://brew.sh/');
140
142
  process.exit(1);
141
143
  }
142
144
  } else {
@@ -147,7 +149,7 @@ function installGo() {
147
149
  } else if (runSilent('pacman --version')) {
148
150
  run('sudo pacman -S --noconfirm go');
149
151
  } else {
150
- console.error(' Error: Please install Go manually from https://go.dev/dl/');
152
+ print(' Error: Please install Go manually from https://go.dev/dl/');
151
153
  process.exit(1);
152
154
  }
153
155
  }
@@ -157,14 +159,14 @@ function installGo() {
157
159
  // Check and Install Dependencies
158
160
  // ============================================================================
159
161
 
160
- console.log('Checking dependencies...\n');
162
+ print('Checking dependencies...\n');
161
163
 
162
164
  // Node.js (must already be installed to run this script)
163
165
  const nodeVersion = getVersion('node --version');
164
- console.log(` Node.js: ${nodeVersion}`);
166
+ print(` Node.js: ${nodeVersion}`);
165
167
 
166
168
  const npmVersion = getVersion('npm --version');
167
- console.log(` npm: ${npmVersion}`);
169
+ print(` npm: ${npmVersion}`);
168
170
 
169
171
  // Python
170
172
  let pyCmd = null;
@@ -180,9 +182,9 @@ if (pyCmd) {
180
182
  if (match) {
181
183
  const [, major, minor] = match.map(Number);
182
184
  if (major >= 3 && minor >= 11) {
183
- console.log(` ${pyVersion}`);
185
+ print(` ${pyVersion}`);
184
186
  } else {
185
- console.log(` ${pyVersion} (too old, need 3.11+)`);
187
+ print(` ${pyVersion} (too old, need 3.11+)`);
186
188
  installPython();
187
189
  }
188
190
  }
@@ -190,21 +192,21 @@ if (pyCmd) {
190
192
  installPython();
191
193
  // Re-check
192
194
  pyCmd = runSilent('python --version') ? 'python' : 'python3';
193
- console.log(` ${getVersion(`${pyCmd} --version`)}`);
195
+ print(` ${getVersion(`${pyCmd} --version`)}`);
194
196
  }
195
197
 
196
198
  // uv
197
199
  let uvVersion = getVersion('uv --version');
198
200
  if (uvVersion) {
199
- console.log(` uv: ${uvVersion}`);
201
+ print(` uv: ${uvVersion}`);
200
202
  } else {
201
203
  installUv();
202
204
  uvVersion = getVersion('uv --version');
203
205
  if (uvVersion) {
204
- console.log(` uv: ${uvVersion}`);
206
+ print(` uv: ${uvVersion}`);
205
207
  } else {
206
- console.error(' Error: Failed to install uv. Please install manually.');
207
- console.error(' https://docs.astral.sh/uv/getting-started/installation/');
208
+ print(' Error: Failed to install uv. Please install manually.');
209
+ print(' https://docs.astral.sh/uv/getting-started/installation/');
208
210
  process.exit(1);
209
211
  }
210
212
  }
@@ -213,21 +215,21 @@ if (uvVersion) {
213
215
  let goVersionFull = getVersion('go version');
214
216
  if (goVersionFull) {
215
217
  const goVersion = goVersionFull.match(/go\d+\.\d+(\.\d+)?/)?.[0] || 'go';
216
- console.log(` Go: ${goVersion}`);
218
+ print(` Go: ${goVersion}`);
217
219
  } else {
218
220
  installGo();
219
221
  goVersionFull = getVersion('go version');
220
222
  if (goVersionFull) {
221
223
  const goVersion = goVersionFull.match(/go\d+\.\d+(\.\d+)?/)?.[0] || 'go';
222
- console.log(` Go: ${goVersion}`);
224
+ print(` Go: ${goVersion}`);
223
225
  } else {
224
- console.error(' Error: Failed to install Go. Please install manually.');
225
- console.error(' https://go.dev/dl/');
226
+ print(' Error: Failed to install Go. Please install manually.');
227
+ print(' https://go.dev/dl/');
226
228
  process.exit(1);
227
229
  }
228
230
  }
229
231
 
230
- console.log('\nAll dependencies ready.\n');
232
+ print('\nAll dependencies ready.\n');
231
233
 
232
234
  // ============================================================================
233
235
  // Build
@@ -273,9 +275,9 @@ try {
273
275
  log('6/6', 'Building WhatsApp server...');
274
276
  run('npm run build', whatsappDir);
275
277
 
276
- console.log('\nBuild complete.');
278
+ print('\nBuild complete.');
277
279
 
278
280
  } catch (err) {
279
- console.error('\nBuild failed:', err.message);
281
+ print(`\nBuild failed: ${err.message}`);
280
282
  process.exit(1);
281
283
  }
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Optional binary download script for MachinaOS.
4
+ * Downloads pre-built WhatsApp RPC server binary from GitHub Releases.
5
+ *
6
+ * Skipped if:
7
+ * - MACHINAOS_SKIP_BINARY_DOWNLOAD=1
8
+ * - CI environment (CI=true)
9
+ * - Go is installed (can build from source)
10
+ *
11
+ * Force download even if Go installed:
12
+ * - MACHINAOS_FORCE_BINARY_DOWNLOAD=1
13
+ */
14
+ import { execSync } from 'child_process';
15
+ import { createWriteStream, existsSync, mkdirSync, chmodSync, readFileSync } from 'fs';
16
+ import { resolve, dirname } from 'path';
17
+ import { fileURLToPath } from 'url';
18
+ import https from 'https';
19
+
20
+ const __dirname = dirname(fileURLToPath(import.meta.url));
21
+ const ROOT = resolve(__dirname, '..');
22
+ const WHATSAPP_BIN_DIR = resolve(ROOT, 'server/whatsapp-rpc/bin');
23
+
24
+ // Read version from package.json
25
+ const pkg = JSON.parse(readFileSync(resolve(ROOT, 'package.json'), 'utf-8'));
26
+ const VERSION = pkg.version;
27
+
28
+ // GitHub release URL
29
+ const GITHUB_REPO = 'trohitg/MachinaOS';
30
+ const BASE_URL = `https://github.com/${GITHUB_REPO}/releases/download/v${VERSION}`;
31
+
32
+ // Platform detection
33
+ function getPlatformInfo() {
34
+ const osMap = { 'win32': 'windows', 'darwin': 'darwin', 'linux': 'linux' };
35
+ const archMap = { 'x64': 'amd64', 'arm64': 'arm64' };
36
+
37
+ const os = osMap[process.platform];
38
+ const goarch = archMap[process.arch];
39
+
40
+ if (!os || !goarch) {
41
+ return null;
42
+ }
43
+
44
+ const ext = process.platform === 'win32' ? '.exe' : '';
45
+ return { os, goarch, ext };
46
+ }
47
+
48
+ // Check if Go is installed
49
+ function hasGo() {
50
+ try {
51
+ execSync('go version', { stdio: 'ignore' });
52
+ return true;
53
+ } catch {
54
+ return false;
55
+ }
56
+ }
57
+
58
+ // Download file with redirect handling
59
+ function downloadFile(url, dest) {
60
+ return new Promise((resolve, reject) => {
61
+ const request = (currentUrl, redirectCount = 0) => {
62
+ if (redirectCount > 5) {
63
+ reject(new Error('Too many redirects'));
64
+ return;
65
+ }
66
+
67
+ const client = currentUrl.startsWith('https') ? https : require('http');
68
+
69
+ client.get(currentUrl, (response) => {
70
+ // Handle redirects (GitHub releases redirect to CDN)
71
+ if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
72
+ request(response.headers.location, redirectCount + 1);
73
+ return;
74
+ }
75
+
76
+ if (response.statusCode !== 200) {
77
+ reject(new Error(`HTTP ${response.statusCode}`));
78
+ return;
79
+ }
80
+
81
+ const file = createWriteStream(dest);
82
+ const totalBytes = parseInt(response.headers['content-length'], 10);
83
+ let downloadedBytes = 0;
84
+
85
+ response.on('data', (chunk) => {
86
+ downloadedBytes += chunk.length;
87
+ if (totalBytes) {
88
+ const percent = ((downloadedBytes / totalBytes) * 100).toFixed(1);
89
+ process.stdout.write(`\r Downloading: ${percent}%`);
90
+ }
91
+ });
92
+
93
+ response.pipe(file);
94
+ file.on('finish', () => {
95
+ file.close();
96
+ console.log(' Done');
97
+ resolve();
98
+ });
99
+ file.on('error', (err) => {
100
+ file.close();
101
+ reject(err);
102
+ });
103
+ }).on('error', reject);
104
+ };
105
+
106
+ request(url);
107
+ });
108
+ }
109
+
110
+ // Main
111
+ async function main() {
112
+ // Skip conditions
113
+ if (process.env.MACHINAOS_SKIP_BINARY_DOWNLOAD === '1') {
114
+ console.log('Skipping binary download (MACHINAOS_SKIP_BINARY_DOWNLOAD=1)');
115
+ return;
116
+ }
117
+
118
+ if (process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true') {
119
+ console.log('Skipping binary download (CI environment)');
120
+ return;
121
+ }
122
+
123
+ // Check if Go is installed - prefer source build
124
+ if (hasGo()) {
125
+ if (process.env.MACHINAOS_FORCE_BINARY_DOWNLOAD !== '1') {
126
+ console.log('Go is installed - will build from source');
127
+ return;
128
+ }
129
+ console.log('Go is installed but MACHINAOS_FORCE_BINARY_DOWNLOAD=1, downloading anyway');
130
+ }
131
+
132
+ const platformInfo = getPlatformInfo();
133
+ if (!platformInfo) {
134
+ console.log(`Unsupported platform: ${process.platform}/${process.arch}`);
135
+ return;
136
+ }
137
+
138
+ const { os, goarch, ext } = platformInfo;
139
+ const binaryName = `whatsapp-rpc-server-${os}-${goarch}${ext}`;
140
+ const downloadUrl = `${BASE_URL}/${binaryName}`;
141
+ const destPath = resolve(WHATSAPP_BIN_DIR, `whatsapp-rpc-server${ext}`);
142
+
143
+ console.log(`\nDownloading pre-built WhatsApp RPC binary...`);
144
+ console.log(` Version: v${VERSION}`);
145
+ console.log(` Platform: ${os}/${goarch}`);
146
+
147
+ // Create bin directory
148
+ if (!existsSync(WHATSAPP_BIN_DIR)) {
149
+ mkdirSync(WHATSAPP_BIN_DIR, { recursive: true });
150
+ }
151
+
152
+ // Check if binary already exists
153
+ if (existsSync(destPath)) {
154
+ console.log(` Binary already exists: ${destPath}`);
155
+ return;
156
+ }
157
+
158
+ // Download binary
159
+ try {
160
+ await downloadFile(downloadUrl, destPath);
161
+ } catch (error) {
162
+ console.error(`\nFailed to download binary: ${error.message}`);
163
+ console.log('Will attempt to build from source instead.');
164
+ return;
165
+ }
166
+
167
+ // Set executable permission (Unix only)
168
+ if (process.platform !== 'win32') {
169
+ chmodSync(destPath, 0o755);
170
+ }
171
+
172
+ console.log(`Binary downloaded: ${destPath}`);
173
+ }
174
+
175
+ main().catch((err) => {
176
+ // Don't fail the install - just log and continue
177
+ console.error('Binary download error:', err.message);
178
+ });
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Postinstall script for MachinaOS.
4
+ * Outputs to stderr so npm shows the progress (npm suppresses stdout during postinstall).
5
+ *
6
+ * Scenarios:
7
+ * 1. npm install -g machinaos → Run full install with output
8
+ * 2. npm install (local) → Run full install with output
9
+ * 3. GitHub Actions CI → Skip (workflow handles build separately)
10
+ *
11
+ * Runs:
12
+ * 1. download-binaries.js (optional binary download)
13
+ * 2. build.js (full build)
14
+ */
15
+ import { spawn } from 'child_process';
16
+ import { resolve, dirname } from 'path';
17
+ import { fileURLToPath } from 'url';
18
+
19
+ const __dirname = dirname(fileURLToPath(import.meta.url));
20
+ const ROOT = resolve(__dirname, '..');
21
+
22
+ // Output to stderr so npm shows it during install
23
+ const print = (msg) => process.stderr.write(msg + '\n');
24
+
25
+ // Environment detection
26
+ const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
27
+
28
+ // Skip in CI - GitHub Actions workflow handles build separately
29
+ if (isCI) {
30
+ print('CI environment detected, skipping postinstall.');
31
+ process.exit(0);
32
+ }
33
+
34
+ print('');
35
+ print('========================================');
36
+ print(' MachinaOS - Installing...');
37
+ print('========================================');
38
+ print('');
39
+
40
+ // Run a script and pipe all output to stderr (npm shows stderr during install)
41
+ function runScript(scriptPath) {
42
+ return new Promise((resolve, reject) => {
43
+ const child = spawn(process.execPath, [scriptPath], {
44
+ cwd: ROOT,
45
+ stdio: ['inherit', 'pipe', 'pipe'],
46
+ env: { ...process.env, FORCE_COLOR: '1' }
47
+ });
48
+
49
+ // Pipe stdout to stderr so npm shows it
50
+ child.stdout.on('data', (data) => process.stderr.write(data));
51
+ child.stderr.on('data', (data) => process.stderr.write(data));
52
+
53
+ child.on('error', reject);
54
+ child.on('close', (code) => {
55
+ if (code === 0) {
56
+ resolve();
57
+ } else {
58
+ reject(new Error(`Script exited with code ${code}`));
59
+ }
60
+ });
61
+ });
62
+ }
63
+
64
+ async function main() {
65
+ try {
66
+ // Step 1: Try to download pre-built binaries (optional, non-fatal)
67
+ print('[1/2] Checking for pre-built binaries...');
68
+ try {
69
+ await runScript(resolve(__dirname, 'download-binaries.js'));
70
+ } catch (e) {
71
+ print(' Binary download skipped or failed, will build from source.');
72
+ }
73
+
74
+ // Step 2: Run the full build
75
+ print('');
76
+ print('[2/2] Building MachinaOS...');
77
+ print('');
78
+ await runScript(resolve(__dirname, 'build.js'));
79
+
80
+ print('');
81
+ print('========================================');
82
+ print(' MachinaOS installed successfully!');
83
+ print('========================================');
84
+ print('');
85
+ print('Run: machinaos start');
86
+ print('Open: http://localhost:3000');
87
+ print('');
88
+
89
+ } catch (err) {
90
+ print('');
91
+ print('========================================');
92
+ print(' Installation failed!');
93
+ print('========================================');
94
+ print('');
95
+ print(`Error: ${err.message}`);
96
+ print('');
97
+ print('Try running manually:');
98
+ print(' machinaos build');
99
+ print('');
100
+ process.exit(1);
101
+ }
102
+ }
103
+
104
+ main();
package/server/uv.lock CHANGED
@@ -2582,15 +2582,15 @@ wheels = [
2582
2582
 
2583
2583
  [[package]]
2584
2584
  name = "sqlmodel"
2585
- version = "0.0.31"
2585
+ version = "0.0.32"
2586
2586
  source = { registry = "https://pypi.org/simple" }
2587
2587
  dependencies = [
2588
2588
  { name = "pydantic" },
2589
2589
  { name = "sqlalchemy" },
2590
2590
  ]
2591
- sdist = { url = "https://files.pythonhosted.org/packages/56/b8/e7cd6def4a773f25d6e29ffce63ccbfd6cf9488b804ab6fb9b80d334b39d/sqlmodel-0.0.31.tar.gz", hash = "sha256:2d41a8a9ee05e40736e2f9db8ea28cbfe9b5d4e5a18dd139e80605025e0c516c", size = 94952, upload-time = "2025-12-28T12:35:01.436Z" }
2591
+ sdist = { url = "https://files.pythonhosted.org/packages/d1/89/67f8964f3b2ed073fa4e95201e708291935d00e3600f36f09c1be3e279fe/sqlmodel-0.0.32.tar.gz", hash = "sha256:48e8fe4c8c3d7d8bf8468db17fa92ca680421e86cfec8b352217ef40736767be", size = 94140, upload-time = "2026-02-01T18:19:14.752Z" }
2592
2592
  wheels = [
2593
- { url = "https://files.pythonhosted.org/packages/6c/72/5aa5be921800f6418a949a73c9bb7054890881143e6bc604a93d228a95a3/sqlmodel-0.0.31-py3-none-any.whl", hash = "sha256:6d946d56cac4c2db296ba1541357cee2e795d68174e2043cd138b916794b1513", size = 27093, upload-time = "2025-12-28T12:35:00.108Z" },
2593
+ { url = "https://files.pythonhosted.org/packages/ed/de/d9b40ed2c570fd612c2abd57e4d9084a9d8eb1797447e2ce897b77b1c4b2/sqlmodel-0.0.32-py3-none-any.whl", hash = "sha256:d62f0702599592046c1a136d3512feab3d5a80e2988642ef0ed2c89b9b8b297b", size = 27416, upload-time = "2026-02-01T18:19:15.992Z" },
2594
2594
  ]
2595
2595
 
2596
2596
  [[package]]
@@ -97,13 +97,22 @@ async function status() {
97
97
  }
98
98
 
99
99
  async function build() {
100
+ const bin = join(BIN_DIR, BIN);
101
+
102
+ // Skip if binary already exists (e.g., downloaded from GitHub Releases)
103
+ if (existsSync(bin)) {
104
+ log(`Binary already exists: ${BIN} (${(statSync(bin).size / 1024 / 1024).toFixed(1)}MB)`, 'green');
105
+ return;
106
+ }
107
+
108
+ // Build from source requires Go
100
109
  if (!hasGo()) {
101
- log('Go is not installed. Install from: https://go.dev/dl/', 'red');
110
+ log('Go is not installed and no pre-built binary found.', 'red');
111
+ log('Install Go from: https://go.dev/dl/', 'yellow');
102
112
  process.exit(1);
103
113
  }
104
- const bin = join(BIN_DIR, BIN);
114
+
105
115
  if (!existsSync(BIN_DIR)) { await execa('mkdir', ['-p', BIN_DIR]); }
106
- if (existsSync(bin)) unlinkSync(bin);
107
116
  await execa('go', ['build', '-o', bin, './src/go/cmd/server'], { cwd: ROOT, stdio: 'inherit' });
108
117
  log(`Built: ${BIN} (${(statSync(bin).size / 1024 / 1024).toFixed(1)}MB)`, 'green');
109
118
  }