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 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: Clone & Run
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 2: Global Install
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
- ### Option 3: Docker
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.6",
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
- try {
53
- execSync('npm ci', { cwd, stdio: 'pipe', shell: true });
54
- } catch {
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
- log('1/6', 'Installing root dependencies...');
236
- npmInstall(ROOT);
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.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
  }