@mmmbuto/nexuscli 0.7.0 → 0.7.2
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 +2 -1
- package/bin/nexuscli.js +6 -13
- package/frontend/dist/assets/{index-DuqGKSR-.js → index-DgHku52j.js} +1704 -1704
- package/frontend/dist/index.html +1 -1
- package/lib/cli/model.js +38 -17
- package/lib/config/manager.js +0 -3
- package/lib/config/models.js +157 -0
- package/lib/server/.env.example +1 -1
- package/lib/server/routes/config.js +18 -3
- package/lib/server/routes/models.js +5 -152
- package/lib/server/routes/sessions.js +42 -3
- package/lib/server/server.js +0 -2
- package/lib/server/services/cli-loader.js +75 -13
- package/lib/server/services/codex-output-parser.js +0 -8
- package/lib/server/services/context-bridge.js +4 -6
- package/lib/server/services/gemini-wrapper.js +6 -14
- 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
- package/lib/server/db.js.old +0 -225
- package/lib/server/docs/API_WRAPPER_CONTRACT.md +0 -682
- package/lib/server/docs/ARCHITECTURE.md +0 -441
- package/lib/server/docs/DATABASE_SCHEMA.md +0 -783
- package/lib/server/docs/DESIGN_PRINCIPLES.md +0 -598
- package/lib/server/docs/NEXUSCHAT_ANALYSIS.md +0 -488
- package/lib/server/docs/PIPELINE_INTEGRATION.md +0 -636
- package/lib/server/docs/README.md +0 -272
- package/lib/server/docs/UI_DESIGN.md +0 -916
package/frontend/dist/index.html
CHANGED
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
|
|
60
60
|
<!-- Prevent Scaling on iOS -->
|
|
61
61
|
<meta name="format-detection" content="telephone=no" />
|
|
62
|
-
<script type="module" crossorigin src="/assets/index-
|
|
62
|
+
<script type="module" crossorigin src="/assets/index-DgHku52j.js"></script>
|
|
63
63
|
<link rel="stylesheet" crossorigin href="/assets/index-Bn_l1e6e.css">
|
|
64
64
|
</head>
|
|
65
65
|
<body>
|
package/lib/cli/model.js
CHANGED
|
@@ -4,9 +4,38 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const chalk = require('chalk');
|
|
7
|
-
const {
|
|
7
|
+
const {
|
|
8
|
+
getConfig,
|
|
9
|
+
setConfigValue,
|
|
10
|
+
isInitialized
|
|
11
|
+
} = require('../config/manager');
|
|
12
|
+
const {
|
|
13
|
+
getCliTools,
|
|
14
|
+
isValidModelId,
|
|
15
|
+
getAllModels
|
|
16
|
+
} = require('../config/models');
|
|
8
17
|
|
|
9
18
|
async function modelCommand(modelId) {
|
|
19
|
+
if (!isInitialized()) {
|
|
20
|
+
console.log(chalk.red('NexusCLI non è inizializzato.'));
|
|
21
|
+
console.log(chalk.yellow('Esegui prima: nexuscli init'));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const cliTools = getCliTools();
|
|
26
|
+
const allModels = getAllModels();
|
|
27
|
+
|
|
28
|
+
const printAvailableModels = () => {
|
|
29
|
+
console.log(chalk.bold('\nModelli disponibili:'));
|
|
30
|
+
for (const [key, cli] of Object.entries(cliTools)) {
|
|
31
|
+
console.log(chalk.dim(`${cli.name}:`));
|
|
32
|
+
for (const model of cli.models || []) {
|
|
33
|
+
const label = model.label || model.name;
|
|
34
|
+
const defaultTag = model.default ? chalk.green(' (default)') : '';
|
|
35
|
+
console.log(` ${model.id} ${chalk.gray(`- ${label}`)}${defaultTag}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
10
39
|
|
|
11
40
|
// If no model specified, show current default
|
|
12
41
|
if (!modelId) {
|
|
@@ -21,23 +50,15 @@ async function modelCommand(modelId) {
|
|
|
21
50
|
console.log(chalk.dim('Usage: nexuscli model <model-id>'));
|
|
22
51
|
}
|
|
23
52
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
console.log(' claude-opus-4-5-20250514');
|
|
29
|
-
console.log(' claude-3-7-sonnet-20250219');
|
|
30
|
-
console.log(' claude-haiku-4-5-20250514');
|
|
31
|
-
console.log(chalk.dim('OpenAI (Codex):'));
|
|
32
|
-
console.log(' gpt-5.1-codex-max');
|
|
33
|
-
console.log(' gpt-5.1');
|
|
34
|
-
console.log(' o1-preview');
|
|
35
|
-
console.log(' o1-mini');
|
|
36
|
-
console.log(chalk.dim('Google (Gemini):'));
|
|
37
|
-
console.log(' gemini-3-pro-preview');
|
|
38
|
-
console.log(' gemini-2-5-pro-exp-0827');
|
|
39
|
-
console.log(' gemini-2-0-flash-exp');
|
|
53
|
+
printAvailableModels();
|
|
54
|
+
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
40
57
|
|
|
58
|
+
if (!isValidModelId(modelId)) {
|
|
59
|
+
console.log(chalk.red(`✗ Modello non valido: ${modelId}`));
|
|
60
|
+
printAvailableModels();
|
|
61
|
+
process.exitCode = 1;
|
|
41
62
|
return;
|
|
42
63
|
}
|
|
43
64
|
|
package/lib/config/manager.js
CHANGED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared model catalog for NexusCLI (backend + CLI)
|
|
3
|
+
* Keep this as the single source of truth for available engines/models.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns the available CLI tools and their models.
|
|
8
|
+
* Shape is consumed by API, frontend, and CLI commands.
|
|
9
|
+
*/
|
|
10
|
+
function getCliTools() {
|
|
11
|
+
return {
|
|
12
|
+
// ============================================================
|
|
13
|
+
// CLAUDE - Anthropic Claude Code CLI
|
|
14
|
+
// ============================================================
|
|
15
|
+
'claude': {
|
|
16
|
+
name: 'Claude Code',
|
|
17
|
+
icon: 'Terminal',
|
|
18
|
+
enabled: true,
|
|
19
|
+
endpoint: '/api/v1/chat',
|
|
20
|
+
thinkModes: ['think', 'no-think'],
|
|
21
|
+
defaultThinkMode: 'think',
|
|
22
|
+
models: [
|
|
23
|
+
// === Claude Opus 4.5 (Most Intelligent) ===
|
|
24
|
+
{
|
|
25
|
+
id: 'claude-opus-4-5-20251101',
|
|
26
|
+
name: 'claude-opus-4-5-20251101',
|
|
27
|
+
label: 'Opus 4.5',
|
|
28
|
+
description: '🧠 Most Intelligent',
|
|
29
|
+
category: 'claude'
|
|
30
|
+
},
|
|
31
|
+
// === Claude Sonnet 4.5 (Best Balance) ===
|
|
32
|
+
{
|
|
33
|
+
id: 'claude-sonnet-4-5-20250929',
|
|
34
|
+
name: 'claude-sonnet-4-5-20250929',
|
|
35
|
+
label: 'Sonnet 4.5',
|
|
36
|
+
description: '🧠 Extended Thinking (default)',
|
|
37
|
+
category: 'claude',
|
|
38
|
+
default: true
|
|
39
|
+
},
|
|
40
|
+
// === Claude Haiku 4.5 (Fastest) ===
|
|
41
|
+
{
|
|
42
|
+
id: 'claude-haiku-4-5-20251001',
|
|
43
|
+
name: 'claude-haiku-4-5-20251001',
|
|
44
|
+
label: 'Haiku 4.5',
|
|
45
|
+
description: '⚡ Fast & Efficient',
|
|
46
|
+
category: 'claude'
|
|
47
|
+
},
|
|
48
|
+
// === DeepSeek (Alternative Models) ===
|
|
49
|
+
{
|
|
50
|
+
id: 'deepseek-reasoner',
|
|
51
|
+
name: 'deepseek-reasoner',
|
|
52
|
+
label: 'DeepSeek Reasoner',
|
|
53
|
+
description: '🧠 Deep Reasoning',
|
|
54
|
+
category: 'claude'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'deepseek-chat',
|
|
58
|
+
name: 'deepseek-chat',
|
|
59
|
+
label: 'DeepSeek Chat',
|
|
60
|
+
description: '💬 Fast Chat',
|
|
61
|
+
category: 'claude'
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// ============================================================
|
|
67
|
+
// CODEX - OpenAI Codex CLI
|
|
68
|
+
// ============================================================
|
|
69
|
+
'codex': {
|
|
70
|
+
name: 'Codex',
|
|
71
|
+
icon: 'Code2',
|
|
72
|
+
enabled: true,
|
|
73
|
+
endpoint: '/api/v1/codex',
|
|
74
|
+
models: [
|
|
75
|
+
{
|
|
76
|
+
id: 'gpt-5.1-codex-max',
|
|
77
|
+
name: 'gpt-5.1-codex-max',
|
|
78
|
+
label: 'GPT-5.1 Codex Max',
|
|
79
|
+
description: '💎 Extra High reasoning (best)',
|
|
80
|
+
category: 'codex',
|
|
81
|
+
reasoningEfforts: ['low', 'medium', 'high', 'xhigh'],
|
|
82
|
+
defaultReasoning: 'xhigh',
|
|
83
|
+
default: true
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 'gpt-5.1-codex',
|
|
87
|
+
name: 'gpt-5.1-codex',
|
|
88
|
+
label: 'GPT-5.1 Codex',
|
|
89
|
+
description: '🧠 High reasoning',
|
|
90
|
+
category: 'codex',
|
|
91
|
+
reasoningEfforts: ['low', 'medium', 'high'],
|
|
92
|
+
defaultReasoning: 'high'
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'gpt-5.1-codex-mini',
|
|
96
|
+
name: 'gpt-5.1-codex-mini',
|
|
97
|
+
label: 'GPT-5.1 Codex Mini',
|
|
98
|
+
description: '⚡ Compact & Fast',
|
|
99
|
+
category: 'codex',
|
|
100
|
+
reasoningEfforts: ['medium', 'high'],
|
|
101
|
+
defaultReasoning: 'high'
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: 'gpt-5.1',
|
|
105
|
+
name: 'gpt-5.1',
|
|
106
|
+
label: 'GPT-5.1',
|
|
107
|
+
description: '🧠 General Purpose',
|
|
108
|
+
category: 'codex',
|
|
109
|
+
reasoningEfforts: ['low', 'medium', 'high'],
|
|
110
|
+
defaultReasoning: 'high'
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
// ============================================================
|
|
116
|
+
// GEMINI - Google Gemini CLI
|
|
117
|
+
// ============================================================
|
|
118
|
+
'gemini': {
|
|
119
|
+
name: 'Gemini',
|
|
120
|
+
icon: 'Sparkles',
|
|
121
|
+
enabled: true,
|
|
122
|
+
endpoint: '/api/v1/gemini',
|
|
123
|
+
models: [
|
|
124
|
+
{
|
|
125
|
+
id: 'gemini-3-pro-preview',
|
|
126
|
+
name: 'gemini-3-pro-preview',
|
|
127
|
+
label: 'Gemini 3 Pro',
|
|
128
|
+
description: '🚀 Latest Preview',
|
|
129
|
+
category: 'gemini',
|
|
130
|
+
default: true
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function getAllModels() {
|
|
138
|
+
return Object.values(getCliTools()).flatMap(cli => cli.models || []);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function isValidModelId(modelId) {
|
|
142
|
+
if (!modelId) return false;
|
|
143
|
+
return getAllModels().some(m => m.id === modelId);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function getDefaultModelId() {
|
|
147
|
+
const models = getAllModels();
|
|
148
|
+
const withDefault = models.find(m => m.default);
|
|
149
|
+
return withDefault ? withDefault.id : (models[0]?.id || null);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = {
|
|
153
|
+
getCliTools,
|
|
154
|
+
getAllModels,
|
|
155
|
+
isValidModelId,
|
|
156
|
+
getDefaultModelId
|
|
157
|
+
};
|
package/lib/server/.env.example
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
const express = require('express');
|
|
7
7
|
const router = express.Router();
|
|
8
8
|
const { getConfig } = require('../../config/manager');
|
|
9
|
+
const {
|
|
10
|
+
isValidModelId,
|
|
11
|
+
getDefaultModelId
|
|
12
|
+
} = require('../../config/models');
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
15
|
* GET /api/v1/config
|
|
@@ -15,10 +19,21 @@ router.get('/', (req, res) => {
|
|
|
15
19
|
try {
|
|
16
20
|
const config = getConfig();
|
|
17
21
|
|
|
22
|
+
const preferred = config.preferences?.defaultModel || null;
|
|
23
|
+
let defaultModel = preferred;
|
|
24
|
+
|
|
25
|
+
// Sanitize preferred model; fallback to catalog default to avoid broken UI
|
|
26
|
+
if (defaultModel && !isValidModelId(defaultModel)) {
|
|
27
|
+
console.warn('[Config API] Invalid defaultModel in config:', defaultModel);
|
|
28
|
+
defaultModel = null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!defaultModel) {
|
|
32
|
+
defaultModel = getDefaultModelId();
|
|
33
|
+
}
|
|
34
|
+
|
|
18
35
|
// Return only preferences (not sensitive data like auth)
|
|
19
|
-
const preferences = {
|
|
20
|
-
defaultModel: config.preferences?.defaultModel || null
|
|
21
|
-
};
|
|
36
|
+
const preferences = { defaultModel };
|
|
22
37
|
|
|
23
38
|
res.json(preferences);
|
|
24
39
|
} catch (error) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const router = express.Router();
|
|
3
|
+
const { getCliTools } = require('../../config/models');
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* GET /api/v1/models
|
|
@@ -12,131 +13,7 @@ const router = express.Router();
|
|
|
12
13
|
*/
|
|
13
14
|
router.get('/', (req, res) => {
|
|
14
15
|
try {
|
|
15
|
-
const cliTools =
|
|
16
|
-
// ============================================================
|
|
17
|
-
// CLAUDE - Anthropic Claude Code CLI
|
|
18
|
-
// ============================================================
|
|
19
|
-
'claude': {
|
|
20
|
-
name: 'Claude Code',
|
|
21
|
-
icon: 'Terminal',
|
|
22
|
-
enabled: true,
|
|
23
|
-
endpoint: '/api/v1/chat',
|
|
24
|
-
thinkModes: ['think', 'no-think'],
|
|
25
|
-
defaultThinkMode: 'think',
|
|
26
|
-
models: [
|
|
27
|
-
// === Claude Opus 4.5 (Most Intelligent) ===
|
|
28
|
-
{
|
|
29
|
-
id: 'claude-opus-4-5-20251101',
|
|
30
|
-
name: 'claude-opus-4-5-20251101',
|
|
31
|
-
label: 'Opus 4.5',
|
|
32
|
-
description: '🧠 Most Intelligent',
|
|
33
|
-
category: 'claude'
|
|
34
|
-
},
|
|
35
|
-
// === Claude Sonnet 4.5 (Best Balance) ===
|
|
36
|
-
{
|
|
37
|
-
id: 'claude-sonnet-4-5-20250929',
|
|
38
|
-
name: 'claude-sonnet-4-5-20250929',
|
|
39
|
-
label: 'Sonnet 4.5',
|
|
40
|
-
description: '🧠 Extended Thinking (default)',
|
|
41
|
-
category: 'claude',
|
|
42
|
-
default: true
|
|
43
|
-
},
|
|
44
|
-
// === Claude Haiku 4.5 (Fastest) ===
|
|
45
|
-
{
|
|
46
|
-
id: 'claude-haiku-4-5-20251001',
|
|
47
|
-
name: 'claude-haiku-4-5-20251001',
|
|
48
|
-
label: 'Haiku 4.5',
|
|
49
|
-
description: '⚡ Fast & Efficient',
|
|
50
|
-
category: 'claude'
|
|
51
|
-
},
|
|
52
|
-
// === DeepSeek (Alternative Models) ===
|
|
53
|
-
{
|
|
54
|
-
id: 'deepseek-reasoner',
|
|
55
|
-
name: 'deepseek-reasoner',
|
|
56
|
-
label: 'DeepSeek Reasoner',
|
|
57
|
-
description: '🧠 Deep Reasoning',
|
|
58
|
-
category: 'claude'
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
id: 'deepseek-chat',
|
|
62
|
-
name: 'deepseek-chat',
|
|
63
|
-
label: 'DeepSeek Chat',
|
|
64
|
-
description: '💬 Fast Chat',
|
|
65
|
-
category: 'claude'
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
// ============================================================
|
|
71
|
-
// CODEX - OpenAI Codex CLI
|
|
72
|
-
// ============================================================
|
|
73
|
-
'codex': {
|
|
74
|
-
name: 'Codex',
|
|
75
|
-
icon: 'Code2',
|
|
76
|
-
enabled: true,
|
|
77
|
-
endpoint: '/api/v1/codex',
|
|
78
|
-
models: [
|
|
79
|
-
{
|
|
80
|
-
id: 'gpt-5.1-codex-max',
|
|
81
|
-
name: 'gpt-5.1-codex-max',
|
|
82
|
-
label: 'GPT-5.1 Codex Max',
|
|
83
|
-
description: '💎 Extra High reasoning (best)',
|
|
84
|
-
category: 'codex',
|
|
85
|
-
reasoningEfforts: ['low', 'medium', 'high', 'xhigh'],
|
|
86
|
-
defaultReasoning: 'xhigh',
|
|
87
|
-
default: true
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
id: 'gpt-5.1-codex',
|
|
91
|
-
name: 'gpt-5.1-codex',
|
|
92
|
-
label: 'GPT-5.1 Codex',
|
|
93
|
-
description: '🧠 High reasoning',
|
|
94
|
-
category: 'codex',
|
|
95
|
-
reasoningEfforts: ['low', 'medium', 'high'],
|
|
96
|
-
defaultReasoning: 'high'
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
id: 'gpt-5.1-codex-mini',
|
|
100
|
-
name: 'gpt-5.1-codex-mini',
|
|
101
|
-
label: 'GPT-5.1 Codex Mini',
|
|
102
|
-
description: '⚡ Compact & Fast',
|
|
103
|
-
category: 'codex',
|
|
104
|
-
reasoningEfforts: ['medium', 'high'],
|
|
105
|
-
defaultReasoning: 'high'
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
id: 'gpt-5.1',
|
|
109
|
-
name: 'gpt-5.1',
|
|
110
|
-
label: 'GPT-5.1',
|
|
111
|
-
description: '🧠 General Purpose',
|
|
112
|
-
category: 'codex',
|
|
113
|
-
reasoningEfforts: ['low', 'medium', 'high'],
|
|
114
|
-
defaultReasoning: 'high'
|
|
115
|
-
}
|
|
116
|
-
]
|
|
117
|
-
},
|
|
118
|
-
|
|
119
|
-
// ============================================================
|
|
120
|
-
// GEMINI - Google Gemini CLI
|
|
121
|
-
// ============================================================
|
|
122
|
-
'gemini': {
|
|
123
|
-
name: 'Gemini',
|
|
124
|
-
icon: 'Sparkles',
|
|
125
|
-
enabled: true,
|
|
126
|
-
endpoint: '/api/v1/gemini',
|
|
127
|
-
models: [
|
|
128
|
-
{
|
|
129
|
-
id: 'gemini-3-pro-preview',
|
|
130
|
-
name: 'gemini-3-pro-preview',
|
|
131
|
-
label: 'Gemini 3 Pro',
|
|
132
|
-
description: '🚀 Latest Preview',
|
|
133
|
-
category: 'gemini',
|
|
134
|
-
default: true
|
|
135
|
-
}
|
|
136
|
-
]
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
16
|
+
const cliTools = getCliTools();
|
|
140
17
|
res.json(cliTools);
|
|
141
18
|
} catch (error) {
|
|
142
19
|
console.error('[Models] Error fetching models:', error);
|
|
@@ -151,6 +28,7 @@ router.get('/', (req, res) => {
|
|
|
151
28
|
router.get('/:engine', (req, res) => {
|
|
152
29
|
try {
|
|
153
30
|
const { engine } = req.params;
|
|
31
|
+
const cliTools = getCliTools();
|
|
154
32
|
|
|
155
33
|
// Normalize engine name
|
|
156
34
|
let normalizedEngine = engine.toLowerCase();
|
|
@@ -158,37 +36,12 @@ router.get('/:engine', (req, res) => {
|
|
|
158
36
|
if (normalizedEngine.includes('codex') || normalizedEngine.includes('openai')) normalizedEngine = 'codex';
|
|
159
37
|
if (normalizedEngine.includes('gemini') || normalizedEngine.includes('google')) normalizedEngine = 'gemini';
|
|
160
38
|
|
|
161
|
-
const cliTools = {
|
|
162
|
-
'claude': {
|
|
163
|
-
name: 'Claude Code',
|
|
164
|
-
models: [
|
|
165
|
-
{ id: 'claude-opus-4-5-20251101', label: 'Opus 4.5', description: '🧠 Most Intelligent' },
|
|
166
|
-
{ id: 'claude-sonnet-4-5-20250929', label: 'Sonnet 4.5', description: '🧠 Extended Thinking', default: true },
|
|
167
|
-
{ id: 'claude-haiku-4-5-20251001', label: 'Haiku 4.5', description: '⚡ Fast & Efficient' },
|
|
168
|
-
]
|
|
169
|
-
},
|
|
170
|
-
'codex': {
|
|
171
|
-
name: 'Codex',
|
|
172
|
-
models: [
|
|
173
|
-
{ id: 'gpt-5.1-codex-max', label: 'GPT-5.1 Codex Max', description: '💎 Best Quality', default: true },
|
|
174
|
-
{ id: 'gpt-5.1-codex', label: 'GPT-5.1 Codex', description: '🧠 High reasoning' },
|
|
175
|
-
{ id: 'gpt-5.1-codex-mini', label: 'GPT-5.1 Codex Mini', description: '⚡ Fast' },
|
|
176
|
-
{ id: 'gpt-5.1', label: 'GPT-5.1', description: '🧠 General Purpose' },
|
|
177
|
-
]
|
|
178
|
-
},
|
|
179
|
-
'gemini': {
|
|
180
|
-
name: 'Gemini',
|
|
181
|
-
models: [
|
|
182
|
-
{ id: 'gemini-3-pro-preview', label: 'Gemini 3 Pro', description: '🚀 Latest', default: true },
|
|
183
|
-
]
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
|
|
187
39
|
if (!cliTools[normalizedEngine]) {
|
|
188
40
|
return res.status(404).json({ error: `Engine not found: ${engine}` });
|
|
189
41
|
}
|
|
190
42
|
|
|
191
|
-
|
|
43
|
+
const { name, models } = cliTools[normalizedEngine];
|
|
44
|
+
res.json({ name, models });
|
|
192
45
|
} catch (error) {
|
|
193
46
|
console.error('[Models] Error fetching engine models:', error);
|
|
194
47
|
res.status(500).json({ error: 'Failed to fetch models' });
|
|
@@ -66,6 +66,8 @@ router.get('/:id/messages', async (req, res) => {
|
|
|
66
66
|
|
|
67
67
|
const { messages, pagination } = await cliLoader.loadMessagesFromCLI({
|
|
68
68
|
sessionId,
|
|
69
|
+
threadId: session.session_path, // native thread id (Codex/Gemini)
|
|
70
|
+
sessionPath: session.session_path,
|
|
69
71
|
engine: session.engine || 'claude-code',
|
|
70
72
|
workspacePath: session.workspace_path,
|
|
71
73
|
limit,
|
|
@@ -147,6 +149,8 @@ router.post('/:id/summarize', async (req, res) => {
|
|
|
147
149
|
// Load messages from CLI history
|
|
148
150
|
const { messages } = await cliLoader.loadMessagesFromCLI({
|
|
149
151
|
sessionId,
|
|
152
|
+
threadId: session.session_path,
|
|
153
|
+
sessionPath: session.session_path,
|
|
150
154
|
engine: session.engine || 'claude-code',
|
|
151
155
|
workspacePath: session.workspace_path,
|
|
152
156
|
limit,
|
|
@@ -224,7 +228,7 @@ router.delete('/:id', async (req, res) => {
|
|
|
224
228
|
|
|
225
229
|
// Delete the original .jsonl file (SYNC DELETE)
|
|
226
230
|
let fileDeleted = false;
|
|
227
|
-
const sessionFile = getSessionFilePath(sessionId, session.engine, session.workspace_path);
|
|
231
|
+
const sessionFile = getSessionFilePath(sessionId, session.engine, session.workspace_path, session.session_path);
|
|
228
232
|
if (sessionFile && fs.existsSync(sessionFile)) {
|
|
229
233
|
try {
|
|
230
234
|
fs.unlinkSync(sessionFile);
|
|
@@ -263,7 +267,7 @@ function pathToSlug(workspacePath) {
|
|
|
263
267
|
/**
|
|
264
268
|
* Helper: Get the filesystem path for a session file
|
|
265
269
|
*/
|
|
266
|
-
function getSessionFilePath(sessionId, engine, workspacePath) {
|
|
270
|
+
function getSessionFilePath(sessionId, engine, workspacePath, sessionPath) {
|
|
267
271
|
const normalizedEngine = engine?.toLowerCase().includes('claude') ? 'claude'
|
|
268
272
|
: engine?.toLowerCase().includes('codex') ? 'codex'
|
|
269
273
|
: engine?.toLowerCase().includes('gemini') ? 'gemini'
|
|
@@ -274,7 +278,12 @@ function getSessionFilePath(sessionId, engine, workspacePath) {
|
|
|
274
278
|
const slug = pathToSlug(workspacePath);
|
|
275
279
|
return path.join(SESSION_DIRS.claude, slug, `${sessionId}.jsonl`);
|
|
276
280
|
case 'codex':
|
|
277
|
-
|
|
281
|
+
// Try native threadId first, then legacy sessionId
|
|
282
|
+
const nativeId = sessionPath || sessionId;
|
|
283
|
+
const baseDir = SESSION_DIRS.codex;
|
|
284
|
+
const flatPath = path.join(baseDir, `${nativeId}.jsonl`);
|
|
285
|
+
if (fs.existsSync(flatPath)) return flatPath;
|
|
286
|
+
return findCodexSessionFile(baseDir, nativeId);
|
|
278
287
|
case 'gemini':
|
|
279
288
|
return path.join(SESSION_DIRS.gemini, `${sessionId}.jsonl`);
|
|
280
289
|
default:
|
|
@@ -282,4 +291,34 @@ function getSessionFilePath(sessionId, engine, workspacePath) {
|
|
|
282
291
|
}
|
|
283
292
|
}
|
|
284
293
|
|
|
294
|
+
function findCodexSessionFile(baseDir, threadId) {
|
|
295
|
+
if (!threadId || !fs.existsSync(baseDir)) return null;
|
|
296
|
+
try {
|
|
297
|
+
const years = fs.readdirSync(baseDir);
|
|
298
|
+
for (const year of years) {
|
|
299
|
+
const yearPath = path.join(baseDir, year);
|
|
300
|
+
if (!fs.statSync(yearPath).isDirectory()) continue;
|
|
301
|
+
const months = fs.readdirSync(yearPath);
|
|
302
|
+
for (const month of months) {
|
|
303
|
+
const monthPath = path.join(yearPath, month);
|
|
304
|
+
if (!fs.statSync(monthPath).isDirectory()) continue;
|
|
305
|
+
const days = fs.readdirSync(monthPath);
|
|
306
|
+
for (const day of days) {
|
|
307
|
+
const dayPath = path.join(monthPath, day);
|
|
308
|
+
if (!fs.statSync(dayPath).isDirectory()) continue;
|
|
309
|
+
const files = fs.readdirSync(dayPath);
|
|
310
|
+
for (const file of files) {
|
|
311
|
+
if (file.endsWith('.jsonl') && file.includes(threadId)) {
|
|
312
|
+
return path.join(dayPath, file);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
} catch (err) {
|
|
319
|
+
console.warn(`[Sessions] Failed to search Codex session file: ${err.message}`);
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
|
|
285
324
|
module.exports = router;
|
package/lib/server/server.js
CHANGED
|
@@ -28,7 +28,6 @@ const wakeLockRouter = require('./routes/wake-lock');
|
|
|
28
28
|
const uploadRouter = require('./routes/upload');
|
|
29
29
|
const keysRouter = require('./routes/keys');
|
|
30
30
|
const speechRouter = require('./routes/speech');
|
|
31
|
-
const configRouter = require('./routes/config');
|
|
32
31
|
|
|
33
32
|
const app = express();
|
|
34
33
|
const PORT = process.env.PORT || 41800;
|
|
@@ -63,7 +62,6 @@ app.use(express.static(frontendDist));
|
|
|
63
62
|
// Public routes
|
|
64
63
|
app.use('/api/v1/auth', authRouter);
|
|
65
64
|
app.use('/api/v1/models', modelsRouter);
|
|
66
|
-
app.use('/api/v1/config', configRouter);
|
|
67
65
|
app.use('/api/v1/workspace', workspaceRouter);
|
|
68
66
|
app.use('/api/v1', wakeLockRouter); // Wake lock endpoints (public for app visibility handling)
|
|
69
67
|
app.use('/api/v1/workspaces', authMiddleware, workspacesRouter);
|