@swarmclawai/swarmclaw 1.2.8 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/README.md +39 -6
  2. package/package.json +2 -2
  3. package/src/app/agents/[id]/page.tsx +1 -18
  4. package/src/app/api/activity/route.ts +9 -23
  5. package/src/app/api/agents/route.ts +17 -1
  6. package/src/app/api/agents/thread-route.test.ts +0 -1
  7. package/src/app/api/approvals/route.test.ts +6 -22
  8. package/src/app/api/approvals/route.ts +13 -5
  9. package/src/app/api/connectors/route.ts +2 -2
  10. package/src/app/api/credentials/[id]/route.ts +2 -0
  11. package/src/app/api/credentials/route.ts +4 -1
  12. package/src/app/api/goals/[id]/route.ts +28 -0
  13. package/src/app/api/goals/route.ts +33 -0
  14. package/src/app/api/portability/export/route.ts +8 -0
  15. package/src/app/api/portability/import/route.test.ts +80 -0
  16. package/src/app/api/portability/import/route.ts +28 -0
  17. package/src/app/api/protocols/templates/[id]/route.ts +2 -1
  18. package/src/app/api/protocols/templates/route.ts +2 -1
  19. package/src/app/api/settings/route.ts +13 -2
  20. package/src/app/api/wallets/[id]/route.ts +15 -157
  21. package/src/app/api/wallets/generate/route.ts +22 -0
  22. package/src/app/api/wallets/route.test.ts +147 -0
  23. package/src/app/api/wallets/route.ts +13 -95
  24. package/src/app/autonomy/page.tsx +2 -57
  25. package/src/app/home/page.tsx +3 -0
  26. package/src/app/protocols/page.tsx +2 -21
  27. package/src/app/settings/page.tsx +0 -9
  28. package/src/app/wallets/page.tsx +105 -5
  29. package/src/cli/index.js +32 -33
  30. package/src/cli/spec.js +26 -27
  31. package/src/components/agents/agent-sheet.tsx +2 -40
  32. package/src/components/agents/inspector-panel.tsx +0 -83
  33. package/src/components/chat/chat-card.tsx +0 -31
  34. package/src/components/chat/message-bubble.tsx +1 -108
  35. package/src/components/connectors/connector-sheet.tsx +25 -1
  36. package/src/components/layout/sidebar-rail.tsx +6 -10
  37. package/src/components/projects/project-detail.tsx +3 -35
  38. package/src/components/projects/tabs/overview-tab.tsx +3 -59
  39. package/src/components/projects/tabs/work-tab.tsx +7 -77
  40. package/src/components/protocols/structured-session-launcher.tsx +1 -22
  41. package/src/components/shared/connector-platform-icon.tsx +1 -0
  42. package/src/components/tasks/task-card.tsx +4 -34
  43. package/src/components/tasks/task-sheet.tsx +6 -36
  44. package/src/components/wallets/wallet-list.tsx +150 -0
  45. package/src/lib/app/navigation.test.ts +0 -13
  46. package/src/lib/app/navigation.ts +2 -7
  47. package/src/lib/app/view-constants.ts +14 -19
  48. package/src/lib/server/activity/activity-log.ts +16 -1
  49. package/src/lib/server/agents/agent-service.ts +24 -11
  50. package/src/lib/server/agents/agent-thread-session.ts +0 -1
  51. package/src/lib/server/agents/delegation-advisory.test.ts +0 -1
  52. package/src/lib/server/agents/delegation-jobs.test.ts +0 -69
  53. package/src/lib/server/agents/delegation-jobs.ts +0 -25
  54. package/src/lib/server/agents/main-agent-loop.ts +1 -49
  55. package/src/lib/server/agents/subagent-runtime.ts +0 -1
  56. package/src/lib/server/approval-match.ts +14 -85
  57. package/src/lib/server/approvals/approval-hooks.ts +81 -0
  58. package/src/lib/server/approvals.test.ts +6 -6
  59. package/src/lib/server/approvals.ts +11 -6
  60. package/src/lib/server/autonomy/supervisor-reflection.test.ts +0 -1
  61. package/src/lib/server/builtin-extensions.ts +0 -2
  62. package/src/lib/server/capability-router.test.ts +0 -2
  63. package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +14 -14
  64. package/src/lib/server/chat-execution/chat-execution-types.ts +0 -2
  65. package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -2
  66. package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -30
  67. package/src/lib/server/chat-execution/chat-turn-finalization.ts +1 -36
  68. package/src/lib/server/chat-execution/chat-turn-preparation.ts +2 -22
  69. package/src/lib/server/chat-execution/iteration-event-handler.ts +0 -24
  70. package/src/lib/server/chat-execution/message-classifier.test.ts +0 -45
  71. package/src/lib/server/chat-execution/message-classifier.ts +1 -16
  72. package/src/lib/server/chat-execution/prompt-builder.test.ts +0 -1
  73. package/src/lib/server/chat-execution/prompt-builder.ts +0 -30
  74. package/src/lib/server/chat-execution/prompt-sections.ts +0 -1
  75. package/src/lib/server/chat-execution/situational-awareness.test.ts +2 -73
  76. package/src/lib/server/chat-execution/situational-awareness.ts +4 -38
  77. package/src/lib/server/chat-execution/stream-agent-chat.test.ts +8 -123
  78. package/src/lib/server/chat-execution/stream-agent-chat.ts +1 -5
  79. package/src/lib/server/chat-execution/stream-continuation.test.ts +4 -52
  80. package/src/lib/server/chat-execution/stream-continuation.ts +6 -48
  81. package/src/lib/server/chatrooms/session-mailbox.ts +0 -10
  82. package/src/lib/server/chats/chat-session-service.ts +3 -5
  83. package/src/lib/server/connectors/connector-inbound.ts +0 -1
  84. package/src/lib/server/connectors/connector-lifecycle.ts +19 -3
  85. package/src/lib/server/connectors/connector-service.ts +39 -9
  86. package/src/lib/server/connectors/swarmdock-bidding.ts +74 -0
  87. package/src/lib/server/connectors/swarmdock-payloads.test.ts +85 -0
  88. package/src/lib/server/connectors/swarmdock-secret.test.ts +128 -0
  89. package/src/lib/server/connectors/swarmdock-secret.ts +152 -0
  90. package/src/lib/server/connectors/swarmdock-tasks.ts +127 -0
  91. package/src/lib/server/connectors/swarmdock.ts +285 -0
  92. package/src/lib/server/execution-brief.test.ts +2 -25
  93. package/src/lib/server/execution-brief.ts +30 -35
  94. package/src/lib/server/execution-engine/task-attempt.ts +0 -1
  95. package/src/lib/server/goals/goal-repository.ts +19 -0
  96. package/src/lib/server/goals/goal-service.ts +143 -0
  97. package/src/lib/server/persistence/storage-context.ts +0 -5
  98. package/src/lib/server/portability/export.ts +109 -0
  99. package/src/lib/server/portability/import.ts +159 -0
  100. package/src/lib/server/protocols/protocol-normalization.ts +0 -4
  101. package/src/lib/server/protocols/protocol-queries.ts +0 -6
  102. package/src/lib/server/protocols/protocol-run-lifecycle.ts +4 -32
  103. package/src/lib/server/protocols/protocol-service.ts +0 -1
  104. package/src/lib/server/protocols/protocol-step-helpers.ts +0 -4
  105. package/src/lib/server/protocols/protocol-step-processors.ts +0 -6
  106. package/src/lib/server/protocols/protocol-swarm.ts +0 -2
  107. package/src/lib/server/protocols/protocol-types.ts +0 -2
  108. package/src/lib/server/provider-health.ts +0 -9
  109. package/src/lib/server/runtime/daemon-state/core.ts +0 -9
  110. package/src/lib/server/runtime/daemon-state.test.ts +0 -35
  111. package/src/lib/server/runtime/heartbeat-service.ts +3 -23
  112. package/src/lib/server/runtime/queue/core.ts +11 -33
  113. package/src/lib/server/runtime/runtime-storage-write-paths.test.ts +6 -6
  114. package/src/lib/server/runtime/scheduler.ts +0 -13
  115. package/src/lib/server/runtime/session-run-manager/drain.ts +0 -24
  116. package/src/lib/server/runtime/session-run-manager/enqueue.ts +0 -1
  117. package/src/lib/server/runtime/session-run-manager/queries.ts +0 -1
  118. package/src/lib/server/runtime/session-run-manager/recovery.ts +0 -1
  119. package/src/lib/server/runtime/session-run-manager.test.ts +0 -28
  120. package/src/lib/server/session-tools/crud.ts +0 -14
  121. package/src/lib/server/session-tools/delegate.ts +0 -4
  122. package/src/lib/server/session-tools/index.ts +0 -4
  123. package/src/lib/server/session-tools/team-context.ts +0 -3
  124. package/src/lib/server/storage-normalization.ts +13 -0
  125. package/src/lib/server/storage.ts +75 -45
  126. package/src/lib/server/tasks/task-checkout.ts +59 -0
  127. package/src/lib/server/tasks/task-lifecycle.ts +2 -0
  128. package/src/lib/server/tasks/task-route-service.ts +4 -26
  129. package/src/lib/server/tasks/task-service.ts +0 -7
  130. package/src/lib/server/tool-aliases.ts +0 -1
  131. package/src/lib/server/tool-capability-policy-advanced.test.ts +4 -4
  132. package/src/lib/server/tool-capability-policy.ts +0 -2
  133. package/src/lib/server/tool-planning.ts +0 -12
  134. package/src/lib/server/universal-tool-access.ts +0 -1
  135. package/src/lib/server/usage/cost-rollup.ts +124 -0
  136. package/src/lib/server/usage/usage-repository.ts +6 -0
  137. package/src/lib/server/wallets/wallet-crypto.ts +33 -0
  138. package/src/lib/server/wallets/wallet-repository.ts +24 -0
  139. package/src/lib/server/wallets/wallet-service.ts +119 -0
  140. package/src/lib/server/working-state/extraction.ts +8 -42
  141. package/src/lib/server/working-state/normalization.ts +10 -103
  142. package/src/lib/server/working-state/service.ts +12 -21
  143. package/src/lib/strip-internal-metadata.test.ts +1 -1
  144. package/src/lib/strip-internal-metadata.ts +1 -1
  145. package/src/lib/tool-definitions.ts +0 -1
  146. package/src/lib/validation/schemas.ts +36 -32
  147. package/src/lib/validation/server-schemas.ts +35 -0
  148. package/src/stores/slices/data-slice.ts +5 -1
  149. package/src/stores/slices/ui-slice.ts +0 -4
  150. package/src/types/agent.ts +10 -84
  151. package/src/types/app-settings.ts +6 -2
  152. package/src/types/approval.ts +3 -2
  153. package/src/types/connector.ts +1 -0
  154. package/src/types/goal.ts +30 -0
  155. package/src/types/index.ts +2 -1
  156. package/src/types/message.ts +0 -1
  157. package/src/types/misc.ts +2 -4
  158. package/src/types/protocol.ts +0 -2
  159. package/src/types/run.ts +0 -3
  160. package/src/types/session.ts +1 -51
  161. package/src/types/swarmdock.ts +29 -0
  162. package/src/types/task.ts +9 -3
  163. package/src/types/working-state.ts +2 -9
  164. package/src/views/settings/section-runtime-loop.tsx +0 -14
  165. package/src/app/api/canvas/[sessionId]/route.ts +0 -35
  166. package/src/app/api/missions/[id]/actions/route.ts +0 -31
  167. package/src/app/api/missions/[id]/events/route.ts +0 -14
  168. package/src/app/api/missions/[id]/route.ts +0 -10
  169. package/src/app/api/missions/route.test.ts +0 -244
  170. package/src/app/api/missions/route.ts +0 -57
  171. package/src/app/api/wallets/[id]/approve/route.ts +0 -79
  172. package/src/app/api/wallets/[id]/balance-history/route.ts +0 -18
  173. package/src/app/api/wallets/[id]/send/route.ts +0 -113
  174. package/src/app/api/wallets/[id]/transactions/route.ts +0 -18
  175. package/src/app/missions/[id]/page.tsx +0 -3
  176. package/src/app/missions/page.tsx +0 -685
  177. package/src/components/canvas/canvas-panel.tsx +0 -267
  178. package/src/components/wallets/wallet-approval-dialog.tsx +0 -107
  179. package/src/components/wallets/wallet-panel.tsx +0 -1010
  180. package/src/components/wallets/wallet-section.tsx +0 -260
  181. package/src/features/missions/queries.ts +0 -23
  182. package/src/lib/canvas-content.test.ts +0 -360
  183. package/src/lib/canvas-content.ts +0 -198
  184. package/src/lib/server/canvas-content.test.ts +0 -32
  185. package/src/lib/server/canvas-content.ts +0 -6
  186. package/src/lib/server/ethereum.ts +0 -591
  187. package/src/lib/server/evm-swap.ts +0 -476
  188. package/src/lib/server/missions/mission-intent.test.ts +0 -63
  189. package/src/lib/server/missions/mission-intent.ts +0 -569
  190. package/src/lib/server/missions/mission-repository.ts +0 -74
  191. package/src/lib/server/missions/mission-service/actions.ts +0 -6
  192. package/src/lib/server/missions/mission-service/bindings.ts +0 -9
  193. package/src/lib/server/missions/mission-service/context.ts +0 -4
  194. package/src/lib/server/missions/mission-service/core.ts +0 -2271
  195. package/src/lib/server/missions/mission-service/queries.ts +0 -12
  196. package/src/lib/server/missions/mission-service/recovery.ts +0 -5
  197. package/src/lib/server/missions/mission-service/ticks.ts +0 -9
  198. package/src/lib/server/missions/mission-service.test.ts +0 -888
  199. package/src/lib/server/missions/mission-service.ts +0 -6
  200. package/src/lib/server/session-tools/canvas.ts +0 -105
  201. package/src/lib/server/session-tools/wallet-tool.test.ts +0 -150
  202. package/src/lib/server/session-tools/wallet.ts +0 -1287
  203. package/src/lib/server/solana.ts +0 -327
  204. package/src/lib/server/wallet/wallet-execution.test.ts +0 -198
  205. package/src/lib/server/wallet/wallet-portfolio.test.ts +0 -98
  206. package/src/lib/server/wallet/wallet-portfolio.ts +0 -772
  207. package/src/lib/server/wallet/wallet-service.test.ts +0 -81
  208. package/src/lib/server/wallet/wallet-service.ts +0 -225
  209. package/src/lib/wallet/wallet-transactions.test.ts +0 -75
  210. package/src/lib/wallet/wallet-transactions.ts +0 -43
  211. package/src/lib/wallet/wallet.test.ts +0 -333
  212. package/src/lib/wallet/wallet.ts +0 -183
  213. package/src/types/mission.ts +0 -185
  214. package/src/views/settings/section-wallets.tsx +0 -35
@@ -0,0 +1,143 @@
1
+ import type { Goal, GoalLevel } from '@/types'
2
+ import { genId } from '@/lib/id'
3
+ import { listGoals, getGoal, saveGoal, removeGoal } from './goal-repository'
4
+ import { logActivity } from '@/lib/server/activity/activity-log'
5
+ import { notify } from '@/lib/server/ws-hub'
6
+
7
+ export function getAllGoals(): Goal[] {
8
+ return Object.values(listGoals())
9
+ }
10
+
11
+ export function getGoalById(id: string): Goal | null {
12
+ return getGoal(id)
13
+ }
14
+
15
+ export function createGoal(input: {
16
+ title: string
17
+ description?: string
18
+ level: GoalLevel
19
+ parentGoalId?: string | null
20
+ projectId?: string | null
21
+ agentId?: string | null
22
+ taskId?: string | null
23
+ objective: string
24
+ constraints?: string[]
25
+ successMetric?: string | null
26
+ budgetUsd?: number | null
27
+ deadlineAt?: number | null
28
+ }): Goal {
29
+ const id = genId()
30
+ const now = Date.now()
31
+ const goal: Goal = {
32
+ id,
33
+ title: input.title,
34
+ description: input.description,
35
+ level: input.level,
36
+ parentGoalId: input.parentGoalId ?? null,
37
+ projectId: input.projectId ?? null,
38
+ agentId: input.agentId ?? null,
39
+ taskId: input.taskId ?? null,
40
+ objective: input.objective,
41
+ constraints: input.constraints ?? [],
42
+ successMetric: input.successMetric ?? null,
43
+ budgetUsd: input.budgetUsd ?? null,
44
+ deadlineAt: input.deadlineAt ?? null,
45
+ status: 'active',
46
+ createdAt: now,
47
+ updatedAt: now,
48
+ }
49
+ saveGoal(id, goal)
50
+ logActivity({ entityType: 'task', entityId: id, action: 'created', actor: 'user', summary: `Goal created: "${goal.title}" (${goal.level})` })
51
+ notify('goals')
52
+ return goal
53
+ }
54
+
55
+ export function updateGoal(id: string, updates: Partial<Omit<Goal, 'id' | 'createdAt'>>): Goal | null {
56
+ const existing = getGoal(id)
57
+ if (!existing) return null
58
+ const updated: Goal = {
59
+ ...existing,
60
+ ...updates,
61
+ id,
62
+ createdAt: existing.createdAt,
63
+ updatedAt: Date.now(),
64
+ }
65
+ saveGoal(id, updated)
66
+ logActivity({ entityType: 'task', entityId: id, action: 'updated', actor: 'user', summary: `Goal updated: "${updated.title}"` })
67
+ notify('goals')
68
+ return updated
69
+ }
70
+
71
+ export function deleteGoal(id: string): boolean {
72
+ const existing = getGoal(id)
73
+ if (!existing) return false
74
+ removeGoal(id)
75
+ logActivity({ entityType: 'task', entityId: id, action: 'deleted', actor: 'user', summary: `Goal deleted: "${existing.title}"` })
76
+ notify('goals')
77
+ return true
78
+ }
79
+
80
+ /**
81
+ * Walk the goal hierarchy to build a "why chain" from a specific goal up to the organization root.
82
+ * Returns goals in order from most specific to most general.
83
+ */
84
+ export function getGoalChain(goalId: string): Goal[] {
85
+ const chain: Goal[] = []
86
+ const visited = new Set<string>()
87
+ let currentId: string | null | undefined = goalId
88
+ while (currentId && !visited.has(currentId)) {
89
+ visited.add(currentId)
90
+ const goal = getGoal(currentId)
91
+ if (!goal) break
92
+ chain.push(goal)
93
+ currentId = goal.parentGoalId
94
+ }
95
+ return chain
96
+ }
97
+
98
+ /**
99
+ * Resolve the effective goal for a given context by walking the hierarchy:
100
+ * task goal → agent goal → project goal → organization default.
101
+ */
102
+ export function resolveEffectiveGoal(context: {
103
+ taskId?: string | null
104
+ agentId?: string | null
105
+ projectId?: string | null
106
+ }): Goal | null {
107
+ const goals = getAllGoals().filter((g) => g.status === 'active')
108
+
109
+ // 1. Task-level goal
110
+ if (context.taskId) {
111
+ const taskGoal = goals.find((g) => g.taskId === context.taskId)
112
+ if (taskGoal) return taskGoal
113
+ }
114
+
115
+ // 2. Agent-level goal
116
+ if (context.agentId) {
117
+ const agentGoal = goals.find((g) => g.level === 'agent' && g.agentId === context.agentId)
118
+ if (agentGoal) return agentGoal
119
+ }
120
+
121
+ // 3. Project-level goal
122
+ if (context.projectId) {
123
+ const projectGoal = goals.find((g) => g.level === 'project' && g.projectId === context.projectId)
124
+ if (projectGoal) return projectGoal
125
+ }
126
+
127
+ // 4. Organization default
128
+ const orgGoal = goals.find((g) => g.level === 'organization')
129
+ return orgGoal ?? null
130
+ }
131
+
132
+ /**
133
+ * Format a goal chain as a concise text block for injection into agent execution briefs.
134
+ */
135
+ export function formatGoalChainForBrief(chain: Goal[]): string {
136
+ if (chain.length === 0) return ''
137
+ const lines = chain.map((g, i) => {
138
+ const indent = ' '.repeat(i)
139
+ const label = g.level.charAt(0).toUpperCase() + g.level.slice(1)
140
+ return `${indent}${label}: ${g.title} — ${g.objective}`
141
+ })
142
+ return `Goal alignment:\n${lines.join('\n')}`
143
+ }
@@ -5,7 +5,6 @@ import { approvalRepository } from '@/lib/server/approvals/approval-repository'
5
5
  import { chatroomRepository } from '@/lib/server/chatrooms/chatroom-repository'
6
6
  import { connectorRepository } from '@/lib/server/connectors/connector-repository'
7
7
  import * as messageRepository from '@/lib/server/messages/message-repository'
8
- import { missionEventRepository, missionRepository } from '@/lib/server/missions/mission-repository'
9
8
  import { projectRepository } from '@/lib/server/projects/project-repository'
10
9
  import { scheduleRepository } from '@/lib/server/schedules/schedule-repository'
11
10
  import { sessionRepository } from '@/lib/server/sessions/session-repository'
@@ -19,8 +18,6 @@ export interface StorageTxContext {
19
18
  chatrooms: typeof chatroomRepository
20
19
  connectors: typeof connectorRepository
21
20
  messages: typeof messageRepository
22
- missions: typeof missionRepository
23
- missionEvents: typeof missionEventRepository
24
21
  projects: typeof projectRepository
25
22
  runs: typeof runRepository
26
23
  runEvents: typeof runEventRepository
@@ -37,8 +34,6 @@ export function createStorageTxContext(): StorageTxContext {
37
34
  chatrooms: chatroomRepository,
38
35
  connectors: connectorRepository,
39
36
  messages: messageRepository,
40
- missions: missionRepository,
41
- missionEvents: missionEventRepository,
42
37
  projects: projectRepository,
43
38
  runs: runRepository,
44
39
  runEvents: runEventRepository,
@@ -0,0 +1,109 @@
1
+ import { loadAgents } from '@/lib/server/agents/agent-repository'
2
+ import { loadSkills } from '@/lib/server/skills/skill-repository'
3
+ import { loadSchedules } from '@/lib/server/schedules/schedule-repository'
4
+ import type { Agent } from '@/types/agent'
5
+ import type { Skill } from '@/types/skill'
6
+ import type { Schedule } from '@/types/schedule'
7
+
8
+ export const PORTABILITY_FORMAT_VERSION = 1
9
+
10
+ export interface PortableManifest {
11
+ formatVersion: number
12
+ exportedAt: string
13
+ agents: PortableAgent[]
14
+ skills: PortableSkill[]
15
+ schedules: PortableSchedule[]
16
+ }
17
+
18
+ export type PortableAgent = Omit<Agent,
19
+ // Strip runtime/sensitive fields
20
+ | 'id' | 'credentialId' | 'fallbackCredentialIds' | 'apiEndpoint'
21
+ | 'threadSessionId' | 'lastUsedAt' | 'totalCost' | 'trashedAt'
22
+ | 'openclawAgentId' | 'gatewayProfileId' | 'avatarUrl'
23
+ > & {
24
+ /** Original ID — used for matching during import */
25
+ originalId: string
26
+ }
27
+
28
+ export type PortableSkill = Pick<Skill,
29
+ | 'name' | 'content' | 'description' | 'tags' | 'scope'
30
+ | 'author' | 'version' | 'primaryEnv' | 'capabilities'
31
+ | 'toolNames' | 'frontmatter'
32
+ > & {
33
+ originalId: string
34
+ }
35
+
36
+ export type PortableSchedule = Pick<Schedule,
37
+ | 'name' | 'taskPrompt' | 'taskMode' | 'message' | 'description'
38
+ | 'scheduleType' | 'frequency' | 'cron' | 'atTime' | 'intervalMs'
39
+ | 'timezone' | 'action' | 'path' | 'command'
40
+ > & {
41
+ originalId: string
42
+ /** Original agent ID — resolved to new ID during import */
43
+ originalAgentId: string
44
+ }
45
+
46
+ /** Sensitive fields stripped from exported agents */
47
+ const AGENT_STRIP_KEYS: (keyof Agent)[] = [
48
+ 'id', 'credentialId', 'fallbackCredentialIds', 'apiEndpoint',
49
+ 'threadSessionId', 'lastUsedAt', 'totalCost', 'trashedAt',
50
+ 'openclawAgentId', 'gatewayProfileId', 'avatarUrl',
51
+ ]
52
+
53
+ export function exportConfig(): PortableManifest {
54
+ const agents = loadAgents()
55
+ const skills = loadSkills()
56
+ const schedules = loadSchedules()
57
+
58
+ const portableAgents: PortableAgent[] = Object.values(agents)
59
+ .filter((a) => !a.trashedAt && !a.disabled)
60
+ .map((agent) => {
61
+ const portable = { ...agent, originalId: agent.id } as Record<string, unknown>
62
+ for (const key of AGENT_STRIP_KEYS) delete portable[key]
63
+ return portable as PortableAgent
64
+ })
65
+
66
+ const portableSkills: PortableSkill[] = Object.values(skills).map((skill) => ({
67
+ originalId: skill.id,
68
+ name: skill.name,
69
+ content: skill.content,
70
+ description: skill.description,
71
+ tags: skill.tags,
72
+ scope: skill.scope,
73
+ author: skill.author,
74
+ version: skill.version,
75
+ primaryEnv: skill.primaryEnv,
76
+ capabilities: skill.capabilities,
77
+ toolNames: skill.toolNames,
78
+ frontmatter: skill.frontmatter,
79
+ }))
80
+
81
+ const portableSchedules: PortableSchedule[] = Object.values(schedules)
82
+ .filter((s) => s.status !== 'archived')
83
+ .map((schedule) => ({
84
+ originalId: schedule.id,
85
+ originalAgentId: schedule.agentId,
86
+ name: schedule.name,
87
+ taskPrompt: schedule.taskPrompt,
88
+ taskMode: schedule.taskMode,
89
+ message: schedule.message,
90
+ description: schedule.description,
91
+ scheduleType: schedule.scheduleType,
92
+ frequency: schedule.frequency,
93
+ cron: schedule.cron,
94
+ atTime: schedule.atTime,
95
+ intervalMs: schedule.intervalMs,
96
+ timezone: schedule.timezone,
97
+ action: schedule.action,
98
+ path: schedule.path,
99
+ command: schedule.command,
100
+ }))
101
+
102
+ return {
103
+ formatVersion: PORTABILITY_FORMAT_VERSION,
104
+ exportedAt: new Date().toISOString(),
105
+ agents: portableAgents,
106
+ skills: portableSkills,
107
+ schedules: portableSchedules,
108
+ }
109
+ }
@@ -0,0 +1,159 @@
1
+ import { genId } from '@/lib/id'
2
+ import { loadAgents, saveAgents } from '@/lib/server/agents/agent-repository'
3
+ import { loadSkills, saveSkill } from '@/lib/server/skills/skill-repository'
4
+ import { loadSchedules, upsertSchedule } from '@/lib/server/schedules/schedule-repository'
5
+ import { logActivity } from '@/lib/server/activity/activity-log'
6
+ import type { Agent } from '@/types/agent'
7
+ import type { Skill } from '@/types/skill'
8
+ import type { Schedule } from '@/types/schedule'
9
+ import type { PortableManifest, PortableAgent, PortableSkill, PortableSchedule } from './export'
10
+ import { PORTABILITY_FORMAT_VERSION } from './export'
11
+
12
+ export interface ImportResult {
13
+ agents: { created: number; skipped: number; names: string[] }
14
+ skills: { created: number; skipped: number; names: string[] }
15
+ schedules: { created: number; skipped: number; names: string[] }
16
+ /** Maps original IDs to new IDs for reference */
17
+ idMap: Record<string, string>
18
+ }
19
+
20
+ function deduplicateName(name: string, existingNames: Set<string>): string {
21
+ if (!existingNames.has(name)) return name
22
+ let suffix = 2
23
+ while (existingNames.has(`${name} (${suffix})`)) suffix++
24
+ return `${name} (${suffix})`
25
+ }
26
+
27
+ export function importConfig(manifest: PortableManifest): ImportResult {
28
+ if (manifest.formatVersion > PORTABILITY_FORMAT_VERSION) {
29
+ throw new Error(`Unsupported format version ${manifest.formatVersion} (max supported: ${PORTABILITY_FORMAT_VERSION})`)
30
+ }
31
+
32
+ const idMap: Record<string, string> = {}
33
+ const result: ImportResult = {
34
+ agents: { created: 0, skipped: 0, names: [] },
35
+ skills: { created: 0, skipped: 0, names: [] },
36
+ schedules: { created: 0, skipped: 0, names: [] },
37
+ idMap,
38
+ }
39
+
40
+ // --- Import skills first (agents may reference them) ---
41
+ const existingSkills = loadSkills()
42
+ const existingSkillNames = new Set(Object.values(existingSkills).map((s) => s.name))
43
+
44
+ for (const portable of manifest.skills) {
45
+ const name = deduplicateName(portable.name, existingSkillNames)
46
+ const id = genId()
47
+ idMap[portable.originalId] = id
48
+ existingSkillNames.add(name)
49
+
50
+ const skill: Skill = {
51
+ id,
52
+ name,
53
+ filename: `${name.toLowerCase().replace(/[^a-z0-9]+/g, '-')}.md`,
54
+ content: portable.content,
55
+ description: portable.description,
56
+ tags: portable.tags,
57
+ scope: portable.scope || 'global',
58
+ author: portable.author,
59
+ version: portable.version,
60
+ primaryEnv: portable.primaryEnv,
61
+ capabilities: portable.capabilities,
62
+ toolNames: portable.toolNames,
63
+ frontmatter: portable.frontmatter,
64
+ createdAt: Date.now(),
65
+ updatedAt: Date.now(),
66
+ }
67
+ saveSkill(id, skill)
68
+ result.skills.created++
69
+ result.skills.names.push(name)
70
+ }
71
+
72
+ // --- Import agents ---
73
+ const existingAgents = loadAgents()
74
+ const existingAgentNames = new Set(Object.values(existingAgents).map((a) => a.name))
75
+
76
+ for (const portable of manifest.agents) {
77
+ const name = deduplicateName(portable.name, existingAgentNames)
78
+ const id = genId()
79
+ const now = Date.now()
80
+ idMap[portable.originalId] = id
81
+ existingAgentNames.add(name)
82
+
83
+ // Remap skill IDs if they were imported
84
+ const remappedSkillIds = (portable.skillIds || []).map((sid) => idMap[sid] || sid)
85
+
86
+ const agent: Agent = {
87
+ ...(portable as Omit<PortableAgent, 'originalId'>),
88
+ id,
89
+ name,
90
+ skillIds: remappedSkillIds,
91
+ // Reset runtime fields
92
+ threadSessionId: null,
93
+ lastUsedAt: undefined,
94
+ totalCost: undefined,
95
+ trashedAt: undefined,
96
+ credentialId: null,
97
+ fallbackCredentialIds: [],
98
+ apiEndpoint: null,
99
+ createdAt: typeof portable.createdAt === 'number' ? portable.createdAt : now,
100
+ updatedAt: now,
101
+ }
102
+ existingAgents[id] = agent
103
+ result.agents.created++
104
+ result.agents.names.push(name)
105
+ }
106
+
107
+ saveAgents(existingAgents)
108
+
109
+ // --- Import schedules (need agent ID mapping) ---
110
+ const existingSchedules = loadSchedules()
111
+ const existingScheduleNames = new Set(Object.values(existingSchedules).map((s) => s.name))
112
+
113
+ for (const portable of manifest.schedules) {
114
+ const newAgentId = idMap[portable.originalAgentId]
115
+ if (!newAgentId) {
116
+ result.schedules.skipped++
117
+ continue
118
+ }
119
+
120
+ const name = deduplicateName(portable.name, existingScheduleNames)
121
+ const id = genId()
122
+ idMap[portable.originalId] = id
123
+ existingScheduleNames.add(name)
124
+
125
+ const schedule: Schedule = {
126
+ id,
127
+ name,
128
+ agentId: newAgentId,
129
+ taskPrompt: portable.taskPrompt,
130
+ taskMode: portable.taskMode,
131
+ message: portable.message,
132
+ description: portable.description,
133
+ scheduleType: portable.scheduleType,
134
+ frequency: portable.frequency,
135
+ cron: portable.cron,
136
+ atTime: portable.atTime,
137
+ intervalMs: portable.intervalMs,
138
+ timezone: portable.timezone,
139
+ action: portable.action,
140
+ path: portable.path,
141
+ command: portable.command,
142
+ status: 'paused',
143
+ createdAt: Date.now(),
144
+ }
145
+ upsertSchedule(id, schedule)
146
+ result.schedules.created++
147
+ result.schedules.names.push(name)
148
+ }
149
+
150
+ logActivity({
151
+ entityType: 'system',
152
+ entityId: 'portability',
153
+ action: 'imported',
154
+ actor: 'user',
155
+ summary: `Imported ${result.agents.created} agents, ${result.skills.created} skills, ${result.schedules.created} schedules`,
156
+ })
157
+
158
+ return result
159
+ }
@@ -446,9 +446,6 @@ export function normalizeProtocolSourceRef(run: Partial<ProtocolRun>): ProtocolS
446
446
  if (typeof run.parentChatroomId === 'string' && run.parentChatroomId.trim()) {
447
447
  return { kind: 'chatroom', chatroomId: run.parentChatroomId.trim() }
448
448
  }
449
- if (typeof run.missionId === 'string' && run.missionId.trim()) {
450
- return { kind: 'mission', missionId: run.missionId.trim() }
451
- }
452
449
  if (typeof run.taskId === 'string' && run.taskId.trim()) {
453
450
  return { kind: 'task', taskId: run.taskId.trim() }
454
451
  }
@@ -484,7 +481,6 @@ export function normalizeProtocolRun(run: ProtocolRun): ProtocolRun {
484
481
  participantAgentIds: uniqueIds(run.participantAgentIds, 64),
485
482
  observerAgentIds: uniqueIds(run.observerAgentIds, 64),
486
483
  facilitatorAgentId: typeof run.facilitatorAgentId === 'string' ? run.facilitatorAgentId : null,
487
- missionId: typeof run.missionId === 'string' ? run.missionId : null,
488
484
  taskId: typeof run.taskId === 'string' ? run.taskId : null,
489
485
  sessionId: typeof run.sessionId === 'string' ? run.sessionId : null,
490
486
  parentRunId: typeof run.parentRunId === 'string' ? run.parentRunId : null,
@@ -13,9 +13,6 @@ import {
13
13
  loadChatroom,
14
14
  loadChatroomMany,
15
15
  } from '@/lib/server/chatrooms/chatroom-repository'
16
- import {
17
- loadMission,
18
- } from '@/lib/server/missions/mission-repository'
19
16
  import {
20
17
  loadProtocolRun,
21
18
  loadProtocolRuns,
@@ -37,7 +34,6 @@ export function listProtocolTemplates(): ProtocolTemplate[] {
37
34
 
38
35
  export function listProtocolRuns(options?: {
39
36
  status?: ProtocolRunStatus | null
40
- missionId?: string | null
41
37
  taskId?: string | null
42
38
  sessionId?: string | null
43
39
  parentChatroomId?: string | null
@@ -51,7 +47,6 @@ export function listProtocolRuns(options?: {
51
47
  return Object.values(loadProtocolRuns())
52
48
  .map((run) => normalizeProtocolRun(run))
53
49
  .filter((run) => !options?.status || run.status === options.status)
54
- .filter((run) => !options?.missionId || run.missionId === options.missionId)
55
50
  .filter((run) => !options?.taskId || run.taskId === options.taskId)
56
51
  .filter((run) => !options?.sessionId || run.sessionId === options.sessionId)
57
52
  .filter((run) => !options?.parentChatroomId || run.parentChatroomId === options.parentChatroomId)
@@ -109,7 +104,6 @@ export function getProtocolRunDetail(runId: string): ProtocolRunDetail | null {
109
104
  template: loadTemplate(run.templateId),
110
105
  transcript: run.transcriptChatroomId ? chatrooms[run.transcriptChatroomId] || null : null,
111
106
  parentChatroom: run.parentChatroomId ? chatrooms[run.parentChatroomId] || null : null,
112
- linkedMission: run.missionId ? loadMission(run.missionId) : null,
113
107
  linkedTask: run.taskId ? loadTask(run.taskId) : null,
114
108
  events: listEvents(run.id),
115
109
  }
@@ -19,7 +19,6 @@ import { patchChatroom, upsertChatroom } from '@/lib/server/chatrooms/chatroom-r
19
19
  import { loadProtocolRuns } from '@/lib/server/protocols/protocol-run-repository'
20
20
  import { loadTask } from '@/lib/server/tasks/task-repository'
21
21
  import { errorMessage, hmrSingleton } from '@/lib/shared-utils'
22
- import { requestMissionTick } from '@/lib/server/missions/mission-service'
23
22
  import { cleanText, isDiscussionStepKind, now, uniqueIds } from '@/lib/server/protocols/protocol-types'
24
23
  import type { CreateProtocolRunInput, ProtocolRunActionInput, ProtocolRunDeps } from '@/lib/server/protocols/protocol-types'
25
24
  import { deriveDisplayPhasesFromSteps, loadProtocolRunById, normalizeProtocolRun, resolveRunSteps } from '@/lib/server/protocols/protocol-normalization'
@@ -224,11 +223,10 @@ export function createProtocolRun(input: CreateProtocolRunInput, deps?: Protocol
224
223
  : null
225
224
  const sourceRef = input.sourceRef || (
226
225
  input.parentChatroomId ? { kind: 'chatroom', chatroomId: input.parentChatroomId } as ProtocolSourceRef
227
- : input.missionId ? { kind: 'mission', missionId: input.missionId } as ProtocolSourceRef
228
- : input.taskId ? { kind: 'task', taskId: input.taskId } as ProtocolSourceRef
229
- : input.scheduleId ? { kind: 'schedule', scheduleId: input.scheduleId } as ProtocolSourceRef
230
- : input.sessionId ? { kind: 'session', sessionId: input.sessionId } as ProtocolSourceRef
231
- : { kind: 'manual' } as ProtocolSourceRef
226
+ : input.taskId ? { kind: 'task', taskId: input.taskId } as ProtocolSourceRef
227
+ : input.scheduleId ? { kind: 'schedule', scheduleId: input.scheduleId } as ProtocolSourceRef
228
+ : input.sessionId ? { kind: 'session', sessionId: input.sessionId } as ProtocolSourceRef
229
+ : { kind: 'manual' } as ProtocolSourceRef
232
230
  )
233
231
  const runId = genId()
234
232
  if (transcript) {
@@ -246,7 +244,6 @@ export function createProtocolRun(input: CreateProtocolRunInput, deps?: Protocol
246
244
  participantAgentIds,
247
245
  facilitatorAgentId: cleanText(input.facilitatorAgentId, 64) || participantAgentIds[0] || null,
248
246
  observerAgentIds: uniqueIds(input.observerAgentIds, 32),
249
- missionId: cleanText(input.missionId, 64) || null,
250
247
  taskId: cleanText(input.taskId, 64) || null,
251
248
  sessionId: cleanText(input.sessionId, 64) || null,
252
249
  parentRunId: cleanText(input.parentRunId, 64) || null,
@@ -288,9 +285,6 @@ export function createProtocolRun(input: CreateProtocolRunInput, deps?: Protocol
288
285
  transcriptChatroomId: run.transcriptChatroomId,
289
286
  },
290
287
  }, deps)
291
- if (run.missionId) {
292
- requestMissionTick(run.missionId, 'protocol_run_created', { protocolRunId: run.id })
293
- }
294
288
  if (input.autoStart !== false) {
295
289
  requestProtocolRunExecution(run.id, deps)
296
290
  }
@@ -594,7 +588,6 @@ export function launchProtocolRunForSchedule(schedule: Schedule): ProtocolRun {
594
588
  observerAgentIds: uniqueIds(schedule.protocolObserverAgentIds, 32),
595
589
  scheduleId: schedule.id,
596
590
  sessionId: schedule.createdInSessionId || null,
597
- missionId: schedule.linkedMissionId || null,
598
591
  sourceRef: { kind: 'schedule', scheduleId: schedule.id },
599
592
  autoStart: true,
600
593
  parentChatroomId: null,
@@ -607,31 +600,11 @@ export function launchProtocolRunForSchedule(schedule: Schedule): ProtocolRun {
607
600
  })
608
601
  }
609
602
 
610
- export function launchProtocolRunForMission(input: {
611
- missionId: string
612
- title: string
613
- participantAgentIds: string[]
614
- facilitatorAgentId?: string | null
615
- config?: ProtocolRunConfig | null
616
- templateId?: string | null
617
- }): ProtocolRun {
618
- return createProtocolRun({
619
- title: input.title,
620
- templateId: input.templateId || 'facilitated_discussion',
621
- participantAgentIds: input.participantAgentIds,
622
- facilitatorAgentId: input.facilitatorAgentId || null,
623
- missionId: input.missionId,
624
- sourceRef: { kind: 'mission', missionId: input.missionId },
625
- config: input.config || null,
626
- })
627
- }
628
-
629
603
  export function launchProtocolRunForTask(input: {
630
604
  taskId: string
631
605
  title: string
632
606
  participantAgentIds: string[]
633
607
  facilitatorAgentId?: string | null
634
- missionId?: string | null
635
608
  config?: ProtocolRunConfig | null
636
609
  templateId?: string | null
637
610
  }): ProtocolRun {
@@ -640,7 +613,6 @@ export function launchProtocolRunForTask(input: {
640
613
  templateId: input.templateId || 'facilitated_discussion',
641
614
  participantAgentIds: input.participantAgentIds,
642
615
  facilitatorAgentId: input.facilitatorAgentId || null,
643
- missionId: input.missionId || null,
644
616
  taskId: input.taskId,
645
617
  sourceRef: { kind: 'task', taskId: input.taskId },
646
618
  config: input.config || null,
@@ -43,7 +43,6 @@ export {
43
43
  runProtocolRun,
44
44
  performProtocolRunAction,
45
45
  launchProtocolRunForSchedule,
46
- launchProtocolRunForMission,
47
46
  launchProtocolRunForTask,
48
47
  } from '@/lib/server/protocols/protocol-run-lifecycle'
49
48
 
@@ -36,7 +36,6 @@ import {
36
36
  updateRun,
37
37
  } from '@/lib/server/protocols/protocol-agent-turn'
38
38
  import { isTerminalProtocolRunStatus } from '@/lib/server/protocols/protocol-templates'
39
- import { requestMissionTick } from '@/lib/server/missions/mission-service'
40
39
 
41
40
  // ---- BranchDecisionSchema ----
42
41
 
@@ -329,9 +328,6 @@ export function completeProtocolRun(run: ProtocolRun, deps?: ProtocolRunDeps, su
329
328
  summary,
330
329
  }, deps)
331
330
  emitSummaryToParentChatroom(completed, deps)
332
- if (completed.missionId) {
333
- requestMissionTick(completed.missionId, 'protocol_run_completed', { protocolRunId: completed.id })
334
- }
335
331
  return completed
336
332
  }
337
333
 
@@ -16,7 +16,6 @@ import { errorMessage } from '@/lib/shared-utils'
16
16
  import { getAgents } from '@/lib/server/agents/agent-repository'
17
17
  import { upsertTask } from '@/lib/server/tasks/task-repository'
18
18
  import { notify } from '@/lib/server/ws-hub'
19
- import { ensureMissionForTask } from '@/lib/server/missions/mission-service'
20
19
  import { enqueueTask } from '@/lib/server/runtime/queue'
21
20
  import { cleanText, isDiscussionStepKind, now, uniqueIds } from '@/lib/server/protocols/protocol-types'
22
21
  import type { ProtocolRunDeps } from '@/lib/server/protocols/protocol-types'
@@ -227,7 +226,6 @@ export async function processEmitTasksPhase(run: ProtocolRun, phase: ProtocolPha
227
226
  ...extracted.map((item) => item.agentId || ''),
228
227
  ], 64))
229
228
  const createdTaskIds: string[] = []
230
- const linkedMissionId = typeof run.missionId === 'string' ? run.missionId : null
231
229
  const taskProjectId = run.config?.taskProjectId || null
232
230
  for (const item of extracted) {
233
231
  const assignedAgentId = item.agentId && agents[item.agentId] ? item.agentId : fallbackAssignee
@@ -238,7 +236,6 @@ export async function processEmitTasksPhase(run: ProtocolRun, phase: ProtocolPha
238
236
  description: cleanText(item.description, 1_000) || cleanText(artifact.content, 800),
239
237
  status: 'backlog',
240
238
  agentId: assignedAgentId,
241
- missionId: linkedMissionId,
242
239
  projectId: taskProjectId || undefined,
243
240
  createdByAgentId: chooseFacilitator(run),
244
241
  createdInSessionId: run.sessionId || null,
@@ -248,7 +245,6 @@ export async function processEmitTasksPhase(run: ProtocolRun, phase: ProtocolPha
248
245
  tags: ['structured-session'],
249
246
  }
250
247
  upsertTask(task.id, task)
251
- ensureMissionForTask(task, { source: 'manual' })
252
248
  createdTaskIds.push(task.id)
253
249
  appendProtocolEvent(run.id, {
254
250
  type: 'task_emitted',
@@ -607,7 +603,6 @@ export function processDispatchTaskPhase(run: ProtocolRun, phase: ProtocolPhaseD
607
603
  status: 'queued',
608
604
  agentId,
609
605
  protocolRunId: run.id,
610
- missionId: run.missionId || null,
611
606
  queuedAt: now(deps),
612
607
  createdAt: now(deps),
613
608
  updatedAt: now(deps),
@@ -656,7 +651,6 @@ export function processDispatchDelegationPhase(run: ProtocolRun, phase: Protocol
656
651
  status: 'queued',
657
652
  agentId: config.agentId,
658
653
  protocolRunId: run.id,
659
- missionId: run.missionId || null,
660
654
  sourceType: 'delegation',
661
655
  queuedAt: now(deps),
662
656
  createdAt: now(deps),
@@ -90,7 +90,6 @@ export async function processSwarmStep(run: ProtocolRun, step: ProtocolStepDefin
90
90
  status: 'queued',
91
91
  agentId,
92
92
  protocolRunId: started.id,
93
- missionId: started.missionId || null,
94
93
  sourceType: 'delegation',
95
94
  queuedAt: now(deps),
96
95
  createdAt: now(deps),
@@ -189,7 +188,6 @@ export function claimSwarmWorkItem(
189
188
  status: 'queued',
190
189
  agentId,
191
190
  protocolRunId: runId,
192
- missionId: run.missionId || null,
193
191
  sourceType: 'delegation',
194
192
  queuedAt: now(deps),
195
193
  createdAt: now(deps),