@swarmclawai/swarmclaw 1.2.6 → 1.2.9

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 (269) hide show
  1. package/README.md +54 -23
  2. package/next.config.ts +1 -0
  3. package/package.json +4 -3
  4. package/scripts/easy-setup.mjs +1 -1
  5. package/scripts/postinstall.mjs +1 -1
  6. package/skills/swarmclaw.md +115 -0
  7. package/skills/tools/browser.md +131 -0
  8. package/skills/tools/execute.md +98 -0
  9. package/skills/tools/files.md +98 -0
  10. package/skills/tools/memory.md +104 -0
  11. package/skills/tools/platform.md +144 -0
  12. package/skills/tools/skills.md +83 -0
  13. package/src/app/agents/[id]/page.tsx +1 -18
  14. package/src/app/api/agents/thread-route.test.ts +0 -1
  15. package/src/app/api/approvals/route.test.ts +6 -22
  16. package/src/app/api/chats/[id]/messages/route.ts +23 -19
  17. package/src/app/api/chats/messages-route.test.ts +105 -51
  18. package/src/app/api/connectors/route.ts +2 -2
  19. package/src/app/api/mcp-servers/[id]/test/route.ts +3 -2
  20. package/src/app/api/openclaw/deploy/route.ts +2 -0
  21. package/src/app/api/portability/export/route.ts +8 -0
  22. package/src/app/api/portability/import/route.test.ts +80 -0
  23. package/src/app/api/portability/import/route.ts +28 -0
  24. package/src/app/api/settings/route.ts +0 -2
  25. package/src/app/api/setup/doctor/route.ts +4 -4
  26. package/src/app/api/wallets/[id]/route.ts +15 -157
  27. package/src/app/api/wallets/generate/route.ts +22 -0
  28. package/src/app/api/wallets/route.test.ts +147 -0
  29. package/src/app/api/wallets/route.ts +13 -95
  30. package/src/app/autonomy/page.tsx +2 -57
  31. package/src/app/protocols/page.tsx +2 -21
  32. package/src/app/settings/page.tsx +0 -9
  33. package/src/app/wallets/page.tsx +105 -5
  34. package/src/cli/index.js +21 -33
  35. package/src/cli/spec.js +19 -30
  36. package/src/components/agents/agent-chat-list.tsx +23 -1
  37. package/src/components/agents/agent-sheet.tsx +2 -40
  38. package/src/components/agents/inspector-panel.tsx +165 -131
  39. package/src/components/chat/chat-area.tsx +38 -9
  40. package/src/components/chat/chat-card.tsx +0 -31
  41. package/src/components/chat/message-bubble.tsx +1 -108
  42. package/src/components/chat/message-list.tsx +33 -19
  43. package/src/components/connectors/connector-sheet.tsx +25 -1
  44. package/src/components/gateways/gateway-sheet.tsx +5 -2
  45. package/src/components/layout/sidebar-rail.tsx +6 -10
  46. package/src/components/projects/project-detail.tsx +3 -35
  47. package/src/components/projects/tabs/overview-tab.tsx +3 -59
  48. package/src/components/projects/tabs/work-tab.tsx +7 -77
  49. package/src/components/protocols/structured-session-launcher.tsx +1 -22
  50. package/src/components/shared/connector-platform-icon.tsx +1 -0
  51. package/src/components/tasks/task-card.tsx +4 -34
  52. package/src/components/tasks/task-sheet.tsx +6 -36
  53. package/src/components/wallets/wallet-list.tsx +150 -0
  54. package/src/lib/agent-execute-defaults.test.ts +24 -0
  55. package/src/lib/agent-execute-defaults.ts +62 -0
  56. package/src/lib/app/navigation.test.ts +0 -13
  57. package/src/lib/app/navigation.ts +2 -7
  58. package/src/lib/app/view-constants.ts +14 -19
  59. package/src/lib/chat/queued-message-queue.test.ts +134 -1
  60. package/src/lib/chat/queued-message-queue.ts +77 -2
  61. package/src/lib/server/agents/agent-service.ts +5 -0
  62. package/src/lib/server/agents/agent-thread-session.ts +0 -1
  63. package/src/lib/server/agents/delegation-advisory.test.ts +0 -1
  64. package/src/lib/server/agents/delegation-jobs.test.ts +0 -69
  65. package/src/lib/server/agents/delegation-jobs.ts +0 -25
  66. package/src/lib/server/agents/main-agent-loop.ts +1 -49
  67. package/src/lib/server/agents/subagent-runtime.ts +0 -1
  68. package/src/lib/server/approval-match.ts +0 -85
  69. package/src/lib/server/approvals.test.ts +6 -6
  70. package/src/lib/server/approvals.ts +0 -6
  71. package/src/lib/server/autonomy/supervisor-reflection.test.ts +0 -1
  72. package/src/lib/server/builtin-extensions.ts +1 -2
  73. package/src/lib/server/capability-router.test.ts +0 -2
  74. package/src/lib/server/chat-execution/chat-execution-advanced.test.ts +1 -1
  75. package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +15 -14
  76. package/src/lib/server/chat-execution/chat-execution-types.ts +0 -2
  77. package/src/lib/server/chat-execution/chat-execution-utils.ts +2 -4
  78. package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -30
  79. package/src/lib/server/chat-execution/chat-turn-finalization.ts +1 -36
  80. package/src/lib/server/chat-execution/chat-turn-preparation.ts +81 -64
  81. package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -0
  82. package/src/lib/server/chat-execution/continuation-evaluator.ts +8 -0
  83. package/src/lib/server/chat-execution/iteration-event-handler.ts +0 -24
  84. package/src/lib/server/chat-execution/memory-mutation-tools.ts +1 -1
  85. package/src/lib/server/chat-execution/message-classifier.test.ts +0 -45
  86. package/src/lib/server/chat-execution/message-classifier.ts +11 -16
  87. package/src/lib/server/chat-execution/prompt-builder.test.ts +27 -0
  88. package/src/lib/server/chat-execution/prompt-builder.ts +14 -31
  89. package/src/lib/server/chat-execution/prompt-mode.test.ts +24 -0
  90. package/src/lib/server/chat-execution/prompt-mode.ts +5 -1
  91. package/src/lib/server/chat-execution/prompt-sections.ts +0 -1
  92. package/src/lib/server/chat-execution/situational-awareness.test.ts +2 -73
  93. package/src/lib/server/chat-execution/situational-awareness.ts +4 -38
  94. package/src/lib/server/chat-execution/stream-agent-chat.test.ts +13 -126
  95. package/src/lib/server/chat-execution/stream-agent-chat.ts +46 -21
  96. package/src/lib/server/chat-execution/stream-continuation.test.ts +4 -52
  97. package/src/lib/server/chat-execution/stream-continuation.ts +6 -48
  98. package/src/lib/server/chatrooms/chatroom-routing.test.ts +4 -0
  99. package/src/lib/server/chatrooms/session-mailbox.ts +0 -10
  100. package/src/lib/server/chats/chat-session-service.ts +3 -5
  101. package/src/lib/server/connectors/connector-inbound.ts +0 -1
  102. package/src/lib/server/connectors/connector-lifecycle.ts +19 -3
  103. package/src/lib/server/connectors/connector-service.ts +39 -9
  104. package/src/lib/server/connectors/discord.ts +2 -2
  105. package/src/lib/server/connectors/matrix.ts +3 -2
  106. package/src/lib/server/connectors/signal.ts +5 -4
  107. package/src/lib/server/connectors/slack.ts +10 -9
  108. package/src/lib/server/connectors/swarmdock-bidding.ts +74 -0
  109. package/src/lib/server/connectors/swarmdock-payloads.test.ts +85 -0
  110. package/src/lib/server/connectors/swarmdock-secret.test.ts +128 -0
  111. package/src/lib/server/connectors/swarmdock-secret.ts +152 -0
  112. package/src/lib/server/connectors/swarmdock-tasks.ts +119 -0
  113. package/src/lib/server/connectors/swarmdock.ts +255 -0
  114. package/src/lib/server/connectors/teams.ts +3 -2
  115. package/src/lib/server/connectors/telegram.ts +4 -4
  116. package/src/lib/server/connectors/whatsapp.ts +2 -2
  117. package/src/lib/server/daemon/controller.ts +7 -0
  118. package/src/lib/server/execution-brief.test.ts +2 -25
  119. package/src/lib/server/execution-brief.ts +12 -35
  120. package/src/lib/server/execution-engine/task-attempt.ts +0 -1
  121. package/src/lib/server/gateways/gateway-profile-service.ts +19 -1
  122. package/src/lib/server/messages/message-repository.test.ts +70 -0
  123. package/src/lib/server/messages/message-repository.ts +11 -6
  124. package/src/lib/server/openclaw/deploy.ts +32 -2
  125. package/src/lib/server/persistence/storage-context.ts +0 -5
  126. package/src/lib/server/plugins-advanced.test.ts +1 -2
  127. package/src/lib/server/portability/export.ts +109 -0
  128. package/src/lib/server/portability/import.ts +159 -0
  129. package/src/lib/server/protocols/protocol-normalization.ts +0 -4
  130. package/src/lib/server/protocols/protocol-queries.ts +0 -6
  131. package/src/lib/server/protocols/protocol-run-lifecycle.ts +4 -32
  132. package/src/lib/server/protocols/protocol-service.ts +0 -1
  133. package/src/lib/server/protocols/protocol-step-helpers.ts +0 -4
  134. package/src/lib/server/protocols/protocol-step-processors.ts +0 -6
  135. package/src/lib/server/protocols/protocol-swarm.ts +0 -2
  136. package/src/lib/server/protocols/protocol-types.ts +0 -2
  137. package/src/lib/server/provider-health.ts +1 -10
  138. package/src/lib/server/runtime/daemon-state/core.ts +0 -9
  139. package/src/lib/server/runtime/daemon-state.test.ts +0 -35
  140. package/src/lib/server/runtime/heartbeat-service.ts +3 -23
  141. package/src/lib/server/runtime/process-manager.ts +13 -9
  142. package/src/lib/server/runtime/queue/core.ts +11 -33
  143. package/src/lib/server/runtime/runtime-storage-write-paths.test.ts +6 -6
  144. package/src/lib/server/runtime/scheduler.ts +0 -13
  145. package/src/lib/server/runtime/session-run-manager/drain.ts +0 -24
  146. package/src/lib/server/runtime/session-run-manager/enqueue.ts +0 -1
  147. package/src/lib/server/runtime/session-run-manager/queries.ts +15 -1
  148. package/src/lib/server/runtime/session-run-manager/recovery.ts +0 -1
  149. package/src/lib/server/runtime/session-run-manager.test.ts +58 -28
  150. package/src/lib/server/sandbox/session-runtime.test.ts +18 -1
  151. package/src/lib/server/sandbox/session-runtime.ts +40 -28
  152. package/src/lib/server/session-tools/autonomy-tools.test.ts +7 -9
  153. package/src/lib/server/session-tools/context.ts +1 -1
  154. package/src/lib/server/session-tools/credential-env.ts +109 -0
  155. package/src/lib/server/session-tools/crud.ts +3 -17
  156. package/src/lib/server/session-tools/delegate.ts +0 -4
  157. package/src/lib/server/session-tools/edit_file.ts +3 -2
  158. package/src/lib/server/session-tools/execute.test.ts +58 -0
  159. package/src/lib/server/session-tools/execute.ts +334 -0
  160. package/src/lib/server/session-tools/files-tool.ts +635 -0
  161. package/src/lib/server/session-tools/index.ts +14 -8
  162. package/src/lib/server/session-tools/memory-tool.ts +242 -0
  163. package/src/lib/server/session-tools/memory.ts +1 -1
  164. package/src/lib/server/session-tools/openclaw-nodes.ts +3 -2
  165. package/src/lib/server/session-tools/openclaw-workspace.ts +3 -2
  166. package/src/lib/server/session-tools/platform-tool.ts +617 -0
  167. package/src/lib/server/session-tools/session-info.ts +3 -2
  168. package/src/lib/server/session-tools/session-tools-wiring.test.ts +3 -4
  169. package/src/lib/server/session-tools/shell.ts +7 -122
  170. package/src/lib/server/session-tools/skills-tool.ts +396 -0
  171. package/src/lib/server/session-tools/team-context.ts +0 -3
  172. package/src/lib/server/session-tools/web.ts +2 -2
  173. package/src/lib/server/storage-normalization.ts +10 -0
  174. package/src/lib/server/storage.ts +18 -45
  175. package/src/lib/server/tasks/task-checkout.ts +59 -0
  176. package/src/lib/server/tasks/task-lifecycle.ts +2 -0
  177. package/src/lib/server/tasks/task-route-service.ts +4 -26
  178. package/src/lib/server/tasks/task-service.ts +0 -7
  179. package/src/lib/server/tool-aliases.ts +2 -2
  180. package/src/lib/server/tool-capability-policy-advanced.test.ts +13 -6
  181. package/src/lib/server/tool-capability-policy.test.ts +2 -1
  182. package/src/lib/server/tool-capability-policy.ts +60 -35
  183. package/src/lib/server/tool-planning.ts +11 -12
  184. package/src/lib/server/universal-tool-access.ts +0 -1
  185. package/src/lib/server/wallets/wallet-crypto.ts +33 -0
  186. package/src/lib/server/wallets/wallet-repository.ts +24 -0
  187. package/src/lib/server/wallets/wallet-service.ts +119 -0
  188. package/src/lib/server/working-state/extraction.ts +8 -42
  189. package/src/lib/server/working-state/normalization.ts +10 -103
  190. package/src/lib/server/working-state/service.ts +12 -21
  191. package/src/lib/setup-defaults.ts +5 -0
  192. package/src/lib/strip-internal-metadata.test.ts +1 -1
  193. package/src/lib/strip-internal-metadata.ts +1 -1
  194. package/src/lib/tool-definitions.ts +1 -1
  195. package/src/lib/validation/schemas.test.ts +16 -0
  196. package/src/lib/validation/schemas.ts +49 -2
  197. package/src/stores/slices/data-slice.ts +5 -1
  198. package/src/stores/slices/ui-slice.ts +0 -4
  199. package/src/stores/use-chat-store.test.ts +231 -0
  200. package/src/stores/use-chat-store.ts +62 -13
  201. package/src/types/agent.ts +264 -0
  202. package/src/types/app-settings.ts +173 -0
  203. package/src/types/approval.ts +25 -0
  204. package/src/types/connector.ts +188 -0
  205. package/src/types/extension.ts +386 -0
  206. package/src/types/index.ts +16 -3555
  207. package/src/types/message.ts +56 -0
  208. package/src/types/misc.ts +737 -0
  209. package/src/types/protocol.ts +420 -0
  210. package/src/types/provider.ts +52 -0
  211. package/src/types/run.ts +180 -0
  212. package/src/types/schedule.ts +59 -0
  213. package/src/types/session.ts +215 -0
  214. package/src/types/skill.ts +157 -0
  215. package/src/types/swarmdock.ts +29 -0
  216. package/src/types/task.ts +144 -0
  217. package/src/types/working-state.ts +204 -0
  218. package/src/views/settings/section-heartbeat.tsx +2 -2
  219. package/src/views/settings/section-runtime-loop.tsx +0 -14
  220. package/src/app/api/canvas/[sessionId]/route.ts +0 -35
  221. package/src/app/api/missions/[id]/actions/route.ts +0 -31
  222. package/src/app/api/missions/[id]/events/route.ts +0 -14
  223. package/src/app/api/missions/[id]/route.ts +0 -10
  224. package/src/app/api/missions/route.test.ts +0 -244
  225. package/src/app/api/missions/route.ts +0 -57
  226. package/src/app/api/wallets/[id]/approve/route.ts +0 -79
  227. package/src/app/api/wallets/[id]/balance-history/route.ts +0 -18
  228. package/src/app/api/wallets/[id]/send/route.ts +0 -113
  229. package/src/app/api/wallets/[id]/transactions/route.ts +0 -18
  230. package/src/app/missions/[id]/page.tsx +0 -3
  231. package/src/app/missions/page.tsx +0 -685
  232. package/src/components/canvas/canvas-panel.tsx +0 -267
  233. package/src/components/wallets/wallet-approval-dialog.tsx +0 -107
  234. package/src/components/wallets/wallet-panel.tsx +0 -1010
  235. package/src/components/wallets/wallet-section.tsx +0 -260
  236. package/src/features/missions/queries.ts +0 -23
  237. package/src/lib/canvas-content.test.ts +0 -360
  238. package/src/lib/canvas-content.ts +0 -198
  239. package/src/lib/server/canvas-content.test.ts +0 -32
  240. package/src/lib/server/canvas-content.ts +0 -6
  241. package/src/lib/server/ethereum.ts +0 -591
  242. package/src/lib/server/evm-swap.ts +0 -476
  243. package/src/lib/server/missions/mission-intent.test.ts +0 -63
  244. package/src/lib/server/missions/mission-intent.ts +0 -569
  245. package/src/lib/server/missions/mission-repository.ts +0 -74
  246. package/src/lib/server/missions/mission-service/actions.ts +0 -6
  247. package/src/lib/server/missions/mission-service/bindings.ts +0 -9
  248. package/src/lib/server/missions/mission-service/context.ts +0 -4
  249. package/src/lib/server/missions/mission-service/core.ts +0 -2271
  250. package/src/lib/server/missions/mission-service/queries.ts +0 -12
  251. package/src/lib/server/missions/mission-service/recovery.ts +0 -5
  252. package/src/lib/server/missions/mission-service/ticks.ts +0 -9
  253. package/src/lib/server/missions/mission-service.test.ts +0 -888
  254. package/src/lib/server/missions/mission-service.ts +0 -6
  255. package/src/lib/server/session-tools/canvas.ts +0 -105
  256. package/src/lib/server/session-tools/sandbox.ts +0 -281
  257. package/src/lib/server/session-tools/wallet-tool.test.ts +0 -150
  258. package/src/lib/server/session-tools/wallet.ts +0 -1287
  259. package/src/lib/server/solana.ts +0 -327
  260. package/src/lib/server/wallet/wallet-execution.test.ts +0 -198
  261. package/src/lib/server/wallet/wallet-portfolio.test.ts +0 -98
  262. package/src/lib/server/wallet/wallet-portfolio.ts +0 -772
  263. package/src/lib/server/wallet/wallet-service.test.ts +0 -81
  264. package/src/lib/server/wallet/wallet-service.ts +0 -225
  265. package/src/lib/wallet/wallet-transactions.test.ts +0 -75
  266. package/src/lib/wallet/wallet-transactions.ts +0 -43
  267. package/src/lib/wallet/wallet.test.ts +0 -333
  268. package/src/lib/wallet/wallet.ts +0 -183
  269. package/src/views/settings/section-wallets.tsx +0 -35
@@ -0,0 +1,334 @@
1
+ /**
2
+ * execute — Unified code execution tool with dual backends.
3
+ *
4
+ * Sandbox backend (default): just-bash with OverlayFS. Reads workspace
5
+ * files from disk, writes stay in memory. Credential injection + secret
6
+ * redaction. No npm, no background processes, no persistent writes.
7
+ *
8
+ * Host backend (opt-in per agent config): Real bash on the host. Full
9
+ * system access — npm, git, background processes, persistent writes.
10
+ * Retains current safety guards from shell.ts.
11
+ */
12
+
13
+ import { z } from 'zod'
14
+ import { tool } from '@langchain/core/tools'
15
+ import { spawn, type ChildProcess } from 'child_process'
16
+ import type { Extension, ExtensionHooks, Agent } from '@/types'
17
+ import { registerNativeCapability } from '../native-capabilities'
18
+ import { errorMessage } from '@/lib/shared-utils'
19
+ import { log } from '../logger'
20
+ import { normalizeToolInputArgs } from './normalize-tool-args'
21
+ import { buildCredentialEnv, redactSecrets } from './credential-env'
22
+ import type { ToolBuildContext } from './context'
23
+ import { truncate, MAX_OUTPUT } from './context'
24
+ import {
25
+ DEFAULT_AGENT_EXECUTE_CONFIG,
26
+ normalizeAgentExecuteConfig,
27
+ type AgentExecuteConfig,
28
+ } from '@/lib/agent-execute-defaults'
29
+
30
+ const TAG = 'execute'
31
+
32
+ export type ExecuteConfig = AgentExecuteConfig
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Sandbox backend — just-bash with OverlayFS
36
+ // ---------------------------------------------------------------------------
37
+
38
+ async function executeSandbox(
39
+ code: string,
40
+ cwd: string,
41
+ config: ExecuteConfig,
42
+ signal?: AbortSignal,
43
+ ): Promise<{ stdout: string; stderr: string; exit_code: number }> {
44
+ // Dynamic import to avoid loading just-bash when not needed
45
+ const { Bash, OverlayFs } = await import('just-bash')
46
+
47
+ const fs = new OverlayFs({
48
+ root: cwd,
49
+ mountPoint: '/workspace',
50
+ })
51
+
52
+ const timeoutMs = (config.timeout ?? DEFAULT_AGENT_EXECUTE_CONFIG.timeout ?? 30) * 1000
53
+
54
+ // Build credential env vars
55
+ const { env: credEnv, secrets } = buildCredentialEnv(config.credentials ?? [])
56
+
57
+ // Base env vars
58
+ const env: Record<string, string> = {
59
+ HOME: '/home/user',
60
+ WORKSPACE: '/workspace',
61
+ PATH: '/usr/local/bin:/usr/bin:/bin',
62
+ TERM: 'xterm-256color',
63
+ ...credEnv,
64
+ }
65
+
66
+ // Network configuration
67
+ let network: Record<string, unknown> | undefined
68
+ if (config.network?.enabled) {
69
+ if (config.network.allowedUrls?.length) {
70
+ network = {
71
+ allowedUrls: config.network.allowedUrls.map((url: string) => ({
72
+ url,
73
+ methods: ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'],
74
+ })),
75
+ }
76
+ } else {
77
+ // Full internet access
78
+ network = { allowedUrls: [{ url: '*', methods: ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'] }] }
79
+ }
80
+ }
81
+
82
+ const bash = new Bash({
83
+ fs,
84
+ env,
85
+ cwd: '/workspace',
86
+ executionLimits: {
87
+ maxCommandCount: 1000,
88
+ maxLoopIterations: 10000,
89
+ maxCallDepth: 50,
90
+ },
91
+ python: config.runtimes?.python ?? false,
92
+ javascript: config.runtimes?.javascript ?? false,
93
+ ...(network ? { network: network as Record<string, unknown> } : {}),
94
+ defenseInDepth: true,
95
+ } as Record<string, unknown>)
96
+
97
+ // Execute with timeout
98
+ const controller = new AbortController()
99
+ const timer = setTimeout(() => controller.abort(), timeoutMs)
100
+
101
+ // Compose parent signal with our timeout
102
+ if (signal?.aborted) {
103
+ clearTimeout(timer)
104
+ return { stdout: '', stderr: 'Execution cancelled', exit_code: 130 }
105
+ }
106
+ signal?.addEventListener('abort', () => {
107
+ clearTimeout(timer)
108
+ controller.abort()
109
+ }, { once: true })
110
+
111
+ try {
112
+ const result = await bash.exec(code, {
113
+ signal: controller.signal,
114
+ })
115
+ clearTimeout(timer)
116
+
117
+ return {
118
+ stdout: redactSecrets(result.stdout, secrets),
119
+ stderr: redactSecrets(result.stderr, secrets),
120
+ exit_code: result.exitCode,
121
+ }
122
+ } catch (err: unknown) {
123
+ clearTimeout(timer)
124
+ const msg = errorMessage(err)
125
+ if (msg.includes('abort') || msg.includes('cancel') || msg.includes('Timeout')) {
126
+ return { stdout: '', stderr: `Execution timed out after ${config.timeout ?? DEFAULT_AGENT_EXECUTE_CONFIG.timeout ?? 30}s`, exit_code: 124 }
127
+ }
128
+ return { stdout: '', stderr: `Execution error: ${redactSecrets(msg, secrets)}`, exit_code: 1 }
129
+ }
130
+ }
131
+
132
+ // ---------------------------------------------------------------------------
133
+ // Host backend — real bash via child_process
134
+ //
135
+ // NOTE: This intentionally spawns bash to execute agent code. This is the
136
+ // same pattern used by the existing shell.ts tool. Agent code execution is
137
+ // the explicit purpose of this tool — this is not a command injection risk.
138
+ // ---------------------------------------------------------------------------
139
+
140
+ async function executeHost(
141
+ code: string,
142
+ cwd: string,
143
+ config: ExecuteConfig,
144
+ ): Promise<{ stdout: string; stderr: string; exit_code: number }> {
145
+ const timeoutMs = (config.timeout ?? DEFAULT_AGENT_EXECUTE_CONFIG.timeout ?? 30) * 1000
146
+
147
+ // Build credential env vars
148
+ const { env: credEnv, secrets } = buildCredentialEnv(config.credentials ?? [])
149
+
150
+ const env: Record<string, string> = {
151
+ ...Object.fromEntries(
152
+ Object.entries(process.env).filter((entry): entry is [string, string] => entry[1] != null),
153
+ ),
154
+ WORKSPACE: cwd,
155
+ SESSION_CWD: cwd,
156
+ SWARMCLAW_SANDBOX_MODE: 'host',
157
+ ...credEnv,
158
+ }
159
+
160
+ return new Promise((resolve) => {
161
+ const proc: ChildProcess = spawn('/bin/bash', ['-c', code], {
162
+ cwd,
163
+ env: env as NodeJS.ProcessEnv,
164
+ timeout: timeoutMs,
165
+ })
166
+
167
+ let stdout = ''
168
+ let stderr = ''
169
+ const maxBytes = MAX_OUTPUT
170
+
171
+ proc.stdout?.on('data', (chunk: Buffer) => {
172
+ if (stdout.length < maxBytes) stdout += chunk.toString('utf-8')
173
+ })
174
+ proc.stderr?.on('data', (chunk: Buffer) => {
175
+ if (stderr.length < maxBytes) stderr += chunk.toString('utf-8')
176
+ })
177
+
178
+ proc.on('close', (exitCode: number | null) => {
179
+ resolve({
180
+ stdout: redactSecrets(stdout, secrets),
181
+ stderr: redactSecrets(stderr, secrets),
182
+ exit_code: exitCode ?? 1,
183
+ })
184
+ })
185
+
186
+ proc.on('error', (err: Error) => {
187
+ resolve({
188
+ stdout: redactSecrets(stdout, secrets),
189
+ stderr: redactSecrets(`Process error: ${err.message}`, secrets),
190
+ exit_code: 1,
191
+ })
192
+ })
193
+ })
194
+ }
195
+
196
+ // ---------------------------------------------------------------------------
197
+ // Main execute action
198
+ // ---------------------------------------------------------------------------
199
+
200
+ interface ExecuteActionContext {
201
+ cwd: string
202
+ agentId?: string | null
203
+ sessionId?: string | null
204
+ executeConfig?: ExecuteConfig | null
205
+ }
206
+
207
+ async function executeAction(
208
+ args: Record<string, unknown>,
209
+ ctx: ExecuteActionContext,
210
+ ): Promise<string> {
211
+ const normalized = normalizeToolInputArgs(args)
212
+ const code = (normalized.code as string | undefined)?.trim()
213
+
214
+ if (!code) {
215
+ return 'Error: `code` parameter is required. Provide the bash script to execute.'
216
+ }
217
+
218
+ const config = normalizeAgentExecuteConfig(ctx.executeConfig)
219
+
220
+ const persistent = normalized.persistent === true
221
+ const timeoutOverride = typeof normalized.timeout === 'number' ? normalized.timeout : undefined
222
+ if (timeoutOverride) {
223
+ config.timeout = Math.min(Math.max(timeoutOverride, 1), 300) // Clamp 1-300s
224
+ }
225
+
226
+ if (persistent && config.backend !== 'host') {
227
+ return 'Error: `persistent=true` requires `executeConfig.backend = "host"` for this agent.'
228
+ }
229
+
230
+ log.info(TAG, `Executing code (backend=${config.backend}, persistent=${persistent})`, {
231
+ agentId: ctx.agentId,
232
+ sessionId: ctx.sessionId,
233
+ codeLength: code.length,
234
+ })
235
+
236
+ try {
237
+ let result: { stdout: string; stderr: string; exit_code: number }
238
+
239
+ if (config.backend === 'host') {
240
+ // Host backend for persistent mode or explicit host config
241
+ result = await executeHost(code, ctx.cwd, config)
242
+ } else {
243
+ // Sandbox backend (default)
244
+ result = await executeSandbox(code, ctx.cwd, config)
245
+ }
246
+
247
+ // Format output
248
+ const parts: string[] = []
249
+ if (result.stdout) parts.push(result.stdout)
250
+ if (result.stderr) parts.push(`[stderr] ${result.stderr}`)
251
+ if (result.exit_code !== 0) parts.push(`[exit code: ${result.exit_code}]`)
252
+
253
+ const output = parts.join('\n') || '(no output)'
254
+ return truncate(output, MAX_OUTPUT)
255
+ } catch (err: unknown) {
256
+ return `Error: ${errorMessage(err)}`
257
+ }
258
+ }
259
+
260
+ // ---------------------------------------------------------------------------
261
+ // Extension registration
262
+ // ---------------------------------------------------------------------------
263
+
264
+ const ExecuteExtension: Extension = {
265
+ name: 'Core Execute',
266
+ description: 'Execute code in a sandboxed or host bash environment with credential injection and secret redaction.',
267
+ hooks: {
268
+ getCapabilityDescription: () =>
269
+ 'I can execute bash scripts with the `execute` tool. ' +
270
+ 'By default, code runs in a sandboxed environment (just-bash) that reads workspace files but keeps writes in memory. ' +
271
+ 'For tasks requiring persistent writes, npm, or git, the agent can be configured to use the host backend. ' +
272
+ 'Credentials are injected as environment variables and automatically redacted from output.',
273
+ getOperatingGuidance: () =>
274
+ 'Use `execute` for: data processing (jq, awk, sed), API calls (curl), file inspection (cat, grep, find), ' +
275
+ 'computation, and any CLI tool. ' +
276
+ 'In sandbox mode, writes are ephemeral — use the `files` tool for persistent file changes. ' +
277
+ 'In host mode, writes persist to the real filesystem.',
278
+ } as ExtensionHooks,
279
+ tools: [
280
+ {
281
+ name: 'execute',
282
+ description:
283
+ 'Execute a bash script. Supports curl, jq, awk, sed, grep, and 70+ Unix commands. ' +
284
+ 'Credentials are injected as environment variables (e.g., $API_KEY). ' +
285
+ 'By default runs sandboxed — workspace files are readable, writes stay in memory. ' +
286
+ 'Set persistent=true for real filesystem writes only when the agent is configured for host execution.',
287
+ parameters: {
288
+ type: 'object',
289
+ properties: {
290
+ code: { type: 'string', description: 'The bash script to execute' },
291
+ persistent: { type: 'boolean', description: 'Use host backend for persistent writes (default: false)' },
292
+ timeout: { type: 'number', description: 'Timeout in seconds (default: 30, max: 300)' },
293
+ },
294
+ required: ['code'],
295
+ },
296
+ execute: async (args, context) =>
297
+ executeAction(args as Record<string, unknown>, {
298
+ cwd: context.session?.cwd || process.cwd(),
299
+ }),
300
+ },
301
+ ],
302
+ }
303
+
304
+ registerNativeCapability('execute', ExecuteExtension)
305
+
306
+ // ---------------------------------------------------------------------------
307
+ // Tool builder (called from session-tools/index.ts)
308
+ // ---------------------------------------------------------------------------
309
+
310
+ export function buildExecuteTools(bctx: ToolBuildContext) {
311
+ if (!bctx.hasExtension('execute')) return []
312
+
313
+ // Resolve execute config from the agent
314
+ const session = bctx.resolveCurrentSession?.()
315
+ const agent = session?.agent as (Agent & { executeConfig?: ExecuteConfig }) | undefined
316
+ const executeConfig = normalizeAgentExecuteConfig(agent?.executeConfig)
317
+
318
+ return [
319
+ tool(
320
+ async (args) =>
321
+ executeAction(args, {
322
+ cwd: bctx.cwd,
323
+ agentId: bctx.ctx?.agentId,
324
+ sessionId: bctx.ctx?.sessionId,
325
+ executeConfig,
326
+ }),
327
+ {
328
+ name: 'execute',
329
+ description: ExecuteExtension.tools![0].description,
330
+ schema: z.object({}).passthrough(),
331
+ },
332
+ ),
333
+ ]
334
+ }