@mmmbuto/nexuscli 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -4
- package/bin/nexuscli.js +6 -6
- package/frontend/dist/assets/{index-CikJbUR5.js → index-BAY_sRAu.js} +1704 -1704
- package/frontend/dist/assets/{index-Bn_l1e6e.css → index-CHOlrfA0.css} +1 -1
- package/frontend/dist/index.html +2 -2
- package/lib/server/.env.example +1 -1
- package/lib/server/db.js.old +225 -0
- package/lib/server/docs/API_WRAPPER_CONTRACT.md +682 -0
- package/lib/server/docs/ARCHITECTURE.md +441 -0
- package/lib/server/docs/DATABASE_SCHEMA.md +783 -0
- package/lib/server/docs/DESIGN_PRINCIPLES.md +598 -0
- package/lib/server/docs/NEXUSCHAT_ANALYSIS.md +488 -0
- package/lib/server/docs/PIPELINE_INTEGRATION.md +636 -0
- package/lib/server/docs/README.md +272 -0
- package/lib/server/docs/UI_DESIGN.md +916 -0
- package/lib/server/lib/pty-adapter.js +15 -1
- package/lib/server/routes/chat.js +70 -8
- package/lib/server/routes/codex.js +61 -7
- package/lib/server/routes/gemini.js +66 -12
- package/lib/server/routes/sessions.js +7 -2
- package/lib/server/server.js +2 -0
- package/lib/server/services/base-cli-wrapper.js +137 -0
- package/lib/server/services/claude-wrapper.js +11 -1
- package/lib/server/services/cli-loader.js.backup +446 -0
- package/lib/server/services/codex-output-parser.js +8 -0
- package/lib/server/services/codex-wrapper.js +13 -4
- package/lib/server/services/context-bridge.js +24 -20
- package/lib/server/services/gemini-wrapper.js +26 -8
- package/lib/server/services/session-manager.js +20 -0
- package/lib/server/services/workspace-manager.js +1 -1
- package/lib/server/tests/performance.test.js +1 -1
- package/lib/server/tests/services.test.js +2 -2
- package/package.json +1 -1
|
@@ -10,13 +10,14 @@
|
|
|
10
10
|
* - -o stream-json: JSON streaming output
|
|
11
11
|
* - --include-directories: Workspace access
|
|
12
12
|
*
|
|
13
|
-
* @version 0.
|
|
13
|
+
* @version 0.5.0 - Extended BaseCliWrapper for interrupt support
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const path = require('path');
|
|
18
18
|
const pty = require('../lib/pty-adapter');
|
|
19
19
|
const GeminiOutputParser = require('./gemini-output-parser');
|
|
20
|
+
const BaseCliWrapper = require('./base-cli-wrapper');
|
|
20
21
|
|
|
21
22
|
// Default model - Gemini 3 Pro Preview
|
|
22
23
|
const DEFAULT_MODEL = 'gemini-3-pro-preview';
|
|
@@ -24,8 +25,9 @@ const DEFAULT_MODEL = 'gemini-3-pro-preview';
|
|
|
24
25
|
// CLI timeout (10 minutes)
|
|
25
26
|
const CLI_TIMEOUT_MS = 600000;
|
|
26
27
|
|
|
27
|
-
class GeminiWrapper {
|
|
28
|
+
class GeminiWrapper extends BaseCliWrapper {
|
|
28
29
|
constructor(options = {}) {
|
|
30
|
+
super(); // Initialize activeProcesses from BaseCliWrapper
|
|
29
31
|
this.geminiPath = this._resolveGeminiPath(options.geminiPath);
|
|
30
32
|
this.workspaceDir = options.workspaceDir || process.cwd();
|
|
31
33
|
|
|
@@ -67,15 +69,15 @@ class GeminiWrapper {
|
|
|
67
69
|
*
|
|
68
70
|
* @param {Object} params
|
|
69
71
|
* @param {string} params.prompt - User message/prompt
|
|
70
|
-
* @param {string} params.
|
|
72
|
+
* @param {string} params.threadId - Native Gemini session ID for resume
|
|
71
73
|
* @param {string} [params.model='gemini-3-pro-preview'] - Model name
|
|
72
74
|
* @param {string} [params.workspacePath] - Workspace directory
|
|
73
75
|
* @param {Function} [params.onStatus] - Callback for status events (SSE streaming)
|
|
74
|
-
* @returns {Promise<{text: string, usage: Object}>}
|
|
76
|
+
* @returns {Promise<{text: string, usage: Object, sessionId: string}>}
|
|
75
77
|
*/
|
|
76
78
|
async sendMessage({
|
|
77
79
|
prompt,
|
|
78
|
-
|
|
80
|
+
threadId,
|
|
79
81
|
model = DEFAULT_MODEL,
|
|
80
82
|
workspacePath,
|
|
81
83
|
onStatus
|
|
@@ -87,16 +89,23 @@ class GeminiWrapper {
|
|
|
87
89
|
const cwd = workspacePath || this.workspaceDir;
|
|
88
90
|
|
|
89
91
|
// Build CLI arguments
|
|
90
|
-
//
|
|
92
|
+
// If threadId exists, use --resume to continue native session
|
|
91
93
|
const args = [
|
|
92
94
|
'-y', // YOLO mode - auto-approve all actions
|
|
93
95
|
'-m', model, // Model selection
|
|
94
96
|
'-o', 'stream-json', // JSON streaming for structured events
|
|
95
|
-
prompt // Prompt as positional argument
|
|
96
97
|
];
|
|
97
98
|
|
|
99
|
+
// Add resume flag if continuing existing session
|
|
100
|
+
if (threadId) {
|
|
101
|
+
args.push('--resume', threadId);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Add prompt as positional argument
|
|
105
|
+
args.push(prompt);
|
|
106
|
+
|
|
98
107
|
console.log(`[GeminiWrapper] Model: ${model}`);
|
|
99
|
-
console.log(`[GeminiWrapper]
|
|
108
|
+
console.log(`[GeminiWrapper] ThreadId: ${threadId || '(new session)'}`);
|
|
100
109
|
console.log(`[GeminiWrapper] CWD: ${cwd}`);
|
|
101
110
|
console.log(`[GeminiWrapper] Prompt length: ${prompt.length}`);
|
|
102
111
|
|
|
@@ -117,6 +126,11 @@ class GeminiWrapper {
|
|
|
117
126
|
return reject(new Error(`Failed to spawn Gemini CLI: ${spawnError.message}`));
|
|
118
127
|
}
|
|
119
128
|
|
|
129
|
+
// Register process for interrupt capability
|
|
130
|
+
// Use threadId if available, otherwise generate temp ID
|
|
131
|
+
const processId = threadId || `gemini-${Date.now()}`;
|
|
132
|
+
this.registerProcess(processId, ptyProcess, 'pty');
|
|
133
|
+
|
|
120
134
|
let stdout = '';
|
|
121
135
|
|
|
122
136
|
// Handle PTY data
|
|
@@ -145,6 +159,9 @@ class GeminiWrapper {
|
|
|
145
159
|
|
|
146
160
|
// Handle PTY exit
|
|
147
161
|
ptyProcess.onExit(({ exitCode }) => {
|
|
162
|
+
// Unregister process on exit
|
|
163
|
+
this.unregisterProcess(processId);
|
|
164
|
+
|
|
148
165
|
if (promiseSettled) return;
|
|
149
166
|
promiseSettled = true;
|
|
150
167
|
|
|
@@ -170,6 +187,7 @@ class GeminiWrapper {
|
|
|
170
187
|
|
|
171
188
|
resolve({
|
|
172
189
|
text: finalResponse,
|
|
190
|
+
sessionId: parser.getSessionId(), // Native Gemini session ID for resume
|
|
173
191
|
usage: {
|
|
174
192
|
prompt_tokens: promptTokens,
|
|
175
193
|
completion_tokens: completionTokens,
|
|
@@ -442,6 +442,26 @@ class SessionManager {
|
|
|
442
442
|
}
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
+
/**
|
|
446
|
+
* Bump session activity counters (message_count, last_used_at)
|
|
447
|
+
* @param {string} sessionId
|
|
448
|
+
* @param {number} increment
|
|
449
|
+
*/
|
|
450
|
+
bumpSessionActivity(sessionId, increment = 1) {
|
|
451
|
+
if (!sessionId) return;
|
|
452
|
+
try {
|
|
453
|
+
const stmt = prepare(`
|
|
454
|
+
UPDATE sessions
|
|
455
|
+
SET message_count = COALESCE(message_count, 0) + ?, last_used_at = ?
|
|
456
|
+
WHERE id = ?
|
|
457
|
+
`);
|
|
458
|
+
stmt.run(increment, Date.now(), sessionId);
|
|
459
|
+
saveDb();
|
|
460
|
+
} catch (error) {
|
|
461
|
+
console.warn(`[SessionManager] Failed to bump activity for ${sessionId}:`, error.message);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
445
465
|
/**
|
|
446
466
|
* Get all sessions for a conversation
|
|
447
467
|
*/
|
|
@@ -396,7 +396,7 @@ class WorkspaceManager {
|
|
|
396
396
|
* @returns {string}
|
|
397
397
|
*/
|
|
398
398
|
getSessionPath(workspacePath) {
|
|
399
|
-
// Convert /
|
|
399
|
+
// Convert /var/www/myapp → -var-www-myapp
|
|
400
400
|
const projectDir = workspacePath.replace(/\//g, '-').replace(/^-/, '');
|
|
401
401
|
return path.join(this.claudePath, 'projects', projectDir);
|
|
402
402
|
}
|
|
@@ -45,7 +45,7 @@ describe('Performance Benchmarks', () => {
|
|
|
45
45
|
|
|
46
46
|
test('Workspace validation should be fast', async () => {
|
|
47
47
|
const manager = new WorkspaceManager();
|
|
48
|
-
const testPath = '/
|
|
48
|
+
const testPath = '/var/www/myapp';
|
|
49
49
|
|
|
50
50
|
const start = Date.now();
|
|
51
51
|
const validated = await manager.validateWorkspace(testPath);
|
|
@@ -16,7 +16,7 @@ describe('WorkspaceManager', () => {
|
|
|
16
16
|
|
|
17
17
|
test('should validate workspace path', async () => {
|
|
18
18
|
// Test with allowed path
|
|
19
|
-
const validPath = '/
|
|
19
|
+
const validPath = '/var/www/myapp';
|
|
20
20
|
const result = await manager.validateWorkspace(validPath);
|
|
21
21
|
expect(result).toBe(validPath);
|
|
22
22
|
});
|
|
@@ -147,7 +147,7 @@ describe('SummaryGenerator', () => {
|
|
|
147
147
|
describe('Integration - Service Interactions', () => {
|
|
148
148
|
test('WorkspaceManager should use consistent path resolution', async () => {
|
|
149
149
|
const manager = new WorkspaceManager();
|
|
150
|
-
const testPath = '/
|
|
150
|
+
const testPath = '/var/www/myapp';
|
|
151
151
|
const validated = await manager.validateWorkspace(testPath);
|
|
152
152
|
expect(validated).toBe(testPath);
|
|
153
153
|
});
|