@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,124 @@
1
+ import { timingSafeEqual } from 'node:crypto';
2
+ import * as cookie from 'cookie';
3
+ import { generateSessionId } from './token-generator.js';
4
+ import { RateLimiter } from './rate-limiter.js';
5
+ import { logger } from '../logger/logger.js';
6
+ /**
7
+ * Authentication module managing token verification, session cookies, and rate limiting.
8
+ */
9
+ export class AuthModule {
10
+ token;
11
+ sessionTtlMs;
12
+ cookieName;
13
+ sessions = new Map();
14
+ rateLimiter;
15
+ constructor(options) {
16
+ this.token = options.token;
17
+ this.sessionTtlMs = options.sessionTtlMs;
18
+ this.cookieName = options.cookieName;
19
+ this.rateLimiter = new RateLimiter(options.rateLimitPerMinute);
20
+ }
21
+ /**
22
+ * Verify a token using timing-safe comparison.
23
+ */
24
+ verifyToken(candidate) {
25
+ const a = Buffer.from(this.token);
26
+ const b = Buffer.from(candidate);
27
+ if (a.length !== b.length)
28
+ return false;
29
+ return timingSafeEqual(a, b);
30
+ }
31
+ /**
32
+ * Create a new session and return the session ID.
33
+ */
34
+ createSession(ip) {
35
+ const sessionId = generateSessionId();
36
+ this.sessions.set(sessionId, { createdAt: Date.now(), ip });
37
+ logger.info({ ip }, 'Session created');
38
+ return sessionId;
39
+ }
40
+ /**
41
+ * Validate a session ID. Returns true if valid and not expired.
42
+ */
43
+ validateSession(sessionId) {
44
+ const entry = this.sessions.get(sessionId);
45
+ if (!entry)
46
+ return false;
47
+ if (Date.now() - entry.createdAt > this.sessionTtlMs) {
48
+ this.sessions.delete(sessionId);
49
+ return false;
50
+ }
51
+ return true;
52
+ }
53
+ /**
54
+ * Extract session ID from request cookies.
55
+ */
56
+ getSessionFromRequest(req) {
57
+ const cookies = cookie.parse(req.headers.cookie ?? '');
58
+ return cookies[this.cookieName] ?? null;
59
+ }
60
+ /**
61
+ * Extract session ID from a raw cookie header string.
62
+ */
63
+ getSessionFromCookieHeader(cookieHeader) {
64
+ const cookies = cookie.parse(cookieHeader);
65
+ return cookies[this.cookieName] ?? null;
66
+ }
67
+ getCookieName() {
68
+ return this.cookieName;
69
+ }
70
+ /**
71
+ * Express middleware that protects routes with session auth.
72
+ */
73
+ requireAuth = (req, res, next) => {
74
+ const sessionId = this.getSessionFromRequest(req);
75
+ const isValid = sessionId ? this.validateSession(sessionId) : false;
76
+ if (!isValid) {
77
+ logger.warn({
78
+ path: req.path,
79
+ instanceCookieName: this.cookieName,
80
+ hasSessionCookie: Boolean(sessionId),
81
+ sessionFound: Boolean(sessionId && this.sessions.has(sessionId)),
82
+ }, 'Auth rejected: invalid session');
83
+ res.status(401).json({ error: 'Unauthorized' });
84
+ return;
85
+ }
86
+ next();
87
+ };
88
+ /**
89
+ * Handle auth POST (verify token, create session, return cookie).
90
+ */
91
+ handleAuth = (req, res) => {
92
+ const ip = req.ip ?? req.socket.remoteAddress ?? 'unknown';
93
+ if (!this.rateLimiter.attempt(ip)) {
94
+ logger.warn({ ip }, 'Auth rate limit hit');
95
+ res.status(429).json({ error: 'Too many attempts. Try again later.' });
96
+ return;
97
+ }
98
+ const { token } = req.body;
99
+ if (!token || !this.verifyToken(token)) {
100
+ logger.warn({ ip }, 'Auth failed: invalid token');
101
+ res.status(401).json({ error: 'Invalid token' });
102
+ return;
103
+ }
104
+ const sessionId = this.createSession(ip);
105
+ // Reset rate limiter on successful auth - user has proven they know the token
106
+ this.rateLimiter.reset(ip);
107
+ res.setHeader('Set-Cookie', cookie.serialize(this.cookieName, sessionId, {
108
+ httpOnly: true,
109
+ secure: req.protocol === 'https',
110
+ sameSite: 'lax',
111
+ path: '/',
112
+ maxAge: Math.floor(this.sessionTtlMs / 1000),
113
+ }));
114
+ logger.info({ ip, instanceCookieName: this.cookieName }, 'Auth successful');
115
+ res.json({ ok: true });
116
+ };
117
+ /**
118
+ * Cleanup resources.
119
+ */
120
+ destroy() {
121
+ this.rateLimiter.destroy();
122
+ }
123
+ }
124
+ //# sourceMappingURL=auth-middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-middleware.js","sourceRoot":"","sources":["../../src/auth/auth-middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Simple in-memory rate limiter per IP.
3
+ * Window: 1 minute. Configurable max attempts.
4
+ *
5
+ * 多实例限制:各实例独立计数,不共享状态。
6
+ * 在多实例场景下,同一 IP 的有效总尝试次数 = maxAttempts × 实例数。
7
+ * 这在实际场景中可接受:token 为 256 位(64 hex chars),暴力破解不可行。
8
+ */
9
+ export declare class RateLimiter {
10
+ private entries;
11
+ private readonly maxAttempts;
12
+ private readonly windowMs;
13
+ private cleanupTimer;
14
+ constructor(maxAttempts?: number, windowMs?: number);
15
+ /**
16
+ * Check if an IP is allowed. Returns true if allowed, false if rate limited.
17
+ * Automatically increments the counter.
18
+ */
19
+ attempt(ip: string): boolean;
20
+ /**
21
+ * Get remaining attempts for an IP.
22
+ */
23
+ remaining(ip: string): number;
24
+ /**
25
+ * Clean up expired entries.
26
+ */
27
+ private cleanup;
28
+ /**
29
+ * Reset rate limit counter for an IP (e.g., after successful auth).
30
+ */
31
+ reset(ip: string): void;
32
+ /**
33
+ * Stop cleanup timer.
34
+ */
35
+ destroy(): void;
36
+ }
37
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/auth/rate-limiter.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,YAAY,CAA+C;gBAEvD,WAAW,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAe;IAW9D;;;OAGG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAmB5B;;OAEG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAO7B;;OAEG;IACH,OAAO,CAAC,OAAO;IASf;;OAEG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIvB;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB"}
@@ -0,0 +1,81 @@
1
+ import { logger } from '../logger/logger.js';
2
+ /**
3
+ * Simple in-memory rate limiter per IP.
4
+ * Window: 1 minute. Configurable max attempts.
5
+ *
6
+ * 多实例限制:各实例独立计数,不共享状态。
7
+ * 在多实例场景下,同一 IP 的有效总尝试次数 = maxAttempts × 实例数。
8
+ * 这在实际场景中可接受:token 为 256 位(64 hex chars),暴力破解不可行。
9
+ */
10
+ export class RateLimiter {
11
+ entries = new Map();
12
+ maxAttempts;
13
+ windowMs;
14
+ cleanupTimer = null;
15
+ constructor(maxAttempts = 5, windowMs = 60_000) {
16
+ this.maxAttempts = maxAttempts;
17
+ this.windowMs = windowMs;
18
+ // Periodic cleanup of stale entries
19
+ this.cleanupTimer = setInterval(() => this.cleanup(), windowMs * 2);
20
+ // Don't block process exit
21
+ if (this.cleanupTimer.unref) {
22
+ this.cleanupTimer.unref();
23
+ }
24
+ }
25
+ /**
26
+ * Check if an IP is allowed. Returns true if allowed, false if rate limited.
27
+ * Automatically increments the counter.
28
+ */
29
+ attempt(ip) {
30
+ const now = Date.now();
31
+ const entry = this.entries.get(ip);
32
+ if (!entry || now >= entry.resetAt) {
33
+ // First attempt or window expired
34
+ this.entries.set(ip, { count: 1, resetAt: now + this.windowMs });
35
+ return true;
36
+ }
37
+ entry.count++;
38
+ if (entry.count > this.maxAttempts) {
39
+ logger.warn({ ip, count: entry.count, maxAttempts: this.maxAttempts }, 'Rate limit exceeded');
40
+ return false;
41
+ }
42
+ return true;
43
+ }
44
+ /**
45
+ * Get remaining attempts for an IP.
46
+ */
47
+ remaining(ip) {
48
+ const now = Date.now();
49
+ const entry = this.entries.get(ip);
50
+ if (!entry || now >= entry.resetAt)
51
+ return this.maxAttempts;
52
+ return Math.max(0, this.maxAttempts - entry.count);
53
+ }
54
+ /**
55
+ * Clean up expired entries.
56
+ */
57
+ cleanup() {
58
+ const now = Date.now();
59
+ for (const [ip, entry] of this.entries) {
60
+ if (now >= entry.resetAt) {
61
+ this.entries.delete(ip);
62
+ }
63
+ }
64
+ }
65
+ /**
66
+ * Reset rate limit counter for an IP (e.g., after successful auth).
67
+ */
68
+ reset(ip) {
69
+ this.entries.delete(ip);
70
+ }
71
+ /**
72
+ * Stop cleanup timer.
73
+ */
74
+ destroy() {
75
+ if (this.cleanupTimer) {
76
+ clearInterval(this.cleanupTimer);
77
+ this.cleanupTimer = null;
78
+ }
79
+ }
80
+ }
81
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/auth/rate-limiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAO7C;;;;;;;GAOG;AACH,MAAM,OAAO,WAAW;IACd,OAAO,GAAgC,IAAI,GAAG,EAAE,CAAC;IACxC,WAAW,CAAS;IACpB,QAAQ,CAAS;IAC1B,YAAY,GAA0C,IAAI,CAAC;IAEnE,YAAY,cAAsB,CAAC,EAAE,WAAmB,MAAM;QAC5D,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,oCAAoC;QACpC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;QACpE,2BAA2B;QAC3B,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;YAC5B,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,EAAU;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEnC,IAAI,CAAC,KAAK,IAAI,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,kCAAkC;YAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,IAAI,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,qBAAqB,CAAC,CAAC;YAC9F,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,EAAU;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK,IAAI,GAAG,IAAI,KAAK,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,WAAW,CAAC;QAC5D,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACK,OAAO;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACvC,IAAI,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBACzB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,EAAU;QACd,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACjC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Generate a random hex token for authentication.
3
+ */
4
+ export declare function generateToken(): string;
5
+ /**
6
+ * Generate a random session ID.
7
+ */
8
+ export declare function generateSessionId(): string;
9
+ //# sourceMappingURL=token-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-generator.d.ts","sourceRoot":"","sources":["../../src/auth/token-generator.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
@@ -0,0 +1,15 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { TOKEN_BYTES, SESSION_ID_BYTES } from '../../shared-dist/index.js';
3
+ /**
4
+ * Generate a random hex token for authentication.
5
+ */
6
+ export function generateToken() {
7
+ return randomBytes(TOKEN_BYTES).toString('hex');
8
+ }
9
+ /**
10
+ * Generate a random session ID.
11
+ */
12
+ export function generateSessionId() {
13
+ return randomBytes(SESSION_ID_BYTES).toString('hex');
14
+ }
15
+ //# sourceMappingURL=token-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-generator.js","sourceRoot":"","sources":["../../src/auth/token-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEtE;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,WAAW,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * CLI 参数解析工具函数
3
+ *
4
+ * 从 cli.ts 提取出来,避免 cli.ts 有静态 import。
5
+ */
6
+ export interface CliOptions {
7
+ port?: number;
8
+ host?: string;
9
+ token?: string;
10
+ name?: string;
11
+ help: boolean;
12
+ noTerminal: boolean;
13
+ claudeArgs: string[];
14
+ /** attach 子命令 */
15
+ attach?: string;
16
+ }
17
+ export declare function parseCliArgs(argv: string[]): CliOptions;
18
+ export declare function showHelp(): void;
19
+ //# sourceMappingURL=cli-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-utils.d.ts","sourceRoot":"","sources":["../src/cli-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,iBAAiB;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAaD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAkEvD;AAED,wBAAgB,QAAQ,IAAI,IAAI,CA0C/B"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * CLI 参数解析工具函数
3
+ *
4
+ * 从 cli.ts 提取出来,避免 cli.ts 有静态 import。
5
+ */
6
+ function parsePort(raw) {
7
+ if (!raw || !/^\d+$/.test(raw)) {
8
+ throw new Error('--port requires a numeric value');
9
+ }
10
+ const port = Number(raw);
11
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
12
+ throw new Error('--port must be between 1 and 65535');
13
+ }
14
+ return port;
15
+ }
16
+ export function parseCliArgs(argv) {
17
+ const options = {
18
+ help: false,
19
+ noTerminal: false,
20
+ claudeArgs: [],
21
+ };
22
+ let i = 2; // Skip 'node' and script path
23
+ // 检查子命令
24
+ if (argv.length > 2) {
25
+ const firstArg = argv[2];
26
+ if (firstArg === 'attach') {
27
+ if (argv.length <= 3) {
28
+ throw new Error('attach 命令需要指定目标实例(端口或名称)');
29
+ }
30
+ options.attach = argv[3];
31
+ return options;
32
+ }
33
+ }
34
+ while (i < argv.length) {
35
+ const arg = argv[i];
36
+ if (arg === '--help' || arg === '-h') {
37
+ options.help = true;
38
+ i++;
39
+ }
40
+ else if (arg === '--no-terminal') {
41
+ options.noTerminal = true;
42
+ i++;
43
+ }
44
+ else if (arg === '--port') {
45
+ options.port = parsePort(argv[++i]);
46
+ i++;
47
+ }
48
+ else if (arg === '--host') {
49
+ options.host = argv[++i];
50
+ i++;
51
+ }
52
+ else if (arg === '--token') {
53
+ options.token = argv[++i];
54
+ i++;
55
+ }
56
+ else if (arg === '--name') {
57
+ options.name = argv[++i];
58
+ i++;
59
+ }
60
+ else if (arg === '--') {
61
+ // Stop parsing, pass all remaining args to claude
62
+ options.claudeArgs.push(...argv.slice(i + 1));
63
+ break;
64
+ }
65
+ else if (arg.startsWith('--port=')) {
66
+ options.port = parsePort(arg.split('=')[1]);
67
+ i++;
68
+ }
69
+ else if (arg.startsWith('--host=')) {
70
+ options.host = arg.split('=')[1];
71
+ i++;
72
+ }
73
+ else if (arg.startsWith('--token=')) {
74
+ options.token = arg.split('=')[1];
75
+ i++;
76
+ }
77
+ else if (arg.startsWith('--name=')) {
78
+ options.name = arg.split('=')[1];
79
+ i++;
80
+ }
81
+ else {
82
+ // Unknown arg: pass to claude
83
+ options.claudeArgs.push(arg);
84
+ i++;
85
+ }
86
+ }
87
+ return options;
88
+ }
89
+ export function showHelp() {
90
+ console.log(`
91
+ Claude Code Remote - 在局域网内通过手机远程控制 Claude Code
92
+
93
+ 用法:
94
+ claude-remote [options] [--] [claude args...]
95
+ claude-remote attach <port|name> # 接管指定实例
96
+
97
+ 代理层选项:
98
+ --port <number> 服务端口 (默认: 3000, 被占用时自动递增)
99
+ --host <ip> 绑定地址 (默认: 自动检测 LAN IP)
100
+ --token <string> 认证 Token (默认: 共享 Token)
101
+ --name <string> 实例名称 (默认: 工作目录名)
102
+ --no-terminal 无终端模式(web 创建的实例使用)
103
+ --help, -h 显示帮助信息
104
+
105
+ 配置文件:
106
+ ~/.claude-remote/config.json 用户配置文件 (JSON 格式)
107
+
108
+ 可配置项:
109
+ port 服务端口
110
+ host 绑定地址
111
+ token 固定 Token (覆盖共享 Token)
112
+ instanceName 实例名称
113
+ claudeCommand Claude CLI 命令路径 (默认: claude)
114
+ claudeCwd Claude 工作目录 (默认: 当前目录)
115
+ claudeArgs Claude CLI 额外参数 (数组)
116
+ maxBufferLines 输出缓冲区行数 (默认: 10000)
117
+ workspaces 预设工作目录列表 (数组)
118
+ defaultClaudeArgs 默认 Claude 参数 (数组)
119
+
120
+ 示例:
121
+ claude-remote # 启动 Claude Code
122
+ claude-remote chat # 启动 Claude Code 并进入 chat 模式
123
+ claude-remote --port 8080 # 使用端口 8080
124
+ claude-remote --name api # 自定义实例名称
125
+ claude-remote -- --dangerously-skip-permissions # 透传参数给 claude
126
+ claude-remote attach 3001 # 接管端口 3001 的实例
127
+ claude-remote attach myproject # 接管名为 myproject 的实例
128
+
129
+ 更多 Claude Code 选项请运行:claude --help
130
+ `);
131
+ }
132
+ //# sourceMappingURL=cli-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-utils.js","sourceRoot":"","sources":["../src/cli-utils.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * claude-remote CLI entry point
4
+ *
5
+ * 用法:
6
+ * claude-remote [options] [--] [claude args...]
7
+ * claude-remote attach <port|name>
8
+ *
9
+ * 代理层选项:
10
+ * --port <number> 服务端口 (默认: 3000, 被占用时自动递增)
11
+ * --host <ip> 绑定地址 (默认: 自动检测 LAN IP)
12
+ * --token <string> 认证 Token (默认: 共享 Token)
13
+ * --name <string> 实例名称 (默认: 工作目录名)
14
+ * --help, -h 显示帮助信息
15
+ *
16
+ * 其他所有参数透传给 claude 命令。
17
+ *
18
+ * 注意:此文件不能有任何静态 import,因为 ESM 会提升它们到模块顶部执行,
19
+ * 导致 CLI_MODE 设置在 logger 模块加载之后才生效。
20
+ */
21
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;GAkBG"}
package/dist/cli.js ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * claude-remote CLI entry point
5
+ *
6
+ * 用法:
7
+ * claude-remote [options] [--] [claude args...]
8
+ * claude-remote attach <port|name>
9
+ *
10
+ * 代理层选项:
11
+ * --port <number> 服务端口 (默认: 3000, 被占用时自动递增)
12
+ * --host <ip> 绑定地址 (默认: 自动检测 LAN IP)
13
+ * --token <string> 认证 Token (默认: 共享 Token)
14
+ * --name <string> 实例名称 (默认: 工作目录名)
15
+ * --help, -h 显示帮助信息
16
+ *
17
+ * 其他所有参数透传给 claude 命令。
18
+ *
19
+ * 注意:此文件不能有任何静态 import,因为 ESM 会提升它们到模块顶部执行,
20
+ * 导致 CLI_MODE 设置在 logger 模块加载之后才生效。
21
+ */
22
+ // 必须在任何模块加载之前设置 CLI_MODE,因为 logger.ts 在模块顶层读取此变量
23
+ process.env.CLI_MODE = 'true';
24
+ // 所有模块必须使用动态 import
25
+ void (async () => {
26
+ const { fileURLToPath } = await import('node:url');
27
+ const { parseCliArgs, showHelp } = await import('./cli-utils.js');
28
+ const options = parseCliArgs(process.argv);
29
+ if (options.help) {
30
+ showHelp();
31
+ process.exit(0);
32
+ }
33
+ // 处理 attach 子命令
34
+ if (options.attach) {
35
+ const { attachInstance } = await import('./attach.js');
36
+ await attachInstance({ target: options.attach });
37
+ return;
38
+ }
39
+ // Set NO_TERMINAL flag for headless mode
40
+ if (options.noTerminal) {
41
+ process.env.NO_TERMINAL = 'true';
42
+ }
43
+ // 动态导入 CliOverrides 类型(仅类型,编译后会移除)
44
+ const { loadConfig, createSessionCookieName } = await import('./config.js');
45
+ // Build CLI overrides for config
46
+ const cliOverrides = {
47
+ port: options.port,
48
+ host: options.host,
49
+ token: options.token,
50
+ instanceName: options.name,
51
+ claudeArgs: options.claudeArgs.length > 0 ? options.claudeArgs : undefined,
52
+ noTerminal: options.noTerminal,
53
+ };
54
+ // 动态加载 startServer
55
+ const { startServer } = await import('./index.js');
56
+ await startServer(cliOverrides);
57
+ })();
58
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AACA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,iDAAiD;AACjD,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC;AAE9B,oBAAoB;AACpB,KAAK,CAAC,KAAK,IAAI,EAAE;IACf,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAEnD,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAElE,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,QAAQ,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,gBAAgB;IAChB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACvD,MAAM,cAAc,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IAED,yCAAyC;IACzC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC;IACnC,CAAC;IAED,mCAAmC;IACnC,MAAM,EAAE,UAAU,EAAE,uBAAuB,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IAE5E,iCAAiC;IACjC,MAAM,YAAY,GAAG;QACnB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,YAAY,EAAE,OAAO,CAAC,IAAI;QAC1B,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;QAC1E,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC;IAEF,mBAAmB;IACnB,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IACnD,MAAM,WAAW,CAAC,YAAY,CAAC,CAAC;AAClC,CAAC,CAAC,EAAE,CAAC"}