expxagents 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/dist/__tests__/cli.test.d.ts +1 -0
  2. package/dist/__tests__/cli.test.js +23 -0
  3. package/dist/cli/src/commands/init.js +12 -2
  4. package/dist/cli/src/commands/virtual-office.js +50 -5
  5. package/dist/cli/src/utils/config.d.ts +5 -0
  6. package/dist/cli/src/utils/config.js +1 -1
  7. package/dist/commands/create.d.ts +1 -0
  8. package/dist/commands/create.js +34 -0
  9. package/dist/commands/init.d.ts +1 -0
  10. package/dist/commands/init.js +58 -0
  11. package/dist/commands/install.d.ts +1 -0
  12. package/dist/commands/install.js +16 -0
  13. package/dist/commands/list.d.ts +1 -0
  14. package/dist/commands/list.js +58 -0
  15. package/dist/commands/run.d.ts +1 -0
  16. package/dist/commands/run.js +173 -0
  17. package/dist/commands/server.d.ts +1 -0
  18. package/dist/commands/server.js +22 -0
  19. package/dist/commands/stop.d.ts +1 -0
  20. package/dist/commands/stop.js +23 -0
  21. package/dist/commands/uninstall.d.ts +1 -0
  22. package/dist/commands/uninstall.js +12 -0
  23. package/dist/dashboard/assets/BufferResource-Cf2Uo4_f.js +185 -0
  24. package/dist/dashboard/assets/CanvasRenderer-DFdMBORe.js +1 -0
  25. package/dist/dashboard/assets/RenderTargetSystem-CMh8XRf_.js +172 -0
  26. package/dist/dashboard/assets/WebGLRenderer-B5huw0RY.js +156 -0
  27. package/dist/dashboard/assets/WebGPURenderer-BdIKurkV.js +41 -0
  28. package/dist/dashboard/assets/browserAll-BjVJrv1L.js +14 -0
  29. package/dist/dashboard/assets/index-DwTFo09S.js +344 -0
  30. package/dist/dashboard/assets/webworkerAll-DMtK63GZ.js +83 -0
  31. package/dist/dashboard/index.html +16 -0
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.js +47 -0
  34. package/dist/server/api/health-routes.d.ts +3 -0
  35. package/dist/server/api/health-routes.d.ts.map +1 -0
  36. package/dist/server/api/health-routes.js +6 -0
  37. package/dist/server/api/health-routes.js.map +1 -0
  38. package/dist/server/api/squads-routes.d.ts +7 -0
  39. package/dist/server/api/squads-routes.d.ts.map +1 -0
  40. package/dist/server/api/squads-routes.js +91 -0
  41. package/dist/server/api/squads-routes.js.map +1 -0
  42. package/dist/server/api/users-routes.d.ts +8 -0
  43. package/dist/server/api/users-routes.d.ts.map +1 -0
  44. package/dist/server/api/users-routes.js +45 -0
  45. package/dist/server/api/users-routes.js.map +1 -0
  46. package/dist/server/app.d.ts +7 -0
  47. package/dist/server/app.d.ts.map +1 -0
  48. package/dist/server/app.js +109 -0
  49. package/dist/server/app.js.map +1 -0
  50. package/dist/server/auth/auth-middleware.d.ts +13 -0
  51. package/dist/server/auth/auth-middleware.d.ts.map +1 -0
  52. package/dist/server/auth/auth-middleware.js +25 -0
  53. package/dist/server/auth/auth-middleware.js.map +1 -0
  54. package/dist/server/auth/auth-routes.d.ts +9 -0
  55. package/dist/server/auth/auth-routes.d.ts.map +1 -0
  56. package/dist/server/auth/auth-routes.js +149 -0
  57. package/dist/server/auth/auth-routes.js.map +1 -0
  58. package/dist/server/auth/jwt.d.ts +14 -0
  59. package/dist/server/auth/jwt.d.ts.map +1 -0
  60. package/dist/server/auth/jwt.js +16 -0
  61. package/dist/server/auth/jwt.js.map +1 -0
  62. package/dist/server/auth/password.d.ts +3 -0
  63. package/dist/server/auth/password.d.ts.map +1 -0
  64. package/dist/server/auth/password.js +9 -0
  65. package/dist/server/auth/password.js.map +1 -0
  66. package/dist/server/bridge/__tests__/chat-handler.test.d.ts +2 -0
  67. package/dist/server/bridge/__tests__/chat-handler.test.d.ts.map +1 -0
  68. package/dist/server/bridge/__tests__/chat-handler.test.js +132 -0
  69. package/dist/server/bridge/__tests__/chat-handler.test.js.map +1 -0
  70. package/dist/server/bridge/__tests__/chat-integration.test.d.ts +2 -0
  71. package/dist/server/bridge/__tests__/chat-integration.test.d.ts.map +1 -0
  72. package/dist/server/bridge/__tests__/chat-integration.test.js +141 -0
  73. package/dist/server/bridge/__tests__/chat-integration.test.js.map +1 -0
  74. package/dist/server/bridge/__tests__/claude-bridge.test.d.ts +2 -0
  75. package/dist/server/bridge/__tests__/claude-bridge.test.d.ts.map +1 -0
  76. package/dist/server/bridge/__tests__/claude-bridge.test.js +223 -0
  77. package/dist/server/bridge/__tests__/claude-bridge.test.js.map +1 -0
  78. package/dist/server/bridge/__tests__/conversation.test.d.ts +2 -0
  79. package/dist/server/bridge/__tests__/conversation.test.d.ts.map +1 -0
  80. package/dist/server/bridge/__tests__/conversation.test.js +168 -0
  81. package/dist/server/bridge/__tests__/conversation.test.js.map +1 -0
  82. package/dist/server/bridge/__tests__/stream-parser.test.d.ts +2 -0
  83. package/dist/server/bridge/__tests__/stream-parser.test.d.ts.map +1 -0
  84. package/dist/server/bridge/__tests__/stream-parser.test.js +66 -0
  85. package/dist/server/bridge/__tests__/stream-parser.test.js.map +1 -0
  86. package/dist/server/bridge/chat-handler.d.ts +19 -0
  87. package/dist/server/bridge/chat-handler.d.ts.map +1 -0
  88. package/dist/server/bridge/chat-handler.js +104 -0
  89. package/dist/server/bridge/chat-handler.js.map +1 -0
  90. package/dist/server/bridge/claude-bridge.d.ts +27 -0
  91. package/dist/server/bridge/claude-bridge.d.ts.map +1 -0
  92. package/dist/server/bridge/claude-bridge.js +91 -0
  93. package/dist/server/bridge/claude-bridge.js.map +1 -0
  94. package/dist/server/bridge/conversation.d.ts +44 -0
  95. package/dist/server/bridge/conversation.d.ts.map +1 -0
  96. package/dist/server/bridge/conversation.js +73 -0
  97. package/dist/server/bridge/conversation.js.map +1 -0
  98. package/dist/server/bridge/stream-parser.d.ts +14 -0
  99. package/dist/server/bridge/stream-parser.d.ts.map +1 -0
  100. package/dist/server/bridge/stream-parser.js +26 -0
  101. package/dist/server/bridge/stream-parser.js.map +1 -0
  102. package/dist/server/config.d.ts +10 -0
  103. package/dist/server/config.d.ts.map +1 -0
  104. package/dist/server/config.js +22 -0
  105. package/dist/server/config.js.map +1 -0
  106. package/dist/server/db/__tests__/chat-tables.test.d.ts +2 -0
  107. package/dist/server/db/__tests__/chat-tables.test.d.ts.map +1 -0
  108. package/dist/server/db/__tests__/chat-tables.test.js +82 -0
  109. package/dist/server/db/__tests__/chat-tables.test.js.map +1 -0
  110. package/dist/server/db/connection.d.ts +4 -0
  111. package/dist/server/db/connection.d.ts.map +1 -0
  112. package/dist/server/db/connection.js +21 -0
  113. package/dist/server/db/connection.js.map +1 -0
  114. package/dist/server/db/migrations.d.ts +4 -0
  115. package/dist/server/db/migrations.d.ts.map +1 -0
  116. package/dist/server/db/migrations.js +17 -0
  117. package/dist/server/db/migrations.js.map +1 -0
  118. package/dist/server/db/schema.d.ts +2 -0
  119. package/dist/server/db/schema.d.ts.map +1 -0
  120. package/dist/server/db/schema.js +44 -0
  121. package/dist/server/db/schema.js.map +1 -0
  122. package/dist/server/index.d.ts +2 -0
  123. package/dist/server/index.d.ts.map +1 -0
  124. package/dist/server/index.js +18 -0
  125. package/dist/server/index.js.map +1 -0
  126. package/dist/server/routes/__tests__/conversations.test.d.ts +2 -0
  127. package/dist/server/routes/__tests__/conversations.test.d.ts.map +1 -0
  128. package/dist/server/routes/__tests__/conversations.test.js +94 -0
  129. package/dist/server/routes/__tests__/conversations.test.js.map +1 -0
  130. package/dist/server/routes/conversations.d.ts +8 -0
  131. package/dist/server/routes/conversations.d.ts.map +1 -0
  132. package/dist/server/routes/conversations.js +25 -0
  133. package/dist/server/routes/conversations.js.map +1 -0
  134. package/dist/server/watcher/file-watcher.d.ts +12 -0
  135. package/dist/server/watcher/file-watcher.d.ts.map +1 -0
  136. package/dist/server/watcher/file-watcher.js +68 -0
  137. package/dist/server/watcher/file-watcher.js.map +1 -0
  138. package/dist/server/watcher/state-parser.d.ts +77 -0
  139. package/dist/server/watcher/state-parser.d.ts.map +1 -0
  140. package/dist/server/watcher/state-parser.js +74 -0
  141. package/dist/server/watcher/state-parser.js.map +1 -0
  142. package/dist/server/ws/ws-auth.d.ts +4 -0
  143. package/dist/server/ws/ws-auth.d.ts.map +1 -0
  144. package/dist/server/ws/ws-auth.js +42 -0
  145. package/dist/server/ws/ws-auth.js.map +1 -0
  146. package/dist/server/ws/ws-handler.d.ts +11 -0
  147. package/dist/server/ws/ws-handler.d.ts.map +1 -0
  148. package/dist/server/ws/ws-handler.js +107 -0
  149. package/dist/server/ws/ws-handler.js.map +1 -0
  150. package/dist/server/ws/ws-rooms.d.ts +12 -0
  151. package/dist/server/ws/ws-rooms.d.ts.map +1 -0
  152. package/dist/server/ws/ws-rooms.js +52 -0
  153. package/dist/server/ws/ws-rooms.js.map +1 -0
  154. package/dist/utils/config.d.ts +15 -0
  155. package/dist/utils/config.js +23 -0
  156. package/package.json +16 -5
@@ -0,0 +1,149 @@
1
+ import crypto from 'node:crypto';
2
+ import { hashPassword, verifyPassword } from './password.js';
3
+ import { signAccessToken, signRefreshToken, verifyRefreshToken } from './jwt.js';
4
+ export async function authRoutes(app, opts) {
5
+ const { db, jwtSecret } = opts;
6
+ // --- POST /api/auth/login ---
7
+ app.post('/api/auth/login', {
8
+ config: {
9
+ rateLimit: { max: 5, timeWindow: '1 minute' },
10
+ },
11
+ schema: {
12
+ body: {
13
+ type: 'object',
14
+ required: ['username', 'password'],
15
+ properties: {
16
+ username: { type: 'string', minLength: 1 },
17
+ password: { type: 'string', minLength: 1 },
18
+ },
19
+ },
20
+ },
21
+ }, async (request, reply) => {
22
+ const { username, password } = request.body;
23
+ const user = db.prepare('SELECT * FROM users WHERE username = ?').get(username);
24
+ if (!user || !(await verifyPassword(password, user.password_hash))) {
25
+ return reply.code(401).send({ error: 'Invalid username or password' });
26
+ }
27
+ // Create session
28
+ const sessionId = crypto.randomUUID();
29
+ const refreshToken = signRefreshToken({ sessionId, userId: user.id }, jwtSecret);
30
+ const tokenHash = crypto.createHash('sha256').update(refreshToken).digest('hex');
31
+ const expiresAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString();
32
+ db.prepare('INSERT INTO sessions (id, user_id, token_hash, expires_at, created_at) VALUES (?, ?, ?, ?, ?)').run(sessionId, user.id, tokenHash, expiresAt, new Date().toISOString());
33
+ // Update last_login
34
+ db.prepare('UPDATE users SET last_login = ? WHERE id = ?').run(new Date().toISOString(), user.id);
35
+ // Audit log
36
+ db.prepare('INSERT INTO audit_log (user_id, action, details, created_at) VALUES (?, ?, ?, ?)').run(user.id, 'login', JSON.stringify({ ip: request.ip }), new Date().toISOString());
37
+ const accessToken = signAccessToken({ userId: user.id, role: user.role }, jwtSecret);
38
+ const isSecure = request.protocol === 'https';
39
+ reply
40
+ .setCookie('access_token', accessToken, {
41
+ httpOnly: true,
42
+ secure: isSecure,
43
+ sameSite: 'strict',
44
+ path: '/',
45
+ maxAge: 24 * 60 * 60, // 24h
46
+ })
47
+ .setCookie('refresh_token', refreshToken, {
48
+ httpOnly: true,
49
+ secure: isSecure,
50
+ sameSite: 'strict',
51
+ path: '/api/auth/refresh',
52
+ maxAge: 30 * 24 * 60 * 60, // 30d
53
+ });
54
+ return {
55
+ user: {
56
+ id: user.id,
57
+ username: user.username,
58
+ email: user.email,
59
+ role: user.role,
60
+ },
61
+ };
62
+ });
63
+ // --- POST /api/auth/register (admin only) ---
64
+ app.post('/api/auth/register', {
65
+ preHandler: [app.requireAuth, app.requireRole('admin')],
66
+ schema: {
67
+ body: {
68
+ type: 'object',
69
+ required: ['username', 'password'],
70
+ properties: {
71
+ username: { type: 'string', minLength: 1 },
72
+ password: { type: 'string', minLength: 6 },
73
+ email: { type: 'string' },
74
+ role: { type: 'string', enum: ['admin', 'operator', 'viewer'] },
75
+ },
76
+ },
77
+ },
78
+ }, async (request, reply) => {
79
+ const { username, password, email, role } = request.body;
80
+ const validRoles = ['admin', 'operator', 'viewer'];
81
+ const userRole = role && validRoles.includes(role) ? role : 'operator';
82
+ const existing = db.prepare('SELECT id FROM users WHERE username = ?').get(username);
83
+ if (existing) {
84
+ return reply.code(409).send({ error: 'Username already exists' });
85
+ }
86
+ const id = crypto.randomUUID();
87
+ const passwordHash = await hashPassword(password);
88
+ db.prepare('INSERT INTO users (id, username, email, password_hash, role, created_at) VALUES (?, ?, ?, ?, ?, ?)').run(id, username, email || null, passwordHash, userRole, new Date().toISOString());
89
+ // Audit log
90
+ db.prepare('INSERT INTO audit_log (user_id, action, details, created_at) VALUES (?, ?, ?, ?)').run(request.user.userId, 'create_user', JSON.stringify({ newUserId: id, username, role: userRole }), new Date().toISOString());
91
+ return reply.code(201).send({
92
+ user: { id, username, email: email || null, role: userRole },
93
+ });
94
+ });
95
+ // --- POST /api/auth/refresh ---
96
+ app.post('/api/auth/refresh', async (request, reply) => {
97
+ const refreshToken = request.cookies?.refresh_token;
98
+ if (!refreshToken) {
99
+ return reply.code(401).send({ error: 'Refresh token required' });
100
+ }
101
+ try {
102
+ const payload = verifyRefreshToken(refreshToken, jwtSecret);
103
+ const tokenHash = crypto.createHash('sha256').update(refreshToken).digest('hex');
104
+ const session = db
105
+ .prepare('SELECT * FROM sessions WHERE id = ? AND token_hash = ?')
106
+ .get(payload.sessionId, tokenHash);
107
+ if (!session || new Date(session.expires_at) < new Date()) {
108
+ return reply.code(401).send({ error: 'Invalid or expired session' });
109
+ }
110
+ const user = db.prepare('SELECT * FROM users WHERE id = ?').get(session.user_id);
111
+ if (!user) {
112
+ return reply.code(401).send({ error: 'User not found' });
113
+ }
114
+ const accessToken = signAccessToken({ userId: user.id, role: user.role }, jwtSecret);
115
+ const isSecure = request.protocol === 'https';
116
+ reply.setCookie('access_token', accessToken, {
117
+ httpOnly: true,
118
+ secure: isSecure,
119
+ sameSite: 'strict',
120
+ path: '/',
121
+ maxAge: 24 * 60 * 60,
122
+ });
123
+ return { user: { id: user.id, username: user.username, role: user.role } };
124
+ }
125
+ catch {
126
+ return reply.code(401).send({ error: 'Invalid refresh token' });
127
+ }
128
+ });
129
+ // --- POST /api/auth/logout ---
130
+ app.post('/api/auth/logout', { preHandler: [app.requireAuth] }, async (request, reply) => {
131
+ // Delete all sessions for user
132
+ db.prepare('DELETE FROM sessions WHERE user_id = ?').run(request.user.userId);
133
+ reply
134
+ .clearCookie('access_token', { path: '/' })
135
+ .clearCookie('refresh_token', { path: '/api/auth/refresh' });
136
+ return { ok: true };
137
+ });
138
+ // --- GET /api/auth/me ---
139
+ app.get('/api/auth/me', { preHandler: [app.requireAuth] }, async (request) => {
140
+ const user = db
141
+ .prepare('SELECT id, username, email, role, created_at, last_login FROM users WHERE id = ?')
142
+ .get(request.user.userId);
143
+ if (!user) {
144
+ return { error: 'User not found' };
145
+ }
146
+ return { user };
147
+ });
148
+ }
149
+ //# sourceMappingURL=auth-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-routes.js","sourceRoot":"","sources":["../../src/auth/auth-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type SignOptions } from 'jsonwebtoken';
2
+ export interface AccessTokenPayload {
3
+ userId: string;
4
+ role: string;
5
+ }
6
+ export interface RefreshTokenPayload {
7
+ sessionId: string;
8
+ userId: string;
9
+ }
10
+ export declare function signAccessToken(payload: AccessTokenPayload, secret: string, expiresIn?: SignOptions['expiresIn']): string;
11
+ export declare function verifyAccessToken(token: string, secret: string): AccessTokenPayload;
12
+ export declare function signRefreshToken(payload: RefreshTokenPayload, secret: string, expiresIn?: SignOptions['expiresIn']): string;
13
+ export declare function verifyRefreshToken(token: string, secret: string): RefreshTokenPayload;
14
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA,OAAY,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,WAAW,CAAC,WAAW,CAAS,GAC1C,MAAM,CAER;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAGnF;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,WAAW,CAAC,WAAW,CAAS,GAC1C,MAAM,CAER;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAGrF"}
@@ -0,0 +1,16 @@
1
+ import jwt from 'jsonwebtoken';
2
+ export function signAccessToken(payload, secret, expiresIn = '24h') {
3
+ return jwt.sign(payload, secret, { expiresIn });
4
+ }
5
+ export function verifyAccessToken(token, secret) {
6
+ const decoded = jwt.verify(token, secret);
7
+ return { userId: decoded.userId, role: decoded.role };
8
+ }
9
+ export function signRefreshToken(payload, secret, expiresIn = '30d') {
10
+ return jwt.sign(payload, secret, { expiresIn });
11
+ }
12
+ export function verifyRefreshToken(token, secret) {
13
+ const decoded = jwt.verify(token, secret);
14
+ return { sessionId: decoded.sessionId, userId: decoded.userId };
15
+ }
16
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,GAAyB,MAAM,cAAc,CAAC;AAYrD,MAAM,UAAU,eAAe,CAC7B,OAA2B,EAC3B,MAAc,EACd,YAAsC,KAAK;IAE3C,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,MAAc;IAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAwC,CAAC;IACjF,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,OAA4B,EAC5B,MAAc,EACd,YAAsC,KAAK;IAE3C,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,MAAc;IAC9D,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAyC,CAAC;IAClF,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;AAClE,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function hashPassword(password: string): Promise<string>;
2
+ export declare function verifyPassword(password: string, hash: string): Promise<boolean>;
3
+ //# sourceMappingURL=password.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/auth/password.ts"],"names":[],"mappings":"AAIA,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpE;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAErF"}
@@ -0,0 +1,9 @@
1
+ import bcrypt from 'bcrypt';
2
+ const SALT_ROUNDS = 12;
3
+ export async function hashPassword(password) {
4
+ return bcrypt.hash(password, SALT_ROUNDS);
5
+ }
6
+ export async function verifyPassword(password, hash) {
7
+ return bcrypt.compare(password, hash);
8
+ }
9
+ //# sourceMappingURL=password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.js","sourceRoot":"","sources":["../../src/auth/password.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,IAAY;IACjE,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chat-handler.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-handler.test.d.ts","sourceRoot":"","sources":["../../../src/bridge/__tests__/chat-handler.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,132 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import Database from 'better-sqlite3';
3
+ import { ChatHandler } from '../chat-handler';
4
+ function createTestDb() {
5
+ const db = new Database(':memory:');
6
+ db.pragma('journal_mode = WAL');
7
+ db.exec(`
8
+ CREATE TABLE IF NOT EXISTS conversations (
9
+ id TEXT PRIMARY KEY,
10
+ squad_name TEXT NOT NULL,
11
+ created_at TEXT NOT NULL
12
+ );
13
+ CREATE TABLE IF NOT EXISTS chat_messages (
14
+ id TEXT PRIMARY KEY,
15
+ conversation_id TEXT NOT NULL REFERENCES conversations(id),
16
+ role TEXT NOT NULL,
17
+ content TEXT NOT NULL,
18
+ agent_id TEXT,
19
+ agent_name TEXT,
20
+ created_at TEXT NOT NULL
21
+ );
22
+ `);
23
+ return db;
24
+ }
25
+ function createMockBridge() {
26
+ return {
27
+ send: vi.fn(),
28
+ isActive: vi.fn().mockReturnValue(false),
29
+ kill: vi.fn(),
30
+ };
31
+ }
32
+ describe('ChatHandler', () => {
33
+ let db;
34
+ let bridge;
35
+ let handler;
36
+ let broadcast;
37
+ beforeEach(() => {
38
+ db = createTestDb();
39
+ bridge = createMockBridge();
40
+ broadcast = vi.fn();
41
+ handler = new ChatHandler({ db, bridge, broadcast, squadsDir: '/tmp/squads' });
42
+ });
43
+ describe('handleChatSend', () => {
44
+ it('should create a conversation if none exists', () => {
45
+ handler.handleChatSend('content-team', 'Hello');
46
+ expect(broadcast).toHaveBeenCalledWith('content-team', expect.objectContaining({
47
+ type: 'chat:conversation_created',
48
+ squadName: 'content-team',
49
+ conversationId: expect.any(String),
50
+ }));
51
+ });
52
+ it('should save user message to database', () => {
53
+ handler.handleChatSend('content-team', 'Hello');
54
+ const msgs = db.prepare('SELECT * FROM chat_messages WHERE role = ?').all('user');
55
+ expect(msgs).toHaveLength(1);
56
+ expect(msgs[0].content).toBe('Hello');
57
+ });
58
+ it('should call bridge.send with constructed prompt', () => {
59
+ handler.handleChatSend('content-team', 'Hello');
60
+ expect(bridge.send).toHaveBeenCalledWith(expect.objectContaining({
61
+ prompt: expect.stringContaining('Hello'),
62
+ cwd: '/tmp/squads/content-team',
63
+ squadName: 'content-team',
64
+ }));
65
+ });
66
+ it('should reuse existing conversation', () => {
67
+ handler.handleChatSend('content-team', 'First');
68
+ handler.handleChatSend('content-team', 'Second');
69
+ const createdMessages = broadcast.mock.calls.filter((call) => call[1].type === 'chat:conversation_created');
70
+ expect(createdMessages).toHaveLength(1);
71
+ const msgs = db.prepare('SELECT * FROM chat_messages WHERE role = ?').all('user');
72
+ expect(msgs).toHaveLength(2);
73
+ });
74
+ it('should broadcast chunks from bridge', () => {
75
+ let capturedOnChunk;
76
+ bridge.send.mockImplementation((opts) => {
77
+ capturedOnChunk = opts.onChunk;
78
+ });
79
+ handler.handleChatSend('content-team', 'Hello');
80
+ expect(capturedOnChunk).toBeDefined();
81
+ capturedOnChunk('chunk-1');
82
+ expect(broadcast).toHaveBeenCalledWith('content-team', expect.objectContaining({
83
+ type: 'chat:chunk',
84
+ squadName: 'content-team',
85
+ delta: 'chunk-1',
86
+ }));
87
+ });
88
+ it('should save assistant message and broadcast done on bridge completion', () => {
89
+ let capturedOnDone;
90
+ bridge.send.mockImplementation((opts) => {
91
+ capturedOnDone = opts.onDone;
92
+ });
93
+ handler.handleChatSend('content-team', 'Hello');
94
+ capturedOnDone('Full response text');
95
+ const msgs = db.prepare('SELECT * FROM chat_messages WHERE role = ?').all('assistant');
96
+ expect(msgs).toHaveLength(1);
97
+ expect(msgs[0].content).toBe('Full response text');
98
+ expect(broadcast).toHaveBeenCalledWith('content-team', expect.objectContaining({
99
+ type: 'chat:done',
100
+ squadName: 'content-team',
101
+ messageId: expect.any(String),
102
+ }));
103
+ });
104
+ it('should broadcast error from bridge', () => {
105
+ let capturedOnError;
106
+ bridge.send.mockImplementation((opts) => {
107
+ capturedOnError = opts.onError;
108
+ });
109
+ handler.handleChatSend('content-team', 'Hello');
110
+ capturedOnError({ code: 1, message: 'Exit code 1: error' });
111
+ expect(broadcast).toHaveBeenCalledWith('content-team', expect.objectContaining({
112
+ type: 'chat:error',
113
+ squadName: 'content-team',
114
+ error: 'Exit code 1: error',
115
+ }));
116
+ });
117
+ });
118
+ describe('handleNewConversation', () => {
119
+ it('should create a new conversation and broadcast', () => {
120
+ handler.handleChatSend('content-team', 'Old message');
121
+ broadcast.mockClear();
122
+ handler.handleNewConversation('content-team');
123
+ expect(broadcast).toHaveBeenCalledWith('content-team', expect.objectContaining({
124
+ type: 'chat:conversation_created',
125
+ squadName: 'content-team',
126
+ }));
127
+ const convs = db.prepare('SELECT * FROM conversations WHERE squad_name = ?').all('content-team');
128
+ expect(convs).toHaveLength(2);
129
+ });
130
+ });
131
+ });
132
+ //# sourceMappingURL=chat-handler.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-handler.test.js","sourceRoot":"","sources":["../../../src/bridge/__tests__/chat-handler.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chat-integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-integration.test.d.ts","sourceRoot":"","sources":["../../../src/bridge/__tests__/chat-integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,141 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import Database from 'better-sqlite3';
3
+ import { ChatHandler } from '../chat-handler';
4
+ import { getActiveConversation, getMessages, } from '../conversation';
5
+ function createTestDb() {
6
+ const db = new Database(':memory:');
7
+ db.pragma('journal_mode = WAL');
8
+ db.exec(`
9
+ CREATE TABLE IF NOT EXISTS conversations (
10
+ id TEXT PRIMARY KEY,
11
+ squad_name TEXT NOT NULL,
12
+ created_at TEXT NOT NULL
13
+ );
14
+ CREATE TABLE IF NOT EXISTS chat_messages (
15
+ id TEXT PRIMARY KEY,
16
+ conversation_id TEXT NOT NULL REFERENCES conversations(id),
17
+ role TEXT NOT NULL,
18
+ content TEXT NOT NULL,
19
+ agent_id TEXT,
20
+ agent_name TEXT,
21
+ created_at TEXT NOT NULL
22
+ );
23
+ `);
24
+ return db;
25
+ }
26
+ describe('Chat round-trip integration', () => {
27
+ let db;
28
+ let broadcasts;
29
+ let capturedBridgeCalls;
30
+ let handler;
31
+ beforeEach(() => {
32
+ db = createTestDb();
33
+ broadcasts = [];
34
+ capturedBridgeCalls = [];
35
+ const mockBridge = {
36
+ send: vi.fn((opts) => {
37
+ capturedBridgeCalls.push(opts);
38
+ }),
39
+ isActive: vi.fn().mockReturnValue(false),
40
+ kill: vi.fn(),
41
+ };
42
+ handler = new ChatHandler({
43
+ db,
44
+ bridge: mockBridge,
45
+ broadcast: (squadName, message) => {
46
+ broadcasts.push({ squadName, message });
47
+ },
48
+ squadsDir: '/tmp/squads',
49
+ });
50
+ });
51
+ it('should complete a full send -> stream -> done cycle', () => {
52
+ handler.handleChatSend('content-team', 'What topics should we cover?');
53
+ const createMsg = broadcasts.find((b) => b.message.type === 'chat:conversation_created');
54
+ expect(createMsg).toBeDefined();
55
+ expect(createMsg.squadName).toBe('content-team');
56
+ const conv = getActiveConversation(db, 'content-team');
57
+ expect(conv).not.toBeNull();
58
+ const msgs1 = getMessages(db, conv.id, { limit: 50 });
59
+ expect(msgs1.data).toHaveLength(1);
60
+ expect(msgs1.data[0].role).toBe('user');
61
+ expect(msgs1.data[0].content).toBe('What topics should we cover?');
62
+ const bridgeCall = capturedBridgeCalls[0];
63
+ expect(bridgeCall.squadName).toBe('content-team');
64
+ expect(bridgeCall.prompt).toContain('What topics should we cover?');
65
+ bridgeCall.onChunk('Here are ');
66
+ bridgeCall.onChunk('5 topics');
67
+ const chunks = broadcasts.filter((b) => b.message.type === 'chat:chunk');
68
+ expect(chunks).toHaveLength(2);
69
+ expect(chunks[0].message.delta).toBe('Here are ');
70
+ expect(chunks[1].message.delta).toBe('5 topics');
71
+ bridgeCall.onDone('Here are 5 topics');
72
+ const msgs2 = getMessages(db, conv.id, { limit: 50 });
73
+ expect(msgs2.data).toHaveLength(2);
74
+ expect(msgs2.data[1].role).toBe('assistant');
75
+ expect(msgs2.data[1].content).toBe('Here are 5 topics');
76
+ const doneMsg = broadcasts.find((b) => b.message.type === 'chat:done');
77
+ expect(doneMsg).toBeDefined();
78
+ expect(doneMsg.message.messageId).toBeDefined();
79
+ });
80
+ it('should persist multiple messages in the same conversation', () => {
81
+ handler.handleChatSend('content-team', 'Hello');
82
+ capturedBridgeCalls[0].onDone('Hi!');
83
+ handler.handleChatSend('content-team', 'Tell me more');
84
+ capturedBridgeCalls[1].onDone('Sure, here is more info');
85
+ const conv = getActiveConversation(db, 'content-team');
86
+ const msgs = getMessages(db, conv.id, { limit: 50 });
87
+ expect(msgs.data).toHaveLength(4);
88
+ // Same-millisecond IDs may sort by random hex suffix, so verify content exists
89
+ const contents = msgs.data.map((m) => m.content);
90
+ expect(contents).toContain('Hello');
91
+ expect(contents).toContain('Hi!');
92
+ expect(contents).toContain('Tell me more');
93
+ expect(contents).toContain('Sure, here is more info');
94
+ // Verify roles: 2 user + 2 assistant
95
+ expect(msgs.data.filter((m) => m.role === 'user')).toHaveLength(2);
96
+ expect(msgs.data.filter((m) => m.role === 'assistant')).toHaveLength(2);
97
+ });
98
+ it('should include conversation history in bridge prompt', () => {
99
+ handler.handleChatSend('content-team', 'Hello');
100
+ capturedBridgeCalls[0].onDone('Hi there!');
101
+ handler.handleChatSend('content-team', 'What next?');
102
+ const secondPrompt = capturedBridgeCalls[1].prompt;
103
+ expect(secondPrompt).toContain('User: Hello');
104
+ expect(secondPrompt).toContain('Assistant: Hi there!');
105
+ expect(secondPrompt).toContain('User: What next?');
106
+ });
107
+ it('should handle bridge error gracefully', () => {
108
+ handler.handleChatSend('content-team', 'Hello');
109
+ capturedBridgeCalls[0].onError({ code: 1, message: 'Process failed' });
110
+ const errorMsg = broadcasts.find((b) => b.message.type === 'chat:error');
111
+ expect(errorMsg).toBeDefined();
112
+ expect(errorMsg.message.error).toBe('Process failed');
113
+ const conv = getActiveConversation(db, 'content-team');
114
+ const msgs = getMessages(db, conv.id, { limit: 50 });
115
+ expect(msgs.data).toHaveLength(1);
116
+ expect(msgs.data[0].role).toBe('user');
117
+ });
118
+ it('should create a fresh conversation on handleNewConversation', () => {
119
+ // Insert old conversation with explicit earlier timestamp
120
+ db.prepare('INSERT INTO conversations (id, squad_name, created_at) VALUES (?, ?, ?)').run('2026-03-13T09:00:00.000Z-old', 'content-team', '2026-03-13T09:00:00.000Z');
121
+ db.prepare('INSERT INTO chat_messages (id, conversation_id, role, content, created_at) VALUES (?, ?, ?, ?, ?)').run('2026-03-13T09:00:01.000Z-m1', '2026-03-13T09:00:00.000Z-old', 'user', 'Old message', '2026-03-13T09:00:01.000Z');
122
+ // Create new conversation — its generateId() will produce a later timestamp than 2026-03-13T09:00:00
123
+ handler.handleNewConversation('content-team');
124
+ // handleChatSend should pick up the new (latest) conversation
125
+ handler.handleChatSend('content-team', 'New message');
126
+ capturedBridgeCalls[0].onDone('New response');
127
+ // Verify the new conversation got the new messages
128
+ const convCreatedBroadcasts = broadcasts.filter((b) => b.message.type === 'chat:conversation_created');
129
+ expect(convCreatedBroadcasts).toHaveLength(1);
130
+ // There should be 2 conversations total
131
+ const allConvs = db.prepare('SELECT * FROM conversations WHERE squad_name = ?').all('content-team');
132
+ expect(allConvs).toHaveLength(2);
133
+ // The newest conversation should have only 2 messages (New message + New response)
134
+ const newConvId = convCreatedBroadcasts[0].message.conversationId;
135
+ const msgs = getMessages(db, newConvId, { limit: 50 });
136
+ const contents = msgs.data.map((m) => m.content);
137
+ expect(contents).toContain('New message');
138
+ expect(contents).toContain('New response');
139
+ });
140
+ });
141
+ //# sourceMappingURL=chat-integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-integration.test.js","sourceRoot":"","sources":["../../../src/bridge/__tests__/chat-integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=claude-bridge.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-bridge.test.d.ts","sourceRoot":"","sources":["../../../src/bridge/__tests__/claude-bridge.test.ts"],"names":[],"mappings":""}