@cloudcli-ai/cloudcli 1.29.2 → 1.29.4
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/dist/assets/{index-ByHZ8-LL.css → index-BBAE1OJ_.css} +1 -1
- package/dist/assets/{index-Ile1bTCU.js → index-Cyya3LhN.js} +229 -229
- package/dist/index.html +2 -2
- package/dist-server/server/claude-sdk.js +702 -0
- package/dist-server/server/claude-sdk.js.map +1 -0
- package/dist-server/server/cli.js +642 -0
- package/dist-server/server/cli.js.map +1 -0
- package/dist-server/server/constants/config.js +6 -0
- package/dist-server/server/constants/config.js.map +1 -0
- package/dist-server/server/cursor-cli.js +277 -0
- package/dist-server/server/cursor-cli.js.map +1 -0
- package/dist-server/server/database/db.js +535 -0
- package/dist-server/server/database/db.js.map +1 -0
- package/dist-server/server/database/schema.js +97 -0
- package/dist-server/server/database/schema.js.map +1 -0
- package/dist-server/server/gemini-cli.js +408 -0
- package/dist-server/server/gemini-cli.js.map +1 -0
- package/dist-server/server/gemini-response-handler.js +72 -0
- package/dist-server/server/gemini-response-handler.js.map +1 -0
- package/dist-server/server/index.js +2175 -0
- package/dist-server/server/index.js.map +1 -0
- package/dist-server/server/load-env.js +32 -0
- package/dist-server/server/load-env.js.map +1 -0
- package/dist-server/server/middleware/auth.js +111 -0
- package/dist-server/server/middleware/auth.js.map +1 -0
- package/dist-server/server/openai-codex.js +373 -0
- package/dist-server/server/openai-codex.js.map +1 -0
- package/dist-server/server/projects.js +2325 -0
- package/dist-server/server/projects.js.map +1 -0
- package/dist-server/server/providers/claude/adapter.js +266 -0
- package/dist-server/server/providers/claude/adapter.js.map +1 -0
- package/dist-server/server/providers/claude/status.js +121 -0
- package/dist-server/server/providers/claude/status.js.map +1 -0
- package/dist-server/server/providers/codex/adapter.js +232 -0
- package/dist-server/server/providers/codex/adapter.js.map +1 -0
- package/dist-server/server/providers/codex/status.js +70 -0
- package/dist-server/server/providers/codex/status.js.map +1 -0
- package/dist-server/server/providers/cursor/adapter.js +342 -0
- package/dist-server/server/providers/cursor/adapter.js.map +1 -0
- package/dist-server/server/providers/cursor/status.js +118 -0
- package/dist-server/server/providers/cursor/status.js.map +1 -0
- package/dist-server/server/providers/gemini/adapter.js +174 -0
- package/dist-server/server/providers/gemini/adapter.js.map +1 -0
- package/dist-server/server/providers/gemini/status.js +104 -0
- package/dist-server/server/providers/gemini/status.js.map +1 -0
- package/dist-server/server/providers/registry.js +58 -0
- package/dist-server/server/providers/registry.js.map +1 -0
- package/dist-server/server/providers/types.js +117 -0
- package/dist-server/server/providers/types.js.map +1 -0
- package/dist-server/server/providers/utils.js +28 -0
- package/dist-server/server/providers/utils.js.map +1 -0
- package/dist-server/server/routes/agent.js +1147 -0
- package/dist-server/server/routes/agent.js.map +1 -0
- package/dist-server/server/routes/auth.js +117 -0
- package/dist-server/server/routes/auth.js.map +1 -0
- package/dist-server/server/routes/cli-auth.js +25 -0
- package/dist-server/server/routes/cli-auth.js.map +1 -0
- package/dist-server/server/routes/codex.js +294 -0
- package/dist-server/server/routes/codex.js.map +1 -0
- package/dist-server/server/routes/commands.js +531 -0
- package/dist-server/server/routes/commands.js.map +1 -0
- package/dist-server/server/routes/cursor.js +529 -0
- package/dist-server/server/routes/cursor.js.map +1 -0
- package/dist-server/server/routes/gemini.js +21 -0
- package/dist-server/server/routes/gemini.js.map +1 -0
- package/dist-server/server/routes/git.js +1259 -0
- package/dist-server/server/routes/git.js.map +1 -0
- package/dist-server/server/routes/mcp-utils.js +46 -0
- package/dist-server/server/routes/mcp-utils.js.map +1 -0
- package/dist-server/server/routes/mcp.js +480 -0
- package/dist-server/server/routes/mcp.js.map +1 -0
- package/dist-server/server/routes/messages.js +56 -0
- package/dist-server/server/routes/messages.js.map +1 -0
- package/dist-server/server/routes/plugins.js +266 -0
- package/dist-server/server/routes/plugins.js.map +1 -0
- package/dist-server/server/routes/projects.js +505 -0
- package/dist-server/server/routes/projects.js.map +1 -0
- package/dist-server/server/routes/settings.js +249 -0
- package/dist-server/server/routes/settings.js.map +1 -0
- package/dist-server/server/routes/taskmaster.js +1832 -0
- package/dist-server/server/routes/taskmaster.js.map +1 -0
- package/dist-server/server/routes/user.js +115 -0
- package/dist-server/server/routes/user.js.map +1 -0
- package/dist-server/server/services/notification-orchestrator.js +177 -0
- package/dist-server/server/services/notification-orchestrator.js.map +1 -0
- package/dist-server/server/services/vapid-keys.js +26 -0
- package/dist-server/server/services/vapid-keys.js.map +1 -0
- package/dist-server/server/sessionManager.js +194 -0
- package/dist-server/server/sessionManager.js.map +1 -0
- package/dist-server/server/utils/colors.js +20 -0
- package/dist-server/server/utils/colors.js.map +1 -0
- package/dist-server/server/utils/commandParser.js +255 -0
- package/dist-server/server/utils/commandParser.js.map +1 -0
- package/dist-server/server/utils/frontmatter.js +16 -0
- package/dist-server/server/utils/frontmatter.js.map +1 -0
- package/dist-server/server/utils/gitConfig.js +36 -0
- package/dist-server/server/utils/gitConfig.js.map +1 -0
- package/dist-server/server/utils/mcp-detector.js +183 -0
- package/dist-server/server/utils/mcp-detector.js.map +1 -0
- package/dist-server/server/utils/plugin-loader.js +413 -0
- package/dist-server/server/utils/plugin-loader.js.map +1 -0
- package/dist-server/server/utils/plugin-process-manager.js +163 -0
- package/dist-server/server/utils/plugin-process-manager.js.map +1 -0
- package/dist-server/server/utils/runtime-paths.js +30 -0
- package/dist-server/server/utils/runtime-paths.js.map +1 -0
- package/dist-server/server/utils/taskmaster-websocket.js +118 -0
- package/dist-server/server/utils/taskmaster-websocket.js.map +1 -0
- package/dist-server/server/utils/url-detection.js +58 -0
- package/dist-server/server/utils/url-detection.js.map +1 -0
- package/dist-server/shared/modelConstants.js +87 -0
- package/dist-server/shared/modelConstants.js.map +1 -0
- package/dist-server/shared/networkHosts.js +20 -0
- package/dist-server/shared/networkHosts.js.map +1 -0
- package/package.json +23 -14
- package/server/claude-sdk.js +13 -4
- package/server/cli.js +13 -9
- package/server/cursor-cli.js +8 -1
- package/server/database/db.js +24 -61
- package/server/database/schema.js +102 -0
- package/server/gemini-cli.js +17 -1
- package/server/index.js +20 -96
- package/server/load-env.js +11 -6
- package/server/openai-codex.js +9 -1
- package/server/projects.js +38 -44
- package/server/providers/claude/status.js +136 -0
- package/server/providers/codex/status.js +78 -0
- package/server/providers/cursor/adapter.js +5 -10
- package/server/providers/cursor/status.js +128 -0
- package/server/providers/gemini/status.js +111 -0
- package/server/providers/registry.js +25 -2
- package/server/providers/types.js +13 -0
- package/server/routes/cli-auth.js +14 -421
- package/server/routes/commands.js +6 -4
- package/server/routes/cursor.js +6 -240
- package/server/tsconfig.json +33 -0
- package/server/utils/colors.js +21 -0
- package/server/utils/runtime-paths.js +37 -0
- package/server/utils/url-detection.js +71 -0
- package/shared/modelConstants.js +4 -2
- package/server/database/init.sql +0 -99
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex (OpenAI) provider adapter.
|
|
3
|
+
*
|
|
4
|
+
* Normalizes Codex SDK session history into NormalizedMessage format.
|
|
5
|
+
* @module adapters/codex
|
|
6
|
+
*/
|
|
7
|
+
import { getCodexSessionMessages } from '../../projects.js';
|
|
8
|
+
import { createNormalizedMessage, generateMessageId } from '../types.js';
|
|
9
|
+
const PROVIDER = 'codex';
|
|
10
|
+
/**
|
|
11
|
+
* Normalize a raw Codex JSONL message into NormalizedMessage(s).
|
|
12
|
+
* @param {object} raw - A single parsed message from Codex JSONL
|
|
13
|
+
* @param {string} sessionId
|
|
14
|
+
* @returns {import('../types.js').NormalizedMessage[]}
|
|
15
|
+
*/
|
|
16
|
+
function normalizeCodexHistoryEntry(raw, sessionId) {
|
|
17
|
+
const ts = raw.timestamp || new Date().toISOString();
|
|
18
|
+
const baseId = raw.uuid || generateMessageId('codex');
|
|
19
|
+
// User message
|
|
20
|
+
if (raw.message?.role === 'user') {
|
|
21
|
+
const content = typeof raw.message.content === 'string'
|
|
22
|
+
? raw.message.content
|
|
23
|
+
: Array.isArray(raw.message.content)
|
|
24
|
+
? raw.message.content.map(p => typeof p === 'string' ? p : p?.text || '').filter(Boolean).join('\n')
|
|
25
|
+
: String(raw.message.content || '');
|
|
26
|
+
if (!content.trim())
|
|
27
|
+
return [];
|
|
28
|
+
return [createNormalizedMessage({
|
|
29
|
+
id: baseId,
|
|
30
|
+
sessionId,
|
|
31
|
+
timestamp: ts,
|
|
32
|
+
provider: PROVIDER,
|
|
33
|
+
kind: 'text',
|
|
34
|
+
role: 'user',
|
|
35
|
+
content,
|
|
36
|
+
})];
|
|
37
|
+
}
|
|
38
|
+
// Assistant message
|
|
39
|
+
if (raw.message?.role === 'assistant') {
|
|
40
|
+
const content = typeof raw.message.content === 'string'
|
|
41
|
+
? raw.message.content
|
|
42
|
+
: Array.isArray(raw.message.content)
|
|
43
|
+
? raw.message.content.map(p => typeof p === 'string' ? p : p?.text || '').filter(Boolean).join('\n')
|
|
44
|
+
: '';
|
|
45
|
+
if (!content.trim())
|
|
46
|
+
return [];
|
|
47
|
+
return [createNormalizedMessage({
|
|
48
|
+
id: baseId,
|
|
49
|
+
sessionId,
|
|
50
|
+
timestamp: ts,
|
|
51
|
+
provider: PROVIDER,
|
|
52
|
+
kind: 'text',
|
|
53
|
+
role: 'assistant',
|
|
54
|
+
content,
|
|
55
|
+
})];
|
|
56
|
+
}
|
|
57
|
+
// Thinking/reasoning
|
|
58
|
+
if (raw.type === 'thinking' || raw.isReasoning) {
|
|
59
|
+
return [createNormalizedMessage({
|
|
60
|
+
id: baseId,
|
|
61
|
+
sessionId,
|
|
62
|
+
timestamp: ts,
|
|
63
|
+
provider: PROVIDER,
|
|
64
|
+
kind: 'thinking',
|
|
65
|
+
content: raw.message?.content || '',
|
|
66
|
+
})];
|
|
67
|
+
}
|
|
68
|
+
// Tool use
|
|
69
|
+
if (raw.type === 'tool_use' || raw.toolName) {
|
|
70
|
+
return [createNormalizedMessage({
|
|
71
|
+
id: baseId,
|
|
72
|
+
sessionId,
|
|
73
|
+
timestamp: ts,
|
|
74
|
+
provider: PROVIDER,
|
|
75
|
+
kind: 'tool_use',
|
|
76
|
+
toolName: raw.toolName || 'Unknown',
|
|
77
|
+
toolInput: raw.toolInput,
|
|
78
|
+
toolId: raw.toolCallId || baseId,
|
|
79
|
+
})];
|
|
80
|
+
}
|
|
81
|
+
// Tool result
|
|
82
|
+
if (raw.type === 'tool_result') {
|
|
83
|
+
return [createNormalizedMessage({
|
|
84
|
+
id: baseId,
|
|
85
|
+
sessionId,
|
|
86
|
+
timestamp: ts,
|
|
87
|
+
provider: PROVIDER,
|
|
88
|
+
kind: 'tool_result',
|
|
89
|
+
toolId: raw.toolCallId || '',
|
|
90
|
+
content: raw.output || '',
|
|
91
|
+
isError: Boolean(raw.isError),
|
|
92
|
+
})];
|
|
93
|
+
}
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Normalize a raw Codex event (history JSONL or transformed SDK event) into NormalizedMessage(s).
|
|
98
|
+
* @param {object} raw - A history entry (has raw.message.role) or transformed SDK event (has raw.type)
|
|
99
|
+
* @param {string} sessionId
|
|
100
|
+
* @returns {import('../types.js').NormalizedMessage[]}
|
|
101
|
+
*/
|
|
102
|
+
export function normalizeMessage(raw, sessionId) {
|
|
103
|
+
// History format: has message.role
|
|
104
|
+
if (raw.message?.role) {
|
|
105
|
+
return normalizeCodexHistoryEntry(raw, sessionId);
|
|
106
|
+
}
|
|
107
|
+
const ts = raw.timestamp || new Date().toISOString();
|
|
108
|
+
const baseId = raw.uuid || generateMessageId('codex');
|
|
109
|
+
// SDK event format (output of transformCodexEvent)
|
|
110
|
+
if (raw.type === 'item') {
|
|
111
|
+
switch (raw.itemType) {
|
|
112
|
+
case 'agent_message':
|
|
113
|
+
return [createNormalizedMessage({
|
|
114
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
115
|
+
kind: 'text', role: 'assistant', content: raw.message?.content || '',
|
|
116
|
+
})];
|
|
117
|
+
case 'reasoning':
|
|
118
|
+
return [createNormalizedMessage({
|
|
119
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
120
|
+
kind: 'thinking', content: raw.message?.content || '',
|
|
121
|
+
})];
|
|
122
|
+
case 'command_execution':
|
|
123
|
+
return [createNormalizedMessage({
|
|
124
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
125
|
+
kind: 'tool_use', toolName: 'Bash', toolInput: { command: raw.command },
|
|
126
|
+
toolId: baseId,
|
|
127
|
+
output: raw.output, exitCode: raw.exitCode, status: raw.status,
|
|
128
|
+
})];
|
|
129
|
+
case 'file_change':
|
|
130
|
+
return [createNormalizedMessage({
|
|
131
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
132
|
+
kind: 'tool_use', toolName: 'FileChanges', toolInput: raw.changes,
|
|
133
|
+
toolId: baseId, status: raw.status,
|
|
134
|
+
})];
|
|
135
|
+
case 'mcp_tool_call':
|
|
136
|
+
return [createNormalizedMessage({
|
|
137
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
138
|
+
kind: 'tool_use', toolName: raw.tool || 'MCP', toolInput: raw.arguments,
|
|
139
|
+
toolId: baseId, server: raw.server, result: raw.result,
|
|
140
|
+
error: raw.error, status: raw.status,
|
|
141
|
+
})];
|
|
142
|
+
case 'web_search':
|
|
143
|
+
return [createNormalizedMessage({
|
|
144
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
145
|
+
kind: 'tool_use', toolName: 'WebSearch', toolInput: { query: raw.query },
|
|
146
|
+
toolId: baseId,
|
|
147
|
+
})];
|
|
148
|
+
case 'todo_list':
|
|
149
|
+
return [createNormalizedMessage({
|
|
150
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
151
|
+
kind: 'tool_use', toolName: 'TodoList', toolInput: { items: raw.items },
|
|
152
|
+
toolId: baseId,
|
|
153
|
+
})];
|
|
154
|
+
case 'error':
|
|
155
|
+
return [createNormalizedMessage({
|
|
156
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
157
|
+
kind: 'error', content: raw.message?.content || 'Unknown error',
|
|
158
|
+
})];
|
|
159
|
+
default:
|
|
160
|
+
// Unknown item type — pass through as generic tool_use
|
|
161
|
+
return [createNormalizedMessage({
|
|
162
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
163
|
+
kind: 'tool_use', toolName: raw.itemType || 'Unknown',
|
|
164
|
+
toolInput: raw.item || raw, toolId: baseId,
|
|
165
|
+
})];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (raw.type === 'turn_complete') {
|
|
169
|
+
return [createNormalizedMessage({
|
|
170
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
171
|
+
kind: 'complete',
|
|
172
|
+
})];
|
|
173
|
+
}
|
|
174
|
+
if (raw.type === 'turn_failed') {
|
|
175
|
+
return [createNormalizedMessage({
|
|
176
|
+
id: baseId, sessionId, timestamp: ts, provider: PROVIDER,
|
|
177
|
+
kind: 'error', content: raw.error?.message || 'Turn failed',
|
|
178
|
+
})];
|
|
179
|
+
}
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* @type {import('../types.js').ProviderAdapter}
|
|
184
|
+
*/
|
|
185
|
+
export const codexAdapter = {
|
|
186
|
+
normalizeMessage,
|
|
187
|
+
/**
|
|
188
|
+
* Fetch session history from Codex JSONL files.
|
|
189
|
+
*/
|
|
190
|
+
async fetchHistory(sessionId, opts = {}) {
|
|
191
|
+
const { limit = null, offset = 0 } = opts;
|
|
192
|
+
let result;
|
|
193
|
+
try {
|
|
194
|
+
result = await getCodexSessionMessages(sessionId, limit, offset);
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
console.warn(`[CodexAdapter] Failed to load session ${sessionId}:`, error.message);
|
|
198
|
+
return { messages: [], total: 0, hasMore: false, offset: 0, limit: null };
|
|
199
|
+
}
|
|
200
|
+
const rawMessages = Array.isArray(result) ? result : (result.messages || []);
|
|
201
|
+
const total = Array.isArray(result) ? rawMessages.length : (result.total || 0);
|
|
202
|
+
const hasMore = Array.isArray(result) ? false : Boolean(result.hasMore);
|
|
203
|
+
const tokenUsage = result.tokenUsage || null;
|
|
204
|
+
const normalized = [];
|
|
205
|
+
for (const raw of rawMessages) {
|
|
206
|
+
const entries = normalizeCodexHistoryEntry(raw, sessionId);
|
|
207
|
+
normalized.push(...entries);
|
|
208
|
+
}
|
|
209
|
+
// Attach tool results to tool_use messages
|
|
210
|
+
const toolResultMap = new Map();
|
|
211
|
+
for (const msg of normalized) {
|
|
212
|
+
if (msg.kind === 'tool_result' && msg.toolId) {
|
|
213
|
+
toolResultMap.set(msg.toolId, msg);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
for (const msg of normalized) {
|
|
217
|
+
if (msg.kind === 'tool_use' && msg.toolId && toolResultMap.has(msg.toolId)) {
|
|
218
|
+
const tr = toolResultMap.get(msg.toolId);
|
|
219
|
+
msg.toolResult = { content: tr.content, isError: tr.isError };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
messages: normalized,
|
|
224
|
+
total,
|
|
225
|
+
hasMore,
|
|
226
|
+
offset,
|
|
227
|
+
limit,
|
|
228
|
+
tokenUsage,
|
|
229
|
+
};
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../../server/providers/codex/adapter.js"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex Provider Status
|
|
3
|
+
*
|
|
4
|
+
* Checks whether the user has valid Codex authentication credentials.
|
|
5
|
+
* Codex uses an SDK that makes direct API calls (no external binary),
|
|
6
|
+
* so installation check always returns true if the server is running.
|
|
7
|
+
*
|
|
8
|
+
* @module providers/codex/status
|
|
9
|
+
*/
|
|
10
|
+
import { promises as fs } from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import os from 'os';
|
|
13
|
+
/**
|
|
14
|
+
* Check if Codex is installed.
|
|
15
|
+
* Codex SDK is bundled with this application — no external binary needed.
|
|
16
|
+
* @returns {boolean}
|
|
17
|
+
*/
|
|
18
|
+
export function checkInstalled() {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Full status check: installation + authentication.
|
|
23
|
+
* @returns {Promise<import('../types.js').ProviderStatus>}
|
|
24
|
+
*/
|
|
25
|
+
export async function checkStatus() {
|
|
26
|
+
const installed = checkInstalled();
|
|
27
|
+
const result = await checkCredentials();
|
|
28
|
+
return {
|
|
29
|
+
installed,
|
|
30
|
+
authenticated: result.authenticated,
|
|
31
|
+
email: result.email || null,
|
|
32
|
+
error: result.error || null
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// ─── Internal helpers ───────────────────────────────────────────────────────
|
|
36
|
+
async function checkCredentials() {
|
|
37
|
+
try {
|
|
38
|
+
const authPath = path.join(os.homedir(), '.codex', 'auth.json');
|
|
39
|
+
const content = await fs.readFile(authPath, 'utf8');
|
|
40
|
+
const auth = JSON.parse(content);
|
|
41
|
+
const tokens = auth.tokens || {};
|
|
42
|
+
if (tokens.id_token || tokens.access_token) {
|
|
43
|
+
let email = 'Authenticated';
|
|
44
|
+
if (tokens.id_token) {
|
|
45
|
+
try {
|
|
46
|
+
const parts = tokens.id_token.split('.');
|
|
47
|
+
if (parts.length >= 2) {
|
|
48
|
+
const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8'));
|
|
49
|
+
email = payload.email || payload.user || 'Authenticated';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
email = 'Authenticated';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { authenticated: true, email };
|
|
57
|
+
}
|
|
58
|
+
if (auth.OPENAI_API_KEY) {
|
|
59
|
+
return { authenticated: true, email: 'API Key Auth' };
|
|
60
|
+
}
|
|
61
|
+
return { authenticated: false, email: null, error: 'No valid tokens found' };
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error.code === 'ENOENT') {
|
|
65
|
+
return { authenticated: false, email: null, error: 'Codex not configured' };
|
|
66
|
+
}
|
|
67
|
+
return { authenticated: false, email: null, error: error.message };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../../server/providers/codex/status.js"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,SAAS,GAAG,cAAc,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAExC,OAAO;QACL,SAAS;QACT,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;QAC3B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;KAC5B,CAAC;AACJ,CAAC;AAED,+EAA+E;AAE/E,KAAK,UAAU,gBAAgB;IAC7B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEjC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;QAEjC,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YAC3C,IAAI,KAAK,GAAG,eAAe,CAAC;YAC5B,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACpB,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBACzC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;wBACtB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;wBAChF,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,IAAI,eAAe,CAAC;oBAC3D,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,KAAK,GAAG,eAAe,CAAC;gBAC1B,CAAC;YACH,CAAC;YAED,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACxC,CAAC;QAED,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;QACxD,CAAC;QAED,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;IAC/E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC5B,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;QAC9E,CAAC;QACD,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;IACrE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor provider adapter.
|
|
3
|
+
*
|
|
4
|
+
* Normalizes Cursor CLI session history into NormalizedMessage format.
|
|
5
|
+
* @module adapters/cursor
|
|
6
|
+
*/
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import os from 'os';
|
|
9
|
+
import crypto from 'crypto';
|
|
10
|
+
import { createNormalizedMessage, generateMessageId } from '../types.js';
|
|
11
|
+
const PROVIDER = 'cursor';
|
|
12
|
+
/**
|
|
13
|
+
* Load raw blobs from Cursor's SQLite store.db, parse the DAG structure,
|
|
14
|
+
* and return sorted message blobs in chronological order.
|
|
15
|
+
* @param {string} sessionId
|
|
16
|
+
* @param {string} projectPath - Absolute project path (used to compute cwdId hash)
|
|
17
|
+
* @returns {Promise<Array<{id: string, sequence: number, rowid: number, content: object}>>}
|
|
18
|
+
*/
|
|
19
|
+
async function loadCursorBlobs(sessionId, projectPath) {
|
|
20
|
+
// Lazy-import better-sqlite3 so the module doesn't fail if it's unavailable
|
|
21
|
+
const { default: Database } = await import('better-sqlite3');
|
|
22
|
+
const cwdId = crypto.createHash('md5').update(projectPath || process.cwd()).digest('hex');
|
|
23
|
+
const storeDbPath = path.join(os.homedir(), '.cursor', 'chats', cwdId, sessionId, 'store.db');
|
|
24
|
+
const db = new Database(storeDbPath, { readonly: true, fileMustExist: true });
|
|
25
|
+
try {
|
|
26
|
+
const allBlobs = db.prepare('SELECT rowid, id, data FROM blobs').all();
|
|
27
|
+
const blobMap = new Map();
|
|
28
|
+
const parentRefs = new Map();
|
|
29
|
+
const childRefs = new Map();
|
|
30
|
+
const jsonBlobs = [];
|
|
31
|
+
for (const blob of allBlobs) {
|
|
32
|
+
blobMap.set(blob.id, blob);
|
|
33
|
+
if (blob.data && blob.data[0] === 0x7B) {
|
|
34
|
+
try {
|
|
35
|
+
const parsed = JSON.parse(blob.data.toString('utf8'));
|
|
36
|
+
jsonBlobs.push({ ...blob, parsed });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// skip unparseable blobs
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else if (blob.data) {
|
|
43
|
+
const parents = [];
|
|
44
|
+
let i = 0;
|
|
45
|
+
while (i < blob.data.length - 33) {
|
|
46
|
+
if (blob.data[i] === 0x0A && blob.data[i + 1] === 0x20) {
|
|
47
|
+
const parentHash = blob.data.slice(i + 2, i + 34).toString('hex');
|
|
48
|
+
if (blobMap.has(parentHash)) {
|
|
49
|
+
parents.push(parentHash);
|
|
50
|
+
}
|
|
51
|
+
i += 34;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
i++;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (parents.length > 0) {
|
|
58
|
+
parentRefs.set(blob.id, parents);
|
|
59
|
+
for (const parentId of parents) {
|
|
60
|
+
if (!childRefs.has(parentId))
|
|
61
|
+
childRefs.set(parentId, []);
|
|
62
|
+
childRefs.get(parentId).push(blob.id);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Topological sort (DFS)
|
|
68
|
+
const visited = new Set();
|
|
69
|
+
const sorted = [];
|
|
70
|
+
function visit(nodeId) {
|
|
71
|
+
if (visited.has(nodeId))
|
|
72
|
+
return;
|
|
73
|
+
visited.add(nodeId);
|
|
74
|
+
for (const pid of (parentRefs.get(nodeId) || []))
|
|
75
|
+
visit(pid);
|
|
76
|
+
const b = blobMap.get(nodeId);
|
|
77
|
+
if (b)
|
|
78
|
+
sorted.push(b);
|
|
79
|
+
}
|
|
80
|
+
for (const blob of allBlobs) {
|
|
81
|
+
if (!parentRefs.has(blob.id))
|
|
82
|
+
visit(blob.id);
|
|
83
|
+
}
|
|
84
|
+
for (const blob of allBlobs)
|
|
85
|
+
visit(blob.id);
|
|
86
|
+
// Order JSON blobs by DAG appearance
|
|
87
|
+
const messageOrder = new Map();
|
|
88
|
+
let orderIndex = 0;
|
|
89
|
+
for (const blob of sorted) {
|
|
90
|
+
if (blob.data && blob.data[0] !== 0x7B) {
|
|
91
|
+
for (const jb of jsonBlobs) {
|
|
92
|
+
try {
|
|
93
|
+
const idBytes = Buffer.from(jb.id, 'hex');
|
|
94
|
+
if (blob.data.includes(idBytes) && !messageOrder.has(jb.id)) {
|
|
95
|
+
messageOrder.set(jb.id, orderIndex++);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch { /* skip */ }
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const sortedJsonBlobs = jsonBlobs.sort((a, b) => {
|
|
103
|
+
const oa = messageOrder.get(a.id) ?? Number.MAX_SAFE_INTEGER;
|
|
104
|
+
const ob = messageOrder.get(b.id) ?? Number.MAX_SAFE_INTEGER;
|
|
105
|
+
return oa !== ob ? oa - ob : a.rowid - b.rowid;
|
|
106
|
+
});
|
|
107
|
+
const messages = [];
|
|
108
|
+
for (let idx = 0; idx < sortedJsonBlobs.length; idx++) {
|
|
109
|
+
const blob = sortedJsonBlobs[idx];
|
|
110
|
+
const parsed = blob.parsed;
|
|
111
|
+
if (!parsed)
|
|
112
|
+
continue;
|
|
113
|
+
const role = parsed?.role || parsed?.message?.role;
|
|
114
|
+
if (role === 'system')
|
|
115
|
+
continue;
|
|
116
|
+
messages.push({
|
|
117
|
+
id: blob.id,
|
|
118
|
+
sequence: idx + 1,
|
|
119
|
+
rowid: blob.rowid,
|
|
120
|
+
content: parsed,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return messages;
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
db.close();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Normalize a realtime NDJSON event from Cursor CLI into NormalizedMessage(s).
|
|
131
|
+
* History uses normalizeCursorBlobs (SQLite DAG), this handles streaming NDJSON.
|
|
132
|
+
* @param {object|string} raw - A parsed NDJSON event or a raw text line
|
|
133
|
+
* @param {string} sessionId
|
|
134
|
+
* @returns {import('../types.js').NormalizedMessage[]}
|
|
135
|
+
*/
|
|
136
|
+
export function normalizeMessage(raw, sessionId) {
|
|
137
|
+
// Structured assistant message with content array
|
|
138
|
+
if (raw && typeof raw === 'object' && raw.type === 'assistant' && raw.message?.content?.[0]?.text) {
|
|
139
|
+
return [createNormalizedMessage({ kind: 'stream_delta', content: raw.message.content[0].text, sessionId, provider: PROVIDER })];
|
|
140
|
+
}
|
|
141
|
+
// Plain string line (non-JSON output)
|
|
142
|
+
if (typeof raw === 'string' && raw.trim()) {
|
|
143
|
+
return [createNormalizedMessage({ kind: 'stream_delta', content: raw, sessionId, provider: PROVIDER })];
|
|
144
|
+
}
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* @type {import('../types.js').ProviderAdapter}
|
|
149
|
+
*/
|
|
150
|
+
export const cursorAdapter = {
|
|
151
|
+
normalizeMessage,
|
|
152
|
+
/**
|
|
153
|
+
* Fetch session history for Cursor from SQLite store.db.
|
|
154
|
+
*/
|
|
155
|
+
async fetchHistory(sessionId, opts = {}) {
|
|
156
|
+
const { projectPath = '', limit = null, offset = 0 } = opts;
|
|
157
|
+
try {
|
|
158
|
+
const blobs = await loadCursorBlobs(sessionId, projectPath);
|
|
159
|
+
const allNormalized = cursorAdapter.normalizeCursorBlobs(blobs, sessionId);
|
|
160
|
+
// Apply pagination
|
|
161
|
+
if (limit !== null && limit > 0) {
|
|
162
|
+
const start = offset;
|
|
163
|
+
const page = allNormalized.slice(start, start + limit);
|
|
164
|
+
return {
|
|
165
|
+
messages: page,
|
|
166
|
+
total: allNormalized.length,
|
|
167
|
+
hasMore: start + limit < allNormalized.length,
|
|
168
|
+
offset,
|
|
169
|
+
limit,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
messages: allNormalized,
|
|
174
|
+
total: allNormalized.length,
|
|
175
|
+
hasMore: false,
|
|
176
|
+
offset: 0,
|
|
177
|
+
limit: null,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
// DB doesn't exist or is unreadable — return empty
|
|
182
|
+
console.warn(`[CursorAdapter] Failed to load session ${sessionId}:`, error.message);
|
|
183
|
+
return { messages: [], total: 0, hasMore: false, offset: 0, limit: null };
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
/**
|
|
187
|
+
* Normalize raw Cursor blob messages into NormalizedMessage[].
|
|
188
|
+
* @param {any[]} blobs - Raw cursor blobs from store.db ({id, sequence, rowid, content})
|
|
189
|
+
* @param {string} sessionId
|
|
190
|
+
* @returns {import('../types.js').NormalizedMessage[]}
|
|
191
|
+
*/
|
|
192
|
+
normalizeCursorBlobs(blobs, sessionId) {
|
|
193
|
+
const messages = [];
|
|
194
|
+
const toolUseMap = new Map();
|
|
195
|
+
// Use a fixed base timestamp so messages have stable, monotonically-increasing
|
|
196
|
+
// timestamps based on their sequence number rather than wall-clock time.
|
|
197
|
+
const baseTime = Date.now();
|
|
198
|
+
for (let i = 0; i < blobs.length; i++) {
|
|
199
|
+
const blob = blobs[i];
|
|
200
|
+
const content = blob.content;
|
|
201
|
+
const ts = new Date(baseTime + (blob.sequence ?? i) * 100).toISOString();
|
|
202
|
+
const baseId = blob.id || generateMessageId('cursor');
|
|
203
|
+
try {
|
|
204
|
+
if (!content?.role || !content?.content) {
|
|
205
|
+
// Try nested message format
|
|
206
|
+
if (content?.message?.role && content?.message?.content) {
|
|
207
|
+
if (content.message.role === 'system')
|
|
208
|
+
continue;
|
|
209
|
+
const role = content.message.role === 'user' ? 'user' : 'assistant';
|
|
210
|
+
let text = '';
|
|
211
|
+
if (Array.isArray(content.message.content)) {
|
|
212
|
+
text = content.message.content
|
|
213
|
+
.map(p => typeof p === 'string' ? p : p?.text || '')
|
|
214
|
+
.filter(Boolean)
|
|
215
|
+
.join('\n');
|
|
216
|
+
}
|
|
217
|
+
else if (typeof content.message.content === 'string') {
|
|
218
|
+
text = content.message.content;
|
|
219
|
+
}
|
|
220
|
+
if (text?.trim()) {
|
|
221
|
+
messages.push(createNormalizedMessage({
|
|
222
|
+
id: baseId,
|
|
223
|
+
sessionId,
|
|
224
|
+
timestamp: ts,
|
|
225
|
+
provider: PROVIDER,
|
|
226
|
+
kind: 'text',
|
|
227
|
+
role,
|
|
228
|
+
content: text,
|
|
229
|
+
sequence: blob.sequence,
|
|
230
|
+
rowid: blob.rowid,
|
|
231
|
+
}));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (content.role === 'system')
|
|
237
|
+
continue;
|
|
238
|
+
// Tool results
|
|
239
|
+
if (content.role === 'tool') {
|
|
240
|
+
const toolItems = Array.isArray(content.content) ? content.content : [];
|
|
241
|
+
for (const item of toolItems) {
|
|
242
|
+
if (item?.type !== 'tool-result')
|
|
243
|
+
continue;
|
|
244
|
+
const toolCallId = item.toolCallId || content.id;
|
|
245
|
+
messages.push(createNormalizedMessage({
|
|
246
|
+
id: `${baseId}_tr`,
|
|
247
|
+
sessionId,
|
|
248
|
+
timestamp: ts,
|
|
249
|
+
provider: PROVIDER,
|
|
250
|
+
kind: 'tool_result',
|
|
251
|
+
toolId: toolCallId,
|
|
252
|
+
content: item.result || '',
|
|
253
|
+
isError: false,
|
|
254
|
+
}));
|
|
255
|
+
}
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const role = content.role === 'user' ? 'user' : 'assistant';
|
|
259
|
+
if (Array.isArray(content.content)) {
|
|
260
|
+
for (let partIdx = 0; partIdx < content.content.length; partIdx++) {
|
|
261
|
+
const part = content.content[partIdx];
|
|
262
|
+
if (part?.type === 'text' && part?.text) {
|
|
263
|
+
messages.push(createNormalizedMessage({
|
|
264
|
+
id: `${baseId}_${partIdx}`,
|
|
265
|
+
sessionId,
|
|
266
|
+
timestamp: ts,
|
|
267
|
+
provider: PROVIDER,
|
|
268
|
+
kind: 'text',
|
|
269
|
+
role,
|
|
270
|
+
content: part.text,
|
|
271
|
+
sequence: blob.sequence,
|
|
272
|
+
rowid: blob.rowid,
|
|
273
|
+
}));
|
|
274
|
+
}
|
|
275
|
+
else if (part?.type === 'reasoning' && part?.text) {
|
|
276
|
+
messages.push(createNormalizedMessage({
|
|
277
|
+
id: `${baseId}_${partIdx}`,
|
|
278
|
+
sessionId,
|
|
279
|
+
timestamp: ts,
|
|
280
|
+
provider: PROVIDER,
|
|
281
|
+
kind: 'thinking',
|
|
282
|
+
content: part.text,
|
|
283
|
+
}));
|
|
284
|
+
}
|
|
285
|
+
else if (part?.type === 'tool-call' || part?.type === 'tool_use') {
|
|
286
|
+
const toolName = (part.toolName || part.name || 'Unknown Tool') === 'ApplyPatch'
|
|
287
|
+
? 'Edit' : (part.toolName || part.name || 'Unknown Tool');
|
|
288
|
+
const toolId = part.toolCallId || part.id || `tool_${i}_${partIdx}`;
|
|
289
|
+
messages.push(createNormalizedMessage({
|
|
290
|
+
id: `${baseId}_${partIdx}`,
|
|
291
|
+
sessionId,
|
|
292
|
+
timestamp: ts,
|
|
293
|
+
provider: PROVIDER,
|
|
294
|
+
kind: 'tool_use',
|
|
295
|
+
toolName,
|
|
296
|
+
toolInput: part.args || part.input,
|
|
297
|
+
toolId,
|
|
298
|
+
}));
|
|
299
|
+
toolUseMap.set(toolId, messages[messages.length - 1]);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else if (typeof content.content === 'string' && content.content.trim()) {
|
|
304
|
+
messages.push(createNormalizedMessage({
|
|
305
|
+
id: baseId,
|
|
306
|
+
sessionId,
|
|
307
|
+
timestamp: ts,
|
|
308
|
+
provider: PROVIDER,
|
|
309
|
+
kind: 'text',
|
|
310
|
+
role,
|
|
311
|
+
content: content.content,
|
|
312
|
+
sequence: blob.sequence,
|
|
313
|
+
rowid: blob.rowid,
|
|
314
|
+
}));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
console.warn('Error normalizing cursor blob:', error);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// Attach tool results to tool_use messages
|
|
322
|
+
for (const msg of messages) {
|
|
323
|
+
if (msg.kind === 'tool_result' && msg.toolId && toolUseMap.has(msg.toolId)) {
|
|
324
|
+
const toolUse = toolUseMap.get(msg.toolId);
|
|
325
|
+
toolUse.toolResult = {
|
|
326
|
+
content: msg.content,
|
|
327
|
+
isError: msg.isError,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// Sort by sequence/rowid
|
|
332
|
+
messages.sort((a, b) => {
|
|
333
|
+
if (a.sequence !== undefined && b.sequence !== undefined)
|
|
334
|
+
return a.sequence - b.sequence;
|
|
335
|
+
if (a.rowid !== undefined && b.rowid !== undefined)
|
|
336
|
+
return a.rowid - b.rowid;
|
|
337
|
+
return new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime();
|
|
338
|
+
});
|
|
339
|
+
return messages;
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
//# sourceMappingURL=adapter.js.map
|