@caoruhua/open-claude-remote 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +449 -0
  3. package/dist/api/auth-routes.d.ts +4 -0
  4. package/dist/api/auth-routes.d.ts.map +1 -0
  5. package/dist/api/auth-routes.js +7 -0
  6. package/dist/api/auth-routes.js.map +1 -0
  7. package/dist/api/config-routes.d.ts +4 -0
  8. package/dist/api/config-routes.d.ts.map +1 -0
  9. package/dist/api/config-routes.js +180 -0
  10. package/dist/api/config-routes.js.map +1 -0
  11. package/dist/api/health-routes.d.ts +3 -0
  12. package/dist/api/health-routes.d.ts.map +1 -0
  13. package/dist/api/health-routes.js +9 -0
  14. package/dist/api/health-routes.js.map +1 -0
  15. package/dist/api/hook-routes.d.ts +4 -0
  16. package/dist/api/hook-routes.d.ts.map +1 -0
  17. package/dist/api/hook-routes.js +32 -0
  18. package/dist/api/hook-routes.js.map +1 -0
  19. package/dist/api/instance-routes.d.ts +20 -0
  20. package/dist/api/instance-routes.d.ts.map +1 -0
  21. package/dist/api/instance-routes.js +128 -0
  22. package/dist/api/instance-routes.js.map +1 -0
  23. package/dist/api/push-routes.d.ts +5 -0
  24. package/dist/api/push-routes.d.ts.map +1 -0
  25. package/dist/api/push-routes.js +45 -0
  26. package/dist/api/push-routes.js.map +1 -0
  27. package/dist/api/router.d.ts +19 -0
  28. package/dist/api/router.d.ts.map +1 -0
  29. package/dist/api/router.js +37 -0
  30. package/dist/api/router.js.map +1 -0
  31. package/dist/api/status-routes.d.ts +5 -0
  32. package/dist/api/status-routes.d.ts.map +1 -0
  33. package/dist/api/status-routes.js +17 -0
  34. package/dist/api/status-routes.js.map +1 -0
  35. package/dist/attach.d.ts +9 -0
  36. package/dist/attach.d.ts.map +1 -0
  37. package/dist/attach.js +155 -0
  38. package/dist/attach.js.map +1 -0
  39. package/dist/auth/auth-middleware.d.ts +52 -0
  40. package/dist/auth/auth-middleware.d.ts.map +1 -0
  41. package/dist/auth/auth-middleware.js +124 -0
  42. package/dist/auth/auth-middleware.js.map +1 -0
  43. package/dist/auth/rate-limiter.d.ts +37 -0
  44. package/dist/auth/rate-limiter.d.ts.map +1 -0
  45. package/dist/auth/rate-limiter.js +81 -0
  46. package/dist/auth/rate-limiter.js.map +1 -0
  47. package/dist/auth/token-generator.d.ts +9 -0
  48. package/dist/auth/token-generator.d.ts.map +1 -0
  49. package/dist/auth/token-generator.js +15 -0
  50. package/dist/auth/token-generator.js.map +1 -0
  51. package/dist/cli-utils.d.ts +19 -0
  52. package/dist/cli-utils.d.ts.map +1 -0
  53. package/dist/cli-utils.js +132 -0
  54. package/dist/cli-utils.js.map +1 -0
  55. package/dist/cli.d.ts +21 -0
  56. package/dist/cli.d.ts.map +1 -0
  57. package/dist/cli.js +58 -0
  58. package/dist/cli.js.map +1 -0
  59. package/dist/config.d.ts +146 -0
  60. package/dist/config.d.ts.map +1 -0
  61. package/dist/config.js +329 -0
  62. package/dist/config.js.map +1 -0
  63. package/dist/hooks/hook-receiver.d.ts +39 -0
  64. package/dist/hooks/hook-receiver.d.ts.map +1 -0
  65. package/dist/hooks/hook-receiver.js +46 -0
  66. package/dist/hooks/hook-receiver.js.map +1 -0
  67. package/dist/index.d.ts +3 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +353 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/logger/logger.d.ts +8 -0
  72. package/dist/logger/logger.d.ts.map +1 -0
  73. package/dist/logger/logger.js +90 -0
  74. package/dist/logger/logger.js.map +1 -0
  75. package/dist/notification/dingtalk-service.d.ts +24 -0
  76. package/dist/notification/dingtalk-service.d.ts.map +1 -0
  77. package/dist/notification/dingtalk-service.js +94 -0
  78. package/dist/notification/dingtalk-service.js.map +1 -0
  79. package/dist/pty/output-buffer.d.ts +25 -0
  80. package/dist/pty/output-buffer.d.ts.map +1 -0
  81. package/dist/pty/output-buffer.js +58 -0
  82. package/dist/pty/output-buffer.js.map +1 -0
  83. package/dist/pty/pty-manager.d.ts +45 -0
  84. package/dist/pty/pty-manager.d.ts.map +1 -0
  85. package/dist/pty/pty-manager.js +108 -0
  86. package/dist/pty/pty-manager.js.map +1 -0
  87. package/dist/pty/types.d.ts +11 -0
  88. package/dist/pty/types.d.ts.map +1 -0
  89. package/dist/pty/types.js +2 -0
  90. package/dist/pty/types.js.map +1 -0
  91. package/dist/pty/virtual-pty.d.ts +37 -0
  92. package/dist/pty/virtual-pty.d.ts.map +1 -0
  93. package/dist/pty/virtual-pty.js +161 -0
  94. package/dist/pty/virtual-pty.js.map +1 -0
  95. package/dist/push/push-service.d.ts +87 -0
  96. package/dist/push/push-service.d.ts.map +1 -0
  97. package/dist/push/push-service.js +301 -0
  98. package/dist/push/push-service.js.map +1 -0
  99. package/dist/registry/instance-registry.d.ts +32 -0
  100. package/dist/registry/instance-registry.d.ts.map +1 -0
  101. package/dist/registry/instance-registry.js +115 -0
  102. package/dist/registry/instance-registry.js.map +1 -0
  103. package/dist/registry/instance-spawner.d.ts +33 -0
  104. package/dist/registry/instance-spawner.d.ts.map +1 -0
  105. package/dist/registry/instance-spawner.js +91 -0
  106. package/dist/registry/instance-spawner.js.map +1 -0
  107. package/dist/registry/port-finder.d.ts +8 -0
  108. package/dist/registry/port-finder.d.ts.map +1 -0
  109. package/dist/registry/port-finder.js +35 -0
  110. package/dist/registry/port-finder.js.map +1 -0
  111. package/dist/registry/shared-token.d.ts +11 -0
  112. package/dist/registry/shared-token.d.ts.map +1 -0
  113. package/dist/registry/shared-token.js +82 -0
  114. package/dist/registry/shared-token.js.map +1 -0
  115. package/dist/registry/stop-instances.d.ts +27 -0
  116. package/dist/registry/stop-instances.d.ts.map +1 -0
  117. package/dist/registry/stop-instances.js +212 -0
  118. package/dist/registry/stop-instances.js.map +1 -0
  119. package/dist/session/session-controller.d.ts +58 -0
  120. package/dist/session/session-controller.d.ts.map +1 -0
  121. package/dist/session/session-controller.js +273 -0
  122. package/dist/session/session-controller.js.map +1 -0
  123. package/dist/terminal/terminal-relay.d.ts +29 -0
  124. package/dist/terminal/terminal-relay.d.ts.map +1 -0
  125. package/dist/terminal/terminal-relay.js +106 -0
  126. package/dist/terminal/terminal-relay.js.map +1 -0
  127. package/dist/utils/ansi-filter.d.ts +41 -0
  128. package/dist/utils/ansi-filter.d.ts.map +1 -0
  129. package/dist/utils/ansi-filter.js +147 -0
  130. package/dist/utils/ansi-filter.js.map +1 -0
  131. package/dist/utils/file-lock.d.ts +23 -0
  132. package/dist/utils/file-lock.d.ts.map +1 -0
  133. package/dist/utils/file-lock.js +125 -0
  134. package/dist/utils/file-lock.js.map +1 -0
  135. package/dist/utils/ip-monitor.d.ts +39 -0
  136. package/dist/utils/ip-monitor.d.ts.map +1 -0
  137. package/dist/utils/ip-monitor.js +114 -0
  138. package/dist/utils/ip-monitor.js.map +1 -0
  139. package/dist/utils/network.d.ts +19 -0
  140. package/dist/utils/network.d.ts.map +1 -0
  141. package/dist/utils/network.js +54 -0
  142. package/dist/utils/network.js.map +1 -0
  143. package/dist/utils/pid-file.d.ts +10 -0
  144. package/dist/utils/pid-file.d.ts.map +1 -0
  145. package/dist/utils/pid-file.js +30 -0
  146. package/dist/utils/pid-file.js.map +1 -0
  147. package/dist/utils/qrcode-banner.d.ts +6 -0
  148. package/dist/utils/qrcode-banner.d.ts.map +1 -0
  149. package/dist/utils/qrcode-banner.js +16 -0
  150. package/dist/utils/qrcode-banner.js.map +1 -0
  151. package/dist/ws/ws-handler.d.ts +10 -0
  152. package/dist/ws/ws-handler.d.ts.map +1 -0
  153. package/dist/ws/ws-handler.js +36 -0
  154. package/dist/ws/ws-handler.js.map +1 -0
  155. package/dist/ws/ws-server.d.ts +78 -0
  156. package/dist/ws/ws-server.d.ts.map +1 -0
  157. package/dist/ws/ws-server.js +223 -0
  158. package/dist/ws/ws-server.js.map +1 -0
  159. package/frontend-dist/assets/index-BKudo1Dw.css +32 -0
  160. package/frontend-dist/assets/index-BqqB1hYe.js +141 -0
  161. package/frontend-dist/index.html +15 -0
  162. package/frontend-dist/sw.js +46 -0
  163. package/package.json +79 -0
  164. package/shared-dist/constants.d.ts +10 -0
  165. package/shared-dist/constants.d.ts.map +1 -0
  166. package/shared-dist/constants.js +10 -0
  167. package/shared-dist/constants.js.map +1 -0
  168. package/shared-dist/defaults.d.ts +30 -0
  169. package/shared-dist/defaults.d.ts.map +1 -0
  170. package/shared-dist/defaults.js +31 -0
  171. package/shared-dist/defaults.js.map +1 -0
  172. package/shared-dist/index.d.ts +5 -0
  173. package/shared-dist/index.d.ts.map +1 -0
  174. package/shared-dist/index.js +5 -0
  175. package/shared-dist/index.js.map +1 -0
  176. package/shared-dist/instance.d.ts +25 -0
  177. package/shared-dist/instance.d.ts.map +1 -0
  178. package/shared-dist/instance.js +7 -0
  179. package/shared-dist/instance.js.map +1 -0
  180. package/shared-dist/question-utils.d.ts +15 -0
  181. package/shared-dist/question-utils.d.ts.map +1 -0
  182. package/shared-dist/question-utils.js +24 -0
  183. package/shared-dist/question-utils.js.map +1 -0
  184. package/shared-dist/ws-protocol.d.ts +60 -0
  185. package/shared-dist/ws-protocol.d.ts.map +1 -0
  186. package/shared-dist/ws-protocol.js +5 -0
  187. package/shared-dist/ws-protocol.js.map +1 -0
@@ -0,0 +1,3 @@
1
+ import { Router } from 'express';
2
+ export declare function createHealthRoutes(): Router;
3
+ //# sourceMappingURL=health-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-routes.d.ts","sourceRoot":"","sources":["../../src/api/health-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,wBAAgB,kBAAkB,IAAI,MAAM,CAQ3C"}
@@ -0,0 +1,9 @@
1
+ import { Router } from 'express';
2
+ export function createHealthRoutes() {
3
+ const router = Router();
4
+ router.get('/health', (_req, res) => {
5
+ res.json({ status: 'ok' });
6
+ });
7
+ return router;
8
+ }
9
+ //# sourceMappingURL=health-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-routes.js","sourceRoot":"","sources":["../../src/api/health-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,UAAU,kBAAkB;IAChC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QAClC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Router } from 'express';
2
+ import { HookReceiver } from '../hooks/hook-receiver.js';
3
+ export declare function createHookRoutes(hookReceiver: HookReceiver): Router;
4
+ //# sourceMappingURL=hook-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-routes.d.ts","sourceRoot":"","sources":["../../src/api/hook-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,CAiCnE"}
@@ -0,0 +1,32 @@
1
+ import { Router } from 'express';
2
+ import { logger } from '../logger/logger.js';
3
+ export function createHookRoutes(hookReceiver) {
4
+ const router = Router();
5
+ router.post('/hook', async (req, res) => {
6
+ // Only accept from localhost
7
+ const ip = req.ip ?? req.socket.remoteAddress ?? '';
8
+ const isLocalhost = ip === '127.0.0.1' || ip === '::1' || ip === '::ffff:127.0.0.1';
9
+ if (!isLocalhost) {
10
+ logger.warn({ ip }, 'Hook request from non-localhost rejected');
11
+ res.status(403).json({ error: 'Forbidden' });
12
+ return;
13
+ }
14
+ const payload = req.body;
15
+ if (!payload || typeof payload !== 'object') {
16
+ res.status(400).json({ error: 'Invalid payload' });
17
+ return;
18
+ }
19
+ const result = hookReceiver.processHook(payload);
20
+ switch (result.type) {
21
+ case 'notification':
22
+ res.json({ ok: true, tool: result.notification.tool });
23
+ break;
24
+ case 'ignored':
25
+ default:
26
+ res.json({ ok: true, ignored: true });
27
+ break;
28
+ }
29
+ });
30
+ return router;
31
+ }
32
+ //# sourceMappingURL=hook-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-routes.js","sourceRoot":"","sources":["../../src/api/hook-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAEpD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,MAAM,UAAU,gBAAgB,CAAC,YAA0B;IACzD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QACzD,6BAA6B;QAC7B,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,EAAE,CAAC;QACpD,MAAM,WAAW,GAAG,EAAE,KAAK,WAAW,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,kBAAkB,CAAC;QACpF,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,0CAA0C,CAAC,CAAC;YAChE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;YAC7C,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;YACnD,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAEjD,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,KAAK,cAAc;gBACjB,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,YAAa,CAAC,IAAI,EAAE,CAAC,CAAC;gBACxD,MAAM;YACR,KAAK,SAAS,CAAC;YACf;gBACE,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBACtC,MAAM;QACV,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { Router } from 'express';
2
+ import type { InstanceInfo } from '@claude-remote/shared';
3
+ import { AuthModule } from '../auth/auth-middleware.js';
4
+ import { InstanceSpawner } from '../registry/instance-spawner.js';
5
+ export interface CreateInstanceRequest {
6
+ /** 工作目录 */
7
+ cwd: string;
8
+ /** 实例名称(可选) */
9
+ name?: string;
10
+ /** Claude 额外参数(可选) */
11
+ claudeArgs?: string[];
12
+ }
13
+ export interface InstanceConfigResponse {
14
+ /** 预设工作目录列表 */
15
+ workspaces: string[];
16
+ /** Claude 参数 */
17
+ claudeArgs: string[];
18
+ }
19
+ export declare function createInstanceRoutes(authModule: AuthModule, listInstances: () => Promise<InstanceInfo[]>, currentInstanceId: string, spawner?: InstanceSpawner): Router;
20
+ //# sourceMappingURL=instance-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-routes.d.ts","sourceRoot":"","sources":["../../src/api/instance-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAExD,OAAO,EAAE,eAAe,EAAqB,MAAM,iCAAiC,CAAC;AAkCrF,MAAM,WAAW,qBAAqB;IACpC,WAAW;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,sBAAsB;IACrC,eAAe;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,gBAAgB;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC,EAC5C,iBAAiB,EAAE,MAAM,EACzB,OAAO,CAAC,EAAE,eAAe,GACxB,MAAM,CA4GR"}
@@ -0,0 +1,128 @@
1
+ import { Router } from 'express';
2
+ import { existsSync } from 'node:fs';
3
+ import { resolve, relative } from 'node:path';
4
+ import { createAuthRoutes } from './auth-routes.js';
5
+ import { loadUserConfig } from '../config.js';
6
+ import { logger } from '../logger/logger.js';
7
+ /**
8
+ * 检查 cwd 是否在允许的路径范围内
9
+ * 只允许白名单中的目录或其子目录
10
+ */
11
+ function isCwdAllowed(absoluteCwd, allowedCwds) {
12
+ for (const allowed of allowedCwds) {
13
+ const absAllowed = resolve(allowed);
14
+ const rel = relative(absAllowed, absoluteCwd);
15
+ // rel 为空字符串表示路径相同,不以 '..' 开头表示是子目录
16
+ if (rel === '' || (rel && !rel.startsWith('..'))) {
17
+ return true;
18
+ }
19
+ }
20
+ return false;
21
+ }
22
+ /**
23
+ * 获取合并后的允许 cwd 白名单
24
+ * 来源:配置文件 workspaces + 已启动实例的 cwd(去重)
25
+ */
26
+ async function getAllowedCwds(listInstances) {
27
+ const config = loadUserConfig();
28
+ const configWorkspaces = config.workspaces ?? [];
29
+ const instances = await listInstances();
30
+ const instanceCwds = instances.map(inst => inst.cwd);
31
+ return [...new Set([...configWorkspaces, ...instanceCwds])];
32
+ }
33
+ export function createInstanceRoutes(authModule, listInstances, currentInstanceId, spawner) {
34
+ const router = Router();
35
+ // 复用 auth 路由以支持 supertest 认证
36
+ router.use(createAuthRoutes(authModule));
37
+ router.get('/instances', authModule.requireAuth, async (_req, res) => {
38
+ const instances = await listInstances();
39
+ const result = instances.map(inst => ({
40
+ ...inst,
41
+ isCurrent: inst.instanceId === currentInstanceId,
42
+ }));
43
+ res.json(result);
44
+ });
45
+ /**
46
+ * GET /api/instances/config - 获取实例创建配置
47
+ * 返回合并后的工作目录白名单和默认参数
48
+ * 白名单 = 配置文件 workspaces + 已启动实例的 cwd(去重)
49
+ */
50
+ router.get('/instances/config', authModule.requireAuth, async (_req, res) => {
51
+ try {
52
+ const config = loadUserConfig();
53
+ const allowedCwds = await getAllowedCwds(listInstances);
54
+ const response = {
55
+ workspaces: allowedCwds,
56
+ claudeArgs: config.claudeArgs ?? [],
57
+ };
58
+ res.json(response);
59
+ }
60
+ catch (error) {
61
+ logger.error({ error }, 'Failed to get instance config');
62
+ res.status(500).json({ error: 'Failed to get instance config' });
63
+ }
64
+ });
65
+ /**
66
+ * POST /api/instances/create - 创建新实例
67
+ */
68
+ router.post('/instances/create', authModule.requireAuth, async (req, res) => {
69
+ try {
70
+ const { cwd, name, claudeArgs } = req.body;
71
+ // 参数验证
72
+ if (!cwd || typeof cwd !== 'string') {
73
+ res.status(400).json({ error: 'cwd is required and must be a string' });
74
+ return;
75
+ }
76
+ // 检查目录是否存在
77
+ const absoluteCwd = resolve(cwd);
78
+ if (!existsSync(absoluteCwd)) {
79
+ res.status(400).json({ error: `Directory does not exist: ${absoluteCwd}` });
80
+ return;
81
+ }
82
+ // 加载用户配置(用于 workspaces 白名单和默认参数)
83
+ const userConfig = loadUserConfig();
84
+ const allowedCwds = await getAllowedCwds(listInstances);
85
+ // 路径安全检查:cwd 必须在白名单中
86
+ if (!isCwdAllowed(absoluteCwd, allowedCwds)) {
87
+ logger.warn({ absoluteCwd, allowedCwds }, 'Cwd path not allowed');
88
+ res.status(403).json({
89
+ error: 'Directory not allowed. Must be in allowed workspaces list.',
90
+ });
91
+ return;
92
+ }
93
+ // 检查 spawner 是否可用
94
+ if (!spawner) {
95
+ res.status(500).json({ error: 'Instance spawner not configured' });
96
+ return;
97
+ }
98
+ // 合并默认参数
99
+ const finalClaudeArgs = claudeArgs ?? userConfig.claudeArgs ?? [];
100
+ const spawnOptions = {
101
+ cwd: absoluteCwd,
102
+ name: name || undefined,
103
+ claudeArgs: finalClaudeArgs,
104
+ headless: true,
105
+ };
106
+ const result = await spawner.spawn(spawnOptions);
107
+ logger.info({
108
+ pid: result.pid,
109
+ cwd: absoluteCwd,
110
+ name: result.name,
111
+ }, 'Instance created via API');
112
+ res.json({
113
+ success: true,
114
+ instance: {
115
+ pid: result.pid,
116
+ cwd: result.cwd,
117
+ name: result.name,
118
+ },
119
+ });
120
+ }
121
+ catch (error) {
122
+ logger.error({ error }, 'Failed to create instance');
123
+ res.status(500).json({ error: 'Failed to create instance' });
124
+ }
125
+ });
126
+ return router;
127
+ }
128
+ //# sourceMappingURL=instance-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-routes.js","sourceRoot":"","sources":["../../src/api/instance-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Router } from 'express';
2
+ import { AuthModule } from '../auth/auth-middleware.js';
3
+ import { PushService } from '../push/push-service.js';
4
+ export declare function createPushRoutes(authModule: AuthModule, pushService: PushService): Router;
5
+ //# sourceMappingURL=push-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-routes.d.ts","sourceRoot":"","sources":["../../src/api/push-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,CAgDzF"}
@@ -0,0 +1,45 @@
1
+ import { Router } from 'express';
2
+ import { logger } from '../logger/logger.js';
3
+ export function createPushRoutes(authModule, pushService) {
4
+ const router = Router();
5
+ // Get VAPID public key (needed by frontend to subscribe)
6
+ router.get('/push/vapid-key', authModule.requireAuth, async (_req, res) => {
7
+ const key = await pushService.waitForVapidPublicKey(2000);
8
+ if (!key) {
9
+ res.status(503).json({ error: 'Push notifications not available' });
10
+ return;
11
+ }
12
+ res.json({ vapidPublicKey: key });
13
+ });
14
+ // Subscribe to push notifications
15
+ router.post('/push/subscribe', authModule.requireAuth, (req, res) => {
16
+ const { endpoint, keys } = req.body ?? {};
17
+ if (!endpoint || !keys?.p256dh || !keys?.auth) {
18
+ res.status(400).json({ error: 'Invalid subscription data' });
19
+ return;
20
+ }
21
+ // p256dh 是 65 字节的 ECDH 公钥,Base64 URL-safe 编码后约 87 字符
22
+ // 最小长度设为 64,允许不同编码的合理变化
23
+ const P256DH_MIN_LENGTH = 64;
24
+ if (keys.p256dh.length < P256DH_MIN_LENGTH) {
25
+ logger.warn({ p256dhLength: keys.p256dh.length }, 'Invalid p256dh key length');
26
+ res.status(400).json({ error: 'Invalid p256dh key format' });
27
+ return;
28
+ }
29
+ pushService.subscribe({ endpoint, keys });
30
+ logger.info({ endpoint }, 'Push subscription registered via API');
31
+ res.json({ ok: true });
32
+ });
33
+ // Unsubscribe from push notifications
34
+ router.delete('/push/subscribe', authModule.requireAuth, (req, res) => {
35
+ const { endpoint } = req.body ?? {};
36
+ if (!endpoint) {
37
+ res.status(400).json({ error: 'Missing endpoint' });
38
+ return;
39
+ }
40
+ const removed = pushService.unsubscribe(endpoint);
41
+ res.json({ ok: true, removed });
42
+ });
43
+ return router;
44
+ }
45
+ //# sourceMappingURL=push-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-routes.js","sourceRoot":"","sources":["../../src/api/push-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAGpD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,MAAM,UAAU,gBAAgB,CAAC,UAAsB,EAAE,WAAwB;IAC/E,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,yDAAyD;IACzD,MAAM,CAAC,GAAG,CAAC,iBAAiB,EAAE,UAAU,CAAC,WAAW,EAAE,KAAK,EAAE,IAAa,EAAE,GAAa,EAAE,EAAE;QAC3F,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC,CAAC;YACpE,OAAO;QACT,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,kCAAkC;IAClC,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,WAAW,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QACrF,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;YAC9C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC,CAAC;YAC7D,OAAO;QACT,CAAC;QAED,qDAAqD;QACrD,wBAAwB;QACxB,MAAM,iBAAiB,GAAG,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,iBAAiB,EAAE,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,2BAA2B,CAAC,CAAC;YAC/E,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC,CAAC;YAC7D,OAAO;QACT,CAAC;QAED,WAAW,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,sCAAsC,CAAC,CAAC;QAClE,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,sCAAsC;IACtC,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,UAAU,CAAC,WAAW,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QACvF,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;YACpD,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAClD,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { Router } from 'express';
2
+ import { AuthModule } from '../auth/auth-middleware.js';
3
+ import { HookReceiver } from '../hooks/hook-receiver.js';
4
+ import { PushService } from '../push/push-service.js';
5
+ import { InstanceSpawner } from '../registry/instance-spawner.js';
6
+ import type { SessionController } from '../session/session-controller.js';
7
+ import type { InstanceInfo } from '@claude-remote/shared';
8
+ export interface ApiRouterOptions {
9
+ authModule: AuthModule;
10
+ hookReceiver: HookReceiver;
11
+ getController: () => SessionController | null;
12
+ pushService?: PushService;
13
+ listInstances?: () => Promise<InstanceInfo[]>;
14
+ currentInstanceId?: string;
15
+ instanceSpawner?: InstanceSpawner;
16
+ }
17
+ export declare function createApiRouter(opts: ApiRouterOptions): Router;
18
+ export declare function createApiRouter(authModule: AuthModule, hookReceiver: HookReceiver, getController: () => SessionController | null, pushService?: PushService): Router;
19
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/api/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAQjC,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,MAAM,iBAAiB,GAAG,IAAI,CAAC;IAC9C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAAC;AAChE,wBAAgB,eAAe,CAC7B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,YAAY,EAC1B,aAAa,EAAE,MAAM,iBAAiB,GAAG,IAAI,EAC7C,WAAW,CAAC,EAAE,WAAW,GACxB,MAAM,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { Router } from 'express';
2
+ import { createHealthRoutes } from './health-routes.js';
3
+ import { createAuthRoutes } from './auth-routes.js';
4
+ import { createStatusRoutes } from './status-routes.js';
5
+ import { createHookRoutes } from './hook-routes.js';
6
+ import { createPushRoutes } from './push-routes.js';
7
+ import { createInstanceRoutes } from './instance-routes.js';
8
+ import { createConfigRoutes } from './config-routes.js';
9
+ import { AuthModule } from '../auth/auth-middleware.js';
10
+ export function createApiRouter(authModuleOrOpts, hookReceiver, getController, pushService) {
11
+ let opts;
12
+ if (authModuleOrOpts instanceof AuthModule) {
13
+ opts = {
14
+ authModule: authModuleOrOpts,
15
+ hookReceiver: hookReceiver,
16
+ getController: getController,
17
+ pushService,
18
+ };
19
+ }
20
+ else {
21
+ opts = authModuleOrOpts;
22
+ }
23
+ const router = Router();
24
+ router.use(createHealthRoutes());
25
+ router.use(createAuthRoutes(opts.authModule));
26
+ router.use(createStatusRoutes(opts.authModule, opts.getController));
27
+ router.use(createHookRoutes(opts.hookReceiver));
28
+ router.use(createConfigRoutes(opts.authModule));
29
+ if (opts.pushService) {
30
+ router.use(createPushRoutes(opts.authModule, opts.pushService));
31
+ }
32
+ if (opts.listInstances && opts.currentInstanceId) {
33
+ router.use(createInstanceRoutes(opts.authModule, opts.listInstances, opts.currentInstanceId, opts.instanceSpawner));
34
+ }
35
+ return router;
36
+ }
37
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/api/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAwBxD,MAAM,UAAU,eAAe,CAC7B,gBAA+C,EAC/C,YAA2B,EAC3B,aAA8C,EAC9C,WAAyB;IAEzB,IAAI,IAAsB,CAAC;IAC3B,IAAI,gBAAgB,YAAY,UAAU,EAAE,CAAC;QAC3C,IAAI,GAAG;YACL,UAAU,EAAE,gBAAgB;YAC5B,YAAY,EAAE,YAAa;YAC3B,aAAa,EAAE,aAAc;YAC7B,WAAW;SACZ,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,gBAAgB,CAAC;IAC1B,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IACpE,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAChD,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAEhD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAC7B,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,iBAAiB,EACtB,IAAI,CAAC,eAAe,CACrB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Router } from 'express';
2
+ import type { SessionController } from '../session/session-controller.js';
3
+ import { AuthModule } from '../auth/auth-middleware.js';
4
+ export declare function createStatusRoutes(authModule: AuthModule, getController: () => SessionController | null): Router;
5
+ //# sourceMappingURL=status-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-routes.d.ts","sourceRoot":"","sources":["../../src/api/status-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAExD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,iBAAiB,GAAG,IAAI,GAAG,MAAM,CAgBhH"}
@@ -0,0 +1,17 @@
1
+ import { Router } from 'express';
2
+ export function createStatusRoutes(authModule, getController) {
3
+ const router = Router();
4
+ router.get('/status', authModule.requireAuth, (_req, res) => {
5
+ const controller = getController();
6
+ if (!controller) {
7
+ res.json({ status: 'not_started' });
8
+ return;
9
+ }
10
+ res.json({
11
+ status: controller.status,
12
+ connectedClients: controller.connectedClients,
13
+ });
14
+ });
15
+ return router;
16
+ }
17
+ //# sourceMappingURL=status-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-routes.js","sourceRoot":"","sources":["../../src/api/status-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,MAAM,UAAU,kBAAkB,CAAC,UAAsB,EAAE,aAA6C;IACtG,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QAC1D,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;QACnC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;YACpC,OAAO;QACT,CAAC;QACD,GAAG,CAAC,IAAI,CAAC;YACP,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,gBAAgB,EAAE,UAAU,CAAC,gBAAgB;SAC9C,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export interface AttachOptions {
2
+ /** 目标实例端口或名称 */
3
+ target: string;
4
+ }
5
+ /**
6
+ * 执行 attach 命令。
7
+ */
8
+ export declare function attachInstance(options: AttachOptions): Promise<void>;
9
+ //# sourceMappingURL=attach.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attach.d.ts","sourceRoot":"","sources":["../src/attach.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,aAAa;IAC5B,gBAAgB;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AA+CD;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgH1E"}
package/dist/attach.js ADDED
@@ -0,0 +1,155 @@
1
+ /**
2
+ * claude-remote attach 命令实现
3
+ *
4
+ * 用法:
5
+ * claude-remote attach <port|name>
6
+ *
7
+ * 连接到指定的实例,接管其终端输入输出。
8
+ */
9
+ import { homedir } from 'node:os';
10
+ import { resolve } from 'node:path';
11
+ import { CLAUDE_REMOTE_DIR, REGISTRY_FILENAME } from '../shared-dist/index.js';
12
+ import { existsSync, readFileSync } from 'node:fs';
13
+ import { VirtualPtyManager } from './pty/virtual-pty.js';
14
+ import { TerminalRelay } from './terminal/terminal-relay.js';
15
+ import { getOrCreateSharedToken } from './registry/shared-token.js';
16
+ /**
17
+ * 从注册表获取实例列表。
18
+ */
19
+ function loadInstances(baseDir) {
20
+ const registryPath = resolve(baseDir, REGISTRY_FILENAME);
21
+ if (!existsSync(registryPath)) {
22
+ return [];
23
+ }
24
+ try {
25
+ const content = readFileSync(registryPath, 'utf-8');
26
+ const data = JSON.parse(content);
27
+ return data.instances ?? [];
28
+ }
29
+ catch {
30
+ return [];
31
+ }
32
+ }
33
+ /**
34
+ * 查找目标实例。
35
+ */
36
+ function findInstance(target, instances) {
37
+ // 先按端口查找
38
+ const port = parseInt(target, 10);
39
+ if (!isNaN(port)) {
40
+ const byPort = instances.find(inst => inst.port === port);
41
+ if (byPort)
42
+ return byPort;
43
+ }
44
+ // 再按名称查找
45
+ const byName = instances.find(inst => inst.name === target);
46
+ return byName ?? null;
47
+ }
48
+ /**
49
+ * 检查进程是否存活
50
+ */
51
+ function isProcessAlive(pid) {
52
+ try {
53
+ process.kill(pid, 0);
54
+ return true;
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ }
60
+ /**
61
+ * 执行 attach 命令。
62
+ */
63
+ export async function attachInstance(options) {
64
+ const { target } = options;
65
+ // 获取配置目录
66
+ const sharedConfigDir = resolve(homedir(), CLAUDE_REMOTE_DIR);
67
+ // 加载实例列表
68
+ const instances = loadInstances(sharedConfigDir);
69
+ // 过滤存活实例
70
+ const aliveInstances = instances.filter(inst => isProcessAlive(inst.pid));
71
+ if (aliveInstances.length === 0) {
72
+ console.error('没有发现存活实例');
73
+ process.exit(1);
74
+ }
75
+ // 查找目标实例
76
+ const instance = findInstance(target, aliveInstances);
77
+ if (!instance) {
78
+ console.error(`未找到实例: ${target}`);
79
+ console.error('可用实例:');
80
+ for (const inst of aliveInstances) {
81
+ console.error(` - ${inst.name} (端口 ${inst.port})`);
82
+ }
83
+ process.exit(1);
84
+ }
85
+ console.log(`正在连接实例: ${instance.name} (端口 ${instance.port})...`);
86
+ // 获取共享 Token
87
+ const { token } = getOrCreateSharedToken(sharedConfigDir);
88
+ // 创建 VirtualPtyManager
89
+ const virtualPty = new VirtualPtyManager();
90
+ // 创建 TerminalRelay
91
+ const relay = new TerminalRelay(virtualPty);
92
+ // 幂等退出保护
93
+ let stopping = false;
94
+ const cleanup = () => {
95
+ if (stopping)
96
+ return;
97
+ stopping = true;
98
+ virtualPty.destroy();
99
+ relay.stop();
100
+ };
101
+ // 处理 PTY 输出 → stdout
102
+ virtualPty.on('data', (data) => {
103
+ process.stdout.write(data);
104
+ });
105
+ // 处理服务端 resize 通知 → 发送本地终端尺寸
106
+ // 当 WebApp 断开时,服务端广播 terminal_resize,让 attach 用真实尺寸响应
107
+ virtualPty.on('server_resize', () => {
108
+ const cols = process.stdout.columns ?? 80;
109
+ const rows = process.stdout.rows ?? 24;
110
+ virtualPty.resize(cols, rows);
111
+ });
112
+ // 处理连接关闭
113
+ virtualPty.on('exit', (_exitCode) => {
114
+ console.log('\n连接已关闭');
115
+ cleanup();
116
+ process.exit(0);
117
+ });
118
+ virtualPty.on('error', (err) => {
119
+ console.error('连接错误:', err.message);
120
+ cleanup();
121
+ process.exit(1);
122
+ });
123
+ // 连接到实例 - 使用 instance.host(回退为 localhost)
124
+ // 注意:instance.host 为 '0.0.0.0' 时表示监听所有接口,客户端应使用 localhost 连接
125
+ const host = instance.host && instance.host !== '0.0.0.0' ? instance.host : 'localhost';
126
+ const wsUrl = `ws://${host}:${instance.port}/ws`;
127
+ try {
128
+ await virtualPty.connect(wsUrl, token);
129
+ }
130
+ catch (err) {
131
+ console.error('连接失败:', err instanceof Error ? err.message : err);
132
+ cleanup();
133
+ process.exit(1);
134
+ }
135
+ // 同步终端大小
136
+ const cols = process.stdout.columns ?? 80;
137
+ const rows = process.stdout.rows ?? 24;
138
+ virtualPty.resize(cols, rows);
139
+ // 启动 TerminalRelay
140
+ relay.start();
141
+ console.log('已连接。按 Ctrl+C 两次退出。');
142
+ // 等待进程退出
143
+ await new Promise((resolve) => {
144
+ process.on('SIGINT', () => {
145
+ console.log('\n正在断开连接...');
146
+ cleanup();
147
+ resolve();
148
+ });
149
+ process.on('SIGTERM', () => {
150
+ cleanup();
151
+ resolve();
152
+ });
153
+ });
154
+ }
155
+ //# sourceMappingURL=attach.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attach.js","sourceRoot":"","sources":["../src/attach.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ export interface AuthModuleOptions {
3
+ token: string;
4
+ sessionTtlMs: number;
5
+ rateLimitPerMinute: number;
6
+ cookieName: string;
7
+ }
8
+ /**
9
+ * Authentication module managing token verification, session cookies, and rate limiting.
10
+ */
11
+ export declare class AuthModule {
12
+ private readonly token;
13
+ private readonly sessionTtlMs;
14
+ private readonly cookieName;
15
+ private readonly sessions;
16
+ private readonly rateLimiter;
17
+ constructor(options: AuthModuleOptions);
18
+ /**
19
+ * Verify a token using timing-safe comparison.
20
+ */
21
+ verifyToken(candidate: string): boolean;
22
+ /**
23
+ * Create a new session and return the session ID.
24
+ */
25
+ createSession(ip: string): string;
26
+ /**
27
+ * Validate a session ID. Returns true if valid and not expired.
28
+ */
29
+ validateSession(sessionId: string): boolean;
30
+ /**
31
+ * Extract session ID from request cookies.
32
+ */
33
+ getSessionFromRequest(req: Request): string | null;
34
+ /**
35
+ * Extract session ID from a raw cookie header string.
36
+ */
37
+ getSessionFromCookieHeader(cookieHeader: string): string | null;
38
+ getCookieName(): string;
39
+ /**
40
+ * Express middleware that protects routes with session auth.
41
+ */
42
+ requireAuth: (req: Request, res: Response, next: NextFunction) => void;
43
+ /**
44
+ * Handle auth POST (verify token, create session, return cookie).
45
+ */
46
+ handleAuth: (req: Request, res: Response) => void;
47
+ /**
48
+ * Cleanup resources.
49
+ */
50
+ destroy(): void;
51
+ }
52
+ //# sourceMappingURL=auth-middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../../src/auth/auth-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAO1D,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwC;IACjE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;gBAE9B,OAAO,EAAE,iBAAiB;IAOtC;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAOvC;;OAEG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAOjC;;OAEG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAU3C;;OAEG;IACH,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI;IAKlD;;OAEG;IACH,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAK/D,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,WAAW,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAcnE;IAEF;;OAEG;IACH,UAAU,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,KAAG,IAAI,CA+B9C;IAEF;;OAEG;IACH,OAAO,IAAI,IAAI;CAGhB"}