gencode-ai 0.1.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 (274) hide show
  1. package/.env.example +11 -0
  2. package/CLAUDE.md +70 -0
  3. package/LICENSE +21 -0
  4. package/README.md +117 -0
  5. package/dist/agent/agent.d.ts +84 -0
  6. package/dist/agent/agent.d.ts.map +1 -0
  7. package/dist/agent/agent.js +233 -0
  8. package/dist/agent/agent.js.map +1 -0
  9. package/dist/agent/index.d.ts +6 -0
  10. package/dist/agent/index.d.ts.map +1 -0
  11. package/dist/agent/index.js +6 -0
  12. package/dist/agent/index.js.map +1 -0
  13. package/dist/agent/types.d.ts +47 -0
  14. package/dist/agent/types.d.ts.map +1 -0
  15. package/dist/agent/types.js +5 -0
  16. package/dist/agent/types.js.map +1 -0
  17. package/dist/cli/components/App.d.ts +14 -0
  18. package/dist/cli/components/App.d.ts.map +1 -0
  19. package/dist/cli/components/App.js +395 -0
  20. package/dist/cli/components/App.js.map +1 -0
  21. package/dist/cli/components/CommandSuggestions.d.ts +13 -0
  22. package/dist/cli/components/CommandSuggestions.d.ts.map +1 -0
  23. package/dist/cli/components/CommandSuggestions.js +32 -0
  24. package/dist/cli/components/CommandSuggestions.js.map +1 -0
  25. package/dist/cli/components/Header.d.ts +9 -0
  26. package/dist/cli/components/Header.d.ts.map +1 -0
  27. package/dist/cli/components/Header.js +13 -0
  28. package/dist/cli/components/Header.js.map +1 -0
  29. package/dist/cli/components/Input.d.ts +13 -0
  30. package/dist/cli/components/Input.d.ts.map +1 -0
  31. package/dist/cli/components/Input.js +27 -0
  32. package/dist/cli/components/Input.js.map +1 -0
  33. package/dist/cli/components/Logo.d.ts +2 -0
  34. package/dist/cli/components/Logo.d.ts.map +1 -0
  35. package/dist/cli/components/Logo.js +8 -0
  36. package/dist/cli/components/Logo.js.map +1 -0
  37. package/dist/cli/components/Messages.d.ts +37 -0
  38. package/dist/cli/components/Messages.d.ts.map +1 -0
  39. package/dist/cli/components/Messages.js +106 -0
  40. package/dist/cli/components/Messages.js.map +1 -0
  41. package/dist/cli/components/ModelSelector.d.ts +13 -0
  42. package/dist/cli/components/ModelSelector.d.ts.map +1 -0
  43. package/dist/cli/components/ModelSelector.js +72 -0
  44. package/dist/cli/components/ModelSelector.js.map +1 -0
  45. package/dist/cli/components/Spinner.d.ts +12 -0
  46. package/dist/cli/components/Spinner.d.ts.map +1 -0
  47. package/dist/cli/components/Spinner.js +45 -0
  48. package/dist/cli/components/Spinner.js.map +1 -0
  49. package/dist/cli/components/index.d.ts +12 -0
  50. package/dist/cli/components/index.d.ts.map +1 -0
  51. package/dist/cli/components/index.js +12 -0
  52. package/dist/cli/components/index.js.map +1 -0
  53. package/dist/cli/components/theme.d.ts +31 -0
  54. package/dist/cli/components/theme.d.ts.map +1 -0
  55. package/dist/cli/components/theme.js +36 -0
  56. package/dist/cli/components/theme.js.map +1 -0
  57. package/dist/cli/index-legacy.d.ts +7 -0
  58. package/dist/cli/index-legacy.d.ts.map +1 -0
  59. package/dist/cli/index-legacy.js +431 -0
  60. package/dist/cli/index-legacy.js.map +1 -0
  61. package/dist/cli/index.d.ts +7 -0
  62. package/dist/cli/index.d.ts.map +1 -0
  63. package/dist/cli/index.js +116 -0
  64. package/dist/cli/index.js.map +1 -0
  65. package/dist/cli/ink-cli.d.ts +7 -0
  66. package/dist/cli/ink-cli.d.ts.map +1 -0
  67. package/dist/cli/ink-cli.js +105 -0
  68. package/dist/cli/ink-cli.js.map +1 -0
  69. package/dist/cli/session-picker.d.ts +16 -0
  70. package/dist/cli/session-picker.d.ts.map +1 -0
  71. package/dist/cli/session-picker.js +280 -0
  72. package/dist/cli/session-picker.js.map +1 -0
  73. package/dist/cli/ui.d.ts +61 -0
  74. package/dist/cli/ui.d.ts.map +1 -0
  75. package/dist/cli/ui.js +364 -0
  76. package/dist/cli/ui.js.map +1 -0
  77. package/dist/config/index.d.ts +7 -0
  78. package/dist/config/index.d.ts.map +1 -0
  79. package/dist/config/index.js +6 -0
  80. package/dist/config/index.js.map +1 -0
  81. package/dist/config/manager.d.ts +31 -0
  82. package/dist/config/manager.d.ts.map +1 -0
  83. package/dist/config/manager.js +65 -0
  84. package/dist/config/manager.js.map +1 -0
  85. package/dist/config/types.d.ts +22 -0
  86. package/dist/config/types.d.ts.map +1 -0
  87. package/dist/config/types.js +6 -0
  88. package/dist/config/types.js.map +1 -0
  89. package/dist/index.d.ts +12 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +21 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/memory/index.d.ts +10 -0
  94. package/dist/memory/index.d.ts.map +1 -0
  95. package/dist/memory/index.js +9 -0
  96. package/dist/memory/index.js.map +1 -0
  97. package/dist/memory/init.d.ts +20 -0
  98. package/dist/memory/init.d.ts.map +1 -0
  99. package/dist/memory/init.js +332 -0
  100. package/dist/memory/init.js.map +1 -0
  101. package/dist/memory/manager.d.ts +85 -0
  102. package/dist/memory/manager.d.ts.map +1 -0
  103. package/dist/memory/manager.js +234 -0
  104. package/dist/memory/manager.js.map +1 -0
  105. package/dist/memory/types.d.ts +74 -0
  106. package/dist/memory/types.d.ts.map +1 -0
  107. package/dist/memory/types.js +6 -0
  108. package/dist/memory/types.js.map +1 -0
  109. package/dist/permissions/index.d.ts +7 -0
  110. package/dist/permissions/index.d.ts.map +1 -0
  111. package/dist/permissions/index.js +6 -0
  112. package/dist/permissions/index.js.map +1 -0
  113. package/dist/permissions/manager.d.ts +32 -0
  114. package/dist/permissions/manager.d.ts.map +1 -0
  115. package/dist/permissions/manager.js +79 -0
  116. package/dist/permissions/manager.js.map +1 -0
  117. package/dist/permissions/types.d.ts +14 -0
  118. package/dist/permissions/types.d.ts.map +1 -0
  119. package/dist/permissions/types.js +17 -0
  120. package/dist/permissions/types.js.map +1 -0
  121. package/dist/providers/anthropic.d.ts +20 -0
  122. package/dist/providers/anthropic.d.ts.map +1 -0
  123. package/dist/providers/anthropic.js +185 -0
  124. package/dist/providers/anthropic.js.map +1 -0
  125. package/dist/providers/gemini.d.ts +21 -0
  126. package/dist/providers/gemini.d.ts.map +1 -0
  127. package/dist/providers/gemini.js +241 -0
  128. package/dist/providers/gemini.js.map +1 -0
  129. package/dist/providers/index.d.ts +34 -0
  130. package/dist/providers/index.d.ts.map +1 -0
  131. package/dist/providers/index.js +72 -0
  132. package/dist/providers/index.js.map +1 -0
  133. package/dist/providers/openai.d.ts +19 -0
  134. package/dist/providers/openai.d.ts.map +1 -0
  135. package/dist/providers/openai.js +221 -0
  136. package/dist/providers/openai.js.map +1 -0
  137. package/dist/providers/types.d.ts +125 -0
  138. package/dist/providers/types.d.ts.map +1 -0
  139. package/dist/providers/types.js +6 -0
  140. package/dist/providers/types.js.map +1 -0
  141. package/dist/session/index.d.ts +6 -0
  142. package/dist/session/index.d.ts.map +1 -0
  143. package/dist/session/index.js +6 -0
  144. package/dist/session/index.js.map +1 -0
  145. package/dist/session/manager.d.ts +101 -0
  146. package/dist/session/manager.d.ts.map +1 -0
  147. package/dist/session/manager.js +295 -0
  148. package/dist/session/manager.js.map +1 -0
  149. package/dist/session/types.d.ts +39 -0
  150. package/dist/session/types.d.ts.map +1 -0
  151. package/dist/session/types.js +10 -0
  152. package/dist/session/types.js.map +1 -0
  153. package/dist/tools/builtin/bash.d.ts +7 -0
  154. package/dist/tools/builtin/bash.d.ts.map +1 -0
  155. package/dist/tools/builtin/bash.js +80 -0
  156. package/dist/tools/builtin/bash.js.map +1 -0
  157. package/dist/tools/builtin/edit.d.ts +7 -0
  158. package/dist/tools/builtin/edit.d.ts.map +1 -0
  159. package/dist/tools/builtin/edit.js +32 -0
  160. package/dist/tools/builtin/edit.js.map +1 -0
  161. package/dist/tools/builtin/glob.d.ts +7 -0
  162. package/dist/tools/builtin/glob.d.ts.map +1 -0
  163. package/dist/tools/builtin/glob.js +36 -0
  164. package/dist/tools/builtin/glob.js.map +1 -0
  165. package/dist/tools/builtin/grep.d.ts +7 -0
  166. package/dist/tools/builtin/grep.d.ts.map +1 -0
  167. package/dist/tools/builtin/grep.js +59 -0
  168. package/dist/tools/builtin/grep.js.map +1 -0
  169. package/dist/tools/builtin/read.d.ts +7 -0
  170. package/dist/tools/builtin/read.d.ts.map +1 -0
  171. package/dist/tools/builtin/read.js +29 -0
  172. package/dist/tools/builtin/read.js.map +1 -0
  173. package/dist/tools/builtin/write.d.ts +7 -0
  174. package/dist/tools/builtin/write.d.ts.map +1 -0
  175. package/dist/tools/builtin/write.js +24 -0
  176. package/dist/tools/builtin/write.js.map +1 -0
  177. package/dist/tools/index.d.ts +38 -0
  178. package/dist/tools/index.d.ts.map +1 -0
  179. package/dist/tools/index.js +32 -0
  180. package/dist/tools/index.js.map +1 -0
  181. package/dist/tools/registry.d.ts +22 -0
  182. package/dist/tools/registry.d.ts.map +1 -0
  183. package/dist/tools/registry.js +71 -0
  184. package/dist/tools/registry.js.map +1 -0
  185. package/dist/tools/types.d.ts +62 -0
  186. package/dist/tools/types.d.ts.map +1 -0
  187. package/dist/tools/types.js +126 -0
  188. package/dist/tools/types.js.map +1 -0
  189. package/docs/README.md +16 -0
  190. package/docs/proposals/0001-web-fetch-tool.md +293 -0
  191. package/docs/proposals/0002-web-search-tool.md +306 -0
  192. package/docs/proposals/0003-task-subagents.md +333 -0
  193. package/docs/proposals/0004-plan-mode.md +338 -0
  194. package/docs/proposals/0005-todo-system.md +299 -0
  195. package/docs/proposals/0006-memory-system.md +539 -0
  196. package/docs/proposals/0007-context-management.md +429 -0
  197. package/docs/proposals/0008-checkpointing.md +327 -0
  198. package/docs/proposals/0009-hooks-system.md +343 -0
  199. package/docs/proposals/0010-mcp-integration.md +382 -0
  200. package/docs/proposals/0011-custom-commands.md +374 -0
  201. package/docs/proposals/0012-ask-user-question.md +317 -0
  202. package/docs/proposals/0013-multi-edit-tool.md +345 -0
  203. package/docs/proposals/0014-lsp-tool.md +478 -0
  204. package/docs/proposals/0015-ls-tool.md +407 -0
  205. package/docs/proposals/0016-kill-shell-tool.md +455 -0
  206. package/docs/proposals/0017-background-tasks.md +489 -0
  207. package/docs/proposals/0018-parallel-tool-execution.md +415 -0
  208. package/docs/proposals/0019-session-enhancements.md +462 -0
  209. package/docs/proposals/0020-session-summarization.md +447 -0
  210. package/docs/proposals/0021-skills-system.md +409 -0
  211. package/docs/proposals/0022-plugin-system.md +467 -0
  212. package/docs/proposals/0023-permission-enhancements.md +470 -0
  213. package/docs/proposals/0024-keyboard-shortcuts.md +443 -0
  214. package/docs/proposals/0025-cost-tracking.md +447 -0
  215. package/docs/proposals/0026-git-integration.md +475 -0
  216. package/docs/proposals/0027-enhanced-read-tool.md +514 -0
  217. package/docs/proposals/0028-enhanced-bash-tool.md +511 -0
  218. package/docs/proposals/0029-notebook-edit-tool.md +413 -0
  219. package/docs/proposals/0030-plugin-marketplace.md +360 -0
  220. package/docs/proposals/0031-command-suggestions.md +295 -0
  221. package/docs/proposals/0032-ide-integrations.md +328 -0
  222. package/docs/proposals/0033-enterprise-deployment.md +221 -0
  223. package/docs/proposals/0034-sandboxing.md +273 -0
  224. package/docs/proposals/0035-auto-updater.md +311 -0
  225. package/docs/proposals/0036-enhanced-glob-tool.md +267 -0
  226. package/docs/proposals/0037-enhanced-grep-tool.md +360 -0
  227. package/docs/proposals/0038-interactive-cli-ui.md +373 -0
  228. package/docs/proposals/0039-streaming-enhancements.md +359 -0
  229. package/docs/proposals/0040-multi-provider-enhancements.md +369 -0
  230. package/docs/proposals/README.md +84 -0
  231. package/docs/proposals/TEMPLATE.md +57 -0
  232. package/docs/proposals/research/claude-code-research.md +307 -0
  233. package/examples/agent-demo.ts +115 -0
  234. package/examples/basic.ts +166 -0
  235. package/package.json +50 -0
  236. package/src/agent/agent.ts +276 -0
  237. package/src/agent/index.ts +6 -0
  238. package/src/agent/types.ts +62 -0
  239. package/src/cli/components/App.tsx +565 -0
  240. package/src/cli/components/CommandSuggestions.tsx +58 -0
  241. package/src/cli/components/Header.tsx +36 -0
  242. package/src/cli/components/Input.tsx +60 -0
  243. package/src/cli/components/Logo.tsx +16 -0
  244. package/src/cli/components/Messages.tsx +210 -0
  245. package/src/cli/components/ModelSelector.tsx +135 -0
  246. package/src/cli/components/Spinner.tsx +72 -0
  247. package/src/cli/components/index.ts +21 -0
  248. package/src/cli/components/theme.ts +36 -0
  249. package/src/cli/index.tsx +136 -0
  250. package/src/config/index.ts +7 -0
  251. package/src/config/manager.ts +77 -0
  252. package/src/config/types.ts +25 -0
  253. package/src/index.ts +86 -0
  254. package/src/permissions/index.ts +7 -0
  255. package/src/permissions/manager.ts +97 -0
  256. package/src/permissions/types.ts +29 -0
  257. package/src/providers/anthropic.ts +224 -0
  258. package/src/providers/gemini.ts +295 -0
  259. package/src/providers/index.ts +97 -0
  260. package/src/providers/openai.ts +261 -0
  261. package/src/providers/types.ts +181 -0
  262. package/src/session/index.ts +6 -0
  263. package/src/session/manager.ts +354 -0
  264. package/src/session/types.ts +49 -0
  265. package/src/tools/builtin/bash.ts +92 -0
  266. package/src/tools/builtin/edit.ts +37 -0
  267. package/src/tools/builtin/glob.ts +42 -0
  268. package/src/tools/builtin/grep.ts +67 -0
  269. package/src/tools/builtin/read.ts +34 -0
  270. package/src/tools/builtin/write.ts +27 -0
  271. package/src/tools/index.ts +36 -0
  272. package/src/tools/registry.ts +83 -0
  273. package/src/tools/types.ts +172 -0
  274. package/tsconfig.json +21 -0
@@ -0,0 +1,511 @@
1
+ # Proposal: Enhanced Bash Tool
2
+
3
+ - **Proposal ID**: 0028
4
+ - **Author**: mycode team
5
+ - **Status**: Draft
6
+ - **Created**: 2025-01-15
7
+ - **Updated**: 2025-01-15
8
+
9
+ ## Summary
10
+
11
+ Enhance the Bash tool with background execution, streaming output, improved timeout handling, and safety features. This enables running long commands without blocking and provides better control over shell operations.
12
+
13
+ ## Motivation
14
+
15
+ The current Bash tool has limitations:
16
+
17
+ 1. **Blocking only**: Must wait for command completion
18
+ 2. **No streaming**: Output only shown after completion
19
+ 3. **Fixed timeout**: 30 second limit is too restrictive
20
+ 4. **Limited safety**: No command blocking
21
+ 5. **No working directory persistence**: Each command is isolated
22
+
23
+ Enhanced Bash enables flexible, safe shell command execution.
24
+
25
+ ## Claude Code Reference
26
+
27
+ Claude Code's Bash tool provides rich functionality:
28
+
29
+ ### From Tool Description
30
+ ```
31
+ - timeout: Optional timeout in milliseconds (up to 600000 / 10 minutes)
32
+ - run_in_background: Run command without waiting for completion
33
+ - description: Clear description of what the command does
34
+ - Output truncated at 30000 characters
35
+ ```
36
+
37
+ ### Key Features
38
+ - Configurable timeout up to 10 minutes
39
+ - Background execution with task ID
40
+ - Command description for clarity
41
+ - Output truncation
42
+ - Sandboxing option
43
+
44
+ ### Safety Guidelines
45
+ ```
46
+ - Quote paths with spaces
47
+ - Use absolute paths
48
+ - Avoid cd, prefer absolute paths
49
+ - Don't use find/grep/cat (use dedicated tools)
50
+ - Chain commands with && or ;
51
+ ```
52
+
53
+ ## Detailed Design
54
+
55
+ ### API Design
56
+
57
+ ```typescript
58
+ // src/tools/bash/types.ts
59
+ interface BashInput {
60
+ command: string;
61
+ description?: string; // What this command does
62
+ timeout?: number; // Ms, default 120000, max 600000
63
+ run_in_background?: boolean; // Don't wait for completion
64
+ cwd?: string; // Working directory override
65
+ env?: Record<string, string>; // Additional env vars
66
+ }
67
+
68
+ interface BashOutput {
69
+ success: boolean;
70
+ stdout: string;
71
+ stderr: string;
72
+ exit_code: number;
73
+ duration_ms: number;
74
+ truncated?: boolean;
75
+ // For background tasks
76
+ task_id?: string;
77
+ output_file?: string;
78
+ }
79
+
80
+ interface BashConfig {
81
+ defaultTimeout: number;
82
+ maxTimeout: number;
83
+ maxOutputSize: number;
84
+ blockedCommands: string[];
85
+ requireDescription: boolean;
86
+ sandboxMode: boolean;
87
+ }
88
+
89
+ const DEFAULT_CONFIG: BashConfig = {
90
+ defaultTimeout: 120000, // 2 minutes
91
+ maxTimeout: 600000, // 10 minutes
92
+ maxOutputSize: 30000, // 30K characters
93
+ blockedCommands: [
94
+ 'rm -rf /',
95
+ 'mkfs',
96
+ 'dd if=/dev/zero',
97
+ ':(){:|:&};:', // Fork bomb
98
+ ],
99
+ requireDescription: false,
100
+ sandboxMode: false
101
+ };
102
+ ```
103
+
104
+ ### Enhanced Bash Tool
105
+
106
+ ```typescript
107
+ // src/tools/bash/bash-tool.ts
108
+ const bashTool: Tool<BashInput> = {
109
+ name: 'Bash',
110
+ description: `Execute shell commands with configurable options.
111
+
112
+ Parameters:
113
+ - command: The command to execute (required)
114
+ - description: What this command does (recommended)
115
+ - timeout: Timeout in milliseconds (default: 120000, max: 600000)
116
+ - run_in_background: Run without waiting (returns task_id)
117
+ - cwd: Working directory override
118
+ - env: Additional environment variables
119
+
120
+ Best practices:
121
+ - Always quote paths with spaces
122
+ - Use absolute paths when possible
123
+ - Use && to chain dependent commands
124
+ - Use ; to run commands regardless of previous success
125
+ - Prefer dedicated tools over: find, grep, cat, head, tail
126
+
127
+ For long-running commands, use run_in_background: true
128
+ and TaskOutput tool to check results.
129
+ `,
130
+ parameters: z.object({
131
+ command: z.string().min(1),
132
+ description: z.string().optional(),
133
+ timeout: z.number().min(0).max(600000).optional(),
134
+ run_in_background: z.boolean().optional(),
135
+ cwd: z.string().optional(),
136
+ env: z.record(z.string()).optional()
137
+ }),
138
+ execute: async (input, context) => {
139
+ return bashExecutor.execute(input, context);
140
+ }
141
+ };
142
+ ```
143
+
144
+ ### Bash Executor
145
+
146
+ ```typescript
147
+ // src/tools/bash/executor.ts
148
+ class BashExecutor {
149
+ private config: BashConfig;
150
+ private taskManager: TaskManager;
151
+
152
+ constructor(config?: Partial<BashConfig>) {
153
+ this.config = { ...DEFAULT_CONFIG, ...config };
154
+ this.taskManager = new TaskManager();
155
+ }
156
+
157
+ async execute(input: BashInput, context: ToolContext): Promise<BashOutput> {
158
+ // Safety check
159
+ const safetyResult = this.checkSafety(input.command);
160
+ if (!safetyResult.safe) {
161
+ return {
162
+ success: false,
163
+ stdout: '',
164
+ stderr: safetyResult.reason,
165
+ exit_code: -1,
166
+ duration_ms: 0
167
+ };
168
+ }
169
+
170
+ // Determine execution mode
171
+ if (input.run_in_background) {
172
+ return this.executeBackground(input, context);
173
+ }
174
+
175
+ return this.executeForeground(input, context);
176
+ }
177
+
178
+ private async executeForeground(
179
+ input: BashInput,
180
+ context: ToolContext
181
+ ): Promise<BashOutput> {
182
+ const timeout = Math.min(
183
+ input.timeout || this.config.defaultTimeout,
184
+ this.config.maxTimeout
185
+ );
186
+
187
+ const cwd = input.cwd || context.cwd;
188
+ const start = Date.now();
189
+
190
+ try {
191
+ const { stdout, stderr } = await execAsync(input.command, {
192
+ cwd,
193
+ timeout,
194
+ maxBuffer: this.config.maxOutputSize * 2,
195
+ env: { ...process.env, ...input.env },
196
+ shell: '/bin/bash'
197
+ });
198
+
199
+ return {
200
+ success: true,
201
+ stdout: this.truncate(stdout),
202
+ stderr: this.truncate(stderr),
203
+ exit_code: 0,
204
+ duration_ms: Date.now() - start,
205
+ truncated: stdout.length > this.config.maxOutputSize
206
+ };
207
+ } catch (error) {
208
+ const execError = error as ExecException;
209
+ return {
210
+ success: false,
211
+ stdout: this.truncate(execError.stdout || ''),
212
+ stderr: this.truncate(execError.stderr || execError.message),
213
+ exit_code: execError.code || 1,
214
+ duration_ms: Date.now() - start
215
+ };
216
+ }
217
+ }
218
+
219
+ private async executeBackground(
220
+ input: BashInput,
221
+ context: ToolContext
222
+ ): Promise<BashOutput> {
223
+ const taskId = generateTaskId('bash');
224
+ const outputFile = path.join(os.tmpdir(), `mycode-${taskId}.log`);
225
+ const cwd = input.cwd || context.cwd;
226
+
227
+ const child = spawn('bash', ['-c', input.command], {
228
+ cwd,
229
+ detached: true,
230
+ stdio: ['ignore', 'pipe', 'pipe'],
231
+ env: { ...process.env, ...input.env }
232
+ });
233
+
234
+ // Setup output logging
235
+ const logStream = fs.createWriteStream(outputFile);
236
+ child.stdout?.pipe(logStream);
237
+ child.stderr?.pipe(logStream);
238
+
239
+ // Register with task manager
240
+ this.taskManager.register({
241
+ id: taskId,
242
+ type: 'bash',
243
+ command: input.command,
244
+ description: input.description,
245
+ pid: child.pid!,
246
+ outputFile,
247
+ startedAt: new Date(),
248
+ status: 'running'
249
+ });
250
+
251
+ // Handle completion
252
+ child.on('exit', (code) => {
253
+ this.taskManager.complete(taskId, code || 0);
254
+ });
255
+
256
+ // Detach
257
+ child.unref();
258
+
259
+ return {
260
+ success: true,
261
+ stdout: `Background task started: ${taskId}`,
262
+ stderr: '',
263
+ exit_code: 0,
264
+ duration_ms: 0,
265
+ task_id: taskId,
266
+ output_file: outputFile
267
+ };
268
+ }
269
+
270
+ private checkSafety(command: string): { safe: boolean; reason: string } {
271
+ // Check blocked patterns
272
+ for (const blocked of this.config.blockedCommands) {
273
+ if (command.includes(blocked)) {
274
+ return {
275
+ safe: false,
276
+ reason: `Command contains blocked pattern: ${blocked}`
277
+ };
278
+ }
279
+ }
280
+
281
+ // Warn about dangerous patterns
282
+ const dangerous = [
283
+ { pattern: /rm\s+-rf\s+\//, reason: 'Recursive delete from root' },
284
+ { pattern: />\s*\/dev\/sd/, reason: 'Writing to block device' },
285
+ { pattern: /chmod\s+-R\s+777/, reason: 'Insecure permissions' },
286
+ ];
287
+
288
+ for (const { pattern, reason } of dangerous) {
289
+ if (pattern.test(command)) {
290
+ return { safe: false, reason };
291
+ }
292
+ }
293
+
294
+ return { safe: true, reason: '' };
295
+ }
296
+
297
+ private truncate(output: string): string {
298
+ if (output.length <= this.config.maxOutputSize) {
299
+ return output;
300
+ }
301
+
302
+ const half = Math.floor(this.config.maxOutputSize / 2);
303
+ const truncated = output.length - this.config.maxOutputSize;
304
+
305
+ return `${output.slice(0, half)}\n\n... (${truncated} characters truncated) ...\n\n${output.slice(-half)}`;
306
+ }
307
+ }
308
+
309
+ export const bashExecutor = new BashExecutor();
310
+ ```
311
+
312
+ ### Streaming Support
313
+
314
+ ```typescript
315
+ // src/tools/bash/streaming.ts
316
+ async function* executeWithStreaming(
317
+ command: string,
318
+ options: SpawnOptions
319
+ ): AsyncGenerator<StreamEvent> {
320
+ const child = spawn('bash', ['-c', command], {
321
+ ...options,
322
+ stdio: ['ignore', 'pipe', 'pipe']
323
+ });
324
+
325
+ // Stream stdout
326
+ if (child.stdout) {
327
+ child.stdout.on('data', (data: Buffer) => {
328
+ // Yield to event loop
329
+ });
330
+ }
331
+
332
+ // Stream stderr
333
+ if (child.stderr) {
334
+ child.stderr.on('data', (data: Buffer) => {
335
+ // Yield to event loop
336
+ });
337
+ }
338
+
339
+ // Wait for completion
340
+ const exitCode = await new Promise<number>((resolve) => {
341
+ child.on('exit', (code) => resolve(code || 0));
342
+ });
343
+
344
+ yield { type: 'exit', code: exitCode };
345
+ }
346
+ ```
347
+
348
+ ### File Changes
349
+
350
+ | File | Action | Description |
351
+ |------|--------|-------------|
352
+ | `src/tools/bash/types.ts` | Create | Type definitions |
353
+ | `src/tools/bash/bash-tool.ts` | Modify | Enhanced tool |
354
+ | `src/tools/bash/executor.ts` | Create | Command execution |
355
+ | `src/tools/bash/safety.ts` | Create | Safety checks |
356
+ | `src/tools/bash/streaming.ts` | Create | Streaming output |
357
+ | `src/tools/bash/index.ts` | Modify | Updated exports |
358
+ | `src/tasks/task-manager.ts` | Modify | Background task support |
359
+
360
+ ## User Experience
361
+
362
+ ### Foreground with Description
363
+ ```
364
+ Agent: [Bash: command="npm run build", description="Build the project"]
365
+
366
+ Running: Build the project
367
+
368
+ ✓ Command completed (4.2s)
369
+ stdout:
370
+ > mycode@1.0.0 build
371
+ > tsc
372
+
373
+ Build completed successfully.
374
+ ```
375
+
376
+ ### Background Execution
377
+ ```
378
+ Agent: [Bash: command="npm test", run_in_background=true, description="Run tests"]
379
+
380
+ ┌─ Background Task Started ─────────────────────────┐
381
+ │ Task ID: bash-abc123 │
382
+ │ Command: npm test │
383
+ │ Output: /tmp/mycode-bash-abc123.log │
384
+ │ │
385
+ │ Use /tasks to check status │
386
+ │ Use TaskOutput to get results │
387
+ └───────────────────────────────────────────────────┘
388
+ ```
389
+
390
+ ### Streaming Output (Long Command)
391
+ ```
392
+ Agent: [Bash: command="npm install", timeout=300000]
393
+
394
+ Running: npm install
395
+ ────────────────────────────────────────────────────
396
+ added 1 package in 1s
397
+ ⠋ Installing dependencies...
398
+ added 50 packages in 5s
399
+ ⠙ Installing dependencies...
400
+ added 200 packages in 15s
401
+ ✓ added 523 packages in 32s
402
+ ────────────────────────────────────────────────────
403
+ Exit code: 0
404
+ Duration: 32.4s
405
+ ```
406
+
407
+ ### Safety Block
408
+ ```
409
+ Agent: [Bash: command="rm -rf /"]
410
+
411
+ ⚠️ Command Blocked
412
+
413
+ This command matches a blocked pattern:
414
+ "rm -rf /" - Recursive delete from root
415
+
416
+ This operation is not allowed for safety.
417
+ If you need to delete files, specify exact paths.
418
+ ```
419
+
420
+ ### Output Truncation
421
+ ```
422
+ Agent: [Bash: command="cat large-file.log"]
423
+
424
+ Output (truncated):
425
+ ────────────────────────────────────────────────────
426
+ [2024-01-15 10:00:00] Starting application...
427
+ [2024-01-15 10:00:01] Loading configuration...
428
+ ...
429
+
430
+ ... (45,678 characters truncated) ...
431
+
432
+ [2024-01-15 10:15:42] Request completed
433
+ [2024-01-15 10:15:43] Shutting down...
434
+ ────────────────────────────────────────────────────
435
+ ```
436
+
437
+ ## Alternatives Considered
438
+
439
+ ### Alternative 1: PTY-based Execution
440
+ Use pseudo-terminal for full interactivity.
441
+
442
+ **Pros**: Interactive commands work
443
+ **Cons**: Complex, security concerns
444
+ **Decision**: Deferred - Consider for advanced use
445
+
446
+ ### Alternative 2: Sandboxed Containers
447
+ Run commands in Docker/Podman.
448
+
449
+ **Pros**: Full isolation
450
+ **Cons**: Heavy, requires container runtime
451
+ **Decision**: Optional via sandboxMode config
452
+
453
+ ### Alternative 3: PowerShell Support
454
+ Add Windows PowerShell support.
455
+
456
+ **Pros**: Cross-platform
457
+ **Cons**: Different syntax, complexity
458
+ **Decision**: Deferred - Focus on Bash first
459
+
460
+ ## Security Considerations
461
+
462
+ 1. **Command Blocking**: Block dangerous patterns
463
+ 2. **Path Injection**: Validate file paths
464
+ 3. **Environment Isolation**: Don't leak sensitive env vars
465
+ 4. **Resource Limits**: Limit CPU/memory usage
466
+ 5. **Timeout Enforcement**: Kill hung processes
467
+
468
+ ```typescript
469
+ const SAFETY_PATTERNS = [
470
+ /rm\s+-rf\s+\//,
471
+ /mkfs/,
472
+ /dd\s+if=.*of=\/dev/,
473
+ />\s*\/etc/,
474
+ /curl.*\|\s*bash/, // Pipe to shell
475
+ ];
476
+ ```
477
+
478
+ ## Testing Strategy
479
+
480
+ 1. **Unit Tests**:
481
+ - Command parsing
482
+ - Safety checks
483
+ - Output truncation
484
+ - Timeout handling
485
+
486
+ 2. **Integration Tests**:
487
+ - Background execution
488
+ - Streaming output
489
+ - Error handling
490
+
491
+ 3. **Security Tests**:
492
+ - Blocked commands
493
+ - Injection attempts
494
+ - Resource limits
495
+
496
+ ## Migration Path
497
+
498
+ 1. **Phase 1**: Configurable timeout
499
+ 2. **Phase 2**: Background execution
500
+ 3. **Phase 3**: Streaming output
501
+ 4. **Phase 4**: Enhanced safety
502
+ 5. **Phase 5**: Sandboxing option
503
+
504
+ Backward compatible with existing Bash usage.
505
+
506
+ ## References
507
+
508
+ - [Node.js Child Process](https://nodejs.org/api/child_process.html)
509
+ - [Bash Reference Manual](https://www.gnu.org/software/bash/manual/)
510
+ - [Shell Command Injection Prevention](https://owasp.org/www-community/attacks/Command_Injection)
511
+ - [Container Sandboxing](https://docs.docker.com/engine/security/)