@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
@@ -236,15 +236,37 @@ export function resolveSandboxWorkdir(params: {
236
236
  }
237
237
  }
238
238
 
239
- export async function ensureSessionSandbox(params: {
239
+ export function resolveSandboxSessionContext(params: {
240
240
  config: AgentSandboxConfig | null | undefined
241
241
  session?: Session | null
242
242
  agentId?: string | null
243
243
  sessionId?: string | null
244
244
  workspaceDir: string
245
- }): Promise<SandboxSessionContext | null> {
245
+ }): SandboxSessionContext | null {
246
246
  const status = resolveSandboxRuntimeStatus(params)
247
247
  if (!status.sandboxed || !status.config || !status.scopeKey) return null
248
+
249
+ return {
250
+ containerName: `${status.config.containerPrefix}${slugifyScopeKey(status.scopeKey)}`.slice(0, 63),
251
+ containerWorkdir: status.config.workdir,
252
+ workspaceDir: params.workspaceDir,
253
+ workspaceAccess: status.config.workspaceAccess,
254
+ mode: status.mode,
255
+ scope: status.scope,
256
+ scopeKey: status.scopeKey,
257
+ config: status.config,
258
+ }
259
+ }
260
+
261
+ export async function ensureSessionSandbox(params: {
262
+ config: AgentSandboxConfig | null | undefined
263
+ session?: Session | null
264
+ agentId?: string | null
265
+ sessionId?: string | null
266
+ workspaceDir: string
267
+ }): Promise<SandboxSessionContext | null> {
268
+ const context = resolveSandboxSessionContext(params)
269
+ if (!context) return null
248
270
  await maybePruneSandboxes(params.config)
249
271
 
250
272
  const docker = detectDocker()
@@ -252,17 +274,16 @@ export async function ensureSessionSandbox(params: {
252
274
  throw new Error('Sandbox is enabled but Docker is not available. Install Docker Desktop or disable the sandbox in agent settings.')
253
275
  }
254
276
 
255
- const containerName = `${status.config.containerPrefix}${slugifyScopeKey(status.scopeKey)}`.slice(0, 63)
256
277
  const configHash = computeSandboxConfigHash({
257
- config: status.config,
278
+ config: context.config,
258
279
  workspaceDir: params.workspaceDir,
259
- scopeKey: status.scopeKey,
280
+ scopeKey: context.scopeKey,
260
281
  })
261
282
 
262
- const current = await inspectDockerContainer(containerName)
263
- const currentHash = current.exists ? await readDockerLabel(containerName, 'swarmclaw.configHash') : null
283
+ const current = await inspectDockerContainer(context.containerName)
284
+ const currentHash = current.exists ? await readDockerLabel(context.containerName, 'swarmclaw.configHash') : null
264
285
  if (current.exists && currentHash && currentHash !== configHash) {
265
- await execDocker(['rm', '-f', containerName], true)
286
+ await execDocker(['rm', '-f', context.containerName], true)
266
287
  }
267
288
 
268
289
  const next = current.exists && currentHash === configHash
@@ -271,37 +292,28 @@ export async function ensureSessionSandbox(params: {
271
292
 
272
293
  if (!next.exists) {
273
294
  await execDocker(buildSandboxCreateArgs({
274
- containerName,
275
- scopeKey: status.scopeKey,
295
+ containerName: context.containerName,
296
+ scopeKey: context.scopeKey,
276
297
  configHash,
277
- config: status.config,
298
+ config: context.config,
278
299
  workspaceDir: params.workspaceDir,
279
300
  }))
280
- await execDocker(['start', containerName])
281
- if (status.config.setupCommand) {
282
- await execDocker(['exec', '-i', containerName, '/bin/sh', '-lc', status.config.setupCommand])
301
+ await execDocker(['start', context.containerName])
302
+ if (context.config.setupCommand) {
303
+ await execDocker(['exec', '-i', context.containerName, '/bin/sh', '-lc', context.config.setupCommand])
283
304
  }
284
305
  } else if (!next.running) {
285
- await execDocker(['start', containerName])
306
+ await execDocker(['start', context.containerName])
286
307
  }
287
308
 
288
309
  await upsertSandboxRegistryEntry({
289
- containerName,
290
- scopeKey: status.scopeKey,
310
+ containerName: context.containerName,
311
+ scopeKey: context.scopeKey,
291
312
  createdAtMs: Date.now(),
292
313
  lastUsedAtMs: Date.now(),
293
- image: status.config.image,
314
+ image: context.config.image,
294
315
  configHash,
295
316
  })
296
317
 
297
- return {
298
- containerName,
299
- containerWorkdir: status.config.workdir,
300
- workspaceDir: params.workspaceDir,
301
- workspaceAccess: status.config.workspaceAccess,
302
- mode: status.mode,
303
- scope: status.scope,
304
- scopeKey: status.scopeKey,
305
- config: status.config,
306
- }
318
+ return context
307
319
  }
@@ -52,14 +52,12 @@ describe('durable wait surface', () => {
52
52
  })
53
53
  })
54
54
 
55
- describe('sandbox surface', () => {
56
- it('sandbox execution functions remain for shell integration', () => {
57
- const src = readToolSource('sandbox')
58
- assert.equal(src.includes('executeSandboxExec'), true)
59
- assert.equal(src.includes('executeListRuntimes'), true)
60
- assert.equal(src.includes('executeHostNode'), true)
61
- // Extension registration removed — sandbox_exec is now provided by shell
62
- assert.equal(src.includes('registerBuiltin'), false)
55
+ describe('execute surface', () => {
56
+ it('keeps just-bash as the sandboxed execution path with explicit host opt-in', () => {
57
+ const src = readToolSource('execute')
58
+ assert.equal(src.includes('just-bash'), true)
59
+ assert.equal(src.includes('normalizeAgentExecuteConfig'), true)
60
+ assert.equal(src.includes('persistent=true'), true)
63
61
  })
64
62
  })
65
63
 
@@ -81,7 +79,7 @@ describe('delegation job handles', () => {
81
79
 
82
80
  it('scheduler and daemon recover the durable autonomy jobs', () => {
83
81
  const schedulerSrc = fs.readFileSync(path.join(serverDir, 'runtime', 'scheduler.ts'), 'utf-8')
84
- const daemonSrc = fs.readFileSync(path.join(serverDir, 'runtime', 'daemon-state.ts'), 'utf-8')
82
+ const daemonSrc = fs.readFileSync(path.join(serverDir, 'runtime', 'daemon-state', 'core.ts'), 'utf-8')
85
83
  assert.equal(schedulerSrc.includes('processDueWatchJobs'), true)
86
84
  assert.equal(daemonSrc.includes('recoverStaleDelegationJobs'), true)
87
85
  })
@@ -190,7 +190,7 @@ export function findBinaryOnPath(binaryName: string): string | null {
190
190
  const { spawnSync } = require('child_process')
191
191
  const probe = isWindows
192
192
  ? spawnSync('where', [binaryName], { encoding: 'utf-8', timeout: 2000, stdio: 'pipe' })
193
- : spawnSync('/bin/zsh', ['-lc', `command -v ${binaryName} 2>/dev/null`], { encoding: 'utf-8', timeout: 2000 })
193
+ : spawnSync(process.env.SHELL || '/bin/bash', ['-lc', `command -v ${binaryName} 2>/dev/null`], { encoding: 'utf-8', timeout: 2000 })
194
194
  const resolved = (probe.stdout || '').trim() || null
195
195
  binaryLookupCache.set(binaryName, { checkedAt: now, path: resolved })
196
196
  return resolved
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Credential injection and secret redaction for agent code execution.
3
+ *
4
+ * Resolves an agent's configured credentials from the credential store,
5
+ * returns them as env vars for injection, and provides a redaction function
6
+ * to scrub secrets from execution output.
7
+ */
8
+
9
+ import { loadCredentials, decryptKey } from '../storage'
10
+ import { log } from '../logger'
11
+ import type { Credential } from '@/types'
12
+
13
+ const TAG = 'credential-env'
14
+
15
+ export interface CredentialEnv {
16
+ /** Environment variables to inject (name → decrypted value) */
17
+ env: Record<string, string>
18
+ /** Raw secret values for redaction */
19
+ secrets: string[]
20
+ }
21
+
22
+ /**
23
+ * Build credential environment variables for an agent execution.
24
+ *
25
+ * Each credential ID in the list is resolved from the credential store,
26
+ * decrypted, and mapped to an env var name derived from the credential's
27
+ * provider and name fields.
28
+ *
29
+ * Env var naming: `<PROVIDER>_API_KEY` for the primary key, or
30
+ * `<PROVIDER>_<NAME>` if a name is explicitly set. All uppercased,
31
+ * non-alphanumeric chars replaced with underscores.
32
+ */
33
+ export function buildCredentialEnv(credentialIds: string[]): CredentialEnv {
34
+ if (!credentialIds.length) return { env: {}, secrets: [] }
35
+
36
+ const env: Record<string, string> = {}
37
+ const secrets: string[] = []
38
+
39
+ const allCredentials = loadCredentials() as Record<string, Credential & { encrypted?: string }>
40
+
41
+ for (const credId of credentialIds) {
42
+ const cred = allCredentials[credId]
43
+ if (!cred) {
44
+ log.warn(TAG, `Credential not found: ${credId}`)
45
+ continue
46
+ }
47
+
48
+ // Decrypt the stored key
49
+ const encrypted = cred.encrypted
50
+ if (!encrypted || typeof encrypted !== 'string') {
51
+ log.warn(TAG, `Credential has no encrypted value: ${credId}`)
52
+ continue
53
+ }
54
+
55
+ let value: string
56
+ try {
57
+ value = decryptKey(encrypted)
58
+ } catch (err: unknown) {
59
+ log.warn(TAG, `Failed to decrypt credential ${credId}`, { error: String(err) })
60
+ continue
61
+ }
62
+
63
+ // Derive env var name
64
+ const envVarName = deriveEnvVarName(cred.provider, cred.name)
65
+ env[envVarName] = value
66
+ secrets.push(value)
67
+ }
68
+
69
+ return { env, secrets }
70
+ }
71
+
72
+ /**
73
+ * Derive an environment variable name from provider and credential name.
74
+ * e.g., provider="openai", name="default" → "OPENAI_API_KEY"
75
+ * e.g., provider="custom", name="my-service-token" → "CUSTOM_MY_SERVICE_TOKEN"
76
+ */
77
+ function deriveEnvVarName(provider: string, name: string): string {
78
+ const sanitize = (s: string) => s.toUpperCase().replace(/[^A-Z0-9]+/g, '_').replace(/^_|_$/g, '')
79
+
80
+ const providerKey = sanitize(provider)
81
+ const nameKey = sanitize(name)
82
+
83
+ // If name is generic (default, primary, key, api-key, etc.), use PROVIDER_API_KEY
84
+ const genericNames = new Set(['DEFAULT', 'PRIMARY', 'KEY', 'API_KEY', 'APIKEY', ''])
85
+ if (genericNames.has(nameKey)) {
86
+ return `${providerKey}_API_KEY`
87
+ }
88
+
89
+ return `${providerKey}_${nameKey}`
90
+ }
91
+
92
+ /**
93
+ * Redact secret values from execution output.
94
+ *
95
+ * Scans the text for any injected secret values and replaces them
96
+ * with [REDACTED]. Only redacts secrets longer than 4 characters
97
+ * to avoid false positives on short strings.
98
+ */
99
+ export function redactSecrets(text: string, secrets: string[]): string {
100
+ if (!secrets.length || !text) return text
101
+
102
+ let result = text
103
+ for (const secret of secrets) {
104
+ if (secret.length > 4) {
105
+ result = result.replaceAll(secret, '[REDACTED]')
106
+ }
107
+ }
108
+ return result
109
+ }
@@ -38,7 +38,6 @@ import {
38
38
  deriveTaskTitle,
39
39
  prepareTaskCreation,
40
40
  } from '@/lib/server/tasks/task-service'
41
- import { ensureMissionForTask, enrichTaskWithMissionSummary } from '@/lib/server/missions/mission-service'
42
41
  import { classifyMessage } from '@/lib/server/chat-execution/message-classifier'
43
42
  import {
44
43
  buildDelegationTaskProfile,
@@ -48,7 +47,7 @@ import {
48
47
  import type { ToolBuildContext } from './context'
49
48
  import { normalizeToolInputArgs } from './normalize-tool-args'
50
49
  import type { BoardTask } from '@/types'
51
- import { dedup } from '@/lib/shared-utils'
50
+ import { dedup, errorMessage } from '@/lib/shared-utils'
52
51
  import { isDirectConnectorSession } from '../connectors/session-kind'
53
52
  import { buildManageSkillsDescription, executeManageSkillsAction } from './skills'
54
53
  import { isMainSession } from '@/lib/server/agents/main-agent-loop'
@@ -742,19 +741,6 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
742
741
 
743
742
  res.save(all)
744
743
  if (toolKey === 'manage_tasks') {
745
- const mission = ensureMissionForTask(entry as BoardTask, {
746
- source: entry.sourceType === 'schedule'
747
- ? 'schedule'
748
- : entry.sourceType === 'delegation'
749
- ? 'delegation'
750
- : 'manual',
751
- })
752
- if (mission) {
753
- responseEntry = enrichTaskWithMissionSummary({
754
- ...(responseEntry as BoardTask),
755
- missionId: mission.id,
756
- })
757
- }
758
744
  if (taskDelegationAdvisory && responseEntry && typeof responseEntry === 'object') {
759
745
  responseEntry = {
760
746
  ...(responseEntry as Record<string, unknown>),
@@ -1149,8 +1135,8 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
1149
1135
  return JSON.stringify({ ok: true, taskId: id, claimedByAgentId: ctx?.agentId })
1150
1136
  }
1151
1137
  return `Unknown action "${action}". Valid: list, get, create, update, delete, claim_task`
1152
- } catch (err: any) {
1153
- return `Error: ${err.message}`
1138
+ } catch (err: unknown) {
1139
+ return `Error: ${errorMessage(err)}`
1154
1140
  }
1155
1141
  },
1156
1142
  {
@@ -21,7 +21,6 @@ import {
21
21
  registerDelegationRuntime,
22
22
  startDelegationJob,
23
23
  } from '@/lib/server/agents/delegation-jobs'
24
- import { loadSession } from '@/lib/server/sessions/session-repository'
25
24
  import { markProviderFailure, markProviderSuccess } from '../provider-health'
26
25
  import { loadRuntimeSettings } from '../runtime/runtime-settings'
27
26
  import { getSessionDepth } from '../agents/subagent-runtime'
@@ -463,8 +462,6 @@ async function executeDelegateAction(args: Record<string, unknown>, bctx: Delega
463
462
  const jobId = typeof normalized.jobId === 'string' ? normalized.jobId.trim() : ''
464
463
  const waitForCompletion = normalized.waitForCompletion !== false && normalized.background !== true
465
464
  const parentSessionId = resolveDelegateSessionId(bctx)
466
- const parentMissionId = parentSessionId ? loadSession(parentSessionId)?.missionId || null : null
467
-
468
465
  recoverStaleDelegationJobs()
469
466
 
470
467
  if (action === 'status') {
@@ -505,7 +502,6 @@ async function executeDelegateAction(args: Record<string, unknown>, bctx: Delega
505
502
  const job = createDelegationJob({
506
503
  kind: 'delegate',
507
504
  parentSessionId,
508
- parentMissionId,
509
505
  backend: requestedBackend,
510
506
  task,
511
507
  cwd: bctx.cwd || null,
@@ -1,3 +1,4 @@
1
+ import { errorMessage } from '@/lib/shared-utils'
1
2
  import { z } from 'zod'
2
3
  import { tool, type StructuredToolInterface } from '@langchain/core/tools'
3
4
  import fs from 'fs'
@@ -32,8 +33,8 @@ async function executeEditFile(args: { filePath: string; oldString: string; newS
32
33
  const updated = content.replace(oldString, newString)
33
34
  fs.writeFileSync(resolved, updated, 'utf-8')
34
35
  return `Successfully updated ${filePath} (1 replacement made).`
35
- } catch (err: any) {
36
- return `Error: ${err.message}`
36
+ } catch (err: unknown) {
37
+ return `Error: ${errorMessage(err)}`
37
38
  }
38
39
  }
39
40
 
@@ -0,0 +1,58 @@
1
+ import { describe, it } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { redactSecrets, buildCredentialEnv } from './credential-env'
4
+
5
+ describe('credential-env', () => {
6
+ describe('redactSecrets', () => {
7
+ it('redacts secret values from text', () => {
8
+ const secrets = ['sk-abc123456789']
9
+ const text = 'Response: Bearer sk-abc123456789 was used'
10
+ const result = redactSecrets(text, secrets)
11
+ assert.equal(result, 'Response: Bearer [REDACTED] was used')
12
+ })
13
+
14
+ it('skips secrets shorter than 5 characters', () => {
15
+ const secrets = ['abc']
16
+ const text = 'Contains abc value'
17
+ const result = redactSecrets(text, secrets)
18
+ assert.equal(result, 'Contains abc value')
19
+ })
20
+
21
+ it('handles empty secrets list', () => {
22
+ const text = 'No secrets here'
23
+ const result = redactSecrets(text, [])
24
+ assert.equal(result, 'No secrets here')
25
+ })
26
+
27
+ it('handles empty text', () => {
28
+ const result = redactSecrets('', ['secret123'])
29
+ assert.equal(result, '')
30
+ })
31
+
32
+ it('redacts multiple occurrences', () => {
33
+ const secrets = ['mytoken12345']
34
+ const text = 'First: mytoken12345, Second: mytoken12345'
35
+ const result = redactSecrets(text, secrets)
36
+ assert.equal(result, 'First: [REDACTED], Second: [REDACTED]')
37
+ })
38
+
39
+ it('redacts multiple different secrets', () => {
40
+ const secrets = ['secret_one_value', 'secret_two_value']
41
+ const text = 'Key1=secret_one_value Key2=secret_two_value'
42
+ const result = redactSecrets(text, secrets)
43
+ assert.equal(result, 'Key1=[REDACTED] Key2=[REDACTED]')
44
+ })
45
+ })
46
+
47
+ describe('buildCredentialEnv', () => {
48
+ it('returns empty env for empty credential list', () => {
49
+ const result = buildCredentialEnv([])
50
+ assert.deepEqual(result, { env: {}, secrets: [] })
51
+ })
52
+
53
+ it('handles non-existent credential IDs gracefully', () => {
54
+ const result = buildCredentialEnv(['nonexistent-id'])
55
+ assert.deepEqual(result, { env: {}, secrets: [] })
56
+ })
57
+ })
58
+ })