@conversionpros/aiva 1.0.1 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/bin/aiva.js +26 -14
  2. package/lib/bluebubbles.js +145 -0
  3. package/lib/config-gen.js +253 -0
  4. package/lib/constants.js +72 -0
  5. package/lib/launch-agent.js +112 -0
  6. package/lib/prerequisites.js +236 -0
  7. package/lib/process.js +59 -145
  8. package/lib/setup.js +224 -194
  9. package/lib/validate.js +194 -0
  10. package/package.json +9 -34
  11. package/auto-deploy.js +0 -190
  12. package/cli-sync.js +0 -126
  13. package/d2a-prompt-template.txt +0 -106
  14. package/diagnostics-api.js +0 -304
  15. package/docs/ara-dedup-fix-scope.md +0 -112
  16. package/docs/ara-fix-round2-scope.md +0 -61
  17. package/docs/ara-greeting-fix-scope.md +0 -70
  18. package/docs/calendar-date-fix-scope.md +0 -28
  19. package/docs/getting-started.md +0 -115
  20. package/docs/network-architecture-rollout-scope.md +0 -43
  21. package/docs/scope-google-oauth-integration.md +0 -351
  22. package/docs/settings-page-scope.md +0 -50
  23. package/docs/xai-imagine-scope.md +0 -116
  24. package/docs/xai-voice-integration-scope.md +0 -115
  25. package/docs/xai-voice-tools-scope.md +0 -165
  26. package/email-router.js +0 -512
  27. package/follow-up-handler.js +0 -606
  28. package/gateway-monitor.js +0 -158
  29. package/google-email.js +0 -379
  30. package/google-oauth.js +0 -310
  31. package/grok-imagine.js +0 -97
  32. package/health-reporter.js +0 -287
  33. package/invisible-prefix-base.txt +0 -206
  34. package/invisible-prefix-owner.txt +0 -26
  35. package/invisible-prefix-slim.txt +0 -10
  36. package/invisible-prefix.txt +0 -43
  37. package/knowledge-base.js +0 -472
  38. package/lib/cli.js +0 -19
  39. package/lib/server.js +0 -42
  40. package/meta-capi.js +0 -206
  41. package/meta-leads.js +0 -411
  42. package/notion-oauth.js +0 -323
  43. package/public/agent-config.html +0 -241
  44. package/public/aiva-avatar-anime.png +0 -0
  45. package/public/css/docs.css.bak +0 -688
  46. package/public/css/onboarding.css +0 -543
  47. package/public/diagrams/claude-subscription-pool.html +0 -329
  48. package/public/diagrams/claude-subscription-pool.png +0 -0
  49. package/public/docs-icon.png +0 -0
  50. package/public/escalation.html +0 -237
  51. package/public/group-config.html +0 -300
  52. package/public/icon-192.png +0 -0
  53. package/public/icon-512.png +0 -0
  54. package/public/icons/agents.svg +0 -1
  55. package/public/icons/attach.svg +0 -1
  56. package/public/icons/characters.svg +0 -1
  57. package/public/icons/chat.svg +0 -1
  58. package/public/icons/docs.svg +0 -1
  59. package/public/icons/heartbeat.svg +0 -1
  60. package/public/icons/messages.svg +0 -1
  61. package/public/icons/mic.svg +0 -1
  62. package/public/icons/notes.svg +0 -1
  63. package/public/icons/settings.svg +0 -1
  64. package/public/icons/tasks.svg +0 -1
  65. package/public/images/onboarding/p0-communication-layer.png +0 -0
  66. package/public/images/onboarding/p0-infinite-surface.png +0 -0
  67. package/public/images/onboarding/p0-learning-model.png +0 -0
  68. package/public/images/onboarding/p0-meet-aiva.png +0 -0
  69. package/public/images/onboarding/p4-contact-intelligence.png +0 -0
  70. package/public/images/onboarding/p4-context-compounds.png +0 -0
  71. package/public/images/onboarding/p4-message-router.png +0 -0
  72. package/public/images/onboarding/p4-per-contact-rules.png +0 -0
  73. package/public/images/onboarding/p4-send-messages.png +0 -0
  74. package/public/images/onboarding/p6-be-precise.png +0 -0
  75. package/public/images/onboarding/p6-review-escalations.png +0 -0
  76. package/public/images/onboarding/p6-voice-input.png +0 -0
  77. package/public/images/onboarding/p7-completion.png +0 -0
  78. package/public/index.html +0 -11594
  79. package/public/js/onboarding.js +0 -699
  80. package/public/manifest.json +0 -24
  81. package/public/messages-v2.html +0 -2824
  82. package/public/permission-approve.html.bak +0 -107
  83. package/public/permissions.html +0 -150
  84. package/public/styles/design-system.css +0 -68
  85. package/router-db.js +0 -604
  86. package/router-utils.js +0 -28
  87. package/router-v2/adapters/imessage.js +0 -191
  88. package/router-v2/adapters/quo.js +0 -82
  89. package/router-v2/adapters/whatsapp.js +0 -192
  90. package/router-v2/contact-manager.js +0 -234
  91. package/router-v2/conversation-engine.js +0 -498
  92. package/router-v2/data/knowledge-base.json +0 -176
  93. package/router-v2/data/router-v2.db +0 -0
  94. package/router-v2/data/router-v2.db-shm +0 -0
  95. package/router-v2/data/router-v2.db-wal +0 -0
  96. package/router-v2/data/router.db +0 -0
  97. package/router-v2/db.js +0 -457
  98. package/router-v2/escalation-bridge.js +0 -540
  99. package/router-v2/follow-up-engine.js +0 -347
  100. package/router-v2/index.js +0 -441
  101. package/router-v2/ingestion.js +0 -213
  102. package/router-v2/knowledge-base.js +0 -231
  103. package/router-v2/lead-qualifier.js +0 -152
  104. package/router-v2/learning-loop.js +0 -202
  105. package/router-v2/outbound-sender.js +0 -160
  106. package/router-v2/package.json +0 -13
  107. package/router-v2/permission-gate.js +0 -86
  108. package/router-v2/playbook.js +0 -177
  109. package/router-v2/prompts/base.js +0 -52
  110. package/router-v2/prompts/first-contact.js +0 -38
  111. package/router-v2/prompts/lead-qualification.js +0 -37
  112. package/router-v2/prompts/scheduling.js +0 -72
  113. package/router-v2/prompts/style-overrides.js +0 -22
  114. package/router-v2/scheduler.js +0 -301
  115. package/router-v2/scripts/migrate-v1-to-v2.js +0 -215
  116. package/router-v2/scripts/seed-faq.js +0 -67
  117. package/router-v2/seed-knowledge-base.js +0 -39
  118. package/router-v2/utils/ai.js +0 -129
  119. package/router-v2/utils/phone.js +0 -52
  120. package/router-v2/utils/response-validator.js +0 -98
  121. package/router-v2/utils/sanitize.js +0 -222
  122. package/router.js +0 -5005
  123. package/routes/google-calendar.js +0 -186
  124. package/scripts/deploy.sh +0 -62
  125. package/scripts/macos-calendar.sh +0 -232
  126. package/scripts/onboard-device.sh +0 -466
  127. package/server.js +0 -5131
  128. package/start.sh +0 -24
  129. package/templates/AGENTS.md +0 -548
  130. package/templates/IDENTITY.md +0 -15
  131. package/templates/docs-agents.html +0 -132
  132. package/templates/docs-app.html +0 -130
  133. package/templates/docs-home.html +0 -83
  134. package/templates/docs-imessage.html +0 -121
  135. package/templates/docs-tasks.html +0 -123
  136. package/templates/docs-tips.html +0 -175
  137. package/templates/getting-started.html +0 -809
  138. package/templates/invisible-prefix-base.txt +0 -171
  139. package/templates/invisible-prefix-owner.txt +0 -282
  140. package/templates/invisible-prefix.txt +0 -338
  141. package/templates/manifest.json +0 -61
  142. package/templates/memory-org/clients.md +0 -7
  143. package/templates/memory-org/credentials.md +0 -9
  144. package/templates/memory-org/devices.md +0 -7
  145. package/templates/updates.html +0 -464
  146. package/tts-proxy.js +0 -96
  147. package/voice-call-local.js +0 -731
  148. package/voice-call.js +0 -732
  149. 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, spawn } = require('child_process');
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, getDataDir, getUploadsDir } = require('./config');
8
+ const { loadConfig, getLogsDir, getAivaHome } = require('./config');
8
9
  const { checkHealth, checkGateway } = require('./health');
9
10
 
10
- function getEcosystemPath() {
11
- return path.join(getAivaHome(), 'ecosystem.config.js');
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 ensurePm2() {
48
- try {
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(opts = {}) {
62
- const config = loadConfig();
63
- const port = config.port || 3847;
19
+ async function startServer() {
20
+ console.log(pc.cyan('Starting AIVA...'));
64
21
 
65
- if (opts.foreground) {
66
- console.log(pc.cyan(`Starting AIVA in foreground on port ${port}...`));
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
- ensurePm2();
85
- writeEcosystem();
86
-
87
- console.log(pc.cyan(`Starting AIVA on port ${port}...`));
27
+ const uid = getUid();
88
28
  try {
89
- execSync(`pm2 start ${getEcosystemPath()}`, { stdio: 'pipe' });
90
- // Wait briefly for startup
91
- await new Promise(r => setTimeout(r, 2000));
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 AIVA:'), e.message);
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
- execSync('pm2 stop aiva-app', { stdio: 'pipe' });
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 is not running.'));
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('pm2 restart aiva-app', { stdio: 'pipe' });
120
- console.log(pc.green('AIVA restarted.'));
121
- } catch {
122
- console.log(pc.yellow('AIVA not running. Starting...'));
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(''.repeat(40)));
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
- // PM2 status
138
- let pm2Status = 'unknown';
139
- let uptime = '-';
140
- let memory = '-';
69
+ // Check if process is running on port 3847
70
+ let running = false;
141
71
  try {
142
- const raw = execSync('pm2 jlist', { stdio: 'pipe' }).toString();
143
- const procs = JSON.parse(raw);
144
- const aiva = procs.find(p => p.name === 'aiva-app');
145
- if (aiva) {
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
- const statusColor = pm2Status === 'online' ? pc.green : pm2Status === 'stopped' ? pc.red : pc.yellow;
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
- // Data dir size
179
- try {
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(''.repeat(40)));
92
+ console.log(pc.dim('-'.repeat(40)));
187
93
  console.log();
188
94
  }
189
95
 
190
96
  function getLogs(lines = 50) {
191
- ensurePm2();
192
- try {
193
- execSync(`pm2 logs aiva-app --lines ${lines} --nostream`, { stdio: 'inherit' });
194
- } catch {
195
- // Try reading log files directly
196
- const logFile = path.join(getLogsDir(), 'aiva.log');
197
- if (fs.existsSync(logFile)) {
198
- const content = fs.readFileSync(logFile, 'utf8');
199
- const logLines = content.split('\n');
200
- console.log(logLines.slice(-lines).join('\n'));
201
- } else {
202
- console.log(pc.yellow('No logs found.'));
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, writeEcosystem, ensurePm2 };
121
+ module.exports = { startServer, stopServer, restartServer, getStatus, getLogs };