aws-runtime-bridge 1.5.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.js +2 -2
- 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.map +1 -1
- package/dist/routes/file-browser.js +21 -1
- package/dist/routes/file-browser.test.js +9 -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 +15 -5
- package/dist/services/session-output.d.ts.map +1 -1
- package/dist/services/session-output.js +33 -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 +14 -0
- package/dist/services/workspace-files.d.ts.map +1 -1
- package/dist/services/workspace-files.js +52 -0
- package/dist/services/workspace-files.test.js +85 -1
- package/dist/types.d.ts +8 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
|
@@ -55,6 +55,14 @@ describe('instance route validation', () => {
|
|
|
55
55
|
expect(validateStateRequest({}).valid).toBe(false);
|
|
56
56
|
expect(validateStateRequest({ agentId: 'agent-1' }).valid).toBe(true);
|
|
57
57
|
});
|
|
58
|
+
it('always detects panel tool statuses even when legacy enabled tools omit codex', async () => {
|
|
59
|
+
const { buildToolStatusDetectionTargets } = await import('./instance.js');
|
|
60
|
+
expect(buildToolStatusDetectionTargets(['claude', 'opencode'])).toEqual([
|
|
61
|
+
'claude',
|
|
62
|
+
'opencode',
|
|
63
|
+
'codex',
|
|
64
|
+
]);
|
|
65
|
+
});
|
|
58
66
|
it('accepts codex for cc-switch tool installation validation', async () => {
|
|
59
67
|
const { SUPPORTED_INSTALLABLE_TOOLS } = await import('../services/tool-installer.js');
|
|
60
68
|
const normalizeInstallableTools = (tools) => {
|
|
@@ -67,6 +75,48 @@ describe('instance route validation', () => {
|
|
|
67
75
|
expect(normalizeInstallableTools(['Codex'])).toEqual(['codex']);
|
|
68
76
|
expect(SUPPORTED_INSTALLABLE_TOOLS).toContain('codex');
|
|
69
77
|
});
|
|
78
|
+
it('accepts panel tools for cc-switch tool uninstallation validation', async () => {
|
|
79
|
+
const { SUPPORTED_UNINSTALLABLE_TOOLS } = await import('../services/tool-installer.js');
|
|
80
|
+
const normalizeUninstallableTools = (tools) => {
|
|
81
|
+
const supported = new Set(SUPPORTED_UNINSTALLABLE_TOOLS);
|
|
82
|
+
const requestedTools = Array.isArray(tools)
|
|
83
|
+
? tools.map((tool) => String(tool || '').trim().toLowerCase()).filter(Boolean)
|
|
84
|
+
: [];
|
|
85
|
+
return requestedTools.filter((tool) => supported.has(tool));
|
|
86
|
+
};
|
|
87
|
+
expect(normalizeUninstallableTools(['Claude', 'OpenCode', 'Codex'])).toEqual([
|
|
88
|
+
'claude',
|
|
89
|
+
'opencode',
|
|
90
|
+
'codex',
|
|
91
|
+
]);
|
|
92
|
+
expect(normalizeUninstallableTools(['unknown-tool'])).toEqual([]);
|
|
93
|
+
});
|
|
94
|
+
it('reports uninstall failure when a requested tool remains installed', async () => {
|
|
95
|
+
const { buildUninstallFailureMessage } = await import('./instance.js');
|
|
96
|
+
expect(buildUninstallFailureMessage(['opencode'], {
|
|
97
|
+
opencode: {
|
|
98
|
+
tool: 'opencode',
|
|
99
|
+
installed: true,
|
|
100
|
+
executable: '/home/user/.opencode/bin/opencode',
|
|
101
|
+
version: '1.14.39',
|
|
102
|
+
installing: false,
|
|
103
|
+
error: 'uninstall completed but command is still available',
|
|
104
|
+
},
|
|
105
|
+
})).toContain('opencode: uninstall completed but command is still available');
|
|
106
|
+
});
|
|
107
|
+
it('does not report uninstall failure when requested tools are no longer installed', async () => {
|
|
108
|
+
const { buildUninstallFailureMessage } = await import('./instance.js');
|
|
109
|
+
expect(buildUninstallFailureMessage(['claude'], {
|
|
110
|
+
claude: {
|
|
111
|
+
tool: 'claude',
|
|
112
|
+
installed: false,
|
|
113
|
+
executable: null,
|
|
114
|
+
version: null,
|
|
115
|
+
installing: false,
|
|
116
|
+
error: 'command not installed',
|
|
117
|
+
},
|
|
118
|
+
})).toBe('');
|
|
119
|
+
});
|
|
70
120
|
it('allows connection check when no connection key is configured', async () => {
|
|
71
121
|
const { getConfiguredConnectionKeys } = await import('../services/auto-register.js');
|
|
72
122
|
vi.mocked(getConfiguredConnectionKeys).mockReturnValue([]);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { IncomingMessage } from "node:http";
|
|
2
|
+
import type { Socket } from "node:net";
|
|
3
|
+
import type { Router } from "express";
|
|
4
|
+
import * as pty from "node-pty";
|
|
5
|
+
import WebSocket from "ws";
|
|
6
|
+
export type PtySessionStatus = "running" | "exited";
|
|
7
|
+
export interface PtySessionSummary {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
workspacePath: string;
|
|
11
|
+
shell: string;
|
|
12
|
+
cols: number;
|
|
13
|
+
rows: number;
|
|
14
|
+
status: PtySessionStatus;
|
|
15
|
+
createdAt: string;
|
|
16
|
+
lastActiveAt: string;
|
|
17
|
+
exitCode?: number;
|
|
18
|
+
signal?: number;
|
|
19
|
+
attachedClients: number;
|
|
20
|
+
ownerUserId?: string;
|
|
21
|
+
tenantId?: string;
|
|
22
|
+
projectName?: string;
|
|
23
|
+
}
|
|
24
|
+
interface PtySessionEntry extends PtySessionSummary {
|
|
25
|
+
ptyProcess: pty.IPty;
|
|
26
|
+
sockets: Set<WebSocket>;
|
|
27
|
+
outputBuffer: string;
|
|
28
|
+
idleTimer: NodeJS.Timeout | null;
|
|
29
|
+
persistent: boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare const ptySessions: Map<string, PtySessionEntry>;
|
|
32
|
+
/**
|
|
33
|
+
* 解析 PTY 空闲清理时间。
|
|
34
|
+
* 主流程:读取环境变量 -> 非法值回退默认值 -> 用于 WebSocket 全断开后的延迟清理。
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolvePtyIdleTtlMs(env?: NodeJS.ProcessEnv): number;
|
|
37
|
+
/**
|
|
38
|
+
* 选择默认 shell。
|
|
39
|
+
* 主流程:Windows 优先 pwsh/powershell/cmd;Unix 优先 SHELL/bash/sh,返回可执行文件名与参数。
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveDefaultShell(platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): {
|
|
42
|
+
shell: string;
|
|
43
|
+
args: string[];
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* 校验并解析 shell 选择。
|
|
47
|
+
* 主流程:auto 使用默认 shell;显式 shell 必须命中 allowlist,避免前端任意执行二进制。
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveRequestedShell(requestedShell: unknown, platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): {
|
|
50
|
+
shell: string;
|
|
51
|
+
args: string[];
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* 判断候选路径是否位于允许根目录中。
|
|
55
|
+
* 具体逻辑:使用 path.relative 处理 Windows/Unix 分隔符,拒绝向上穿越和跨盘路径。
|
|
56
|
+
*/
|
|
57
|
+
export declare function isPathInsideRoot(candidatePath: string, rootPath: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* 解析并校验 PTY 工作目录。
|
|
60
|
+
* 主流程:要求绝对目录存在;如果配置 AWS_PTY_ALLOWED_ROOTS,则必须位于允许根目录内。
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolvePtyWorkspacePath(workspacePath: unknown, env?: NodeJS.ProcessEnv): string;
|
|
63
|
+
/**
|
|
64
|
+
* 创建 PTY session。
|
|
65
|
+
* 主流程:校验 cwd/shell -> spawn 真实 PTY -> 注册 output/exit 事件 -> 返回元数据给控制面。
|
|
66
|
+
*/
|
|
67
|
+
export declare function createPtySession(input: {
|
|
68
|
+
workspacePath: unknown;
|
|
69
|
+
title?: unknown;
|
|
70
|
+
shell?: unknown;
|
|
71
|
+
cols?: unknown;
|
|
72
|
+
rows?: unknown;
|
|
73
|
+
persistent?: unknown;
|
|
74
|
+
preCommand?: unknown;
|
|
75
|
+
ownerUserId?: unknown;
|
|
76
|
+
tenantId?: unknown;
|
|
77
|
+
projectName?: unknown;
|
|
78
|
+
}): PtySessionSummary;
|
|
79
|
+
export declare function resolvePtyExitedTtlMs(env?: NodeJS.ProcessEnv): number;
|
|
80
|
+
export declare function resolveMaxPtySessions(env?: NodeJS.ProcessEnv): number;
|
|
81
|
+
export declare function listPtySessions(): PtySessionSummary[];
|
|
82
|
+
export declare function getPtySessionSummary(id: string): PtySessionSummary | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* 生成短期 PTY 连接令牌。
|
|
85
|
+
* 主流程:确认 session 存在 -> 生成随机 token -> 记录 session 绑定和过期时间。
|
|
86
|
+
*/
|
|
87
|
+
export declare function createPtyConnectToken(sessionId: string): {
|
|
88
|
+
token: string;
|
|
89
|
+
expiresAt: string;
|
|
90
|
+
} | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* 关闭 PTY session。
|
|
93
|
+
* 主流程:关闭连接 -> kill PTY -> 清理定时器和内存索引。
|
|
94
|
+
*/
|
|
95
|
+
export declare function closePtySession(id: string, reason?: string): boolean;
|
|
96
|
+
export declare function closeAllPtySessions(reason?: string): void;
|
|
97
|
+
export declare const ptyRouter: Router;
|
|
98
|
+
/**
|
|
99
|
+
* 将 PTY WebSocket upgrade 挂到 HTTP server。
|
|
100
|
+
* 主流程:匹配 /pty/sessions/:id/stream -> token 校验 -> session 校验 -> 交给 noServer WSS。
|
|
101
|
+
*/
|
|
102
|
+
export declare function attachPtyWebSocketServer(server: {
|
|
103
|
+
on: (event: "upgrade", listener: (request: IncomingMessage, socket: Socket, head: Buffer) => void) => unknown;
|
|
104
|
+
}): void;
|
|
105
|
+
export {};
|
|
106
|
+
//# sourceMappingURL=pty.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pty.d.ts","sourceRoot":"","sources":["../../src/routes/pty.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,OAAO,SAA8B,MAAM,IAAI,CAAC;AAehD,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,eAAgB,SAAQ,iBAAiB;IACjD,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC;IACrB,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IACjC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,WAAW,8BAAqC,CAAC;AAG9D;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAUhF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAQnC;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,OAAO,EACvB,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAuBnC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGjF;AAUD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,OAAO,EACtB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAoBR;AA2ED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,iBAAiB,CAuEpB;AAgCD,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAUlF;AAED,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAUlF;AAgCD,wBAAgB,eAAe,IAAI,iBAAiB,EAAE,CAErD;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAG9E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQzG;AA0BD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG,OAAO,CAkBtE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,SAAa,GAAG,IAAI,CAI7D;AAED,eAAO,MAAM,SAAS,EAAE,MAAuB,CAAC;AA2HhD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAAE,EAAE,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,KAAK,OAAO,CAAA;CAAE,GAAG,IAAI,CA8BxK"}
|