@swarmclawai/swarmclaw 1.4.8 → 1.5.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.
@@ -1,68 +1,80 @@
1
1
  'use client'
2
2
 
3
+ import { LaunchActionCard } from '@/components/shared/launch-action-card'
3
4
  import type { StepNextProps } from './types'
4
5
  import { StepShell } from './shared'
5
6
 
6
7
  export function StepNext({
7
- onAddProvider,
8
- onAddAgent,
8
+ createdAgents,
9
9
  onContinueToDashboard,
10
+ onOpenFirstAgent,
11
+ onOpenProtocols,
12
+ onOpenBuilder,
13
+ onOpenConnectors,
14
+ onOpenUsage,
10
15
  }: StepNextProps) {
16
+ const firstAgent = createdAgents[0] || null
17
+
11
18
  return (
12
- <StepShell>
19
+ <StepShell wide>
13
20
  <h1 className="font-display text-[36px] font-800 leading-[1.05] tracking-[-0.04em] mb-3">
14
- What&apos;s Next?
21
+ Launch Your Workspace
15
22
  </h1>
16
- <p className="text-[15px] text-text-2 mb-8">
17
- Your agents are saved. You can keep building or head to the dashboard.
23
+ <p className="text-[15px] text-text-2 mb-2">
24
+ Setup is complete. Start from the path that gets you to an actual result fastest.
25
+ </p>
26
+ <p className="text-[13px] text-text-3 mb-7">
27
+ {firstAgent
28
+ ? `${firstAgent.name} is ready to use.`
29
+ : 'You finished setup without starter agents, so the launch options below focus on wiring up the rest of the workspace.'}
18
30
  </p>
19
31
 
20
- <div className="flex flex-col gap-3 max-w-[480px] mx-auto mb-8">
21
- <button
22
- onClick={onAddProvider}
23
- className="w-full px-5 py-4 rounded-[14px] border border-white/[0.08] bg-surface text-left
24
- transition-all duration-200 flex items-start gap-4 cursor-pointer
25
- hover:border-accent-bright/30 hover:bg-surface-hover"
26
- >
27
- <div className="w-10 h-10 rounded-[10px] border border-white/[0.06] bg-white/[0.04] flex items-center justify-center shrink-0 mt-0.5">
28
- <svg width="18" height="18" viewBox="0 0 18 18" fill="none" className="text-accent-bright">
29
- <path d="M9 3V15M3 9H15" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
30
- </svg>
31
- </div>
32
- <div>
33
- <div className="text-[15px] font-display font-600 text-text mb-1">Add Another Provider</div>
34
- <div className="text-[13px] text-text-3 leading-relaxed">
35
- Connect a different LLM provider for more model options.
36
- </div>
37
- </div>
38
- </button>
39
-
40
- <button
41
- onClick={onAddAgent}
42
- className="w-full px-5 py-4 rounded-[14px] border border-white/[0.08] bg-surface text-left
43
- transition-all duration-200 flex items-start gap-4 cursor-pointer
44
- hover:border-accent-bright/30 hover:bg-surface-hover"
45
- >
46
- <div className="w-10 h-10 rounded-[10px] border border-white/[0.06] bg-white/[0.04] flex items-center justify-center shrink-0 mt-0.5">
47
- <svg width="18" height="18" viewBox="0 0 18 18" fill="none" className="text-accent-bright">
48
- <circle cx="9" cy="6" r="3" stroke="currentColor" strokeWidth="1.5" />
49
- <path d="M3 15C3 12.2386 5.68629 10 9 10C12.3137 10 15 12.2386 15 15" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
50
- </svg>
51
- </div>
52
- <div>
53
- <div className="text-[15px] font-display font-600 text-text mb-1">Add Another Agent</div>
54
- <div className="text-[13px] text-text-3 leading-relaxed">
55
- Create another agent using your connected providers.
56
- </div>
57
- </div>
58
- </button>
32
+ <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3 mb-8">
33
+ <LaunchActionCard
34
+ title={firstAgent ? 'Open First Agent Chat' : 'Open Agents'}
35
+ description={firstAgent
36
+ ? `Jump straight into ${firstAgent.name} and start working from the workspace you just created.`
37
+ : 'Open the agents workspace so you can create or tune the first agent manually.'}
38
+ actionLabel={firstAgent ? 'Open Chat' : 'Open Agents'}
39
+ onClick={onOpenFirstAgent}
40
+ tone="primary"
41
+ />
42
+ <LaunchActionCard
43
+ title="Start Structured Session"
44
+ description="Open bounded collaboration runs for reviews, planning rounds, decision-making, or focused multi-agent work."
45
+ actionLabel="Open Protocols"
46
+ onClick={onOpenProtocols}
47
+ />
48
+ <LaunchActionCard
49
+ title="Open Workflow Builder"
50
+ description="Jump into the visual protocol builder if you want a reusable orchestration graph instead of a one-off run."
51
+ actionLabel="Open Builder"
52
+ onClick={onOpenBuilder}
53
+ />
54
+ <LaunchActionCard
55
+ title="Connect a Platform"
56
+ description="Bridge agents into Discord, Slack, Telegram, WhatsApp, or other runtime connectors."
57
+ actionLabel="Open Connectors"
58
+ onClick={onOpenConnectors}
59
+ />
60
+ <LaunchActionCard
61
+ title="Review Usage"
62
+ description="Inspect cost, provider health, and agent activity so the workspace stays observable from day one."
63
+ actionLabel="Open Usage"
64
+ onClick={onOpenUsage}
65
+ />
66
+ <LaunchActionCard
67
+ title="Go to Dashboard"
68
+ description="Land on the main home view. Fresh workspaces open in guided launch mode before switching to the normal ops dashboard."
69
+ actionLabel="Open Home"
70
+ onClick={onContinueToDashboard}
71
+ />
59
72
  </div>
60
73
 
61
74
  <button
75
+ type="button"
62
76
  onClick={onContinueToDashboard}
63
- className="px-10 py-3.5 rounded-[14px] border-none bg-accent-bright text-white text-[15px] font-display font-600
64
- cursor-pointer hover:brightness-110 active:scale-[0.97] transition-all duration-200
65
- shadow-[0_6px_28px_rgba(99,102,241,0.3)]"
77
+ className="px-10 py-3.5 rounded-[14px] border-none bg-accent-bright text-white text-[15px] font-display font-600 cursor-pointer hover:brightness-110 active:scale-[0.97] transition-all duration-200 shadow-[0_6px_28px_rgba(99,102,241,0.3)]"
66
78
  >
67
79
  Continue to Dashboard
68
80
  </button>
@@ -0,0 +1,159 @@
1
+ 'use client'
2
+
3
+ import { ONBOARDING_PATHS } from '@/lib/setup-defaults'
4
+ import type { StepPathProps } from './types'
5
+ import { StepShell, SkipLink } from './shared'
6
+ import { formatAgentCount, getStarterKitsForPath } from './utils'
7
+
8
+ export function StepPath({
9
+ onboardingPath,
10
+ starterKitId,
11
+ intentText,
12
+ onPathChange,
13
+ onStarterKitChange,
14
+ onIntentTextChange,
15
+ onContinue,
16
+ onBack,
17
+ onSkip,
18
+ }: StepPathProps) {
19
+ const visibleStarterKits = getStarterKitsForPath(onboardingPath)
20
+
21
+ return (
22
+ <StepShell wide>
23
+ <h1 className="font-display text-[36px] font-800 leading-[1.05] tracking-[-0.04em] mb-3">
24
+ Choose Your Start
25
+ </h1>
26
+ <p className="text-[15px] text-text-2 mb-2">
27
+ Pick the setup path that matches how much guidance you want.
28
+ </p>
29
+ <p className="text-[13px] text-text-3 mb-7">
30
+ You can still edit providers, prompts, tools, and agent details before finishing setup.
31
+ </p>
32
+
33
+ <div className="grid gap-3 md:grid-cols-3 text-left mb-6">
34
+ {ONBOARDING_PATHS.map((path) => {
35
+ const active = path.id === onboardingPath
36
+ return (
37
+ <button
38
+ key={path.id}
39
+ type="button"
40
+ onClick={() => onPathChange(path.id)}
41
+ className={`rounded-[18px] border px-5 py-4 text-left transition-all duration-200 cursor-pointer ${
42
+ active
43
+ ? 'border-accent-bright/35 bg-accent-soft shadow-[0_0_24px_rgba(99,102,241,0.12)]'
44
+ : 'border-white/[0.08] bg-surface hover:border-accent-bright/20 hover:bg-white/[0.04]'
45
+ }`}
46
+ >
47
+ <div className="flex items-start justify-between gap-3">
48
+ <div className="text-[15px] font-display font-700 text-text">{path.title}</div>
49
+ {path.badge ? (
50
+ <span className={`rounded-full px-2 py-1 text-[10px] font-700 uppercase tracking-[0.12em] ${
51
+ active ? 'bg-accent-bright text-black' : 'bg-white/[0.05] text-text-3/80'
52
+ }`}>
53
+ {path.badge}
54
+ </span>
55
+ ) : null}
56
+ </div>
57
+ <p className="mt-2 text-[13px] leading-relaxed text-text-2">{path.description}</p>
58
+ <p className="mt-3 text-[12px] leading-relaxed text-text-3/72">{path.detail}</p>
59
+ </button>
60
+ )
61
+ })}
62
+ </div>
63
+
64
+ {onboardingPath === 'intent' && (
65
+ <div className="mb-6 rounded-[18px] border border-white/[0.08] bg-surface px-5 py-4 text-left">
66
+ <label className="block text-[12px] font-700 uppercase tracking-[0.12em] text-text-3/60 mb-2">
67
+ What Are You Setting Up SwarmClaw To Do?
68
+ </label>
69
+ <textarea
70
+ value={intentText}
71
+ onChange={(event) => onIntentTextChange(event.target.value)}
72
+ rows={3}
73
+ placeholder="e.g. Help me run product research every week, summarize findings, and turn them into follow-up tasks."
74
+ className="w-full rounded-[14px] border border-white/[0.08] bg-bg px-4 py-3 text-[14px] text-text outline-none transition-all duration-200 resize-none placeholder:text-text-3/45 focus:border-accent-bright/30 focus:shadow-[0_0_30px_rgba(99,102,241,0.1)]"
75
+ />
76
+ <p className="mt-2 text-[12px] leading-relaxed text-text-3/72">
77
+ This is used only to seed the starter prompts. It does not auto-classify your workflow.
78
+ </p>
79
+ </div>
80
+ )}
81
+
82
+ <div className="rounded-[20px] border border-white/[0.08] bg-surface p-5 text-left">
83
+ <div className="flex flex-wrap items-start justify-between gap-3">
84
+ <div>
85
+ <div className="text-[11px] font-700 uppercase tracking-[0.12em] text-text-3/55">Starting Shape</div>
86
+ <div className="mt-1 text-[13px] text-text-3/72">
87
+ Start from a broad team shape instead of a niche preset. You can still edit every agent before setup finishes.
88
+ </div>
89
+ </div>
90
+ <div className="rounded-full border border-white/[0.08] bg-white/[0.03] px-3 py-1 text-[11px] font-700 uppercase tracking-[0.12em] text-text-3/70">
91
+ {visibleStarterKits.length} options
92
+ </div>
93
+ </div>
94
+
95
+ <div className="mt-4 grid gap-3 md:grid-cols-2 xl:grid-cols-3">
96
+ {visibleStarterKits.map((kit) => {
97
+ const active = starterKitId === kit.id
98
+ return (
99
+ <button
100
+ key={kit.id}
101
+ type="button"
102
+ onClick={() => onStarterKitChange(kit.id)}
103
+ className={`rounded-[18px] border px-4 py-4 text-left transition-all duration-200 cursor-pointer ${
104
+ active
105
+ ? 'border-accent-bright/35 bg-accent-soft shadow-[0_0_24px_rgba(99,102,241,0.12)]'
106
+ : 'border-white/[0.08] bg-white/[0.02] hover:border-accent-bright/20 hover:bg-white/[0.04]'
107
+ }`}
108
+ >
109
+ <div className="flex items-start justify-between gap-3">
110
+ <div className="text-[15px] font-display font-700 text-text">{kit.name}</div>
111
+ <span className={`rounded-full px-2 py-1 text-[10px] font-700 uppercase tracking-[0.12em] ${
112
+ active ? 'bg-accent-bright text-black' : 'bg-white/[0.05] text-text-3/80'
113
+ }`}>
114
+ {kit.badge || formatAgentCount(kit.agents.length)}
115
+ </span>
116
+ </div>
117
+ <p className="mt-2 text-[13px] leading-relaxed text-text-2">{kit.description}</p>
118
+ <p className="mt-3 text-[12px] leading-relaxed text-text-3/72">{kit.detail}</p>
119
+ {kit.agents.length > 0 ? (
120
+ <div className="mt-4 flex flex-wrap gap-2">
121
+ {kit.agents.map((agent) => (
122
+ <span
123
+ key={agent.id}
124
+ className="rounded-full border border-white/[0.08] bg-white/[0.03] px-2.5 py-1 text-[11px] text-text-2"
125
+ >
126
+ {agent.name}
127
+ </span>
128
+ ))}
129
+ </div>
130
+ ) : (
131
+ <div className="mt-4 rounded-[12px] border border-dashed border-white/[0.06] bg-white/[0.02] px-3 py-2 text-[11px] text-text-3/70">
132
+ Finish setup without starter agents.
133
+ </div>
134
+ )}
135
+ </button>
136
+ )
137
+ })}
138
+ </div>
139
+ </div>
140
+
141
+ <div className="mt-6 flex items-center justify-center gap-3">
142
+ <button
143
+ onClick={onBack}
144
+ className="px-6 py-3.5 rounded-[14px] border border-white/[0.08] bg-transparent text-text-2 text-[14px] font-display font-500 cursor-pointer hover:bg-white/[0.03] transition-all duration-200"
145
+ >
146
+ Back
147
+ </button>
148
+ <button
149
+ onClick={onContinue}
150
+ className="px-8 py-3.5 rounded-[14px] border-none bg-accent-bright text-white text-[15px] font-display font-600 cursor-pointer hover:brightness-110 active:scale-[0.97] transition-all duration-200 shadow-[0_6px_28px_rgba(99,102,241,0.3)]"
151
+ >
152
+ Continue to Providers
153
+ </button>
154
+ </div>
155
+
156
+ <SkipLink onClick={onSkip} />
157
+ </StepShell>
158
+ )
159
+ }
@@ -2,6 +2,7 @@ import { STEP_ORDER } from './types'
2
2
 
3
3
  const STEP_LABELS: Record<string, string> = {
4
4
  profile: 'You',
5
+ path: 'Start',
5
6
  providers: 'Providers',
6
7
  agents: 'Agents',
7
8
  }
@@ -12,6 +12,7 @@ export function StepProviders({
12
12
  configuredProviderIds,
13
13
  error,
14
14
  canContinue,
15
+ onBack,
15
16
  onSelectProvider,
16
17
  onRemoveProvider,
17
18
  onContinue,
@@ -132,6 +133,14 @@ export function StepProviders({
132
133
  {error && <p className="mt-4 text-[13px] text-red-400">{error}</p>}
133
134
 
134
135
  <div className="mt-6 flex items-center justify-center gap-3">
136
+ <button
137
+ type="button"
138
+ onClick={onBack}
139
+ className="px-6 py-3.5 rounded-[14px] border border-white/[0.08] bg-transparent text-text-2 text-[14px]
140
+ font-display font-500 cursor-pointer hover:bg-white/[0.03] transition-all duration-200"
141
+ >
142
+ Back
143
+ </button>
135
144
  <button
136
145
  onClick={onSkip}
137
146
  className="px-6 py-3.5 rounded-[14px] border border-white/[0.08] bg-transparent text-text-2 text-[14px]
@@ -2,10 +2,10 @@ import assert from 'node:assert/strict'
2
2
  import { test } from 'node:test'
3
3
  import { STEP_ORDER } from './types'
4
4
 
5
- test('STEP_ORDER is [profile, providers, agents]', () => {
6
- assert.deepEqual(STEP_ORDER, ['profile', 'providers', 'agents'])
5
+ test('STEP_ORDER includes the new onboarding path step', () => {
6
+ assert.deepEqual(STEP_ORDER, ['profile', 'path', 'providers', 'agents'])
7
7
  })
8
8
 
9
- test('STEP_ORDER has exactly 3 steps', () => {
10
- assert.equal(STEP_ORDER.length, 3)
9
+ test('STEP_ORDER has exactly 4 steps', () => {
10
+ assert.equal(STEP_ORDER.length, 4)
11
11
  })
@@ -1,7 +1,7 @@
1
1
  import type { GatewayProfile, ProviderId } from '@/types'
2
2
  import type { SetupProvider } from '@/lib/setup-defaults'
3
3
 
4
- export type SetupStep = 'profile' | 'providers' | 'connect' | 'agents' | 'next' | 'done'
4
+ export type SetupStep = 'profile' | 'path' | 'providers' | 'connect' | 'agents' | 'next' | 'done'
5
5
  export type CheckState = 'idle' | 'checking' | 'ok' | 'error'
6
6
 
7
7
  export interface ProviderCheckResponse {
@@ -29,7 +29,7 @@ export interface SetupDoctorResponse {
29
29
  }
30
30
 
31
31
  export interface SetupWizardProps {
32
- onComplete: () => void
32
+ onComplete: (destination?: string) => void
33
33
  }
34
34
 
35
35
  export interface ConfiguredProvider {
@@ -83,7 +83,7 @@ export interface CreatedAgentSummary {
83
83
  providerName: string
84
84
  }
85
85
 
86
- export const STEP_ORDER: SetupStep[] = ['profile', 'providers', 'agents']
86
+ export const STEP_ORDER: SetupStep[] = ['profile', 'path', 'providers', 'agents']
87
87
 
88
88
  export const CONNECTOR_ICONS = [
89
89
  { name: 'Discord', icon: 'D' },
@@ -114,12 +114,25 @@ export interface StepProvidersProps {
114
114
  configuredProviderIds: Set<SetupProvider>
115
115
  error: string
116
116
  canContinue: boolean
117
+ onBack: () => void
117
118
  onSelectProvider: (provider: SetupProvider) => void
118
119
  onRemoveProvider: (id: string) => void
119
120
  onContinue: () => void
120
121
  onSkip: () => void
121
122
  }
122
123
 
124
+ export interface StepPathProps {
125
+ onboardingPath: import('@/lib/setup-defaults').OnboardingPath
126
+ starterKitId: string | null
127
+ intentText: string
128
+ onPathChange: (path: import('@/lib/setup-defaults').OnboardingPath) => void
129
+ onStarterKitChange: (starterKitId: string) => void
130
+ onIntentTextChange: (value: string) => void
131
+ onContinue: () => void
132
+ onBack: () => void
133
+ onSkip: () => void
134
+ }
135
+
123
136
  export interface StepConnectProps {
124
137
  provider: SetupProvider
125
138
  selectedProvider: import('@/lib/setup-defaults').SetupProviderOption
@@ -147,9 +160,13 @@ export interface StepAgentsProps {
147
160
  }
148
161
 
149
162
  export interface StepNextProps {
150
- onAddProvider: () => void
151
- onAddAgent: () => void
163
+ createdAgents: CreatedAgentSummary[]
152
164
  onContinueToDashboard: () => void
165
+ onOpenFirstAgent: () => void
166
+ onOpenProtocols: () => void
167
+ onOpenBuilder: () => void
168
+ onOpenConnectors: () => void
169
+ onOpenUsage: () => void
153
170
  }
154
171
 
155
172
  export interface StepDoneProps {
@@ -2,7 +2,9 @@ import assert from 'node:assert/strict'
2
2
  import { test } from 'node:test'
3
3
  import {
4
4
  stepIndex,
5
+ defaultKitForPath,
5
6
  formatEndpointHost,
7
+ getStarterKitsForPath,
6
8
  isLocalOpenClawEndpoint,
7
9
  resolveOpenClawDashboardUrl,
8
10
  getOpenClawErrorHint,
@@ -21,16 +23,50 @@ test('stepIndex: profile → 0', () => {
21
23
  assert.equal(stepIndex('profile'), 0)
22
24
  })
23
25
 
24
- test('stepIndex: providers → 1', () => {
25
- assert.equal(stepIndex('providers'), 1)
26
+ test('stepIndex: path → 1', () => {
27
+ assert.equal(stepIndex('path'), 1)
26
28
  })
27
29
 
28
- test('stepIndex: connect maps to providers index (1)', () => {
29
- assert.equal(stepIndex('connect'), 1)
30
+ test('stepIndex: providers 2', () => {
31
+ assert.equal(stepIndex('providers'), 2)
30
32
  })
31
33
 
32
- test('stepIndex: agents 2', () => {
33
- assert.equal(stepIndex('agents'), 2)
34
+ test('stepIndex: connect maps to providers index (2)', () => {
35
+ assert.equal(stepIndex('connect'), 2)
36
+ })
37
+
38
+ test('stepIndex: agents → 3', () => {
39
+ assert.equal(stepIndex('agents'), 3)
40
+ })
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // onboarding path defaults
44
+ // ---------------------------------------------------------------------------
45
+
46
+ test('defaultKitForPath returns personal assistant for quick and intent', () => {
47
+ assert.equal(defaultKitForPath('quick'), 'personal_assistant')
48
+ assert.equal(defaultKitForPath('intent'), 'personal_assistant')
49
+ })
50
+
51
+ test('defaultKitForPath returns blank workspace for manual', () => {
52
+ assert.equal(defaultKitForPath('manual'), 'blank_workspace')
53
+ })
54
+
55
+ test('getStarterKitsForPath: quick exposes a reduced starter set', () => {
56
+ const ids = getStarterKitsForPath('quick').map((kit) => kit.id)
57
+ assert.deepEqual(ids, ['personal_assistant', 'research_copilot', 'builder_studio'])
58
+ })
59
+
60
+ test('getStarterKitsForPath: intent stays focused on broad starter shapes', () => {
61
+ const ids = getStarterKitsForPath('intent').map((kit) => kit.id)
62
+ assert.deepEqual(ids, ['personal_assistant', 'research_copilot', 'builder_studio', 'operator_swarm'])
63
+ })
64
+
65
+ test('getStarterKitsForPath: manual keeps the full catalog', () => {
66
+ const ids = new Set(getStarterKitsForPath('manual').map((kit) => kit.id))
67
+ assert.equal(ids.has('blank_workspace'), true)
68
+ assert.equal(ids.has('content_studio'), true)
69
+ assert.equal(ids.has('openclaw_fleet'), true)
34
70
  })
35
71
 
36
72
  // ---------------------------------------------------------------------------
@@ -261,6 +297,37 @@ test('buildStarterDrafts carries custom runtime provider ids alongside custom se
261
297
  }
262
298
  })
263
299
 
300
+ test('buildStarterDrafts injects current intent into starter prompts', () => {
301
+ const cp = makeConfiguredProvider({
302
+ setupProvider: 'openai',
303
+ provider: 'openai',
304
+ defaultModel: 'gpt-4o',
305
+ })
306
+ const drafts = buildStarterDrafts({
307
+ starterKitId: 'personal_assistant',
308
+ intentText: 'Help me run weekly product research and turn it into follow-up tasks.',
309
+ configuredProviders: [cp],
310
+ })
311
+
312
+ assert.match(drafts[0]?.systemPrompt || '', /Current user intent:/)
313
+ assert.match(drafts[0]?.systemPrompt || '', /weekly product research/i)
314
+ })
315
+
316
+ test('buildStarterDrafts creates the delegate team starter pair', () => {
317
+ const cp = makeConfiguredProvider({
318
+ setupProvider: 'openai',
319
+ provider: 'openai',
320
+ defaultModel: 'gpt-4o',
321
+ })
322
+ const drafts = buildStarterDrafts({
323
+ starterKitId: 'operator_swarm',
324
+ intentText: '',
325
+ configuredProviders: [cp],
326
+ })
327
+
328
+ assert.deepEqual(drafts.map((draft) => draft.name), ['Operator', 'Maker'])
329
+ })
330
+
264
331
  test('requiresSetupProviderVerification skips custom providers', () => {
265
332
  assert.equal(requiresSetupProviderVerification('custom'), false)
266
333
  assert.equal(requiresSetupProviderVerification('openclaw'), false)
@@ -2,6 +2,7 @@ import {
2
2
  STARTER_KITS,
3
3
  getDefaultModelForProvider,
4
4
  type OnboardingPath,
5
+ type StarterKit,
5
6
  type SetupProvider,
6
7
  type StarterKitAgentTemplate,
7
8
  } from '@/lib/setup-defaults'
@@ -18,6 +19,18 @@ export function defaultKitForPath(path: OnboardingPath): string {
18
19
  return 'personal_assistant'
19
20
  }
20
21
 
22
+ export function getStarterKitsForPath(path: OnboardingPath): StarterKit[] {
23
+ if (path === 'quick') {
24
+ const quickIds = new Set(['personal_assistant', 'builder_studio', 'research_copilot'])
25
+ return STARTER_KITS.filter((kit) => quickIds.has(kit.id))
26
+ }
27
+ if (path === 'intent') {
28
+ const intentIds = new Set(['personal_assistant', 'builder_studio', 'research_copilot', 'operator_swarm'])
29
+ return STARTER_KITS.filter((kit) => intentIds.has(kit.id))
30
+ }
31
+ return STARTER_KITS
32
+ }
33
+
21
34
  export function applyIntentContext(prompt: string, intentText: string): string {
22
35
  const trimmed = intentText.trim()
23
36
  if (!trimmed) return prompt