@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.
- package/README.md +54 -23
- package/next.config.ts +1 -0
- package/package.json +4 -3
- package/scripts/easy-setup.mjs +1 -1
- package/scripts/postinstall.mjs +1 -1
- package/skills/swarmclaw.md +115 -0
- package/skills/tools/browser.md +131 -0
- package/skills/tools/execute.md +98 -0
- package/skills/tools/files.md +98 -0
- package/skills/tools/memory.md +104 -0
- package/skills/tools/platform.md +144 -0
- package/skills/tools/skills.md +83 -0
- package/src/app/agents/[id]/page.tsx +1 -18
- package/src/app/api/agents/thread-route.test.ts +0 -1
- package/src/app/api/approvals/route.test.ts +6 -22
- package/src/app/api/chats/[id]/messages/route.ts +23 -19
- package/src/app/api/chats/messages-route.test.ts +105 -51
- package/src/app/api/connectors/route.ts +2 -2
- package/src/app/api/mcp-servers/[id]/test/route.ts +3 -2
- package/src/app/api/openclaw/deploy/route.ts +2 -0
- package/src/app/api/portability/export/route.ts +8 -0
- package/src/app/api/portability/import/route.test.ts +80 -0
- package/src/app/api/portability/import/route.ts +28 -0
- package/src/app/api/settings/route.ts +0 -2
- package/src/app/api/setup/doctor/route.ts +4 -4
- package/src/app/api/wallets/[id]/route.ts +15 -157
- package/src/app/api/wallets/generate/route.ts +22 -0
- package/src/app/api/wallets/route.test.ts +147 -0
- package/src/app/api/wallets/route.ts +13 -95
- package/src/app/autonomy/page.tsx +2 -57
- package/src/app/protocols/page.tsx +2 -21
- package/src/app/settings/page.tsx +0 -9
- package/src/app/wallets/page.tsx +105 -5
- package/src/cli/index.js +21 -33
- package/src/cli/spec.js +19 -30
- package/src/components/agents/agent-chat-list.tsx +23 -1
- package/src/components/agents/agent-sheet.tsx +2 -40
- package/src/components/agents/inspector-panel.tsx +165 -131
- package/src/components/chat/chat-area.tsx +38 -9
- package/src/components/chat/chat-card.tsx +0 -31
- package/src/components/chat/message-bubble.tsx +1 -108
- package/src/components/chat/message-list.tsx +33 -19
- package/src/components/connectors/connector-sheet.tsx +25 -1
- package/src/components/gateways/gateway-sheet.tsx +5 -2
- package/src/components/layout/sidebar-rail.tsx +6 -10
- package/src/components/projects/project-detail.tsx +3 -35
- package/src/components/projects/tabs/overview-tab.tsx +3 -59
- package/src/components/projects/tabs/work-tab.tsx +7 -77
- package/src/components/protocols/structured-session-launcher.tsx +1 -22
- package/src/components/shared/connector-platform-icon.tsx +1 -0
- package/src/components/tasks/task-card.tsx +4 -34
- package/src/components/tasks/task-sheet.tsx +6 -36
- package/src/components/wallets/wallet-list.tsx +150 -0
- package/src/lib/agent-execute-defaults.test.ts +24 -0
- package/src/lib/agent-execute-defaults.ts +62 -0
- package/src/lib/app/navigation.test.ts +0 -13
- package/src/lib/app/navigation.ts +2 -7
- package/src/lib/app/view-constants.ts +14 -19
- package/src/lib/chat/queued-message-queue.test.ts +134 -1
- package/src/lib/chat/queued-message-queue.ts +77 -2
- package/src/lib/server/agents/agent-service.ts +5 -0
- package/src/lib/server/agents/agent-thread-session.ts +0 -1
- package/src/lib/server/agents/delegation-advisory.test.ts +0 -1
- package/src/lib/server/agents/delegation-jobs.test.ts +0 -69
- package/src/lib/server/agents/delegation-jobs.ts +0 -25
- package/src/lib/server/agents/main-agent-loop.ts +1 -49
- package/src/lib/server/agents/subagent-runtime.ts +0 -1
- package/src/lib/server/approval-match.ts +0 -85
- package/src/lib/server/approvals.test.ts +6 -6
- package/src/lib/server/approvals.ts +0 -6
- package/src/lib/server/autonomy/supervisor-reflection.test.ts +0 -1
- package/src/lib/server/builtin-extensions.ts +1 -2
- package/src/lib/server/capability-router.test.ts +0 -2
- package/src/lib/server/chat-execution/chat-execution-advanced.test.ts +1 -1
- package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +15 -14
- package/src/lib/server/chat-execution/chat-execution-types.ts +0 -2
- package/src/lib/server/chat-execution/chat-execution-utils.ts +2 -4
- package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -30
- package/src/lib/server/chat-execution/chat-turn-finalization.ts +1 -36
- package/src/lib/server/chat-execution/chat-turn-preparation.ts +81 -64
- package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -0
- package/src/lib/server/chat-execution/continuation-evaluator.ts +8 -0
- package/src/lib/server/chat-execution/iteration-event-handler.ts +0 -24
- package/src/lib/server/chat-execution/memory-mutation-tools.ts +1 -1
- package/src/lib/server/chat-execution/message-classifier.test.ts +0 -45
- package/src/lib/server/chat-execution/message-classifier.ts +11 -16
- package/src/lib/server/chat-execution/prompt-builder.test.ts +27 -0
- package/src/lib/server/chat-execution/prompt-builder.ts +14 -31
- package/src/lib/server/chat-execution/prompt-mode.test.ts +24 -0
- package/src/lib/server/chat-execution/prompt-mode.ts +5 -1
- package/src/lib/server/chat-execution/prompt-sections.ts +0 -1
- package/src/lib/server/chat-execution/situational-awareness.test.ts +2 -73
- package/src/lib/server/chat-execution/situational-awareness.ts +4 -38
- package/src/lib/server/chat-execution/stream-agent-chat.test.ts +13 -126
- package/src/lib/server/chat-execution/stream-agent-chat.ts +46 -21
- package/src/lib/server/chat-execution/stream-continuation.test.ts +4 -52
- package/src/lib/server/chat-execution/stream-continuation.ts +6 -48
- package/src/lib/server/chatrooms/chatroom-routing.test.ts +4 -0
- package/src/lib/server/chatrooms/session-mailbox.ts +0 -10
- package/src/lib/server/chats/chat-session-service.ts +3 -5
- package/src/lib/server/connectors/connector-inbound.ts +0 -1
- package/src/lib/server/connectors/connector-lifecycle.ts +19 -3
- package/src/lib/server/connectors/connector-service.ts +39 -9
- package/src/lib/server/connectors/discord.ts +2 -2
- package/src/lib/server/connectors/matrix.ts +3 -2
- package/src/lib/server/connectors/signal.ts +5 -4
- package/src/lib/server/connectors/slack.ts +10 -9
- package/src/lib/server/connectors/swarmdock-bidding.ts +74 -0
- package/src/lib/server/connectors/swarmdock-payloads.test.ts +85 -0
- package/src/lib/server/connectors/swarmdock-secret.test.ts +128 -0
- package/src/lib/server/connectors/swarmdock-secret.ts +152 -0
- package/src/lib/server/connectors/swarmdock-tasks.ts +119 -0
- package/src/lib/server/connectors/swarmdock.ts +255 -0
- package/src/lib/server/connectors/teams.ts +3 -2
- package/src/lib/server/connectors/telegram.ts +4 -4
- package/src/lib/server/connectors/whatsapp.ts +2 -2
- package/src/lib/server/daemon/controller.ts +7 -0
- package/src/lib/server/execution-brief.test.ts +2 -25
- package/src/lib/server/execution-brief.ts +12 -35
- package/src/lib/server/execution-engine/task-attempt.ts +0 -1
- package/src/lib/server/gateways/gateway-profile-service.ts +19 -1
- package/src/lib/server/messages/message-repository.test.ts +70 -0
- package/src/lib/server/messages/message-repository.ts +11 -6
- package/src/lib/server/openclaw/deploy.ts +32 -2
- package/src/lib/server/persistence/storage-context.ts +0 -5
- package/src/lib/server/plugins-advanced.test.ts +1 -2
- package/src/lib/server/portability/export.ts +109 -0
- package/src/lib/server/portability/import.ts +159 -0
- package/src/lib/server/protocols/protocol-normalization.ts +0 -4
- package/src/lib/server/protocols/protocol-queries.ts +0 -6
- package/src/lib/server/protocols/protocol-run-lifecycle.ts +4 -32
- package/src/lib/server/protocols/protocol-service.ts +0 -1
- package/src/lib/server/protocols/protocol-step-helpers.ts +0 -4
- package/src/lib/server/protocols/protocol-step-processors.ts +0 -6
- package/src/lib/server/protocols/protocol-swarm.ts +0 -2
- package/src/lib/server/protocols/protocol-types.ts +0 -2
- package/src/lib/server/provider-health.ts +1 -10
- package/src/lib/server/runtime/daemon-state/core.ts +0 -9
- package/src/lib/server/runtime/daemon-state.test.ts +0 -35
- package/src/lib/server/runtime/heartbeat-service.ts +3 -23
- package/src/lib/server/runtime/process-manager.ts +13 -9
- package/src/lib/server/runtime/queue/core.ts +11 -33
- package/src/lib/server/runtime/runtime-storage-write-paths.test.ts +6 -6
- package/src/lib/server/runtime/scheduler.ts +0 -13
- package/src/lib/server/runtime/session-run-manager/drain.ts +0 -24
- package/src/lib/server/runtime/session-run-manager/enqueue.ts +0 -1
- package/src/lib/server/runtime/session-run-manager/queries.ts +15 -1
- package/src/lib/server/runtime/session-run-manager/recovery.ts +0 -1
- package/src/lib/server/runtime/session-run-manager.test.ts +58 -28
- package/src/lib/server/sandbox/session-runtime.test.ts +18 -1
- package/src/lib/server/sandbox/session-runtime.ts +40 -28
- package/src/lib/server/session-tools/autonomy-tools.test.ts +7 -9
- package/src/lib/server/session-tools/context.ts +1 -1
- package/src/lib/server/session-tools/credential-env.ts +109 -0
- package/src/lib/server/session-tools/crud.ts +3 -17
- package/src/lib/server/session-tools/delegate.ts +0 -4
- package/src/lib/server/session-tools/edit_file.ts +3 -2
- package/src/lib/server/session-tools/execute.test.ts +58 -0
- package/src/lib/server/session-tools/execute.ts +334 -0
- package/src/lib/server/session-tools/files-tool.ts +635 -0
- package/src/lib/server/session-tools/index.ts +14 -8
- package/src/lib/server/session-tools/memory-tool.ts +242 -0
- package/src/lib/server/session-tools/memory.ts +1 -1
- package/src/lib/server/session-tools/openclaw-nodes.ts +3 -2
- package/src/lib/server/session-tools/openclaw-workspace.ts +3 -2
- package/src/lib/server/session-tools/platform-tool.ts +617 -0
- package/src/lib/server/session-tools/session-info.ts +3 -2
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +3 -4
- package/src/lib/server/session-tools/shell.ts +7 -122
- package/src/lib/server/session-tools/skills-tool.ts +396 -0
- package/src/lib/server/session-tools/team-context.ts +0 -3
- package/src/lib/server/session-tools/web.ts +2 -2
- package/src/lib/server/storage-normalization.ts +10 -0
- package/src/lib/server/storage.ts +18 -45
- package/src/lib/server/tasks/task-checkout.ts +59 -0
- package/src/lib/server/tasks/task-lifecycle.ts +2 -0
- package/src/lib/server/tasks/task-route-service.ts +4 -26
- package/src/lib/server/tasks/task-service.ts +0 -7
- package/src/lib/server/tool-aliases.ts +2 -2
- package/src/lib/server/tool-capability-policy-advanced.test.ts +13 -6
- package/src/lib/server/tool-capability-policy.test.ts +2 -1
- package/src/lib/server/tool-capability-policy.ts +60 -35
- package/src/lib/server/tool-planning.ts +11 -12
- package/src/lib/server/universal-tool-access.ts +0 -1
- package/src/lib/server/wallets/wallet-crypto.ts +33 -0
- package/src/lib/server/wallets/wallet-repository.ts +24 -0
- package/src/lib/server/wallets/wallet-service.ts +119 -0
- package/src/lib/server/working-state/extraction.ts +8 -42
- package/src/lib/server/working-state/normalization.ts +10 -103
- package/src/lib/server/working-state/service.ts +12 -21
- package/src/lib/setup-defaults.ts +5 -0
- package/src/lib/strip-internal-metadata.test.ts +1 -1
- package/src/lib/strip-internal-metadata.ts +1 -1
- package/src/lib/tool-definitions.ts +1 -1
- package/src/lib/validation/schemas.test.ts +16 -0
- package/src/lib/validation/schemas.ts +49 -2
- package/src/stores/slices/data-slice.ts +5 -1
- package/src/stores/slices/ui-slice.ts +0 -4
- package/src/stores/use-chat-store.test.ts +231 -0
- package/src/stores/use-chat-store.ts +62 -13
- package/src/types/agent.ts +264 -0
- package/src/types/app-settings.ts +173 -0
- package/src/types/approval.ts +25 -0
- package/src/types/connector.ts +188 -0
- package/src/types/extension.ts +386 -0
- package/src/types/index.ts +16 -3555
- package/src/types/message.ts +56 -0
- package/src/types/misc.ts +737 -0
- package/src/types/protocol.ts +420 -0
- package/src/types/provider.ts +52 -0
- package/src/types/run.ts +180 -0
- package/src/types/schedule.ts +59 -0
- package/src/types/session.ts +215 -0
- package/src/types/skill.ts +157 -0
- package/src/types/swarmdock.ts +29 -0
- package/src/types/task.ts +144 -0
- package/src/types/working-state.ts +204 -0
- package/src/views/settings/section-heartbeat.tsx +2 -2
- package/src/views/settings/section-runtime-loop.tsx +0 -14
- package/src/app/api/canvas/[sessionId]/route.ts +0 -35
- package/src/app/api/missions/[id]/actions/route.ts +0 -31
- package/src/app/api/missions/[id]/events/route.ts +0 -14
- package/src/app/api/missions/[id]/route.ts +0 -10
- package/src/app/api/missions/route.test.ts +0 -244
- package/src/app/api/missions/route.ts +0 -57
- package/src/app/api/wallets/[id]/approve/route.ts +0 -79
- package/src/app/api/wallets/[id]/balance-history/route.ts +0 -18
- package/src/app/api/wallets/[id]/send/route.ts +0 -113
- package/src/app/api/wallets/[id]/transactions/route.ts +0 -18
- package/src/app/missions/[id]/page.tsx +0 -3
- package/src/app/missions/page.tsx +0 -685
- package/src/components/canvas/canvas-panel.tsx +0 -267
- package/src/components/wallets/wallet-approval-dialog.tsx +0 -107
- package/src/components/wallets/wallet-panel.tsx +0 -1010
- package/src/components/wallets/wallet-section.tsx +0 -260
- package/src/features/missions/queries.ts +0 -23
- package/src/lib/canvas-content.test.ts +0 -360
- package/src/lib/canvas-content.ts +0 -198
- package/src/lib/server/canvas-content.test.ts +0 -32
- package/src/lib/server/canvas-content.ts +0 -6
- package/src/lib/server/ethereum.ts +0 -591
- package/src/lib/server/evm-swap.ts +0 -476
- package/src/lib/server/missions/mission-intent.test.ts +0 -63
- package/src/lib/server/missions/mission-intent.ts +0 -569
- package/src/lib/server/missions/mission-repository.ts +0 -74
- package/src/lib/server/missions/mission-service/actions.ts +0 -6
- package/src/lib/server/missions/mission-service/bindings.ts +0 -9
- package/src/lib/server/missions/mission-service/context.ts +0 -4
- package/src/lib/server/missions/mission-service/core.ts +0 -2271
- package/src/lib/server/missions/mission-service/queries.ts +0 -12
- package/src/lib/server/missions/mission-service/recovery.ts +0 -5
- package/src/lib/server/missions/mission-service/ticks.ts +0 -9
- package/src/lib/server/missions/mission-service.test.ts +0 -888
- package/src/lib/server/missions/mission-service.ts +0 -6
- package/src/lib/server/session-tools/canvas.ts +0 -105
- package/src/lib/server/session-tools/sandbox.ts +0 -281
- package/src/lib/server/session-tools/wallet-tool.test.ts +0 -150
- package/src/lib/server/session-tools/wallet.ts +0 -1287
- package/src/lib/server/solana.ts +0 -327
- package/src/lib/server/wallet/wallet-execution.test.ts +0 -198
- package/src/lib/server/wallet/wallet-portfolio.test.ts +0 -98
- package/src/lib/server/wallet/wallet-portfolio.ts +0 -772
- package/src/lib/server/wallet/wallet-service.test.ts +0 -81
- package/src/lib/server/wallet/wallet-service.ts +0 -225
- package/src/lib/wallet/wallet-transactions.test.ts +0 -75
- package/src/lib/wallet/wallet-transactions.ts +0 -43
- package/src/lib/wallet/wallet.test.ts +0 -333
- package/src/lib/wallet/wallet.ts +0 -183
- package/src/views/settings/section-wallets.tsx +0 -35
|
@@ -24,8 +24,6 @@ import type {
|
|
|
24
24
|
GuardianCheckpoint,
|
|
25
25
|
LearnedSkill,
|
|
26
26
|
Message,
|
|
27
|
-
Mission,
|
|
28
|
-
MissionEvent,
|
|
29
27
|
ProtocolTemplate,
|
|
30
28
|
ProtocolRun,
|
|
31
29
|
ProtocolRunEvent,
|
|
@@ -138,9 +136,6 @@ const COLLECTIONS = [
|
|
|
138
136
|
'webhook_retry_queue',
|
|
139
137
|
'notifications',
|
|
140
138
|
'chatrooms',
|
|
141
|
-
'wallets',
|
|
142
|
-
'wallet_transactions',
|
|
143
|
-
'wallet_balance_history',
|
|
144
139
|
'moderation_logs',
|
|
145
140
|
'connector_health',
|
|
146
141
|
'connector_outbox',
|
|
@@ -152,8 +147,6 @@ const COLLECTIONS = [
|
|
|
152
147
|
'watch_jobs',
|
|
153
148
|
'delegation_jobs',
|
|
154
149
|
'external_agents',
|
|
155
|
-
'missions',
|
|
156
|
-
'mission_events',
|
|
157
150
|
'protocol_templates',
|
|
158
151
|
'protocol_runs',
|
|
159
152
|
'protocol_run_events',
|
|
@@ -162,6 +155,8 @@ const COLLECTIONS = [
|
|
|
162
155
|
'main_loop_states',
|
|
163
156
|
'working_states',
|
|
164
157
|
'daemon_status',
|
|
158
|
+
'wallets',
|
|
159
|
+
'wallet_transactions',
|
|
165
160
|
] as const
|
|
166
161
|
|
|
167
162
|
export type StorageCollection = (typeof COLLECTIONS)[number]
|
|
@@ -545,8 +540,6 @@ const JSON_FILES: Record<string, string> = {
|
|
|
545
540
|
documents: path.join(DATA_DIR, 'documents.json'),
|
|
546
541
|
webhooks: path.join(DATA_DIR, 'webhooks.json'),
|
|
547
542
|
external_agents: path.join(DATA_DIR, 'external-agents.json'),
|
|
548
|
-
missions: path.join(DATA_DIR, 'missions.json'),
|
|
549
|
-
mission_events: path.join(DATA_DIR, 'mission-events.json'),
|
|
550
543
|
protocol_templates: path.join(DATA_DIR, 'protocol-templates.json'),
|
|
551
544
|
protocol_runs: path.join(DATA_DIR, 'protocol-runs.json'),
|
|
552
545
|
protocol_run_events: path.join(DATA_DIR, 'protocol-run-events.json'),
|
|
@@ -1208,25 +1201,6 @@ export const loadProjects = projectsStore.load
|
|
|
1208
1201
|
export const saveProjects = projectsStore.save
|
|
1209
1202
|
export const deleteProject = projectsStore.deleteItem
|
|
1210
1203
|
|
|
1211
|
-
// --- Missions ---
|
|
1212
|
-
const missionsStore = createCollectionStore('missions')
|
|
1213
|
-
export const loadMissions = missionsStore.load as () => Record<string, Mission>
|
|
1214
|
-
export const saveMissions = missionsStore.save as (items: Record<string, Mission>) => void
|
|
1215
|
-
export const loadMission = missionsStore.loadItem as (id: string) => Mission | null
|
|
1216
|
-
export const upsertMission = missionsStore.upsert as (id: string, value: Mission) => void
|
|
1217
|
-
export const patchMission = missionsStore.patch as (
|
|
1218
|
-
id: string,
|
|
1219
|
-
updater: (current: Mission | null) => Mission | null,
|
|
1220
|
-
) => Mission | null
|
|
1221
|
-
export const deleteMission = missionsStore.deleteItem
|
|
1222
|
-
|
|
1223
|
-
const missionEventsStore = createCollectionStore('mission_events')
|
|
1224
|
-
export const loadMissionEvents = missionEventsStore.load as () => Record<string, MissionEvent>
|
|
1225
|
-
export const saveMissionEvents = missionEventsStore.save as (items: Record<string, MissionEvent>) => void
|
|
1226
|
-
export const loadMissionEvent = missionEventsStore.loadItem as (id: string) => MissionEvent | null
|
|
1227
|
-
export const upsertMissionEvent = missionEventsStore.upsert as (id: string, value: MissionEvent) => void
|
|
1228
|
-
export const upsertMissionEvents = missionEventsStore.upsertMany as (entries: Array<[string, MissionEvent]>) => void
|
|
1229
|
-
|
|
1230
1204
|
const protocolTemplatesStore = createCollectionStore('protocol_templates')
|
|
1231
1205
|
export const loadProtocolTemplates = protocolTemplatesStore.load as () => Record<string, ProtocolTemplate>
|
|
1232
1206
|
export const saveProtocolTemplates = protocolTemplatesStore.save as (items: Record<string, ProtocolTemplate>) => void
|
|
@@ -1541,23 +1515,6 @@ export function markNotificationRead(id: string) {
|
|
|
1541
1515
|
}
|
|
1542
1516
|
}
|
|
1543
1517
|
|
|
1544
|
-
// --- Wallets ---
|
|
1545
|
-
const walletsStore = createCollectionStore('wallets')
|
|
1546
|
-
export const loadWallets = walletsStore.load
|
|
1547
|
-
export const upsertWallet = walletsStore.upsert
|
|
1548
|
-
export const deleteWallet = walletsStore.deleteItem
|
|
1549
|
-
|
|
1550
|
-
// --- Wallet Transactions ---
|
|
1551
|
-
const walletTransactionsStore = createCollectionStore('wallet_transactions')
|
|
1552
|
-
export const loadWalletTransactions = walletTransactionsStore.load
|
|
1553
|
-
export const upsertWalletTransaction = walletTransactionsStore.upsert
|
|
1554
|
-
export const deleteWalletTransaction = walletTransactionsStore.deleteItem
|
|
1555
|
-
|
|
1556
|
-
// --- Wallet Balance History ---
|
|
1557
|
-
const walletBalanceHistoryStore = createCollectionStore('wallet_balance_history')
|
|
1558
|
-
export const loadWalletBalanceHistory = walletBalanceHistoryStore.load
|
|
1559
|
-
export const upsertWalletBalanceSnapshot = walletBalanceHistoryStore.upsert
|
|
1560
|
-
|
|
1561
1518
|
// --- Moderation Logs ---
|
|
1562
1519
|
const moderationLogsStore = createCollectionStore('moderation_logs')
|
|
1563
1520
|
export const loadModerationLogs = moderationLogsStore.load
|
|
@@ -1613,6 +1570,22 @@ export const loadPersistedWorkingState = workingStatesStore.loadItem
|
|
|
1613
1570
|
export const upsertPersistedWorkingState = workingStatesStore.upsert
|
|
1614
1571
|
export const deletePersistedWorkingState = workingStatesStore.deleteItem
|
|
1615
1572
|
|
|
1573
|
+
// --- Wallets ---
|
|
1574
|
+
const walletsStore = createCollectionStore('wallets')
|
|
1575
|
+
export const loadWallets = walletsStore.load
|
|
1576
|
+
export const saveWallets = walletsStore.save
|
|
1577
|
+
export const loadWallet = walletsStore.loadItem
|
|
1578
|
+
export const upsertWallet = walletsStore.upsert
|
|
1579
|
+
export const deleteWalletItem = walletsStore.deleteItem
|
|
1580
|
+
|
|
1581
|
+
// --- Wallet Transactions ---
|
|
1582
|
+
const walletTransactionsStore = createCollectionStore('wallet_transactions')
|
|
1583
|
+
export const loadWalletTransactions = walletTransactionsStore.load
|
|
1584
|
+
export const saveWalletTransactions = walletTransactionsStore.save
|
|
1585
|
+
export const loadWalletTransaction = walletTransactionsStore.loadItem
|
|
1586
|
+
export const upsertWalletTransaction = walletTransactionsStore.upsert
|
|
1587
|
+
export const deleteWalletTransaction = walletTransactionsStore.deleteItem
|
|
1588
|
+
|
|
1616
1589
|
export function getSessionMessages(sessionId: string): Message[] {
|
|
1617
1590
|
const session = loadSession(sessionId)
|
|
1618
1591
|
return Array.isArray(session?.messages) ? session.messages : []
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { BoardTask } from '@/types'
|
|
2
|
+
import { withTransaction } from '@/lib/server/persistence/transaction'
|
|
3
|
+
import { loadTasks, saveTasks } from '@/lib/server/tasks/task-repository'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Atomically transition a task from queued → running with a checkout run ID.
|
|
7
|
+
*
|
|
8
|
+
* Uses a SQLite IMMEDIATE transaction to prevent two runners from starting the
|
|
9
|
+
* same task concurrently (Paperclip-inspired atomic checkout pattern).
|
|
10
|
+
*
|
|
11
|
+
* Returns the checked-out task on success, or null if the task was already
|
|
12
|
+
* taken, missing, or no longer in queued status.
|
|
13
|
+
*/
|
|
14
|
+
export function checkoutTask(
|
|
15
|
+
taskId: string,
|
|
16
|
+
runId: string,
|
|
17
|
+
): BoardTask | null {
|
|
18
|
+
return withTransaction(() => {
|
|
19
|
+
const tasks = loadTasks() as Record<string, BoardTask>
|
|
20
|
+
const task = tasks[taskId]
|
|
21
|
+
if (!task || task.status !== 'queued') return null
|
|
22
|
+
if (task.checkoutRunId) return null // already checked out
|
|
23
|
+
|
|
24
|
+
const now = Date.now()
|
|
25
|
+
task.status = 'running'
|
|
26
|
+
task.checkoutRunId = runId
|
|
27
|
+
task.startedAt = now
|
|
28
|
+
task.lastActivityAt = now
|
|
29
|
+
task.retryScheduledAt = null
|
|
30
|
+
task.deadLetteredAt = null
|
|
31
|
+
task.error = null
|
|
32
|
+
task.validation = null
|
|
33
|
+
task.updatedAt = now
|
|
34
|
+
|
|
35
|
+
saveTasks(tasks)
|
|
36
|
+
return { ...task }
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Release a checkout after task completion or failure.
|
|
42
|
+
* Only the holder of the checkout (matching runId) can release it.
|
|
43
|
+
*/
|
|
44
|
+
export function releaseCheckout(
|
|
45
|
+
taskId: string,
|
|
46
|
+
runId: string,
|
|
47
|
+
): boolean {
|
|
48
|
+
return withTransaction(() => {
|
|
49
|
+
const tasks = loadTasks() as Record<string, BoardTask>
|
|
50
|
+
const task = tasks[taskId]
|
|
51
|
+
if (!task) return false
|
|
52
|
+
if (task.checkoutRunId !== runId) return false
|
|
53
|
+
|
|
54
|
+
task.checkoutRunId = null
|
|
55
|
+
task.updatedAt = Date.now()
|
|
56
|
+
saveTasks(tasks)
|
|
57
|
+
return true
|
|
58
|
+
})
|
|
59
|
+
}
|
|
@@ -176,6 +176,7 @@ export function markValidatedTaskCompleted(
|
|
|
176
176
|
task.completedAt = options.preserveCompletedAt ? (task.completedAt || options.now) : options.now
|
|
177
177
|
task.updatedAt = options.now
|
|
178
178
|
task.error = null
|
|
179
|
+
task.checkoutRunId = null
|
|
179
180
|
return task
|
|
180
181
|
}
|
|
181
182
|
|
|
@@ -187,6 +188,7 @@ export function markInvalidCompletedTaskFailed(
|
|
|
187
188
|
task.status = 'failed'
|
|
188
189
|
task.completedAt = null
|
|
189
190
|
task.updatedAt = options.now
|
|
191
|
+
task.checkoutRunId = null
|
|
190
192
|
task.error = formatValidationFailure(validation.reasons).slice(0, 500)
|
|
191
193
|
if (options.comment) {
|
|
192
194
|
if (!task.comments) task.comments = []
|
|
@@ -6,11 +6,6 @@ import { logActivity } from '@/lib/server/activity/activity-log'
|
|
|
6
6
|
import { createNotification } from '@/lib/server/create-notification'
|
|
7
7
|
import { validateDag, cascadeUnblock } from '@/lib/server/dag-validation'
|
|
8
8
|
import { getExtensionManager } from '@/lib/server/extensions'
|
|
9
|
-
import {
|
|
10
|
-
enrichTaskWithMissionSummary,
|
|
11
|
-
ensureMissionForTask,
|
|
12
|
-
noteMissionTaskFinished,
|
|
13
|
-
} from '@/lib/server/missions/mission-service'
|
|
14
9
|
import {
|
|
15
10
|
disableSessionHeartbeat,
|
|
16
11
|
enqueueTask,
|
|
@@ -64,9 +59,7 @@ export function prepareTasksForListing() {
|
|
|
64
59
|
validateCompletedTasksQueue()
|
|
65
60
|
recoverStalledRunningTasks()
|
|
66
61
|
const allTasks = loadTasks()
|
|
67
|
-
return
|
|
68
|
-
Object.entries(allTasks).map(([id, task]) => [id, enrichTaskWithMissionSummary(task)]),
|
|
69
|
-
)
|
|
62
|
+
return allTasks
|
|
70
63
|
}
|
|
71
64
|
|
|
72
65
|
export function updateTaskFromRoute(id: string, body: Record<string, unknown>): ServiceResult<BoardTask> {
|
|
@@ -128,10 +121,6 @@ export function updateTaskFromRoute(id: string, body: Record<string, unknown>):
|
|
|
128
121
|
}
|
|
129
122
|
|
|
130
123
|
saveTask(id, tasks[id])
|
|
131
|
-
const mission = ensureMissionForTask(tasks[id], { source: 'manual' })
|
|
132
|
-
if (tasks[id].status === 'completed' || tasks[id].status === 'failed' || tasks[id].status === 'cancelled') {
|
|
133
|
-
noteMissionTaskFinished(tasks[id], tasks[id].status, tasks[id].id)
|
|
134
|
-
}
|
|
135
124
|
logActivity({ entityType: 'task', entityId: id, action: 'updated', actor: 'user', summary: `Task updated: "${tasks[id].title}" (${prevStatus} → ${tasks[id].status})` })
|
|
136
125
|
if (prevStatus !== tasks[id].status) {
|
|
137
126
|
pushMainLoopEventToMainSessions({
|
|
@@ -143,10 +132,7 @@ export function updateTaskFromRoute(id: string, body: Record<string, unknown>):
|
|
|
143
132
|
if (prevStatus !== tasks[id].status && tasks[id].status === 'cancelled') {
|
|
144
133
|
disableSessionHeartbeat(tasks[id].sessionId)
|
|
145
134
|
notify('tasks')
|
|
146
|
-
return serviceOk(
|
|
147
|
-
...tasks[id],
|
|
148
|
-
missionId: mission?.id || tasks[id].missionId || null,
|
|
149
|
-
}))
|
|
135
|
+
return serviceOk(tasks[id])
|
|
150
136
|
}
|
|
151
137
|
|
|
152
138
|
if (prevStatus !== tasks[id].status && (tasks[id].status === 'completed' || tasks[id].status === 'failed')) {
|
|
@@ -216,10 +202,7 @@ export function updateTaskFromRoute(id: string, body: Record<string, unknown>):
|
|
|
216
202
|
}
|
|
217
203
|
|
|
218
204
|
notify('tasks')
|
|
219
|
-
return serviceOk(
|
|
220
|
-
...tasks[id],
|
|
221
|
-
missionId: mission?.id || tasks[id].missionId || null,
|
|
222
|
-
}))
|
|
205
|
+
return serviceOk(tasks[id])
|
|
223
206
|
}
|
|
224
207
|
|
|
225
208
|
export function archiveTaskFromRoute(id: string): ServiceResult<BoardTask> {
|
|
@@ -346,11 +329,6 @@ export function createTaskFromRoute(body: Record<string, unknown>): ServiceResul
|
|
|
346
329
|
}
|
|
347
330
|
|
|
348
331
|
saveTask(id, task)
|
|
349
|
-
const mission = ensureMissionForTask(task, { source: 'manual' })
|
|
350
|
-
const finalTask = enrichTaskWithMissionSummary({
|
|
351
|
-
...task,
|
|
352
|
-
missionId: mission?.id || task.missionId || null,
|
|
353
|
-
})
|
|
354
332
|
logActivity({ entityType: 'task', entityId: id, action: 'created', actor: 'user', summary: `Task created: "${task.title}"` })
|
|
355
333
|
pushMainLoopEventToMainSessions({
|
|
356
334
|
type: 'task_created',
|
|
@@ -360,7 +338,7 @@ export function createTaskFromRoute(body: Record<string, unknown>): ServiceResul
|
|
|
360
338
|
enqueueTask(id)
|
|
361
339
|
}
|
|
362
340
|
notify('tasks')
|
|
363
|
-
return serviceOk(
|
|
341
|
+
return serviceOk(task)
|
|
364
342
|
}
|
|
365
343
|
|
|
366
344
|
export function bulkUpdateTasksFromRoute(body: Record<string, unknown>): ServiceResult<{ updated: number; ids: string[] }> {
|
|
@@ -106,13 +106,6 @@ export function applyTaskContinuationDefaults(
|
|
|
106
106
|
if (!Object.prototype.hasOwnProperty.call(explicit, 'cwd') && typeof sourceTask.cwd === 'string' && sourceTask.cwd.trim()) {
|
|
107
107
|
parsed.cwd = sourceTask.cwd.trim()
|
|
108
108
|
}
|
|
109
|
-
if (
|
|
110
|
-
!Object.prototype.hasOwnProperty.call(explicit, 'missionId')
|
|
111
|
-
&& typeof sourceTask.missionId === 'string'
|
|
112
|
-
&& sourceTask.missionId.trim()
|
|
113
|
-
) {
|
|
114
|
-
parsed.missionId = sourceTask.missionId.trim()
|
|
115
|
-
}
|
|
116
109
|
const sourceSessionId = typeof sourceTask.checkpoint?.lastSessionId === 'string' && sourceTask.checkpoint.lastSessionId.trim()
|
|
117
110
|
? sourceTask.checkpoint.lastSessionId.trim()
|
|
118
111
|
: typeof sourceTask.sessionId === 'string' && sourceTask.sessionId.trim()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const EXTENSION_ALIAS_GROUPS: string[][] = [
|
|
2
|
-
['shell', 'execute_command', 'process_tool', 'git'
|
|
2
|
+
['shell', 'execute_command', 'process_tool', 'git'],
|
|
3
|
+
['execute', 'sandbox'],
|
|
3
4
|
['files', 'read_file', 'write_file', 'list_files', 'copy_file', 'move_file', 'delete_file', 'send_file'],
|
|
4
5
|
['edit_file'],
|
|
5
6
|
['web', 'web_search', 'web_fetch', 'http_request', 'http'],
|
|
@@ -21,7 +22,6 @@ const EXTENSION_ALIAS_GROUPS: string[][] = [
|
|
|
21
22
|
['schedule_wake', 'schedule'],
|
|
22
23
|
// http_request/http now aliased into web group above
|
|
23
24
|
['memory', 'memory_tool', 'memory_search', 'memory_get', 'memory_store', 'memory_update'],
|
|
24
|
-
['wallet', 'wallet_tool'],
|
|
25
25
|
['monitor', 'monitor_tool'],
|
|
26
26
|
['context_mgmt', 'context_status', 'context_summarize'],
|
|
27
27
|
['openclaw_workspace'],
|
|
@@ -92,6 +92,13 @@ describe('strict mode', () => {
|
|
|
92
92
|
assert.match(d.blockedExtensions[0].reason, /strict policy/)
|
|
93
93
|
})
|
|
94
94
|
|
|
95
|
+
it('blocks execute (execution category)', () => {
|
|
96
|
+
const d = resolveSessionToolPolicy(['execute'], mode)
|
|
97
|
+
assert.equal(d.blockedExtensions.length, 1)
|
|
98
|
+
assert.equal(d.blockedExtensions[0].tool, 'execute')
|
|
99
|
+
assert.match(d.blockedExtensions[0].reason, /strict policy/)
|
|
100
|
+
})
|
|
101
|
+
|
|
95
102
|
it('blocks files (filesystem category)', () => {
|
|
96
103
|
const d = resolveSessionToolPolicy(['files'], mode)
|
|
97
104
|
assert.equal(d.blockedExtensions.length, 1)
|
|
@@ -168,7 +175,7 @@ describe('safety blocks', () => {
|
|
|
168
175
|
assert.equal(d.blockedExtensions[0].source, 'safety')
|
|
169
176
|
})
|
|
170
177
|
|
|
171
|
-
it('safety block on concrete web_search blocks the
|
|
178
|
+
it('safety block on concrete web_search blocks the requested extension', () => {
|
|
172
179
|
const d = resolveSessionToolPolicy(['web_search'], {
|
|
173
180
|
safetyBlockedTools: ['web_search'],
|
|
174
181
|
})
|
|
@@ -186,7 +193,7 @@ describe('safety blocks', () => {
|
|
|
186
193
|
assert.equal(d.blockedExtensions[0].source, 'safety')
|
|
187
194
|
})
|
|
188
195
|
|
|
189
|
-
it('safety block on delegate_to_claude_code blocks
|
|
196
|
+
it('safety block on delegate_to_claude_code blocks the requested extension', () => {
|
|
190
197
|
const d = resolveSessionToolPolicy(['claude_code'], {
|
|
191
198
|
safetyBlockedTools: ['delegate_to_claude_code'],
|
|
192
199
|
})
|
|
@@ -416,17 +423,17 @@ describe('compound scenarios', () => {
|
|
|
416
423
|
assert.match(tasksBlock.reason, /task management is disabled/)
|
|
417
424
|
})
|
|
418
425
|
|
|
419
|
-
it('
|
|
426
|
+
it('19 tools requested: correctly partitioned into enabled vs blocked', () => {
|
|
420
427
|
const tools = [
|
|
421
428
|
'shell', 'files', 'web', 'web_search', 'web_fetch', 'browser',
|
|
422
429
|
'memory', 'delegate', 'manage_platform', 'manage_tasks',
|
|
423
|
-
'manage_schedules', 'wallet', 'delete_file',
|
|
430
|
+
'manage_schedules', 'wallet', 'delete_file',
|
|
424
431
|
'manage_connectors', 'git', 'sandbox', 'claude_code',
|
|
425
432
|
'monitor', 'http_request',
|
|
426
433
|
]
|
|
427
434
|
const d = resolveSessionToolPolicy(tools, { capabilityPolicyMode: 'strict' })
|
|
428
|
-
assert.equal(d.requestedExtensions.length,
|
|
429
|
-
assert.equal(d.enabledExtensions.length + d.blockedExtensions.length,
|
|
435
|
+
assert.equal(d.requestedExtensions.length, 19)
|
|
436
|
+
assert.equal(d.enabledExtensions.length + d.blockedExtensions.length, 19)
|
|
430
437
|
|
|
431
438
|
// memory, web, web_search, web_fetch should be enabled
|
|
432
439
|
assert.ok(d.enabledExtensions.includes('memory'))
|
|
@@ -20,11 +20,12 @@ test('capability policy balanced mode blocks destructive delete_file', () => {
|
|
|
20
20
|
|
|
21
21
|
test('capability policy strict mode blocks execution/platform families', () => {
|
|
22
22
|
const decision = resolveSessionToolPolicy(
|
|
23
|
-
['shell', 'manage_tasks', 'web_search', 'memory'],
|
|
23
|
+
['shell', 'execute', 'manage_tasks', 'web_search', 'memory'],
|
|
24
24
|
{ capabilityPolicyMode: 'strict' },
|
|
25
25
|
)
|
|
26
26
|
assert.deepEqual(decision.enabledExtensions, ['web_search', 'memory'])
|
|
27
27
|
assert.equal(decision.blockedExtensions.some((entry) => entry.tool === 'shell'), true)
|
|
28
|
+
assert.equal(decision.blockedExtensions.some((entry) => entry.tool === 'execute'), true)
|
|
28
29
|
assert.equal(decision.blockedExtensions.some((entry) => entry.tool === 'manage_tasks'), true)
|
|
29
30
|
})
|
|
30
31
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AppSettings } from '@/types'
|
|
2
2
|
import { dedup } from '@/lib/shared-utils'
|
|
3
|
+
import { canonicalizeExtensionId } from './tool-aliases'
|
|
3
4
|
|
|
4
5
|
export type CapabilityPolicyMode = 'permissive' | 'balanced' | 'strict'
|
|
5
6
|
|
|
@@ -37,6 +38,7 @@ interface ToolDescriptor {
|
|
|
37
38
|
|
|
38
39
|
const TOOL_DESCRIPTORS: Record<string, ToolDescriptor> = {
|
|
39
40
|
shell: { categories: ['execution'], concreteTools: ['shell', 'execute_command'] },
|
|
41
|
+
execute: { categories: ['execution'], concreteTools: ['execute'] },
|
|
40
42
|
process: { categories: ['execution'], concreteTools: ['process', 'process_tool'] },
|
|
41
43
|
files: { categories: ['filesystem'], concreteTools: ['files', 'read_file', 'write_file', 'list_files', 'send_file'] },
|
|
42
44
|
read_file: { categories: ['filesystem'], concreteTools: ['read_file'] },
|
|
@@ -57,10 +59,7 @@ const TOOL_DESCRIPTORS: Record<string, ToolDescriptor> = {
|
|
|
57
59
|
opencode_cli: { categories: ['delegation', 'execution'], concreteTools: ['delegate_to_opencode_cli'] },
|
|
58
60
|
gemini_cli: { categories: ['delegation', 'execution'], concreteTools: ['delegate_to_gemini_cli'] },
|
|
59
61
|
memory: { categories: ['memory'], concreteTools: ['memory', 'memory_tool', 'memory_search', 'memory_get', 'memory_store', 'memory_update', 'context_status', 'context_summarize'] },
|
|
60
|
-
// sandbox_exec/sandbox_list_runtimes routed through shell; git uses shell
|
|
61
62
|
// http_request consolidated into web 'api' action — no separate descriptor
|
|
62
|
-
canvas: { categories: ['filesystem'], concreteTools: ['canvas'] },
|
|
63
|
-
wallet: { categories: ['outbound'], concreteTools: ['wallet', 'wallet_tool'] },
|
|
64
63
|
monitor: { categories: ['execution'], concreteTools: ['monitor', 'monitor_tool'] },
|
|
65
64
|
openclaw_workspace: { categories: ['filesystem', 'platform'], concreteTools: ['openclaw_workspace'] },
|
|
66
65
|
openclaw_nodes: { categories: ['platform'], concreteTools: ['openclaw_nodes'] },
|
|
@@ -118,6 +117,55 @@ function normalizeList(value: unknown): string[] {
|
|
|
118
117
|
return dedup(names)
|
|
119
118
|
}
|
|
120
119
|
|
|
120
|
+
function getDescriptor(toolName: string): ToolDescriptor | undefined {
|
|
121
|
+
const normalized = normalizeName(toolName)
|
|
122
|
+
if (!normalized) return undefined
|
|
123
|
+
return TOOL_DESCRIPTORS[normalized] || TOOL_DESCRIPTORS[normalizeName(canonicalizeExtensionId(normalized))]
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function addComparableName(names: Set<string>, value: string | null | undefined): void {
|
|
127
|
+
const normalized = normalizeName(value)
|
|
128
|
+
if (!normalized) return
|
|
129
|
+
names.add(normalized)
|
|
130
|
+
const canonical = normalizeName(canonicalizeExtensionId(normalized))
|
|
131
|
+
if (canonical) names.add(canonical)
|
|
132
|
+
for (const mappedTool of CONCRETE_TOOL_TO_SESSION_TOOLS.get(normalized) || []) {
|
|
133
|
+
names.add(mappedTool)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function collectRequestedExtensionNames(toolName: string, descriptor?: ToolDescriptor): string[] {
|
|
138
|
+
const names = new Set<string>()
|
|
139
|
+
addComparableName(names, toolName)
|
|
140
|
+
for (const concreteName of descriptor?.concreteTools || []) {
|
|
141
|
+
addComparableName(names, concreteName)
|
|
142
|
+
}
|
|
143
|
+
return Array.from(names)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function entryMatchesSessionTool(entry: string, sessionTool: string): boolean {
|
|
147
|
+
const normalizedEntry = normalizeName(entry)
|
|
148
|
+
const normalizedTool = normalizeName(sessionTool)
|
|
149
|
+
if (!normalizedEntry || !normalizedTool) return false
|
|
150
|
+
if (normalizedEntry === normalizedTool) return true
|
|
151
|
+
if (!CONCRETE_TOOL_TO_SESSION_TOOLS.has(normalizedEntry)) {
|
|
152
|
+
return normalizeName(canonicalizeExtensionId(normalizedEntry)) === normalizedTool
|
|
153
|
+
}
|
|
154
|
+
return false
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function matchesConcreteToolSetting(configuredNames: Set<string>, concreteToolName: string): boolean {
|
|
158
|
+
const normalizedName = normalizeName(concreteToolName)
|
|
159
|
+
if (!normalizedName || configuredNames.size === 0) return false
|
|
160
|
+
if (configuredNames.has(normalizedName)) return true
|
|
161
|
+
for (const sessionTool of CONCRETE_TOOL_TO_SESSION_TOOLS.get(normalizedName) || []) {
|
|
162
|
+
for (const entry of configuredNames) {
|
|
163
|
+
if (entryMatchesSessionTool(entry, sessionTool)) return true
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return false
|
|
167
|
+
}
|
|
168
|
+
|
|
121
169
|
function getSettingsList(settings: Record<string, unknown>, key: string): string[] {
|
|
122
170
|
return normalizeList(settings[key])
|
|
123
171
|
}
|
|
@@ -138,29 +186,11 @@ function modeBlocksTool(mode: CapabilityPolicyMode, toolName: string, descriptor
|
|
|
138
186
|
}
|
|
139
187
|
|
|
140
188
|
function safetyMatchesTool(safetyBlocked: Set<string>, toolName: string, descriptor?: ToolDescriptor): boolean {
|
|
141
|
-
|
|
142
|
-
if (!descriptor) return false
|
|
143
|
-
for (const concreteName of descriptor.concreteTools) {
|
|
144
|
-
if (safetyBlocked.has(concreteName)) return true
|
|
145
|
-
}
|
|
146
|
-
if (toolName === 'memory' && safetyBlocked.has('memory_tool')) return true
|
|
147
|
-
if (toolName === 'manage_connectors' && safetyBlocked.has('connector_message_tool')) return true
|
|
148
|
-
if (toolName === 'manage_sessions' && (
|
|
149
|
-
safetyBlocked.has('sessions_tool')
|
|
150
|
-
|| safetyBlocked.has('search_history_tool')
|
|
151
|
-
|| safetyBlocked.has('whoami_tool')
|
|
152
|
-
)) return true
|
|
153
|
-
if (toolName === 'claude_code' && safetyBlocked.has('delegate_to_claude_code')) return true
|
|
154
|
-
if (toolName === 'codex_cli' && safetyBlocked.has('delegate_to_codex_cli')) return true
|
|
155
|
-
if (toolName === 'opencode_cli' && safetyBlocked.has('delegate_to_opencode_cli')) return true
|
|
156
|
-
if (toolName === 'gemini_cli' && safetyBlocked.has('delegate_to_gemini_cli')) return true
|
|
157
|
-
return false
|
|
189
|
+
return collectRequestedExtensionNames(toolName, descriptor).some((name) => safetyBlocked.has(name))
|
|
158
190
|
}
|
|
159
191
|
|
|
160
192
|
function policyMatchesTool(blockedNames: Set<string>, toolName: string, descriptor?: ToolDescriptor): boolean {
|
|
161
|
-
|
|
162
|
-
if (!descriptor) return false
|
|
163
|
-
return descriptor.concreteTools.some((concreteName) => blockedNames.has(concreteName))
|
|
193
|
+
return collectRequestedExtensionNames(toolName, descriptor).some((name) => blockedNames.has(name))
|
|
164
194
|
}
|
|
165
195
|
|
|
166
196
|
function categoryBlockReason(blockedCategories: Set<string>, descriptor?: ToolDescriptor): string | null {
|
|
@@ -232,7 +262,7 @@ export function resolveSessionToolPolicy(
|
|
|
232
262
|
const blockedExtensions: CapabilityPolicyBlock[] = []
|
|
233
263
|
|
|
234
264
|
for (const extensionName of requestedExtensions) {
|
|
235
|
-
const descriptor =
|
|
265
|
+
const descriptor = getDescriptor(extensionName)
|
|
236
266
|
const settingsReason = settingsBlockReason(extensionName, normalizedSettings)
|
|
237
267
|
|
|
238
268
|
if (settingsReason) {
|
|
@@ -296,24 +326,19 @@ export function resolveConcreteToolPolicyBlock(
|
|
|
296
326
|
|
|
297
327
|
if (settingsReason) return settingsReason
|
|
298
328
|
|
|
299
|
-
if (safetyBlocked.has(name)) return 'blocked by safety policy'
|
|
300
|
-
|
|
301
329
|
const mappedTools = CONCRETE_TOOL_TO_SESSION_TOOLS.get(name) || []
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const policyBlockedFamily = mappedTools.find((tool) => policyBlockedNames.has(tool) && !policyAllowedNames.has(tool))
|
|
307
|
-
if (policyBlockedFamily) {
|
|
308
|
-
return `blocked because "${policyBlockedFamily}" is policy-blocked`
|
|
330
|
+
if (matchesConcreteToolSetting(safetyBlocked, name)) return 'blocked by safety policy'
|
|
331
|
+
const explicitlyAllowed = matchesConcreteToolSetting(policyAllowedNames, name)
|
|
332
|
+
if (matchesConcreteToolSetting(policyBlockedNames, name) && !explicitlyAllowed) {
|
|
333
|
+
return 'blocked by explicit policy rule'
|
|
309
334
|
}
|
|
310
335
|
|
|
311
336
|
if (mappedTools.length > 0) {
|
|
312
|
-
const enabledRoot = mappedTools.find((tool) => decision.enabledExtensions.
|
|
337
|
+
const enabledRoot = mappedTools.find((tool) => decision.enabledExtensions.some((entry) => entryMatchesSessionTool(entry, tool)))
|
|
313
338
|
if (enabledRoot) return null
|
|
314
339
|
|
|
315
340
|
const blockedRoot = mappedTools
|
|
316
|
-
.map((tool) => decision.blockedExtensions.find((entry) => entry.tool
|
|
341
|
+
.map((tool) => decision.blockedExtensions.find((entry) => entryMatchesSessionTool(entry.tool, tool)))
|
|
317
342
|
.find(Boolean)
|
|
318
343
|
if (blockedRoot) return blockedRoot.reason
|
|
319
344
|
|
|
@@ -13,8 +13,6 @@ export const TOOL_CAPABILITY = {
|
|
|
13
13
|
deliveryMessage: 'delivery.message',
|
|
14
14
|
deliveryMedia: 'delivery.media',
|
|
15
15
|
deliveryVoiceNote: 'delivery.voice_note',
|
|
16
|
-
walletInspect: 'wallet.inspect',
|
|
17
|
-
walletExecute: 'wallet.execute',
|
|
18
16
|
} as const
|
|
19
17
|
|
|
20
18
|
export interface ToolPlanningEntry {
|
|
@@ -58,6 +56,17 @@ const CORE_TOOL_PLANNING: Record<string, LegacyToolPlanningEntry[]> = {
|
|
|
58
56
|
requestMatchers: [],
|
|
59
57
|
},
|
|
60
58
|
],
|
|
59
|
+
execute: [
|
|
60
|
+
{
|
|
61
|
+
toolName: 'execute',
|
|
62
|
+
capabilities: ['runtime.execute'],
|
|
63
|
+
disciplineGuidance: [
|
|
64
|
+
'For `execute`, pass the full bash script in `{"code":"..."}`. Use it for sandboxed command execution, curl-based fetches, and one-shot scripts.',
|
|
65
|
+
'Use `persistent=true` only when the agent is explicitly configured for host execution. Otherwise use `files` for persistent writes.',
|
|
66
|
+
],
|
|
67
|
+
requestMatchers: [],
|
|
68
|
+
},
|
|
69
|
+
],
|
|
61
70
|
web: [
|
|
62
71
|
{
|
|
63
72
|
toolName: 'web_search',
|
|
@@ -362,16 +371,6 @@ const CORE_TOOL_PLANNING: Record<string, LegacyToolPlanningEntry[]> = {
|
|
|
362
371
|
requestMatchers: [],
|
|
363
372
|
},
|
|
364
373
|
],
|
|
365
|
-
wallet: [
|
|
366
|
-
{
|
|
367
|
-
toolName: 'wallet_tool',
|
|
368
|
-
capabilities: [TOOL_CAPABILITY.walletInspect, TOOL_CAPABILITY.walletExecute],
|
|
369
|
-
disciplineGuidance: [
|
|
370
|
-
'Inspect wallet state once, then act. Use `simulate_transaction` to validate before executing. Do not re-inspect balances between each operation unless the operation changes them.',
|
|
371
|
-
],
|
|
372
|
-
requestMatchers: [],
|
|
373
|
-
},
|
|
374
|
-
],
|
|
375
374
|
image_gen: [
|
|
376
375
|
{
|
|
377
376
|
toolName: 'generate_image',
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { encryptKey, decryptKey } from '@/lib/server/storage'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate a new Ethereum wallet (Base L2 compatible) with an encrypted private key.
|
|
5
|
+
* Uses ethers v6 for keypair generation and the existing AES-256-GCM encryption
|
|
6
|
+
* from storage.ts (CREDENTIAL_SECRET env var).
|
|
7
|
+
*/
|
|
8
|
+
export async function generateEthereumWallet(): Promise<{ address: string; encryptedPrivateKey: string }> {
|
|
9
|
+
const { Wallet } = await import('ethers')
|
|
10
|
+
const wallet = Wallet.createRandom()
|
|
11
|
+
const encryptedPrivateKey = encryptKey(wallet.privateKey)
|
|
12
|
+
return {
|
|
13
|
+
address: wallet.address,
|
|
14
|
+
encryptedPrivateKey,
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function normalizeEthereumAddress(address: string): Promise<string | null> {
|
|
19
|
+
const { getAddress } = await import('ethers')
|
|
20
|
+
try {
|
|
21
|
+
return getAddress(address.trim())
|
|
22
|
+
} catch {
|
|
23
|
+
return null
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Decrypt a wallet's private key for server-side use only.
|
|
29
|
+
* Never expose the result to API responses or the frontend.
|
|
30
|
+
*/
|
|
31
|
+
export function decryptWalletPrivateKey(encrypted: string): string {
|
|
32
|
+
return decryptKey(encrypted)
|
|
33
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadWallets as loadWalletsStore,
|
|
3
|
+
saveWallets as saveWalletsStore,
|
|
4
|
+
loadWallet as loadWalletItem,
|
|
5
|
+
upsertWallet,
|
|
6
|
+
deleteWalletItem,
|
|
7
|
+
} from '@/lib/server/storage'
|
|
8
|
+
import type { AgentWallet } from '@/types/swarmdock'
|
|
9
|
+
|
|
10
|
+
export function loadWallets(): Record<string, AgentWallet> {
|
|
11
|
+
return loadWalletsStore() as Record<string, AgentWallet>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function loadWallet(id: string): AgentWallet | null {
|
|
15
|
+
return loadWalletItem(id) as AgentWallet | null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function saveWallet(id: string, wallet: AgentWallet): void {
|
|
19
|
+
upsertWallet(id, wallet)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function deleteWallet(id: string): void {
|
|
23
|
+
deleteWalletItem(id)
|
|
24
|
+
}
|