@cloudcli-ai/cloudcli 1.35.1 → 1.36.1
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.de.md +17 -18
- package/README.ja.md +16 -17
- package/README.ko.md +17 -18
- package/README.md +19 -20
- package/README.ru.md +17 -18
- package/README.tr.md +17 -18
- package/README.zh-CN.md +17 -18
- package/README.zh-TW.md +17 -18
- package/dist/api-docs.html +8 -3
- package/dist/assets/{index-D1IdCTT6.js → index-Bz9vXV2m.js} +265 -260
- package/dist/assets/index-DLmhQ15L.css +32 -0
- package/dist/assets/{vendor-xterm-CJZjLICi.js → vendor-xterm-CS4rQ5Mr.js} +12 -12
- package/dist/index.html +3 -3
- package/dist-server/server/claude-sdk.js +62 -116
- package/dist-server/server/claude-sdk.js.map +1 -1
- package/dist-server/server/cli.js +1 -4
- package/dist-server/server/cli.js.map +1 -1
- package/dist-server/server/cursor-cli.js +12 -11
- package/dist-server/server/cursor-cli.js.map +1 -1
- package/dist-server/server/index.js +10 -141
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/assets/assets.routes.js +89 -0
- package/dist-server/server/modules/assets/assets.routes.js.map +1 -0
- package/dist-server/server/modules/assets/index.js +4 -0
- package/dist-server/server/modules/assets/index.js.map +1 -0
- package/dist-server/server/modules/assets/services/image-assets.service.js +57 -0
- package/dist-server/server/modules/assets/services/image-assets.service.js.map +1 -0
- package/dist-server/server/modules/assets/tests/image-assets.service.test.js +36 -0
- package/dist-server/server/modules/assets/tests/image-assets.service.test.js.map +1 -0
- package/dist-server/server/modules/browser-use/browser-use.service.js +6 -3
- package/dist-server/server/modules/browser-use/browser-use.service.js.map +1 -1
- package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js +2 -2
- package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js.map +1 -1
- package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js +0 -1
- package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js.map +1 -1
- package/dist-server/server/modules/projects/services/project-clone.service.js +2 -1
- package/dist-server/server/modules/projects/services/project-clone.service.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +70 -1
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +28 -0
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +52 -11
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +54 -1
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +36 -1
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +3 -17
- package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js +7 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +49 -13
- package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js +0 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +145 -14
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +24 -5
- package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +10 -21
- package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/provider.registry.js +0 -2
- package/dist-server/server/modules/providers/provider.registry.js.map +1 -1
- package/dist-server/server/modules/providers/provider.routes.js +0 -1
- package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-capabilities.service.js +11 -13
- package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-models.service.js +2 -2
- package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js +3 -77
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js +0 -1
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js +0 -13
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js +96 -0
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/mcp.test.js +3 -29
- package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/opencode-models.test.js +65 -1
- package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +117 -0
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/provider-image-history.test.js +147 -0
- package/dist-server/server/modules/providers/tests/provider-image-history.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/provider-models.service.test.js +8 -8
- package/dist-server/server/modules/providers/tests/skills.test.js +3 -26
- package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
- package/dist-server/server/modules/websocket/services/chat-run-registry.service.js +14 -0
- package/dist-server/server/modules/websocket/services/chat-run-registry.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js +36 -2
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js +3 -12
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
- package/dist-server/server/modules/websocket/tests/chat-image-filter.test.js +33 -0
- package/dist-server/server/modules/websocket/tests/chat-image-filter.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js +37 -4
- package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js.map +1 -1
- package/dist-server/server/openai-codex.js +16 -9
- package/dist-server/server/openai-codex.js.map +1 -1
- package/dist-server/server/opencode-cli.js +62 -7
- package/dist-server/server/opencode-cli.js.map +1 -1
- package/dist-server/server/opencode-cli.test.js +103 -3
- package/dist-server/server/opencode-cli.test.js.map +1 -1
- package/dist-server/server/routes/agent.js +22 -21
- package/dist-server/server/routes/agent.js.map +1 -1
- package/dist-server/server/routes/commands.js +1 -2
- package/dist-server/server/routes/commands.js.map +1 -1
- package/dist-server/server/routes/git.js +179 -53
- package/dist-server/server/routes/git.js.map +1 -1
- package/dist-server/server/routes/git.test.js +80 -0
- package/dist-server/server/routes/git.test.js.map +1 -0
- package/dist-server/server/routes/taskmaster.js +3 -1
- package/dist-server/server/routes/taskmaster.js.map +1 -1
- package/dist-server/server/routes/user.js +2 -1
- package/dist-server/server/routes/user.js.map +1 -1
- package/dist-server/server/shared/image-attachments.js +270 -0
- package/dist-server/server/shared/image-attachments.js.map +1 -0
- package/dist-server/server/shared/tests/image-attachments.test.js +220 -0
- package/dist-server/server/shared/tests/image-attachments.test.js.map +1 -0
- package/dist-server/server/shared/utils.js +43 -0
- package/dist-server/server/shared/utils.js.map +1 -1
- package/dist-server/server/utils/gitConfig.js +2 -1
- package/dist-server/server/utils/gitConfig.js.map +1 -1
- package/dist-server/server/utils/plugin-process-manager.js +2 -1
- package/dist-server/server/utils/plugin-process-manager.js.map +1 -1
- package/electron/launcher/launcher.js +1 -1
- package/package.json +3 -3
- package/public/api-docs.html +8 -3
- package/server/claude-sdk.js +69 -131
- package/server/cli.js +1 -4
- package/server/cursor-cli.js +13 -12
- package/server/index.js +11 -159
- package/server/modules/assets/assets.routes.ts +103 -0
- package/server/modules/assets/index.ts +3 -0
- package/server/modules/assets/services/image-assets.service.ts +82 -0
- package/server/modules/assets/tests/image-assets.service.test.ts +46 -0
- package/server/modules/browser-use/browser-use.service.ts +7 -3
- package/server/modules/database/tests/sessions-provider-mapping.test.ts +2 -2
- package/server/modules/notifications/services/notification-orchestrator.service.js +0 -1
- package/server/modules/projects/services/project-clone.service.ts +3 -1
- package/server/modules/providers/README.md +1 -7
- package/server/modules/providers/list/claude/claude-models.provider.ts +73 -1
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +30 -0
- package/server/modules/providers/list/codex/codex-models.provider.ts +59 -11
- package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +60 -1
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +41 -1
- package/server/modules/providers/list/cursor/cursor-models.provider.ts +3 -17
- package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +7 -1
- package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +56 -15
- package/server/modules/providers/list/opencode/opencode-auth.provider.ts +0 -1
- package/server/modules/providers/list/opencode/opencode-models.provider.ts +193 -18
- package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +25 -4
- package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +10 -21
- package/server/modules/providers/provider.registry.ts +0 -2
- package/server/modules/providers/provider.routes.ts +0 -1
- package/server/modules/providers/services/provider-capabilities.service.ts +13 -13
- package/server/modules/providers/services/provider-models.service.ts +2 -2
- package/server/modules/providers/services/session-conversations-search.service.ts +3 -93
- package/server/modules/providers/services/session-synchronizer.service.ts +0 -1
- package/server/modules/providers/services/sessions-watcher.service.ts +0 -14
- package/server/modules/providers/tests/codex-sessions.test.ts +111 -0
- package/server/modules/providers/tests/mcp.test.ts +3 -34
- package/server/modules/providers/tests/opencode-models.test.ts +69 -0
- package/server/modules/providers/tests/opencode-sessions.test.ts +139 -0
- package/server/modules/providers/tests/provider-image-history.test.ts +180 -0
- package/server/modules/providers/tests/provider-models.service.test.ts +8 -8
- package/server/modules/providers/tests/skills.test.ts +3 -42
- package/server/modules/websocket/services/chat-run-registry.service.ts +16 -0
- package/server/modules/websocket/services/chat-websocket.service.ts +41 -2
- package/server/modules/websocket/services/shell-websocket.service.ts +1 -11
- package/server/modules/websocket/tests/chat-image-filter.test.ts +44 -0
- package/server/modules/websocket/tests/chat-run-registry.test.ts +42 -4
- package/server/openai-codex.js +18 -8
- package/server/opencode-cli.js +64 -7
- package/server/opencode-cli.test.js +112 -3
- package/server/routes/agent.js +22 -21
- package/server/routes/commands.js +1 -2
- package/server/routes/git.js +201 -60
- package/server/routes/git.test.js +106 -0
- package/server/routes/taskmaster.js +3 -1
- package/server/routes/user.js +2 -1
- package/server/shared/image-attachments.ts +341 -0
- package/server/shared/tests/image-attachments.test.ts +298 -0
- package/server/shared/types.ts +8 -1
- package/server/shared/utils.ts +45 -0
- package/server/utils/gitConfig.js +2 -1
- package/server/utils/plugin-process-manager.js +3 -1
- package/dist/assets/index-BvX30NW5.css +0 -32
- package/dist/icons/gemini-ai-icon.svg +0 -1
- package/dist-server/server/gemini-cli.js +0 -551
- package/dist-server/server/gemini-cli.js.map +0 -1
- package/dist-server/server/gemini-response-handler.js +0 -106
- package/dist-server/server/gemini-response-handler.js.map +0 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +0 -254
- package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +0 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js +0 -82
- package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js.map +0 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-models.provider.js +0 -24
- package/dist-server/server/modules/providers/list/gemini/gemini-models.provider.js.map +0 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js +0 -312
- package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js.map +0 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +0 -474
- package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +0 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js +0 -40
- package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js.map +0 -1
- package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +0 -19
- package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +0 -1
- package/dist-server/server/routes/gemini.js +0 -21
- package/dist-server/server/routes/gemini.js.map +0 -1
- package/dist-server/server/sessionManager.js +0 -194
- package/dist-server/server/sessionManager.js.map +0 -1
- package/server/gemini-cli.js +0 -638
- package/server/gemini-response-handler.js +0 -117
- package/server/modules/providers/list/gemini/gemini-auth.provider.ts +0 -307
- package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +0 -110
- package/server/modules/providers/list/gemini/gemini-models.provider.ts +0 -39
- package/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.ts +0 -405
- package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +0 -540
- package/server/modules/providers/list/gemini/gemini-skills.provider.ts +0 -44
- package/server/modules/providers/list/gemini/gemini.provider.ts +0 -27
- package/server/routes/gemini.js +0 -25
- package/server/sessionManager.js +0 -226
package/server/claude-sdk.js
CHANGED
|
@@ -12,11 +12,14 @@
|
|
|
12
12
|
* - WebSocket message streaming
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
16
15
|
import crypto from 'crypto';
|
|
17
16
|
import { promises as fs } from 'fs';
|
|
18
|
-
import path from 'path';
|
|
19
17
|
import os from 'os';
|
|
18
|
+
import path from 'path';
|
|
19
|
+
|
|
20
|
+
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
21
|
+
|
|
22
|
+
import { buildClaudeUserContent, normalizeImageDescriptors } from './shared/image-attachments.js';
|
|
20
23
|
import { CLAUDE_FALLBACK_MODELS } from './modules/providers/list/claude/claude-models.provider.js';
|
|
21
24
|
import { providerModelsService } from './modules/providers/services/provider-models.service.js';
|
|
22
25
|
import { resolveClaudeCodeExecutablePath } from './shared/claude-cli-path.js';
|
|
@@ -41,6 +44,15 @@ const TOOL_APPROVAL_TIMEOUT_MS = parseInt(process.env.CLAUDE_TOOL_APPROVAL_TIMEO
|
|
|
41
44
|
|
|
42
45
|
const TOOLS_REQUIRING_INTERACTION = new Set(['AskUserQuestion', 'ExitPlanMode']);
|
|
43
46
|
|
|
47
|
+
function resolveClaudeEffort(model, effort, modelsDefinition = CLAUDE_FALLBACK_MODELS) {
|
|
48
|
+
const selectedModel = modelsDefinition?.OPTIONS?.find((option) => option.value === model) || null;
|
|
49
|
+
const allowedEfforts = selectedModel?.effort?.values
|
|
50
|
+
?.map((value) => value.value) || [];
|
|
51
|
+
return typeof effort === 'string' && effort !== 'default' && allowedEfforts.includes(effort)
|
|
52
|
+
? effort
|
|
53
|
+
: undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
44
56
|
function createRequestId() {
|
|
45
57
|
if (typeof crypto.randomUUID === 'function') {
|
|
46
58
|
return crypto.randomUUID();
|
|
@@ -145,13 +157,8 @@ function matchesToolPermission(entry, toolName, input) {
|
|
|
145
157
|
return false;
|
|
146
158
|
}
|
|
147
159
|
|
|
148
|
-
/**
|
|
149
|
-
* Maps CLI options to SDK-compatible options format
|
|
150
|
-
* @param {Object} options - CLI options
|
|
151
|
-
* @returns {Object} SDK-compatible options
|
|
152
|
-
*/
|
|
153
160
|
function mapCliOptionsToSDK(options = {}) {
|
|
154
|
-
const { sessionId, cwd, toolsSettings, permissionMode } = options;
|
|
161
|
+
const { sessionId, cwd, toolsSettings, permissionMode, effort } = options;
|
|
155
162
|
|
|
156
163
|
const sdkOptions = {};
|
|
157
164
|
|
|
@@ -163,32 +170,26 @@ function mapCliOptionsToSDK(options = {}) {
|
|
|
163
170
|
// which does not reliably follow npm's shell wrappers like cross-spawn does.
|
|
164
171
|
sdkOptions.pathToClaudeCodeExecutable = resolveClaudeCodeExecutablePath(process.env.CLAUDE_CLI_PATH);
|
|
165
172
|
|
|
166
|
-
// Map working directory
|
|
167
173
|
if (cwd) {
|
|
168
174
|
sdkOptions.cwd = cwd;
|
|
169
175
|
}
|
|
170
176
|
|
|
171
|
-
// Map permission mode
|
|
172
177
|
if (permissionMode && permissionMode !== 'default') {
|
|
173
178
|
sdkOptions.permissionMode = permissionMode;
|
|
174
179
|
}
|
|
175
180
|
|
|
176
|
-
// Map tool settings
|
|
177
181
|
const settings = toolsSettings || {
|
|
178
182
|
allowedTools: [],
|
|
179
183
|
disallowedTools: [],
|
|
180
184
|
skipPermissions: false
|
|
181
185
|
};
|
|
182
186
|
|
|
183
|
-
// Handle tool permissions
|
|
184
187
|
if (settings.skipPermissions && permissionMode !== 'plan') {
|
|
185
|
-
// When skipping permissions, use bypassPermissions mode
|
|
186
188
|
sdkOptions.permissionMode = 'bypassPermissions';
|
|
187
189
|
}
|
|
188
190
|
|
|
189
191
|
let allowedTools = [...(settings.allowedTools || [])];
|
|
190
192
|
|
|
191
|
-
// Add plan mode default tools
|
|
192
193
|
if (permissionMode === 'plan') {
|
|
193
194
|
const planModeTools = ['Read', 'Task', 'exit_plan_mode', 'TodoRead', 'TodoWrite', 'WebFetch', 'WebSearch'];
|
|
194
195
|
for (const tool of planModeTools) {
|
|
@@ -207,22 +208,24 @@ function mapCliOptionsToSDK(options = {}) {
|
|
|
207
208
|
|
|
208
209
|
sdkOptions.disallowedTools = settings.disallowedTools || [];
|
|
209
210
|
|
|
210
|
-
// Map model (default to sonnet)
|
|
211
|
-
// Valid models: sonnet, opus, haiku, opusplan, sonnet[1m], fable
|
|
212
211
|
sdkOptions.model = options.model || CLAUDE_FALLBACK_MODELS.DEFAULT;
|
|
213
|
-
// Model logged at query start below
|
|
214
212
|
|
|
215
|
-
|
|
213
|
+
const resolvedEffort = resolveClaudeEffort(
|
|
214
|
+
sdkOptions.model,
|
|
215
|
+
effort,
|
|
216
|
+
options.effortModels || CLAUDE_FALLBACK_MODELS,
|
|
217
|
+
);
|
|
218
|
+
if (resolvedEffort) {
|
|
219
|
+
sdkOptions.effort = resolvedEffort;
|
|
220
|
+
}
|
|
221
|
+
|
|
216
222
|
sdkOptions.systemPrompt = {
|
|
217
223
|
type: 'preset',
|
|
218
|
-
preset: 'claude_code'
|
|
224
|
+
preset: 'claude_code'
|
|
219
225
|
};
|
|
220
226
|
|
|
221
|
-
// Map setting sources for CLAUDE.md loading
|
|
222
|
-
// This loads CLAUDE.md from project, user (~/.config/claude/CLAUDE.md), and local directories
|
|
223
227
|
sdkOptions.settingSources = ['project', 'user', 'local'];
|
|
224
228
|
|
|
225
|
-
// Map resume session
|
|
226
229
|
if (sessionId) {
|
|
227
230
|
sdkOptions.resume = sessionId;
|
|
228
231
|
}
|
|
@@ -234,16 +237,13 @@ function mapCliOptionsToSDK(options = {}) {
|
|
|
234
237
|
* Adds a session to the active sessions map
|
|
235
238
|
* @param {string} sessionId - Session identifier
|
|
236
239
|
* @param {Object} queryInstance - SDK query instance
|
|
237
|
-
* @param {
|
|
238
|
-
* @param {string} tempDir - Temp directory for cleanup
|
|
240
|
+
* @param {Object} writer - WebSocket writer for reconnect support
|
|
239
241
|
*/
|
|
240
|
-
function addSession(sessionId, queryInstance,
|
|
242
|
+
function addSession(sessionId, queryInstance, writer = null) {
|
|
241
243
|
activeSessions.set(sessionId, {
|
|
242
244
|
instance: queryInstance,
|
|
243
245
|
startTime: Date.now(),
|
|
244
246
|
status: 'active',
|
|
245
|
-
tempImagePaths,
|
|
246
|
-
tempDir,
|
|
247
247
|
writer
|
|
248
248
|
});
|
|
249
249
|
}
|
|
@@ -362,90 +362,35 @@ function extractTokenBudget(sdkMessage) {
|
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
/**
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
if (!images || images.length === 0) {
|
|
377
|
-
return { modifiedCommand: command, tempImagePaths, tempDir };
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
try {
|
|
381
|
-
// Create temp directory in the project directory
|
|
382
|
-
const workingDir = cwd || process.cwd();
|
|
383
|
-
tempDir = path.join(workingDir, '.tmp', 'images', Date.now().toString());
|
|
384
|
-
await fs.mkdir(tempDir, { recursive: true });
|
|
385
|
-
|
|
386
|
-
// Save each image to a temp file
|
|
387
|
-
for (const [index, image] of images.entries()) {
|
|
388
|
-
// Extract base64 data and mime type
|
|
389
|
-
const matches = image.data.match(/^data:([^;]+);base64,(.+)$/);
|
|
390
|
-
if (!matches) {
|
|
391
|
-
console.error('Invalid image data format');
|
|
392
|
-
continue;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const [, mimeType, base64Data] = matches;
|
|
396
|
-
const extension = mimeType.split('/')[1] || 'png';
|
|
397
|
-
const filename = `image_${index}.${extension}`;
|
|
398
|
-
const filepath = path.join(tempDir, filename);
|
|
399
|
-
|
|
400
|
-
// Write base64 data to file
|
|
401
|
-
await fs.writeFile(filepath, Buffer.from(base64Data, 'base64'));
|
|
402
|
-
tempImagePaths.push(filepath);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Include the full image paths in the prompt
|
|
406
|
-
let modifiedCommand = command;
|
|
407
|
-
if (tempImagePaths.length > 0 && command && command.trim()) {
|
|
408
|
-
const imageNote = `\n\n[Images provided at the following paths:]\n${tempImagePaths.map((p, i) => `${i + 1}. ${p}`).join('\n')}`;
|
|
409
|
-
modifiedCommand = command + imageNote;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Images processed
|
|
413
|
-
return { modifiedCommand, tempImagePaths, tempDir };
|
|
414
|
-
} catch (error) {
|
|
415
|
-
console.error('Error processing images for SDK:', error);
|
|
416
|
-
return { modifiedCommand: command, tempImagePaths, tempDir };
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Cleans up temporary image files
|
|
422
|
-
* @param {Array<string>} tempImagePaths - Array of temp file paths to delete
|
|
423
|
-
* @param {string} tempDir - Temp directory to remove
|
|
365
|
+
* Builds the SDK `prompt` payload for one turn.
|
|
366
|
+
*
|
|
367
|
+
* Plain text turns pass the string through unchanged. Turns with image
|
|
368
|
+
* attachments use the SDK's streaming-input mode: a single SDKUserMessage
|
|
369
|
+
* whose content carries the prompt text plus one base64 `image` block per
|
|
370
|
+
* attachment (read from the global `~/.cloudcli/assets` folder).
|
|
371
|
+
*
|
|
372
|
+
* @param {string} command - User prompt
|
|
373
|
+
* @param {Array} images - Image descriptors ({ path, name?, mimeType? })
|
|
374
|
+
* @param {string} cwd - Project working directory image paths resolve against
|
|
375
|
+
* @returns {Promise<string|AsyncIterable>} SDK prompt payload
|
|
424
376
|
*/
|
|
425
|
-
async function
|
|
426
|
-
if (
|
|
427
|
-
return;
|
|
377
|
+
async function buildPromptPayload(command, images, cwd) {
|
|
378
|
+
if (normalizeImageDescriptors(images).length === 0) {
|
|
379
|
+
return command;
|
|
428
380
|
}
|
|
429
381
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// Temp files cleaned
|
|
446
|
-
} catch (error) {
|
|
447
|
-
console.error('Error during temp file cleanup:', error);
|
|
448
|
-
}
|
|
382
|
+
const content = await buildClaudeUserContent(command, images, cwd);
|
|
383
|
+
return (async function* () {
|
|
384
|
+
yield {
|
|
385
|
+
type: 'user',
|
|
386
|
+
message: {
|
|
387
|
+
role: 'user',
|
|
388
|
+
content
|
|
389
|
+
},
|
|
390
|
+
parent_tool_use_id: null,
|
|
391
|
+
timestamp: new Date().toISOString()
|
|
392
|
+
};
|
|
393
|
+
})();
|
|
449
394
|
}
|
|
450
395
|
|
|
451
396
|
/**
|
|
@@ -516,8 +461,6 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
516
461
|
const { sessionId, sessionSummary } = options;
|
|
517
462
|
let capturedSessionId = sessionId;
|
|
518
463
|
let sessionCreatedSent = false;
|
|
519
|
-
let tempImagePaths = [];
|
|
520
|
-
let tempDir = null;
|
|
521
464
|
|
|
522
465
|
const emitNotification = (event) => {
|
|
523
466
|
notifyUserIfEnabled({
|
|
@@ -533,24 +476,28 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
533
476
|
sessionId,
|
|
534
477
|
options.model,
|
|
535
478
|
);
|
|
479
|
+
let effortModels = CLAUDE_FALLBACK_MODELS;
|
|
480
|
+
try {
|
|
481
|
+
effortModels = (await providerModelsService.getProviderModels('claude')).models;
|
|
482
|
+
} catch (error) {
|
|
483
|
+
console.warn('[Claude SDK] Unable to load provider models for effort validation:', error);
|
|
484
|
+
}
|
|
536
485
|
|
|
537
|
-
// Map CLI options to SDK format
|
|
538
486
|
const sdkOptions = mapCliOptionsToSDK({
|
|
539
487
|
...options,
|
|
540
488
|
model: resolvedModel || options.model,
|
|
489
|
+
effortModels,
|
|
541
490
|
});
|
|
542
491
|
|
|
543
|
-
// Load MCP configuration
|
|
544
492
|
const mcpServers = await loadMcpConfig(options.cwd);
|
|
545
493
|
if (mcpServers) {
|
|
546
494
|
sdkOptions.mcpServers = mcpServers;
|
|
547
495
|
}
|
|
548
496
|
|
|
549
|
-
//
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
tempDir = imageResult.tempDir;
|
|
497
|
+
// Turns with image attachments switch to streaming input so the images
|
|
498
|
+
// ride along as real content blocks. Built per query attempt because an
|
|
499
|
+
// async generator cannot be replayed once consumed.
|
|
500
|
+
const createPrompt = () => buildPromptPayload(command, options.images, options.cwd);
|
|
554
501
|
|
|
555
502
|
sdkOptions.hooks = {
|
|
556
503
|
Notification: [{
|
|
@@ -650,14 +597,14 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
650
597
|
return { behavior: 'deny', message: decision.message ?? 'User denied tool use' };
|
|
651
598
|
};
|
|
652
599
|
|
|
653
|
-
//
|
|
600
|
+
// Query constructor reads this synchronously.
|
|
654
601
|
const prevStreamTimeout = process.env.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT;
|
|
655
602
|
process.env.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT = '300000';
|
|
656
603
|
|
|
657
604
|
let queryInstance;
|
|
658
605
|
try {
|
|
659
606
|
queryInstance = query({
|
|
660
|
-
prompt:
|
|
607
|
+
prompt: await createPrompt(),
|
|
661
608
|
options: sdkOptions
|
|
662
609
|
});
|
|
663
610
|
} catch (hookError) {
|
|
@@ -666,7 +613,7 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
666
613
|
console.warn('Failed to initialize Claude query with hooks, retrying without hooks:', hookError?.message || hookError);
|
|
667
614
|
delete sdkOptions.hooks;
|
|
668
615
|
queryInstance = query({
|
|
669
|
-
prompt:
|
|
616
|
+
prompt: await createPrompt(),
|
|
670
617
|
options: sdkOptions
|
|
671
618
|
});
|
|
672
619
|
}
|
|
@@ -680,7 +627,7 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
680
627
|
|
|
681
628
|
// Track the query instance for abort capability
|
|
682
629
|
if (capturedSessionId) {
|
|
683
|
-
addSession(capturedSessionId, queryInstance,
|
|
630
|
+
addSession(capturedSessionId, queryInstance, ws);
|
|
684
631
|
}
|
|
685
632
|
|
|
686
633
|
// Process streaming messages
|
|
@@ -690,7 +637,7 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
690
637
|
if (message.session_id && !capturedSessionId) {
|
|
691
638
|
|
|
692
639
|
capturedSessionId = message.session_id;
|
|
693
|
-
addSession(capturedSessionId, queryInstance,
|
|
640
|
+
addSession(capturedSessionId, queryInstance, ws);
|
|
694
641
|
|
|
695
642
|
// Set session ID on writer
|
|
696
643
|
if (ws.setSessionId && typeof ws.setSessionId === 'function') {
|
|
@@ -732,9 +679,6 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
732
679
|
removeSession(capturedSessionId);
|
|
733
680
|
}
|
|
734
681
|
|
|
735
|
-
// Clean up temporary image files
|
|
736
|
-
await cleanupTempFiles(tempImagePaths, tempDir);
|
|
737
|
-
|
|
738
682
|
// Send the terminal completion event — skipped for aborted runs, whose
|
|
739
683
|
// terminal `complete` (aborted: true) was already sent by abort-session.
|
|
740
684
|
const wasAborted = capturedSessionId ? abortedSessionIds.delete(capturedSessionId) : false;
|
|
@@ -758,9 +702,6 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
758
702
|
removeSession(capturedSessionId);
|
|
759
703
|
}
|
|
760
704
|
|
|
761
|
-
// Clean up temporary image files on error
|
|
762
|
-
await cleanupTempFiles(tempImagePaths, tempDir);
|
|
763
|
-
|
|
764
705
|
const wasAborted = capturedSessionId ? abortedSessionIds.delete(capturedSessionId) : false;
|
|
765
706
|
if (wasAborted) {
|
|
766
707
|
// The abort already produced the terminal complete; a generator throw
|
|
@@ -813,9 +754,6 @@ async function abortClaudeSDKSession(sessionId) {
|
|
|
813
754
|
// Update session status
|
|
814
755
|
session.status = 'aborted';
|
|
815
756
|
|
|
816
|
-
// Clean up temporary image files
|
|
817
|
-
await cleanupTempFiles(session.tempImagePaths, session.tempDir);
|
|
818
|
-
|
|
819
757
|
// Clean up session
|
|
820
758
|
removeSession(sessionId);
|
|
821
759
|
|
package/server/cli.js
CHANGED
|
@@ -256,13 +256,11 @@ async function updatePackage() {
|
|
|
256
256
|
const SANDBOX_TEMPLATES = {
|
|
257
257
|
claude: 'docker.io/cloudcliai/sandbox:claude-code',
|
|
258
258
|
codex: 'docker.io/cloudcliai/sandbox:codex',
|
|
259
|
-
gemini: 'docker.io/cloudcliai/sandbox:gemini',
|
|
260
259
|
};
|
|
261
260
|
|
|
262
261
|
const SANDBOX_SECRETS = {
|
|
263
262
|
claude: 'anthropic',
|
|
264
263
|
codex: 'openai',
|
|
265
|
-
gemini: 'google',
|
|
266
264
|
};
|
|
267
265
|
|
|
268
266
|
function parseSandboxArgs(args) {
|
|
@@ -338,7 +336,7 @@ Subcommands:
|
|
|
338
336
|
${c.bright('help')} Show this help
|
|
339
337
|
|
|
340
338
|
Options:
|
|
341
|
-
-a, --agent <agent> Agent to use: claude, codex
|
|
339
|
+
-a, --agent <agent> Agent to use: claude, codex (default: claude)
|
|
342
340
|
-n, --name <name> Sandbox name (default: derived from workspace folder)
|
|
343
341
|
-t, --template <image> Custom template image
|
|
344
342
|
-e, --env <KEY=VALUE> Set environment variable (repeatable)
|
|
@@ -359,7 +357,6 @@ Prerequisites:
|
|
|
359
357
|
sbx login
|
|
360
358
|
sbx secret set -g anthropic # for Claude
|
|
361
359
|
sbx secret set -g openai # for Codex
|
|
362
|
-
sbx secret set -g google # for Gemini
|
|
363
360
|
|
|
364
361
|
Advanced usage:
|
|
365
362
|
For branch mode, multiple workspaces, memory limits, network policies,
|
package/server/cursor-cli.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
1
|
import crossSpawn from 'cross-spawn';
|
|
2
|
+
|
|
3
|
+
import { appendImagesInputTag } from './shared/image-attachments.js';
|
|
3
4
|
import { notifyRunFailed, notifyRunStopped } from './services/notification-orchestrator.js';
|
|
4
5
|
import { sessionsService } from './modules/providers/services/sessions.service.js';
|
|
5
6
|
import { providerAuthService } from './modules/providers/services/provider-auth.service.js';
|
|
6
7
|
import { providerModelsService } from './modules/providers/services/provider-models.service.js';
|
|
7
|
-
import { createCompleteMessage, createNormalizedMessage } from './shared/utils.js';
|
|
8
|
+
import { createCompleteMessage, createNormalizedMessage, flattenPromptForWindowsShell } from './shared/utils.js';
|
|
8
9
|
|
|
9
|
-
//
|
|
10
|
-
|
|
10
|
+
// cross-spawn resolves .cmd shims/PATHEXT on Windows and delegates to
|
|
11
|
+
// child_process.spawn everywhere else.
|
|
12
|
+
const spawnFunction = crossSpawn;
|
|
11
13
|
|
|
12
14
|
let activeCursorProcesses = new Map(); // Track active processes by session ID
|
|
13
15
|
|
|
@@ -28,7 +30,7 @@ function isWorkspaceTrustPrompt(text = '') {
|
|
|
28
30
|
|
|
29
31
|
async function spawnCursor(command, options = {}, ws) {
|
|
30
32
|
return new Promise(async (resolve, reject) => {
|
|
31
|
-
const { sessionId, projectPath, cwd,
|
|
33
|
+
const { sessionId, projectPath, cwd, toolsSettings, skipPermissions, model, sessionSummary, images } = options;
|
|
32
34
|
const resolvedModel = await providerModelsService.resolveResumeModel('cursor', sessionId, model);
|
|
33
35
|
let capturedSessionId = sessionId; // Track session ID throughout the process
|
|
34
36
|
let sessionCreatedSent = false; // Track if we've already sent session-created event
|
|
@@ -55,8 +57,12 @@ async function spawnCursor(command, options = {}, ws) {
|
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
if (command && command.trim()) {
|
|
58
|
-
// Provide a prompt (works for both new and resumed sessions)
|
|
59
|
-
|
|
60
|
+
// Provide a prompt (works for both new and resumed sessions). Image
|
|
61
|
+
// attachments ride along as an <images_input> path list appended to the
|
|
62
|
+
// prompt; the session history reader strips the tag back out for display.
|
|
63
|
+
// cursor-agent is a .cmd shim on Windows, so the whole argument must be
|
|
64
|
+
// newline-free or cmd.exe silently truncates it at the first newline.
|
|
65
|
+
baseArgs.push('-p', flattenPromptForWindowsShell(appendImagesInputTag(command, images)));
|
|
60
66
|
|
|
61
67
|
// Model overrides are applied to both new and resumed sessions so a
|
|
62
68
|
// session-scoped change request can take effect on the next turn.
|
|
@@ -71,7 +77,6 @@ async function spawnCursor(command, options = {}, ws) {
|
|
|
71
77
|
// Add skip permissions flag if enabled
|
|
72
78
|
if (skipPermissions || settings.skipPermissions) {
|
|
73
79
|
baseArgs.push('-f');
|
|
74
|
-
console.log('Using -f flag (skip permissions)');
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
// Use cwd (actual project directory) instead of projectPath
|
|
@@ -126,10 +131,6 @@ async function spawnCursor(command, options = {}, ws) {
|
|
|
126
131
|
console.log('Retrying Cursor CLI with --trust after workspace trust prompt');
|
|
127
132
|
}
|
|
128
133
|
|
|
129
|
-
console.log('Spawning Cursor CLI:', 'cursor-agent', args.join(' '));
|
|
130
|
-
console.log('Working directory:', workingDir);
|
|
131
|
-
console.log('Session info - Input sessionId:', sessionId, 'Resume:', resume);
|
|
132
|
-
|
|
133
134
|
const cursorProcess = spawnFunction('cursor-agent', args, {
|
|
134
135
|
cwd: workingDir,
|
|
135
136
|
stdio: ['pipe', 'pipe', 'pipe'],
|