machinaos 0.0.6 → 0.0.8
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/README.md +21 -3
- package/install.ps1 +308 -0
- package/install.sh +343 -0
- package/package.json +6 -3
- package/scripts/build.js +22 -8
- package/scripts/download-binaries.js +178 -0
- package/scripts/postinstall.js +100 -0
- package/server/uv.lock +3 -3
- package/server/whatsapp-rpc/bin/whatsapp-rpc-server +0 -0
- package/server/whatsapp-rpc/scripts/cli.js +12 -3
package/README.md
CHANGED
|
@@ -4,7 +4,21 @@ Open-source workflow automation platform with AI agents, React Flow, and n8n-ins
|
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
|
-
### Option 1:
|
|
7
|
+
### Option 1: One-Line Install (Recommended)
|
|
8
|
+
|
|
9
|
+
**Linux/macOS:**
|
|
10
|
+
```bash
|
|
11
|
+
curl -fsSL https://raw.githubusercontent.com/trohitg/MachinaOS/main/install.sh | bash
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**Windows (PowerShell):**
|
|
15
|
+
```powershell
|
|
16
|
+
iwr -useb https://raw.githubusercontent.com/trohitg/MachinaOS/main/install.ps1 | iex
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This automatically installs all dependencies (Node.js, Python, uv, Go) and MachinaOS.
|
|
20
|
+
|
|
21
|
+
### Option 2: Clone & Run
|
|
8
22
|
|
|
9
23
|
```bash
|
|
10
24
|
git clone https://github.com/trohitg/MachinaOS.git
|
|
@@ -13,14 +27,16 @@ npm run build
|
|
|
13
27
|
npm run start
|
|
14
28
|
```
|
|
15
29
|
|
|
16
|
-
### Option
|
|
30
|
+
### Option 3: npm Global Install
|
|
17
31
|
|
|
18
32
|
```bash
|
|
19
33
|
npm install -g machinaos
|
|
20
34
|
machinaos start
|
|
21
35
|
```
|
|
22
36
|
|
|
23
|
-
|
|
37
|
+
Requires Node.js 18+, Python 3.11+, uv, and Go 1.21+ to be pre-installed.
|
|
38
|
+
|
|
39
|
+
### Option 4: Docker
|
|
24
40
|
|
|
25
41
|
```bash
|
|
26
42
|
git clone https://github.com/trohitg/MachinaOS.git
|
|
@@ -32,6 +48,8 @@ Open http://localhost:3000
|
|
|
32
48
|
|
|
33
49
|
## Prerequisites
|
|
34
50
|
|
|
51
|
+
The install script handles these automatically, but for manual installation:
|
|
52
|
+
|
|
35
53
|
- **Node.js 18+** - https://nodejs.org/
|
|
36
54
|
- **Python 3.11+** - https://python.org/
|
|
37
55
|
- **uv** - `curl -LsSf https://astral.sh/uv/install.sh | sh`
|
package/install.ps1
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# MachinaOS Installer for Windows
|
|
2
|
+
# Usage: iwr -useb https://raw.githubusercontent.com/trohitg/MachinaOS/main/install.ps1 | iex
|
|
3
|
+
#
|
|
4
|
+
# This script installs MachinaOS and its dependencies:
|
|
5
|
+
# - Node.js 18+ (via winget/choco)
|
|
6
|
+
# - Python 3.11+ (via winget/choco)
|
|
7
|
+
# - uv (Python package manager)
|
|
8
|
+
# - Go 1.21+ (for WhatsApp service)
|
|
9
|
+
|
|
10
|
+
$ErrorActionPreference = "Stop"
|
|
11
|
+
|
|
12
|
+
# Configuration
|
|
13
|
+
$REPO_URL = "https://github.com/trohitg/MachinaOS.git"
|
|
14
|
+
$INSTALL_DIR = if ($env:MACHINAOS_HOME) { $env:MACHINAOS_HOME } else { "$env:USERPROFILE\.machinaos" }
|
|
15
|
+
$MIN_NODE_VERSION = 18
|
|
16
|
+
$MIN_PYTHON_VERSION = "3.11"
|
|
17
|
+
$MIN_GO_VERSION = "1.21"
|
|
18
|
+
|
|
19
|
+
# Colors
|
|
20
|
+
function Write-Color {
|
|
21
|
+
param([string]$Text, [string]$Color = "White")
|
|
22
|
+
Write-Host $Text -ForegroundColor $Color
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function Info { Write-Color "[INFO] $args" "Cyan" }
|
|
26
|
+
function Success { Write-Color "[OK] $args" "Green" }
|
|
27
|
+
function Warn { Write-Color "[WARN] $args" "Yellow" }
|
|
28
|
+
function Error-Exit { Write-Color "[ERROR] $args" "Red"; exit 1 }
|
|
29
|
+
|
|
30
|
+
# Banner
|
|
31
|
+
Write-Host ""
|
|
32
|
+
Write-Color " __ __ _ _ ___ ____ " "Cyan"
|
|
33
|
+
Write-Color " | \/ | __ _ ___| |__ (_)_ __ __ _/ _ \/ ___| " "Cyan"
|
|
34
|
+
Write-Color " | |\/| |/ _`` |/ __| '_ \| | '_ \ / _`` | | | \___ \ " "Cyan"
|
|
35
|
+
Write-Color " | | | | (_| | (__| | | | | | | | (_| | |_| |___) |" "Cyan"
|
|
36
|
+
Write-Color " |_| |_|\__,_|\___|_| |_|_|_| |_|\__,_|\___/|____/ " "Cyan"
|
|
37
|
+
Write-Host ""
|
|
38
|
+
Write-Host "Open-source workflow automation with AI agents"
|
|
39
|
+
Write-Host ""
|
|
40
|
+
|
|
41
|
+
# Check if command exists
|
|
42
|
+
function Has-Command {
|
|
43
|
+
param([string]$Command)
|
|
44
|
+
$null -ne (Get-Command $Command -ErrorAction SilentlyContinue)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Get package manager
|
|
48
|
+
function Get-PackageManager {
|
|
49
|
+
if (Has-Command "winget") { return "winget" }
|
|
50
|
+
if (Has-Command "choco") { return "choco" }
|
|
51
|
+
return $null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# =============================================================================
|
|
55
|
+
# Dependency Checks and Installation
|
|
56
|
+
# =============================================================================
|
|
57
|
+
|
|
58
|
+
function Check-Node {
|
|
59
|
+
if (Has-Command "node") {
|
|
60
|
+
$version = (node --version) -replace "v", ""
|
|
61
|
+
$major = [int]($version.Split(".")[0])
|
|
62
|
+
if ($major -ge $MIN_NODE_VERSION) {
|
|
63
|
+
Success "Node.js v$version"
|
|
64
|
+
return $true
|
|
65
|
+
}
|
|
66
|
+
Warn "Node.js v$version is too old (need v$MIN_NODE_VERSION+)"
|
|
67
|
+
}
|
|
68
|
+
return $false
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function Install-Node {
|
|
72
|
+
Info "Installing Node.js..."
|
|
73
|
+
$pm = Get-PackageManager
|
|
74
|
+
|
|
75
|
+
switch ($pm) {
|
|
76
|
+
"winget" {
|
|
77
|
+
winget install OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements
|
|
78
|
+
}
|
|
79
|
+
"choco" {
|
|
80
|
+
choco install nodejs-lts -y
|
|
81
|
+
}
|
|
82
|
+
default {
|
|
83
|
+
Error-Exit "Please install winget or chocolatey, or install Node.js manually from https://nodejs.org/"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Refresh PATH
|
|
88
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
89
|
+
|
|
90
|
+
if (-not (Check-Node)) {
|
|
91
|
+
Error-Exit "Failed to install Node.js. Please install manually and restart PowerShell."
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function Check-Python {
|
|
96
|
+
foreach ($cmd in @("python", "python3")) {
|
|
97
|
+
if (Has-Command $cmd) {
|
|
98
|
+
$version = & $cmd --version 2>&1 | Select-String -Pattern "\d+\.\d+" | ForEach-Object { $_.Matches.Value }
|
|
99
|
+
if ($version -ge $MIN_PYTHON_VERSION) {
|
|
100
|
+
Success "Python $version ($cmd)"
|
|
101
|
+
$script:PYTHON_CMD = $cmd
|
|
102
|
+
return $true
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
Warn "Python $MIN_PYTHON_VERSION+ not found"
|
|
107
|
+
return $false
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function Install-Python {
|
|
111
|
+
Info "Installing Python..."
|
|
112
|
+
$pm = Get-PackageManager
|
|
113
|
+
|
|
114
|
+
switch ($pm) {
|
|
115
|
+
"winget" {
|
|
116
|
+
winget install Python.Python.3.12 --accept-package-agreements --accept-source-agreements
|
|
117
|
+
}
|
|
118
|
+
"choco" {
|
|
119
|
+
choco install python312 -y
|
|
120
|
+
}
|
|
121
|
+
default {
|
|
122
|
+
Error-Exit "Please install winget or chocolatey, or install Python manually from https://python.org/"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# Refresh PATH
|
|
127
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
128
|
+
|
|
129
|
+
if (-not (Check-Python)) {
|
|
130
|
+
Error-Exit "Failed to install Python. Please install manually and restart PowerShell."
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function Check-Uv {
|
|
135
|
+
if (Has-Command "uv") {
|
|
136
|
+
$version = (uv --version) -replace "uv ", ""
|
|
137
|
+
Success "uv $version"
|
|
138
|
+
return $true
|
|
139
|
+
}
|
|
140
|
+
return $false
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function Install-Uv {
|
|
144
|
+
Info "Installing uv (Python package manager)..."
|
|
145
|
+
Invoke-RestMethod https://astral.sh/uv/install.ps1 | Invoke-Expression
|
|
146
|
+
|
|
147
|
+
# Add to PATH for current session
|
|
148
|
+
$env:Path = "$env:USERPROFILE\.local\bin;$env:Path"
|
|
149
|
+
|
|
150
|
+
if (-not (Check-Uv)) {
|
|
151
|
+
Error-Exit "Failed to install uv"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function Check-Go {
|
|
156
|
+
if (Has-Command "go") {
|
|
157
|
+
$versionOutput = go version
|
|
158
|
+
if ($versionOutput -match "go(\d+\.\d+)") {
|
|
159
|
+
$version = $Matches[1]
|
|
160
|
+
if ($version -ge $MIN_GO_VERSION) {
|
|
161
|
+
Success "Go $version"
|
|
162
|
+
return $true
|
|
163
|
+
}
|
|
164
|
+
Warn "Go $version is too old (need $MIN_GO_VERSION+)"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return $false
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function Install-Go {
|
|
171
|
+
Info "Installing Go..."
|
|
172
|
+
$pm = Get-PackageManager
|
|
173
|
+
|
|
174
|
+
switch ($pm) {
|
|
175
|
+
"winget" {
|
|
176
|
+
winget install GoLang.Go --accept-package-agreements --accept-source-agreements
|
|
177
|
+
}
|
|
178
|
+
"choco" {
|
|
179
|
+
choco install golang -y
|
|
180
|
+
}
|
|
181
|
+
default {
|
|
182
|
+
Error-Exit "Please install winget or chocolatey, or install Go manually from https://go.dev/dl/"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
# Refresh PATH
|
|
187
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
188
|
+
|
|
189
|
+
if (-not (Check-Go)) {
|
|
190
|
+
Error-Exit "Failed to install Go. Please install manually and restart PowerShell."
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function Check-Git {
|
|
195
|
+
if (Has-Command "git") {
|
|
196
|
+
$version = (git --version) -replace "git version ", ""
|
|
197
|
+
Success "Git $version"
|
|
198
|
+
return $true
|
|
199
|
+
}
|
|
200
|
+
return $false
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function Install-Git {
|
|
204
|
+
Info "Installing Git..."
|
|
205
|
+
$pm = Get-PackageManager
|
|
206
|
+
|
|
207
|
+
switch ($pm) {
|
|
208
|
+
"winget" {
|
|
209
|
+
winget install Git.Git --accept-package-agreements --accept-source-agreements
|
|
210
|
+
}
|
|
211
|
+
"choco" {
|
|
212
|
+
choco install git -y
|
|
213
|
+
}
|
|
214
|
+
default {
|
|
215
|
+
Error-Exit "Please install winget or chocolatey, or install Git manually from https://git-scm.com/"
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
# Refresh PATH
|
|
220
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
221
|
+
|
|
222
|
+
if (-not (Check-Git)) {
|
|
223
|
+
Error-Exit "Failed to install Git. Please install manually and restart PowerShell."
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
# =============================================================================
|
|
228
|
+
# MachinaOS Installation
|
|
229
|
+
# =============================================================================
|
|
230
|
+
|
|
231
|
+
function Install-MachinaOS {
|
|
232
|
+
Write-Host ""
|
|
233
|
+
Info "Installing MachinaOS to $INSTALL_DIR..."
|
|
234
|
+
|
|
235
|
+
# Create install directory
|
|
236
|
+
if (-not (Test-Path $INSTALL_DIR)) {
|
|
237
|
+
New-Item -ItemType Directory -Path $INSTALL_DIR -Force | Out-Null
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
# Clone or update repository
|
|
241
|
+
if (Test-Path "$INSTALL_DIR\.git") {
|
|
242
|
+
Info "Updating existing installation..."
|
|
243
|
+
Push-Location $INSTALL_DIR
|
|
244
|
+
git pull origin main
|
|
245
|
+
} else {
|
|
246
|
+
Info "Cloning repository..."
|
|
247
|
+
git clone $REPO_URL $INSTALL_DIR
|
|
248
|
+
Push-Location $INSTALL_DIR
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
# Run build
|
|
252
|
+
Info "Building MachinaOS..."
|
|
253
|
+
npm run build
|
|
254
|
+
|
|
255
|
+
Pop-Location
|
|
256
|
+
|
|
257
|
+
# Add to PATH suggestion
|
|
258
|
+
$binPath = "$INSTALL_DIR\bin"
|
|
259
|
+
if ($env:Path -notlike "*$binPath*") {
|
|
260
|
+
Warn "Add MachinaOS to your PATH:"
|
|
261
|
+
Write-Host ""
|
|
262
|
+
Write-Host " # Run this command to add to PATH permanently:"
|
|
263
|
+
Write-Host " [Environment]::SetEnvironmentVariable('Path', `$env:Path + ';$binPath', 'User')"
|
|
264
|
+
Write-Host ""
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# =============================================================================
|
|
269
|
+
# Main Installation Flow
|
|
270
|
+
# =============================================================================
|
|
271
|
+
|
|
272
|
+
function Main {
|
|
273
|
+
Write-Host ""
|
|
274
|
+
Info "Checking dependencies..."
|
|
275
|
+
Write-Host ""
|
|
276
|
+
|
|
277
|
+
# Check and install dependencies
|
|
278
|
+
if (-not (Check-Git)) { Install-Git }
|
|
279
|
+
if (-not (Check-Node)) { Install-Node }
|
|
280
|
+
if (-not (Check-Python)) { Install-Python }
|
|
281
|
+
if (-not (Check-Uv)) { Install-Uv }
|
|
282
|
+
if (-not (Check-Go)) { Install-Go }
|
|
283
|
+
|
|
284
|
+
# Install MachinaOS
|
|
285
|
+
Install-MachinaOS
|
|
286
|
+
|
|
287
|
+
Write-Host ""
|
|
288
|
+
Write-Color "============================================" "Green"
|
|
289
|
+
Write-Color " MachinaOS installed successfully!" "Green"
|
|
290
|
+
Write-Color "============================================" "Green"
|
|
291
|
+
Write-Host ""
|
|
292
|
+
Write-Host " Start MachinaOS:"
|
|
293
|
+
Write-Host " cd $INSTALL_DIR"
|
|
294
|
+
Write-Host " npm run start"
|
|
295
|
+
Write-Host ""
|
|
296
|
+
Write-Host " Or use the CLI:"
|
|
297
|
+
Write-Host " node $INSTALL_DIR\bin\cli.js start"
|
|
298
|
+
Write-Host ""
|
|
299
|
+
Write-Host " Open in browser:"
|
|
300
|
+
Write-Host " http://localhost:3000"
|
|
301
|
+
Write-Host ""
|
|
302
|
+
Write-Host " Documentation:"
|
|
303
|
+
Write-Host " https://github.com/trohitg/MachinaOS"
|
|
304
|
+
Write-Host ""
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
# Run main
|
|
308
|
+
Main
|
package/install.sh
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# MachinaOS Installer
|
|
3
|
+
# Usage: curl -fsSL https://raw.githubusercontent.com/trohitg/MachinaOS/main/install.sh | bash
|
|
4
|
+
#
|
|
5
|
+
# This script installs MachinaOS and its dependencies:
|
|
6
|
+
# - Node.js 18+ (if not installed)
|
|
7
|
+
# - Python 3.11+ (if not installed)
|
|
8
|
+
# - uv (Python package manager)
|
|
9
|
+
# - Go 1.21+ (for WhatsApp service)
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
# Colors
|
|
14
|
+
RED='\033[0;31m'
|
|
15
|
+
GREEN='\033[0;32m'
|
|
16
|
+
YELLOW='\033[1;33m'
|
|
17
|
+
BLUE='\033[0;34m'
|
|
18
|
+
CYAN='\033[0;36m'
|
|
19
|
+
NC='\033[0m' # No Color
|
|
20
|
+
|
|
21
|
+
# Configuration
|
|
22
|
+
REPO_URL="https://github.com/trohitg/MachinaOS.git"
|
|
23
|
+
INSTALL_DIR="${MACHINAOS_HOME:-$HOME/.machinaos}"
|
|
24
|
+
MIN_NODE_VERSION=18
|
|
25
|
+
MIN_PYTHON_VERSION="3.11"
|
|
26
|
+
MIN_GO_VERSION="1.21"
|
|
27
|
+
|
|
28
|
+
# Logging functions
|
|
29
|
+
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
30
|
+
success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
31
|
+
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
32
|
+
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
|
|
33
|
+
|
|
34
|
+
# Banner
|
|
35
|
+
echo -e "${CYAN}"
|
|
36
|
+
echo " __ __ _ _ ___ ____ "
|
|
37
|
+
echo " | \/ | __ _ ___| |__ (_)_ __ __ _/ _ \/ ___| "
|
|
38
|
+
echo " | |\/| |/ _\` |/ __| '_ \| | '_ \ / _\` | | | \___ \\ "
|
|
39
|
+
echo " | | | | (_| | (__| | | | | | | | (_| | |_| |___) |"
|
|
40
|
+
echo " |_| |_|\__,_|\___|_| |_|_|_| |_|\__,_|\___/|____/ "
|
|
41
|
+
echo -e "${NC}"
|
|
42
|
+
echo "Open-source workflow automation with AI agents"
|
|
43
|
+
echo ""
|
|
44
|
+
|
|
45
|
+
# Detect OS
|
|
46
|
+
detect_os() {
|
|
47
|
+
case "$(uname -s)" in
|
|
48
|
+
Linux*) OS="linux";;
|
|
49
|
+
Darwin*) OS="macos";;
|
|
50
|
+
MINGW*|MSYS*|CYGWIN*) OS="windows";;
|
|
51
|
+
*) error "Unsupported operating system: $(uname -s)";;
|
|
52
|
+
esac
|
|
53
|
+
|
|
54
|
+
# Detect architecture
|
|
55
|
+
case "$(uname -m)" in
|
|
56
|
+
x86_64|amd64) ARCH="x64";;
|
|
57
|
+
arm64|aarch64) ARCH="arm64";;
|
|
58
|
+
*) error "Unsupported architecture: $(uname -m)";;
|
|
59
|
+
esac
|
|
60
|
+
|
|
61
|
+
info "Detected: $OS ($ARCH)"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Check if command exists
|
|
65
|
+
has_cmd() {
|
|
66
|
+
command -v "$1" &> /dev/null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# Get version number from string
|
|
70
|
+
get_version() {
|
|
71
|
+
echo "$1" | grep -oE '[0-9]+\.[0-9]+' | head -1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Compare versions (returns 0 if $1 >= $2)
|
|
75
|
+
version_gte() {
|
|
76
|
+
[ "$(printf '%s\n' "$2" "$1" | sort -V | head -n1)" = "$2" ]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# =============================================================================
|
|
80
|
+
# Dependency Checks and Installation
|
|
81
|
+
# =============================================================================
|
|
82
|
+
|
|
83
|
+
check_node() {
|
|
84
|
+
if has_cmd node; then
|
|
85
|
+
NODE_VERSION=$(node --version | sed 's/v//')
|
|
86
|
+
NODE_MAJOR=$(echo "$NODE_VERSION" | cut -d. -f1)
|
|
87
|
+
if [ "$NODE_MAJOR" -ge "$MIN_NODE_VERSION" ]; then
|
|
88
|
+
success "Node.js v$NODE_VERSION"
|
|
89
|
+
return 0
|
|
90
|
+
else
|
|
91
|
+
warn "Node.js v$NODE_VERSION is too old (need v$MIN_NODE_VERSION+)"
|
|
92
|
+
fi
|
|
93
|
+
fi
|
|
94
|
+
return 1
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
install_node() {
|
|
98
|
+
info "Installing Node.js..."
|
|
99
|
+
|
|
100
|
+
if [ "$OS" = "macos" ]; then
|
|
101
|
+
if has_cmd brew; then
|
|
102
|
+
brew install node@20
|
|
103
|
+
else
|
|
104
|
+
error "Please install Homebrew first: https://brew.sh/"
|
|
105
|
+
fi
|
|
106
|
+
elif [ "$OS" = "linux" ]; then
|
|
107
|
+
# Use NodeSource for latest Node.js
|
|
108
|
+
if has_cmd curl; then
|
|
109
|
+
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
|
110
|
+
sudo apt-get install -y nodejs
|
|
111
|
+
else
|
|
112
|
+
error "curl is required. Install with: sudo apt install curl"
|
|
113
|
+
fi
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
check_node || error "Failed to install Node.js"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
check_python() {
|
|
120
|
+
local py_cmd=""
|
|
121
|
+
|
|
122
|
+
# Try python3 first, then python
|
|
123
|
+
for cmd in python3 python; do
|
|
124
|
+
if has_cmd "$cmd"; then
|
|
125
|
+
PY_VERSION=$($cmd --version 2>&1 | grep -oE '[0-9]+\.[0-9]+')
|
|
126
|
+
if version_gte "$PY_VERSION" "$MIN_PYTHON_VERSION"; then
|
|
127
|
+
success "Python $PY_VERSION ($cmd)"
|
|
128
|
+
PYTHON_CMD="$cmd"
|
|
129
|
+
return 0
|
|
130
|
+
fi
|
|
131
|
+
fi
|
|
132
|
+
done
|
|
133
|
+
|
|
134
|
+
warn "Python $MIN_PYTHON_VERSION+ not found"
|
|
135
|
+
return 1
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
install_python() {
|
|
139
|
+
info "Installing Python..."
|
|
140
|
+
|
|
141
|
+
if [ "$OS" = "macos" ]; then
|
|
142
|
+
if has_cmd brew; then
|
|
143
|
+
brew install python@3.12
|
|
144
|
+
else
|
|
145
|
+
error "Please install Homebrew first: https://brew.sh/"
|
|
146
|
+
fi
|
|
147
|
+
elif [ "$OS" = "linux" ]; then
|
|
148
|
+
if has_cmd apt; then
|
|
149
|
+
sudo apt update
|
|
150
|
+
sudo apt install -y python3.12 python3.12-venv python3-pip
|
|
151
|
+
elif has_cmd dnf; then
|
|
152
|
+
sudo dnf install -y python3.12
|
|
153
|
+
elif has_cmd pacman; then
|
|
154
|
+
sudo pacman -S --noconfirm python
|
|
155
|
+
else
|
|
156
|
+
error "Please install Python manually from https://python.org/"
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
check_python || error "Failed to install Python"
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
check_uv() {
|
|
164
|
+
if has_cmd uv; then
|
|
165
|
+
UV_VERSION=$(uv --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
|
|
166
|
+
success "uv $UV_VERSION"
|
|
167
|
+
return 0
|
|
168
|
+
fi
|
|
169
|
+
return 1
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
install_uv() {
|
|
173
|
+
info "Installing uv (Python package manager)..."
|
|
174
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
175
|
+
|
|
176
|
+
# Add to PATH for current session
|
|
177
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
178
|
+
|
|
179
|
+
check_uv || error "Failed to install uv"
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
check_go() {
|
|
183
|
+
if has_cmd go; then
|
|
184
|
+
GO_VERSION=$(go version | grep -oE 'go[0-9]+\.[0-9]+' | sed 's/go//')
|
|
185
|
+
if version_gte "$GO_VERSION" "$MIN_GO_VERSION"; then
|
|
186
|
+
success "Go $GO_VERSION"
|
|
187
|
+
return 0
|
|
188
|
+
else
|
|
189
|
+
warn "Go $GO_VERSION is too old (need $MIN_GO_VERSION+)"
|
|
190
|
+
fi
|
|
191
|
+
fi
|
|
192
|
+
return 1
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
install_go() {
|
|
196
|
+
info "Installing Go..."
|
|
197
|
+
|
|
198
|
+
if [ "$OS" = "macos" ]; then
|
|
199
|
+
if has_cmd brew; then
|
|
200
|
+
brew install go
|
|
201
|
+
else
|
|
202
|
+
error "Please install Homebrew first: https://brew.sh/"
|
|
203
|
+
fi
|
|
204
|
+
elif [ "$OS" = "linux" ]; then
|
|
205
|
+
if has_cmd apt; then
|
|
206
|
+
sudo apt update
|
|
207
|
+
sudo apt install -y golang-go
|
|
208
|
+
elif has_cmd dnf; then
|
|
209
|
+
sudo dnf install -y golang
|
|
210
|
+
elif has_cmd pacman; then
|
|
211
|
+
sudo pacman -S --noconfirm go
|
|
212
|
+
else
|
|
213
|
+
# Manual install
|
|
214
|
+
GO_TAR="go1.21.13.linux-${ARCH}.tar.gz"
|
|
215
|
+
curl -LO "https://go.dev/dl/$GO_TAR"
|
|
216
|
+
sudo rm -rf /usr/local/go
|
|
217
|
+
sudo tar -C /usr/local -xzf "$GO_TAR"
|
|
218
|
+
rm "$GO_TAR"
|
|
219
|
+
export PATH="$PATH:/usr/local/go/bin"
|
|
220
|
+
fi
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
check_go || error "Failed to install Go"
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
check_git() {
|
|
227
|
+
if has_cmd git; then
|
|
228
|
+
GIT_VERSION=$(git --version | grep -oE '[0-9]+\.[0-9]+')
|
|
229
|
+
success "Git $GIT_VERSION"
|
|
230
|
+
return 0
|
|
231
|
+
fi
|
|
232
|
+
return 1
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
install_git() {
|
|
236
|
+
info "Installing Git..."
|
|
237
|
+
|
|
238
|
+
if [ "$OS" = "macos" ]; then
|
|
239
|
+
xcode-select --install 2>/dev/null || true
|
|
240
|
+
elif [ "$OS" = "linux" ]; then
|
|
241
|
+
if has_cmd apt; then
|
|
242
|
+
sudo apt update && sudo apt install -y git
|
|
243
|
+
elif has_cmd dnf; then
|
|
244
|
+
sudo dnf install -y git
|
|
245
|
+
elif has_cmd pacman; then
|
|
246
|
+
sudo pacman -S --noconfirm git
|
|
247
|
+
fi
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
check_git || error "Failed to install Git"
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
# =============================================================================
|
|
254
|
+
# MachinaOS Installation
|
|
255
|
+
# =============================================================================
|
|
256
|
+
|
|
257
|
+
install_machinaos() {
|
|
258
|
+
echo ""
|
|
259
|
+
info "Installing MachinaOS to $INSTALL_DIR..."
|
|
260
|
+
|
|
261
|
+
# Create install directory
|
|
262
|
+
mkdir -p "$INSTALL_DIR"
|
|
263
|
+
|
|
264
|
+
# Clone or update repository
|
|
265
|
+
if [ -d "$INSTALL_DIR/.git" ]; then
|
|
266
|
+
info "Updating existing installation..."
|
|
267
|
+
cd "$INSTALL_DIR"
|
|
268
|
+
git pull origin main
|
|
269
|
+
else
|
|
270
|
+
info "Cloning repository..."
|
|
271
|
+
git clone "$REPO_URL" "$INSTALL_DIR"
|
|
272
|
+
cd "$INSTALL_DIR"
|
|
273
|
+
fi
|
|
274
|
+
|
|
275
|
+
# Run build
|
|
276
|
+
info "Building MachinaOS..."
|
|
277
|
+
npm run build
|
|
278
|
+
|
|
279
|
+
# Create symlink for global command
|
|
280
|
+
info "Creating global command..."
|
|
281
|
+
|
|
282
|
+
SYMLINK_DIR="$HOME/.local/bin"
|
|
283
|
+
mkdir -p "$SYMLINK_DIR"
|
|
284
|
+
|
|
285
|
+
# Remove old symlink if exists
|
|
286
|
+
rm -f "$SYMLINK_DIR/machinaos"
|
|
287
|
+
|
|
288
|
+
# Create new symlink
|
|
289
|
+
ln -s "$INSTALL_DIR/bin/cli.js" "$SYMLINK_DIR/machinaos"
|
|
290
|
+
chmod +x "$INSTALL_DIR/bin/cli.js"
|
|
291
|
+
|
|
292
|
+
# Check if PATH includes ~/.local/bin
|
|
293
|
+
if [[ ":$PATH:" != *":$SYMLINK_DIR:"* ]]; then
|
|
294
|
+
warn "Add $SYMLINK_DIR to your PATH:"
|
|
295
|
+
echo ""
|
|
296
|
+
echo " # Add to ~/.bashrc or ~/.zshrc:"
|
|
297
|
+
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
|
|
298
|
+
echo ""
|
|
299
|
+
fi
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
# =============================================================================
|
|
303
|
+
# Main Installation Flow
|
|
304
|
+
# =============================================================================
|
|
305
|
+
|
|
306
|
+
main() {
|
|
307
|
+
detect_os
|
|
308
|
+
|
|
309
|
+
echo ""
|
|
310
|
+
info "Checking dependencies..."
|
|
311
|
+
echo ""
|
|
312
|
+
|
|
313
|
+
# Check and install dependencies
|
|
314
|
+
check_git || install_git
|
|
315
|
+
check_node || install_node
|
|
316
|
+
check_python || install_python
|
|
317
|
+
check_uv || install_uv
|
|
318
|
+
check_go || install_go
|
|
319
|
+
|
|
320
|
+
# Install MachinaOS
|
|
321
|
+
install_machinaos
|
|
322
|
+
|
|
323
|
+
echo ""
|
|
324
|
+
echo -e "${GREEN}============================================${NC}"
|
|
325
|
+
echo -e "${GREEN} MachinaOS installed successfully!${NC}"
|
|
326
|
+
echo -e "${GREEN}============================================${NC}"
|
|
327
|
+
echo ""
|
|
328
|
+
echo " Start MachinaOS:"
|
|
329
|
+
echo " cd $INSTALL_DIR && npm run start"
|
|
330
|
+
echo ""
|
|
331
|
+
echo " Or use the global command (after adding to PATH):"
|
|
332
|
+
echo " machinaos start"
|
|
333
|
+
echo ""
|
|
334
|
+
echo " Open in browser:"
|
|
335
|
+
echo " http://localhost:3000"
|
|
336
|
+
echo ""
|
|
337
|
+
echo " Documentation:"
|
|
338
|
+
echo " https://github.com/trohitg/MachinaOS"
|
|
339
|
+
echo ""
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
# Run main
|
|
343
|
+
main "$@"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "machinaos",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "Open source workflow automation platform with AI agents, React Flow, and n8n-inspired architecture",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -38,7 +38,9 @@
|
|
|
38
38
|
"client/",
|
|
39
39
|
"server/",
|
|
40
40
|
".env.template",
|
|
41
|
-
"README.md"
|
|
41
|
+
"README.md",
|
|
42
|
+
"install.sh",
|
|
43
|
+
"install.ps1"
|
|
42
44
|
],
|
|
43
45
|
"workspaces": [
|
|
44
46
|
"client"
|
|
@@ -68,7 +70,8 @@
|
|
|
68
70
|
"docker:prod:logs": "docker-compose -f docker-compose.prod.yml logs -f",
|
|
69
71
|
"deploy": "bash deploy.sh",
|
|
70
72
|
"deploy:gcp": "bash deploy.sh",
|
|
71
|
-
"prepublishOnly": "node -e \"const p=require('./package.json'); if(!p.bin||!p.version){process.exit(1)}\""
|
|
73
|
+
"prepublishOnly": "node -e \"const p=require('./package.json'); if(!p.bin||!p.version){process.exit(1)}\"",
|
|
74
|
+
"postinstall": "node scripts/postinstall.js"
|
|
72
75
|
},
|
|
73
76
|
"dependencies": {
|
|
74
77
|
"concurrently": "^9.2.1",
|
package/scripts/build.js
CHANGED
|
@@ -20,6 +20,18 @@ const ROOT = resolve(__dirname, '..');
|
|
|
20
20
|
const isWindows = process.platform === 'win32';
|
|
21
21
|
const isMac = process.platform === 'darwin';
|
|
22
22
|
|
|
23
|
+
// Environment detection
|
|
24
|
+
// - postinstall: npm already installed root deps, skip to avoid infinite loop
|
|
25
|
+
// - CI: GitHub Actions handles build separately, skip postinstall entirely
|
|
26
|
+
const isPostInstall = process.env.npm_lifecycle_event === 'postinstall';
|
|
27
|
+
const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
|
|
28
|
+
|
|
29
|
+
// Skip build entirely in CI (workflows handle this)
|
|
30
|
+
if (isCI && isPostInstall) {
|
|
31
|
+
console.log('CI environment detected, skipping postinstall build.');
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
// Ensure Python UTF-8 encoding
|
|
24
36
|
process.env.PYTHONUTF8 = '1';
|
|
25
37
|
|
|
@@ -49,11 +61,9 @@ function log(step, msg) {
|
|
|
49
61
|
}
|
|
50
62
|
|
|
51
63
|
function npmInstall(cwd = ROOT) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
execSync('npm install', { cwd, stdio: 'inherit', shell: true });
|
|
56
|
-
}
|
|
64
|
+
// Use npm install directly with visible output
|
|
65
|
+
// npm ci requires package-lock.json which may not exist in all directories
|
|
66
|
+
execSync('npm install', { cwd, stdio: 'inherit', shell: true });
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
// ============================================================================
|
|
@@ -231,9 +241,13 @@ try {
|
|
|
231
241
|
log('0/5', 'Created .env from template');
|
|
232
242
|
}
|
|
233
243
|
|
|
234
|
-
// Step 1: Install root dependencies
|
|
235
|
-
|
|
236
|
-
|
|
244
|
+
// Step 1: Install root dependencies (skip if postinstall - npm already did this)
|
|
245
|
+
if (!isPostInstall) {
|
|
246
|
+
log('1/6', 'Installing root dependencies...');
|
|
247
|
+
npmInstall(ROOT);
|
|
248
|
+
} else {
|
|
249
|
+
log('1/6', 'Root dependencies already installed by npm');
|
|
250
|
+
}
|
|
237
251
|
|
|
238
252
|
// Step 2: Install client dependencies
|
|
239
253
|
log('2/6', 'Installing client dependencies...');
|
|
@@ -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,100 @@
|
|
|
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 output to stderr
|
|
41
|
+
function runScript(scriptPath) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
const child = spawn(process.execPath, [scriptPath], {
|
|
44
|
+
cwd: ROOT,
|
|
45
|
+
stdio: ['inherit', process.stderr, 'inherit'],
|
|
46
|
+
env: { ...process.env, FORCE_COLOR: '1' }
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
child.on('error', reject);
|
|
50
|
+
child.on('close', (code) => {
|
|
51
|
+
if (code === 0) {
|
|
52
|
+
resolve();
|
|
53
|
+
} else {
|
|
54
|
+
reject(new Error(`Script exited with code ${code}`));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function main() {
|
|
61
|
+
try {
|
|
62
|
+
// Step 1: Try to download pre-built binaries (optional, non-fatal)
|
|
63
|
+
print('[1/2] Checking for pre-built binaries...');
|
|
64
|
+
try {
|
|
65
|
+
await runScript(resolve(__dirname, 'download-binaries.js'));
|
|
66
|
+
} catch (e) {
|
|
67
|
+
print(' Binary download skipped or failed, will build from source.');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Step 2: Run the full build
|
|
71
|
+
print('');
|
|
72
|
+
print('[2/2] Building MachinaOS...');
|
|
73
|
+
print('');
|
|
74
|
+
await runScript(resolve(__dirname, 'build.js'));
|
|
75
|
+
|
|
76
|
+
print('');
|
|
77
|
+
print('========================================');
|
|
78
|
+
print(' MachinaOS installed successfully!');
|
|
79
|
+
print('========================================');
|
|
80
|
+
print('');
|
|
81
|
+
print('Run: machinaos start');
|
|
82
|
+
print('Open: http://localhost:3000');
|
|
83
|
+
print('');
|
|
84
|
+
|
|
85
|
+
} catch (err) {
|
|
86
|
+
print('');
|
|
87
|
+
print('========================================');
|
|
88
|
+
print(' Installation failed!');
|
|
89
|
+
print('========================================');
|
|
90
|
+
print('');
|
|
91
|
+
print(`Error: ${err.message}`);
|
|
92
|
+
print('');
|
|
93
|
+
print('Try running manually:');
|
|
94
|
+
print(' machinaos build');
|
|
95
|
+
print('');
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
main();
|
package/server/uv.lock
CHANGED
|
@@ -2582,15 +2582,15 @@ wheels = [
|
|
|
2582
2582
|
|
|
2583
2583
|
[[package]]
|
|
2584
2584
|
name = "sqlmodel"
|
|
2585
|
-
version = "0.0.
|
|
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/
|
|
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/
|
|
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]]
|
|
Binary file
|
|
@@ -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
|
|
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
|
-
|
|
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
|
}
|