@renxqoo/renx-code 0.0.4 → 0.0.6

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 (210) hide show
  1. package/README.md +82 -51
  2. package/bin/renx.cjs +16 -0
  3. package/package.json +2 -45
  4. package/src/agent/runtime/runtime.context-usage.test.ts +4 -5
  5. package/src/agent/runtime/runtime.error-handling.test.ts +4 -5
  6. package/src/agent/runtime/runtime.test.ts +7 -4
  7. package/src/agent/runtime/runtime.ts +3 -9
  8. package/src/agent/runtime/runtime.usage-forwarding.test.ts +4 -5
  9. package/src/agent/runtime/source-modules.test.ts +16 -35
  10. package/src/agent/runtime/source-modules.ts +17 -0
  11. package/vendor/agent-root/src/agent/ENTERPRISE_ACCEPTANCE_CHECKLIST.md +95 -0
  12. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.html +1345 -0
  13. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.md +1353 -0
  14. package/vendor/agent-root/src/agent/ERROR_CONTRACT.md +60 -0
  15. package/vendor/agent-root/src/agent/TEST_COVERAGE_ANALYSIS.md +278 -0
  16. package/vendor/agent-root/src/agent/__test__/error-contract.test.ts +72 -0
  17. package/vendor/agent-root/src/agent/__test__/types.test.ts +137 -0
  18. package/vendor/agent-root/src/agent/agent/__test__/abort-runtime.test.ts +83 -0
  19. package/vendor/agent-root/src/agent/agent/__test__/callback-safety.test.ts +34 -0
  20. package/vendor/agent-root/src/agent/agent/__test__/compaction.test.ts +323 -0
  21. package/vendor/agent-root/src/agent/agent/__test__/concurrency.test.ts +290 -0
  22. package/vendor/agent-root/src/agent/agent/__test__/error-normalizer.test.ts +377 -0
  23. package/vendor/agent-root/src/agent/agent/__test__/error.test.ts +212 -0
  24. package/vendor/agent-root/src/agent/agent/__test__/fault-injection.test.ts +295 -0
  25. package/vendor/agent-root/src/agent/agent/__test__/index.test.ts +3607 -0
  26. package/vendor/agent-root/src/agent/agent/__test__/logger.test.ts +35 -0
  27. package/vendor/agent-root/src/agent/agent/__test__/message-utils.test.ts +517 -0
  28. package/vendor/agent-root/src/agent/agent/__test__/telemetry.test.ts +97 -0
  29. package/vendor/agent-root/src/agent/agent/__test__/timeout-budget.test.ts +479 -0
  30. package/vendor/agent-root/src/agent/agent/__test__/tool-call-merge.test.ts +80 -0
  31. package/vendor/agent-root/src/agent/agent/__test__/tool-execution-ledger.test.ts +76 -0
  32. package/vendor/agent-root/src/agent/agent/__test__/write-buffer.test.ts +173 -0
  33. package/vendor/agent-root/src/agent/agent/__test__/write-file-session.test.ts +109 -0
  34. package/vendor/agent-root/src/agent/agent/abort-runtime.ts +71 -0
  35. package/vendor/agent-root/src/agent/agent/callback-safety.ts +33 -0
  36. package/vendor/agent-root/src/agent/agent/compaction.ts +291 -0
  37. package/vendor/agent-root/src/agent/agent/concurrency.ts +103 -0
  38. package/vendor/agent-root/src/agent/agent/error-normalizer.ts +190 -0
  39. package/vendor/agent-root/src/agent/agent/error.ts +198 -0
  40. package/vendor/agent-root/src/agent/agent/index.ts +1772 -0
  41. package/vendor/agent-root/src/agent/agent/logger.ts +65 -0
  42. package/vendor/agent-root/src/agent/agent/message-utils.ts +101 -0
  43. package/vendor/agent-root/src/agent/agent/stream-events.ts +61 -0
  44. package/vendor/agent-root/src/agent/agent/telemetry.ts +123 -0
  45. package/vendor/agent-root/src/agent/agent/timeout-budget.ts +227 -0
  46. package/vendor/agent-root/src/agent/agent/tool-call-merge.ts +111 -0
  47. package/vendor/agent-root/src/agent/agent/tool-execution-ledger.ts +164 -0
  48. package/vendor/agent-root/src/agent/agent/write-buffer.ts +188 -0
  49. package/vendor/agent-root/src/agent/agent/write-file-session.ts +238 -0
  50. package/vendor/agent-root/src/agent/app/__test__/agent-app-service.test.ts +1053 -0
  51. package/vendor/agent-root/src/agent/app/__test__/minimal-agent-application.test.ts +158 -0
  52. package/vendor/agent-root/src/agent/app/__test__/sqlite-agent-app-store.test.ts +437 -0
  53. package/vendor/agent-root/src/agent/app/agent-app-service.ts +748 -0
  54. package/vendor/agent-root/src/agent/app/contracts.ts +109 -0
  55. package/vendor/agent-root/src/agent/app/index.ts +5 -0
  56. package/vendor/agent-root/src/agent/app/minimal-agent-application.ts +151 -0
  57. package/vendor/agent-root/src/agent/app/ports.ts +72 -0
  58. package/vendor/agent-root/src/agent/app/sqlite-agent-app-store.ts +1182 -0
  59. package/vendor/agent-root/src/agent/app/sqlite-client.ts +177 -0
  60. package/vendor/agent-root/src/agent/docs/cli-app-layer/00-README.md +36 -0
  61. package/vendor/agent-root/src/agent/docs/cli-app-layer/01-scope-and-goals.md +33 -0
  62. package/vendor/agent-root/src/agent/docs/cli-app-layer/02-architecture-overview.md +40 -0
  63. package/vendor/agent-root/src/agent/docs/cli-app-layer/03-domain-model-and-contracts.md +91 -0
  64. package/vendor/agent-root/src/agent/docs/cli-app-layer/04-ports-and-interfaces.md +116 -0
  65. package/vendor/agent-root/src/agent/docs/cli-app-layer/05-run-orchestration-and-state-machine.md +52 -0
  66. package/vendor/agent-root/src/agent/docs/cli-app-layer/06-cli-commands-and-ux.md +53 -0
  67. package/vendor/agent-root/src/agent/docs/cli-app-layer/07-storage-design-local.md +52 -0
  68. package/vendor/agent-root/src/agent/docs/cli-app-layer/08-error-and-observability.md +40 -0
  69. package/vendor/agent-root/src/agent/docs/cli-app-layer/09-security-and-policy-boundary.md +19 -0
  70. package/vendor/agent-root/src/agent/docs/cli-app-layer/10-test-plan-and-acceptance.md +28 -0
  71. package/vendor/agent-root/src/agent/docs/cli-app-layer/11-implementation-phases.md +26 -0
  72. package/vendor/agent-root/src/agent/docs/cli-app-layer/12-open-questions-and-risks.md +30 -0
  73. package/vendor/agent-root/src/agent/docs/cli-app-layer/13-sqlite-schema-fields-and-rationale.md +567 -0
  74. package/vendor/agent-root/src/agent/docs/cli-app-layer/14-project-flow-mermaid.md +583 -0
  75. package/vendor/agent-root/src/agent/docs/cli-app-layer/15-openclaw-style-project-blueprint.md +972 -0
  76. package/vendor/agent-root/src/agent/error-contract.ts +154 -0
  77. package/vendor/agent-root/src/agent/prompts/system.ts +246 -0
  78. package/vendor/agent-root/src/agent/prompts/system1.ts +208 -0
  79. package/vendor/agent-root/src/agent/storage/__test__/file-history-store.test.ts +98 -0
  80. package/vendor/agent-root/src/agent/storage/file-history-store.ts +313 -0
  81. package/vendor/agent-root/src/agent/storage/file-storage-config.ts +94 -0
  82. package/vendor/agent-root/src/agent/storage/file-system.ts +31 -0
  83. package/vendor/agent-root/src/agent/storage/file-write-service.ts +21 -0
  84. package/vendor/agent-root/src/agent/tool/__test__/base-tool.test.ts +413 -0
  85. package/vendor/agent-root/src/agent/tool/__test__/bash-policy.test.ts +356 -0
  86. package/vendor/agent-root/src/agent/tool/__test__/bash.mocked-coverage.test.ts +375 -0
  87. package/vendor/agent-root/src/agent/tool/__test__/bash.test.ts +372 -0
  88. package/vendor/agent-root/src/agent/tool/__test__/error.test.ts +108 -0
  89. package/vendor/agent-root/src/agent/tool/__test__/file-edit-tool.test.ts +258 -0
  90. package/vendor/agent-root/src/agent/tool/__test__/file-history-tools.test.ts +121 -0
  91. package/vendor/agent-root/src/agent/tool/__test__/file-read-tool.test.ts +210 -0
  92. package/vendor/agent-root/src/agent/tool/__test__/glob.test.ts +139 -0
  93. package/vendor/agent-root/src/agent/tool/__test__/grep.mocked-coverage.test.ts +456 -0
  94. package/vendor/agent-root/src/agent/tool/__test__/grep.test.ts +192 -0
  95. package/vendor/agent-root/src/agent/tool/__test__/lsp.test.ts +300 -0
  96. package/vendor/agent-root/src/agent/tool/__test__/outside-workspace-confirmation.test.ts +214 -0
  97. package/vendor/agent-root/src/agent/tool/__test__/path-security.test.ts +336 -0
  98. package/vendor/agent-root/src/agent/tool/__test__/skill-loader.test.ts +494 -0
  99. package/vendor/agent-root/src/agent/tool/__test__/skill-parser.test.ts +543 -0
  100. package/vendor/agent-root/src/agent/tool/__test__/skill-tool.test.ts +172 -0
  101. package/vendor/agent-root/src/agent/tool/__test__/task-concurrency-and-version.test.ts +116 -0
  102. package/vendor/agent-root/src/agent/tool/__test__/task-create-get-list-update.test.ts +267 -0
  103. package/vendor/agent-root/src/agent/tool/__test__/task-create.test.ts +519 -0
  104. package/vendor/agent-root/src/agent/tool/__test__/task-errors.test.ts +225 -0
  105. package/vendor/agent-root/src/agent/tool/__test__/task-output-blocking.test.ts +223 -0
  106. package/vendor/agent-root/src/agent/tool/__test__/task-output.test.ts +184 -0
  107. package/vendor/agent-root/src/agent/tool/__test__/task-parent-abort.test.ts +287 -0
  108. package/vendor/agent-root/src/agent/tool/__test__/task-real-runner-adapter.test.ts +190 -0
  109. package/vendor/agent-root/src/agent/tool/__test__/task-run-lifecycle.test.ts +352 -0
  110. package/vendor/agent-root/src/agent/tool/__test__/task-store-runner-branches.test.ts +395 -0
  111. package/vendor/agent-root/src/agent/tool/__test__/task-store.test.ts +391 -0
  112. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config-integration.test.ts +176 -0
  113. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config.test.ts +68 -0
  114. package/vendor/agent-root/src/agent/tool/__test__/task-tools-core-edges.test.ts +630 -0
  115. package/vendor/agent-root/src/agent/tool/__test__/task-tools-runtime-edges.test.ts +732 -0
  116. package/vendor/agent-root/src/agent/tool/__test__/task-types.test.ts +494 -0
  117. package/vendor/agent-root/src/agent/tool/__test__/task-utils-branches.test.ts +175 -0
  118. package/vendor/agent-root/src/agent/tool/__test__/tool-manager.test.ts +505 -0
  119. package/vendor/agent-root/src/agent/tool/__test__/types.test.ts +55 -0
  120. package/vendor/agent-root/src/agent/tool/__test__/web-fetch.test.ts +244 -0
  121. package/vendor/agent-root/src/agent/tool/__test__/web-search.test.ts +290 -0
  122. package/vendor/agent-root/src/agent/tool/__test__/write-file.test.ts +368 -0
  123. package/vendor/agent-root/src/agent/tool/base-tool.ts +345 -0
  124. package/vendor/agent-root/src/agent/tool/bash-policy.ts +636 -0
  125. package/vendor/agent-root/src/agent/tool/bash.ts +688 -0
  126. package/vendor/agent-root/src/agent/tool/error.ts +131 -0
  127. package/vendor/agent-root/src/agent/tool/file-edit-tool.ts +264 -0
  128. package/vendor/agent-root/src/agent/tool/file-history-list.ts +103 -0
  129. package/vendor/agent-root/src/agent/tool/file-history-restore.ts +149 -0
  130. package/vendor/agent-root/src/agent/tool/file-read-tool.ts +211 -0
  131. package/vendor/agent-root/src/agent/tool/glob.ts +171 -0
  132. package/vendor/agent-root/src/agent/tool/grep.ts +496 -0
  133. package/vendor/agent-root/src/agent/tool/lsp.ts +481 -0
  134. package/vendor/agent-root/src/agent/tool/path-security.ts +117 -0
  135. package/vendor/agent-root/src/agent/tool/search/common.ts +153 -0
  136. package/vendor/agent-root/src/agent/tool/skill/index.ts +13 -0
  137. package/vendor/agent-root/src/agent/tool/skill/loader.ts +229 -0
  138. package/vendor/agent-root/src/agent/tool/skill/parser.ts +124 -0
  139. package/vendor/agent-root/src/agent/tool/skill/types.ts +27 -0
  140. package/vendor/agent-root/src/agent/tool/skill-tool.ts +143 -0
  141. package/vendor/agent-root/src/agent/tool/task-create.ts +186 -0
  142. package/vendor/agent-root/src/agent/tool/task-errors.ts +42 -0
  143. package/vendor/agent-root/src/agent/tool/task-get.ts +116 -0
  144. package/vendor/agent-root/src/agent/tool/task-graph.ts +78 -0
  145. package/vendor/agent-root/src/agent/tool/task-list.ts +141 -0
  146. package/vendor/agent-root/src/agent/tool/task-mock-runner-adapter.ts +232 -0
  147. package/vendor/agent-root/src/agent/tool/task-output.ts +223 -0
  148. package/vendor/agent-root/src/agent/tool/task-parent-abort.ts +115 -0
  149. package/vendor/agent-root/src/agent/tool/task-real-runner-adapter.ts +336 -0
  150. package/vendor/agent-root/src/agent/tool/task-runner-adapter.ts +55 -0
  151. package/vendor/agent-root/src/agent/tool/task-stop.ts +187 -0
  152. package/vendor/agent-root/src/agent/tool/task-store.ts +217 -0
  153. package/vendor/agent-root/src/agent/tool/task-subagent-config.ts +149 -0
  154. package/vendor/agent-root/src/agent/tool/task-types.ts +264 -0
  155. package/vendor/agent-root/src/agent/tool/task-update.ts +315 -0
  156. package/vendor/agent-root/src/agent/tool/task.ts +209 -0
  157. package/vendor/agent-root/src/agent/tool/tool-manager.ts +362 -0
  158. package/vendor/agent-root/src/agent/tool/tool-prompts.ts +242 -0
  159. package/vendor/agent-root/src/agent/tool/types.ts +116 -0
  160. package/vendor/agent-root/src/agent/tool/web-fetch.ts +227 -0
  161. package/vendor/agent-root/src/agent/tool/web-search.ts +208 -0
  162. package/vendor/agent-root/src/agent/tool/write-file.ts +497 -0
  163. package/vendor/agent-root/src/agent/types.ts +232 -0
  164. package/vendor/agent-root/src/agent/utils/__tests__/index.test.ts +18 -0
  165. package/vendor/agent-root/src/agent/utils/__tests__/message-utils.test.ts +610 -0
  166. package/vendor/agent-root/src/agent/utils/__tests__/message.test.ts +223 -0
  167. package/vendor/agent-root/src/agent/utils/__tests__/token.test.ts +42 -0
  168. package/vendor/agent-root/src/agent/utils/index.ts +16 -0
  169. package/vendor/agent-root/src/agent/utils/message.ts +171 -0
  170. package/vendor/agent-root/src/agent/utils/token.ts +28 -0
  171. package/vendor/agent-root/src/config/__tests__/load-config-to-env.test.ts +129 -0
  172. package/vendor/agent-root/src/config/__tests__/loader.test.ts +247 -0
  173. package/vendor/agent-root/src/config/__tests__/runtime.test.ts +88 -0
  174. package/vendor/agent-root/src/config/index.ts +54 -0
  175. package/vendor/agent-root/src/config/loader.ts +431 -0
  176. package/vendor/agent-root/src/config/paths.ts +30 -0
  177. package/vendor/agent-root/src/config/runtime.ts +163 -0
  178. package/vendor/agent-root/src/config/types.ts +70 -0
  179. package/vendor/agent-root/src/logger/index.ts +57 -0
  180. package/vendor/agent-root/src/logger/logger.ts +819 -0
  181. package/vendor/agent-root/src/logger/types.ts +150 -0
  182. package/vendor/agent-root/src/providers/__tests__/errors.test.ts +441 -0
  183. package/vendor/agent-root/src/providers/__tests__/index.test.ts +16 -0
  184. package/vendor/agent-root/src/providers/__tests__/openai-compatible.options.test.ts +318 -0
  185. package/vendor/agent-root/src/providers/__tests__/openai-compatible.test.ts +600 -0
  186. package/vendor/agent-root/src/providers/__tests__/registry.test.ts +449 -0
  187. package/vendor/agent-root/src/providers/__tests__/responses-adapter.test.ts +298 -0
  188. package/vendor/agent-root/src/providers/adapters/__tests__/anthropic.test.ts +354 -0
  189. package/vendor/agent-root/src/providers/adapters/__tests__/kimi.test.ts +58 -0
  190. package/vendor/agent-root/src/providers/adapters/__tests__/standard.test.ts +261 -0
  191. package/vendor/agent-root/src/providers/adapters/anthropic.ts +572 -0
  192. package/vendor/agent-root/src/providers/adapters/base.ts +131 -0
  193. package/vendor/agent-root/src/providers/adapters/kimi.ts +48 -0
  194. package/vendor/agent-root/src/providers/adapters/responses.ts +732 -0
  195. package/vendor/agent-root/src/providers/adapters/standard.ts +120 -0
  196. package/vendor/agent-root/src/providers/http/__tests__/client.timeout.test.ts +313 -0
  197. package/vendor/agent-root/src/providers/http/client.ts +289 -0
  198. package/vendor/agent-root/src/providers/http/stream-parser.ts +109 -0
  199. package/vendor/agent-root/src/providers/index.ts +76 -0
  200. package/vendor/agent-root/src/providers/kimi-headers.ts +177 -0
  201. package/vendor/agent-root/src/providers/openai-compatible.ts +387 -0
  202. package/vendor/agent-root/src/providers/registry/model-config.ts +230 -0
  203. package/vendor/agent-root/src/providers/registry/provider-factory.ts +123 -0
  204. package/vendor/agent-root/src/providers/registry.ts +135 -0
  205. package/vendor/agent-root/src/providers/types/api.ts +284 -0
  206. package/vendor/agent-root/src/providers/types/config.ts +58 -0
  207. package/vendor/agent-root/src/providers/types/errors.ts +323 -0
  208. package/vendor/agent-root/src/providers/types/index.ts +72 -0
  209. package/vendor/agent-root/src/providers/types/provider.ts +45 -0
  210. package/vendor/agent-root/src/providers/types/registry.ts +88 -0
@@ -0,0 +1,375 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import * as fsp from 'node:fs/promises';
3
+ import * as os from 'node:os';
4
+ import * as path from 'node:path';
5
+ import { PassThrough } from 'node:stream';
6
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
7
+
8
+ const { spawnMock, spawnSyncMock, existsSyncMock } = vi.hoisted(() => ({
9
+ spawnMock: vi.fn(),
10
+ spawnSyncMock: vi.fn(),
11
+ existsSyncMock: vi.fn(),
12
+ }));
13
+
14
+ vi.mock('node:child_process', () => ({
15
+ spawn: spawnMock,
16
+ spawnSync: spawnSyncMock,
17
+ }));
18
+
19
+ vi.mock('node:fs', async () => {
20
+ const actual = await vi.importActual<typeof import('node:fs')>('node:fs');
21
+ return {
22
+ ...actual,
23
+ existsSync: existsSyncMock,
24
+ };
25
+ });
26
+
27
+ import { BashTool } from '../bash';
28
+
29
+ const originalPlatformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
30
+
31
+ function setPlatform(value: NodeJS.Platform): void {
32
+ Object.defineProperty(process, 'platform', {
33
+ configurable: true,
34
+ value,
35
+ });
36
+ }
37
+
38
+ function restorePlatform(): void {
39
+ if (originalPlatformDescriptor) {
40
+ Object.defineProperty(process, 'platform', originalPlatformDescriptor);
41
+ }
42
+ }
43
+
44
+ function createChild(options: { withStdout?: boolean; withStderr?: boolean; pid?: number } = {}) {
45
+ const child = new EventEmitter() as EventEmitter & {
46
+ stdout?: PassThrough;
47
+ stderr?: PassThrough;
48
+ pid?: number;
49
+ killed: boolean;
50
+ kill: (signal?: string) => boolean;
51
+ unref: () => void;
52
+ };
53
+ if (options.withStdout !== false) {
54
+ child.stdout = new PassThrough();
55
+ }
56
+ if (options.withStderr !== false) {
57
+ child.stderr = new PassThrough();
58
+ }
59
+ child.pid = options.pid ?? 4242;
60
+ child.killed = false;
61
+ child.kill = vi.fn((): boolean => {
62
+ child.killed = true;
63
+ return true;
64
+ }) as unknown as (signal?: string) => boolean;
65
+ child.unref = vi.fn() as unknown as () => void;
66
+ return child;
67
+ }
68
+
69
+ describe('BashTool mocked branch coverage', () => {
70
+ beforeEach(() => {
71
+ spawnMock.mockReset();
72
+ spawnSyncMock.mockReset();
73
+ existsSyncMock.mockReset();
74
+ existsSyncMock.mockReturnValue(false);
75
+ spawnSyncMock.mockReturnValue({ status: 1, stdout: '' });
76
+ delete process.env.BASH_TOOL_SHELL;
77
+ delete process.env.BASH_TOOL_POLICY;
78
+ });
79
+
80
+ afterEach(() => {
81
+ vi.restoreAllMocks();
82
+ vi.useRealTimers();
83
+ restorePlatform();
84
+ delete process.env.BASH_TOOL_SHELL;
85
+ delete process.env.BASH_TOOL_POLICY;
86
+ });
87
+
88
+ it('denies empty commands and uses fallback deny reason when policy reason is missing', async () => {
89
+ const tool = new BashTool();
90
+ const empty = await tool.execute({ command: ' ' });
91
+ expect(empty.success).toBe(false);
92
+ expect(empty.output).toContain('Command is empty');
93
+
94
+ const helper = tool as unknown as {
95
+ validatePolicy: (command: string) => { effect: 'allow' | 'ask' | 'deny'; reason?: string };
96
+ };
97
+ vi.spyOn(helper, 'validatePolicy').mockReturnValueOnce({ effect: 'deny' });
98
+ const denied = await tool.execute({ command: 'echo x' });
99
+ expect(denied.success).toBe(false);
100
+ expect(denied.output).toContain('Command not allowed');
101
+ });
102
+
103
+ it('covers background unknown pid and non-Error execution failure mapping', async () => {
104
+ const tool = new BashTool();
105
+ const helper = tool as unknown as {
106
+ executeInBackground: (command: string) => Promise<{ pid?: number; logPath: string }>;
107
+ executeForeground: () => Promise<never>;
108
+ };
109
+ vi.spyOn(helper, 'executeInBackground').mockResolvedValueOnce({ logPath: 'bg.log' });
110
+ const bg = await tool.execute({ command: 'echo bg', run_in_background: true });
111
+ expect(bg.success).toBe(true);
112
+ expect(bg.output).toContain('pid=unknown');
113
+
114
+ vi.spyOn(helper, 'executeForeground').mockRejectedValueOnce('STRING_FAILURE');
115
+ const failed = await tool.execute({ command: 'echo fg' });
116
+ expect(failed.success).toBe(false);
117
+ expect(failed.output).toBe('EXECUTION_FAILED: STRING_FAILURE');
118
+ });
119
+
120
+ it('covers executeForeground fail path and finish guard path', async () => {
121
+ const tool = new BashTool();
122
+ const helper = tool as unknown as {
123
+ executeForeground: (
124
+ command: string,
125
+ timeoutMs: number,
126
+ abortSignal?: AbortSignal
127
+ ) => Promise<{ exitCode: number; output: string; timedOut: boolean }>;
128
+ };
129
+
130
+ const child = createChild();
131
+ spawnMock.mockReturnValueOnce(child);
132
+
133
+ const run = helper.executeForeground('echo x', 0);
134
+ child.emit('error', new Error('spawn failed'));
135
+ child.emit('close', 1, null);
136
+ await expect(run).rejects.toThrow('spawn failed');
137
+ });
138
+
139
+ it('covers executeForeground fail guard branch after successful close', async () => {
140
+ const tool = new BashTool();
141
+ const helper = tool as unknown as {
142
+ executeForeground: (
143
+ command: string,
144
+ timeoutMs: number,
145
+ abortSignal?: AbortSignal
146
+ ) => Promise<{ exitCode: number; output: string; timedOut: boolean }>;
147
+ };
148
+
149
+ const child = createChild();
150
+ spawnMock.mockReturnValueOnce(child);
151
+ const run = helper.executeForeground('echo ok', 0);
152
+ child.emit('close', 0, null);
153
+ const result = await run;
154
+ expect(result.exitCode).toBe(0);
155
+
156
+ child.emit('error', new Error('late error should be ignored'));
157
+ });
158
+
159
+ it('covers executeForeground abort branches (already aborted + listener)', async () => {
160
+ const tool = new BashTool();
161
+ const helper = tool as unknown as {
162
+ executeForeground: (
163
+ command: string,
164
+ timeoutMs: number,
165
+ abortSignal?: AbortSignal
166
+ ) => Promise<{ exitCode: number; output: string; timedOut: boolean }>;
167
+ terminateChildProcess: (child: unknown) => void;
168
+ };
169
+ vi.spyOn(helper, 'terminateChildProcess').mockImplementation(() => {});
170
+
171
+ const firstChild = createChild();
172
+ spawnMock.mockReturnValueOnce(firstChild);
173
+ const firstAbort = new AbortController();
174
+ firstAbort.abort();
175
+ const firstRun = helper.executeForeground('echo first', 0, firstAbort.signal);
176
+ firstChild.emit('close', null, null);
177
+ const firstResult = await firstRun;
178
+ expect(firstResult.timedOut).toBe(true);
179
+
180
+ const secondChild = createChild();
181
+ spawnMock.mockReturnValueOnce(secondChild);
182
+ const secondAbort = new AbortController();
183
+ const secondRun = helper.executeForeground('echo second', 0, secondAbort.signal);
184
+ secondAbort.abort();
185
+ secondChild.emit('close', 0, null);
186
+ const secondResult = await secondRun;
187
+ expect(secondResult.timedOut).toBe(true);
188
+ });
189
+
190
+ it('covers executeForeground close fallback exitCode branch', async () => {
191
+ const tool = new BashTool();
192
+ const helper = tool as unknown as {
193
+ executeForeground: (
194
+ command: string,
195
+ timeoutMs: number,
196
+ abortSignal?: AbortSignal
197
+ ) => Promise<{ exitCode: number; output: string; timedOut: boolean }>;
198
+ };
199
+ const child = createChild();
200
+ spawnMock.mockReturnValueOnce(child);
201
+
202
+ const run = helper.executeForeground('echo fallback', 0);
203
+ child.emit('close', null, null);
204
+ const result = await run;
205
+ expect(result.exitCode).toBe(0);
206
+ });
207
+
208
+ it('covers executeForeground signal-based exit code fallback', async () => {
209
+ const tool = new BashTool();
210
+ const helper = tool as unknown as {
211
+ executeForeground: (
212
+ command: string,
213
+ timeoutMs: number,
214
+ abortSignal?: AbortSignal
215
+ ) => Promise<{ exitCode: number; output: string; timedOut: boolean }>;
216
+ };
217
+ const child = createChild();
218
+ spawnMock.mockReturnValueOnce(child);
219
+
220
+ const run = helper.executeForeground('echo signal', 0);
221
+ child.emit('close', null, 'SIGTERM');
222
+ const result = await run;
223
+ expect(result.exitCode).toBe(1);
224
+ });
225
+
226
+ it('covers executeForeground timeout callback branch', async () => {
227
+ vi.useFakeTimers();
228
+ const tool = new BashTool();
229
+ const helper = tool as unknown as {
230
+ executeForeground: (
231
+ command: string,
232
+ timeoutMs: number,
233
+ abortSignal?: AbortSignal
234
+ ) => Promise<{ exitCode: number; output: string; timedOut: boolean }>;
235
+ terminateChildProcess: (child: unknown) => void;
236
+ };
237
+ const terminateSpy = vi.spyOn(helper, 'terminateChildProcess').mockImplementation(() => {});
238
+
239
+ const child = createChild();
240
+ spawnMock.mockReturnValueOnce(child);
241
+
242
+ const run = helper.executeForeground('echo timeout', 50);
243
+ await vi.advanceTimersByTimeAsync(50);
244
+ child.emit('close', 0, null);
245
+ const result = await run;
246
+
247
+ expect(result.timedOut).toBe(true);
248
+ expect(terminateSpy).toHaveBeenCalled();
249
+ });
250
+
251
+ it('covers executeInBackground non-win log quoting branch', async () => {
252
+ setPlatform('linux');
253
+ const bgDir = await fsp.mkdtemp(path.join(os.tmpdir(), "bash-bg-'"));
254
+ const tool = new BashTool({ backgroundLogDir: bgDir });
255
+ const helper = tool as unknown as {
256
+ executeInBackground: (command: string) => Promise<{ pid?: number; logPath: string }>;
257
+ };
258
+
259
+ const child = createChild();
260
+ spawnMock.mockReturnValueOnce(child);
261
+
262
+ const result = await helper.executeInBackground('echo hello');
263
+ expect(result.logPath).toContain('agent-bash-bg-');
264
+ expect(child.unref).toHaveBeenCalled();
265
+ });
266
+
267
+ it('covers resolveShell windows cmd fallback and git-bash branch', () => {
268
+ setPlatform('win32');
269
+ const tool = new BashTool();
270
+ const helper = tool as unknown as {
271
+ resolveShell: (command: string) => { shellPath: string; shellArgs: string[] };
272
+ findGitBashPath: () => string | null;
273
+ };
274
+
275
+ vi.spyOn(helper, 'findGitBashPath').mockReturnValueOnce('C:\\Git\\bin\\bash.exe');
276
+ const gitBashShell = helper.resolveShell('echo hi');
277
+ expect(gitBashShell.shellPath).toBe('C:\\Git\\bin\\bash.exe');
278
+
279
+ const originalComspec = process.env.COMSPEC;
280
+ delete process.env.COMSPEC;
281
+ vi.spyOn(helper, 'findGitBashPath').mockReturnValueOnce(null);
282
+ const cmdShell = helper.resolveShell('echo hi');
283
+ expect(cmdShell.shellPath).toBe('cmd.exe');
284
+ process.env.COMSPEC = originalComspec;
285
+ });
286
+
287
+ it('covers findGitBashPath non-win, inferred probe, probe catch, and probe miss', () => {
288
+ const tool = new BashTool();
289
+ const helper = tool as unknown as { findGitBashPath: () => string | null };
290
+
291
+ setPlatform('linux');
292
+ expect(helper.findGitBashPath()).toBeNull();
293
+
294
+ setPlatform('win32');
295
+ spawnSyncMock.mockReturnValueOnce({
296
+ status: 0,
297
+ stdout: 'C:\\Tools\\Git\\cmd\\git.exe\r\n',
298
+ });
299
+ existsSyncMock.mockImplementation((candidate: string) => {
300
+ if (candidate === 'C:\\Tools\\Git\\cmd\\git.exe') {
301
+ return true;
302
+ }
303
+ // Return false for inferred bash.exe path to test probe miss
304
+ return false;
305
+ });
306
+ expect(helper.findGitBashPath()).toBeNull();
307
+
308
+ existsSyncMock.mockReturnValue(false);
309
+ spawnSyncMock.mockImplementationOnce(() => {
310
+ throw new Error('where failed');
311
+ });
312
+ expect(helper.findGitBashPath()).toBeNull();
313
+
314
+ spawnSyncMock.mockReset();
315
+ spawnSyncMock.mockReturnValueOnce({ status: 1, stdout: '' });
316
+ expect(helper.findGitBashPath()).toBeNull();
317
+ });
318
+
319
+ it('covers terminateChildProcess windows catch and unix fallback catch paths', () => {
320
+ const tool = new BashTool();
321
+ type KillableChild = {
322
+ pid?: number;
323
+ killed: boolean;
324
+ kill: (signal?: string) => boolean;
325
+ };
326
+ const helper = tool as unknown as { terminateChildProcess: (child: KillableChild) => void };
327
+
328
+ setPlatform('win32');
329
+ spawnMock.mockImplementationOnce(() => {
330
+ throw new Error('taskkill failed');
331
+ });
332
+ helper.terminateChildProcess({
333
+ pid: 100,
334
+ killed: false,
335
+ kill: vi.fn(),
336
+ });
337
+
338
+ setPlatform('linux');
339
+ vi.useFakeTimers();
340
+ const killSpy = vi.spyOn(process, 'kill').mockImplementation(() => {
341
+ throw new Error('kill failed');
342
+ });
343
+ const child: KillableChild = {
344
+ pid: 200,
345
+ killed: false,
346
+ kill: vi.fn(() => {
347
+ throw new Error('child kill failed');
348
+ }),
349
+ };
350
+ helper.terminateChildProcess(child);
351
+ vi.advanceTimersByTime(250);
352
+ expect(killSpy).toHaveBeenCalled();
353
+ expect(child.kill).toHaveBeenCalled();
354
+ });
355
+
356
+ it('covers constructor fallback for invalid default timeout option', () => {
357
+ const invalid = new BashTool({ defaultTimeoutMs: -1 });
358
+ const invalidHelper = invalid as unknown as { defaultTimeoutMs: number };
359
+ expect(invalidHelper.defaultTimeoutMs).toBe(60000);
360
+
361
+ const valid = new BashTool({ defaultTimeoutMs: 1234 });
362
+ const validHelper = valid as unknown as { defaultTimeoutMs: number };
363
+ expect(validHelper.defaultTimeoutMs).toBe(1234);
364
+ });
365
+
366
+ it('covers hard-cut truncation branch for tiny output budgets', () => {
367
+ const tool = new BashTool({ maxOutputLength: 16 });
368
+ const helper = tool as unknown as {
369
+ truncateOutput: (output: string) => { output: string; truncated: boolean };
370
+ };
371
+ const result = helper.truncateOutput('x'.repeat(100));
372
+ expect(result.truncated).toBe(true);
373
+ expect(result.output.length).toBe(16);
374
+ });
375
+ });