@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.
Files changed (140) hide show
  1. package/dist/assets/{index-ByHZ8-LL.css → index-BBAE1OJ_.css} +1 -1
  2. package/dist/assets/{index-Ile1bTCU.js → index-Cyya3LhN.js} +229 -229
  3. package/dist/index.html +2 -2
  4. package/dist-server/server/claude-sdk.js +702 -0
  5. package/dist-server/server/claude-sdk.js.map +1 -0
  6. package/dist-server/server/cli.js +642 -0
  7. package/dist-server/server/cli.js.map +1 -0
  8. package/dist-server/server/constants/config.js +6 -0
  9. package/dist-server/server/constants/config.js.map +1 -0
  10. package/dist-server/server/cursor-cli.js +277 -0
  11. package/dist-server/server/cursor-cli.js.map +1 -0
  12. package/dist-server/server/database/db.js +535 -0
  13. package/dist-server/server/database/db.js.map +1 -0
  14. package/dist-server/server/database/schema.js +97 -0
  15. package/dist-server/server/database/schema.js.map +1 -0
  16. package/dist-server/server/gemini-cli.js +408 -0
  17. package/dist-server/server/gemini-cli.js.map +1 -0
  18. package/dist-server/server/gemini-response-handler.js +72 -0
  19. package/dist-server/server/gemini-response-handler.js.map +1 -0
  20. package/dist-server/server/index.js +2175 -0
  21. package/dist-server/server/index.js.map +1 -0
  22. package/dist-server/server/load-env.js +32 -0
  23. package/dist-server/server/load-env.js.map +1 -0
  24. package/dist-server/server/middleware/auth.js +111 -0
  25. package/dist-server/server/middleware/auth.js.map +1 -0
  26. package/dist-server/server/openai-codex.js +373 -0
  27. package/dist-server/server/openai-codex.js.map +1 -0
  28. package/dist-server/server/projects.js +2325 -0
  29. package/dist-server/server/projects.js.map +1 -0
  30. package/dist-server/server/providers/claude/adapter.js +266 -0
  31. package/dist-server/server/providers/claude/adapter.js.map +1 -0
  32. package/dist-server/server/providers/claude/status.js +121 -0
  33. package/dist-server/server/providers/claude/status.js.map +1 -0
  34. package/dist-server/server/providers/codex/adapter.js +232 -0
  35. package/dist-server/server/providers/codex/adapter.js.map +1 -0
  36. package/dist-server/server/providers/codex/status.js +70 -0
  37. package/dist-server/server/providers/codex/status.js.map +1 -0
  38. package/dist-server/server/providers/cursor/adapter.js +342 -0
  39. package/dist-server/server/providers/cursor/adapter.js.map +1 -0
  40. package/dist-server/server/providers/cursor/status.js +118 -0
  41. package/dist-server/server/providers/cursor/status.js.map +1 -0
  42. package/dist-server/server/providers/gemini/adapter.js +174 -0
  43. package/dist-server/server/providers/gemini/adapter.js.map +1 -0
  44. package/dist-server/server/providers/gemini/status.js +104 -0
  45. package/dist-server/server/providers/gemini/status.js.map +1 -0
  46. package/dist-server/server/providers/registry.js +58 -0
  47. package/dist-server/server/providers/registry.js.map +1 -0
  48. package/dist-server/server/providers/types.js +117 -0
  49. package/dist-server/server/providers/types.js.map +1 -0
  50. package/dist-server/server/providers/utils.js +28 -0
  51. package/dist-server/server/providers/utils.js.map +1 -0
  52. package/dist-server/server/routes/agent.js +1147 -0
  53. package/dist-server/server/routes/agent.js.map +1 -0
  54. package/dist-server/server/routes/auth.js +117 -0
  55. package/dist-server/server/routes/auth.js.map +1 -0
  56. package/dist-server/server/routes/cli-auth.js +25 -0
  57. package/dist-server/server/routes/cli-auth.js.map +1 -0
  58. package/dist-server/server/routes/codex.js +294 -0
  59. package/dist-server/server/routes/codex.js.map +1 -0
  60. package/dist-server/server/routes/commands.js +531 -0
  61. package/dist-server/server/routes/commands.js.map +1 -0
  62. package/dist-server/server/routes/cursor.js +529 -0
  63. package/dist-server/server/routes/cursor.js.map +1 -0
  64. package/dist-server/server/routes/gemini.js +21 -0
  65. package/dist-server/server/routes/gemini.js.map +1 -0
  66. package/dist-server/server/routes/git.js +1259 -0
  67. package/dist-server/server/routes/git.js.map +1 -0
  68. package/dist-server/server/routes/mcp-utils.js +46 -0
  69. package/dist-server/server/routes/mcp-utils.js.map +1 -0
  70. package/dist-server/server/routes/mcp.js +480 -0
  71. package/dist-server/server/routes/mcp.js.map +1 -0
  72. package/dist-server/server/routes/messages.js +56 -0
  73. package/dist-server/server/routes/messages.js.map +1 -0
  74. package/dist-server/server/routes/plugins.js +266 -0
  75. package/dist-server/server/routes/plugins.js.map +1 -0
  76. package/dist-server/server/routes/projects.js +505 -0
  77. package/dist-server/server/routes/projects.js.map +1 -0
  78. package/dist-server/server/routes/settings.js +249 -0
  79. package/dist-server/server/routes/settings.js.map +1 -0
  80. package/dist-server/server/routes/taskmaster.js +1832 -0
  81. package/dist-server/server/routes/taskmaster.js.map +1 -0
  82. package/dist-server/server/routes/user.js +115 -0
  83. package/dist-server/server/routes/user.js.map +1 -0
  84. package/dist-server/server/services/notification-orchestrator.js +177 -0
  85. package/dist-server/server/services/notification-orchestrator.js.map +1 -0
  86. package/dist-server/server/services/vapid-keys.js +26 -0
  87. package/dist-server/server/services/vapid-keys.js.map +1 -0
  88. package/dist-server/server/sessionManager.js +194 -0
  89. package/dist-server/server/sessionManager.js.map +1 -0
  90. package/dist-server/server/utils/colors.js +20 -0
  91. package/dist-server/server/utils/colors.js.map +1 -0
  92. package/dist-server/server/utils/commandParser.js +255 -0
  93. package/dist-server/server/utils/commandParser.js.map +1 -0
  94. package/dist-server/server/utils/frontmatter.js +16 -0
  95. package/dist-server/server/utils/frontmatter.js.map +1 -0
  96. package/dist-server/server/utils/gitConfig.js +36 -0
  97. package/dist-server/server/utils/gitConfig.js.map +1 -0
  98. package/dist-server/server/utils/mcp-detector.js +183 -0
  99. package/dist-server/server/utils/mcp-detector.js.map +1 -0
  100. package/dist-server/server/utils/plugin-loader.js +413 -0
  101. package/dist-server/server/utils/plugin-loader.js.map +1 -0
  102. package/dist-server/server/utils/plugin-process-manager.js +163 -0
  103. package/dist-server/server/utils/plugin-process-manager.js.map +1 -0
  104. package/dist-server/server/utils/runtime-paths.js +30 -0
  105. package/dist-server/server/utils/runtime-paths.js.map +1 -0
  106. package/dist-server/server/utils/taskmaster-websocket.js +118 -0
  107. package/dist-server/server/utils/taskmaster-websocket.js.map +1 -0
  108. package/dist-server/server/utils/url-detection.js +58 -0
  109. package/dist-server/server/utils/url-detection.js.map +1 -0
  110. package/dist-server/shared/modelConstants.js +87 -0
  111. package/dist-server/shared/modelConstants.js.map +1 -0
  112. package/dist-server/shared/networkHosts.js +20 -0
  113. package/dist-server/shared/networkHosts.js.map +1 -0
  114. package/package.json +23 -14
  115. package/server/claude-sdk.js +13 -4
  116. package/server/cli.js +13 -9
  117. package/server/cursor-cli.js +8 -1
  118. package/server/database/db.js +24 -61
  119. package/server/database/schema.js +102 -0
  120. package/server/gemini-cli.js +17 -1
  121. package/server/index.js +20 -96
  122. package/server/load-env.js +11 -6
  123. package/server/openai-codex.js +9 -1
  124. package/server/projects.js +38 -44
  125. package/server/providers/claude/status.js +136 -0
  126. package/server/providers/codex/status.js +78 -0
  127. package/server/providers/cursor/adapter.js +5 -10
  128. package/server/providers/cursor/status.js +128 -0
  129. package/server/providers/gemini/status.js +111 -0
  130. package/server/providers/registry.js +25 -2
  131. package/server/providers/types.js +13 -0
  132. package/server/routes/cli-auth.js +14 -421
  133. package/server/routes/commands.js +6 -4
  134. package/server/routes/cursor.js +6 -240
  135. package/server/tsconfig.json +33 -0
  136. package/server/utils/colors.js +21 -0
  137. package/server/utils/runtime-paths.js +37 -0
  138. package/server/utils/url-detection.js +71 -0
  139. package/shared/modelConstants.js +4 -2
  140. 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