@conversionpros/aiva 1.0.1 → 2.0.0
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/bin/aiva.js +26 -14
- package/lib/bluebubbles.js +145 -0
- package/lib/config-gen.js +253 -0
- package/lib/constants.js +72 -0
- package/lib/launch-agent.js +112 -0
- package/lib/prerequisites.js +236 -0
- package/lib/process.js +59 -145
- package/lib/setup.js +224 -194
- package/lib/validate.js +194 -0
- package/package.json +7 -32
- package/auto-deploy.js +0 -190
- package/cli-sync.js +0 -126
- package/d2a-prompt-template.txt +0 -106
- package/diagnostics-api.js +0 -304
- package/docs/ara-dedup-fix-scope.md +0 -112
- package/docs/ara-fix-round2-scope.md +0 -61
- package/docs/ara-greeting-fix-scope.md +0 -70
- package/docs/calendar-date-fix-scope.md +0 -28
- package/docs/getting-started.md +0 -115
- package/docs/network-architecture-rollout-scope.md +0 -43
- package/docs/scope-google-oauth-integration.md +0 -351
- package/docs/settings-page-scope.md +0 -50
- package/docs/xai-imagine-scope.md +0 -116
- package/docs/xai-voice-integration-scope.md +0 -115
- package/docs/xai-voice-tools-scope.md +0 -165
- package/email-router.js +0 -512
- package/follow-up-handler.js +0 -606
- package/gateway-monitor.js +0 -158
- package/google-email.js +0 -379
- package/google-oauth.js +0 -310
- package/grok-imagine.js +0 -97
- package/health-reporter.js +0 -287
- package/invisible-prefix-base.txt +0 -206
- package/invisible-prefix-owner.txt +0 -26
- package/invisible-prefix-slim.txt +0 -10
- package/invisible-prefix.txt +0 -43
- package/knowledge-base.js +0 -472
- package/lib/cli.js +0 -19
- package/lib/server.js +0 -42
- package/meta-capi.js +0 -206
- package/meta-leads.js +0 -411
- package/notion-oauth.js +0 -323
- package/public/agent-config.html +0 -241
- package/public/aiva-avatar-anime.png +0 -0
- package/public/css/docs.css.bak +0 -688
- package/public/css/onboarding.css +0 -543
- package/public/diagrams/claude-subscription-pool.html +0 -329
- package/public/diagrams/claude-subscription-pool.png +0 -0
- package/public/docs-icon.png +0 -0
- package/public/escalation.html +0 -237
- package/public/group-config.html +0 -300
- package/public/icon-192.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/icons/agents.svg +0 -1
- package/public/icons/attach.svg +0 -1
- package/public/icons/characters.svg +0 -1
- package/public/icons/chat.svg +0 -1
- package/public/icons/docs.svg +0 -1
- package/public/icons/heartbeat.svg +0 -1
- package/public/icons/messages.svg +0 -1
- package/public/icons/mic.svg +0 -1
- package/public/icons/notes.svg +0 -1
- package/public/icons/settings.svg +0 -1
- package/public/icons/tasks.svg +0 -1
- package/public/images/onboarding/p0-communication-layer.png +0 -0
- package/public/images/onboarding/p0-infinite-surface.png +0 -0
- package/public/images/onboarding/p0-learning-model.png +0 -0
- package/public/images/onboarding/p0-meet-aiva.png +0 -0
- package/public/images/onboarding/p4-contact-intelligence.png +0 -0
- package/public/images/onboarding/p4-context-compounds.png +0 -0
- package/public/images/onboarding/p4-message-router.png +0 -0
- package/public/images/onboarding/p4-per-contact-rules.png +0 -0
- package/public/images/onboarding/p4-send-messages.png +0 -0
- package/public/images/onboarding/p6-be-precise.png +0 -0
- package/public/images/onboarding/p6-review-escalations.png +0 -0
- package/public/images/onboarding/p6-voice-input.png +0 -0
- package/public/images/onboarding/p7-completion.png +0 -0
- package/public/index.html +0 -11594
- package/public/js/onboarding.js +0 -699
- package/public/manifest.json +0 -24
- package/public/messages-v2.html +0 -2824
- package/public/permission-approve.html.bak +0 -107
- package/public/permissions.html +0 -150
- package/public/styles/design-system.css +0 -68
- package/router-db.js +0 -604
- package/router-utils.js +0 -28
- package/router-v2/adapters/imessage.js +0 -191
- package/router-v2/adapters/quo.js +0 -82
- package/router-v2/adapters/whatsapp.js +0 -192
- package/router-v2/contact-manager.js +0 -234
- package/router-v2/conversation-engine.js +0 -498
- package/router-v2/data/knowledge-base.json +0 -176
- package/router-v2/data/router-v2.db +0 -0
- package/router-v2/data/router-v2.db-shm +0 -0
- package/router-v2/data/router-v2.db-wal +0 -0
- package/router-v2/data/router.db +0 -0
- package/router-v2/db.js +0 -457
- package/router-v2/escalation-bridge.js +0 -540
- package/router-v2/follow-up-engine.js +0 -347
- package/router-v2/index.js +0 -441
- package/router-v2/ingestion.js +0 -213
- package/router-v2/knowledge-base.js +0 -231
- package/router-v2/lead-qualifier.js +0 -152
- package/router-v2/learning-loop.js +0 -202
- package/router-v2/outbound-sender.js +0 -160
- package/router-v2/package.json +0 -13
- package/router-v2/permission-gate.js +0 -86
- package/router-v2/playbook.js +0 -177
- package/router-v2/prompts/base.js +0 -52
- package/router-v2/prompts/first-contact.js +0 -38
- package/router-v2/prompts/lead-qualification.js +0 -37
- package/router-v2/prompts/scheduling.js +0 -72
- package/router-v2/prompts/style-overrides.js +0 -22
- package/router-v2/scheduler.js +0 -301
- package/router-v2/scripts/migrate-v1-to-v2.js +0 -215
- package/router-v2/scripts/seed-faq.js +0 -67
- package/router-v2/seed-knowledge-base.js +0 -39
- package/router-v2/utils/ai.js +0 -129
- package/router-v2/utils/phone.js +0 -52
- package/router-v2/utils/response-validator.js +0 -98
- package/router-v2/utils/sanitize.js +0 -222
- package/router.js +0 -5005
- package/routes/google-calendar.js +0 -186
- package/scripts/deploy.sh +0 -62
- package/scripts/macos-calendar.sh +0 -232
- package/scripts/onboard-device.sh +0 -466
- package/server.js +0 -5131
- package/start.sh +0 -24
- package/templates/AGENTS.md +0 -548
- package/templates/IDENTITY.md +0 -15
- package/templates/docs-agents.html +0 -132
- package/templates/docs-app.html +0 -130
- package/templates/docs-home.html +0 -83
- package/templates/docs-imessage.html +0 -121
- package/templates/docs-tasks.html +0 -123
- package/templates/docs-tips.html +0 -175
- package/templates/getting-started.html +0 -809
- package/templates/invisible-prefix-base.txt +0 -171
- package/templates/invisible-prefix-owner.txt +0 -282
- package/templates/invisible-prefix.txt +0 -338
- package/templates/manifest.json +0 -61
- package/templates/memory-org/clients.md +0 -7
- package/templates/memory-org/credentials.md +0 -9
- package/templates/memory-org/devices.md +0 -7
- package/templates/updates.html +0 -464
- package/tts-proxy.js +0 -96
- package/voice-call-local.js +0 -731
- package/voice-call.js +0 -732
- package/wa-listener.js +0 -354
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const pc = require('picocolors');
|
|
5
|
+
|
|
6
|
+
function commandExists(cmd) {
|
|
7
|
+
try {
|
|
8
|
+
execSync(`which ${cmd}`, { stdio: 'pipe' });
|
|
9
|
+
return true;
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getNodeMajor() {
|
|
16
|
+
return parseInt(process.versions.node.split('.')[0], 10);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function section(title) {
|
|
20
|
+
console.log();
|
|
21
|
+
console.log(pc.bold(` ${title}`));
|
|
22
|
+
console.log(pc.dim(' ' + '-'.repeat(40)));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function ok(msg) { console.log(` ${pc.green('+')} ${msg}`); }
|
|
26
|
+
function warn(msg) { console.log(` ${pc.yellow('!')} ${msg}`); }
|
|
27
|
+
function fail(msg) { console.log(` ${pc.red('x')} ${msg}`); }
|
|
28
|
+
function info(msg) { console.log(` ${pc.dim(msg)}`); }
|
|
29
|
+
|
|
30
|
+
async function installPrerequisites() {
|
|
31
|
+
section('System Prerequisites');
|
|
32
|
+
|
|
33
|
+
// Check macOS
|
|
34
|
+
if (process.platform !== 'darwin') {
|
|
35
|
+
fail('This installer requires macOS.');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
ok('macOS detected');
|
|
39
|
+
|
|
40
|
+
// Homebrew
|
|
41
|
+
if (commandExists('brew')) {
|
|
42
|
+
ok('Homebrew installed');
|
|
43
|
+
} else {
|
|
44
|
+
warn('Homebrew not found. Installing...');
|
|
45
|
+
try {
|
|
46
|
+
execSync('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', {
|
|
47
|
+
stdio: 'inherit'
|
|
48
|
+
});
|
|
49
|
+
// Add to PATH for this session
|
|
50
|
+
const brewPaths = ['/opt/homebrew/bin', '/usr/local/bin'];
|
|
51
|
+
for (const p of brewPaths) {
|
|
52
|
+
if (!process.env.PATH.includes(p)) {
|
|
53
|
+
process.env.PATH = `${p}:${process.env.PATH}`;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
ok('Homebrew installed');
|
|
57
|
+
} catch (e) {
|
|
58
|
+
fail(`Homebrew installation failed: ${e.message}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Node.js 18+
|
|
64
|
+
if (getNodeMajor() >= 18) {
|
|
65
|
+
ok(`Node.js ${process.versions.node}`);
|
|
66
|
+
} else {
|
|
67
|
+
warn(`Node.js ${process.versions.node} is too old. Installing latest via Homebrew...`);
|
|
68
|
+
try {
|
|
69
|
+
execSync('brew install node', { stdio: 'inherit' });
|
|
70
|
+
ok('Node.js updated');
|
|
71
|
+
} catch (e) {
|
|
72
|
+
fail(`Node.js installation failed: ${e.message}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Git
|
|
78
|
+
if (commandExists('git')) {
|
|
79
|
+
ok('Git installed');
|
|
80
|
+
} else {
|
|
81
|
+
warn('Git not found. Installing...');
|
|
82
|
+
execSync('brew install git', { stdio: 'inherit' });
|
|
83
|
+
ok('Git installed');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// PM2
|
|
87
|
+
if (commandExists('pm2')) {
|
|
88
|
+
ok('PM2 installed');
|
|
89
|
+
} else {
|
|
90
|
+
warn('PM2 not found. Installing globally...');
|
|
91
|
+
try {
|
|
92
|
+
execSync('npm install -g pm2', { stdio: 'inherit' });
|
|
93
|
+
ok('PM2 installed');
|
|
94
|
+
} catch (e) {
|
|
95
|
+
fail(`PM2 installation failed: ${e.message}`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function installTailscale(activationCode) {
|
|
102
|
+
section('Tailscale Network');
|
|
103
|
+
|
|
104
|
+
if (commandExists('tailscale')) {
|
|
105
|
+
ok('Tailscale installed');
|
|
106
|
+
} else {
|
|
107
|
+
warn('Tailscale not found. Installing via Homebrew...');
|
|
108
|
+
try {
|
|
109
|
+
execSync('brew install --cask tailscale', { stdio: 'inherit' });
|
|
110
|
+
ok('Tailscale installed');
|
|
111
|
+
} catch (e) {
|
|
112
|
+
fail(`Tailscale installation failed: ${e.message}`);
|
|
113
|
+
info('Install manually from https://tailscale.com/download');
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Decrypt and join
|
|
119
|
+
const { decryptTailscaleKey } = require('./constants');
|
|
120
|
+
const tsKey = decryptTailscaleKey(activationCode);
|
|
121
|
+
|
|
122
|
+
if (!tsKey) {
|
|
123
|
+
warn('Tailscale auth key not yet configured (placeholder). Skipping auto-join.');
|
|
124
|
+
info('You can join manually: sudo tailscale up --auth-key <key>');
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
execSync(`sudo tailscale up --auth-key ${tsKey}`, { stdio: 'inherit' });
|
|
130
|
+
ok('Joined Tailscale network');
|
|
131
|
+
return true;
|
|
132
|
+
} catch (e) {
|
|
133
|
+
warn(`Tailscale join failed: ${e.message}`);
|
|
134
|
+
info('You can join manually later: sudo tailscale up');
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function installOpenClaw() {
|
|
140
|
+
section('OpenClaw');
|
|
141
|
+
|
|
142
|
+
if (commandExists('openclaw')) {
|
|
143
|
+
const ver = execSync('openclaw --version 2>/dev/null || echo unknown', { stdio: 'pipe' }).toString().trim();
|
|
144
|
+
ok(`OpenClaw already installed (${ver})`);
|
|
145
|
+
} else {
|
|
146
|
+
warn('OpenClaw not found. Installing globally...');
|
|
147
|
+
try {
|
|
148
|
+
execSync('npm install -g openclaw', { stdio: 'inherit' });
|
|
149
|
+
ok('OpenClaw installed');
|
|
150
|
+
} catch (e) {
|
|
151
|
+
fail(`OpenClaw installation failed: ${e.message}`);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function cloneApp() {
|
|
158
|
+
section('AIVA App');
|
|
159
|
+
|
|
160
|
+
const os = require('os');
|
|
161
|
+
const path = require('path');
|
|
162
|
+
const fs = require('fs');
|
|
163
|
+
const appDir = path.join(os.homedir(), '.openclaw', 'workspace', 'aiva-tasks');
|
|
164
|
+
|
|
165
|
+
if (fs.existsSync(path.join(appDir, 'server.js'))) {
|
|
166
|
+
ok(`AIVA app already exists at ${appDir}`);
|
|
167
|
+
info('Pulling latest...');
|
|
168
|
+
try {
|
|
169
|
+
execSync('git pull origin main', { cwd: appDir, stdio: 'pipe' });
|
|
170
|
+
ok('Updated to latest');
|
|
171
|
+
} catch (e) {
|
|
172
|
+
warn(`git pull failed: ${e.message}`);
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
const { GITHUB_CLONE_URL } = require('./constants');
|
|
176
|
+
info(`Cloning AIVA app to ${appDir}...`);
|
|
177
|
+
const parentDir = path.dirname(appDir);
|
|
178
|
+
if (!fs.existsSync(parentDir)) {
|
|
179
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
execSync(`git clone ${GITHUB_CLONE_URL} "${appDir}"`, { stdio: 'pipe' });
|
|
183
|
+
ok('AIVA app cloned');
|
|
184
|
+
} catch (e) {
|
|
185
|
+
fail(`Clone failed: ${e.message}`);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// npm install
|
|
191
|
+
info('Installing dependencies...');
|
|
192
|
+
try {
|
|
193
|
+
execSync('npm install --production', { cwd: appDir, stdio: 'pipe' });
|
|
194
|
+
ok('Dependencies installed');
|
|
195
|
+
} catch (e) {
|
|
196
|
+
warn(`npm install had issues: ${e.message}`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Create message-router directory (SOP requirement)
|
|
200
|
+
const mrDir = path.join(appDir, 'message-router');
|
|
201
|
+
if (!fs.existsSync(mrDir)) {
|
|
202
|
+
fs.mkdirSync(mrDir, { recursive: true });
|
|
203
|
+
ok('Created message-router directory');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return appDir;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function setPowerSettings() {
|
|
210
|
+
section('Power & Sleep Settings');
|
|
211
|
+
info('Setting device to stay awake 24/7...');
|
|
212
|
+
try {
|
|
213
|
+
execSync('sudo pmset -a sleep 0 displaysleep 0 disksleep 0', { stdio: 'pipe' });
|
|
214
|
+
execSync('sudo pmset -a hibernatemode 0', { stdio: 'pipe' });
|
|
215
|
+
execSync('sudo pmset -a womp 1', { stdio: 'pipe' });
|
|
216
|
+
execSync('defaults write com.apple.screensaver idleTime 0', { stdio: 'pipe' });
|
|
217
|
+
ok('Power settings configured (always awake)');
|
|
218
|
+
} catch (e) {
|
|
219
|
+
warn(`Power settings failed (may need sudo): ${e.message}`);
|
|
220
|
+
info('Run manually: sudo pmset -a sleep 0 displaysleep 0 disksleep 0');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
module.exports = {
|
|
225
|
+
installPrerequisites,
|
|
226
|
+
installTailscale,
|
|
227
|
+
installOpenClaw,
|
|
228
|
+
cloneApp,
|
|
229
|
+
setPowerSettings,
|
|
230
|
+
commandExists,
|
|
231
|
+
section,
|
|
232
|
+
ok,
|
|
233
|
+
warn,
|
|
234
|
+
fail,
|
|
235
|
+
info
|
|
236
|
+
};
|
package/lib/process.js
CHANGED
|
@@ -1,127 +1,59 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { execSync
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
6
7
|
const pc = require('picocolors');
|
|
7
|
-
const { loadConfig, getLogsDir, getAivaHome
|
|
8
|
+
const { loadConfig, getLogsDir, getAivaHome } = require('./config');
|
|
8
9
|
const { checkHealth, checkGateway } = require('./health');
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function writeEcosystem() {
|
|
15
|
-
const config = loadConfig();
|
|
16
|
-
const serverPath = path.join(__dirname, 'server.js');
|
|
17
|
-
const ecosystemPath = getEcosystemPath();
|
|
18
|
-
|
|
19
|
-
const content = `module.exports = {
|
|
20
|
-
apps: [{
|
|
21
|
-
name: 'aiva-app',
|
|
22
|
-
script: '${serverPath}',
|
|
23
|
-
cwd: '${getAivaHome()}',
|
|
24
|
-
env: {
|
|
25
|
-
PORT: '${config.port || 3847}',
|
|
26
|
-
AIVA_CONFIG_PATH: '${path.join(getAivaHome(), 'config.json')}',
|
|
27
|
-
AIVA_DATA_DIR: '${getDataDir()}',
|
|
28
|
-
AIVA_UPLOADS_DIR: '${getUploadsDir()}',
|
|
29
|
-
AIVA_LOGS_DIR: '${getLogsDir()}',
|
|
30
|
-
AIVA_HOME: '${getAivaHome()}',
|
|
31
|
-
NODE_ENV: 'production'
|
|
32
|
-
},
|
|
33
|
-
watch: false,
|
|
34
|
-
max_restarts: 10,
|
|
35
|
-
restart_delay: 3000,
|
|
36
|
-
log_file: '${path.join(getLogsDir(), 'aiva.log')}',
|
|
37
|
-
out_file: '${path.join(getLogsDir(), 'aiva-out.log')}',
|
|
38
|
-
error_file: '${path.join(getLogsDir(), 'aiva-error.log')}',
|
|
39
|
-
merge_logs: true,
|
|
40
|
-
time: true
|
|
41
|
-
}]
|
|
42
|
-
};
|
|
43
|
-
`;
|
|
44
|
-
fs.writeFileSync(ecosystemPath, content);
|
|
45
|
-
}
|
|
11
|
+
const APP_DIR = path.join(os.homedir(), '.openclaw', 'workspace', 'aiva-tasks');
|
|
12
|
+
const PLIST_LABEL = 'com.aiva.tasks';
|
|
13
|
+
const PLIST_PATH = path.join(os.homedir(), 'Library', 'LaunchAgents', `${PLIST_LABEL}.plist`);
|
|
46
14
|
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
execSync('which pm2', { stdio: 'pipe' });
|
|
50
|
-
} catch {
|
|
51
|
-
console.log(pc.yellow('PM2 not found. Installing globally...'));
|
|
52
|
-
try {
|
|
53
|
-
execSync('npm install -g pm2', { stdio: 'inherit' });
|
|
54
|
-
} catch (e) {
|
|
55
|
-
console.error(pc.red('Failed to install PM2. Please run: npm install -g pm2'));
|
|
56
|
-
process.exit(1);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
15
|
+
function getUid() {
|
|
16
|
+
return process.getuid ? process.getuid() : 501;
|
|
59
17
|
}
|
|
60
18
|
|
|
61
|
-
async function startServer(
|
|
62
|
-
|
|
63
|
-
const port = config.port || 3847;
|
|
19
|
+
async function startServer() {
|
|
20
|
+
console.log(pc.cyan('Starting AIVA...'));
|
|
64
21
|
|
|
65
|
-
if (
|
|
66
|
-
console.log(pc.
|
|
67
|
-
const serverPath = path.join(__dirname, 'server.js');
|
|
68
|
-
const child = spawn('node', [serverPath], {
|
|
69
|
-
stdio: 'inherit',
|
|
70
|
-
env: {
|
|
71
|
-
...process.env,
|
|
72
|
-
PORT: String(port),
|
|
73
|
-
AIVA_CONFIG_PATH: path.join(getAivaHome(), 'config.json'),
|
|
74
|
-
AIVA_DATA_DIR: getDataDir(),
|
|
75
|
-
AIVA_UPLOADS_DIR: getUploadsDir(),
|
|
76
|
-
AIVA_LOGS_DIR: getLogsDir(),
|
|
77
|
-
AIVA_HOME: getAivaHome()
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
child.on('exit', (code) => process.exit(code));
|
|
22
|
+
if (!fs.existsSync(PLIST_PATH)) {
|
|
23
|
+
console.log(pc.yellow('LaunchAgent plist not found. Run "aiva setup" first.'));
|
|
81
24
|
return;
|
|
82
25
|
}
|
|
83
26
|
|
|
84
|
-
|
|
85
|
-
writeEcosystem();
|
|
86
|
-
|
|
87
|
-
console.log(pc.cyan(`Starting AIVA on port ${port}...`));
|
|
27
|
+
const uid = getUid();
|
|
88
28
|
try {
|
|
89
|
-
execSync(`
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const health = await checkHealth(port);
|
|
93
|
-
if (health.ok) {
|
|
94
|
-
console.log(pc.green(`AIVA is running at http://localhost:${port}`));
|
|
95
|
-
} else {
|
|
96
|
-
console.log(pc.yellow(`AIVA process started but health check pending. Check: aiva logs`));
|
|
97
|
-
}
|
|
29
|
+
execSync(`launchctl bootstrap gui/${uid} "${PLIST_PATH}" 2>/dev/null || true`, { stdio: 'pipe' });
|
|
30
|
+
execSync(`launchctl kickstart -k gui/${uid}/${PLIST_LABEL}`, { stdio: 'pipe' });
|
|
31
|
+
console.log(pc.green('AIVA started via LaunchAgent.'));
|
|
98
32
|
} catch (e) {
|
|
99
|
-
console.error(pc.red('Failed to start
|
|
33
|
+
console.error(pc.red('Failed to start:'), e.message);
|
|
34
|
+
console.log(pc.dim(`Try manually: launchctl kickstart -k gui/${uid}/${PLIST_LABEL}`));
|
|
100
35
|
}
|
|
101
36
|
}
|
|
102
37
|
|
|
103
38
|
function stopServer() {
|
|
104
|
-
ensurePm2();
|
|
105
39
|
console.log(pc.cyan('Stopping AIVA...'));
|
|
106
40
|
try {
|
|
107
|
-
|
|
41
|
+
// Kill port first (SOP requirement)
|
|
42
|
+
execSync('lsof -ti:3847 | xargs kill -9 2>/dev/null || true', { stdio: 'pipe' });
|
|
108
43
|
console.log(pc.green('AIVA stopped.'));
|
|
109
44
|
} catch {
|
|
110
|
-
console.log(pc.yellow('AIVA
|
|
45
|
+
console.log(pc.yellow('AIVA may not be running.'));
|
|
111
46
|
}
|
|
112
47
|
}
|
|
113
48
|
|
|
114
49
|
function restartServer() {
|
|
115
|
-
ensurePm2();
|
|
116
|
-
writeEcosystem();
|
|
117
50
|
console.log(pc.cyan('Restarting AIVA...'));
|
|
51
|
+
// Kill port first (SOP gotcha)
|
|
118
52
|
try {
|
|
119
|
-
execSync('
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
startServer();
|
|
124
|
-
}
|
|
53
|
+
execSync('lsof -ti:3847 | xargs kill -9 2>/dev/null || true', { stdio: 'pipe' });
|
|
54
|
+
} catch { /* ok */ }
|
|
55
|
+
|
|
56
|
+
setTimeout(() => startServer(), 2000);
|
|
125
57
|
}
|
|
126
58
|
|
|
127
59
|
async function getStatus() {
|
|
@@ -130,40 +62,19 @@ async function getStatus() {
|
|
|
130
62
|
const pkg = require('../package.json');
|
|
131
63
|
|
|
132
64
|
console.log(pc.bold(`\n${config.name || 'AIVA'} Status`));
|
|
133
|
-
console.log(pc.dim('
|
|
65
|
+
console.log(pc.dim('-'.repeat(40)));
|
|
134
66
|
console.log(` Version: ${pc.cyan(pkg.version)}`);
|
|
135
67
|
console.log(` Port: ${port}`);
|
|
136
68
|
|
|
137
|
-
//
|
|
138
|
-
let
|
|
139
|
-
let uptime = '-';
|
|
140
|
-
let memory = '-';
|
|
69
|
+
// Check if process is running on port 3847
|
|
70
|
+
let running = false;
|
|
141
71
|
try {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
pm2Status = aiva.pm2_env?.status || 'unknown';
|
|
147
|
-
if (aiva.pm2_env?.pm_uptime) {
|
|
148
|
-
const ms = Date.now() - aiva.pm2_env.pm_uptime;
|
|
149
|
-
const hours = Math.floor(ms / 3600000);
|
|
150
|
-
const mins = Math.floor((ms % 3600000) / 60000);
|
|
151
|
-
uptime = hours > 0 ? `${hours}h ${mins}m` : `${mins}m`;
|
|
152
|
-
}
|
|
153
|
-
if (aiva.monit?.memory) {
|
|
154
|
-
memory = `${Math.round(aiva.monit.memory / 1024 / 1024)}MB`;
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
pm2Status = 'not registered';
|
|
158
|
-
}
|
|
159
|
-
} catch {
|
|
160
|
-
pm2Status = 'pm2 not available';
|
|
161
|
-
}
|
|
72
|
+
const pid = execSync('lsof -ti:3847 2>/dev/null', { stdio: 'pipe' }).toString().trim();
|
|
73
|
+
running = !!pid;
|
|
74
|
+
if (running) console.log(` PID: ${pid}`);
|
|
75
|
+
} catch { /* not running */ }
|
|
162
76
|
|
|
163
|
-
|
|
164
|
-
console.log(` Status: ${statusColor(pm2Status)}`);
|
|
165
|
-
console.log(` Uptime: ${uptime}`);
|
|
166
|
-
console.log(` Memory: ${memory}`);
|
|
77
|
+
console.log(` Status: ${running ? pc.green('Running') : pc.red('Stopped')}`);
|
|
167
78
|
|
|
168
79
|
// Health check
|
|
169
80
|
const health = await checkHealth(port);
|
|
@@ -175,33 +86,36 @@ async function getStatus() {
|
|
|
175
86
|
console.log(` Gateway: ${gw.ok ? pc.green('Connected') : pc.red('Unreachable')}`);
|
|
176
87
|
}
|
|
177
88
|
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
const size = execSync(`du -sh "${getDataDir()}" 2>/dev/null | cut -f1`, { stdio: 'pipe' }).toString().trim();
|
|
181
|
-
console.log(` Data size: ${size || '-'}`);
|
|
182
|
-
} catch {
|
|
183
|
-
console.log(` Data size: -`);
|
|
184
|
-
}
|
|
89
|
+
// LaunchAgent status
|
|
90
|
+
console.log(` LaunchAgent: ${fs.existsSync(PLIST_PATH) ? pc.green('Installed') : pc.yellow('Not installed')}`);
|
|
185
91
|
|
|
186
|
-
console.log(pc.dim('
|
|
92
|
+
console.log(pc.dim('-'.repeat(40)));
|
|
187
93
|
console.log();
|
|
188
94
|
}
|
|
189
95
|
|
|
190
96
|
function getLogs(lines = 50) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
97
|
+
const logFile = '/tmp/aiva-app.log';
|
|
98
|
+
const errFile = '/tmp/aiva-app-err.log';
|
|
99
|
+
|
|
100
|
+
if (fs.existsSync(logFile)) {
|
|
101
|
+
console.log(pc.bold('\n--- stdout ---'));
|
|
102
|
+
try {
|
|
103
|
+
const out = execSync(`tail -n ${lines} "${logFile}"`, { stdio: 'pipe' }).toString();
|
|
104
|
+
console.log(out);
|
|
105
|
+
} catch { console.log(pc.dim('(empty)')); }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (fs.existsSync(errFile)) {
|
|
109
|
+
console.log(pc.bold('--- stderr ---'));
|
|
110
|
+
try {
|
|
111
|
+
const err = execSync(`tail -n ${lines} "${errFile}"`, { stdio: 'pipe' }).toString();
|
|
112
|
+
console.log(err);
|
|
113
|
+
} catch { console.log(pc.dim('(empty)')); }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!fs.existsSync(logFile) && !fs.existsSync(errFile)) {
|
|
117
|
+
console.log(pc.yellow('No logs found. Is AIVA running?'));
|
|
204
118
|
}
|
|
205
119
|
}
|
|
206
120
|
|
|
207
|
-
module.exports = { startServer, stopServer, restartServer, getStatus, getLogs
|
|
121
|
+
module.exports = { startServer, stopServer, restartServer, getStatus, getLogs };
|