@agent-link/server 0.1.187 → 0.1.189

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 (76) hide show
  1. package/dist/auth-manager.d.ts +36 -0
  2. package/dist/auth-manager.js +96 -0
  3. package/dist/auth-manager.js.map +1 -0
  4. package/dist/http.d.ts +4 -0
  5. package/dist/http.js +85 -0
  6. package/dist/http.js.map +1 -0
  7. package/dist/index.js +5 -84
  8. package/dist/index.js.map +1 -1
  9. package/dist/message-relay.d.ts +17 -0
  10. package/dist/message-relay.js +23 -0
  11. package/dist/message-relay.js.map +1 -0
  12. package/dist/session-manager.d.ts +44 -0
  13. package/dist/session-manager.js +83 -0
  14. package/dist/session-manager.js.map +1 -0
  15. package/dist/ws-agent.js +19 -27
  16. package/dist/ws-agent.js.map +1 -1
  17. package/dist/ws-client.js +31 -37
  18. package/dist/ws-client.js.map +1 -1
  19. package/package.json +3 -3
  20. package/web/dist/assets/index-DIO7Hox0.js +320 -0
  21. package/web/dist/assets/index-DIO7Hox0.js.map +1 -0
  22. package/web/dist/assets/index-Y1FN_mFe.css +1 -0
  23. package/web/{index.html → dist/index.html} +2 -19
  24. package/dist/auth.d.ts +0 -13
  25. package/dist/auth.js +0 -65
  26. package/dist/auth.js.map +0 -1
  27. package/dist/context.d.ts +0 -52
  28. package/dist/context.js +0 -60
  29. package/dist/context.js.map +0 -1
  30. package/web/app.js +0 -2881
  31. package/web/css/ask-question.css +0 -333
  32. package/web/css/base.css +0 -270
  33. package/web/css/btw.css +0 -148
  34. package/web/css/chat.css +0 -176
  35. package/web/css/file-browser.css +0 -499
  36. package/web/css/input.css +0 -671
  37. package/web/css/loop.css +0 -674
  38. package/web/css/markdown.css +0 -169
  39. package/web/css/responsive.css +0 -314
  40. package/web/css/sidebar.css +0 -593
  41. package/web/css/team.css +0 -1277
  42. package/web/css/tools.css +0 -327
  43. package/web/encryption.js +0 -56
  44. package/web/modules/appHelpers.js +0 -100
  45. package/web/modules/askQuestion.js +0 -63
  46. package/web/modules/backgroundRouting.js +0 -269
  47. package/web/modules/connection.js +0 -731
  48. package/web/modules/fileAttachments.js +0 -125
  49. package/web/modules/fileBrowser.js +0 -398
  50. package/web/modules/filePreview.js +0 -213
  51. package/web/modules/i18n.js +0 -101
  52. package/web/modules/loop.js +0 -338
  53. package/web/modules/loopTemplates.js +0 -110
  54. package/web/modules/markdown.js +0 -83
  55. package/web/modules/messageHelpers.js +0 -206
  56. package/web/modules/sidebar.js +0 -402
  57. package/web/modules/streaming.js +0 -116
  58. package/web/modules/team.js +0 -396
  59. package/web/modules/teamTemplates.js +0 -360
  60. package/web/vendor/highlight.min.js +0 -1213
  61. package/web/vendor/marked.min.js +0 -6
  62. package/web/vendor/nacl-fast.min.js +0 -1
  63. package/web/vendor/nacl-util.min.js +0 -1
  64. package/web/vendor/pako.min.js +0 -2
  65. package/web/vendor/vue.global.prod.js +0 -13
  66. /package/web/{favicon.svg → dist/favicon.svg} +0 -0
  67. /package/web/{images → dist/images}/chat-iPad.webp +0 -0
  68. /package/web/{images → dist/images}/chat-iPhone.webp +0 -0
  69. /package/web/{images → dist/images}/loop-iPad.webp +0 -0
  70. /package/web/{images → dist/images}/team-iPad.webp +0 -0
  71. /package/web/{landing.html → dist/landing.html} +0 -0
  72. /package/web/{landing.zh.html → dist/landing.zh.html} +0 -0
  73. /package/web/{locales → dist/locales}/en.json +0 -0
  74. /package/web/{locales → dist/locales}/zh.json +0 -0
  75. /package/web/{vendor → dist/vendor}/github-dark.min.css +0 -0
  76. /package/web/{vendor → dist/vendor}/github.min.css +0 -0
@@ -0,0 +1,36 @@
1
+ export interface AuthAttemptState {
2
+ failures: number;
3
+ lockedUntil: Date | null;
4
+ }
5
+ export declare class AuthManager {
6
+ readonly authAttempts: Map<string, AuthAttemptState>;
7
+ readonly pendingAuth: Map<string, string>;
8
+ readonly sessionAuth: Map<string, {
9
+ passwordHash: string;
10
+ passwordSalt: string;
11
+ }>;
12
+ private readonly serverSecret;
13
+ hashPassword(password: string): {
14
+ hash: string;
15
+ salt: string;
16
+ };
17
+ verifyPassword(submitted: string, storedHash: string, storedSalt: string): boolean;
18
+ setSessionPassword(sessionId: string, hash: string, salt: string): void;
19
+ getSessionAuth(sessionId: string): {
20
+ passwordHash: string;
21
+ passwordSalt: string;
22
+ } | undefined;
23
+ requiresAuth(sessionId: string): boolean;
24
+ generateAuthToken(sessionId: string): string;
25
+ verifyAuthToken(token: string, expectedSessionId: string): boolean;
26
+ isLocked(sessionId: string): boolean;
27
+ recordFailure(sessionId: string): {
28
+ locked: boolean;
29
+ remaining: number;
30
+ };
31
+ clearFailures(sessionId: string): void;
32
+ setPending(clientId: string, sessionId: string): void;
33
+ getPending(clientId: string): string | undefined;
34
+ removePending(clientId: string): void;
35
+ }
36
+ export declare const auth: AuthManager;
@@ -0,0 +1,96 @@
1
+ import { scryptSync, randomBytes, timingSafeEqual, createHmac } from 'crypto';
2
+ const MAX_FAILURES = 5;
3
+ const LOCKOUT_MS = 15 * 60 * 1000; // 15 minutes
4
+ const TOKEN_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
5
+ export class AuthManager {
6
+ authAttempts = new Map();
7
+ pendingAuth = new Map();
8
+ sessionAuth = new Map();
9
+ serverSecret = randomBytes(32);
10
+ // --- Password ---
11
+ hashPassword(password) {
12
+ const salt = randomBytes(16).toString('base64');
13
+ const hash = scryptSync(password, salt, 32).toString('base64');
14
+ return { hash, salt };
15
+ }
16
+ verifyPassword(submitted, storedHash, storedSalt) {
17
+ const computed = scryptSync(submitted, storedSalt, 32);
18
+ const expected = Buffer.from(storedHash, 'base64');
19
+ if (computed.length !== expected.length)
20
+ return false;
21
+ return timingSafeEqual(computed, expected);
22
+ }
23
+ // --- Session password ---
24
+ setSessionPassword(sessionId, hash, salt) {
25
+ this.sessionAuth.set(sessionId, { passwordHash: hash, passwordSalt: salt });
26
+ }
27
+ getSessionAuth(sessionId) {
28
+ return this.sessionAuth.get(sessionId);
29
+ }
30
+ requiresAuth(sessionId) {
31
+ const a = this.sessionAuth.get(sessionId);
32
+ return !!(a?.passwordHash && a?.passwordSalt);
33
+ }
34
+ // --- Token ---
35
+ generateAuthToken(sessionId) {
36
+ const ts = Date.now().toString();
37
+ const hmac = createHmac('sha256', this.serverSecret).update(`${sessionId}:${ts}`).digest('base64url');
38
+ return `${sessionId}:${ts}:${hmac}`;
39
+ }
40
+ verifyAuthToken(token, expectedSessionId) {
41
+ const idx1 = token.indexOf(':');
42
+ const idx2 = token.indexOf(':', idx1 + 1);
43
+ if (idx1 === -1 || idx2 === -1)
44
+ return false;
45
+ const sessionId = token.slice(0, idx1);
46
+ const ts = token.slice(idx1 + 1, idx2);
47
+ const hmac = token.slice(idx2 + 1);
48
+ if (sessionId !== expectedSessionId)
49
+ return false;
50
+ const age = Date.now() - parseInt(ts, 10);
51
+ if (isNaN(age) || age < 0 || age > TOKEN_TTL_MS)
52
+ return false;
53
+ const expected = createHmac('sha256', this.serverSecret).update(`${sessionId}:${ts}`).digest('base64url');
54
+ return hmac === expected;
55
+ }
56
+ // --- Brute-force protection ---
57
+ isLocked(sessionId) {
58
+ const state = this.authAttempts.get(sessionId);
59
+ if (!state?.lockedUntil)
60
+ return false;
61
+ if (Date.now() > state.lockedUntil.getTime()) {
62
+ this.authAttempts.delete(sessionId);
63
+ return false;
64
+ }
65
+ return true;
66
+ }
67
+ recordFailure(sessionId) {
68
+ let state = this.authAttempts.get(sessionId);
69
+ if (!state) {
70
+ state = { failures: 0, lockedUntil: null };
71
+ this.authAttempts.set(sessionId, state);
72
+ }
73
+ state.failures++;
74
+ if (state.failures >= MAX_FAILURES) {
75
+ state.lockedUntil = new Date(Date.now() + LOCKOUT_MS);
76
+ return { locked: true, remaining: 0 };
77
+ }
78
+ return { locked: false, remaining: MAX_FAILURES - state.failures };
79
+ }
80
+ clearFailures(sessionId) {
81
+ this.authAttempts.delete(sessionId);
82
+ }
83
+ // --- Pending auth ---
84
+ setPending(clientId, sessionId) {
85
+ this.pendingAuth.set(clientId, sessionId);
86
+ }
87
+ getPending(clientId) {
88
+ return this.pendingAuth.get(clientId);
89
+ }
90
+ removePending(clientId) {
91
+ this.pendingAuth.delete(clientId);
92
+ }
93
+ }
94
+ // Singleton instance
95
+ export const auth = new AuthManager();
96
+ //# sourceMappingURL=auth-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-manager.js","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import express from 'express';
2
+ export declare function createApp(webDir: string, pkg: {
3
+ version: string;
4
+ }, startedAt: Date): express.Express;
package/dist/http.js ADDED
@@ -0,0 +1,85 @@
1
+ import express from 'express';
2
+ import { join } from 'path';
3
+ import { sessions } from './session-manager.js';
4
+ export function createApp(webDir, pkg, startedAt) {
5
+ const app = express();
6
+ // Landing page at root
7
+ app.get('/', (_req, res) => {
8
+ res.sendFile(join(webDir, 'landing.html'));
9
+ });
10
+ // Chinese landing page
11
+ app.get('/zh', (_req, res) => {
12
+ res.sendFile(join(webDir, 'landing.zh.html'));
13
+ });
14
+ // Serve index.html with no-store (Vite hashed filenames handle cache-busting)
15
+ const sendIndexHtml = (_req, res) => {
16
+ res.setHeader('Cache-Control', 'no-store');
17
+ res.sendFile(join(webDir, 'index.html'));
18
+ };
19
+ // Intercept /index.html before express.static to ensure no-store is applied
20
+ app.get('/index.html', sendIndexHtml);
21
+ // Serve static assets from web/ — hashed assets are immutable, others use no-cache
22
+ app.use(express.static(webDir, {
23
+ setHeaders(res, filePath) {
24
+ if (filePath.includes('assets')) {
25
+ // Vite-hashed files (e.g. index-CqWVRN_z.js) — immutable
26
+ res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
27
+ }
28
+ else if (filePath.endsWith('.html')) {
29
+ res.setHeader('Cache-Control', 'no-store');
30
+ }
31
+ else {
32
+ res.setHeader('Cache-Control', 'no-cache');
33
+ }
34
+ },
35
+ }));
36
+ // SPA fallback: /s/:sessionId → serve versioned index.html
37
+ app.get('/s/:sessionId', sendIndexHtml);
38
+ // Health check
39
+ app.get('/api/health', (_req, res) => {
40
+ res.json({
41
+ status: 'ok',
42
+ agents: sessions.agents.size,
43
+ webClients: sessions.webClients.size,
44
+ timestamp: new Date().toISOString(),
45
+ });
46
+ });
47
+ // Server status (aggregate stats, no agent details exposed)
48
+ app.get('/api/status', (_req, res) => {
49
+ const mem = process.memoryUsage();
50
+ res.json({
51
+ server: {
52
+ version: pkg.version,
53
+ startedAt: startedAt.toISOString(),
54
+ uptimeSeconds: Math.floor((Date.now() - startedAt.getTime()) / 1000),
55
+ memoryMB: Math.round(mem.rss / 1024 / 1024),
56
+ },
57
+ agents: {
58
+ connected: sessions.agents.size,
59
+ },
60
+ webClients: {
61
+ connected: sessions.webClients.size,
62
+ },
63
+ });
64
+ });
65
+ // Session info API (web client fetches this to know agent details)
66
+ app.get('/api/session/:sessionId', (req, res) => {
67
+ const { sessionId } = req.params;
68
+ const agent = sessions.getAgentBySession(sessionId);
69
+ if (agent) {
70
+ res.json({
71
+ sessionId,
72
+ agent: {
73
+ name: agent.name,
74
+ workDir: agent.workDir,
75
+ connectedAt: agent.connectedAt,
76
+ },
77
+ });
78
+ }
79
+ else {
80
+ res.status(404).json({ error: 'Session not found' });
81
+ }
82
+ });
83
+ return app;
84
+ }
85
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,11 +1,10 @@
1
- import express from 'express';
2
1
  import { createServer } from 'http';
3
2
  import { createRequire } from 'module';
4
- import { readFileSync } from 'fs';
5
3
  import { WebSocket, WebSocketServer } from 'ws';
6
4
  import { fileURLToPath } from 'url';
7
5
  import { dirname, join } from 'path';
8
- import { agents, webClients, cleanupDeadConnections } from './context.js';
6
+ import { sessions } from './session-manager.js';
7
+ import { createApp } from './http.js';
9
8
  import { handleAgentConnection } from './ws-agent.js';
10
9
  import { handleWebConnection } from './ws-client.js';
11
10
  import { saveServerRuntimeState, clearServerRuntimeState } from './config.js';
@@ -14,89 +13,11 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
14
13
  const require = createRequire(import.meta.url);
15
14
  const pkg = require('../package.json');
16
15
  const startedAt = new Date();
17
- // Build versioned index.html at startup (cache-busting for browsers like iPhone Safari)
18
- const versionTag = `v=${pkg.version}`;
19
- const indexHtml = readFileSync(join(__dirname, '../web/index.html'), 'utf-8')
20
- // Version-stamp local asset URLs in src="..." and href="..." attributes
21
- .replace(/((?:src|href)\s*=\s*")(\/(?!\/)[^"?]+\.(?:js|css))(")/g, `$1$2?${versionTag}$3`)
22
- // Version-stamp JS string literals referencing local .css/.js paths (e.g. theme switching)
23
- .replace(/(')(\/(?!\/)[^'?]+\.(?:js|css))(')/g, `$1$2?${versionTag}$3`);
24
16
  const PORT = parseInt(process.env.PORT || '3456', 10);
25
- const app = express();
17
+ const webDir = join(__dirname, '../web/dist');
18
+ const app = createApp(webDir, pkg, startedAt);
26
19
  const server = createServer(app);
27
20
  const wss = new WebSocketServer({ server });
28
- const webDir = join(__dirname, '../web');
29
- // Landing page at root
30
- app.get('/', (_req, res) => {
31
- res.sendFile(join(webDir, 'landing.html'));
32
- });
33
- // Chinese landing page
34
- app.get('/zh', (_req, res) => {
35
- res.sendFile(join(webDir, 'landing.zh.html'));
36
- });
37
- // Serve versioned index.html with no-store (cache-busting for browsers like iPhone Safari)
38
- const sendIndexHtml = (_req, res) => {
39
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
40
- res.setHeader('Cache-Control', 'no-store');
41
- res.send(indexHtml);
42
- };
43
- // Intercept /index.html before express.static to ensure versioned HTML is served
44
- app.get('/index.html', sendIndexHtml);
45
- // Serve static assets from web/ with no-cache for JS/CSS (ensures updates are picked up)
46
- app.use(express.static(webDir, {
47
- setHeaders(res, filePath) {
48
- if (filePath.endsWith('.js') || filePath.endsWith('.css') || filePath.endsWith('.html')) {
49
- res.setHeader('Cache-Control', 'no-cache');
50
- }
51
- },
52
- }));
53
- // SPA fallback: /s/:sessionId → serve versioned index.html
54
- app.get('/s/:sessionId', sendIndexHtml);
55
- // Health check
56
- app.get('/api/health', (_req, res) => {
57
- res.json({
58
- status: 'ok',
59
- agents: agents.size,
60
- webClients: webClients.size,
61
- timestamp: new Date().toISOString(),
62
- });
63
- });
64
- // Server status (aggregate stats, no agent details exposed)
65
- app.get('/api/status', (_req, res) => {
66
- const mem = process.memoryUsage();
67
- res.json({
68
- server: {
69
- version: pkg.version,
70
- startedAt: startedAt.toISOString(),
71
- uptimeSeconds: Math.floor((Date.now() - startedAt.getTime()) / 1000),
72
- memoryMB: Math.round(mem.rss / 1024 / 1024),
73
- },
74
- agents: {
75
- connected: agents.size,
76
- },
77
- webClients: {
78
- connected: webClients.size,
79
- },
80
- });
81
- });
82
- // Session info API (web client fetches this to know agent details)
83
- app.get('/api/session/:sessionId', (req, res) => {
84
- const { sessionId } = req.params;
85
- for (const [, agent] of agents) {
86
- if (agent.sessionId === sessionId) {
87
- res.json({
88
- sessionId,
89
- agent: {
90
- name: agent.name,
91
- workDir: agent.workDir,
92
- connectedAt: agent.connectedAt,
93
- },
94
- });
95
- return;
96
- }
97
- }
98
- res.status(404).json({ error: 'Session not found' });
99
- });
100
21
  // WebSocket routing: agent or web client
101
22
  wss.on('connection', (ws, req) => {
102
23
  const url = new URL(req.url || '/', `http://${req.headers.host}`);
@@ -114,7 +35,7 @@ wss.on('connection', (ws, req) => {
114
35
  });
115
36
  // Heartbeat every 30s to detect dead connections
116
37
  setInterval(() => {
117
- cleanupDeadConnections((client, msg) => {
38
+ sessions.cleanupDeadConnections((client, msg) => {
118
39
  if (client.ws.readyState === WebSocket.OPEN) {
119
40
  encryptAndSend(client.ws, msg, client.sessionKey);
120
41
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Per-ID ordered message relay queue.
3
+ * Guarantees messages for the same ID are processed sequentially,
4
+ * preventing out-of-order delivery caused by async encryption/compression.
5
+ */
6
+ export declare class MessageRelay {
7
+ private queues;
8
+ /**
9
+ * Enqueue a message handler for the given ID.
10
+ * Handlers for the same ID execute in order; different IDs run concurrently.
11
+ */
12
+ enqueue(id: string, handler: () => Promise<void>): void;
13
+ /**
14
+ * Remove the queue for the given ID (call on disconnect).
15
+ */
16
+ cleanup(id: string): void;
17
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Per-ID ordered message relay queue.
3
+ * Guarantees messages for the same ID are processed sequentially,
4
+ * preventing out-of-order delivery caused by async encryption/compression.
5
+ */
6
+ export class MessageRelay {
7
+ queues = new Map();
8
+ /**
9
+ * Enqueue a message handler for the given ID.
10
+ * Handlers for the same ID execute in order; different IDs run concurrently.
11
+ */
12
+ enqueue(id, handler) {
13
+ const prev = this.queues.get(id) || Promise.resolve();
14
+ this.queues.set(id, prev.then(handler).catch(() => { }));
15
+ }
16
+ /**
17
+ * Remove the queue for the given ID (call on disconnect).
18
+ */
19
+ cleanup(id) {
20
+ this.queues.delete(id);
21
+ }
22
+ }
23
+ //# sourceMappingURL=message-relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-relay.js","sourceRoot":"","sources":["../src/message-relay.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,YAAY;IACf,MAAM,GAAG,IAAI,GAAG,EAAyB,CAAC;IAElD;;;OAGG;IACH,OAAO,CAAC,EAAU,EAAE,OAA4B;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACtD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,EAAU;QAChB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,44 @@
1
+ import { WebSocket } from 'ws';
2
+ export interface AgentSession {
3
+ ws: WebSocket;
4
+ agentId: string;
5
+ name: string;
6
+ hostname: string;
7
+ workDir: string;
8
+ version: string;
9
+ sessionId: string;
10
+ sessionKey: Uint8Array | null;
11
+ connectedAt: Date;
12
+ isAlive: boolean;
13
+ passwordHash: string | null;
14
+ passwordSalt: string | null;
15
+ }
16
+ export interface WebClient {
17
+ ws: WebSocket;
18
+ clientId: string;
19
+ sessionId: string;
20
+ sessionKey: Uint8Array | null;
21
+ connectedAt: Date;
22
+ isAlive: boolean;
23
+ }
24
+ export declare class SessionManager {
25
+ readonly agents: Map<string, AgentSession>;
26
+ readonly sessionToAgent: Map<string, string>;
27
+ readonly webClients: Map<string, WebClient>;
28
+ generateSessionId(): string;
29
+ registerAgent(agentId: string, agent: AgentSession): void;
30
+ removeAgent(agentId: string): void;
31
+ getAgent(agentId: string): AgentSession | undefined;
32
+ getAgentBySession(sessionId: string): AgentSession | undefined;
33
+ registerClient(clientId: string, client: WebClient): void;
34
+ removeClient(clientId: string): void;
35
+ getClient(clientId: string): WebClient | undefined;
36
+ getClientsForSession(sessionId: string): WebClient[];
37
+ cleanupDeadConnections(notifyFn: (client: WebClient, msg: {
38
+ type: string;
39
+ }) => void): {
40
+ removedAgents: string[];
41
+ removedClients: string[];
42
+ };
43
+ }
44
+ export declare const sessions: SessionManager;
@@ -0,0 +1,83 @@
1
+ import { randomBytes } from 'crypto';
2
+ export class SessionManager {
3
+ agents = new Map();
4
+ sessionToAgent = new Map();
5
+ webClients = new Map();
6
+ generateSessionId() {
7
+ return randomBytes(12).toString('base64url');
8
+ }
9
+ // --- Agent operations ---
10
+ registerAgent(agentId, agent) {
11
+ this.agents.set(agentId, agent);
12
+ this.sessionToAgent.set(agent.sessionId, agentId);
13
+ }
14
+ removeAgent(agentId) {
15
+ const agent = this.agents.get(agentId);
16
+ if (agent) {
17
+ this.sessionToAgent.delete(agent.sessionId);
18
+ this.agents.delete(agentId);
19
+ }
20
+ }
21
+ getAgent(agentId) {
22
+ return this.agents.get(agentId);
23
+ }
24
+ getAgentBySession(sessionId) {
25
+ const agentId = this.sessionToAgent.get(sessionId);
26
+ return agentId ? this.agents.get(agentId) : undefined;
27
+ }
28
+ // --- Client operations ---
29
+ registerClient(clientId, client) {
30
+ this.webClients.set(clientId, client);
31
+ }
32
+ removeClient(clientId) {
33
+ this.webClients.delete(clientId);
34
+ }
35
+ getClient(clientId) {
36
+ return this.webClients.get(clientId);
37
+ }
38
+ getClientsForSession(sessionId) {
39
+ const result = [];
40
+ for (const [, client] of this.webClients) {
41
+ if (client.sessionId === sessionId) {
42
+ result.push(client);
43
+ }
44
+ }
45
+ return result;
46
+ }
47
+ // --- Heartbeat ---
48
+ cleanupDeadConnections(notifyFn) {
49
+ const removedAgents = [];
50
+ const removedClients = [];
51
+ for (const [agentId, agent] of this.agents) {
52
+ if (!agent.isAlive) {
53
+ console.log(`[Heartbeat] Agent ${agent.name} timed out`);
54
+ agent.ws.terminate();
55
+ this.sessionToAgent.delete(agent.sessionId);
56
+ this.agents.delete(agentId);
57
+ removedAgents.push(agentId);
58
+ for (const [, client] of this.webClients) {
59
+ if (client.sessionId === agent.sessionId) {
60
+ notifyFn(client, { type: 'agent_disconnected' });
61
+ }
62
+ }
63
+ continue;
64
+ }
65
+ agent.isAlive = false;
66
+ agent.ws.ping();
67
+ }
68
+ for (const [clientId, client] of this.webClients) {
69
+ if (!client.isAlive) {
70
+ client.ws.terminate();
71
+ this.webClients.delete(clientId);
72
+ removedClients.push(clientId);
73
+ continue;
74
+ }
75
+ client.isAlive = false;
76
+ client.ws.ping();
77
+ }
78
+ return { removedAgents, removedClients };
79
+ }
80
+ }
81
+ // Singleton instance for backward compatibility
82
+ export const sessions = new SessionManager();
83
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../src/session-manager.ts"],"names":[],"mappings":"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"}