aws-runtime-bridge 1.4.0 → 1.6.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.md +1 -1
- package/dist/adapter/AdapterRegistry.d.ts +1 -1
- package/dist/adapter/AdapterRegistry.d.ts.map +1 -1
- package/dist/adapter/AdapterRegistry.js +0 -2
- package/dist/adapter/ClaudeSdkAdapter.d.ts +4 -0
- package/dist/adapter/ClaudeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/ClaudeSdkAdapter.js +11 -2
- package/dist/adapter/CodexSdkAdapter.js +1 -1
- package/dist/adapter/OpencodeSdkAdapter.d.ts +13 -1
- package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/OpencodeSdkAdapter.js +58 -6
- package/dist/adapter/OpencodeSdkAdapter.test.js +57 -1
- package/dist/adapter/types.d.ts +10 -0
- package/dist/adapter/types.d.ts.map +1 -1
- package/dist/index.js +14 -43
- package/dist/middleware/auth.d.ts +5 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +9 -1
- package/dist/routes/file-browser.d.ts +10 -0
- package/dist/routes/file-browser.d.ts.map +1 -1
- package/dist/routes/file-browser.js +226 -4
- package/dist/routes/file-browser.test.js +31 -0
- package/dist/routes/instance.d.ts +10 -0
- package/dist/routes/instance.d.ts.map +1 -1
- package/dist/routes/instance.js +93 -2
- package/dist/routes/instance.test.js +50 -0
- package/dist/routes/pty.d.ts +106 -0
- package/dist/routes/pty.d.ts.map +1 -0
- package/dist/routes/pty.js +526 -0
- package/dist/routes/pty.test.d.ts +2 -0
- package/dist/routes/pty.test.d.ts.map +1 -0
- package/dist/routes/pty.test.js +73 -0
- package/dist/routes/sessions.d.ts +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +32 -213
- package/dist/routes/terminal.d.ts +32 -3
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +411 -243
- package/dist/routes/terminal.test.js +105 -29
- package/dist/services/agent-process-manager.d.ts +2 -2
- package/dist/services/agent-process-manager.d.ts.map +1 -1
- package/dist/services/agent-process-manager.js +3 -3
- package/dist/services/process-detector.d.ts +2 -4
- package/dist/services/process-detector.d.ts.map +1 -1
- package/dist/services/process-detector.js +9 -16
- package/dist/services/process-registry.d.ts +2 -2
- package/dist/services/process-registry.d.ts.map +1 -1
- package/dist/services/process-registry.js +1 -1
- package/dist/services/session-output.d.ts +27 -5
- package/dist/services/session-output.d.ts.map +1 -1
- package/dist/services/session-output.js +48 -3
- package/dist/services/session-output.test.js +43 -29
- package/dist/services/terminal-persistence.d.ts +9 -0
- package/dist/services/terminal-persistence.d.ts.map +1 -1
- package/dist/services/terminal-persistence.js +20 -0
- package/dist/services/tool-installer.d.ts +10 -0
- package/dist/services/tool-installer.d.ts.map +1 -1
- package/dist/services/tool-installer.js +126 -5
- package/dist/services/tool-installer.test.js +32 -1
- package/dist/services/workspace-files.d.ts +86 -0
- package/dist/services/workspace-files.d.ts.map +1 -1
- package/dist/services/workspace-files.js +571 -21
- package/dist/services/workspace-files.test.js +471 -11
- package/dist/services/workspace-watch.d.ts +21 -0
- package/dist/services/workspace-watch.d.ts.map +1 -0
- package/dist/services/workspace-watch.js +123 -0
- package/dist/services/workspace-watch.test.d.ts +2 -0
- package/dist/services/workspace-watch.test.d.ts.map +1 -0
- package/dist/services/workspace-watch.test.js +38 -0
- package/dist/types.d.ts +8 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -1
|
@@ -28,6 +28,15 @@ export declare function savePersistedSessions(sessions: PersistedSession[]): Pro
|
|
|
28
28
|
* @param session - 会话数据
|
|
29
29
|
*/
|
|
30
30
|
export declare function upsertPersistedSession(session: PersistedSession): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* 更新指定 Agent 的持久化自动命令配置。
|
|
33
|
+
*
|
|
34
|
+
* 主流程:加载 running 会话 -> 命中 agentId 时只替换自动命令字段,保留原 command/workspace/pid。
|
|
35
|
+
*/
|
|
36
|
+
export declare function updatePersistedSessionAutoCommands(agentId: string, commands: {
|
|
37
|
+
idleInputAutoCommand: string;
|
|
38
|
+
nonInputAutoCommand: string;
|
|
39
|
+
}): Promise<boolean>;
|
|
31
40
|
/**
|
|
32
41
|
* 移除持久化会话(从完整文件中删除,包括 stopped 状态的)
|
|
33
42
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal-persistence.d.ts","sourceRoot":"","sources":["../../src/services/terminal-persistence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA6BpD;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAOzE;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvF;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWrF;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB7E;AAED;;;;;GAKG;AACH,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAGvC;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBpF"}
|
|
1
|
+
{"version":3,"file":"terminal-persistence.d.ts","sourceRoot":"","sources":["../../src/services/terminal-persistence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA6BpD;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAOzE;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvF;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWrF;AAED;;;;GAIG;AACH,wBAAsB,kCAAkC,CACtD,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE;IAAE,oBAAoB,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,GACtE,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB7E;AAED;;;;;GAKG;AACH,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAGvC;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBpF"}
|
|
@@ -80,6 +80,26 @@ export async function upsertPersistedSession(session) {
|
|
|
80
80
|
return runningSessions;
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* 更新指定 Agent 的持久化自动命令配置。
|
|
85
|
+
*
|
|
86
|
+
* 主流程:加载 running 会话 -> 命中 agentId 时只替换自动命令字段,保留原 command/workspace/pid。
|
|
87
|
+
*/
|
|
88
|
+
export async function updatePersistedSessionAutoCommands(agentId, commands) {
|
|
89
|
+
let updated = false;
|
|
90
|
+
await updatePersistedSessions((sessions) => sessions.map((session) => {
|
|
91
|
+
if (session.agentId !== agentId) {
|
|
92
|
+
return session;
|
|
93
|
+
}
|
|
94
|
+
updated = true;
|
|
95
|
+
return {
|
|
96
|
+
...session,
|
|
97
|
+
idleInputAutoCommand: commands.idleInputAutoCommand,
|
|
98
|
+
nonInputAutoCommand: commands.nonInputAutoCommand,
|
|
99
|
+
};
|
|
100
|
+
}));
|
|
101
|
+
return updated;
|
|
102
|
+
}
|
|
83
103
|
/**
|
|
84
104
|
* 移除持久化会话(从完整文件中删除,包括 stopped 状态的)
|
|
85
105
|
*
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { ToolInstallStatus } from "../types.js";
|
|
2
2
|
export declare const SUPPORTED_INSTALLABLE_TOOLS: readonly string[];
|
|
3
|
+
export declare const SUPPORTED_UNINSTALLABLE_TOOLS: readonly string[];
|
|
4
|
+
/**
|
|
5
|
+
* 返回工具对应的全局卸载命令副本,用于诊断与测试卸载覆盖范围。
|
|
6
|
+
*/
|
|
7
|
+
export declare function getToolUninstallCommands(tool: string): string[];
|
|
8
|
+
export declare function isVoltaShimPath(commandPath: string): boolean;
|
|
3
9
|
/**
|
|
4
10
|
* 检查单个工具的 CLI 可执行状态,供实例状态展示与初始化前判断使用。
|
|
5
11
|
*/
|
|
@@ -12,4 +18,8 @@ export declare function detectToolStatuses(tools: string[]): Promise<Record<stri
|
|
|
12
18
|
* 根据勾选工具自动安装缺失 CLI,安装后重新检测状态并返回。
|
|
13
19
|
*/
|
|
14
20
|
export declare function ensureToolsInstalled(tools: string[]): Promise<Record<string, ToolInstallStatus>>;
|
|
21
|
+
/**
|
|
22
|
+
* 按工具定义执行全局卸载命令,随后重新检测并返回最新安装状态。
|
|
23
|
+
*/
|
|
24
|
+
export declare function uninstallTools(tools: string[]): Promise<Record<string, ToolInstallStatus>>;
|
|
15
25
|
//# sourceMappingURL=tool-installer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-installer.d.ts","sourceRoot":"","sources":["../../src/services/tool-installer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-installer.d.ts","sourceRoot":"","sources":["../../src/services/tool-installer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA8GrD,eAAO,MAAM,2BAA2B,mBAEvC,CAAC;AAEF,eAAO,MAAM,6BAA6B,mBAIzC,CAAC;AAEF;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAK/D;AAoDD,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAM5D;AAqJD;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,CAAC,CAyB5B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAkB5C;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CA+C5C;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAiD5C"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { access } from "node:fs/promises";
|
|
1
3
|
import os from "node:os";
|
|
2
4
|
import path from "node:path";
|
|
3
|
-
import { access } from "node:fs/promises";
|
|
4
|
-
import { execFile } from "node:child_process";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
const execFileAsync = promisify(execFile);
|
|
7
7
|
const isWindows = process.platform === "win32";
|
|
8
8
|
const TOOL_DEFINITIONS = {
|
|
9
9
|
claude: {
|
|
10
10
|
key: "claude",
|
|
11
|
+
packageName: "@anthropic-ai/claude-code",
|
|
11
12
|
aliases: isWindows ? ["claude.cmd", "claude.exe", "claude"] : ["claude"],
|
|
12
13
|
versionArgs: ["--version"],
|
|
13
14
|
installCommands: isWindows
|
|
@@ -16,9 +17,20 @@ const TOOL_DEFINITIONS = {
|
|
|
16
17
|
"curl -fsSL https://claude.ai/install.sh | bash",
|
|
17
18
|
"npm install -g @anthropic-ai/claude-code@latest",
|
|
18
19
|
],
|
|
20
|
+
uninstallCommands: isWindows
|
|
21
|
+
? [
|
|
22
|
+
"npm uninstall -g @anthropic-ai/claude-code",
|
|
23
|
+
"volta uninstall @anthropic-ai/claude-code",
|
|
24
|
+
]
|
|
25
|
+
: [
|
|
26
|
+
"npm uninstall -g @anthropic-ai/claude-code",
|
|
27
|
+
"volta uninstall @anthropic-ai/claude-code",
|
|
28
|
+
"rm -f ~/.local/bin/claude",
|
|
29
|
+
],
|
|
19
30
|
},
|
|
20
31
|
claudecode: {
|
|
21
32
|
key: "claudecode",
|
|
33
|
+
packageName: "@anthropic-ai/claude-code",
|
|
22
34
|
aliases: isWindows ? ["claude.cmd", "claude.exe", "claude"] : ["claude"],
|
|
23
35
|
versionArgs: ["--version"],
|
|
24
36
|
installCommands: isWindows
|
|
@@ -27,9 +39,20 @@ const TOOL_DEFINITIONS = {
|
|
|
27
39
|
"curl -fsSL https://claude.ai/install.sh | bash",
|
|
28
40
|
"npm install -g @anthropic-ai/claude-code@latest",
|
|
29
41
|
],
|
|
42
|
+
uninstallCommands: isWindows
|
|
43
|
+
? [
|
|
44
|
+
"npm uninstall -g @anthropic-ai/claude-code",
|
|
45
|
+
"volta uninstall @anthropic-ai/claude-code",
|
|
46
|
+
]
|
|
47
|
+
: [
|
|
48
|
+
"npm uninstall -g @anthropic-ai/claude-code",
|
|
49
|
+
"volta uninstall @anthropic-ai/claude-code",
|
|
50
|
+
"rm -f ~/.local/bin/claude",
|
|
51
|
+
],
|
|
30
52
|
},
|
|
31
53
|
opencode: {
|
|
32
54
|
key: "opencode",
|
|
55
|
+
packageName: "opencode-ai",
|
|
33
56
|
aliases: isWindows
|
|
34
57
|
? ["opencode.cmd", "opencode.exe", "opencode"]
|
|
35
58
|
: ["opencode"],
|
|
@@ -40,6 +63,18 @@ const TOOL_DEFINITIONS = {
|
|
|
40
63
|
"curl -fsSL https://opencode.ai/install | bash",
|
|
41
64
|
"npm install -g opencode-ai@latest",
|
|
42
65
|
],
|
|
66
|
+
uninstallCommands: isWindows
|
|
67
|
+
? [
|
|
68
|
+
"opencode uninstall --force",
|
|
69
|
+
"npm uninstall -g opencode-ai",
|
|
70
|
+
"volta uninstall opencode-ai",
|
|
71
|
+
]
|
|
72
|
+
: [
|
|
73
|
+
"opencode uninstall --force",
|
|
74
|
+
"npm uninstall -g opencode-ai",
|
|
75
|
+
"volta uninstall opencode-ai",
|
|
76
|
+
"rm -f ~/.opencode/bin/opencode",
|
|
77
|
+
],
|
|
43
78
|
extraSearchPaths: () => {
|
|
44
79
|
const home = os.homedir();
|
|
45
80
|
return [
|
|
@@ -53,12 +88,27 @@ const TOOL_DEFINITIONS = {
|
|
|
53
88
|
},
|
|
54
89
|
codex: {
|
|
55
90
|
key: "codex",
|
|
91
|
+
packageName: "@openai/codex",
|
|
56
92
|
aliases: isWindows ? ["codex.cmd", "codex.exe", "codex"] : ["codex"],
|
|
57
93
|
versionArgs: ["--version"],
|
|
58
94
|
installCommands: ["npm install -g @openai/codex@latest"],
|
|
95
|
+
uninstallCommands: [
|
|
96
|
+
"npm uninstall -g @openai/codex",
|
|
97
|
+
"volta uninstall @openai/codex",
|
|
98
|
+
],
|
|
59
99
|
},
|
|
60
100
|
};
|
|
61
101
|
export const SUPPORTED_INSTALLABLE_TOOLS = Object.freeze(Object.keys(TOOL_DEFINITIONS));
|
|
102
|
+
export const SUPPORTED_UNINSTALLABLE_TOOLS = Object.freeze(Object.keys(TOOL_DEFINITIONS).filter((tool) => TOOL_DEFINITIONS[tool].uninstallCommands.length > 0));
|
|
103
|
+
/**
|
|
104
|
+
* 返回工具对应的全局卸载命令副本,用于诊断与测试卸载覆盖范围。
|
|
105
|
+
*/
|
|
106
|
+
export function getToolUninstallCommands(tool) {
|
|
107
|
+
const normalizedTool = String(tool || "")
|
|
108
|
+
.trim()
|
|
109
|
+
.toLowerCase();
|
|
110
|
+
return [...(TOOL_DEFINITIONS[normalizedTool]?.uninstallCommands || [])];
|
|
111
|
+
}
|
|
62
112
|
function parseVersion(output) {
|
|
63
113
|
const normalized = String(output || "").trim();
|
|
64
114
|
if (!normalized) {
|
|
@@ -103,6 +153,26 @@ function describeExecError(error) {
|
|
|
103
153
|
}
|
|
104
154
|
return message || "command execution failed";
|
|
105
155
|
}
|
|
156
|
+
export function isVoltaShimPath(commandPath) {
|
|
157
|
+
const normalizedPath = path
|
|
158
|
+
.normalize(commandPath)
|
|
159
|
+
.replaceAll("\\", "/")
|
|
160
|
+
.toLowerCase();
|
|
161
|
+
return /(?:^|\/)\.?volta\/bin\//.test(normalizedPath);
|
|
162
|
+
}
|
|
163
|
+
async function isVoltaPackageInstalled(packageName) {
|
|
164
|
+
try {
|
|
165
|
+
const { stdout, stderr } = await execFileAsync("volta", ["list", "--format", "plain"], {
|
|
166
|
+
timeout: 20_000,
|
|
167
|
+
});
|
|
168
|
+
const output = `${stdout || ""}\n${stderr || ""}`;
|
|
169
|
+
const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
170
|
+
return new RegExp(`^package\\s+${escapedPackageName}(?:@|\\s)`, "im").test(output);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
106
176
|
/**
|
|
107
177
|
* 在 Windows 上执行命令(处理 .cmd/.bat 文件)
|
|
108
178
|
* 在 Unix 系统上直接执行
|
|
@@ -151,7 +221,7 @@ async function resolveExecutableCandidate(definition) {
|
|
|
151
221
|
}
|
|
152
222
|
catch (error) {
|
|
153
223
|
executionFailureMessage = describeExecError(error);
|
|
154
|
-
if (executionFailureMessage !== "command not found in PATH") {
|
|
224
|
+
if (!isWindows && executionFailureMessage !== "command not found in PATH") {
|
|
155
225
|
return {
|
|
156
226
|
executable: alias,
|
|
157
227
|
version: null,
|
|
@@ -164,6 +234,11 @@ async function resolveExecutableCandidate(definition) {
|
|
|
164
234
|
try {
|
|
165
235
|
await access(absolutePath);
|
|
166
236
|
foundCommandPath = absolutePath;
|
|
237
|
+
if (isVoltaShimPath(absolutePath) &&
|
|
238
|
+
!(await isVoltaPackageInstalled(definition.packageName))) {
|
|
239
|
+
foundCommandPath = null;
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
167
242
|
const { stdout, stderr } = await executeVersionCommand(absolutePath, definition.versionArgs);
|
|
168
243
|
const version = parseVersion(`${stdout || ""}\n${stderr || ""}`);
|
|
169
244
|
if (!version) {
|
|
@@ -196,7 +271,7 @@ async function resolveExecutableCandidate(definition) {
|
|
|
196
271
|
}
|
|
197
272
|
return { executable: null, version: null, error: "command not installed" };
|
|
198
273
|
}
|
|
199
|
-
async function
|
|
274
|
+
async function runToolCommand(command) {
|
|
200
275
|
if (isWindows) {
|
|
201
276
|
await execFileAsync("cmd.exe", ["/d", "/s", "/c", command], {
|
|
202
277
|
timeout: 10 * 60 * 1000,
|
|
@@ -267,7 +342,7 @@ export async function ensureToolsInstalled(tools) {
|
|
|
267
342
|
let lastError = current.error;
|
|
268
343
|
for (const command of definition.installCommands) {
|
|
269
344
|
try {
|
|
270
|
-
await
|
|
345
|
+
await runToolCommand(command);
|
|
271
346
|
const detected = await detectToolInstallStatus(tool);
|
|
272
347
|
nextStatuses[tool] = detected;
|
|
273
348
|
if (detected.installed) {
|
|
@@ -295,3 +370,49 @@ export async function ensureToolsInstalled(tools) {
|
|
|
295
370
|
}
|
|
296
371
|
return nextStatuses;
|
|
297
372
|
}
|
|
373
|
+
/**
|
|
374
|
+
* 按工具定义执行全局卸载命令,随后重新检测并返回最新安装状态。
|
|
375
|
+
*/
|
|
376
|
+
export async function uninstallTools(tools) {
|
|
377
|
+
const normalizedTools = [
|
|
378
|
+
...new Set((Array.isArray(tools) ? tools : [])
|
|
379
|
+
.map((item) => String(item || "")
|
|
380
|
+
.trim()
|
|
381
|
+
.toLowerCase())
|
|
382
|
+
.filter(Boolean)),
|
|
383
|
+
];
|
|
384
|
+
const nextStatuses = {};
|
|
385
|
+
for (const tool of normalizedTools) {
|
|
386
|
+
const definition = TOOL_DEFINITIONS[tool];
|
|
387
|
+
if (!definition) {
|
|
388
|
+
nextStatuses[tool] = await detectToolInstallStatus(tool);
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
let lastError = null;
|
|
392
|
+
for (const command of definition.uninstallCommands) {
|
|
393
|
+
try {
|
|
394
|
+
await runToolCommand(command);
|
|
395
|
+
lastError = null;
|
|
396
|
+
const detectedAfterCommand = await detectToolInstallStatus(tool);
|
|
397
|
+
if (!detectedAfterCommand.installed) {
|
|
398
|
+
nextStatuses[tool] = detectedAfterCommand;
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
lastError =
|
|
404
|
+
error instanceof Error
|
|
405
|
+
? error.message
|
|
406
|
+
: String(error || "uninstall failed");
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
const detected = await detectToolInstallStatus(tool);
|
|
410
|
+
nextStatuses[tool] = {
|
|
411
|
+
...detected,
|
|
412
|
+
error: detected.installed
|
|
413
|
+
? lastError || detected.error || "uninstall completed but command is still available"
|
|
414
|
+
: detected.error,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
return nextStatuses;
|
|
418
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { detectToolStatuses,
|
|
2
|
+
import { detectToolInstallStatus, SUPPORTED_INSTALLABLE_TOOLS, SUPPORTED_UNINSTALLABLE_TOOLS, detectToolStatuses, getToolUninstallCommands, isVoltaShimPath } from './tool-installer.js';
|
|
3
3
|
describe('tool installer service', () => {
|
|
4
4
|
it('returns structured status for supported tools', async () => {
|
|
5
5
|
const statuses = await detectToolStatuses(['claude', 'opencode', 'codex']);
|
|
@@ -76,6 +76,37 @@ describe('tool installer service', () => {
|
|
|
76
76
|
expect(typeof status.installed).toBe('boolean');
|
|
77
77
|
expect(status.error).not.toBe('unsupported tool');
|
|
78
78
|
});
|
|
79
|
+
it('supports all panel tools as uninstallable tools', () => {
|
|
80
|
+
expect(SUPPORTED_UNINSTALLABLE_TOOLS).toEqual(expect.arrayContaining(['claude', 'opencode', 'codex']));
|
|
81
|
+
});
|
|
82
|
+
it('covers npm and native installer uninstall paths for OpenCode', () => {
|
|
83
|
+
const commands = getToolUninstallCommands('opencode');
|
|
84
|
+
expect(commands).toContain('npm uninstall -g opencode-ai');
|
|
85
|
+
expect(commands).toContain('volta uninstall opencode-ai');
|
|
86
|
+
if (process.platform !== 'win32') {
|
|
87
|
+
expect(commands).toContain('opencode uninstall --force');
|
|
88
|
+
expect(commands).toContain('rm -f ~/.opencode/bin/opencode');
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
it('covers npm and native installer uninstall paths for Claude Code on Unix', () => {
|
|
92
|
+
const commands = getToolUninstallCommands('claude');
|
|
93
|
+
expect(commands).toContain('npm uninstall -g @anthropic-ai/claude-code');
|
|
94
|
+
expect(commands).toContain('volta uninstall @anthropic-ai/claude-code');
|
|
95
|
+
if (process.platform !== 'win32') {
|
|
96
|
+
expect(commands).toContain('rm -f ~/.local/bin/claude');
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
it('covers Volta package uninstall for Codex', () => {
|
|
100
|
+
const commands = getToolUninstallCommands('codex');
|
|
101
|
+
expect(commands).toContain('npm uninstall -g @openai/codex');
|
|
102
|
+
expect(commands).toContain('volta uninstall @openai/codex');
|
|
103
|
+
});
|
|
104
|
+
it('recognizes Volta shim paths for package-manager-aware detection', () => {
|
|
105
|
+
expect(isVoltaShimPath('C:\\Users\\tester\\AppData\\Local\\Volta\\bin\\codex.cmd')).toBe(true);
|
|
106
|
+
expect(isVoltaShimPath('/home/tester/.volta/bin/codex')).toBe(true);
|
|
107
|
+
expect(isVoltaShimPath('/Users/tester/.volta/bin/claude')).toBe(true);
|
|
108
|
+
expect(isVoltaShimPath('/usr/local/bin/codex')).toBe(false);
|
|
109
|
+
});
|
|
79
110
|
it('detectToolStatuses returns status for all requested tools', async () => {
|
|
80
111
|
const tools = ['claude', 'opencode', 'unknown-tool'];
|
|
81
112
|
const statuses = await detectToolStatuses(tools);
|
|
@@ -6,6 +6,7 @@ export interface WorkspaceFileItem {
|
|
|
6
6
|
name: string;
|
|
7
7
|
path: string;
|
|
8
8
|
isDirectory: boolean;
|
|
9
|
+
size?: number;
|
|
9
10
|
}
|
|
10
11
|
export interface ListWorkspaceDirectoryResult {
|
|
11
12
|
currentPath: string;
|
|
@@ -17,6 +18,36 @@ export interface ReadWorkspaceFileResult {
|
|
|
17
18
|
filePath: string;
|
|
18
19
|
content: string;
|
|
19
20
|
}
|
|
21
|
+
export interface WorkspaceDocumentPreviewResult {
|
|
22
|
+
workspacePath: string;
|
|
23
|
+
filePath: string;
|
|
24
|
+
kind: 'html' | 'unsupported';
|
|
25
|
+
content: string;
|
|
26
|
+
message?: string;
|
|
27
|
+
size: number;
|
|
28
|
+
mtimeMs: number;
|
|
29
|
+
}
|
|
30
|
+
export interface WorkspaceDownloadTarget {
|
|
31
|
+
workspacePath: string;
|
|
32
|
+
targetPath: string;
|
|
33
|
+
resolvedTargetPath: string;
|
|
34
|
+
fileName: string;
|
|
35
|
+
contentType: string;
|
|
36
|
+
isDirectory: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface WorkspaceUploadFile {
|
|
39
|
+
originalname: string;
|
|
40
|
+
relativePath?: string;
|
|
41
|
+
path: string;
|
|
42
|
+
size: number;
|
|
43
|
+
}
|
|
44
|
+
export interface WorkspaceArchiveExtractResult {
|
|
45
|
+
ok: true;
|
|
46
|
+
workspacePath: string;
|
|
47
|
+
archivePath: string;
|
|
48
|
+
targetPath: string;
|
|
49
|
+
extractedEntries: number;
|
|
50
|
+
}
|
|
20
51
|
interface WorkspacePathParams {
|
|
21
52
|
workspacePath: string;
|
|
22
53
|
targetPath?: string;
|
|
@@ -36,9 +67,24 @@ interface RenameWorkspaceEntryParams extends WorkspacePathParams {
|
|
|
36
67
|
targetPath: string;
|
|
37
68
|
newName: string;
|
|
38
69
|
}
|
|
70
|
+
interface MoveWorkspaceEntryParams extends WorkspacePathParams {
|
|
71
|
+
targetPath: string;
|
|
72
|
+
destinationPath: string;
|
|
73
|
+
}
|
|
39
74
|
interface DeleteWorkspaceEntryParams extends WorkspacePathParams {
|
|
40
75
|
targetPath: string;
|
|
41
76
|
}
|
|
77
|
+
interface UploadWorkspaceFilesParams extends WorkspacePathParams {
|
|
78
|
+
files: WorkspaceUploadFile[];
|
|
79
|
+
extractArchives?: boolean;
|
|
80
|
+
}
|
|
81
|
+
interface DownloadWorkspaceEntryParams extends WorkspacePathParams {
|
|
82
|
+
targetPath: string;
|
|
83
|
+
}
|
|
84
|
+
interface ExtractWorkspaceArchiveParams extends WorkspacePathParams {
|
|
85
|
+
archivePath: string;
|
|
86
|
+
outputPath?: string;
|
|
87
|
+
}
|
|
42
88
|
/**
|
|
43
89
|
* 列出工作区目录内容。
|
|
44
90
|
*/
|
|
@@ -47,6 +93,10 @@ export declare function listWorkspaceDirectory(params: WorkspacePathParams): Pro
|
|
|
47
93
|
* 读取工作区中的文本文件。
|
|
48
94
|
*/
|
|
49
95
|
export declare function readWorkspaceFile(params: WorkspaceFileParams): Promise<ReadWorkspaceFileResult>;
|
|
96
|
+
/**
|
|
97
|
+
* 返回工作区内 Word 文档的预览元数据;docx 由前端下载原文件后渲染,旧版 doc 明确提示不支持。
|
|
98
|
+
*/
|
|
99
|
+
export declare function previewWorkspaceDocument(params: WorkspaceFileParams): Promise<WorkspaceDocumentPreviewResult>;
|
|
50
100
|
/**
|
|
51
101
|
* 将文本内容保存到工作区文件中。
|
|
52
102
|
*/
|
|
@@ -73,6 +123,16 @@ export declare function renameWorkspaceEntry(params: RenameWorkspaceEntryParams)
|
|
|
73
123
|
sourcePath: string;
|
|
74
124
|
targetPath: string;
|
|
75
125
|
}>;
|
|
126
|
+
/**
|
|
127
|
+
* 将工作区内文件或目录移动到另一个工作区目录,保持原文件名不变。
|
|
128
|
+
*/
|
|
129
|
+
export declare function moveWorkspaceEntry(params: MoveWorkspaceEntryParams): Promise<{
|
|
130
|
+
ok: true;
|
|
131
|
+
workspacePath: string;
|
|
132
|
+
sourcePath: string;
|
|
133
|
+
targetPath: string;
|
|
134
|
+
destinationPath: string;
|
|
135
|
+
}>;
|
|
76
136
|
/**
|
|
77
137
|
* 删除工作区内的文件或目录,并阻止误删工作区根目录。
|
|
78
138
|
*/
|
|
@@ -81,5 +141,31 @@ export declare function deleteWorkspaceEntry(params: DeleteWorkspaceEntryParams)
|
|
|
81
141
|
workspacePath: string;
|
|
82
142
|
targetPath: string;
|
|
83
143
|
}>;
|
|
144
|
+
/**
|
|
145
|
+
* 上传文件到工作区指定目录,并可在上传后自动解压常见归档。
|
|
146
|
+
*/
|
|
147
|
+
export declare function uploadWorkspaceFiles(params: UploadWorkspaceFilesParams): Promise<{
|
|
148
|
+
ok: true;
|
|
149
|
+
workspacePath: string;
|
|
150
|
+
targetPath: string;
|
|
151
|
+
files: Array<{
|
|
152
|
+
fileName: string;
|
|
153
|
+
targetPath: string;
|
|
154
|
+
size: number;
|
|
155
|
+
extracted?: WorkspaceArchiveExtractResult;
|
|
156
|
+
}>;
|
|
157
|
+
}>;
|
|
158
|
+
/**
|
|
159
|
+
* 解析工作区下载目标;目录由路由层打包为 zip,文件直接流式下载。
|
|
160
|
+
*/
|
|
161
|
+
export declare function resolveWorkspaceDownloadTarget(params: DownloadWorkspaceEntryParams): Promise<WorkspaceDownloadTarget>;
|
|
162
|
+
/**
|
|
163
|
+
* 将目录内容以 zip 格式写入输出流,避免在磁盘生成临时包。
|
|
164
|
+
*/
|
|
165
|
+
export declare function streamWorkspaceDirectoryZip(directoryPath: string, output: NodeJS.WritableStream): Promise<void>;
|
|
166
|
+
/**
|
|
167
|
+
* 解压工作区中的归档文件到指定目录,支持 zip、tar、tar.gz/tgz 与单文件 gz。
|
|
168
|
+
*/
|
|
169
|
+
export declare function extractWorkspaceArchive(params: ExtractWorkspaceArchiveParams): Promise<WorkspaceArchiveExtractResult>;
|
|
84
170
|
export {};
|
|
85
171
|
//# sourceMappingURL=workspace-files.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-files.d.ts","sourceRoot":"","sources":["../../src/services/workspace-files.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"workspace-files.d.ts","sourceRoot":"","sources":["../../src/services/workspace-files.ts"],"names":[],"mappings":"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"}
|