@solidxai/solidctl 0.1.27 → 0.1.28-beta.10

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.
@@ -0,0 +1,2 @@
1
+ export declare function ensureAgentInstalled(): string;
2
+ export declare function ensureAgentUIInstalled(): string;
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ensureAgentInstalled = ensureAgentInstalled;
7
+ exports.ensureAgentUIInstalled = ensureAgentUIInstalled;
8
+ const child_process_1 = require("child_process");
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const os_1 = __importDefault(require("os"));
12
+ const AGENT_PACKAGE = 'solidx-ai-agent';
13
+ const AGENT_UI_PACKAGE = '@solidxai/agent-ui';
14
+ const VENV_DIR = path_1.default.join(os_1.default.homedir(), '.solidx', 'venv');
15
+ const VENV_BIN = path_1.default.join(VENV_DIR, process.platform === 'win32' ? 'Scripts' : 'bin');
16
+ const VENV_AGENT_BIN = path_1.default.join(VENV_BIN, process.platform === 'win32' ? 'solidx-agent.exe' : 'solidx-agent');
17
+ const AGENT_UI_DIR = path_1.default.join(os_1.default.homedir(), '.solidx', 'agent-ui');
18
+ const AGENT_UI_PKG_DIR = path_1.default.join(AGENT_UI_DIR, 'node_modules', '@solidxai', 'agent-ui');
19
+ const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
20
+ function commandExists(cmd) {
21
+ const result = (0, child_process_1.spawnSync)(process.platform === 'win32' ? 'where' : 'which', [cmd], { stdio: 'pipe' });
22
+ return result.status === 0;
23
+ }
24
+ function findAgentBinary() {
25
+ const pathBinary = process.platform === 'win32' ? 'solidx-agent.cmd' : 'solidx-agent';
26
+ if (commandExists(pathBinary)) {
27
+ return pathBinary;
28
+ }
29
+ if (fs_1.default.existsSync(VENV_AGENT_BIN)) {
30
+ return VENV_AGENT_BIN;
31
+ }
32
+ return null;
33
+ }
34
+ function findPython() {
35
+ for (const cmd of ['python3', 'python']) {
36
+ const result = (0, child_process_1.spawnSync)(cmd, ['--version'], { stdio: 'pipe' });
37
+ if (result.status === 0) {
38
+ const output = (result.stdout?.toString() || '') + (result.stderr?.toString() || '');
39
+ const match = output.match(/Python\s+(\d+)\.(\d+)/);
40
+ if (match && (+match[1] > 3 || (+match[1] === 3 && +match[2] >= 11))) {
41
+ return cmd;
42
+ }
43
+ }
44
+ }
45
+ return null;
46
+ }
47
+ function findUv() {
48
+ if (commandExists('uv')) {
49
+ return 'uv';
50
+ }
51
+ return null;
52
+ }
53
+ function ensureVenv(pythonCmd, uvCmd) {
54
+ if (fs_1.default.existsSync(path_1.default.join(VENV_DIR, 'pyvenv.cfg'))) {
55
+ return true;
56
+ }
57
+ fs_1.default.mkdirSync(path_1.default.dirname(VENV_DIR), { recursive: true });
58
+ console.log(`📦 Creating virtual environment at ${VENV_DIR}`);
59
+ if (uvCmd) {
60
+ const result = (0, child_process_1.spawnSync)(uvCmd, ['venv', VENV_DIR, '--python', pythonCmd], {
61
+ stdio: 'inherit',
62
+ });
63
+ if (result.status === 0)
64
+ return true;
65
+ console.warn('⚠ uv venv failed, falling back to python -m venv');
66
+ }
67
+ const result = (0, child_process_1.spawnSync)(pythonCmd, ['-m', 'venv', VENV_DIR], {
68
+ stdio: 'inherit',
69
+ });
70
+ return result.status === 0;
71
+ }
72
+ function installAgent(pythonCmd, uvCmd) {
73
+ const pipBin = path_1.default.join(VENV_BIN, process.platform === 'win32' ? 'pip.exe' : 'pip');
74
+ console.log(`📦 Installing ${AGENT_PACKAGE}...`);
75
+ if (uvCmd) {
76
+ const result = (0, child_process_1.spawnSync)(uvCmd, ['pip', 'install', AGENT_PACKAGE, '--python', pipBin], {
77
+ stdio: 'inherit',
78
+ });
79
+ if (result.status === 0)
80
+ return true;
81
+ console.warn('⚠ uv pip install failed, falling back to pip');
82
+ }
83
+ const result = (0, child_process_1.spawnSync)(pipBin, ['install', AGENT_PACKAGE], {
84
+ stdio: 'inherit',
85
+ shell: process.platform === 'win32',
86
+ });
87
+ return result.status === 0;
88
+ }
89
+ function ensureAgentInstalled() {
90
+ const existing = findAgentBinary();
91
+ if (existing) {
92
+ return existing;
93
+ }
94
+ console.log(`⚠ solidx-agent not found in PATH`);
95
+ const pythonCmd = findPython();
96
+ if (!pythonCmd) {
97
+ console.error('❌ Python 3.11+ is required but not found.\n' +
98
+ ' Install Python 3.11+ and try again, or manually run:\n' +
99
+ ` pip install ${AGENT_PACKAGE}`);
100
+ process.exit(1);
101
+ }
102
+ const uvCmd = findUv();
103
+ if (!ensureVenv(pythonCmd, uvCmd)) {
104
+ console.error('❌ Failed to create virtual environment at ' + VENV_DIR + '\n' +
105
+ ' Try creating it manually:\n' +
106
+ ` ${pythonCmd} -m venv ${VENV_DIR}`);
107
+ process.exit(1);
108
+ }
109
+ if (!installAgent(pythonCmd, uvCmd)) {
110
+ console.error('❌ Failed to install ' + AGENT_PACKAGE + '\n' +
111
+ ' Try installing manually:\n' +
112
+ ` ${VENV_BIN}/pip install ${AGENT_PACKAGE}`);
113
+ process.exit(1);
114
+ }
115
+ if (!fs_1.default.existsSync(VENV_AGENT_BIN)) {
116
+ console.error('❌ Package installed but solidx-agent binary not found at ' + VENV_AGENT_BIN + '\n' +
117
+ ' The package may not have installed correctly. Try:\n' +
118
+ ` ${VENV_BIN}/pip install --force-reinstall ${AGENT_PACKAGE}`);
119
+ process.exit(1);
120
+ }
121
+ console.log(`✔ ${AGENT_PACKAGE} installed successfully`);
122
+ return VENV_AGENT_BIN;
123
+ }
124
+ const MIN_AGENT_UI_VERSION = '0.1.2';
125
+ function parseVersion(version) {
126
+ const match = version.replace(/^v/, '').match(/^(\d+)\.(\d+)\.(\d+)/);
127
+ if (!match)
128
+ return [0, 0, 0];
129
+ return [+match[1], +match[2], +match[3]];
130
+ }
131
+ function isVersionSatisfied(installedVersion, minVersion) {
132
+ const installed = parseVersion(installedVersion);
133
+ const min = parseVersion(minVersion);
134
+ for (let i = 0; i < 3; i++) {
135
+ if (installed[i] > min[i])
136
+ return true;
137
+ if (installed[i] < min[i])
138
+ return false;
139
+ }
140
+ return true;
141
+ }
142
+ function ensureAgentUIInstalled() {
143
+ const markerFile = path_1.default.join(AGENT_UI_DIR, 'node_modules', '.package-lock.json');
144
+ const packageJsonPath = path_1.default.join(AGENT_UI_DIR, 'package.json');
145
+ const installedAgentUiPkgJson = path_1.default.join(AGENT_UI_PKG_DIR, 'package.json');
146
+ const runnerPackageJson = {
147
+ name: 'solidx-agent-ui-runner',
148
+ private: true,
149
+ scripts: {
150
+ dev: 'vite --port 8768 --host --config ./node_modules/@solidxai/agent-ui/vite.config.ts',
151
+ },
152
+ };
153
+ let needsInstall = false;
154
+ if (!fs_1.default.existsSync(packageJsonPath)) {
155
+ needsInstall = true;
156
+ }
157
+ else {
158
+ try {
159
+ const existing = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
160
+ if (JSON.stringify(existing.scripts) !== JSON.stringify(runnerPackageJson.scripts)) {
161
+ needsInstall = true;
162
+ }
163
+ }
164
+ catch {
165
+ needsInstall = true;
166
+ }
167
+ }
168
+ if (!needsInstall && fs_1.default.existsSync(installedAgentUiPkgJson)) {
169
+ try {
170
+ const installed = JSON.parse(fs_1.default.readFileSync(installedAgentUiPkgJson, 'utf-8'));
171
+ if (!isVersionSatisfied(installed.version || '0.0.0', MIN_AGENT_UI_VERSION)) {
172
+ console.log(`📦 ${AGENT_UI_PACKAGE} v${installed.version} is outdated (need >= ${MIN_AGENT_UI_VERSION}), updating...`);
173
+ needsInstall = true;
174
+ }
175
+ }
176
+ catch {
177
+ needsInstall = true;
178
+ }
179
+ }
180
+ if (!needsInstall && fs_1.default.existsSync(markerFile)) {
181
+ return AGENT_UI_DIR;
182
+ }
183
+ console.log(`📦 Installing ${AGENT_UI_PACKAGE}...`);
184
+ fs_1.default.mkdirSync(AGENT_UI_DIR, { recursive: true });
185
+ fs_1.default.writeFileSync(packageJsonPath, JSON.stringify(runnerPackageJson, null, 2));
186
+ const staleRunnerConfig = path_1.default.join(AGENT_UI_DIR, 'vite.config.ts');
187
+ if (fs_1.default.existsSync(staleRunnerConfig)) {
188
+ fs_1.default.unlinkSync(staleRunnerConfig);
189
+ }
190
+ const result = (0, child_process_1.spawnSync)(npmCommand, ['install', `${AGENT_UI_PACKAGE}@latest`], {
191
+ cwd: AGENT_UI_DIR,
192
+ stdio: 'inherit',
193
+ });
194
+ if (result.status !== 0) {
195
+ console.error(`❌ Failed to install ${AGENT_UI_PACKAGE}\n` +
196
+ ' Try installing manually:\n' +
197
+ ` cd ${AGENT_UI_DIR} && npm install ${AGENT_UI_PACKAGE}@latest`);
198
+ process.exit(1);
199
+ }
200
+ if (!fs_1.default.existsSync(AGENT_UI_PKG_DIR)) {
201
+ console.error(`❌ Package installed but not found at ${AGENT_UI_PKG_DIR}\n` +
202
+ ' Try reinstalling:\n' +
203
+ ` cd ${AGENT_UI_DIR} && npm install ${AGENT_UI_PACKAGE}@latest`);
204
+ process.exit(1);
205
+ }
206
+ console.log(`✔ ${AGENT_UI_PACKAGE} installed successfully`);
207
+ return AGENT_UI_DIR;
208
+ }
209
+ //# sourceMappingURL=agent-helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-helper.js","sourceRoot":"","sources":["../../src/commands/agent-helper.ts"],"names":[],"mappings":"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"}
@@ -5,9 +5,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.registerAgentCommand = registerAgentCommand;
7
7
  const child_process_1 = require("child_process");
8
+ const chalk_1 = __importDefault(require("chalk"));
8
9
  const path_1 = __importDefault(require("path"));
10
+ const readline_1 = __importDefault(require("readline"));
9
11
  const dotenv_1 = require("dotenv");
10
12
  const helper_1 = require("../helper");
13
+ const agent_helper_1 = require("./agent-helper");
11
14
  function resolveDatabaseUrl() {
12
15
  if (process.env.DATABASE_URL)
13
16
  return process.env.DATABASE_URL;
@@ -21,24 +24,128 @@ function resolveDatabaseUrl() {
21
24
  }
22
25
  return undefined;
23
26
  }
24
- function registerAgentCommand(program) {
25
- const agent = program
26
- .command('agent')
27
- .description('SolidX AI Agent — start the server or run a single task');
28
- agent
29
- .command('start')
30
- .description('Start the AI agent server')
31
- .option('-p, --port <port>', 'Port number', '8765')
32
- .option('-H, --host <host>', 'Host to bind', '0.0.0.0')
33
- .option('-l, --log-level <level>', 'Logging level', 'INFO')
34
- .action((options) => {
35
- (0, helper_1.validateProjectRoot)();
36
- const projectRoot = process.cwd();
37
- (0, dotenv_1.config)({ path: path_1.default.join(projectRoot, 'solid-api', '.env') });
27
+ class AgentSupervisor {
28
+ serviceConfigs;
29
+ serviceStates;
30
+ isInteractive;
31
+ npmCommand;
32
+ projectRoot;
33
+ agentCommand;
34
+ agentUiDir;
35
+ agentPort;
36
+ agentHost;
37
+ agentLogLevel;
38
+ shuttingDown = false;
39
+ exitCode = 0;
40
+ stdinWasRaw = false;
41
+ constructor(projectRoot, agentCommand, agentUiDir, options) {
42
+ this.projectRoot = projectRoot;
43
+ this.agentCommand = agentCommand;
44
+ this.agentUiDir = agentUiDir;
45
+ this.agentPort = options.port;
46
+ this.agentHost = options.host;
47
+ this.agentLogLevel = options.logLevel;
48
+ this.isInteractive = Boolean(process.stdout.isTTY && process.stdin.isTTY && !options.plain);
49
+ this.npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
50
+ this.serviceConfigs = {
51
+ agent: {
52
+ cwd: projectRoot,
53
+ label: 'agent',
54
+ color: chalk_1.default.green,
55
+ },
56
+ ui: {
57
+ cwd: agentUiDir,
58
+ label: 'ui',
59
+ color: chalk_1.default.magenta,
60
+ },
61
+ };
62
+ this.serviceStates = {
63
+ agent: this.createInitialState(),
64
+ ui: this.createInitialState(),
65
+ };
66
+ }
67
+ async start() {
68
+ this.attachSignalHandlers();
69
+ this.attachKeyboardControls();
70
+ this.printStatus('Starting SolidX Agent processes');
71
+ this.spawnService('agent');
72
+ this.spawnService('ui');
73
+ this.renderFooter();
74
+ await new Promise((resolve) => {
75
+ const poll = setInterval(() => {
76
+ if (!this.hasRunningChildren()) {
77
+ clearInterval(poll);
78
+ this.cleanupTerminal();
79
+ resolve();
80
+ }
81
+ }, 100);
82
+ });
83
+ process.exit(this.exitCode);
84
+ }
85
+ createInitialState() {
86
+ return {
87
+ child: null,
88
+ restartRequested: false,
89
+ stoppingForShutdown: false,
90
+ outputBuffer: '',
91
+ };
92
+ }
93
+ spawnService(serviceName) {
94
+ const config = this.serviceConfigs[serviceName];
95
+ const state = this.serviceStates[serviceName];
96
+ state.restartRequested = false;
97
+ state.stoppingForShutdown = false;
98
+ let child;
99
+ if (serviceName === 'agent') {
100
+ child = (0, child_process_1.spawn)(this.agentCommand, ['serve', '--port', this.agentPort, '--host', this.agentHost, '--log-level', this.agentLogLevel], {
101
+ cwd: config.cwd,
102
+ env: this.getAgentEnv(),
103
+ stdio: ['ignore', 'pipe', 'pipe'],
104
+ shell: process.platform === 'win32',
105
+ });
106
+ }
107
+ else {
108
+ child = (0, child_process_1.spawn)(this.npmCommand, ['run', 'dev'], {
109
+ cwd: config.cwd,
110
+ env: this.getUiEnv(),
111
+ stdio: ['ignore', 'pipe', 'pipe'],
112
+ shell: false,
113
+ });
114
+ }
115
+ state.child = child;
116
+ this.printStatus(`Started ${config.label}`);
117
+ child.stdout?.on('data', (chunk) => {
118
+ this.handleChunk(serviceName, String(chunk), false);
119
+ });
120
+ child.stderr?.on('data', (chunk) => {
121
+ this.handleChunk(serviceName, String(chunk), true);
122
+ });
123
+ child.on('error', (error) => {
124
+ this.printLog(serviceName, `Failed to start: ${error.message}`, true);
125
+ this.handleUnexpectedExit(serviceName, 1);
126
+ });
127
+ child.on('exit', (code, signal) => {
128
+ this.flushBuffer(serviceName);
129
+ state.child = null;
130
+ if (this.shuttingDown || state.stoppingForShutdown) {
131
+ this.printStatus(`${config.label} stopped`);
132
+ return;
133
+ }
134
+ if (state.restartRequested) {
135
+ this.printStatus(`Restarting ${config.label}`);
136
+ this.spawnService(serviceName);
137
+ return;
138
+ }
139
+ const reason = signal ? `signal ${signal}` : `code ${code ?? 0}`;
140
+ this.printLog(serviceName, `Exited unexpectedly with ${reason}`, true);
141
+ this.handleUnexpectedExit(serviceName, typeof code === 'number' ? code : 1);
142
+ });
143
+ }
144
+ getAgentEnv() {
38
145
  const databaseUrl = resolveDatabaseUrl();
39
146
  const env = {
40
147
  ...process.env,
41
- SOLIDX_PROJECT_ROOT: projectRoot,
148
+ SOLIDX_PROJECT_ROOT: this.projectRoot,
42
149
  ...(databaseUrl ? { DATABASE_URL: databaseUrl } : {}),
43
150
  ...(process.env.BASE_URL ? { BASE_URL: process.env.BASE_URL } : {}),
44
151
  ...(process.env.APP_ENCRYPTION_KEY ? { APP_ENCRYPTION_KEY: process.env.APP_ENCRYPTION_KEY } : {}),
@@ -46,25 +153,258 @@ function registerAgentCommand(program) {
46
153
  const bridgedKeys = ['DATABASE_URL', 'SOLIDX_PROJECT_ROOT', 'BASE_URL', 'APP_ENCRYPTION_KEY'];
47
154
  const bridged = bridgedKeys.filter((k) => env[k]);
48
155
  const missing = bridgedKeys.filter((k) => !env[k]);
49
- console.log(`✔ Bridged env: ${bridged.join(', ') || 'none'}`);
156
+ this.printStatus(`Agent bridged env: ${bridged.join(', ') || 'none'}`);
50
157
  if (missing.length)
51
- console.warn(`⚠ Missing env: ${missing.join(', ')}`);
52
- console.log(`▶ Starting SolidX AI Agent server on ${options.host}:${options.port}`);
53
- const agentCommand = process.platform === 'win32' ? 'solidx-agent.cmd' : 'solidx-agent';
54
- const result = (0, child_process_1.spawnSync)(agentCommand, ['serve', '--port', options.port, '--host', options.host, '--log-level', options.logLevel], {
55
- cwd: projectRoot,
56
- stdio: 'inherit',
57
- env,
58
- shell: process.platform === 'win32',
158
+ this.printStatus(`Agent missing env: ${missing.join(', ')}`);
159
+ return env;
160
+ }
161
+ getUiEnv() {
162
+ return {
163
+ ...process.env,
164
+ SOLIDX_AGENT_URL: `http://localhost:${this.agentPort}`,
165
+ };
166
+ }
167
+ handleChunk(serviceName, chunk, isError) {
168
+ const state = this.serviceStates[serviceName];
169
+ state.outputBuffer += chunk;
170
+ const lines = state.outputBuffer.split(/\r?\n/);
171
+ state.outputBuffer = lines.pop() ?? '';
172
+ for (const line of lines) {
173
+ this.printLog(serviceName, line, isError);
174
+ }
175
+ }
176
+ flushBuffer(serviceName) {
177
+ const state = this.serviceStates[serviceName];
178
+ if (!state.outputBuffer) {
179
+ return;
180
+ }
181
+ this.printLog(serviceName, state.outputBuffer, false);
182
+ state.outputBuffer = '';
183
+ }
184
+ printLog(serviceName, message, isError) {
185
+ const config = this.serviceConfigs[serviceName];
186
+ const prefix = config.color(`[${config.label}]`);
187
+ const line = `${prefix} ${message}`;
188
+ this.writeWithFooter(line, isError ? process.stderr : process.stdout);
189
+ }
190
+ printStatus(message) {
191
+ this.writeWithFooter(chalk_1.default.dim(`[solidctl] ${message}`), process.stdout);
192
+ }
193
+ writeWithFooter(line, stream) {
194
+ if (!this.isInteractive) {
195
+ stream.write(`${line}\n`);
196
+ return;
197
+ }
198
+ readline_1.default.clearLine(process.stdout, 0);
199
+ readline_1.default.cursorTo(process.stdout, 0);
200
+ stream.write(`${line}\n`);
201
+ this.renderFooter();
202
+ }
203
+ renderFooter() {
204
+ if (!this.isInteractive) {
205
+ return;
206
+ }
207
+ const footer = [
208
+ chalk_1.default.bold('Controls'),
209
+ 'q quit',
210
+ 'c clear',
211
+ 'r restart both',
212
+ 'a restart Agent',
213
+ 'u restart UI',
214
+ ].join(chalk_1.default.dim(' | '));
215
+ const terminalWidth = process.stdout.columns || 80;
216
+ const renderedFooter = chalk_1.default.inverse(` ${footer} `);
217
+ const safeFooter = this.truncateAnsiText(renderedFooter, terminalWidth);
218
+ readline_1.default.clearLine(process.stdout, 0);
219
+ readline_1.default.cursorTo(process.stdout, 0);
220
+ process.stdout.write(safeFooter);
221
+ }
222
+ truncateAnsiText(text, maxWidth) {
223
+ if (maxWidth <= 0) {
224
+ return '';
225
+ }
226
+ let visibleWidth = 0;
227
+ let index = 0;
228
+ let output = '';
229
+ let lastEscapeIndex = -1;
230
+ while (index < text.length) {
231
+ if (text[index] === '\u001b') {
232
+ const match = /\u001b\[[0-9;]*m/.exec(text.slice(index));
233
+ if (!match) {
234
+ break;
235
+ }
236
+ output += match[0];
237
+ lastEscapeIndex = output.length;
238
+ index += match[0].length;
239
+ continue;
240
+ }
241
+ if (visibleWidth >= maxWidth) {
242
+ break;
243
+ }
244
+ output += text[index];
245
+ visibleWidth += 1;
246
+ index += 1;
247
+ }
248
+ if (index < text.length && maxWidth >= 1) {
249
+ let visibleChars = 0;
250
+ let truncated = '';
251
+ let cursor = 0;
252
+ while (cursor < output.length) {
253
+ if (output[cursor] === '\u001b') {
254
+ const match = /\u001b\[[0-9;]*m/.exec(output.slice(cursor));
255
+ if (!match) {
256
+ break;
257
+ }
258
+ truncated += match[0];
259
+ cursor += match[0].length;
260
+ continue;
261
+ }
262
+ if (visibleChars >= Math.max(0, maxWidth - 1)) {
263
+ break;
264
+ }
265
+ truncated += output[cursor];
266
+ visibleChars += 1;
267
+ cursor += 1;
268
+ }
269
+ output = `${truncated}\u2026`;
270
+ if (lastEscapeIndex !== -1 && !output.endsWith('\u001b[0m')) {
271
+ output += '\u001b[0m';
272
+ }
273
+ }
274
+ return output;
275
+ }
276
+ attachSignalHandlers() {
277
+ process.on('SIGINT', () => {
278
+ this.shutdown(0);
59
279
  });
60
- if (result.error) {
61
- console.error('❌ Failed to start agent server:', result.error.message);
62
- process.exit(1);
280
+ process.on('SIGTERM', () => {
281
+ this.shutdown(0);
282
+ });
283
+ }
284
+ attachKeyboardControls() {
285
+ if (!this.isInteractive) {
286
+ return;
63
287
  }
64
- if (result.status !== 0) {
65
- console.error('❌ Agent server exited with code', result.status);
66
- process.exit(result.status ?? 1);
288
+ readline_1.default.emitKeypressEvents(process.stdin);
289
+ this.stdinWasRaw = Boolean(process.stdin.isRaw);
290
+ process.stdin.setRawMode?.(true);
291
+ process.stdin.resume();
292
+ process.stdin.on('keypress', (_str, key) => {
293
+ if (key.ctrl && key.name === 'c') {
294
+ this.shutdown(0);
295
+ return;
296
+ }
297
+ switch (key.name) {
298
+ case 'a':
299
+ this.restartService('agent');
300
+ break;
301
+ case 'u':
302
+ this.restartService('ui');
303
+ break;
304
+ case 'r':
305
+ this.restartService('agent');
306
+ this.restartService('ui');
307
+ break;
308
+ case 'c':
309
+ console.clear();
310
+ this.renderFooter();
311
+ break;
312
+ case 'q':
313
+ this.shutdown(0);
314
+ break;
315
+ default:
316
+ break;
317
+ }
318
+ });
319
+ }
320
+ restartService(serviceName) {
321
+ const state = this.serviceStates[serviceName];
322
+ if (!state.child) {
323
+ this.printStatus(`${this.serviceConfigs[serviceName].label} is not running, starting it now`);
324
+ this.spawnService(serviceName);
325
+ this.renderFooter();
326
+ return;
327
+ }
328
+ state.restartRequested = true;
329
+ this.printStatus(`Stopping ${this.serviceConfigs[serviceName].label} for restart`);
330
+ this.stopChild(serviceName);
331
+ }
332
+ stopChild(serviceName) {
333
+ const state = this.serviceStates[serviceName];
334
+ if (!state.child) {
335
+ return;
336
+ }
337
+ state.child.kill('SIGTERM');
338
+ }
339
+ handleUnexpectedExit(serviceName, code) {
340
+ if (this.shuttingDown) {
341
+ return;
342
+ }
343
+ this.exitCode = code === 0 ? 1 : code;
344
+ this.shuttingDown = true;
345
+ for (const otherServiceName of Object.keys(this.serviceStates)) {
346
+ if (otherServiceName === serviceName) {
347
+ continue;
348
+ }
349
+ const otherState = this.serviceStates[otherServiceName];
350
+ if (otherState.child) {
351
+ otherState.stoppingForShutdown = true;
352
+ this.stopChild(otherServiceName);
353
+ }
67
354
  }
355
+ this.renderFooter();
356
+ }
357
+ shutdown(code) {
358
+ if (this.shuttingDown) {
359
+ return;
360
+ }
361
+ this.exitCode = code;
362
+ this.shuttingDown = true;
363
+ this.printStatus('Shutting down');
364
+ for (const serviceName of Object.keys(this.serviceStates)) {
365
+ const state = this.serviceStates[serviceName];
366
+ state.stoppingForShutdown = true;
367
+ state.restartRequested = false;
368
+ this.stopChild(serviceName);
369
+ }
370
+ this.renderFooter();
371
+ }
372
+ hasRunningChildren() {
373
+ return Object.keys(this.serviceStates).some((serviceName) => {
374
+ return this.serviceStates[serviceName].child !== null;
375
+ });
376
+ }
377
+ cleanupTerminal() {
378
+ if (!this.isInteractive) {
379
+ return;
380
+ }
381
+ readline_1.default.clearLine(process.stdout, 0);
382
+ readline_1.default.cursorTo(process.stdout, 0);
383
+ if (!this.stdinWasRaw) {
384
+ process.stdin.setRawMode?.(false);
385
+ }
386
+ process.stdout.write('\n');
387
+ }
388
+ }
389
+ function registerAgentCommand(program) {
390
+ const agent = program
391
+ .command('agent')
392
+ .description('SolidX AI Agent — start the server or run a single task');
393
+ agent
394
+ .command('start')
395
+ .description('Start the AI agent server and chat UI in a single supervisor')
396
+ .option('-p, --port <port>', 'Agent backend port', '8765')
397
+ .option('-H, --host <host>', 'Host to bind', '0.0.0.0')
398
+ .option('-l, --log-level <level>', 'Logging level', 'INFO')
399
+ .option('--plain', 'Disable interactive controls and print merged logs only')
400
+ .action(async (options) => {
401
+ (0, helper_1.validateProjectRoot)();
402
+ const projectRoot = process.cwd();
403
+ (0, dotenv_1.config)({ path: path_1.default.join(projectRoot, 'solid-api', '.env') });
404
+ const agentCommand = (0, agent_helper_1.ensureAgentInstalled)();
405
+ const agentUiDir = (0, agent_helper_1.ensureAgentUIInstalled)();
406
+ const supervisor = new AgentSupervisor(projectRoot, agentCommand, agentUiDir, options);
407
+ await supervisor.start();
68
408
  });
69
409
  agent
70
410
  .command('run')
@@ -96,7 +436,7 @@ function registerAgentCommand(program) {
96
436
  if (missing.length)
97
437
  console.warn(`⚠ Missing env: ${missing.join(', ')}`);
98
438
  console.log(`▶ Running SolidX AI Agent: ${task}`);
99
- const agentCommand = process.platform === 'win32' ? 'solidx-agent.cmd' : 'solidx-agent';
439
+ const agentCommand = (0, agent_helper_1.ensureAgentInstalled)();
100
440
  const result = (0, child_process_1.spawnSync)(agentCommand, args, {
101
441
  cwd: projectRoot,
102
442
  stdio: 'inherit',