@mmmbuto/nexuscli 0.5.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/LICENSE +21 -0
- package/README.md +172 -0
- package/bin/nexuscli.js +117 -0
- package/frontend/dist/apple-touch-icon.png +0 -0
- package/frontend/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/frontend/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/frontend/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/frontend/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/frontend/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/frontend/dist/assets/index-Bn_l1e6e.css +1 -0
- package/frontend/dist/assets/index-CikJbUR5.js +8617 -0
- package/frontend/dist/browserconfig.xml +12 -0
- package/frontend/dist/favicon-16x16.png +0 -0
- package/frontend/dist/favicon-32x32.png +0 -0
- package/frontend/dist/favicon-48x48.png +0 -0
- package/frontend/dist/favicon.ico +0 -0
- package/frontend/dist/icon-192.png +0 -0
- package/frontend/dist/icon-512.png +0 -0
- package/frontend/dist/icon-maskable-192.png +0 -0
- package/frontend/dist/icon-maskable-512.png +0 -0
- package/frontend/dist/index.html +79 -0
- package/frontend/dist/manifest.json +75 -0
- package/frontend/dist/sw.js +122 -0
- package/frontend/package.json +28 -0
- package/lib/cli/api.js +156 -0
- package/lib/cli/boot.js +172 -0
- package/lib/cli/config.js +185 -0
- package/lib/cli/engines.js +257 -0
- package/lib/cli/init.js +660 -0
- package/lib/cli/logs.js +72 -0
- package/lib/cli/start.js +220 -0
- package/lib/cli/status.js +187 -0
- package/lib/cli/stop.js +64 -0
- package/lib/cli/uninstall.js +194 -0
- package/lib/cli/users.js +295 -0
- package/lib/cli/workspaces.js +337 -0
- package/lib/config/manager.js +233 -0
- package/lib/server/.env.example +20 -0
- package/lib/server/db/adapter.js +314 -0
- package/lib/server/db/drivers/better-sqlite3.js +38 -0
- package/lib/server/db/drivers/sql-js.js +75 -0
- package/lib/server/db/migrate.js +174 -0
- package/lib/server/db/migrations/001_ultra_light_schema.sql +96 -0
- package/lib/server/db/migrations/002_session_conversation_mapping.sql +19 -0
- package/lib/server/db/migrations/003_message_engine_tracking.sql +18 -0
- package/lib/server/db/migrations/004_performance_indexes.sql +16 -0
- package/lib/server/db.js +2 -0
- package/lib/server/lib/cli-wrapper.js +164 -0
- package/lib/server/lib/output-parser.js +132 -0
- package/lib/server/lib/pty-adapter.js +57 -0
- package/lib/server/middleware/auth.js +103 -0
- package/lib/server/models/Conversation.js +259 -0
- package/lib/server/models/Message.js +228 -0
- package/lib/server/models/User.js +115 -0
- package/lib/server/package-lock.json +5895 -0
- package/lib/server/routes/auth.js +168 -0
- package/lib/server/routes/chat.js +206 -0
- package/lib/server/routes/codex.js +205 -0
- package/lib/server/routes/conversations.js +224 -0
- package/lib/server/routes/gemini.js +228 -0
- package/lib/server/routes/jobs.js +317 -0
- package/lib/server/routes/messages.js +60 -0
- package/lib/server/routes/models.js +198 -0
- package/lib/server/routes/sessions.js +285 -0
- package/lib/server/routes/upload.js +134 -0
- package/lib/server/routes/wake-lock.js +95 -0
- package/lib/server/routes/workspace.js +80 -0
- package/lib/server/routes/workspaces.js +142 -0
- package/lib/server/scripts/cleanup-ghost-sessions.js +71 -0
- package/lib/server/scripts/seed-users.js +37 -0
- package/lib/server/scripts/test-history-access.js +50 -0
- package/lib/server/server.js +227 -0
- package/lib/server/services/cache.js +85 -0
- package/lib/server/services/claude-wrapper.js +312 -0
- package/lib/server/services/cli-loader.js +384 -0
- package/lib/server/services/codex-output-parser.js +277 -0
- package/lib/server/services/codex-wrapper.js +224 -0
- package/lib/server/services/context-bridge.js +289 -0
- package/lib/server/services/gemini-output-parser.js +398 -0
- package/lib/server/services/gemini-wrapper.js +249 -0
- package/lib/server/services/history-sync.js +407 -0
- package/lib/server/services/output-parser.js +415 -0
- package/lib/server/services/session-manager.js +465 -0
- package/lib/server/services/summary-generator.js +259 -0
- package/lib/server/services/workspace-manager.js +516 -0
- package/lib/server/tests/history-sync.test.js +90 -0
- package/lib/server/tests/integration-session-sync.test.js +151 -0
- package/lib/server/tests/integration.test.js +76 -0
- package/lib/server/tests/performance.test.js +118 -0
- package/lib/server/tests/services.test.js +160 -0
- package/lib/setup/postinstall.js +216 -0
- package/lib/utils/paths.js +107 -0
- package/lib/utils/termux.js +145 -0
- package/package.json +82 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nexuscli config - Manage configuration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const inquirer = require('inquirer');
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
isInitialized,
|
|
10
|
+
getConfig,
|
|
11
|
+
getConfigValue,
|
|
12
|
+
setConfigValue,
|
|
13
|
+
getConfigKeys
|
|
14
|
+
} = require('../config/manager');
|
|
15
|
+
const { PATHS } = require('../utils/paths');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* List all config values
|
|
19
|
+
*/
|
|
20
|
+
function listConfig() {
|
|
21
|
+
const keys = getConfigKeys();
|
|
22
|
+
const maxKeyLen = Math.max(...keys.map(k => k.length));
|
|
23
|
+
|
|
24
|
+
console.log(chalk.cyan('Configuration:'));
|
|
25
|
+
console.log(chalk.gray(` File: ${PATHS.CONFIG_FILE}`));
|
|
26
|
+
console.log('');
|
|
27
|
+
|
|
28
|
+
for (const key of keys) {
|
|
29
|
+
const value = getConfigValue(key);
|
|
30
|
+
const displayValue = formatValue(value);
|
|
31
|
+
console.log(` ${chalk.white(key.padEnd(maxKeyLen))} ${displayValue}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Format a value for display
|
|
37
|
+
*/
|
|
38
|
+
function formatValue(value) {
|
|
39
|
+
if (value === null || value === undefined) {
|
|
40
|
+
return chalk.gray('null');
|
|
41
|
+
}
|
|
42
|
+
if (typeof value === 'boolean') {
|
|
43
|
+
return value ? chalk.green('true') : chalk.red('false');
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === 'number') {
|
|
46
|
+
return chalk.yellow(String(value));
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
return chalk.cyan(JSON.stringify(value));
|
|
50
|
+
}
|
|
51
|
+
if (typeof value === 'string') {
|
|
52
|
+
// Hide sensitive values
|
|
53
|
+
if (value.length > 20 && (value.includes('-') || value.includes('$'))) {
|
|
54
|
+
return chalk.gray('***hidden***');
|
|
55
|
+
}
|
|
56
|
+
return chalk.white(value);
|
|
57
|
+
}
|
|
58
|
+
return chalk.gray(String(value));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Main config command
|
|
63
|
+
*/
|
|
64
|
+
async function config(action, key, value) {
|
|
65
|
+
console.log('');
|
|
66
|
+
|
|
67
|
+
if (!isInitialized()) {
|
|
68
|
+
console.log(chalk.yellow('NexusCLI is not configured.'));
|
|
69
|
+
console.log(`Run ${chalk.cyan('nexuscli init')} first.`);
|
|
70
|
+
console.log('');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// No action = list all
|
|
75
|
+
if (!action || action === 'list') {
|
|
76
|
+
listConfig();
|
|
77
|
+
console.log('');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Get value
|
|
82
|
+
if (action === 'get') {
|
|
83
|
+
if (!key) {
|
|
84
|
+
console.log(chalk.red('Usage: nexuscli config get <key>'));
|
|
85
|
+
console.log('');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const val = getConfigValue(key);
|
|
90
|
+
if (val === undefined) {
|
|
91
|
+
console.log(chalk.yellow(`Key not found: ${key}`));
|
|
92
|
+
} else {
|
|
93
|
+
console.log(formatValue(val));
|
|
94
|
+
}
|
|
95
|
+
console.log('');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Set value
|
|
100
|
+
if (action === 'set') {
|
|
101
|
+
if (!key || value === undefined) {
|
|
102
|
+
console.log(chalk.red('Usage: nexuscli config set <key> <value>'));
|
|
103
|
+
console.log('');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Confirm sensitive changes
|
|
108
|
+
const sensitiveKeys = ['auth.jwt_secret', 'auth.pass_hash'];
|
|
109
|
+
if (sensitiveKeys.includes(key)) {
|
|
110
|
+
const { confirm } = await inquirer.prompt([{
|
|
111
|
+
type: 'confirm',
|
|
112
|
+
name: 'confirm',
|
|
113
|
+
message: `Changing ${key} may break authentication. Continue?`,
|
|
114
|
+
default: false
|
|
115
|
+
}]);
|
|
116
|
+
|
|
117
|
+
if (!confirm) {
|
|
118
|
+
console.log(chalk.yellow('Cancelled.'));
|
|
119
|
+
console.log('');
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (setConfigValue(key, value)) {
|
|
125
|
+
console.log(chalk.green(` ✓ ${key} = ${value}`));
|
|
126
|
+
} else {
|
|
127
|
+
console.log(chalk.red(` ✗ Failed to set ${key}`));
|
|
128
|
+
}
|
|
129
|
+
console.log('');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Interactive editor
|
|
134
|
+
if (action === 'edit') {
|
|
135
|
+
const currentConfig = getConfig();
|
|
136
|
+
|
|
137
|
+
const answers = await inquirer.prompt([
|
|
138
|
+
{
|
|
139
|
+
type: 'number',
|
|
140
|
+
name: 'port',
|
|
141
|
+
message: 'Server port:',
|
|
142
|
+
default: currentConfig.server.port
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: 'list',
|
|
146
|
+
name: 'claudeModel',
|
|
147
|
+
message: 'Claude default model:',
|
|
148
|
+
choices: ['haiku', 'sonnet', 'opus'],
|
|
149
|
+
default: currentConfig.engines?.claude?.model || 'sonnet'
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
type: 'confirm',
|
|
153
|
+
name: 'wakeLock',
|
|
154
|
+
message: 'Enable wake-lock?',
|
|
155
|
+
default: currentConfig.termux?.wake_lock ?? true
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
type: 'confirm',
|
|
159
|
+
name: 'notifications',
|
|
160
|
+
message: 'Enable notifications?',
|
|
161
|
+
default: currentConfig.termux?.notifications ?? true
|
|
162
|
+
}
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
setConfigValue('server.port', answers.port);
|
|
166
|
+
setConfigValue('engines.claude.model', answers.claudeModel);
|
|
167
|
+
setConfigValue('termux.wake_lock', answers.wakeLock);
|
|
168
|
+
setConfigValue('termux.notifications', answers.notifications);
|
|
169
|
+
|
|
170
|
+
console.log(chalk.green(' ✓ Configuration updated'));
|
|
171
|
+
console.log('');
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Unknown action
|
|
176
|
+
console.log(chalk.red(`Unknown action: ${action}`));
|
|
177
|
+
console.log('Usage:');
|
|
178
|
+
console.log(' nexuscli config List all');
|
|
179
|
+
console.log(' nexuscli config get <k> Get value');
|
|
180
|
+
console.log(' nexuscli config set <k> <v> Set value');
|
|
181
|
+
console.log(' nexuscli config edit Interactive editor');
|
|
182
|
+
console.log('');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
module.exports = config;
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nexuscli engines - Manage AI engines
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const inquirer = require('inquirer');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const { isInitialized, getConfig, setConfigValue } = require('../config/manager');
|
|
12
|
+
const { HOME } = require('../utils/paths');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Detect available engines (TRI CLI v0.4.0)
|
|
16
|
+
*/
|
|
17
|
+
function detectEngines() {
|
|
18
|
+
const engines = {
|
|
19
|
+
claude: { available: false, path: null, version: null },
|
|
20
|
+
codex: { available: false, path: null, version: null },
|
|
21
|
+
gemini: { available: false, path: null, version: null }
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Claude
|
|
25
|
+
try {
|
|
26
|
+
const claudePath = execSync('which claude 2>/dev/null', { encoding: 'utf8' }).trim();
|
|
27
|
+
const claudeVersion = execSync('claude --version 2>/dev/null', { encoding: 'utf8' }).trim().split('\n')[0];
|
|
28
|
+
engines.claude = { available: true, path: claudePath, version: claudeVersion };
|
|
29
|
+
} catch {}
|
|
30
|
+
|
|
31
|
+
// Codex
|
|
32
|
+
try {
|
|
33
|
+
const codexPath = execSync('which codex 2>/dev/null', { encoding: 'utf8' }).trim();
|
|
34
|
+
const codexVersion = execSync('codex --version 2>/dev/null', { encoding: 'utf8' }).trim().split('\n')[0];
|
|
35
|
+
engines.codex = { available: true, path: codexPath, version: codexVersion };
|
|
36
|
+
} catch {}
|
|
37
|
+
|
|
38
|
+
// Gemini
|
|
39
|
+
try {
|
|
40
|
+
const geminiPath = execSync('which gemini 2>/dev/null', { encoding: 'utf8' }).trim();
|
|
41
|
+
const geminiVersion = execSync('gemini --version 2>/dev/null', { encoding: 'utf8' }).trim().split('\n')[0];
|
|
42
|
+
engines.gemini = { available: true, path: geminiPath, version: geminiVersion };
|
|
43
|
+
} catch {}
|
|
44
|
+
|
|
45
|
+
return engines;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* List engines status (TRI CLI v0.4.0)
|
|
50
|
+
*/
|
|
51
|
+
function listEngines() {
|
|
52
|
+
const config = getConfig();
|
|
53
|
+
const detected = detectEngines();
|
|
54
|
+
|
|
55
|
+
console.log(chalk.bold('╔═══════════════════════════════════════════╗'));
|
|
56
|
+
console.log(chalk.bold('║ AI Engines (TRI CLI) ║'));
|
|
57
|
+
console.log(chalk.bold('╠═══════════════════════════════════════════╣'));
|
|
58
|
+
|
|
59
|
+
// Claude
|
|
60
|
+
const claudeEnabled = config.engines?.claude?.enabled !== false;
|
|
61
|
+
const claudeModel = config.engines?.claude?.model || 'sonnet';
|
|
62
|
+
if (detected.claude.available) {
|
|
63
|
+
const status = claudeEnabled ? chalk.green('✓ enabled') : chalk.gray('○ disabled');
|
|
64
|
+
console.log(chalk.bold(`║ Claude: ${status} (${claudeModel})`));
|
|
65
|
+
console.log(chalk.gray(`║ ${detected.claude.version}`));
|
|
66
|
+
} else {
|
|
67
|
+
console.log(chalk.bold(`║ Claude: ${chalk.red('✗ not installed')}`));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Codex
|
|
71
|
+
const codexEnabled = config.engines?.codex?.enabled === true;
|
|
72
|
+
if (detected.codex.available) {
|
|
73
|
+
const status = codexEnabled ? chalk.green('✓ enabled') : chalk.gray('○ disabled');
|
|
74
|
+
console.log(chalk.bold(`║ Codex: ${status}`));
|
|
75
|
+
console.log(chalk.gray(`║ ${detected.codex.version}`));
|
|
76
|
+
} else {
|
|
77
|
+
console.log(chalk.bold(`║ Codex: ${chalk.gray('○ not installed')}`));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Gemini
|
|
81
|
+
const geminiEnabled = config.engines?.gemini?.enabled === true;
|
|
82
|
+
if (detected.gemini.available) {
|
|
83
|
+
const status = geminiEnabled ? chalk.green('✓ enabled') : chalk.gray('○ disabled');
|
|
84
|
+
console.log(chalk.bold(`║ Gemini: ${status}`));
|
|
85
|
+
console.log(chalk.gray(`║ ${detected.gemini.version}`));
|
|
86
|
+
} else {
|
|
87
|
+
console.log(chalk.bold(`║ Gemini: ${chalk.gray('○ not installed')}`));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log(chalk.bold('╚═══════════════════════════════════════════╝'));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Test an engine
|
|
95
|
+
*/
|
|
96
|
+
async function testEngine(engine) {
|
|
97
|
+
console.log(chalk.cyan(`Testing ${engine}...`));
|
|
98
|
+
|
|
99
|
+
if (engine === 'claude') {
|
|
100
|
+
try {
|
|
101
|
+
execSync('claude --version', { stdio: 'inherit' });
|
|
102
|
+
console.log(chalk.green(` ✓ Claude CLI is working`));
|
|
103
|
+
return true;
|
|
104
|
+
} catch {
|
|
105
|
+
console.log(chalk.red(` ✗ Claude CLI failed`));
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (engine === 'codex') {
|
|
111
|
+
try {
|
|
112
|
+
execSync('codex --version', { stdio: 'inherit' });
|
|
113
|
+
console.log(chalk.green(` ✓ Codex CLI is working`));
|
|
114
|
+
return true;
|
|
115
|
+
} catch {
|
|
116
|
+
console.log(chalk.red(` ✗ Codex CLI not found`));
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (engine === 'gemini') {
|
|
122
|
+
try {
|
|
123
|
+
execSync('gemini --version', { stdio: 'inherit' });
|
|
124
|
+
console.log(chalk.green(` ✓ Gemini CLI is working`));
|
|
125
|
+
return true;
|
|
126
|
+
} catch {
|
|
127
|
+
console.log(chalk.red(` ✗ Gemini CLI not found`));
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(chalk.yellow(` Engine ${engine} not testable`));
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Add/configure an engine (TRI CLI v0.4.0)
|
|
138
|
+
*/
|
|
139
|
+
async function addEngine() {
|
|
140
|
+
const detected = detectEngines();
|
|
141
|
+
|
|
142
|
+
const choices = [];
|
|
143
|
+
if (detected.claude.available) {
|
|
144
|
+
choices.push({ name: `Claude (${detected.claude.version})`, value: 'claude' });
|
|
145
|
+
}
|
|
146
|
+
if (detected.codex.available) {
|
|
147
|
+
choices.push({ name: `Codex (${detected.codex.version})`, value: 'codex' });
|
|
148
|
+
}
|
|
149
|
+
if (detected.gemini.available) {
|
|
150
|
+
choices.push({ name: `Gemini (${detected.gemini.version})`, value: 'gemini' });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (choices.length === 0) {
|
|
154
|
+
console.log(chalk.yellow(' No AI engines detected.'));
|
|
155
|
+
console.log(chalk.gray(' Install: claude, codex, or gemini CLI'));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const { engine } = await inquirer.prompt([{
|
|
160
|
+
type: 'list',
|
|
161
|
+
name: 'engine',
|
|
162
|
+
message: 'Select engine to configure:',
|
|
163
|
+
choices
|
|
164
|
+
}]);
|
|
165
|
+
|
|
166
|
+
if (engine === 'claude') {
|
|
167
|
+
const { model } = await inquirer.prompt([{
|
|
168
|
+
type: 'list',
|
|
169
|
+
name: 'model',
|
|
170
|
+
message: 'Default Claude model:',
|
|
171
|
+
choices: [
|
|
172
|
+
{ name: 'Haiku 4.5 (Fast)', value: 'haiku' },
|
|
173
|
+
{ name: 'Sonnet 4.5 (Balanced)', value: 'sonnet' },
|
|
174
|
+
{ name: 'Opus 4.5 (Most Intelligent)', value: 'opus' }
|
|
175
|
+
],
|
|
176
|
+
default: 'sonnet'
|
|
177
|
+
}]);
|
|
178
|
+
|
|
179
|
+
setConfigValue('engines.claude.enabled', true);
|
|
180
|
+
setConfigValue('engines.claude.model', model);
|
|
181
|
+
console.log(chalk.green(` ✓ Claude configured (${model})`));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (engine === 'codex') {
|
|
185
|
+
const { model } = await inquirer.prompt([{
|
|
186
|
+
type: 'list',
|
|
187
|
+
name: 'model',
|
|
188
|
+
message: 'Default Codex model:',
|
|
189
|
+
choices: [
|
|
190
|
+
{ name: 'GPT-5.1 Codex Max (Best)', value: 'gpt-5.1-codex-max' },
|
|
191
|
+
{ name: 'GPT-5.1 Codex', value: 'gpt-5.1-codex' },
|
|
192
|
+
{ name: 'GPT-5.1 Codex Mini (Fast)', value: 'gpt-5.1-codex-mini' },
|
|
193
|
+
{ name: 'GPT-5.1 (General)', value: 'gpt-5.1' }
|
|
194
|
+
],
|
|
195
|
+
default: 'gpt-5.1-codex-max'
|
|
196
|
+
}]);
|
|
197
|
+
|
|
198
|
+
setConfigValue('engines.codex.enabled', true);
|
|
199
|
+
setConfigValue('engines.codex.model', model);
|
|
200
|
+
console.log(chalk.green(` ✓ Codex configured (${model})`));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (engine === 'gemini') {
|
|
204
|
+
setConfigValue('engines.gemini.enabled', true);
|
|
205
|
+
setConfigValue('engines.gemini.model', 'gemini-3-pro-preview');
|
|
206
|
+
console.log(chalk.green(` ✓ Gemini configured (gemini-3-pro-preview)`));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Main engines command
|
|
212
|
+
*/
|
|
213
|
+
async function engines(action) {
|
|
214
|
+
console.log('');
|
|
215
|
+
|
|
216
|
+
if (!isInitialized()) {
|
|
217
|
+
console.log(chalk.yellow('NexusCLI is not configured.'));
|
|
218
|
+
console.log(`Run ${chalk.cyan('nexuscli init')} first.`);
|
|
219
|
+
console.log('');
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// No action = list
|
|
224
|
+
if (!action || action === 'list') {
|
|
225
|
+
listEngines();
|
|
226
|
+
console.log('');
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Add engine
|
|
231
|
+
if (action === 'add') {
|
|
232
|
+
await addEngine();
|
|
233
|
+
console.log('');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Test engine
|
|
238
|
+
if (action === 'test') {
|
|
239
|
+
const config = getConfig();
|
|
240
|
+
const active = config.engines?.active || ['claude'];
|
|
241
|
+
|
|
242
|
+
for (const eng of active) {
|
|
243
|
+
await testEngine(eng);
|
|
244
|
+
}
|
|
245
|
+
console.log('');
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
console.log(chalk.red(`Unknown action: ${action}`));
|
|
250
|
+
console.log('Usage:');
|
|
251
|
+
console.log(' nexuscli engines List engines');
|
|
252
|
+
console.log(' nexuscli engines add Add/configure engine');
|
|
253
|
+
console.log(' nexuscli engines test Test active engines');
|
|
254
|
+
console.log('');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
module.exports = engines;
|