@swarmclawai/swarmclaw 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/README.md +14 -0
  2. package/bin/daemon-cmd.js +169 -0
  3. package/bin/server-cmd.js +3 -0
  4. package/bin/swarmclaw.js +11 -0
  5. package/package.json +17 -16
  6. package/src/app/api/agents/[id]/clone/route.ts +3 -32
  7. package/src/app/api/agents/[id]/route.ts +6 -158
  8. package/src/app/api/agents/[id]/status/route.ts +2 -3
  9. package/src/app/api/agents/[id]/thread/route.ts +4 -17
  10. package/src/app/api/agents/bulk/route.ts +5 -47
  11. package/src/app/api/agents/route.ts +5 -119
  12. package/src/app/api/agents/trash/route.ts +13 -24
  13. package/src/app/api/auth/route.ts +3 -9
  14. package/src/app/api/autonomy/estop/route.ts +5 -5
  15. package/src/app/api/chatrooms/[id]/chat/route.ts +11 -5
  16. package/src/app/api/chatrooms/[id]/route.ts +23 -2
  17. package/src/app/api/chatrooms/route.ts +13 -2
  18. package/src/app/api/chats/[id]/clear/route.ts +2 -13
  19. package/src/app/api/chats/[id]/deploy/route.ts +2 -3
  20. package/src/app/api/chats/[id]/edit-resend/route.ts +7 -13
  21. package/src/app/api/chats/[id]/mailbox/route.ts +6 -8
  22. package/src/app/api/chats/[id]/queue/route.ts +17 -64
  23. package/src/app/api/chats/[id]/retry/route.ts +4 -22
  24. package/src/app/api/chats/[id]/route.ts +10 -138
  25. package/src/app/api/chats/heartbeat/route.ts +2 -1
  26. package/src/app/api/chats/migrate-messages/route.ts +7 -0
  27. package/src/app/api/chats/route.ts +13 -134
  28. package/src/app/api/connectors/[id]/access/route.ts +12 -229
  29. package/src/app/api/connectors/[id]/doctor/route.ts +1 -1
  30. package/src/app/api/connectors/[id]/health/route.ts +12 -39
  31. package/src/app/api/connectors/[id]/route.ts +14 -122
  32. package/src/app/api/connectors/[id]/webhook/route.ts +1 -1
  33. package/src/app/api/connectors/doctor/route.ts +1 -1
  34. package/src/app/api/connectors/route.ts +12 -70
  35. package/src/app/api/credentials/[id]/route.ts +2 -4
  36. package/src/app/api/credentials/route.ts +10 -19
  37. package/src/app/api/daemon/health-check/route.ts +3 -4
  38. package/src/app/api/daemon/route.ts +10 -8
  39. package/src/app/api/documents/route.ts +11 -10
  40. package/src/app/api/external-agents/route.ts +3 -3
  41. package/src/app/api/gateways/[id]/health/route.ts +2 -3
  42. package/src/app/api/gateways/[id]/route.ts +7 -122
  43. package/src/app/api/gateways/route.ts +3 -103
  44. package/src/app/api/mcp-servers/[id]/tools/route.ts +5 -5
  45. package/src/app/api/openclaw/dashboard-url/route.ts +8 -16
  46. package/src/app/api/openclaw/directory/route.ts +2 -2
  47. package/src/app/api/openclaw/history/route.ts +3 -5
  48. package/src/app/api/providers/[id]/route.test.ts +49 -0
  49. package/src/app/api/providers/ollama/route.ts +6 -5
  50. package/src/app/api/schedules/[id]/route.ts +14 -108
  51. package/src/app/api/schedules/[id]/run/route.ts +6 -67
  52. package/src/app/api/schedules/route.ts +9 -51
  53. package/src/app/api/settings/route.ts +4 -3
  54. package/src/app/api/setup/check-provider/route.ts +23 -1
  55. package/src/app/api/setup/openclaw-device/route.ts +2 -2
  56. package/src/app/api/system/status/route.ts +2 -2
  57. package/src/app/api/tasks/[id]/route.ts +16 -202
  58. package/src/app/api/tasks/bulk/route.ts +5 -86
  59. package/src/app/api/tasks/metrics/route.ts +2 -1
  60. package/src/app/api/tasks/route.ts +11 -171
  61. package/src/app/api/upload/route.ts +1 -1
  62. package/src/app/api/uploads/[filename]/route.ts +1 -1
  63. package/src/app/api/uploads/route.ts +1 -1
  64. package/src/app/api/webhooks/[id]/history/route.ts +2 -2
  65. package/src/app/layout.tsx +9 -6
  66. package/src/app/protocols/page.tsx +71 -89
  67. package/src/app/tasks/page.tsx +32 -32
  68. package/src/cli/index.js +1 -0
  69. package/src/cli/spec.js +1 -0
  70. package/src/components/agents/agent-sheet.tsx +5 -5
  71. package/src/components/auth/setup-wizard/index.tsx +4 -4
  72. package/src/components/auth/setup-wizard/step-agents.tsx +1 -1
  73. package/src/components/auth/setup-wizard/step-connect.tsx +1 -1
  74. package/src/components/auth/setup-wizard/utils.ts +1 -1
  75. package/src/components/chatrooms/chatroom-sheet.tsx +16 -276
  76. package/src/components/connectors/connector-list.tsx +26 -40
  77. package/src/components/connectors/connector-sheet.tsx +95 -149
  78. package/src/components/gateways/gateway-sheet.tsx +61 -110
  79. package/src/components/layout/live-query-sync.tsx +121 -0
  80. package/src/components/protocols/structured-session-launcher.tsx +24 -45
  81. package/src/components/providers/app-query-provider.tsx +17 -0
  82. package/src/components/providers/provider-list.tsx +60 -61
  83. package/src/components/providers/provider-sheet.tsx +74 -56
  84. package/src/components/skills/skill-list.tsx +5 -18
  85. package/src/components/skills/skill-sheet.tsx +21 -20
  86. package/src/components/skills/skills-workspace.tsx +48 -87
  87. package/src/components/tasks/task-card.tsx +20 -13
  88. package/src/components/tasks/task-column.tsx +22 -7
  89. package/src/components/tasks/task-list.tsx +8 -11
  90. package/src/components/tasks/task-sheet.tsx +111 -103
  91. package/src/features/agents/queries.ts +20 -0
  92. package/src/features/chatrooms/queries.ts +20 -0
  93. package/src/features/chats/queries.ts +27 -0
  94. package/src/features/connectors/queries.ts +145 -0
  95. package/src/features/credentials/queries.ts +37 -0
  96. package/src/features/extensions/queries.ts +26 -0
  97. package/src/features/external-agents/queries.ts +36 -0
  98. package/src/features/gateways/queries.ts +274 -0
  99. package/src/features/missions/queries.ts +23 -0
  100. package/src/features/projects/queries.ts +20 -0
  101. package/src/features/protocols/queries.ts +149 -0
  102. package/src/features/providers/queries.ts +142 -0
  103. package/src/features/settings/queries.ts +20 -0
  104. package/src/features/skills/queries.ts +182 -0
  105. package/src/features/tasks/queries.ts +189 -0
  106. package/src/hooks/use-ws.ts +3 -2
  107. package/src/lib/app/api-client.ts +2 -2
  108. package/src/lib/providers/index.test.ts +108 -0
  109. package/src/lib/providers/index.ts +38 -15
  110. package/src/lib/query/client.ts +17 -0
  111. package/src/lib/server/agents/agent-runtime-config.ts +1 -1
  112. package/src/lib/server/agents/agent-service.ts +429 -0
  113. package/src/lib/server/agents/agent-thread-session.ts +6 -5
  114. package/src/lib/server/agents/autonomy-contract.ts +1 -4
  115. package/src/lib/server/agents/delegation-advisory.test.ts +206 -0
  116. package/src/lib/server/agents/delegation-advisory.ts +251 -0
  117. package/src/lib/server/agents/main-agent-loop.ts +98 -40
  118. package/src/lib/server/agents/subagent-runtime.ts +12 -0
  119. package/src/lib/server/autonomy/supervisor-reflection.test.ts +20 -1
  120. package/src/lib/server/autonomy/supervisor-reflection.ts +39 -19
  121. package/src/lib/server/build-llm.ts +7 -15
  122. package/src/lib/server/capability-router.test.ts +70 -1
  123. package/src/lib/server/capability-router.ts +24 -99
  124. package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -15
  125. package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -4
  126. package/src/lib/server/chat-execution/chat-turn-finalization.ts +77 -12
  127. package/src/lib/server/chat-execution/chat-turn-partial-persistence.ts +4 -4
  128. package/src/lib/server/chat-execution/chat-turn-preflight.ts +2 -2
  129. package/src/lib/server/chat-execution/chat-turn-preparation.ts +41 -17
  130. package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -2
  131. package/src/lib/server/chat-execution/chat-turn-tool-routing.test.ts +45 -0
  132. package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +48 -17
  133. package/src/lib/server/chat-execution/continuation-evaluator.ts +4 -1
  134. package/src/lib/server/chat-execution/direct-memory-intent.test.ts +9 -0
  135. package/src/lib/server/chat-execution/direct-memory-intent.ts +12 -2
  136. package/src/lib/server/chat-execution/message-classifier.test.ts +35 -23
  137. package/src/lib/server/chat-execution/message-classifier.ts +74 -32
  138. package/src/lib/server/chat-execution/prompt-builder.test.ts +29 -0
  139. package/src/lib/server/chat-execution/prompt-builder.ts +37 -2
  140. package/src/lib/server/chat-execution/prompt-sections.test.ts +56 -0
  141. package/src/lib/server/chat-execution/prompt-sections.ts +193 -0
  142. package/src/lib/server/chat-execution/stream-agent-chat.ts +63 -7
  143. package/src/lib/server/chat-execution/stream-continuation.test.ts +36 -0
  144. package/src/lib/server/chat-execution/stream-continuation.ts +28 -13
  145. package/src/lib/server/chatrooms/chatroom-agent-signals.ts +26 -18
  146. package/src/lib/server/chatrooms/chatroom-helpers.ts +19 -18
  147. package/src/lib/server/chatrooms/chatroom-repository.ts +16 -0
  148. package/src/lib/server/chatrooms/chatroom-routing.test.ts +96 -0
  149. package/src/lib/server/chatrooms/chatroom-routing.ts +207 -53
  150. package/src/lib/server/chatrooms/mailbox-utils.ts +4 -2
  151. package/src/lib/server/chatrooms/session-mailbox.ts +50 -40
  152. package/src/lib/server/chats/chat-session-service.ts +410 -0
  153. package/src/lib/server/connectors/access.ts +1 -1
  154. package/src/lib/server/connectors/commands.ts +7 -6
  155. package/src/lib/server/connectors/connector-inbound.ts +14 -7
  156. package/src/lib/server/connectors/connector-outbound.ts +16 -11
  157. package/src/lib/server/connectors/connector-service.ts +453 -0
  158. package/src/lib/server/connectors/delivery.ts +17 -12
  159. package/src/lib/server/connectors/inbound-audio-transcription.ts +5 -14
  160. package/src/lib/server/connectors/media.ts +1 -1
  161. package/src/lib/server/connectors/response-media.ts +1 -1
  162. package/src/lib/server/connectors/session-consolidation.ts +11 -7
  163. package/src/lib/server/connectors/session.ts +9 -7
  164. package/src/lib/server/connectors/voice-note.ts +2 -1
  165. package/src/lib/server/context-manager.ts +20 -1
  166. package/src/lib/server/cost.ts +2 -3
  167. package/src/lib/server/credentials/credential-repository.ts +43 -4
  168. package/src/lib/server/credentials/credential-service.ts +112 -0
  169. package/src/lib/server/daemon/admin-metadata.ts +64 -0
  170. package/src/lib/server/daemon/controller.ts +577 -0
  171. package/src/lib/server/daemon/daemon-runtime.ts +352 -0
  172. package/src/lib/server/daemon/daemon-status-repository.ts +63 -0
  173. package/src/lib/server/daemon/types.ts +101 -0
  174. package/src/lib/server/embeddings.ts +3 -9
  175. package/src/lib/server/eval/agent-regression.ts +3 -2
  176. package/src/lib/server/eval/runner.ts +2 -2
  177. package/src/lib/server/execution-brief.test.ts +167 -0
  178. package/src/lib/server/execution-brief.ts +295 -0
  179. package/src/lib/server/execution-engine/chat-turn.ts +9 -0
  180. package/src/lib/server/execution-engine/import-boundary.test.ts +44 -0
  181. package/src/lib/server/execution-engine/index.ts +35 -0
  182. package/src/lib/server/execution-engine/task-attempt.ts +303 -0
  183. package/src/lib/server/execution-engine/types.ts +33 -0
  184. package/src/lib/server/gateways/gateway-profile-repository.ts +47 -3
  185. package/src/lib/server/gateways/gateway-profile-service.ts +200 -0
  186. package/src/lib/server/memory/session-archive-memory.ts +12 -10
  187. package/src/lib/server/messages/message-repository.ts +330 -0
  188. package/src/lib/server/missions/mission-service/core.ts +8 -6
  189. package/src/lib/server/openclaw/agent-resolver.ts +2 -3
  190. package/src/lib/server/openclaw/doctor.ts +1 -1
  191. package/src/lib/server/openclaw/gateway.test.ts +10 -1
  192. package/src/lib/server/openclaw/gateway.ts +5 -14
  193. package/src/lib/server/openclaw/health.ts +3 -11
  194. package/src/lib/server/openclaw/sync.ts +8 -6
  195. package/src/lib/server/persistence/storage-context.ts +3 -0
  196. package/src/lib/server/protocols/protocol-agent-turn.ts +25 -17
  197. package/src/lib/server/protocols/protocol-normalization.ts +1 -1
  198. package/src/lib/server/protocols/protocol-queries.ts +13 -7
  199. package/src/lib/server/protocols/protocol-run-lifecycle.ts +16 -20
  200. package/src/lib/server/protocols/protocol-run-repository.ts +81 -0
  201. package/src/lib/server/protocols/protocol-step-processors.ts +23 -31
  202. package/src/lib/server/protocols/protocol-swarm.ts +8 -8
  203. package/src/lib/server/protocols/protocol-template-repository.ts +42 -0
  204. package/src/lib/server/protocols/protocol-templates.ts +4 -2
  205. package/src/lib/server/protocols/protocol-types.ts +10 -7
  206. package/src/lib/server/provider-endpoint.ts +7 -12
  207. package/src/lib/server/provider-model-discovery.ts +2 -11
  208. package/src/lib/server/query-expansion.ts +5 -6
  209. package/src/lib/server/run-context.test.ts +365 -0
  210. package/src/lib/server/run-context.ts +367 -0
  211. package/src/lib/server/runtime/heartbeat-service.ts +7 -5
  212. package/src/lib/server/runtime/queue/core.ts +61 -190
  213. package/src/lib/server/runtime/run-ledger.ts +8 -0
  214. package/src/lib/server/runtime/session-run-manager/drain.ts +2 -2
  215. package/src/lib/server/runtime/session-run-manager/enqueue.ts +6 -0
  216. package/src/lib/server/runtime/session-run-manager/state.ts +4 -0
  217. package/src/lib/server/schedules/schedule-route-service.ts +230 -0
  218. package/src/lib/server/service-result.ts +16 -0
  219. package/src/lib/server/session-note.ts +2 -3
  220. package/src/lib/server/session-reset-policy.ts +4 -3
  221. package/src/lib/server/session-tools/connector.ts +9 -6
  222. package/src/lib/server/session-tools/context-mgmt.ts +58 -9
  223. package/src/lib/server/session-tools/crud.ts +162 -10
  224. package/src/lib/server/session-tools/delegate.ts +1 -1
  225. package/src/lib/server/session-tools/manage-tasks.test.ts +152 -0
  226. package/src/lib/server/session-tools/memory.ts +6 -4
  227. package/src/lib/server/session-tools/session-info.test.ts +56 -0
  228. package/src/lib/server/session-tools/session-info.ts +119 -12
  229. package/src/lib/server/session-tools/skill-runtime.ts +3 -1
  230. package/src/lib/server/session-tools/skills.ts +15 -15
  231. package/src/lib/server/session-tools/subagent.test.ts +115 -1
  232. package/src/lib/server/session-tools/subagent.ts +125 -7
  233. package/src/lib/server/session-tools/team-context.ts +4 -3
  234. package/src/lib/server/session-tools/wallet.ts +0 -58
  235. package/src/lib/server/sessions/session-lineage.ts +55 -0
  236. package/src/lib/server/sessions/session-repository.ts +2 -2
  237. package/src/lib/server/skills/learned-skills.ts +24 -23
  238. package/src/lib/server/skills/runtime-skill-resolver.ts +2 -1
  239. package/src/lib/server/skills/skill-repository.ts +136 -13
  240. package/src/lib/server/skills/skill-suggestions.ts +25 -28
  241. package/src/lib/server/storage-normalization.test.ts +44 -267
  242. package/src/lib/server/storage-normalization.ts +75 -0
  243. package/src/lib/server/storage.ts +19 -0
  244. package/src/lib/server/structured-extract.ts +3 -14
  245. package/src/lib/server/tasks/task-followups.ts +16 -11
  246. package/src/lib/server/tasks/task-result.test.ts +25 -29
  247. package/src/lib/server/tasks/task-result.ts +5 -9
  248. package/src/lib/server/tasks/task-route-service.ts +449 -0
  249. package/src/lib/server/text-normalization.ts +41 -0
  250. package/src/lib/server/tool-planning.ts +6 -42
  251. package/src/lib/server/upload-path.ts +5 -0
  252. package/src/lib/server/working-state/extraction.ts +614 -0
  253. package/src/lib/server/working-state/normalization.ts +866 -0
  254. package/src/lib/server/working-state/prompt.ts +60 -0
  255. package/src/lib/server/working-state/repository.ts +38 -0
  256. package/src/lib/server/working-state/service.test.ts +253 -0
  257. package/src/lib/server/working-state/service.ts +293 -0
  258. package/src/lib/validation/schemas.ts +1 -0
  259. package/src/lib/ws-client.ts +3 -3
  260. package/src/stores/slices/task-slice.ts +1 -4
  261. package/src/stores/use-chatroom-store.ts +2 -2
  262. package/src/types/index.ts +277 -12
@@ -1,5 +1,7 @@
1
- import type { Message } from '@/types'
1
+ import type { Message, Session } from '@/types'
2
2
  import { getMemoryDb } from '@/lib/server/memory/memory-db'
3
+ import { extractFactsFromMessages, ensureRunContext, pruneRunContext } from '@/lib/server/run-context'
4
+ import { getSession, saveSession } from '@/lib/server/sessions/session-repository'
3
5
 
4
6
  import { repairTranscriptConsistency } from './transcript-repair'
5
7
 
@@ -549,6 +551,23 @@ export async function llmCompact(opts: {
549
551
  const oldMessages = repaired.slice(0, -keepLastN)
550
552
  const recentMessages = repaired.slice(-keepLastN)
551
553
 
554
+ // 0. Extract facts from messages about to be dropped into RunContext (non-critical)
555
+ try {
556
+ const session = getSession(sessionId) as Session | undefined
557
+ if (session && oldMessages.length > 0) {
558
+ const extracted = extractFactsFromMessages(oldMessages)
559
+ if (extracted.keyFacts.length > 0 || extracted.failedApproaches.length > 0) {
560
+ const ctx = ensureRunContext(session.runContext)
561
+ ctx.keyFacts = [...ctx.keyFacts, ...extracted.keyFacts]
562
+ ctx.failedApproaches = [...ctx.failedApproaches, ...extracted.failedApproaches]
563
+ ctx.version++
564
+ ctx.updatedAt = Date.now()
565
+ session.runContext = pruneRunContext(ctx)
566
+ saveSession(sessionId, session)
567
+ }
568
+ }
569
+ } catch { /* non-critical — compaction continues even if extraction fails */ }
570
+
552
571
  // 1. Consolidate important info to memory
553
572
  const memoriesStored = consolidateToMemory(oldMessages, agentId, sessionId)
554
573
 
@@ -1,4 +1,4 @@
1
- import type { Agent, UsageRecord, ExtensionDefinitionCost } from '@/types'
1
+ import type { Agent, Session, UsageRecord, ExtensionDefinitionCost } from '@/types'
2
2
  import type { StructuredToolInterface } from '@langchain/core/tools'
3
3
  import { loadSessions, loadUsage } from './storage'
4
4
 
@@ -26,8 +26,7 @@ const MODEL_COSTS: Record<string, [number, number]> = {
26
26
  const ONE_HOUR_MS = 60 * 60 * 1000
27
27
  const WARNING_RATIO = 0.8
28
28
 
29
- type GenericRecord = Record<string, unknown>
30
- type SessionsMap = Record<string, GenericRecord>
29
+ type SessionsMap = Record<string, Session | Record<string, unknown>>
31
30
  type UsageMap = Record<string, unknown>
32
31
 
33
32
  function parsePositiveBudget(value: unknown): number | null {
@@ -1,7 +1,46 @@
1
- export {
1
+ import type { Credential } from '@/types'
2
+
3
+ import {
2
4
  decryptKey,
3
- deleteCredential,
5
+ deleteCredential as deleteStoredCredential,
4
6
  encryptKey,
5
- loadCredentials,
6
- saveCredentials,
7
+ loadCredentials as loadStoredCredentials,
8
+ saveCredentials as saveStoredCredentials,
9
+ upsertStoredItem,
7
10
  } from '@/lib/server/storage'
11
+ import { createRecordRepository } from '@/lib/server/persistence/repository-utils'
12
+
13
+ export type StoredCredential = Credential & {
14
+ encryptedKey?: string | null
15
+ updatedAt?: number
16
+ [key: string]: unknown
17
+ }
18
+
19
+ export const credentialRepository = createRecordRepository<StoredCredential>(
20
+ 'credentials',
21
+ {
22
+ get(id) {
23
+ return (loadStoredCredentials() as Record<string, StoredCredential>)[id] || null
24
+ },
25
+ list() {
26
+ return loadStoredCredentials() as Record<string, StoredCredential>
27
+ },
28
+ upsert(id, value) {
29
+ upsertStoredItem('credentials', id, value)
30
+ },
31
+ replace(data) {
32
+ saveStoredCredentials(data)
33
+ },
34
+ delete(id) {
35
+ deleteStoredCredential(id)
36
+ },
37
+ },
38
+ )
39
+
40
+ export const loadCredentials = () => credentialRepository.list()
41
+ export const loadCredential = (id: string) => credentialRepository.get(id)
42
+ export const saveCredentials = (items: Record<string, StoredCredential | Record<string, unknown>>) => credentialRepository.replace(items as Record<string, StoredCredential>)
43
+ export const saveCredential = (id: string, value: StoredCredential | Record<string, unknown>) => credentialRepository.upsert(id, value as StoredCredential)
44
+ export const deleteCredential = (id: string) => credentialRepository.delete(id)
45
+
46
+ export { decryptKey, encryptKey }
@@ -0,0 +1,112 @@
1
+ import type { Credential } from '@/types'
2
+
3
+ import { genId } from '@/lib/id'
4
+ import {
5
+ deleteCredential,
6
+ decryptKey,
7
+ encryptKey,
8
+ loadCredential,
9
+ loadCredentials,
10
+ saveCredential,
11
+ } from '@/lib/server/credentials/credential-repository'
12
+
13
+ export type CredentialSummary = Pick<Credential, 'id' | 'provider' | 'name' | 'createdAt'>
14
+
15
+ function clean(value: string | null | undefined): string {
16
+ return typeof value === 'string' ? value.trim() : ''
17
+ }
18
+
19
+ function toCredentialSummary(credential: Credential | null | undefined): CredentialSummary | null {
20
+ if (!credential) return null
21
+ return {
22
+ id: credential.id,
23
+ provider: credential.provider,
24
+ name: credential.name,
25
+ createdAt: credential.createdAt,
26
+ }
27
+ }
28
+
29
+ export function listCredentialSummaries(): Record<string, CredentialSummary> {
30
+ const credentials = loadCredentials()
31
+ const summaries: Record<string, CredentialSummary> = {}
32
+ for (const [id, credential] of Object.entries(credentials)) {
33
+ const summary = toCredentialSummary(credential)
34
+ if (summary) summaries[id] = summary
35
+ }
36
+ return summaries
37
+ }
38
+
39
+ export function getCredentialSummary(id: string): CredentialSummary | null {
40
+ return toCredentialSummary(loadCredential(id))
41
+ }
42
+
43
+ export function listCredentialIdsByProvider(provider: string): string[] {
44
+ const normalizedProvider = clean(provider)
45
+ if (!normalizedProvider) return []
46
+ return Object.entries(loadCredentials())
47
+ .filter(([, credential]) => credential?.provider === normalizedProvider)
48
+ .map(([id]) => id)
49
+ }
50
+
51
+ export function resolveCredentialSecret(credentialId: string | null | undefined): string | null {
52
+ const id = clean(credentialId)
53
+ if (!id) return null
54
+ const credential = loadCredential(id)
55
+ if (!credential?.encryptedKey) return null
56
+ try {
57
+ return decryptKey(credential.encryptedKey)
58
+ } catch {
59
+ return null
60
+ }
61
+ }
62
+
63
+ export function requireCredentialSecret(
64
+ credentialId: string | null | undefined,
65
+ missingMessage = 'Credential secret not found.',
66
+ ): string {
67
+ const id = clean(credentialId)
68
+ if (!id) throw new Error(missingMessage)
69
+ const credential = loadCredential(id)
70
+ if (!credential?.encryptedKey) throw new Error(missingMessage)
71
+ try {
72
+ return decryptKey(credential.encryptedKey)
73
+ } catch {
74
+ throw new Error(missingMessage)
75
+ }
76
+ }
77
+
78
+ export function createCredentialRecord(input: {
79
+ provider: string
80
+ name?: string | null
81
+ apiKey: string
82
+ }): CredentialSummary {
83
+ const provider = clean(input.provider)
84
+ const apiKey = clean(input.apiKey)
85
+ if (!provider || !apiKey) {
86
+ throw new Error('provider and apiKey are required')
87
+ }
88
+ const id = `cred_${genId(6)}`
89
+ const createdAt = Date.now()
90
+ const credentialName = clean(input.name) || `${provider} key`
91
+ saveCredential(id, {
92
+ id,
93
+ provider,
94
+ name: credentialName,
95
+ encryptedKey: encryptKey(apiKey),
96
+ createdAt,
97
+ })
98
+ return {
99
+ id,
100
+ provider,
101
+ name: credentialName,
102
+ createdAt,
103
+ }
104
+ }
105
+
106
+ export function deleteCredentialRecord(id: string): boolean {
107
+ const credentialId = clean(id)
108
+ if (!credentialId) return false
109
+ if (!loadCredential(credentialId)) return false
110
+ deleteCredential(credentialId)
111
+ return true
112
+ }
@@ -0,0 +1,64 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+
4
+ import { DATA_DIR } from '@/lib/server/data-dir'
5
+ import type { DaemonAdminMetadata } from '@/lib/server/daemon/types'
6
+
7
+ function resolveHomeDir(): string {
8
+ const configured = process.env.SWARMCLAW_HOME?.trim()
9
+ if (configured) return path.resolve(configured)
10
+ return path.dirname(DATA_DIR)
11
+ }
12
+
13
+ export const DAEMON_ADMIN_METADATA_PATH = path.join(resolveHomeDir(), 'daemon-admin.json')
14
+ export const DAEMON_LOG_PATH = path.join(resolveHomeDir(), 'daemon.log')
15
+
16
+ export function isProcessRunning(pid: number | null | undefined): boolean {
17
+ if (typeof pid !== 'number' || !Number.isFinite(pid) || pid <= 0) return false
18
+ try {
19
+ process.kill(pid, 0)
20
+ return true
21
+ } catch {
22
+ return false
23
+ }
24
+ }
25
+
26
+ function normalizeMetadata(value: unknown): DaemonAdminMetadata | null {
27
+ if (!value || typeof value !== 'object') return null
28
+ const candidate = value as Partial<DaemonAdminMetadata>
29
+ const pid = typeof candidate.pid === 'number' && Number.isFinite(candidate.pid) ? Math.trunc(candidate.pid) : null
30
+ const port = typeof candidate.port === 'number' && Number.isFinite(candidate.port) ? Math.trunc(candidate.port) : null
31
+ const token = typeof candidate.token === 'string' ? candidate.token.trim() : ''
32
+ if (!pid || !port || !token) return null
33
+ return {
34
+ pid,
35
+ port,
36
+ token,
37
+ launchedAt: typeof candidate.launchedAt === 'number' && Number.isFinite(candidate.launchedAt)
38
+ ? Math.trunc(candidate.launchedAt)
39
+ : Date.now(),
40
+ source: typeof candidate.source === 'string' ? candidate.source : null,
41
+ }
42
+ }
43
+
44
+ export function readDaemonAdminMetadata(): DaemonAdminMetadata | null {
45
+ try {
46
+ const raw = JSON.parse(fs.readFileSync(DAEMON_ADMIN_METADATA_PATH, 'utf8'))
47
+ return normalizeMetadata(raw)
48
+ } catch {
49
+ return null
50
+ }
51
+ }
52
+
53
+ export function writeDaemonAdminMetadata(metadata: DaemonAdminMetadata): void {
54
+ fs.mkdirSync(path.dirname(DAEMON_ADMIN_METADATA_PATH), { recursive: true })
55
+ fs.writeFileSync(DAEMON_ADMIN_METADATA_PATH, `${JSON.stringify(metadata, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 })
56
+ }
57
+
58
+ export function clearDaemonAdminMetadata(): void {
59
+ try {
60
+ fs.unlinkSync(DAEMON_ADMIN_METADATA_PATH)
61
+ } catch {
62
+ // Ignore missing metadata file.
63
+ }
64
+ }