@terminai/a2a-server 0.21.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 (154) hide show
  1. package/README.md +5 -0
  2. package/dist/.last_build +0 -0
  3. package/dist/a2a-server.mjs +415698 -0
  4. package/dist/index.d.ts +7 -0
  5. package/dist/index.js +8 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/src/agent/executor.d.ts +41 -0
  8. package/dist/src/agent/executor.js +408 -0
  9. package/dist/src/agent/executor.js.map +1 -0
  10. package/dist/src/agent/task.d.ts +67 -0
  11. package/dist/src/agent/task.js +799 -0
  12. package/dist/src/agent/task.js.map +1 -0
  13. package/dist/src/agent/task.test.d.ts +7 -0
  14. package/dist/src/agent/task.test.js +435 -0
  15. package/dist/src/agent/task.test.js.map +1 -0
  16. package/dist/src/agent/task.token.test.d.ts +7 -0
  17. package/dist/src/agent/task.token.test.js +53 -0
  18. package/dist/src/agent/task.token.test.js.map +1 -0
  19. package/dist/src/auth/llmAuthManager.d.ts +39 -0
  20. package/dist/src/auth/llmAuthManager.js +209 -0
  21. package/dist/src/auth/llmAuthManager.js.map +1 -0
  22. package/dist/src/auth/llmAuthManager.test.d.ts +7 -0
  23. package/dist/src/auth/llmAuthManager.test.js +92 -0
  24. package/dist/src/auth/llmAuthManager.test.js.map +1 -0
  25. package/dist/src/commands/command-registry.d.ts +16 -0
  26. package/dist/src/commands/command-registry.js +35 -0
  27. package/dist/src/commands/command-registry.js.map +1 -0
  28. package/dist/src/commands/command-registry.test.d.ts +7 -0
  29. package/dist/src/commands/command-registry.test.js +100 -0
  30. package/dist/src/commands/command-registry.test.js.map +1 -0
  31. package/dist/src/commands/extensions.d.ts +19 -0
  32. package/dist/src/commands/extensions.js +26 -0
  33. package/dist/src/commands/extensions.js.map +1 -0
  34. package/dist/src/commands/extensions.test.d.ts +7 -0
  35. package/dist/src/commands/extensions.test.js +70 -0
  36. package/dist/src/commands/extensions.test.js.map +1 -0
  37. package/dist/src/commands/init.d.ts +16 -0
  38. package/dist/src/commands/init.js +111 -0
  39. package/dist/src/commands/init.js.map +1 -0
  40. package/dist/src/commands/init.test.d.ts +7 -0
  41. package/dist/src/commands/init.test.js +146 -0
  42. package/dist/src/commands/init.test.js.map +1 -0
  43. package/dist/src/commands/restore.d.ts +21 -0
  44. package/dist/src/commands/restore.js +126 -0
  45. package/dist/src/commands/restore.js.map +1 -0
  46. package/dist/src/commands/restore.test.d.ts +7 -0
  47. package/dist/src/commands/restore.test.js +111 -0
  48. package/dist/src/commands/restore.test.js.map +1 -0
  49. package/dist/src/commands/types.d.ts +33 -0
  50. package/dist/src/commands/types.js +8 -0
  51. package/dist/src/commands/types.js.map +1 -0
  52. package/dist/src/config/config.d.ts +24 -0
  53. package/dist/src/config/config.js +140 -0
  54. package/dist/src/config/config.js.map +1 -0
  55. package/dist/src/config/extension.d.ts +12 -0
  56. package/dist/src/config/extension.js +105 -0
  57. package/dist/src/config/extension.js.map +1 -0
  58. package/dist/src/config/settings.d.ts +15 -0
  59. package/dist/src/config/settings.js +20 -0
  60. package/dist/src/config/settings.js.map +1 -0
  61. package/dist/src/config/settings.test.d.ts +7 -0
  62. package/dist/src/config/settings.test.js +170 -0
  63. package/dist/src/config/settings.test.js.map +1 -0
  64. package/dist/src/http/app.d.ts +17 -0
  65. package/dist/src/http/app.js +399 -0
  66. package/dist/src/http/app.js.map +1 -0
  67. package/dist/src/http/app.test.d.ts +7 -0
  68. package/dist/src/http/app.test.js +1048 -0
  69. package/dist/src/http/app.test.js.map +1 -0
  70. package/dist/src/http/auth.d.ts +21 -0
  71. package/dist/src/http/auth.js +55 -0
  72. package/dist/src/http/auth.js.map +1 -0
  73. package/dist/src/http/auth.test.d.ts +7 -0
  74. package/dist/src/http/auth.test.js +53 -0
  75. package/dist/src/http/auth.test.js.map +1 -0
  76. package/dist/src/http/authRoutes.test.d.ts +7 -0
  77. package/dist/src/http/authRoutes.test.js +169 -0
  78. package/dist/src/http/authRoutes.test.js.map +1 -0
  79. package/dist/src/http/cors.d.ts +8 -0
  80. package/dist/src/http/cors.js +96 -0
  81. package/dist/src/http/cors.js.map +1 -0
  82. package/dist/src/http/cors.test.d.ts +7 -0
  83. package/dist/src/http/cors.test.js +62 -0
  84. package/dist/src/http/cors.test.js.map +1 -0
  85. package/dist/src/http/deferredAuth.test.d.ts +7 -0
  86. package/dist/src/http/deferredAuth.test.js +45 -0
  87. package/dist/src/http/deferredAuth.test.js.map +1 -0
  88. package/dist/src/http/endpoints.test.d.ts +7 -0
  89. package/dist/src/http/endpoints.test.js +149 -0
  90. package/dist/src/http/endpoints.test.js.map +1 -0
  91. package/dist/src/http/llmAuthMiddleware.d.ts +9 -0
  92. package/dist/src/http/llmAuthMiddleware.js +37 -0
  93. package/dist/src/http/llmAuthMiddleware.js.map +1 -0
  94. package/dist/src/http/relay.d.ts +28 -0
  95. package/dist/src/http/relay.js +342 -0
  96. package/dist/src/http/relay.js.map +1 -0
  97. package/dist/src/http/relay.test.d.ts +7 -0
  98. package/dist/src/http/relay.test.js +149 -0
  99. package/dist/src/http/relay.test.js.map +1 -0
  100. package/dist/src/http/replay.d.ts +19 -0
  101. package/dist/src/http/replay.js +90 -0
  102. package/dist/src/http/replay.js.map +1 -0
  103. package/dist/src/http/replay.test.d.ts +7 -0
  104. package/dist/src/http/replay.test.js +78 -0
  105. package/dist/src/http/replay.test.js.map +1 -0
  106. package/dist/src/http/requestStorage.d.ts +11 -0
  107. package/dist/src/http/requestStorage.js +9 -0
  108. package/dist/src/http/requestStorage.js.map +1 -0
  109. package/dist/src/http/routes/auth.d.ts +9 -0
  110. package/dist/src/http/routes/auth.js +125 -0
  111. package/dist/src/http/routes/auth.js.map +1 -0
  112. package/dist/src/http/server.d.ts +8 -0
  113. package/dist/src/http/server.js +28 -0
  114. package/dist/src/http/server.js.map +1 -0
  115. package/dist/src/index.d.ts +10 -0
  116. package/dist/src/index.js +11 -0
  117. package/dist/src/index.js.map +1 -0
  118. package/dist/src/persistence/gcs.d.ts +25 -0
  119. package/dist/src/persistence/gcs.js +248 -0
  120. package/dist/src/persistence/gcs.js.map +1 -0
  121. package/dist/src/persistence/gcs.test.d.ts +7 -0
  122. package/dist/src/persistence/gcs.test.js +335 -0
  123. package/dist/src/persistence/gcs.test.js.map +1 -0
  124. package/dist/src/persistence/remoteAuthStore.d.ts +21 -0
  125. package/dist/src/persistence/remoteAuthStore.js +74 -0
  126. package/dist/src/persistence/remoteAuthStore.js.map +1 -0
  127. package/dist/src/types.d.ts +100 -0
  128. package/dist/src/types.js +49 -0
  129. package/dist/src/types.js.map +1 -0
  130. package/dist/src/utils/envAliases.d.ts +7 -0
  131. package/dist/src/utils/envAliases.js +9 -0
  132. package/dist/src/utils/envAliases.js.map +1 -0
  133. package/dist/src/utils/executor_utils.d.ts +8 -0
  134. package/dist/src/utils/executor_utils.js +42 -0
  135. package/dist/src/utils/executor_utils.js.map +1 -0
  136. package/dist/src/utils/logger.d.ts +9 -0
  137. package/dist/src/utils/logger.js +26 -0
  138. package/dist/src/utils/logger.js.map +1 -0
  139. package/dist/src/utils/redactSecrets.d.ts +16 -0
  140. package/dist/src/utils/redactSecrets.js +72 -0
  141. package/dist/src/utils/redactSecrets.js.map +1 -0
  142. package/dist/src/utils/redactSecrets.test.d.ts +7 -0
  143. package/dist/src/utils/redactSecrets.test.js +62 -0
  144. package/dist/src/utils/redactSecrets.test.js.map +1 -0
  145. package/dist/src/utils/testing_utils.d.ts +48 -0
  146. package/dist/src/utils/testing_utils.js +173 -0
  147. package/dist/src/utils/testing_utils.js.map +1 -0
  148. package/dist/tsconfig.tsbuildinfo +1 -0
  149. package/dist/web-client/app.js +526 -0
  150. package/dist/web-client/index.html +43 -0
  151. package/dist/web-client/package.json +10 -0
  152. package/dist/web-client/relay-client.js +330 -0
  153. package/dist/web-client/style.css +189 -0
  154. package/package.json +53 -0
@@ -0,0 +1,330 @@
1
+ export class RelayClient {
2
+ constructor(
3
+ relayUrl,
4
+ sessionId,
5
+ keyBase64,
6
+ onMessage,
7
+ onStatus,
8
+ onPairingRequired,
9
+ ) {
10
+ this.relayUrl = relayUrl;
11
+ this.sessionId = sessionId;
12
+ this.keyBase64 = keyBase64;
13
+ this.onMessage = onMessage;
14
+ this.onStatus = onStatus;
15
+ this.onPairingRequired = onPairingRequired || (() => {}); // Callback when pairing needed
16
+ this.ws = null;
17
+ this.key = null;
18
+ this.reconnectAttempts = 0;
19
+ this.inboundMaxSeq = 0;
20
+ this.outboundSeq = 0;
21
+ this.state = 'WAIT_HELLO'; // 'WAIT_HELLO', 'READY'
22
+ this.protocolVersion = 2; // Default to v2
23
+ this.epoch = null; // Set by HELLO_ACK for v2
24
+ this.requiresPairing = false; // Exposed for UI
25
+ this.pairingComplete = false;
26
+ }
27
+
28
+ async sendHello() {
29
+ // Request both v1 and v2, server will pick highest mutual
30
+ const helloEnvelope = {
31
+ v: 2,
32
+ type: 'HELLO',
33
+ dir: 'c2h',
34
+ seq: ++this.outboundSeq,
35
+ ts: Date.now(),
36
+ payload: { clientId: this.sessionId, protocols: [1, 2] },
37
+ };
38
+ const encrypted = await this.encryptEnvelope(helloEnvelope);
39
+ this.ws.send(encrypted);
40
+ }
41
+
42
+ resetForRehandshake() {
43
+ this.state = 'WAIT_HELLO';
44
+ this.inboundMaxSeq = 0;
45
+ this.outboundSeq = 0;
46
+ this.epoch = null;
47
+ this.pairingComplete = false;
48
+ }
49
+
50
+ async connect() {
51
+ this.onStatus('Connecting to Relay...', 'var(--muted)');
52
+
53
+ // Import Key
54
+ this.key = await this.importKey(this.keyBase64);
55
+
56
+ const wsUrl = new URL(this.relayUrl);
57
+ wsUrl.searchParams.set('role', 'client');
58
+ wsUrl.searchParams.set('session', this.sessionId);
59
+
60
+ this.ws = new WebSocket(wsUrl.toString());
61
+
62
+ this.ws.onopen = () => {
63
+ this.reconnectAttempts = 0; // Reset on successful connection
64
+ this.resetForRehandshake();
65
+ this.onStatus('Handshaking with Relay...', 'var(--muted)');
66
+ console.log(
67
+ JSON.stringify({ event: 'client_ws_connected', timestamp: Date.now() }),
68
+ );
69
+ this.sendHello();
70
+ };
71
+
72
+ this.ws.onclose = () => {
73
+ this.reconnectAttempts++;
74
+ const delay = Math.min(
75
+ 3000 * Math.pow(2, this.reconnectAttempts - 1),
76
+ 30000,
77
+ );
78
+ console.log(
79
+ JSON.stringify({
80
+ event: 'client_ws_disconnected',
81
+ retryDelay: delay,
82
+ timestamp: Date.now(),
83
+ }),
84
+ );
85
+ this.onStatus(
86
+ `Relay Disconnected (retry in ${delay / 1000}s)`,
87
+ 'var(--danger)',
88
+ );
89
+ setTimeout(() => this.connect(), delay);
90
+ };
91
+
92
+ this.ws.onerror = (err) => {
93
+ console.error(
94
+ JSON.stringify({
95
+ event: 'client_ws_error',
96
+ error: err.message || 'unknown',
97
+ timestamp: Date.now(),
98
+ }),
99
+ );
100
+ this.onStatus('Relay Error', 'var(--danger)');
101
+ };
102
+
103
+ this.ws.onmessage = async (event) => {
104
+ if (event.data instanceof Blob) {
105
+ const buffer = await event.data.arrayBuffer();
106
+ await this.handleEncryptedMessage(buffer);
107
+ } else {
108
+ // Check for control messages (unencrypted JSON from relay)
109
+ try {
110
+ const msg = JSON.parse(event.data);
111
+ if (msg.type === 'RELAY_STATUS') {
112
+ if (msg.status === 'HOST_CONNECTED') {
113
+ // Host (re)connected - reset state and re-handshake
114
+ console.log(
115
+ JSON.stringify({
116
+ event: 'host_reconnected_rehandshake',
117
+ timestamp: Date.now(),
118
+ }),
119
+ );
120
+ this.resetForRehandshake();
121
+ this.onStatus(
122
+ 'Host reconnected, re-handshaking...',
123
+ 'var(--muted)',
124
+ );
125
+ this.sendHello();
126
+ } else if (msg.status === 'HOST_DISCONNECTED') {
127
+ this.onStatus('Host Disconnected', 'var(--danger)');
128
+ }
129
+ }
130
+ } catch {
131
+ // Ignore malformed control messages
132
+ }
133
+ }
134
+ };
135
+ }
136
+
137
+ async importKey(base64Key) {
138
+ const binaryDerString = atob(base64Key);
139
+ const binaryDer = new Uint8Array(binaryDerString.length);
140
+ for (let i = 0; i < binaryDerString.length; i++) {
141
+ binaryDer[i] = binaryDerString.charCodeAt(i);
142
+ }
143
+ return await window.crypto.subtle.importKey(
144
+ 'raw',
145
+ binaryDer,
146
+ { name: 'AES-GCM' },
147
+ true,
148
+ ['encrypt', 'decrypt'],
149
+ );
150
+ }
151
+
152
+ buildAad(dir) {
153
+ if (this.protocolVersion === 2 && this.epoch) {
154
+ return `terminai-relay|v=2|session=${this.sessionId}|epoch=${this.epoch}|dir=${dir}`;
155
+ }
156
+ return `terminai-relay|v=1|session=${this.sessionId}|dir=${dir}`;
157
+ }
158
+
159
+ async encryptEnvelope(envelope) {
160
+ // For HELLO, use v1 AAD since we don't have epoch yet
161
+ const aad =
162
+ envelope.type === 'HELLO'
163
+ ? `terminai-relay|v=1|session=${this.sessionId}|dir=${envelope.dir}`
164
+ : this.buildAad(envelope.dir);
165
+ const iv = window.crypto.getRandomValues(new Uint8Array(12));
166
+ const encoded = new TextEncoder().encode(JSON.stringify(envelope));
167
+
168
+ const ciphertext = await window.crypto.subtle.encrypt(
169
+ { name: 'AES-GCM', iv, additionalData: new TextEncoder().encode(aad) },
170
+ this.key,
171
+ encoded,
172
+ );
173
+
174
+ const ctWithTag = new Uint8Array(ciphertext);
175
+ const tagLength = 16;
176
+ const ctLength = ctWithTag.length - tagLength;
177
+
178
+ const tag = ctWithTag.slice(ctLength);
179
+ const actualCt = ctWithTag.slice(0, ctLength);
180
+
181
+ const result = new Uint8Array(12 + 16 + actualCt.length);
182
+ result.set(iv, 0);
183
+ result.set(tag, 12);
184
+ result.set(actualCt, 12 + 16);
185
+
186
+ return result;
187
+ }
188
+
189
+ async encrypt(data) {
190
+ const envelope = {
191
+ v: this.protocolVersion,
192
+ type: 'RPC',
193
+ dir: 'c2h',
194
+ seq: ++this.outboundSeq,
195
+ ts: Date.now(),
196
+ epoch: this.protocolVersion === 2 ? this.epoch : undefined,
197
+ payload: data,
198
+ };
199
+ return this.encryptEnvelope(envelope);
200
+ }
201
+
202
+ async decryptEnvelope(buffer) {
203
+ const input = new Uint8Array(buffer);
204
+ const iv = input.slice(0, 12);
205
+ const tag = input.slice(12, 12 + 16);
206
+ const ciphertext = input.slice(12 + 16);
207
+
208
+ const decryptInput = new Uint8Array(ciphertext.length + tag.length);
209
+ decryptInput.set(ciphertext, 0);
210
+ decryptInput.set(tag, ciphertext.length);
211
+
212
+ // Try v2 AAD first (if we have epoch), then v1
213
+ const aadsToTry = [];
214
+ if (this.epoch) {
215
+ aadsToTry.push(this.buildAad('h2c'));
216
+ }
217
+ aadsToTry.push(`terminai-relay|v=1|session=${this.sessionId}|dir=h2c`);
218
+
219
+ let lastError;
220
+ for (const aad of aadsToTry) {
221
+ try {
222
+ const decrypted = await window.crypto.subtle.decrypt(
223
+ {
224
+ name: 'AES-GCM',
225
+ iv,
226
+ additionalData: new TextEncoder().encode(aad),
227
+ },
228
+ this.key,
229
+ decryptInput,
230
+ );
231
+ const text = new TextDecoder().decode(decrypted);
232
+ return JSON.parse(text);
233
+ } catch (e) {
234
+ lastError = e;
235
+ continue;
236
+ }
237
+ }
238
+ throw lastError;
239
+ }
240
+
241
+ async decrypt(buffer) {
242
+ return this.decryptEnvelope(buffer);
243
+ }
244
+
245
+ async handleEncryptedMessage(buffer) {
246
+ try {
247
+ const envelope = await this.decryptEnvelope(buffer);
248
+
249
+ // Validate sequence
250
+ if (envelope.dir !== 'h2c' || envelope.seq !== this.inboundMaxSeq + 1) {
251
+ console.error('Invalid envelope or sequence', {
252
+ expected: this.inboundMaxSeq + 1,
253
+ got: envelope.seq,
254
+ });
255
+ return;
256
+ }
257
+ this.inboundMaxSeq = envelope.seq;
258
+
259
+ if (envelope.type === 'HELLO_ACK') {
260
+ this.state = 'READY';
261
+ this.protocolVersion = envelope.payload.selectedVersion || 1;
262
+ if (envelope.payload.epoch) {
263
+ this.epoch = envelope.payload.epoch;
264
+ }
265
+
266
+ // Check if pairing required
267
+ if (envelope.payload.requiresPairing && !this.pairingComplete) {
268
+ this.requiresPairing = true;
269
+ this.onStatus('Pairing Required', 'var(--warning)');
270
+ this.onPairingRequired(); // Trigger UI callback
271
+ } else {
272
+ this.onStatus('Ready (Handshake Complete)', 'var(--accent)');
273
+ }
274
+ } else if (envelope.type === 'PAIR_ACK') {
275
+ this.pairingComplete = true;
276
+ this.requiresPairing = false;
277
+ this.onStatus('Paired Successfully', 'var(--accent)');
278
+ } else if (envelope.type === 'RPC') {
279
+ this.onMessage({ result: envelope.payload });
280
+ } else if (envelope.type === 'EVENT') {
281
+ this.onMessage(envelope.payload);
282
+ } else if (envelope.type === 'ERROR') {
283
+ console.error(
284
+ JSON.stringify({
285
+ event: 'client_relay_error',
286
+ error: envelope.payload,
287
+ timestamp: Date.now(),
288
+ }),
289
+ );
290
+ const msg = envelope.payload?.message || 'Relay Error';
291
+ this.onStatus(msg, 'var(--danger)');
292
+ }
293
+ } catch (e) {
294
+ console.error(
295
+ JSON.stringify({
296
+ event: 'client_decrypt_error',
297
+ error: e.message,
298
+ timestamp: Date.now(),
299
+ }),
300
+ );
301
+ }
302
+ }
303
+
304
+ async send(body) {
305
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
306
+ throw new Error('Relay not connected');
307
+ }
308
+ if (this.state !== 'READY') {
309
+ throw new Error('Handshake not complete');
310
+ }
311
+ const encrypted = await this.encrypt(body);
312
+ this.ws.send(encrypted);
313
+
314
+ return { ok: true };
315
+ }
316
+
317
+ async sendPairingCode(code) {
318
+ const pairEnvelope = {
319
+ v: this.protocolVersion,
320
+ type: 'PAIR',
321
+ dir: 'c2h',
322
+ seq: ++this.outboundSeq,
323
+ ts: Date.now(),
324
+ epoch: this.protocolVersion === 2 ? this.epoch : undefined,
325
+ payload: { code },
326
+ };
327
+ const encrypted = await this.encryptEnvelope(pairEnvelope);
328
+ this.ws.send(encrypted);
329
+ }
330
+ }
@@ -0,0 +1,189 @@
1
+ :root {
2
+ --bg: radial-gradient(circle at 10% 20%, #141a2f, #0c111c 40%);
3
+ --card: rgba(16, 21, 34, 0.9);
4
+ --border: rgba(255, 255, 255, 0.07);
5
+ --text: #e9edf5;
6
+ --muted: #8ca0be;
7
+ --accent: #4be1ec;
8
+ --accent-2: #7c6cff;
9
+ --danger: #ff6b6b;
10
+ --shadow: 0 15px 45px rgba(0, 0, 0, 0.3);
11
+ --radius: 18px;
12
+ font-family: 'IBM Plex Sans', 'Segoe UI', 'Helvetica Neue', sans-serif;
13
+ }
14
+
15
+ *,
16
+ *::before,
17
+ *::after {
18
+ box-sizing: border-box;
19
+ }
20
+
21
+ body {
22
+ margin: 0;
23
+ min-height: 100vh;
24
+ background: var(--bg);
25
+ color: var(--text);
26
+ display: flex;
27
+ align-items: center;
28
+ justify-content: center;
29
+ padding: 24px;
30
+ }
31
+
32
+ #app {
33
+ width: min(1100px, 100%);
34
+ background: var(--card);
35
+ border: 1px solid var(--border);
36
+ border-radius: var(--radius);
37
+ box-shadow: var(--shadow);
38
+ padding: 24px;
39
+ display: grid;
40
+ grid-template-rows: auto 1fr auto;
41
+ gap: 16px;
42
+ }
43
+
44
+ header {
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: space-between;
48
+ gap: 16px;
49
+ }
50
+
51
+ .eyebrow {
52
+ text-transform: uppercase;
53
+ letter-spacing: 0.08em;
54
+ color: var(--muted);
55
+ font-size: 12px;
56
+ margin: 0 0 4px;
57
+ }
58
+
59
+ h1 {
60
+ margin: 0 0 4px;
61
+ font-weight: 700;
62
+ letter-spacing: -0.01em;
63
+ }
64
+
65
+ .lede {
66
+ margin: 0;
67
+ color: var(--muted);
68
+ }
69
+
70
+ .status {
71
+ display: inline-flex;
72
+ align-items: center;
73
+ gap: 8px;
74
+ padding: 8px 12px;
75
+ border-radius: 999px;
76
+ background: rgba(255, 255, 255, 0.06);
77
+ font-size: 13px;
78
+ color: var(--muted);
79
+ }
80
+
81
+ .dot {
82
+ width: 10px;
83
+ height: 10px;
84
+ border-radius: 50%;
85
+ background: var(--muted);
86
+ display: inline-block;
87
+ box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.06);
88
+ }
89
+
90
+ main {
91
+ border: 1px solid var(--border);
92
+ border-radius: var(--radius);
93
+ padding: 16px;
94
+ background: rgba(255, 255, 255, 0.02);
95
+ overflow-y: auto;
96
+ display: flex;
97
+ flex-direction: column;
98
+ gap: 12px;
99
+ }
100
+
101
+ .message {
102
+ padding: 12px 14px;
103
+ border-radius: 12px;
104
+ max-width: 80%;
105
+ line-height: 1.5;
106
+ border: 1px solid var(--border);
107
+ }
108
+
109
+ .message.user {
110
+ align-self: flex-end;
111
+ background: linear-gradient(120deg, var(--accent), var(--accent-2));
112
+ color: #0c0f17;
113
+ border: none;
114
+ }
115
+
116
+ .message.ai {
117
+ align-self: flex-start;
118
+ background: rgba(255, 255, 255, 0.05);
119
+ }
120
+
121
+ .message.error {
122
+ align-self: flex-start;
123
+ background: rgba(255, 107, 107, 0.14);
124
+ border-color: rgba(255, 107, 107, 0.5);
125
+ color: #ffeaea;
126
+ }
127
+
128
+ footer {
129
+ display: flex;
130
+ flex-direction: column;
131
+ gap: 8px;
132
+ }
133
+
134
+ footer label {
135
+ font-size: 13px;
136
+ color: var(--muted);
137
+ }
138
+
139
+ textarea {
140
+ width: 100%;
141
+ border-radius: 14px;
142
+ border: 1px solid var(--border);
143
+ background: rgba(255, 255, 255, 0.03);
144
+ color: var(--text);
145
+ padding: 12px;
146
+ resize: vertical;
147
+ min-height: 90px;
148
+ font-size: 15px;
149
+ }
150
+
151
+ textarea:focus {
152
+ outline: 2px solid rgba(75, 225, 236, 0.6);
153
+ }
154
+
155
+ .actions {
156
+ display: flex;
157
+ align-items: center;
158
+ justify-content: space-between;
159
+ gap: 8px;
160
+ color: var(--muted);
161
+ }
162
+
163
+ button {
164
+ background: linear-gradient(120deg, var(--accent), var(--accent-2));
165
+ color: #0b0f17;
166
+ border: none;
167
+ border-radius: 12px;
168
+ padding: 10px 18px;
169
+ font-weight: 600;
170
+ cursor: pointer;
171
+ box-shadow: 0 10px 30px rgba(75, 225, 236, 0.25);
172
+ }
173
+
174
+ button:active {
175
+ transform: translateY(1px);
176
+ }
177
+
178
+ @media (max-width: 720px) {
179
+ body {
180
+ padding: 12px;
181
+ }
182
+ header {
183
+ flex-direction: column;
184
+ align-items: flex-start;
185
+ }
186
+ main {
187
+ max-height: 50vh;
188
+ }
189
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@terminai/a2a-server",
3
+ "version": "0.21.0",
4
+ "description": "TerminaI A2A Server",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/Prof-Harita/terminaI.git",
8
+ "directory": "packages/a2a-server"
9
+ },
10
+ "type": "module",
11
+ "main": "dist/index.js",
12
+ "bin": {
13
+ "terminai-a2a-server": "dist/a2a-server.mjs"
14
+ },
15
+ "scripts": {
16
+ "build": "node ../../scripts/build_package.js",
17
+ "start": "node dist/src/http/server.js",
18
+ "lint": "eslint . --ext .ts,.tsx",
19
+ "format": "prettier --write .",
20
+ "test": "vitest run --passWithNoTests",
21
+ "test:ci": "vitest run --passWithNoTests --coverage",
22
+ "typecheck": "tsc --noEmit"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "dependencies": {
28
+ "@a2a-js/sdk": "^0.3.7",
29
+ "@google-cloud/storage": "^7.16.0",
30
+ "@google/genai": "^1.30.0",
31
+ "@terminai/core": "0.21.0",
32
+ "express": "^5.1.0",
33
+ "fs-extra": "^11.3.0",
34
+ "tar": "^7.5.2",
35
+ "uuid": "^11.1.0",
36
+ "winston": "^3.17.0",
37
+ "ws": "^8.18.3"
38
+ },
39
+ "devDependencies": {
40
+ "@types/express": "^5.0.3",
41
+ "@types/fs-extra": "^11.0.4",
42
+ "@types/supertest": "^6.0.3",
43
+ "@types/tar": "^6.1.13",
44
+ "@types/ws": "^8.18.1",
45
+ "dotenv": "^16.4.5",
46
+ "supertest": "^7.1.4",
47
+ "typescript": "^5.3.3",
48
+ "vitest": "^3.1.1"
49
+ },
50
+ "engines": {
51
+ "node": ">=20"
52
+ }
53
+ }