@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,209 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import { Config, checkGeminiAuthStatusNonInteractive, beginGeminiOAuthLoopbackFlow, AuthType, saveApiKey, clearCachedCredentialFile, } from '@terminai/core';
8
+ import { logger } from '../utils/logger.js';
9
+ export class AuthConflictError extends Error {
10
+ statusCode = 409;
11
+ }
12
+ export class LlmAuthManager {
13
+ config;
14
+ getSelectedAuthType;
15
+ effectiveAuthType;
16
+ oauthFlow = null;
17
+ lastErrorMessage = null;
18
+ lastErrorCode;
19
+ constructor(input) {
20
+ this.config = input.config;
21
+ this.getSelectedAuthType = input.getSelectedAuthType;
22
+ this.effectiveAuthType = this.getSelectedAuthType();
23
+ }
24
+ async getStatus() {
25
+ const authType = this.effectiveAuthType ?? this.getSelectedAuthType();
26
+ if (this.oauthFlow) {
27
+ return {
28
+ status: 'in_progress',
29
+ authType,
30
+ message: 'OAuth sign-in in progress',
31
+ };
32
+ }
33
+ const check = await checkGeminiAuthStatusNonInteractive(authType, process.env);
34
+ if (check.status === 'ok') {
35
+ return { status: 'ok', authType };
36
+ }
37
+ if (check.status === 'required') {
38
+ return {
39
+ status: 'required',
40
+ authType,
41
+ message: check.message ?? this.lastErrorMessage ?? undefined,
42
+ errorCode: this.lastErrorCode,
43
+ };
44
+ }
45
+ return {
46
+ status: 'error',
47
+ authType,
48
+ message: check.message ?? this.lastErrorMessage ?? undefined,
49
+ errorCode: this.lastErrorCode,
50
+ };
51
+ }
52
+ async submitGeminiApiKey(apiKey) {
53
+ const trimmed = apiKey.trim();
54
+ if (trimmed.length === 0) {
55
+ return {
56
+ status: 'required',
57
+ authType: AuthType.USE_GEMINI,
58
+ message: 'API key must be a non-empty string',
59
+ };
60
+ }
61
+ this.effectiveAuthType = AuthType.USE_GEMINI;
62
+ this.lastErrorMessage = null;
63
+ await saveApiKey(trimmed);
64
+ await this.config.refreshAuth(AuthType.USE_GEMINI);
65
+ return this.getStatus();
66
+ }
67
+ async startGeminiOAuth() {
68
+ if (this.oauthFlow) {
69
+ throw new AuthConflictError('OAuth already in progress');
70
+ }
71
+ this.effectiveAuthType = AuthType.LOGIN_WITH_GOOGLE;
72
+ this.lastErrorMessage = null;
73
+ const { authUrl, waitForCompletion, cancel } = await beginGeminiOAuthLoopbackFlow(this.config);
74
+ this.oauthFlow = { waitForCompletion, cancel };
75
+ // Do not block the request; update auth in the background.
76
+ void waitForCompletion
77
+ .then(async () => {
78
+ await this.config.refreshAuth(AuthType.LOGIN_WITH_GOOGLE);
79
+ this.lastErrorMessage = null;
80
+ this.lastErrorCode = undefined;
81
+ })
82
+ .catch((err) => {
83
+ const error = err instanceof Error ? err : new Error('OAuth failed');
84
+ const { message, code } = this.mapOAuthError(error);
85
+ this.lastErrorMessage = message;
86
+ this.lastErrorCode = code;
87
+ logger.warn('[LlmAuthManager] OAuth did not complete:', {
88
+ message,
89
+ code,
90
+ });
91
+ })
92
+ .finally(() => {
93
+ this.oauthFlow = null;
94
+ });
95
+ return { authUrl };
96
+ }
97
+ async cancelGeminiOAuth() {
98
+ if (this.oauthFlow) {
99
+ const cancel = this.oauthFlow.cancel;
100
+ this.oauthFlow = null;
101
+ try {
102
+ cancel();
103
+ }
104
+ catch (err) {
105
+ logger.warn('[LlmAuthManager] OAuth cancel threw:', err);
106
+ }
107
+ }
108
+ this.lastErrorMessage = null;
109
+ this.lastErrorCode = undefined;
110
+ return this.getStatus();
111
+ }
112
+ async useGeminiVertex() {
113
+ this.effectiveAuthType = AuthType.USE_VERTEX_AI;
114
+ const hasVertexEnv = (process.env['GOOGLE_CLOUD_PROJECT'] &&
115
+ process.env['GOOGLE_CLOUD_LOCATION']) ||
116
+ process.env['GOOGLE_API_KEY'];
117
+ if (!hasVertexEnv) {
118
+ return {
119
+ status: 'required',
120
+ authType: AuthType.USE_VERTEX_AI,
121
+ message: 'Vertex AI requires either GOOGLE_CLOUD_PROJECT + GOOGLE_CLOUD_LOCATION, or GOOGLE_API_KEY (express mode).',
122
+ };
123
+ }
124
+ await this.config.refreshAuth(AuthType.USE_VERTEX_AI);
125
+ return this.getStatus();
126
+ }
127
+ async clearGeminiAuth() {
128
+ // Cancel any in-progress OAuth flow
129
+ if (this.oauthFlow) {
130
+ const cancel = this.oauthFlow.cancel;
131
+ this.oauthFlow = null;
132
+ try {
133
+ cancel();
134
+ }
135
+ catch (err) {
136
+ logger.warn('[LlmAuthManager] OAuth cancel during clear threw:', err);
137
+ }
138
+ }
139
+ // Clear OAuth credentials
140
+ try {
141
+ await clearCachedCredentialFile();
142
+ }
143
+ catch (err) {
144
+ logger.warn('[LlmAuthManager] Failed to clear cached credentials:', err);
145
+ }
146
+ // Reset effective auth type to undefined to force re-selection
147
+ this.effectiveAuthType = undefined;
148
+ this.lastErrorMessage = null;
149
+ this.lastErrorCode = undefined;
150
+ // Try to refresh with undefined auth type, which should fail gracefully
151
+ try {
152
+ await this.config.refreshAuth(undefined);
153
+ }
154
+ catch (err) {
155
+ // Expected to fail when no auth is configured
156
+ }
157
+ return this.getStatus();
158
+ }
159
+ mapOAuthError(error) {
160
+ const message = error.message.toLowerCase();
161
+ if (message.includes('timeout') || message.includes('timed out')) {
162
+ return {
163
+ message: 'The sign-in request timed out. Please try again.',
164
+ code: 'timeout',
165
+ };
166
+ }
167
+ if (message.includes('denied') || message.includes('access_denied')) {
168
+ return {
169
+ message: 'Sign-in was denied. Please try again and grant the requested permissions.',
170
+ code: 'denied',
171
+ };
172
+ }
173
+ if (message.includes('state') && message.includes('mismatch')) {
174
+ return {
175
+ message: 'Security error occurred during sign-in. Please try again.',
176
+ code: 'state_mismatch',
177
+ };
178
+ }
179
+ if (message.includes('bind') ||
180
+ message.includes('port') ||
181
+ message.includes('address')) {
182
+ return {
183
+ message: 'Could not start local server for sign-in. Please check if another application is using the required port.',
184
+ code: 'server_bind_failed',
185
+ };
186
+ }
187
+ if (message.includes('token') ||
188
+ message.includes('exchange') ||
189
+ message.includes('authorization code')) {
190
+ return {
191
+ message: 'Failed to exchange authorization code for access token. Please try again.',
192
+ code: 'token_exchange_failed',
193
+ };
194
+ }
195
+ if (message.includes('network') ||
196
+ message.includes('fetch') ||
197
+ message.includes('connection')) {
198
+ return {
199
+ message: 'Network error occurred. Please check your internet connection and try again.',
200
+ code: 'network_error',
201
+ };
202
+ }
203
+ return {
204
+ message: 'An unexpected error occurred during sign-in. Please try again.',
205
+ code: 'network_error',
206
+ };
207
+ }
208
+ }
209
+ //# sourceMappingURL=llmAuthManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llmAuthManager.js","sourceRoot":"","sources":["../../../src/auth/llmAuthManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ export {};
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
8
+ import { AuthType } from '@terminai/core';
9
+ import { AuthConflictError, LlmAuthManager } from './llmAuthManager.js';
10
+ const mockCheck = vi.hoisted(() => vi.fn());
11
+ const mockBeginFlow = vi.hoisted(() => vi.fn());
12
+ const mockSaveApiKey = vi.hoisted(() => vi.fn());
13
+ vi.mock('@terminai/core', async (importOriginal) => {
14
+ const actual = await importOriginal();
15
+ return {
16
+ ...actual,
17
+ checkGeminiAuthStatusNonInteractive: mockCheck,
18
+ beginGeminiOAuthLoopbackFlow: mockBeginFlow,
19
+ saveApiKey: mockSaveApiKey,
20
+ };
21
+ });
22
+ describe('LlmAuthManager', () => {
23
+ let mockConfig;
24
+ beforeEach(() => {
25
+ mockConfig = {
26
+ // Config is heavyweight; we only need refreshAuth for these unit tests.
27
+ refreshAuth: vi.fn().mockResolvedValue(undefined),
28
+ getProxy: vi.fn().mockReturnValue(undefined),
29
+ };
30
+ mockCheck.mockResolvedValue({ status: 'required' });
31
+ mockSaveApiKey.mockResolvedValue(undefined);
32
+ delete process.env['GOOGLE_CLOUD_PROJECT'];
33
+ delete process.env['GOOGLE_CLOUD_LOCATION'];
34
+ delete process.env['GOOGLE_API_KEY'];
35
+ });
36
+ afterEach(() => {
37
+ vi.resetAllMocks();
38
+ });
39
+ it('reports in_progress after starting OAuth', async () => {
40
+ const waitForCompletion = new Promise(() => { });
41
+ const cancel = vi.fn();
42
+ mockBeginFlow.mockResolvedValue({
43
+ authUrl: 'https://example.test/auth',
44
+ waitForCompletion,
45
+ cancel,
46
+ });
47
+ const manager = new LlmAuthManager({
48
+ config: mockConfig,
49
+ getSelectedAuthType: () => AuthType.LOGIN_WITH_GOOGLE,
50
+ });
51
+ const start = await manager.startGeminiOAuth();
52
+ expect(start.authUrl).toBe('https://example.test/auth');
53
+ const status = await manager.getStatus();
54
+ expect(status.status).toBe('in_progress');
55
+ expect(status.authType).toBe(AuthType.LOGIN_WITH_GOOGLE);
56
+ });
57
+ it('prevents starting a second OAuth flow concurrently', async () => {
58
+ const waitForCompletion = new Promise(() => { });
59
+ mockBeginFlow.mockResolvedValue({
60
+ authUrl: 'https://example.test/auth',
61
+ waitForCompletion,
62
+ cancel: vi.fn(),
63
+ });
64
+ const manager = new LlmAuthManager({
65
+ config: mockConfig,
66
+ getSelectedAuthType: () => AuthType.LOGIN_WITH_GOOGLE,
67
+ });
68
+ await manager.startGeminiOAuth();
69
+ await expect(manager.startGeminiOAuth()).rejects.toBeInstanceOf(AuthConflictError);
70
+ });
71
+ it('submits Gemini API key via keychain and refreshAuth', async () => {
72
+ mockCheck.mockResolvedValue({ status: 'ok' });
73
+ const manager = new LlmAuthManager({
74
+ config: mockConfig,
75
+ getSelectedAuthType: () => AuthType.USE_GEMINI,
76
+ });
77
+ const status = await manager.submitGeminiApiKey(' test-key ');
78
+ expect(mockSaveApiKey).toHaveBeenCalledWith('test-key');
79
+ expect(mockConfig.refreshAuth).toHaveBeenCalledWith(AuthType.USE_GEMINI);
80
+ expect(status.status).toBe('ok');
81
+ });
82
+ it('returns required for Vertex when env is missing', async () => {
83
+ const manager = new LlmAuthManager({
84
+ config: mockConfig,
85
+ getSelectedAuthType: () => AuthType.USE_VERTEX_AI,
86
+ });
87
+ const status = await manager.useGeminiVertex();
88
+ expect(status.status).toBe('required');
89
+ expect(status.authType).toBe(AuthType.USE_VERTEX_AI);
90
+ });
91
+ });
92
+ //# sourceMappingURL=llmAuthManager.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llmAuthManager.test.js","sourceRoot":"","sources":["../../../src/auth/llmAuthManager.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import type { Command } from './types.js';
8
+ declare class CommandRegistry {
9
+ private readonly commands;
10
+ constructor();
11
+ register(command: Command): void;
12
+ get(commandName: string): Command | undefined;
13
+ getAllCommands(): Command[];
14
+ }
15
+ export declare const commandRegistry: CommandRegistry;
16
+ export {};
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import { ExtensionsCommand } from './extensions.js';
8
+ import { InitCommand } from './init.js';
9
+ import { RestoreCommand } from './restore.js';
10
+ class CommandRegistry {
11
+ commands = new Map();
12
+ constructor() {
13
+ this.register(new ExtensionsCommand());
14
+ this.register(new RestoreCommand());
15
+ this.register(new InitCommand());
16
+ }
17
+ register(command) {
18
+ if (this.commands.has(command.name)) {
19
+ console.warn(`Command ${command.name} already registered. Skipping.`);
20
+ return;
21
+ }
22
+ this.commands.set(command.name, command);
23
+ for (const subCommand of command.subCommands ?? []) {
24
+ this.register(subCommand);
25
+ }
26
+ }
27
+ get(commandName) {
28
+ return this.commands.get(commandName);
29
+ }
30
+ getAllCommands() {
31
+ return [...this.commands.values()];
32
+ }
33
+ }
34
+ export const commandRegistry = new CommandRegistry();
35
+ //# sourceMappingURL=command-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-registry.js","sourceRoot":"","sources":["../../../src/commands/command-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,MAAM,eAAe;IACF,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IAEvD;QACE,IAAI,CAAC,QAAQ,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC,QAAQ,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,QAAQ,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,QAAQ,CAAC,OAAgB;QACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,IAAI,gCAAgC,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAEzC,KAAK,MAAM,UAAU,IAAI,OAAO,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;YACnD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,GAAG,CAAC,WAAmB;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACxC,CAAC;IAED,cAAc;QACZ,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ export {};
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
8
+ describe('CommandRegistry', () => {
9
+ const mockListExtensionsCommandInstance = {
10
+ name: 'extensions list',
11
+ description: 'Lists all installed extensions.',
12
+ execute: vi.fn(),
13
+ };
14
+ const mockListExtensionsCommand = vi.fn(() => mockListExtensionsCommandInstance);
15
+ const mockExtensionsCommandInstance = {
16
+ name: 'extensions',
17
+ description: 'Manage extensions.',
18
+ execute: vi.fn(),
19
+ subCommands: [mockListExtensionsCommandInstance],
20
+ };
21
+ const mockExtensionsCommand = vi.fn(() => mockExtensionsCommandInstance);
22
+ beforeEach(async () => {
23
+ vi.resetModules();
24
+ vi.doMock('./extensions.js', () => ({
25
+ ExtensionsCommand: mockExtensionsCommand,
26
+ ListExtensionsCommand: mockListExtensionsCommand,
27
+ }));
28
+ });
29
+ it('should register ExtensionsCommand on initialization', async () => {
30
+ const { commandRegistry } = await import('./command-registry.js');
31
+ expect(mockExtensionsCommand).toHaveBeenCalled();
32
+ const command = commandRegistry.get('extensions');
33
+ expect(command).toBe(mockExtensionsCommandInstance);
34
+ });
35
+ it('should register sub commands on initialization', async () => {
36
+ const { commandRegistry } = await import('./command-registry.js');
37
+ const command = commandRegistry.get('extensions list');
38
+ expect(command).toBe(mockListExtensionsCommandInstance);
39
+ });
40
+ it('get() should return undefined for a non-existent command', async () => {
41
+ const { commandRegistry } = await import('./command-registry.js');
42
+ const command = commandRegistry.get('non-existent');
43
+ expect(command).toBeUndefined();
44
+ });
45
+ it('register() should register a new command', async () => {
46
+ const { commandRegistry } = await import('./command-registry.js');
47
+ const mockCommand = {
48
+ name: 'test-command',
49
+ description: '',
50
+ execute: vi.fn(),
51
+ };
52
+ commandRegistry.register(mockCommand);
53
+ const command = commandRegistry.get('test-command');
54
+ expect(command).toBe(mockCommand);
55
+ });
56
+ it('register() should register a nested command', async () => {
57
+ const { commandRegistry } = await import('./command-registry.js');
58
+ const mockSubSubCommand = {
59
+ name: 'test-command-sub-sub',
60
+ description: '',
61
+ execute: vi.fn(),
62
+ };
63
+ const mockSubCommand = {
64
+ name: 'test-command-sub',
65
+ description: '',
66
+ execute: vi.fn(),
67
+ subCommands: [mockSubSubCommand],
68
+ };
69
+ const mockCommand = {
70
+ name: 'test-command',
71
+ description: '',
72
+ execute: vi.fn(),
73
+ subCommands: [mockSubCommand],
74
+ };
75
+ commandRegistry.register(mockCommand);
76
+ const command = commandRegistry.get('test-command');
77
+ const subCommand = commandRegistry.get('test-command-sub');
78
+ const subSubCommand = commandRegistry.get('test-command-sub-sub');
79
+ expect(command).toBe(mockCommand);
80
+ expect(subCommand).toBe(mockSubCommand);
81
+ expect(subSubCommand).toBe(mockSubSubCommand);
82
+ });
83
+ it('register() should not enter an infinite loop with a cyclic command', async () => {
84
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
85
+ const { commandRegistry } = await import('./command-registry.js');
86
+ const mockCommand = {
87
+ name: 'cyclic-command',
88
+ description: '',
89
+ subCommands: [],
90
+ execute: vi.fn(),
91
+ };
92
+ mockCommand.subCommands?.push(mockCommand); // Create cycle
93
+ commandRegistry.register(mockCommand);
94
+ expect(commandRegistry.get('cyclic-command')).toBe(mockCommand);
95
+ expect(warnSpy).toHaveBeenCalledWith('Command cyclic-command already registered. Skipping.');
96
+ // If the test finishes, it means we didn't get into an infinite loop.
97
+ warnSpy.mockRestore();
98
+ });
99
+ });
100
+ //# sourceMappingURL=command-registry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-registry.test.js","sourceRoot":"","sources":["../../../src/commands/command-registry.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import type { Command, CommandContext, CommandExecutionResponse } from './types.js';
8
+ export declare class ExtensionsCommand implements Command {
9
+ readonly name = "extensions";
10
+ readonly description = "Manage extensions.";
11
+ readonly subCommands: ListExtensionsCommand[];
12
+ readonly topLevel = true;
13
+ execute(context: CommandContext, _: string[]): Promise<CommandExecutionResponse>;
14
+ }
15
+ export declare class ListExtensionsCommand implements Command {
16
+ readonly name = "extensions list";
17
+ readonly description = "Lists all installed extensions.";
18
+ execute(context: CommandContext, _: string[]): Promise<CommandExecutionResponse>;
19
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import { listExtensions } from '@terminai/core';
8
+ export class ExtensionsCommand {
9
+ name = 'extensions';
10
+ description = 'Manage extensions.';
11
+ subCommands = [new ListExtensionsCommand()];
12
+ topLevel = true;
13
+ async execute(context, _) {
14
+ return new ListExtensionsCommand().execute(context, _);
15
+ }
16
+ }
17
+ export class ListExtensionsCommand {
18
+ name = 'extensions list';
19
+ description = 'Lists all installed extensions.';
20
+ async execute(context, _) {
21
+ const extensions = listExtensions(context.config);
22
+ const data = extensions.length ? extensions : 'No extensions installed.';
23
+ return { name: this.name, data };
24
+ }
25
+ }
26
+ //# sourceMappingURL=extensions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions.js","sourceRoot":"","sources":["../../../src/commands/extensions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAOhD,MAAM,OAAO,iBAAiB;IACnB,IAAI,GAAG,YAAY,CAAC;IACpB,WAAW,GAAG,oBAAoB,CAAC;IACnC,WAAW,GAAG,CAAC,IAAI,qBAAqB,EAAE,CAAC,CAAC;IAC5C,QAAQ,GAAG,IAAI,CAAC;IAEzB,KAAK,CAAC,OAAO,CACX,OAAuB,EACvB,CAAW;QAEX,OAAO,IAAI,qBAAqB,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;CACF;AAED,MAAM,OAAO,qBAAqB;IACvB,IAAI,GAAG,iBAAiB,CAAC;IACzB,WAAW,GAAG,iCAAiC,CAAC;IAEzD,KAAK,CAAC,OAAO,CACX,OAAuB,EACvB,CAAW;QAEX,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,0BAA0B,CAAC;QAEzE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ export {};
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import { describe, it, expect, vi } from 'vitest';
8
+ import { ExtensionsCommand, ListExtensionsCommand } from './extensions.js';
9
+ const mockListExtensions = vi.hoisted(() => vi.fn());
10
+ vi.mock('@terminai/core', async (importOriginal) => {
11
+ const original = await importOriginal();
12
+ return {
13
+ ...original,
14
+ listExtensions: mockListExtensions,
15
+ };
16
+ });
17
+ describe('ExtensionsCommand', () => {
18
+ it('should have the correct name', () => {
19
+ const command = new ExtensionsCommand();
20
+ expect(command.name).toEqual('extensions');
21
+ });
22
+ it('should have the correct description', () => {
23
+ const command = new ExtensionsCommand();
24
+ expect(command.description).toEqual('Manage extensions.');
25
+ });
26
+ it('should have "extensions list" as a subcommand', () => {
27
+ const command = new ExtensionsCommand();
28
+ expect(command.subCommands.map((c) => c.name)).toContain('extensions list');
29
+ });
30
+ it('should be a top-level command', () => {
31
+ const command = new ExtensionsCommand();
32
+ expect(command.topLevel).toBe(true);
33
+ });
34
+ it('should default to listing extensions', async () => {
35
+ const command = new ExtensionsCommand();
36
+ const mockConfig = { config: {} };
37
+ const mockExtensions = [{ name: 'ext1' }];
38
+ mockListExtensions.mockReturnValue(mockExtensions);
39
+ const result = await command.execute(mockConfig, []);
40
+ expect(result).toEqual({ name: 'extensions list', data: mockExtensions });
41
+ expect(mockListExtensions).toHaveBeenCalledWith(mockConfig.config);
42
+ });
43
+ });
44
+ describe('ListExtensionsCommand', () => {
45
+ it('should have the correct name', () => {
46
+ const command = new ListExtensionsCommand();
47
+ expect(command.name).toEqual('extensions list');
48
+ });
49
+ it('should call listExtensions with the provided config', async () => {
50
+ const command = new ListExtensionsCommand();
51
+ const mockConfig = { config: {} };
52
+ const mockExtensions = [{ name: 'ext1' }];
53
+ mockListExtensions.mockReturnValue(mockExtensions);
54
+ const result = await command.execute(mockConfig, []);
55
+ expect(result).toEqual({ name: 'extensions list', data: mockExtensions });
56
+ expect(mockListExtensions).toHaveBeenCalledWith(mockConfig.config);
57
+ });
58
+ it('should return a message when no extensions are installed', async () => {
59
+ const command = new ListExtensionsCommand();
60
+ const mockConfig = { config: {} };
61
+ mockListExtensions.mockReturnValue([]);
62
+ const result = await command.execute(mockConfig, []);
63
+ expect(result).toEqual({
64
+ name: 'extensions list',
65
+ data: 'No extensions installed.',
66
+ });
67
+ expect(mockListExtensions).toHaveBeenCalledWith(mockConfig.config);
68
+ });
69
+ });
70
+ //# sourceMappingURL=extensions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions.test.js","sourceRoot":"","sources":["../../../src/commands/extensions.test.ts"],"names":[],"mappings":"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"}