@swarmclawai/swarmclaw 1.7.0 → 1.7.1
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 +15 -9
- package/bin/swarmclaw.js +87 -0
- package/package.json +1 -1
- package/src/app/home/page.tsx +19 -10
- package/src/cli/index.js +8 -2
- package/src/cli/index.ts +12 -3
- package/src/components/agents/inspector-panel.tsx +25 -3
- package/src/components/auth/setup-wizard/index.tsx +6 -2
- package/src/components/auth/setup-wizard/step-next.tsx +46 -39
- package/src/components/auth/setup-wizard/step-providers.tsx +76 -142
- package/src/components/auth/setup-wizard/types.ts +5 -2
- package/src/components/auth/setup-wizard/utils.test.ts +0 -19
- package/src/components/auth/setup-wizard/utils.ts +0 -69
- package/src/components/chat/chat-card.tsx +5 -0
- package/src/components/home/home-launchpad.tsx +123 -71
- package/src/lib/home-launchpad.test.ts +1 -31
- package/src/lib/home-launchpad.ts +0 -58
- package/src/lib/providers/cli-utils.test.ts +65 -1
- package/src/lib/providers/cli-utils.ts +22 -1
- package/src/lib/providers/codex-cli.ts +71 -75
- package/src/lib/server/chat-execution/chat-execution-session-sync.test.ts +189 -0
- package/src/lib/server/chat-execution/chat-turn-finalization.ts +26 -19
- package/src/stores/slices/session-slice.test.ts +40 -2
- package/src/stores/slices/session-slice.ts +41 -1
package/README.md
CHANGED
|
@@ -399,24 +399,30 @@ Operational docs: https://swarmclaw.ai/docs/observability
|
|
|
399
399
|
|
|
400
400
|
## Releases
|
|
401
401
|
|
|
402
|
-
### v1.7.
|
|
402
|
+
### v1.7.1 Highlights
|
|
403
|
+
|
|
404
|
+
Republish of v1.7.0 from the correct commit. The v1.7.0 tarball on npm was inadvertently published from a pre-rebase tree that did not include the v1.6.1 codex continuity fixes (PR #62) or the v1.6.2 plan doc. v1.7.1 ships the same coding-agent-roster expansion on top of the correct v1.6.1+ history.
|
|
403
405
|
|
|
404
|
-
|
|
406
|
+
Use v1.7.1 instead of v1.7.0; v1.7.0 has been deprecated on npm.
|
|
405
407
|
|
|
406
|
-
|
|
408
|
+
### v1.7.0 Highlights
|
|
407
409
|
|
|
408
|
-
|
|
410
|
+
Extended CLI provider roster — every coding agent recognized by SwarmSkills now has a corresponding CLI provider in SwarmClaw, routed through a generic streamer when no bespoke parser exists.
|
|
411
|
+
|
|
412
|
+
- **31 new CLI providers.** Aider, Amp, Augment, AdaL, IBM Bob, Cline, CodeBuddy, Command Code, Continue, Cortex Code, Crush, Deep Agents, Firebender, iFlow, Junie, Kilo Code, Kimi, Kode, MCPJam, Mistral Vibe, Mux, Neovate, OpenHands, Pochi, Qoder, Replit Agent, Roo Code, TRAE CN, Warp Agent, Windsurf, and Zencoder are now first-class provider IDs in `ProviderType`.
|
|
409
413
|
- **Generic CLI streamer.** New `streamGenericCliChat` (`src/lib/providers/generic-cli.ts`) spawns the configured binary with the prompt as final argv and emits stdout lines as SSE deltas. Used by the new providers when no bespoke parser is available; existing bespoke parsers (Claude, Codex, Cursor, Gemini, Copilot, Droid, Qwen, OpenCode, Goose) are untouched.
|
|
410
414
|
- **Capability metadata.** `CLI_PROVIDER_CAPABILITIES` (`src/lib/providers/cli-utils.ts`) carries a one-line description for each new provider so the UI and `isCliProvider()` recognize them.
|
|
415
|
+
- **Tests.** New `generic-cli.test.ts` exercises the streamer against `echo` and asserts the missing-binary error path; `cli-utils.test.ts` extends the CLI provider recognition coverage.
|
|
416
|
+
|
|
417
|
+
### v1.6.1 Highlights
|
|
411
418
|
|
|
412
|
-
|
|
419
|
+
Follow-up release for v1.6 with workflow starts, safer metadata handling, A2A discovery polish, and [#61](https://github.com/swarmclawai/swarmclaw/pull/61) by [@latentwill](https://github.com/latentwill). Thanks latentwill!
|
|
413
420
|
|
|
414
|
-
- **First useful action after install.** Setup completion and the home launchpad share the same assistant, workflow, and mission paths.
|
|
415
|
-
- **Provider setup is easier to scan.** The setup wizard groups providers into fast local/no-key starts, recommended API providers, and advanced catalog/custom options, with the readiness check visible before provider details.
|
|
416
421
|
- **Mission and protocol templates for real work.** New starter paths cover codebase review sprints, research bureau scans, content studio cycles, release readiness panels, synthesis panels, and builder review loops.
|
|
417
|
-
- **
|
|
422
|
+
- **Home launchpad paths.** First-run users can choose a self-hosted assistant, visual workflow, or autonomous mission path, with quality actions still one click away.
|
|
423
|
+
- **A2A discovery is easier to integrate.** The canonical `/.well-known/agent-card.json` endpoint now works alongside the legacy API route and hides disabled or trashed agents from public discovery.
|
|
418
424
|
- **Internal metadata stripping is safer.** Side-channel JSON is removed with balanced-object parsing and zod validation so nested payloads are scrubbed without deleting ordinary user JSON.
|
|
419
|
-
- **Browser smoke gate restored.** `npm run test:e2e` runs a Playwright smoke against health, A2A discovery, `/home
|
|
425
|
+
- **Browser smoke gate restored.** `npm run test:e2e` now runs a Playwright smoke against health, A2A discovery, `/home`, and `/quality`, either against a live URL or a temporary local dev server.
|
|
420
426
|
- **OpenCode CLI hang fixed.** OpenCode CLI delegation no longer keeps an inherited stdin pipe open, preventing hangs in non-interactive runs.
|
|
421
427
|
|
|
422
428
|
### v1.6.0 Highlights
|
package/bin/swarmclaw.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
4
4
|
|
|
5
5
|
const path = require('node:path')
|
|
6
|
+
const fs = require('node:fs')
|
|
7
|
+
const os = require('node:os')
|
|
6
8
|
const { spawnSync } = require('node:child_process')
|
|
7
9
|
|
|
8
10
|
// Legacy TS CLI groups/actions that provide richer, command-specific options.
|
|
@@ -142,6 +144,79 @@ Show the installed SwarmClaw package version.
|
|
|
142
144
|
`.trim() + '\n')
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
function readUserServiceSwarmclawHome() {
|
|
148
|
+
const homeDir = process.env.HOME || os.homedir()
|
|
149
|
+
const servicePath = path.join(homeDir, '.config', 'systemd', 'user', 'swarmclaw.service')
|
|
150
|
+
try {
|
|
151
|
+
const text = fs.readFileSync(servicePath, 'utf8')
|
|
152
|
+
const lines = text.split(/\r?\n/)
|
|
153
|
+
for (const line of lines) {
|
|
154
|
+
const trimmed = line.trim()
|
|
155
|
+
if (!trimmed.startsWith('Environment=')) continue
|
|
156
|
+
let value = trimmed.slice('Environment='.length).trim()
|
|
157
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
158
|
+
value = value.slice(1, -1)
|
|
159
|
+
}
|
|
160
|
+
if (!value.startsWith('SWARMCLAW_HOME=')) continue
|
|
161
|
+
const homeValue = value.slice('SWARMCLAW_HOME='.length).trim()
|
|
162
|
+
if (homeValue) return homeValue
|
|
163
|
+
}
|
|
164
|
+
} catch {
|
|
165
|
+
return null
|
|
166
|
+
}
|
|
167
|
+
return null
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function getUserServicePath() {
|
|
171
|
+
const homeDir = process.env.HOME || os.homedir()
|
|
172
|
+
return path.join(homeDir, '.config', 'systemd', 'user', 'swarmclaw.service')
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function hasUserSystemdService() {
|
|
176
|
+
return fs.existsSync(getUserServicePath())
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function runSystemctlUser(args) {
|
|
180
|
+
return spawnSync('systemctl', ['--user', ...args], { stdio: 'inherit', env: process.env })
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function hasServerLifecycleFlags(argv) {
|
|
184
|
+
return argv.some((arg) => (
|
|
185
|
+
arg === '--build'
|
|
186
|
+
|| arg === '-d'
|
|
187
|
+
|| arg === '--detach'
|
|
188
|
+
|| arg === '--port'
|
|
189
|
+
|| arg === '--ws-port'
|
|
190
|
+
|| arg === '--host'
|
|
191
|
+
))
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function handleServiceLifecycle(top, argv) {
|
|
195
|
+
// If the user passed host/port/build flags, fall back to local server-cmd behavior.
|
|
196
|
+
const hasServerFlags = hasServerLifecycleFlags(argv)
|
|
197
|
+
if (hasServerFlags || !hasUserSystemdService()) return false
|
|
198
|
+
|
|
199
|
+
const unit = 'swarmclaw.service'
|
|
200
|
+
if (top === 'run' || top === 'start') {
|
|
201
|
+
const started = runSystemctlUser(['start', unit])
|
|
202
|
+
if (typeof started.status === 'number') process.exitCode = started.status
|
|
203
|
+
return true
|
|
204
|
+
}
|
|
205
|
+
if (top === 'stop') {
|
|
206
|
+
const stopped = runSystemctlUser(['stop', unit])
|
|
207
|
+
if (typeof stopped.status === 'number') process.exitCode = stopped.status
|
|
208
|
+
return true
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return false
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function applyServiceHomeDefault() {
|
|
215
|
+
if (typeof process.env.SWARMCLAW_HOME === 'string' && process.env.SWARMCLAW_HOME.trim()) return
|
|
216
|
+
const serviceHome = readUserServiceSwarmclawHome()
|
|
217
|
+
if (serviceHome) process.env.SWARMCLAW_HOME = serviceHome
|
|
218
|
+
}
|
|
219
|
+
|
|
145
220
|
async function runMappedCli(argv) {
|
|
146
221
|
const cliPath = path.join(__dirname, '..', 'src', 'cli', 'index.js')
|
|
147
222
|
const cliModule = await import(cliPath)
|
|
@@ -196,6 +271,8 @@ async function runHelp(argv) {
|
|
|
196
271
|
}
|
|
197
272
|
|
|
198
273
|
async function main() {
|
|
274
|
+
applyServiceHomeDefault()
|
|
275
|
+
|
|
199
276
|
const argv = process.argv.slice(2)
|
|
200
277
|
const top = argv[0]
|
|
201
278
|
|
|
@@ -233,10 +310,20 @@ async function main() {
|
|
|
233
310
|
}
|
|
234
311
|
}
|
|
235
312
|
if (top === 'run' || top === 'start') {
|
|
313
|
+
if (handleServiceLifecycle(top, argv.slice(1))) return
|
|
236
314
|
await require('./server-cmd.js').main(argv.slice(1))
|
|
237
315
|
return
|
|
238
316
|
}
|
|
239
317
|
if (top === 'status' || top === 'stop') {
|
|
318
|
+
if (top === 'status' && hasUserSystemdService() && !hasServerLifecycleFlags(argv.slice(1))) {
|
|
319
|
+
const serviceStatus = runSystemctlUser(['status', 'swarmclaw.service', '--no-pager'])
|
|
320
|
+
const apiStatusCode = await runMappedCli(['system-status', 'get'])
|
|
321
|
+
const serviceCode = typeof serviceStatus.status === 'number' ? serviceStatus.status : 1
|
|
322
|
+
const apiCode = typeof apiStatusCode === 'number' ? apiStatusCode : 1
|
|
323
|
+
process.exitCode = serviceCode !== 0 ? serviceCode : apiCode
|
|
324
|
+
return
|
|
325
|
+
}
|
|
326
|
+
if (handleServiceLifecycle(top, argv.slice(1))) return
|
|
240
327
|
await require('./server-cmd.js').main([top, ...argv.slice(1)])
|
|
241
328
|
return
|
|
242
329
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmclawai/swarmclaw",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "Build and run autonomous AI agents with OpenClaw, Hermes, multiple model providers, orchestration, delegation, memory, skills, schedules, and chat connectors.",
|
|
5
5
|
"main": "electron-dist/main.js",
|
|
6
6
|
"license": "MIT",
|
package/src/app/home/page.tsx
CHANGED
|
@@ -14,13 +14,7 @@ import { useNavigate } from '@/lib/app/navigation'
|
|
|
14
14
|
import { safeStorageGet, safeStorageRemove } from '@/lib/app/safe-storage'
|
|
15
15
|
import { isLocalhostBrowser, isVisibleSessionForViewer } from '@/lib/observability/local-observability'
|
|
16
16
|
import { getSessionLastMessage } from '@/lib/chat/session-summary'
|
|
17
|
-
import {
|
|
18
|
-
deriveHomeMode,
|
|
19
|
-
HOME_LAUNCHPAD_AFTER_SETUP_KEY,
|
|
20
|
-
resolveLaunchPathHref,
|
|
21
|
-
type LaunchPathAction,
|
|
22
|
-
type LaunchPathId,
|
|
23
|
-
} from '@/lib/home-launchpad'
|
|
17
|
+
import { DEFAULT_BUILDER_ROUTE, deriveHomeMode, HOME_LAUNCHPAD_AFTER_SETUP_KEY } from '@/lib/home-launchpad'
|
|
24
18
|
import { getNotificationActivityAt, getNotificationOccurrenceCount } from '@/lib/notifications/notification-utils'
|
|
25
19
|
import { timeAgo, timeUntil } from '@/lib/time-format'
|
|
26
20
|
import type { Agent, Session, BoardTask, AppNotification, ActivityEntry } from '@/types'
|
|
@@ -260,8 +254,16 @@ export default function HomePage() {
|
|
|
260
254
|
todayCost,
|
|
261
255
|
})
|
|
262
256
|
|
|
263
|
-
const
|
|
264
|
-
|
|
257
|
+
const openFirstAgent = () => {
|
|
258
|
+
if (firstAgent) {
|
|
259
|
+
navigateTo('agents', firstAgent.id)
|
|
260
|
+
return
|
|
261
|
+
}
|
|
262
|
+
navigateTo('agents')
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const openBuilder = () => {
|
|
266
|
+
router.push(DEFAULT_BUILDER_ROUTE)
|
|
265
267
|
}
|
|
266
268
|
|
|
267
269
|
if (homeMode === 'launchpad') {
|
|
@@ -276,8 +278,15 @@ export default function HomePage() {
|
|
|
276
278
|
scheduleCount={scheduleCount}
|
|
277
279
|
connectorCount={connectorCount}
|
|
278
280
|
todayCost={todayCost}
|
|
279
|
-
|
|
281
|
+
onOpenFirstAgent={openFirstAgent}
|
|
282
|
+
onOpenProtocols={() => navigateTo('protocols')}
|
|
283
|
+
onOpenBuilder={openBuilder}
|
|
284
|
+
onOpenConnectors={() => navigateTo('connectors')}
|
|
280
285
|
onOpenUsage={() => navigateTo('usage')}
|
|
286
|
+
onRunEvalSuite={() => navigateTo('quality')}
|
|
287
|
+
onReviewApprovals={() => navigateTo('quality')}
|
|
288
|
+
onInspectFailedRuns={() => navigateTo('quality')}
|
|
289
|
+
onStartReleaseQaMission={() => navigateTo('missions')}
|
|
281
290
|
/>
|
|
282
291
|
</div>
|
|
283
292
|
</MainContent>
|
package/src/cli/index.js
CHANGED
|
@@ -1001,8 +1001,14 @@ function resolveAccessKey(opts, env, cwd) {
|
|
|
1001
1001
|
const envKey = env.SWARMCLAW_API_KEY || env.SC_ACCESS_KEY || env.SWARMCLAW_ACCESS_KEY || ''
|
|
1002
1002
|
if (envKey) return String(envKey).trim()
|
|
1003
1003
|
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1004
|
+
const keyLocations = [
|
|
1005
|
+
path.join(cwd, 'platform-api-key.txt'),
|
|
1006
|
+
]
|
|
1007
|
+
const homeDir = String(env.SWARMCLAW_HOME || '').trim()
|
|
1008
|
+
if (homeDir) keyLocations.push(path.join(homeDir, 'platform-api-key.txt'))
|
|
1009
|
+
|
|
1010
|
+
for (const keyFile of keyLocations) {
|
|
1011
|
+
if (!fs.existsSync(keyFile)) continue
|
|
1006
1012
|
const content = fs.readFileSync(keyFile, 'utf8').trim()
|
|
1007
1013
|
if (content) return content
|
|
1008
1014
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -45,9 +45,18 @@ function resolveDefaultAccessKey(cwd: string = process.cwd()): string {
|
|
|
45
45
|
).trim()
|
|
46
46
|
if (envKey) return envKey
|
|
47
47
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
const keyLocations = [
|
|
49
|
+
path.join(cwd, 'platform-api-key.txt'),
|
|
50
|
+
]
|
|
51
|
+
const serviceHome = (process.env.SWARMCLAW_HOME || '').trim()
|
|
52
|
+
if (serviceHome) keyLocations.push(path.join(serviceHome, 'platform-api-key.txt'))
|
|
53
|
+
|
|
54
|
+
for (const keyFile of keyLocations) {
|
|
55
|
+
if (!fs.existsSync(keyFile)) continue
|
|
56
|
+
const value = fs.readFileSync(keyFile, 'utf8').trim()
|
|
57
|
+
if (value) return value
|
|
58
|
+
}
|
|
59
|
+
return ''
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
const DEFAULT_ACCESS_KEY = resolveDefaultAccessKey()
|
|
@@ -4,9 +4,9 @@ import { DEFAULT_HEARTBEAT_INTERVAL_SEC } from '@/lib/runtime/heartbeat-defaults
|
|
|
4
4
|
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
|
|
5
5
|
import type { Agent, MemoryEntry, Session } from '@/types'
|
|
6
6
|
import { useAppStore } from '@/stores/use-app-store'
|
|
7
|
+
import { selectActiveSessionId } from '@/stores/slices/session-slice'
|
|
7
8
|
import { useChatStore } from '@/stores/use-chat-store'
|
|
8
9
|
import { api } from '@/lib/app/api-client'
|
|
9
|
-
import { sortSessionsNewestFirst } from '@/lib/chat/new-session'
|
|
10
10
|
import { AgentAvatar } from './agent-avatar'
|
|
11
11
|
import { AgentFilesEditor } from './agent-files-editor'
|
|
12
12
|
import { OpenClawSkillsPanel } from './openclaw-skills-panel'
|
|
@@ -901,6 +901,7 @@ function QuickActionsSection({ agent, session }: { agent: Agent; session: Sessio
|
|
|
901
901
|
|
|
902
902
|
function SessionsSection({ agent }: { agent: Agent }) {
|
|
903
903
|
const sessions = useAppStore((s) => s.sessions)
|
|
904
|
+
const activeSessionId = useAppStore(selectActiveSessionId)
|
|
904
905
|
const connectors = useAppStore((s) => s.connectors)
|
|
905
906
|
const agents = useAppStore((s) => s.agents)
|
|
906
907
|
const setCurrentAgent = useAppStore((s) => s.setCurrentAgent)
|
|
@@ -908,7 +909,19 @@ function SessionsSection({ agent }: { agent: Agent }) {
|
|
|
908
909
|
const setInspectorOpen = useAppStore((s) => s.setInspectorOpen)
|
|
909
910
|
|
|
910
911
|
const agentSessions = useMemo(() => {
|
|
911
|
-
|
|
912
|
+
const getLastMessageTime = (session: Session): number => {
|
|
913
|
+
const summaryTime = session.lastMessageSummary?.time
|
|
914
|
+
if (typeof summaryTime === 'number' && Number.isFinite(summaryTime)) return summaryTime
|
|
915
|
+
if (Array.isArray(session.messages) && session.messages.length > 0) {
|
|
916
|
+
const last = session.messages[session.messages.length - 1]
|
|
917
|
+
if (typeof last?.time === 'number' && Number.isFinite(last.time)) return last.time
|
|
918
|
+
}
|
|
919
|
+
return session.lastActiveAt || session.createdAt || 0
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
return Object.values(sessions)
|
|
923
|
+
.filter((s) => s.agentId === agent.id)
|
|
924
|
+
.sort((left, right) => getLastMessageTime(right) - getLastMessageTime(left))
|
|
912
925
|
}, [sessions, agent.id])
|
|
913
926
|
|
|
914
927
|
if (agentSessions.length === 0) return null
|
|
@@ -918,6 +931,7 @@ function SessionsSection({ agent }: { agent: Agent }) {
|
|
|
918
931
|
<SectionLabel>Sessions ({agentSessions.length})</SectionLabel>
|
|
919
932
|
<div className="flex flex-col gap-1.5">
|
|
920
933
|
{agentSessions.map((s) => {
|
|
934
|
+
const isSelected = s.id === activeSessionId
|
|
921
935
|
const connector = getSessionConnector(s, connectors)
|
|
922
936
|
const delegatedByAgentId = (s as unknown as Record<string, unknown>).delegatedByAgentId as string | undefined
|
|
923
937
|
const delegatedBy = delegatedByAgentId ? agents[delegatedByAgentId] : null
|
|
@@ -934,7 +948,10 @@ function SessionsSection({ agent }: { agent: Agent }) {
|
|
|
934
948
|
}
|
|
935
949
|
}).catch(() => {})
|
|
936
950
|
}}
|
|
937
|
-
className=
|
|
951
|
+
className={`flex items-center gap-2 w-full py-1.5 px-2 rounded-[8px] border-none cursor-pointer transition-colors text-left
|
|
952
|
+
${isSelected
|
|
953
|
+
? 'bg-accent-soft/70 ring-1 ring-accent-bright/25'
|
|
954
|
+
: 'bg-transparent hover:bg-white/[0.04]'}`}
|
|
938
955
|
>
|
|
939
956
|
{connector ? (
|
|
940
957
|
<ConnectorPlatformIcon platform={connector.platform} size={14} />
|
|
@@ -944,6 +961,11 @@ function SessionsSection({ agent }: { agent: Agent }) {
|
|
|
944
961
|
</svg>
|
|
945
962
|
)}
|
|
946
963
|
<span className="text-[12px] text-text-2 truncate flex-1">{s.name}</span>
|
|
964
|
+
{isSelected && (
|
|
965
|
+
<span className="text-[9px] font-700 uppercase tracking-[0.08em] text-accent-bright bg-accent-bright/15 px-1.5 py-0.5 rounded-[6px] shrink-0">
|
|
966
|
+
Selected
|
|
967
|
+
</span>
|
|
968
|
+
)}
|
|
947
969
|
{delegatedBy && (
|
|
948
970
|
<span className="text-[9px] text-amber-300/60 font-600 shrink-0">from {delegatedBy.name}</span>
|
|
949
971
|
)}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type OnboardingPath,
|
|
12
12
|
type SetupProvider,
|
|
13
13
|
} from '@/lib/setup-defaults'
|
|
14
|
-
import {
|
|
14
|
+
import { DEFAULT_BUILDER_ROUTE } from '@/lib/home-launchpad'
|
|
15
15
|
import type {
|
|
16
16
|
SetupStep,
|
|
17
17
|
SetupWizardProps,
|
|
@@ -482,7 +482,11 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
482
482
|
<StepNext
|
|
483
483
|
createdAgents={createdAgents}
|
|
484
484
|
onContinueToDashboard={() => finishSetup('/home')}
|
|
485
|
-
|
|
485
|
+
onOpenFirstAgent={() => finishSetup(createdAgents[0]?.id ? `/agents/${encodeURIComponent(createdAgents[0].id)}` : '/agents')}
|
|
486
|
+
onOpenProtocols={() => finishSetup('/protocols')}
|
|
487
|
+
onOpenBuilder={() => finishSetup(DEFAULT_BUILDER_ROUTE)}
|
|
488
|
+
onOpenConnectors={() => finishSetup('/connectors')}
|
|
489
|
+
onOpenUsage={() => finishSetup('/usage')}
|
|
486
490
|
/>
|
|
487
491
|
)}
|
|
488
492
|
|
|
@@ -1,48 +1,19 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { LaunchActionCard } from '@/components/shared/launch-action-card'
|
|
4
4
|
import type { StepNextProps } from './types'
|
|
5
5
|
import { StepShell } from './shared'
|
|
6
6
|
|
|
7
|
-
function PathCard({
|
|
8
|
-
card,
|
|
9
|
-
onAction,
|
|
10
|
-
}: {
|
|
11
|
-
card: LaunchPathCardCopy
|
|
12
|
-
onAction: (id: LaunchPathId, action: LaunchPathAction) => void
|
|
13
|
-
}) {
|
|
14
|
-
return (
|
|
15
|
-
<div className="flex min-h-[220px] flex-col rounded-[18px] border border-white/[0.07] bg-white/[0.03] p-5 text-left">
|
|
16
|
-
<div className="text-[11px] font-700 uppercase tracking-[0.12em] text-text-3/55">{card.kicker}</div>
|
|
17
|
-
<div className="mt-3 text-[18px] font-display font-700 tracking-normal text-text">{card.title}</div>
|
|
18
|
-
<p className="mt-2 flex-1 text-[13px] leading-relaxed text-text-3/72">{card.description}</p>
|
|
19
|
-
<div className="mt-5 flex flex-wrap gap-2">
|
|
20
|
-
<button
|
|
21
|
-
type="button"
|
|
22
|
-
onClick={() => onAction(card.id, 'primary')}
|
|
23
|
-
className="rounded-[10px] bg-accent-bright px-3.5 py-2 text-[12px] font-display font-700 text-black transition-opacity hover:opacity-90"
|
|
24
|
-
>
|
|
25
|
-
{card.primaryLabel}
|
|
26
|
-
</button>
|
|
27
|
-
<button
|
|
28
|
-
type="button"
|
|
29
|
-
onClick={() => onAction(card.id, 'secondary')}
|
|
30
|
-
className="rounded-[10px] border border-white/[0.08] bg-white/[0.04] px-3.5 py-2 text-[12px] font-display font-700 text-text-2 transition-colors hover:bg-white/[0.08]"
|
|
31
|
-
>
|
|
32
|
-
{card.secondaryLabel}
|
|
33
|
-
</button>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
7
|
export function StepNext({
|
|
40
8
|
createdAgents,
|
|
41
9
|
onContinueToDashboard,
|
|
42
|
-
|
|
10
|
+
onOpenFirstAgent,
|
|
11
|
+
onOpenProtocols,
|
|
12
|
+
onOpenBuilder,
|
|
13
|
+
onOpenConnectors,
|
|
14
|
+
onOpenUsage,
|
|
43
15
|
}: StepNextProps) {
|
|
44
16
|
const firstAgent = createdAgents[0] || null
|
|
45
|
-
const launchPathCards = getLaunchPathCards({ firstAgentName: firstAgent?.name })
|
|
46
17
|
|
|
47
18
|
return (
|
|
48
19
|
<StepShell wide>
|
|
@@ -58,10 +29,46 @@ export function StepNext({
|
|
|
58
29
|
: 'You finished setup without starter agents, so the launch options below focus on wiring up the rest of the workspace.'}
|
|
59
30
|
</p>
|
|
60
31
|
|
|
61
|
-
<div className="grid gap-3 xl:grid-cols-3 mb-8">
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
+
/>
|
|
65
72
|
</div>
|
|
66
73
|
|
|
67
74
|
<button
|