centaurus-cli 3.1.3 → 3.1.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/cli-adapter.js +685 -153
- package/dist/cli-adapter.js.map +1 -1
- package/dist/config/defaultConfig.js +1 -4
- package/dist/config/defaultConfig.js.map +1 -1
- package/dist/config/models.js +4 -0
- package/dist/config/models.js.map +1 -1
- package/dist/config/slash-commands.js +66 -2
- package/dist/config/slash-commands.js.map +1 -1
- package/dist/config/types.js +4 -4
- package/dist/config/types.js.map +1 -1
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -1
- package/dist/services/ai-context-injector.js +109 -0
- package/dist/services/ai-context-injector.js.map +1 -1
- package/dist/services/api-client.js.map +1 -1
- package/dist/services/background-task-manager.js +59 -0
- package/dist/services/background-task-manager.js.map +1 -1
- package/dist/services/local-chat-storage.js +2 -0
- package/dist/services/local-chat-storage.js.map +1 -1
- package/dist/services/skill-storage.js +141 -0
- package/dist/services/skill-storage.js.map +1 -0
- package/dist/services/sub-agent-manager.js +49 -8
- package/dist/services/sub-agent-manager.js.map +1 -1
- package/dist/services/warpify-detector.js +17 -5
- package/dist/services/warpify-detector.js.map +1 -1
- package/dist/tools/background-command.js +5 -2
- package/dist/tools/background-command.js.map +1 -1
- package/dist/tools/command.js +367 -109
- package/dist/tools/command.js.map +1 -1
- package/dist/tools/file-ops.js +23 -6
- package/dist/tools/file-ops.js.map +1 -1
- package/dist/tools/plan-mode.js +184 -336
- package/dist/tools/plan-mode.js.map +1 -1
- package/dist/tools/sub-agent.js +24 -5
- package/dist/tools/sub-agent.js.map +1 -1
- package/dist/tools/todo-list.js +157 -0
- package/dist/tools/todo-list.js.map +1 -0
- package/dist/types/skill.js +30 -0
- package/dist/types/skill.js.map +1 -0
- package/dist/ui/components/App.js +956 -162
- package/dist/ui/components/App.js.map +1 -1
- package/dist/ui/components/AuthScreen.js +3 -1
- package/dist/ui/components/AuthScreen.js.map +1 -1
- package/dist/ui/components/AuthWelcomeScreen.js +3 -1
- package/dist/ui/components/AuthWelcomeScreen.js.map +1 -1
- package/dist/ui/components/CodeBlock.js +3 -1
- package/dist/ui/components/CodeBlock.js.map +1 -1
- package/dist/ui/components/CompactShellPreview.js +44 -0
- package/dist/ui/components/CompactShellPreview.js.map +1 -0
- package/dist/ui/components/ConfigViewer.js +3 -1
- package/dist/ui/components/ConfigViewer.js.map +1 -1
- package/dist/ui/components/ConfirmPrompt.js +3 -1
- package/dist/ui/components/ConfirmPrompt.js.map +1 -1
- package/dist/ui/components/ConnectionStatusMessage.js +3 -1
- package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
- package/dist/ui/components/DetailedPlanReviewScreen.js +84 -74
- package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
- package/dist/ui/components/DiffViewer.js +6 -3
- package/dist/ui/components/DiffViewer.js.map +1 -1
- package/dist/ui/components/FileCreationPreview.js.map +1 -1
- package/dist/ui/components/FileTagAutocomplete.js +4 -2
- package/dist/ui/components/FileTagAutocomplete.js.map +1 -1
- package/dist/ui/components/InputBox.js +243 -40
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/InteractiveShell.js +5 -3
- package/dist/ui/components/InteractiveShell.js.map +1 -1
- package/dist/ui/components/KeyboardHelp.js +4 -1
- package/dist/ui/components/KeyboardHelp.js.map +1 -1
- package/dist/ui/components/LoadingIndicator.js +3 -1
- package/dist/ui/components/LoadingIndicator.js.map +1 -1
- package/dist/ui/components/MCPAddScreen.js +63 -13
- package/dist/ui/components/MCPAddScreen.js.map +1 -1
- package/dist/ui/components/MarkdownRenderer.js +3 -1
- package/dist/ui/components/MarkdownRenderer.js.map +1 -1
- package/dist/ui/components/MessageDisplay.js +9 -7
- package/dist/ui/components/MessageDisplay.js.map +1 -1
- package/dist/ui/components/ModelPicker.js +170 -0
- package/dist/ui/components/ModelPicker.js.map +1 -0
- package/dist/ui/components/MonitorModeAIPanel.js +3 -1
- package/dist/ui/components/MonitorModeAIPanel.js.map +1 -1
- package/dist/ui/components/PlanAcceptedMessage.js +12 -6
- package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
- package/dist/ui/components/PlanQuestionMessage.js +37 -0
- package/dist/ui/components/PlanQuestionMessage.js.map +1 -0
- package/dist/ui/components/PlanQuestionScreen.js +138 -0
- package/dist/ui/components/PlanQuestionScreen.js.map +1 -0
- package/dist/ui/components/PlanReviewScreen.js +7 -9
- package/dist/ui/components/PlanReviewScreen.js.map +1 -1
- package/dist/ui/components/RulesEditorScreen.js +65 -28
- package/dist/ui/components/RulesEditorScreen.js.map +1 -1
- package/dist/ui/components/SelectPrompt.js +3 -1
- package/dist/ui/components/SelectPrompt.js.map +1 -1
- package/dist/ui/components/SkillCreatorScreen.js +217 -0
- package/dist/ui/components/SkillCreatorScreen.js.map +1 -0
- package/dist/ui/components/SlashCommandAutocomplete.js +4 -2
- package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -1
- package/dist/ui/components/StatusBar.js +4 -2
- package/dist/ui/components/StatusBar.js.map +1 -1
- package/dist/ui/components/StreamingMessageDisplay.js +5 -3
- package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
- package/dist/ui/components/SubAgentListScreen.js +65 -0
- package/dist/ui/components/SubAgentListScreen.js.map +1 -0
- package/dist/ui/components/SubAgentViewScreen.js +123 -0
- package/dist/ui/components/SubAgentViewScreen.js.map +1 -0
- package/dist/ui/components/TaskCompletedMessage.js +40 -8
- package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
- package/dist/ui/components/TaskProgressIndicator.js +6 -4
- package/dist/ui/components/TaskProgressIndicator.js.map +1 -1
- package/dist/ui/components/TextEditor.js +297 -0
- package/dist/ui/components/TextEditor.js.map +1 -0
- package/dist/ui/components/TodoListMessage.js +59 -0
- package/dist/ui/components/TodoListMessage.js.map +1 -0
- package/dist/ui/components/ToolExecutionMessage.js +134 -84
- package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
- package/dist/ui/components/ToolExecutionStatus.js +3 -1
- package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
- package/dist/ui/components/WelcomeBanner.js +33 -33
- package/dist/ui/components/WelcomeBanner.js.map +1 -1
- package/dist/ui/components/WorkflowCreatorScreen.js +5 -3
- package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -1
- package/dist/ui/theme.js +97 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/utils/chat-history-limit.js +247 -0
- package/dist/ui/utils/chat-history-limit.js.map +1 -0
- package/dist/utils/chat-formatter.js +22 -9
- package/dist/utils/chat-formatter.js.map +1 -1
- package/dist/utils/input-classifier.js +11 -1
- package/dist/utils/input-classifier.js.map +1 -1
- package/dist/utils/output-truncation.js +175 -0
- package/dist/utils/output-truncation.js.map +1 -0
- package/dist/utils/rule-reference-resolver.js +3 -3
- package/dist/utils/rule-reference-resolver.js.map +1 -1
- package/dist/utils/tunnel-commands-manager.js +134 -0
- package/dist/utils/tunnel-commands-manager.js.map +1 -0
- package/package.json +91 -90
- package/postinstall.js +4 -11
- package/dist/ui/components/MultiLineInput.js +0 -255
- package/dist/ui/components/MultiLineInput.js.map +0 -1
package/dist/tools/command.js
CHANGED
|
@@ -2,6 +2,63 @@ import * as shellUtils from "../utils/shell.js";
|
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import { runWSLCommand, runDockerCommand, runSSHCommand } from "../utils/editor-utils.js";
|
|
5
|
+
import { BackgroundTaskManager } from "../services/background-task-manager.js";
|
|
6
|
+
import { quickLog } from "../utils/conversation-logger.js";
|
|
7
|
+
function extractCdTargetsFromCommand(command) {
|
|
8
|
+
const targets = [];
|
|
9
|
+
const segments = command.split(/\s*(?:&&|\|\||;)\s*/);
|
|
10
|
+
for (const segment of segments) {
|
|
11
|
+
const trimmed = segment.trim();
|
|
12
|
+
if (!trimmed) continue;
|
|
13
|
+
let match = null;
|
|
14
|
+
match = trimmed.match(/^cd\s+\/d\s+(.+)$/i);
|
|
15
|
+
if (!match) {
|
|
16
|
+
match = trimmed.match(/^cd\s+(.+)$/i);
|
|
17
|
+
}
|
|
18
|
+
if (!match) {
|
|
19
|
+
match = trimmed.match(/^pushd\s+(.+)$/i);
|
|
20
|
+
}
|
|
21
|
+
if (!match) {
|
|
22
|
+
match = trimmed.match(/^Set-Location\s+(.+)$/i);
|
|
23
|
+
}
|
|
24
|
+
if (!match) {
|
|
25
|
+
match = trimmed.match(/^sl\s+(.+)$/i);
|
|
26
|
+
}
|
|
27
|
+
if (!match) {
|
|
28
|
+
match = trimmed.match(/^chdir\s+(.+)$/i);
|
|
29
|
+
}
|
|
30
|
+
if (match) {
|
|
31
|
+
let target = match[1].trim();
|
|
32
|
+
target = target.replace(/^["']|["']$/g, "");
|
|
33
|
+
if (target.length > 1) {
|
|
34
|
+
target = target.replace(/[\/\\]+$/, "");
|
|
35
|
+
}
|
|
36
|
+
targets.push(target);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return targets;
|
|
40
|
+
}
|
|
41
|
+
function resolvePostCommandCwd(currentCwd, command, isWindows = false) {
|
|
42
|
+
const targets = extractCdTargetsFromCommand(command);
|
|
43
|
+
if (targets.length === 0) return null;
|
|
44
|
+
let cwd = currentCwd;
|
|
45
|
+
for (const target of targets) {
|
|
46
|
+
let expanded = target;
|
|
47
|
+
if (expanded === "~" || expanded.startsWith("~/") || expanded.startsWith("~\\")) {
|
|
48
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
49
|
+
expanded = homeDir + expanded.substring(1);
|
|
50
|
+
}
|
|
51
|
+
if (expanded === "-") continue;
|
|
52
|
+
cwd = path.resolve(cwd, expanded);
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
if (fs.existsSync(cwd) && fs.statSync(cwd).isDirectory()) {
|
|
56
|
+
return cwd;
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
5
62
|
function processShellInput(input) {
|
|
6
63
|
let processed = input.replace(/\\n/g, "\r").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\b/g, "\b").replace(/\\x1B/g, "\x1B");
|
|
7
64
|
const keyMap = {
|
|
@@ -33,6 +90,25 @@ function resolveCommandWorkingDirectory(currentContext, contextCwd, commandCwd)
|
|
|
33
90
|
}
|
|
34
91
|
return path.posix.isAbsolute(commandCwd) ? commandCwd : path.posix.join(remoteBase, commandCwd);
|
|
35
92
|
}
|
|
93
|
+
const TIMEOUT_TRANSFER_PREFIX = "__TIMEOUT_TRANSFER__";
|
|
94
|
+
function buildTransferMessage(taskId, command, cwd, timeoutSeconds, outputSoFar, remoteContext) {
|
|
95
|
+
const outputPreview = outputSoFar.length > 500 ? outputSoFar.slice(-500) : outputSoFar;
|
|
96
|
+
const location = remoteContext ? ` (on ${remoteContext})` : "";
|
|
97
|
+
return `Command exceeded timeout of ${timeoutSeconds}s and has been transferred to background${location}.
|
|
98
|
+
|
|
99
|
+
**Background Task ID:** ${taskId}
|
|
100
|
+
**Command:** ${command}
|
|
101
|
+
**Working Directory:** ${cwd}
|
|
102
|
+
**Status:** Still running in background
|
|
103
|
+
|
|
104
|
+
**Output so far (last 500 chars):**
|
|
105
|
+
\`\`\`
|
|
106
|
+
${outputPreview || "(no output yet)"}
|
|
107
|
+
\`\`\`
|
|
108
|
+
|
|
109
|
+
Use \`background_command\` with action="status" and task_id="${taskId}" to check progress.
|
|
110
|
+
Use \`background_command\` with action="kill" and task_id="${taskId}" to terminate it.`;
|
|
111
|
+
}
|
|
36
112
|
const runCommandTool = {
|
|
37
113
|
schema: {
|
|
38
114
|
name: "execute_command",
|
|
@@ -71,13 +147,48 @@ Commands will be run with PAGER=cat. You may want to limit the length of output
|
|
|
71
147
|
shell_input: {
|
|
72
148
|
type: "string",
|
|
73
149
|
description: "[INTERNAL - DO NOT USE FROM MAIN AGENT] Input to send to a CURRENTLY RUNNING interactive shell. This parameter is used internally by the shell input sub-agent. When starting a command, do NOT set this parameter - just start the command and the user will provide input through the shell UI or agent control mode."
|
|
150
|
+
},
|
|
151
|
+
timeout_seconds: {
|
|
152
|
+
type: "integer",
|
|
153
|
+
description: "Optional timeout in seconds. If the command takes longer than this, it will be automatically transferred to a background shell and you will receive the background task ID to monitor it. Use this for commands that might take a while (e.g., builds, installs, tests) where you want to continue working if they run long. If not set, the command runs until completion with no timeout."
|
|
74
154
|
}
|
|
75
155
|
},
|
|
76
156
|
required: ["reason_text", "CommandLine", "Cwd", "SafeToAutoRun", "WaitMsBeforeAsync"]
|
|
77
157
|
}
|
|
78
158
|
},
|
|
79
159
|
async execute(args, context) {
|
|
80
|
-
const { CommandLine, Cwd, shell_input } = args;
|
|
160
|
+
const { CommandLine, Cwd, shell_input, timeout_seconds } = args;
|
|
161
|
+
const timeoutMs = timeout_seconds && timeout_seconds > 0 ? timeout_seconds * 1e3 : 0;
|
|
162
|
+
if (!shell_input && context.cliAdapter && context.cliAdapter.isCustomTunnelActive()) {
|
|
163
|
+
const interactiveProcess = context.cliAdapter.getCurrentInteractiveProcess();
|
|
164
|
+
if (interactiveProcess && CommandLine) {
|
|
165
|
+
const inputWithEnter = CommandLine.endsWith("\n") || CommandLine.endsWith("\r") ? CommandLine : CommandLine + "\r";
|
|
166
|
+
const processedInput = processShellInput(inputWithEnter);
|
|
167
|
+
interactiveProcess.write(processedInput);
|
|
168
|
+
const tunnelBuf = () => context.cliAdapter.tunnelOutputBuffer || "";
|
|
169
|
+
const beforeLen = tunnelBuf().length;
|
|
170
|
+
let lastLen = beforeLen;
|
|
171
|
+
let stableTime = 0;
|
|
172
|
+
const waitStart = Date.now();
|
|
173
|
+
while (Date.now() - waitStart < 5e3) {
|
|
174
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
175
|
+
const curLen = tunnelBuf().length;
|
|
176
|
+
if (curLen > lastLen) {
|
|
177
|
+
lastLen = curLen;
|
|
178
|
+
stableTime = 0;
|
|
179
|
+
} else {
|
|
180
|
+
stableTime += 300;
|
|
181
|
+
if (stableTime >= 800) break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const captured = tunnelBuf().substring(beforeLen);
|
|
185
|
+
const { processTerminalOutput } = await import("../utils/terminal-output.js");
|
|
186
|
+
return processTerminalOutput(captured).trim() || "(command sent, no output captured)";
|
|
187
|
+
}
|
|
188
|
+
if (!interactiveProcess) {
|
|
189
|
+
context.cliAdapter.customTunnelCommand = null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
81
192
|
if (shell_input) {
|
|
82
193
|
if (context.cliAdapter) {
|
|
83
194
|
const interactiveProcess = context.cliAdapter.getCurrentInteractiveProcess();
|
|
@@ -223,69 +334,124 @@ Command that needs background execution: ${command}`
|
|
|
223
334
|
return new Promise((resolve, reject) => {
|
|
224
335
|
let output = "";
|
|
225
336
|
let exitCode;
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
337
|
+
let transferred = false;
|
|
338
|
+
let timeoutTimer = null;
|
|
339
|
+
let onDataCallback = (data) => {
|
|
340
|
+
output += data;
|
|
341
|
+
if (context.onStreamingOutput) {
|
|
342
|
+
context.onStreamingOutput(data, "stdout");
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
let onExitCallback = (code) => {
|
|
346
|
+
exitCode = code;
|
|
347
|
+
if (timeoutTimer) {
|
|
348
|
+
clearTimeout(timeoutTimer);
|
|
349
|
+
timeoutTimer = null;
|
|
350
|
+
}
|
|
351
|
+
if (transferred) return;
|
|
352
|
+
if (context.cliAdapter) {
|
|
353
|
+
context.cliAdapter.setCurrentInteractiveProcess(void 0);
|
|
354
|
+
}
|
|
355
|
+
if (code === 0) {
|
|
356
|
+
const newCwd = resolvePostCommandCwd(executionCwd, command);
|
|
357
|
+
if (newCwd && newCwd !== executionCwd && context.cliAdapter) {
|
|
358
|
+
context.cliAdapter.cwd = newCwd;
|
|
359
|
+
contextManager.updateWorkingDirectory(newCwd);
|
|
360
|
+
if (context.cliAdapter.onCwdChange) {
|
|
361
|
+
context.cliAdapter.onCwdChange(newCwd);
|
|
362
|
+
}
|
|
239
363
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const errorOutput = output + `
|
|
364
|
+
resolve(output || "Command executed successfully");
|
|
365
|
+
} else {
|
|
366
|
+
const errorOutput = output + `
|
|
244
367
|
Exit Code: ${code}`;
|
|
245
|
-
|
|
368
|
+
reject(new Error(`${errorOutput || `Command failed with exit code ${code}`}
|
|
246
369
|
|
|
247
370
|
Possible reasons:
|
|
248
371
|
1. The command is invalid or not installed.
|
|
249
372
|
2. The arguments are incorrect.
|
|
250
373
|
3. The command requires user input (interactive mode).`));
|
|
251
|
-
}
|
|
252
374
|
}
|
|
375
|
+
};
|
|
376
|
+
const interactiveProcess = shellUtils.executeCommandInteractive(
|
|
377
|
+
command,
|
|
378
|
+
executionCwd,
|
|
379
|
+
(data) => onDataCallback(data),
|
|
380
|
+
(code) => onExitCallback(code)
|
|
253
381
|
);
|
|
254
382
|
if (context.cliAdapter) {
|
|
255
383
|
context.cliAdapter.setCurrentInteractiveProcess(interactiveProcess);
|
|
256
384
|
}
|
|
385
|
+
if (timeoutMs > 0) {
|
|
386
|
+
timeoutTimer = setTimeout(() => {
|
|
387
|
+
if (transferred || exitCode !== void 0) return;
|
|
388
|
+
transferred = true;
|
|
389
|
+
args.timeoutTransferred = true;
|
|
390
|
+
quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [execute_command] Timeout (${timeout_seconds}s) exceeded for: ${command}. Transferring to background.
|
|
391
|
+
`);
|
|
392
|
+
const adopted = BackgroundTaskManager.adoptRunningProcess(
|
|
393
|
+
command,
|
|
394
|
+
executionCwd,
|
|
395
|
+
output
|
|
396
|
+
);
|
|
397
|
+
const remotePty = {
|
|
398
|
+
write: (data) => interactiveProcess.write(data),
|
|
399
|
+
kill: () => interactiveProcess.kill(),
|
|
400
|
+
resize: (cols, rows) => {
|
|
401
|
+
if (interactiveProcess.resize) interactiveProcess.resize(cols, rows);
|
|
402
|
+
},
|
|
403
|
+
isRunning: () => interactiveProcess.ptyProcess?.isRunning?.() ?? false
|
|
404
|
+
};
|
|
405
|
+
adopted.setRemotePty(remotePty);
|
|
406
|
+
onDataCallback = adopted.onData;
|
|
407
|
+
onExitCallback = adopted.onExit;
|
|
408
|
+
if (context.cliAdapter) {
|
|
409
|
+
context.cliAdapter.setCurrentInteractiveProcess(void 0);
|
|
410
|
+
}
|
|
411
|
+
resolve(buildTransferMessage(adopted.id, command, executionCwd, timeout_seconds, output));
|
|
412
|
+
}, timeoutMs);
|
|
413
|
+
}
|
|
257
414
|
});
|
|
258
415
|
} else if (currentContext.type === "wsl") {
|
|
259
416
|
const remoteCwd = executionCwd;
|
|
260
417
|
const distribution = currentContext.metadata?.distroName || "Ubuntu";
|
|
261
418
|
return new Promise((resolve, reject) => {
|
|
262
419
|
let output = "";
|
|
420
|
+
let transferred = false;
|
|
421
|
+
let timeoutTimer = null;
|
|
263
422
|
const constrainedCols = Math.max(40, (process.stdout.columns || 80) - 4);
|
|
264
423
|
const constrainedRows = Math.min(process.stdout.rows || 24, 50);
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
424
|
+
let onDataCallback = (data) => {
|
|
425
|
+
output += data;
|
|
426
|
+
if (context.onStreamingOutput) {
|
|
427
|
+
context.onStreamingOutput(data, "stdout");
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
let onExitCallback = (exitCode) => {
|
|
431
|
+
if (timeoutTimer) {
|
|
432
|
+
clearTimeout(timeoutTimer);
|
|
433
|
+
timeoutTimer = null;
|
|
434
|
+
}
|
|
435
|
+
if (transferred) return;
|
|
436
|
+
if (context.cliAdapter) {
|
|
437
|
+
context.cliAdapter.setCurrentInteractiveProcess(void 0);
|
|
438
|
+
}
|
|
439
|
+
if (exitCode !== 0) {
|
|
440
|
+
reject(new Error(`${output || `Command failed with exit code ${exitCode}`}
|
|
281
441
|
|
|
282
442
|
Possible reasons:
|
|
283
443
|
1. The command is invalid or not installed.
|
|
284
444
|
2. The arguments are incorrect.`));
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
445
|
+
} else {
|
|
446
|
+
resolve(output || "Command executed successfully");
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
const wslPty = runWSLCommand(
|
|
450
|
+
distribution,
|
|
451
|
+
command,
|
|
452
|
+
remoteCwd,
|
|
453
|
+
(data) => onDataCallback(data),
|
|
454
|
+
(exitCode) => onExitCallback(exitCode),
|
|
289
455
|
constrainedCols,
|
|
290
456
|
constrainedRows
|
|
291
457
|
);
|
|
@@ -303,6 +469,24 @@ Possible reasons:
|
|
|
303
469
|
isPty: true
|
|
304
470
|
});
|
|
305
471
|
}
|
|
472
|
+
if (timeoutMs > 0) {
|
|
473
|
+
timeoutTimer = setTimeout(() => {
|
|
474
|
+
if (transferred) return;
|
|
475
|
+
transferred = true;
|
|
476
|
+
args.timeoutTransferred = true;
|
|
477
|
+
const adopted = BackgroundTaskManager.adoptRunningProcess(command, remoteCwd, output, `wsl:${distribution}`);
|
|
478
|
+
adopted.setRemotePty({
|
|
479
|
+
write: (data) => wslPty.write(data),
|
|
480
|
+
kill: () => wslPty.kill(),
|
|
481
|
+
resize: (cols, rows) => wslPty.resize(cols, rows),
|
|
482
|
+
isRunning: () => wslPty.isRunning()
|
|
483
|
+
});
|
|
484
|
+
onDataCallback = adopted.onData;
|
|
485
|
+
onExitCallback = adopted.onExit;
|
|
486
|
+
if (context.cliAdapter) context.cliAdapter.setCurrentInteractiveProcess(void 0);
|
|
487
|
+
resolve(buildTransferMessage(adopted.id, command, remoteCwd, timeout_seconds, output, `wsl:${distribution}`));
|
|
488
|
+
}, timeoutMs);
|
|
489
|
+
}
|
|
306
490
|
});
|
|
307
491
|
} else if (currentContext.type === "docker") {
|
|
308
492
|
const parentContext = contextManager.getParentContext();
|
|
@@ -317,33 +501,41 @@ Possible reasons:
|
|
|
317
501
|
}
|
|
318
502
|
const escapedCommand = command.replace(/"/g, '\\"');
|
|
319
503
|
const dockerCommand = `docker exec -w "${remoteCwd}" ${containerId} sh -c "${escapedCommand}"`;
|
|
504
|
+
const remoteLabel = `docker:${containerId.substring(0, 12)} via ssh`;
|
|
320
505
|
return new Promise((resolve, reject) => {
|
|
321
506
|
let output = "";
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
507
|
+
let transferred = false;
|
|
508
|
+
let timeoutTimer = null;
|
|
509
|
+
let onDataCallback = (data) => {
|
|
510
|
+
output += data;
|
|
511
|
+
if (context.onStreamingOutput) {
|
|
512
|
+
context.onStreamingOutput(data, "stdout");
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
let onExitCallback = (exitCode) => {
|
|
516
|
+
if (timeoutTimer) {
|
|
517
|
+
clearTimeout(timeoutTimer);
|
|
518
|
+
timeoutTimer = null;
|
|
519
|
+
}
|
|
520
|
+
if (transferred) return;
|
|
521
|
+
if (context.cliAdapter) context.cliAdapter.setCurrentInteractiveProcess(void 0);
|
|
522
|
+
if (exitCode !== 0) {
|
|
523
|
+
reject(new Error(`${output || `Command failed with exit code ${exitCode}`}
|
|
338
524
|
|
|
339
525
|
Possible reasons:
|
|
340
526
|
1. The command is invalid or not installed in the container.
|
|
341
527
|
2. The arguments are incorrect.
|
|
342
528
|
3. The Docker container may not be running.`));
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
529
|
+
} else {
|
|
530
|
+
resolve(output || "Command executed successfully");
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
const sshPty = runSSHCommand(
|
|
534
|
+
sshClient,
|
|
535
|
+
dockerCommand,
|
|
536
|
+
parentContext.metadata.workingDirectory || "~",
|
|
537
|
+
(data) => onDataCallback(data),
|
|
538
|
+
(exitCode) => onExitCallback(exitCode),
|
|
347
539
|
constrainedCols,
|
|
348
540
|
constrainedRows
|
|
349
541
|
);
|
|
@@ -353,42 +545,66 @@ Possible reasons:
|
|
|
353
545
|
write: (data) => sshPty.write(data),
|
|
354
546
|
kill: () => sshPty.kill(),
|
|
355
547
|
signal: (sig) => {
|
|
356
|
-
if (sig === "SIGINT")
|
|
357
|
-
sshPty.write("");
|
|
358
|
-
}
|
|
548
|
+
if (sig === "SIGINT") sshPty.write("");
|
|
359
549
|
},
|
|
360
550
|
resize: (cols, rows) => sshPty.resize(cols, rows),
|
|
361
551
|
isPty: true
|
|
362
552
|
});
|
|
363
553
|
}
|
|
554
|
+
if (timeoutMs > 0) {
|
|
555
|
+
timeoutTimer = setTimeout(() => {
|
|
556
|
+
if (transferred) return;
|
|
557
|
+
transferred = true;
|
|
558
|
+
args.timeoutTransferred = true;
|
|
559
|
+
const adopted = BackgroundTaskManager.adoptRunningProcess(command, remoteCwd, output, remoteLabel);
|
|
560
|
+
adopted.setRemotePty({
|
|
561
|
+
write: (data) => sshPty.write(data),
|
|
562
|
+
kill: () => sshPty.kill(),
|
|
563
|
+
resize: (cols, rows) => sshPty.resize(cols, rows),
|
|
564
|
+
isRunning: () => sshPty.isRunning()
|
|
565
|
+
});
|
|
566
|
+
onDataCallback = adopted.onData;
|
|
567
|
+
onExitCallback = adopted.onExit;
|
|
568
|
+
if (context.cliAdapter) context.cliAdapter.setCurrentInteractiveProcess(void 0);
|
|
569
|
+
resolve(buildTransferMessage(adopted.id, command, remoteCwd, timeout_seconds, output, remoteLabel));
|
|
570
|
+
}, timeoutMs);
|
|
571
|
+
}
|
|
364
572
|
});
|
|
365
573
|
} else {
|
|
574
|
+
const dockerLabel = `docker:${containerId.substring(0, 12)}`;
|
|
366
575
|
return new Promise((resolve, reject) => {
|
|
367
576
|
let output = "";
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
(
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
577
|
+
let transferred = false;
|
|
578
|
+
let timeoutTimer = null;
|
|
579
|
+
let onDataCallback = (data) => {
|
|
580
|
+
output += data;
|
|
581
|
+
if (context.onStreamingOutput) {
|
|
582
|
+
context.onStreamingOutput(data, "stdout");
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
let onExitCallback = (exitCode) => {
|
|
586
|
+
if (timeoutTimer) {
|
|
587
|
+
clearTimeout(timeoutTimer);
|
|
588
|
+
timeoutTimer = null;
|
|
589
|
+
}
|
|
590
|
+
if (transferred) return;
|
|
591
|
+
if (context.cliAdapter) context.cliAdapter.setCurrentInteractiveProcess(void 0);
|
|
592
|
+
if (exitCode !== 0) {
|
|
593
|
+
reject(new Error(`${output || `Command failed with exit code ${exitCode}`}
|
|
384
594
|
|
|
385
595
|
Possible reasons:
|
|
386
596
|
1. The command is invalid or not installed.
|
|
387
597
|
2. The arguments are incorrect.`));
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
598
|
+
} else {
|
|
599
|
+
resolve(output || "Command executed successfully");
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
const dockerPty = runDockerCommand(
|
|
603
|
+
containerId,
|
|
604
|
+
command,
|
|
605
|
+
remoteCwd,
|
|
606
|
+
(data) => onDataCallback(data),
|
|
607
|
+
(exitCode) => onExitCallback(exitCode),
|
|
392
608
|
constrainedCols,
|
|
393
609
|
constrainedRows
|
|
394
610
|
);
|
|
@@ -398,14 +614,30 @@ Possible reasons:
|
|
|
398
614
|
write: (data) => dockerPty.write(data),
|
|
399
615
|
kill: () => dockerPty.kill(),
|
|
400
616
|
signal: (sig) => {
|
|
401
|
-
if (sig === "SIGINT")
|
|
402
|
-
dockerPty.write("");
|
|
403
|
-
}
|
|
617
|
+
if (sig === "SIGINT") dockerPty.write("");
|
|
404
618
|
},
|
|
405
619
|
resize: (cols, rows) => dockerPty.resize(cols, rows),
|
|
406
620
|
isPty: true
|
|
407
621
|
});
|
|
408
622
|
}
|
|
623
|
+
if (timeoutMs > 0) {
|
|
624
|
+
timeoutTimer = setTimeout(() => {
|
|
625
|
+
if (transferred) return;
|
|
626
|
+
transferred = true;
|
|
627
|
+
args.timeoutTransferred = true;
|
|
628
|
+
const adopted = BackgroundTaskManager.adoptRunningProcess(command, remoteCwd, output, dockerLabel);
|
|
629
|
+
adopted.setRemotePty({
|
|
630
|
+
write: (data) => dockerPty.write(data),
|
|
631
|
+
kill: () => dockerPty.kill(),
|
|
632
|
+
resize: (cols, rows) => dockerPty.resize(cols, rows),
|
|
633
|
+
isRunning: () => dockerPty.isRunning()
|
|
634
|
+
});
|
|
635
|
+
onDataCallback = adopted.onData;
|
|
636
|
+
onExitCallback = adopted.onExit;
|
|
637
|
+
if (context.cliAdapter) context.cliAdapter.setCurrentInteractiveProcess(void 0);
|
|
638
|
+
resolve(buildTransferMessage(adopted.id, command, remoteCwd, timeout_seconds, output, dockerLabel));
|
|
639
|
+
}, timeoutMs);
|
|
640
|
+
}
|
|
409
641
|
});
|
|
410
642
|
}
|
|
411
643
|
} else if (currentContext.type === "ssh") {
|
|
@@ -414,34 +646,42 @@ Possible reasons:
|
|
|
414
646
|
if (!sshClient) {
|
|
415
647
|
throw new Error("SSH client not available");
|
|
416
648
|
}
|
|
649
|
+
const sshLabel = `${currentContext.metadata?.username || "user"}@${currentContext.metadata?.hostname || "remote"}`;
|
|
417
650
|
return new Promise((resolve, reject) => {
|
|
418
651
|
let output = "";
|
|
652
|
+
let transferred = false;
|
|
653
|
+
let timeoutTimer = null;
|
|
419
654
|
const constrainedCols = Math.max(40, (process.stdout.columns || 80) - 4);
|
|
420
655
|
const constrainedRows = Math.min(process.stdout.rows || 24, 50);
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
reject(new Error(`${output || `Command failed with exit code ${exitCode}`}
|
|
656
|
+
let onDataCallback = (data) => {
|
|
657
|
+
output += data;
|
|
658
|
+
if (context.onStreamingOutput) {
|
|
659
|
+
context.onStreamingOutput(data, "stdout");
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
let onExitCallback = (exitCode) => {
|
|
663
|
+
if (timeoutTimer) {
|
|
664
|
+
clearTimeout(timeoutTimer);
|
|
665
|
+
timeoutTimer = null;
|
|
666
|
+
}
|
|
667
|
+
if (transferred) return;
|
|
668
|
+
if (context.cliAdapter) context.cliAdapter.setCurrentInteractiveProcess(void 0);
|
|
669
|
+
if (exitCode !== 0) {
|
|
670
|
+
reject(new Error(`${output || `Command failed with exit code ${exitCode}`}
|
|
437
671
|
|
|
438
672
|
Possible reasons:
|
|
439
673
|
1. The command is invalid or not installed.
|
|
440
674
|
2. The arguments are incorrect.`));
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
675
|
+
} else {
|
|
676
|
+
resolve(output || "Command executed successfully");
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
const sshPty = runSSHCommand(
|
|
680
|
+
sshClient,
|
|
681
|
+
command,
|
|
682
|
+
remoteCwd,
|
|
683
|
+
(data) => onDataCallback(data),
|
|
684
|
+
(exitCode) => onExitCallback(exitCode),
|
|
445
685
|
constrainedCols,
|
|
446
686
|
constrainedRows
|
|
447
687
|
);
|
|
@@ -451,19 +691,37 @@ Possible reasons:
|
|
|
451
691
|
write: (data) => sshPty.write(data),
|
|
452
692
|
kill: () => sshPty.kill(),
|
|
453
693
|
signal: (sig) => {
|
|
454
|
-
if (sig === "SIGINT")
|
|
455
|
-
sshPty.write("");
|
|
456
|
-
}
|
|
694
|
+
if (sig === "SIGINT") sshPty.write("");
|
|
457
695
|
},
|
|
458
696
|
resize: (cols, rows) => sshPty.resize(cols, rows),
|
|
459
697
|
isPty: true
|
|
460
698
|
});
|
|
461
699
|
}
|
|
700
|
+
if (timeoutMs > 0) {
|
|
701
|
+
timeoutTimer = setTimeout(() => {
|
|
702
|
+
if (transferred) return;
|
|
703
|
+
transferred = true;
|
|
704
|
+
args.timeoutTransferred = true;
|
|
705
|
+
const adopted = BackgroundTaskManager.adoptRunningProcess(command, remoteCwd, output, sshLabel);
|
|
706
|
+
adopted.setRemotePty({
|
|
707
|
+
write: (data) => sshPty.write(data),
|
|
708
|
+
kill: () => sshPty.kill(),
|
|
709
|
+
resize: (cols, rows) => sshPty.resize(cols, rows),
|
|
710
|
+
isRunning: () => sshPty.isRunning()
|
|
711
|
+
});
|
|
712
|
+
onDataCallback = adopted.onData;
|
|
713
|
+
onExitCallback = adopted.onExit;
|
|
714
|
+
if (context.cliAdapter) context.cliAdapter.setCurrentInteractiveProcess(void 0);
|
|
715
|
+
resolve(buildTransferMessage(adopted.id, command, remoteCwd, timeout_seconds, output, sshLabel));
|
|
716
|
+
}, timeoutMs);
|
|
717
|
+
}
|
|
462
718
|
});
|
|
463
719
|
}
|
|
464
720
|
}
|
|
465
721
|
};
|
|
466
722
|
export {
|
|
723
|
+
extractCdTargetsFromCommand,
|
|
724
|
+
resolvePostCommandCwd,
|
|
467
725
|
runCommandTool
|
|
468
726
|
};
|
|
469
727
|
//# sourceMappingURL=command.js.map
|