@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,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, CommandContext, CommandExecutionResponse } from './types.js';
8
+ export declare class InitCommand implements Command {
9
+ name: string;
10
+ description: string;
11
+ requiresWorkspace: boolean;
12
+ streaming: boolean;
13
+ private handleMessageResult;
14
+ private handleSubmitPromptResult;
15
+ execute(context: CommandContext, _args?: string[]): Promise<CommandExecutionResponse>;
16
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import * as fs from 'node:fs';
8
+ import * as path from 'node:path';
9
+ import { CoderAgentEvent } from '../types.js';
10
+ import { performInit } from '@terminai/core';
11
+ import { v4 as uuidv4 } from 'uuid';
12
+ import { logger } from '../utils/logger.js';
13
+ export class InitCommand {
14
+ name = 'init';
15
+ description = 'Analyzes the project and creates a tailored terminaI.md file';
16
+ requiresWorkspace = true;
17
+ streaming = true;
18
+ handleMessageResult(result, context, eventBus, taskId, contextId) {
19
+ const statusState = result.messageType === 'error' ? 'failed' : 'completed';
20
+ const eventType = result.messageType === 'error'
21
+ ? CoderAgentEvent.StateChangeEvent
22
+ : CoderAgentEvent.TextContentEvent;
23
+ const event = {
24
+ kind: 'status-update',
25
+ taskId,
26
+ contextId,
27
+ status: {
28
+ state: statusState,
29
+ message: {
30
+ kind: 'message',
31
+ role: 'agent',
32
+ parts: [{ kind: 'text', text: result.content }],
33
+ messageId: uuidv4(),
34
+ taskId,
35
+ contextId,
36
+ },
37
+ timestamp: new Date().toISOString(),
38
+ },
39
+ final: true,
40
+ metadata: {
41
+ coderAgent: { kind: eventType },
42
+ model: context.config.getModel(),
43
+ },
44
+ };
45
+ logger.info('[EventBus event]: ', event);
46
+ eventBus.publish(event);
47
+ return {
48
+ name: this.name,
49
+ data: result,
50
+ };
51
+ }
52
+ async handleSubmitPromptResult(result, context, geminiMdPath, eventBus, taskId, contextId) {
53
+ fs.writeFileSync(geminiMdPath, '', 'utf8');
54
+ if (!context.agentExecutor) {
55
+ throw new Error('Agent executor not found in context.');
56
+ }
57
+ const agentExecutor = context.agentExecutor;
58
+ const agentSettings = {
59
+ kind: CoderAgentEvent.StateAgentSettingsEvent,
60
+ workspacePath: process.env['CODER_AGENT_WORKSPACE_PATH'],
61
+ autoExecute: true,
62
+ };
63
+ if (typeof result.content !== 'string') {
64
+ throw new Error('Init command content must be a string.');
65
+ }
66
+ const promptText = result.content;
67
+ const requestContext = {
68
+ userMessage: {
69
+ kind: 'message',
70
+ role: 'user',
71
+ parts: [{ kind: 'text', text: promptText }],
72
+ messageId: uuidv4(),
73
+ taskId,
74
+ contextId,
75
+ metadata: {
76
+ coderAgent: agentSettings,
77
+ },
78
+ },
79
+ taskId,
80
+ contextId,
81
+ };
82
+ // The executor will handle the entire agentic loop, including
83
+ // creating the task, streaming responses, and handling tools.
84
+ await agentExecutor.execute(requestContext, eventBus);
85
+ return {
86
+ name: this.name,
87
+ data: geminiMdPath,
88
+ };
89
+ }
90
+ async execute(context, _args = []) {
91
+ if (!context.eventBus) {
92
+ return {
93
+ name: this.name,
94
+ data: 'Use executeStream to get streaming results.',
95
+ };
96
+ }
97
+ const geminiMdPath = path.join(process.env['CODER_AGENT_WORKSPACE_PATH'], 'terminaI.md');
98
+ const result = performInit(fs.existsSync(geminiMdPath));
99
+ const taskId = uuidv4();
100
+ const contextId = uuidv4();
101
+ switch (result.type) {
102
+ case 'message':
103
+ return this.handleMessageResult(result, context, context.eventBus, taskId, contextId);
104
+ case 'submit_prompt':
105
+ return this.handleSubmitPromptResult(result, context, geminiMdPath, context.eventBus, taskId, contextId);
106
+ default:
107
+ throw new Error('Unknown result type from performInit');
108
+ }
109
+ }
110
+ }
111
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,eAAe,EAAsB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAY7C,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,OAAO,WAAW;IACtB,IAAI,GAAG,MAAM,CAAC;IACd,WAAW,GAAG,8DAA8D,CAAC;IAC7E,iBAAiB,GAAG,IAAI,CAAC;IACzB,SAAS,GAAG,IAAI,CAAC;IAET,mBAAmB,CACzB,MAA0D,EAC1D,OAAuB,EACvB,QAA2B,EAC3B,MAAc,EACd,SAAiB;QAEjB,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;QAC5E,MAAM,SAAS,GACb,MAAM,CAAC,WAAW,KAAK,OAAO;YAC5B,CAAC,CAAC,eAAe,CAAC,gBAAgB;YAClC,CAAC,CAAC,eAAe,CAAC,gBAAgB,CAAC;QAEvC,MAAM,KAAK,GAAwB;YACjC,IAAI,EAAE,eAAe;YACrB,MAAM;YACN,SAAS;YACT,MAAM,EAAE;gBACN,KAAK,EAAE,WAAW;gBAClB,OAAO,EAAE;oBACP,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;oBAC/C,SAAS,EAAE,MAAM,EAAE;oBACnB,MAAM;oBACN,SAAS;iBACV;gBACD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC;YACD,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE;gBACR,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBAC/B,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE;aACjC;SACF,CAAC;QAEF,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;QACzC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,MAAM;SACb,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,wBAAwB,CACpC,MAA4B,EAC5B,OAAuB,EACvB,YAAoB,EACpB,QAA2B,EAC3B,MAAc,EACd,SAAiB;QAEjB,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QAE3C,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAmC,CAAC;QAElE,MAAM,aAAa,GAAkB;YACnC,IAAI,EAAE,eAAe,CAAC,uBAAuB;YAC7C,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAE;YACzD,WAAW,EAAE,IAAI;SAClB,CAAC;QAEF,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC;QAElC,MAAM,cAAc,GAAmB;YACrC,WAAW,EAAE;gBACX,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;gBAC3C,SAAS,EAAE,MAAM,EAAE;gBACnB,MAAM;gBACN,SAAS;gBACT,QAAQ,EAAE;oBACR,UAAU,EAAE,aAAa;iBAC1B;aACF;YACD,MAAM;YACN,SAAS;SACV,CAAC;QAEF,8DAA8D;QAC9D,8DAA8D;QAC9D,MAAM,aAAa,CAAC,OAAO,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;QACtD,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,YAAY;SACnB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAO,CACX,OAAuB,EACvB,QAAkB,EAAE;QAEpB,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtB,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,6CAA6C;aACpD,CAAC;QACJ,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAC5B,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAE,EAC1C,aAAa,CACd,CAAC;QACF,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;QAExD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC;QAE3B,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,KAAK,SAAS;gBACZ,OAAO,IAAI,CAAC,mBAAmB,CAC7B,MAAM,EACN,OAAO,EACP,OAAO,CAAC,QAAQ,EAChB,MAAM,EACN,SAAS,CACV,CAAC;YACJ,KAAK,eAAe;gBAClB,OAAO,IAAI,CAAC,wBAAwB,CAClC,MAAM,EACN,OAAO,EACP,YAAY,EACZ,OAAO,CAAC,QAAQ,EAChB,MAAM,EACN,SAAS,CACV,CAAC;YACJ;gBACE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC5D,CAAC;IACH,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,146 @@
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
+ import { InitCommand } from './init.js';
9
+ import { performInit } from '@terminai/core';
10
+ import * as fs from 'node:fs';
11
+ import * as path from 'node:path';
12
+ import { CoderAgentExecutor } from '../agent/executor.js';
13
+ import { CoderAgentEvent } from '../types.js';
14
+ import { createMockConfig } from '../utils/testing_utils.js';
15
+ import { logger } from '../utils/logger.js';
16
+ vi.mock('@terminai/core', async (importOriginal) => {
17
+ const actual = await importOriginal();
18
+ return {
19
+ ...actual,
20
+ performInit: vi.fn(),
21
+ };
22
+ });
23
+ vi.mock('node:fs', () => ({
24
+ existsSync: vi.fn(),
25
+ writeFileSync: vi.fn(),
26
+ }));
27
+ vi.mock('../agent/executor.js', () => ({
28
+ CoderAgentExecutor: vi.fn().mockImplementation(() => ({
29
+ execute: vi.fn(),
30
+ })),
31
+ }));
32
+ vi.mock('../utils/logger.js', () => ({
33
+ logger: {
34
+ info: vi.fn(),
35
+ error: vi.fn(),
36
+ },
37
+ }));
38
+ describe('InitCommand', () => {
39
+ let eventBus;
40
+ let command;
41
+ let context;
42
+ let publishSpy;
43
+ let mockExecute;
44
+ const mockWorkspacePath = path.resolve('/tmp');
45
+ beforeEach(() => {
46
+ process.env['CODER_AGENT_WORKSPACE_PATH'] = mockWorkspacePath;
47
+ eventBus = {
48
+ publish: vi.fn(),
49
+ };
50
+ command = new InitCommand();
51
+ const mockConfig = createMockConfig({
52
+ getModel: () => 'gemini-pro',
53
+ });
54
+ const mockExecutorInstance = new CoderAgentExecutor();
55
+ context = {
56
+ config: mockConfig,
57
+ agentExecutor: mockExecutorInstance,
58
+ eventBus,
59
+ };
60
+ publishSpy = vi.spyOn(eventBus, 'publish');
61
+ mockExecute = vi.fn();
62
+ vi.spyOn(mockExecutorInstance, 'execute').mockImplementation(mockExecute);
63
+ vi.clearAllMocks();
64
+ });
65
+ it('has requiresWorkspace set to true', () => {
66
+ expect(command.requiresWorkspace).toBe(true);
67
+ });
68
+ describe('execute', () => {
69
+ it('handles info from performInit', async () => {
70
+ vi.mocked(performInit).mockReturnValue({
71
+ type: 'message',
72
+ messageType: 'info',
73
+ content: 'terminaI.md already exists.',
74
+ });
75
+ await command.execute(context, []);
76
+ expect(logger.info).toHaveBeenCalledWith('[EventBus event]: ', expect.objectContaining({
77
+ kind: 'status-update',
78
+ status: expect.objectContaining({
79
+ state: 'completed',
80
+ message: expect.objectContaining({
81
+ parts: [{ kind: 'text', text: 'terminaI.md already exists.' }],
82
+ }),
83
+ }),
84
+ }));
85
+ expect(publishSpy).toHaveBeenCalledWith(expect.objectContaining({
86
+ kind: 'status-update',
87
+ status: expect.objectContaining({
88
+ state: 'completed',
89
+ message: expect.objectContaining({
90
+ parts: [{ kind: 'text', text: 'terminaI.md already exists.' }],
91
+ }),
92
+ }),
93
+ }));
94
+ });
95
+ it('handles error from performInit', async () => {
96
+ vi.mocked(performInit).mockReturnValue({
97
+ type: 'message',
98
+ messageType: 'error',
99
+ content: 'An error occurred.',
100
+ });
101
+ await command.execute(context, []);
102
+ expect(publishSpy).toHaveBeenCalledWith(expect.objectContaining({
103
+ kind: 'status-update',
104
+ status: expect.objectContaining({
105
+ state: 'failed',
106
+ message: expect.objectContaining({
107
+ parts: [{ kind: 'text', text: 'An error occurred.' }],
108
+ }),
109
+ }),
110
+ }));
111
+ });
112
+ describe('when handling submit_prompt', () => {
113
+ beforeEach(() => {
114
+ vi.mocked(performInit).mockReturnValue({
115
+ type: 'submit_prompt',
116
+ content: 'Create a new terminaI.md file.',
117
+ });
118
+ });
119
+ it('writes the file and executes the agent', async () => {
120
+ await command.execute(context, []);
121
+ expect(fs.writeFileSync).toHaveBeenCalledWith(path.join(mockWorkspacePath, 'terminaI.md'), '', 'utf8');
122
+ expect(mockExecute).toHaveBeenCalled();
123
+ });
124
+ it('passes autoExecute to the agent executor', async () => {
125
+ await command.execute(context, []);
126
+ expect(mockExecute).toHaveBeenCalledWith(expect.objectContaining({
127
+ userMessage: expect.objectContaining({
128
+ parts: expect.arrayContaining([
129
+ expect.objectContaining({
130
+ text: 'Create a new terminaI.md file.',
131
+ }),
132
+ ]),
133
+ metadata: {
134
+ coderAgent: {
135
+ kind: CoderAgentEvent.StateAgentSettingsEvent,
136
+ workspacePath: mockWorkspacePath,
137
+ autoExecute: true,
138
+ },
139
+ },
140
+ }),
141
+ }), eventBus);
142
+ });
143
+ });
144
+ });
145
+ });
146
+ //# sourceMappingURL=init.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.test.js","sourceRoot":"","sources":["../../../src/commands/init.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
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 RestoreCommand implements Command {
9
+ readonly name = "restore";
10
+ readonly description = "Restore to a previous checkpoint, or list available checkpoints to restore. This will reset the conversation and file history to the state it was in when the checkpoint was created";
11
+ readonly topLevel = true;
12
+ readonly requiresWorkspace = true;
13
+ readonly subCommands: ListCheckpointsCommand[];
14
+ execute(context: CommandContext, args: string[]): Promise<CommandExecutionResponse>;
15
+ }
16
+ export declare class ListCheckpointsCommand implements Command {
17
+ readonly name = "restore list";
18
+ readonly description = "Lists all available checkpoints.";
19
+ readonly topLevel = false;
20
+ execute(context: CommandContext): Promise<CommandExecutionResponse>;
21
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import { getCheckpointInfoList, getToolCallDataSchema, isNodeError, performRestore, } from '@terminai/core';
8
+ import * as fs from 'node:fs/promises';
9
+ import * as path from 'node:path';
10
+ export class RestoreCommand {
11
+ name = 'restore';
12
+ description = 'Restore to a previous checkpoint, or list available checkpoints to restore. This will reset the conversation and file history to the state it was in when the checkpoint was created';
13
+ topLevel = true;
14
+ requiresWorkspace = true;
15
+ subCommands = [new ListCheckpointsCommand()];
16
+ async execute(context, args) {
17
+ const { config, git: gitService } = context;
18
+ const argsStr = args.join(' ');
19
+ try {
20
+ if (!argsStr) {
21
+ return {
22
+ name: this.name,
23
+ data: {
24
+ type: 'message',
25
+ messageType: 'error',
26
+ content: 'Please provide a checkpoint name to restore.',
27
+ },
28
+ };
29
+ }
30
+ const selectedFile = argsStr.endsWith('.json')
31
+ ? argsStr
32
+ : `${argsStr}.json`;
33
+ const checkpointDir = config.storage.getProjectTempCheckpointsDir();
34
+ const filePath = path.join(checkpointDir, selectedFile);
35
+ let data;
36
+ try {
37
+ data = await fs.readFile(filePath, 'utf-8');
38
+ }
39
+ catch (error) {
40
+ if (isNodeError(error) && error.code === 'ENOENT') {
41
+ return {
42
+ name: this.name,
43
+ data: {
44
+ type: 'message',
45
+ messageType: 'error',
46
+ content: `File not found: ${selectedFile}`,
47
+ },
48
+ };
49
+ }
50
+ throw error;
51
+ }
52
+ const toolCallData = JSON.parse(data);
53
+ const ToolCallDataSchema = getToolCallDataSchema();
54
+ const parseResult = ToolCallDataSchema.safeParse(toolCallData);
55
+ if (!parseResult.success) {
56
+ return {
57
+ name: this.name,
58
+ data: {
59
+ type: 'message',
60
+ messageType: 'error',
61
+ content: 'Checkpoint file is invalid or corrupted.',
62
+ },
63
+ };
64
+ }
65
+ const restoreResultGenerator = performRestore(parseResult.data, gitService);
66
+ const restoreResult = [];
67
+ for await (const result of restoreResultGenerator) {
68
+ restoreResult.push(result);
69
+ }
70
+ return {
71
+ name: this.name,
72
+ data: restoreResult,
73
+ };
74
+ }
75
+ catch (_error) {
76
+ return {
77
+ name: this.name,
78
+ data: {
79
+ type: 'message',
80
+ messageType: 'error',
81
+ content: 'An unexpected error occurred during restore.',
82
+ },
83
+ };
84
+ }
85
+ }
86
+ }
87
+ export class ListCheckpointsCommand {
88
+ name = 'restore list';
89
+ description = 'Lists all available checkpoints.';
90
+ topLevel = false;
91
+ async execute(context) {
92
+ const { config } = context;
93
+ try {
94
+ const checkpointDir = config.storage.getProjectTempCheckpointsDir();
95
+ await fs.mkdir(checkpointDir, { recursive: true });
96
+ const files = await fs.readdir(checkpointDir);
97
+ const jsonFiles = files.filter((file) => file.endsWith('.json'));
98
+ const checkpointFiles = new Map();
99
+ for (const file of jsonFiles) {
100
+ const filePath = path.join(checkpointDir, file);
101
+ const data = await fs.readFile(filePath, 'utf-8');
102
+ checkpointFiles.set(file, data);
103
+ }
104
+ const checkpointInfoList = getCheckpointInfoList(checkpointFiles);
105
+ return {
106
+ name: this.name,
107
+ data: {
108
+ type: 'message',
109
+ messageType: 'info',
110
+ content: JSON.stringify(checkpointInfoList),
111
+ },
112
+ };
113
+ }
114
+ catch (_error) {
115
+ return {
116
+ name: this.name,
117
+ data: {
118
+ type: 'message',
119
+ messageType: 'error',
120
+ content: 'An unexpected error occurred while listing checkpoints.',
121
+ },
122
+ };
123
+ }
124
+ }
125
+ }
126
+ //# sourceMappingURL=restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore.js","sourceRoot":"","sources":["../../../src/commands/restore.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,111 @@
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
+ import { RestoreCommand, ListCheckpointsCommand } from './restore.js';
9
+ import { createMockConfig } from '../utils/testing_utils.js';
10
+ beforeEach(() => {
11
+ vi.clearAllMocks();
12
+ });
13
+ const mockPerformRestore = vi.hoisted(() => vi.fn());
14
+ const mockLoggerInfo = vi.hoisted(() => vi.fn());
15
+ const mockGetCheckpointInfoList = vi.hoisted(() => vi.fn());
16
+ vi.mock('@terminai/core', async (importOriginal) => {
17
+ const original = await importOriginal();
18
+ return {
19
+ ...original,
20
+ performRestore: mockPerformRestore,
21
+ getCheckpointInfoList: mockGetCheckpointInfoList,
22
+ };
23
+ });
24
+ const mockFs = vi.hoisted(() => ({
25
+ readFile: vi.fn(),
26
+ readdir: vi.fn(),
27
+ mkdir: vi.fn(),
28
+ }));
29
+ vi.mock('node:fs/promises', () => mockFs);
30
+ vi.mock('../utils/logger.js', () => ({
31
+ logger: {
32
+ info: mockLoggerInfo,
33
+ },
34
+ }));
35
+ describe('RestoreCommand', () => {
36
+ const mockConfig = {
37
+ config: createMockConfig(),
38
+ git: {},
39
+ };
40
+ it('should return error if no checkpoint name is provided', async () => {
41
+ const command = new RestoreCommand();
42
+ const result = await command.execute(mockConfig, []);
43
+ expect(result.data).toEqual({
44
+ type: 'message',
45
+ messageType: 'error',
46
+ content: 'Please provide a checkpoint name to restore.',
47
+ });
48
+ });
49
+ it('should restore a checkpoint when a valid file is provided', async () => {
50
+ const command = new RestoreCommand();
51
+ const toolCallData = {
52
+ toolCall: {
53
+ name: 'test-tool',
54
+ args: {},
55
+ },
56
+ history: [],
57
+ clientHistory: [],
58
+ commitHash: '123',
59
+ };
60
+ mockFs.readFile.mockResolvedValue(JSON.stringify(toolCallData));
61
+ const restoreContent = {
62
+ type: 'message',
63
+ messageType: 'info',
64
+ content: 'Restored',
65
+ };
66
+ mockPerformRestore.mockReturnValue((async function* () {
67
+ yield restoreContent;
68
+ })());
69
+ const result = await command.execute(mockConfig, ['checkpoint1.json']);
70
+ expect(result.data).toEqual([restoreContent]);
71
+ });
72
+ it('should show "file not found" error for a non-existent checkpoint', async () => {
73
+ const command = new RestoreCommand();
74
+ const error = new Error('File not found');
75
+ error.code = 'ENOENT';
76
+ mockFs.readFile.mockRejectedValue(error);
77
+ const result = await command.execute(mockConfig, ['checkpoint2.json']);
78
+ expect(result.data).toEqual({
79
+ type: 'message',
80
+ messageType: 'error',
81
+ content: 'File not found: checkpoint2.json',
82
+ });
83
+ });
84
+ it('should handle invalid JSON in checkpoint file', async () => {
85
+ const command = new RestoreCommand();
86
+ mockFs.readFile.mockResolvedValue('invalid json');
87
+ const result = await command.execute(mockConfig, ['checkpoint1.json']);
88
+ expect(result.data.content).toContain('An unexpected error occurred during restore.');
89
+ });
90
+ });
91
+ describe('ListCheckpointsCommand', () => {
92
+ const mockConfig = {
93
+ config: createMockConfig(),
94
+ };
95
+ it('should list all available checkpoints', async () => {
96
+ const command = new ListCheckpointsCommand();
97
+ const checkpointInfo = [{ file: 'checkpoint1.json', description: 'Test' }];
98
+ mockFs.readdir.mockResolvedValue(['checkpoint1.json']);
99
+ mockFs.readFile.mockResolvedValue(JSON.stringify({ toolCall: { name: 'Test', args: {} } }));
100
+ mockGetCheckpointInfoList.mockReturnValue(checkpointInfo);
101
+ const result = await command.execute(mockConfig);
102
+ expect(result.data.content).toEqual(JSON.stringify(checkpointInfo));
103
+ });
104
+ it('should handle errors when listing checkpoints', async () => {
105
+ const command = new ListCheckpointsCommand();
106
+ mockFs.readdir.mockRejectedValue(new Error('Read error'));
107
+ const result = await command.execute(mockConfig);
108
+ expect(result.data.content).toContain('An unexpected error occurred while listing checkpoints.');
109
+ });
110
+ });
111
+ //# sourceMappingURL=restore.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore.test.js","sourceRoot":"","sources":["../../../src/commands/restore.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
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 { ExecutionEventBus, AgentExecutor } from '@a2a-js/sdk/server';
8
+ import type { Config, GitService } from '@terminai/core';
9
+ export interface CommandContext {
10
+ config: Config;
11
+ git?: GitService;
12
+ agentExecutor?: AgentExecutor;
13
+ eventBus?: ExecutionEventBus;
14
+ }
15
+ export interface CommandArgument {
16
+ readonly name: string;
17
+ readonly description: string;
18
+ readonly isRequired?: boolean;
19
+ }
20
+ export interface Command {
21
+ readonly name: string;
22
+ readonly description: string;
23
+ readonly arguments?: CommandArgument[];
24
+ readonly subCommands?: Command[];
25
+ readonly topLevel?: boolean;
26
+ readonly requiresWorkspace?: boolean;
27
+ readonly streaming?: boolean;
28
+ execute(config: CommandContext, args: string[]): Promise<CommandExecutionResponse>;
29
+ }
30
+ export interface CommandExecutionResponse {
31
+ readonly name: string;
32
+ readonly data: unknown;
33
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * Portions Copyright 2025 TerminaI Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/commands/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,24 @@
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, type ExtensionLoader } from '@terminai/core';
8
+ import type { LoadedSettings } from './settings.js';
9
+ import { type AgentSettings } from '../types.js';
10
+ export interface LoadConfigOptions {
11
+ /**
12
+ * When true, the server will start without calling `config.refreshAuth(...)`.
13
+ * This enables "deferred auth" flows (e.g. Desktop sidecar) where the client
14
+ * completes LLM auth after the server boots.
15
+ */
16
+ readonly deferLlmAuth?: boolean;
17
+ }
18
+ export declare function loadConfig(loadedSettings: LoadedSettings, extensionLoader: ExtensionLoader, taskId: string, targetDirOverride?: string, options?: LoadConfigOptions): Promise<Config>;
19
+ export declare function setTargetDir(agentSettings: AgentSettings | undefined): string;
20
+ /**
21
+ * Loads environment variables from .env file.
22
+ * Uses Core's findEnvFile for parity with CLI.
23
+ */
24
+ export declare function loadEnvironment(startDir?: string): void;