@tonyclaw/agent-inspector 4.0.1 → 4.0.3
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/.output/backend/nitro.json +1 -1
- package/.output/cli.js +193 -110
- package/.output/server/_ssr/index.mjs +1 -1
- package/.output/server/_ssr/{router-CTHqmroT.mjs → router-ChILzhmz.mjs} +92 -4
- package/.output/server/index.mjs +1 -1
- package/.output/ui/assets/{CompareDrawer-L3n4J-Or.js → CompareDrawer-Co3cUF_I.js} +1 -1
- package/.output/ui/assets/{InspectorPet-D5o_3OZS.js → InspectorPet-jFcrL37X.js} +1 -1
- package/.output/ui/assets/{ProxyViewerContainer-Ocagx75S.js → ProxyViewerContainer-BPzt_VpM.js} +4 -4
- package/.output/ui/assets/{ReplayDialog-Bk7x1h-y.js → ReplayDialog-C6O_zuwI.js} +1 -1
- package/.output/ui/assets/{RequestAnatomy-U4lzL7Sc.js → RequestAnatomy-Ca6NvB7L.js} +1 -1
- package/.output/ui/assets/{ResponseView-LOWfvBLK.js → ResponseView-BzqKcveJ.js} +1 -1
- package/.output/ui/assets/{StreamingChunkSequence-DPfsrrXQ.js → StreamingChunkSequence-9pCZIsS_.js} +1 -1
- package/.output/ui/assets/{_sessionId-0MlWS-CO.js → _sessionId-BMP3KVGR.js} +1 -1
- package/.output/ui/assets/{_sessionId-OdX2Jvt1.js → _sessionId-y4eRoT1H.js} +1 -1
- package/.output/ui/assets/{index-Ea-c8hPg.js → index-CH5w-haG.js} +1 -1
- package/.output/ui/assets/{index-zVVS53Hd.js → index-CmocEhyU.js} +1 -1
- package/.output/ui/assets/{index-Du4qNOOt.js → index-DT8sMJ_n.js} +2 -2
- package/.output/ui/assets/{index-gvFj_9K6.js → index-bfsbIRZa.js} +1 -1
- package/.output/ui/assets/{json-viewer-C1WAMzg3.js → json-viewer-BfFOSDG5.js} +1 -1
- package/.output/ui/assets/{jszip.min-B8AKu2zm.js → jszip.min-BkbVkOsp.js} +1 -1
- package/.output/ui/index.html +1 -1
- package/package.json +5 -10
- package/src/assets/IDE/claudecode-color.svg +0 -1
- package/src/assets/IDE/codex-color.svg +0 -1
- package/src/assets/IDE/opencode.svg +0 -1
- package/src/assets/IDE/xiaomimimo.svg +0 -1
- package/src/assets/favicon.svg +0 -21
- package/src/assets/logos/alibaba.svg +0 -1
- package/src/assets/logos/anthropic.svg +0 -1
- package/src/assets/logos/claude-code.svg +0 -4
- package/src/assets/logos/deepseek.svg +0 -1
- package/src/assets/logos/minimax.jpeg +0 -0
- package/src/assets/logos/openai.svg +0 -1
- package/src/assets/logos/opencode.svg +0 -4
- package/src/assets/logos/qwen.webp +0 -0
- package/src/assets/logos/zhipuai.svg +0 -219
- package/src/backend/router.tsx +0 -36
- package/src/backend/routes/$.ts +0 -26
- package/src/backend/routes/__root.ts +0 -4
- package/src/backend/routes/api/-instances.ts +0 -7
- package/src/backend/routes/api/alerts.summary.ts +0 -28
- package/src/backend/routes/api/alerts.ts +0 -70
- package/src/backend/routes/api/config.paths.ts +0 -14
- package/src/backend/routes/api/config.ts +0 -73
- package/src/backend/routes/api/ecosystem.packages.$packageId.help.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.$packageId.install.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.$packageId.runner-presets.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.$packageId.upgrade.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.ts +0 -21
- package/src/backend/routes/api/ecosystem.recipes.$recipeId.run.ts +0 -11
- package/src/backend/routes/api/ecosystem.tasks.$taskId.ts +0 -16
- package/src/backend/routes/api/ecosystem.tasks.ts +0 -12
- package/src/backend/routes/api/groups.$groupId.evidence.ts +0 -55
- package/src/backend/routes/api/groups.$groupId.sessions.ts +0 -50
- package/src/backend/routes/api/groups.$groupId.ts +0 -93
- package/src/backend/routes/api/groups.ts +0 -79
- package/src/backend/routes/api/health.ts +0 -22
- package/src/backend/routes/api/instances.$name.connection.ts +0 -12
- package/src/backend/routes/api/instances.$name.restart.ts +0 -23
- package/src/backend/routes/api/instances.$name.start.ts +0 -18
- package/src/backend/routes/api/instances.$name.stop.ts +0 -23
- package/src/backend/routes/api/instances.$name.ts +0 -12
- package/src/backend/routes/api/instances.ts +0 -16
- package/src/backend/routes/api/knowledge.candidates.$candidateId.promote.ts +0 -32
- package/src/backend/routes/api/knowledge.candidates.$candidateId.ts +0 -50
- package/src/backend/routes/api/knowledge.candidates.ts +0 -10
- package/src/backend/routes/api/knowledge.project-context.ts +0 -29
- package/src/backend/routes/api/knowledge.search.ts +0 -62
- package/src/backend/routes/api/knowledge.sessions.$sessionId.candidates.ts +0 -26
- package/src/backend/routes/api/logs.$id.body.ts +0 -58
- package/src/backend/routes/api/logs.$id.chunks.ts +0 -37
- package/src/backend/routes/api/logs.$id.replay.ts +0 -297
- package/src/backend/routes/api/logs.$id.ts +0 -23
- package/src/backend/routes/api/logs.import.ts +0 -39
- package/src/backend/routes/api/logs.stream.ts +0 -174
- package/src/backend/routes/api/logs.ts +0 -214
- package/src/backend/routes/api/mcp.ts +0 -25
- package/src/backend/routes/api/models.ts +0 -10
- package/src/backend/routes/api/pi-agent.ts +0 -29
- package/src/backend/routes/api/providers.$providerId.model-metadata.ts +0 -173
- package/src/backend/routes/api/providers.$providerId.test.log.ts +0 -342
- package/src/backend/routes/api/providers.$providerId.ts +0 -111
- package/src/backend/routes/api/providers.export.ts +0 -44
- package/src/backend/routes/api/providers.import.ts +0 -81
- package/src/backend/routes/api/providers.scan.ts +0 -28
- package/src/backend/routes/api/providers.ts +0 -102
- package/src/backend/routes/api/runs.$runId.evidence.ts +0 -55
- package/src/backend/routes/api/runs.$runId.ts +0 -50
- package/src/backend/routes/api/runs.ts +0 -62
- package/src/backend/routes/api/runtime.ts +0 -46
- package/src/backend/routes/api/sessions.ts +0 -51
- package/src/backend/routes/api/storage.ts +0 -56
- package/src/backend/routes/livez.ts +0 -13
- package/src/backend/routes/metrics.ts +0 -14
- package/src/backend/routes/proxy/$.ts +0 -15
- package/src/backend/routes/readyz.ts +0 -18
- package/src/backend/start.ts +0 -10
- package/src/cli/alias.ts +0 -431
- package/src/cli/detect-tools.ts +0 -123
- package/src/cli/doctor.ts +0 -836
- package/src/cli/instance.ts +0 -1071
- package/src/cli/instanceApi.ts +0 -213
- package/src/cli/instanceArgs.ts +0 -301
- package/src/cli/instanceControl.ts +0 -191
- package/src/cli/instanceModel.ts +0 -276
- package/src/cli/instanceRegistry.ts +0 -731
- package/src/cli/networkHints.ts +0 -170
- package/src/cli/onboard.ts +0 -1668
- package/src/cli/onboardTarget.ts +0 -228
- package/src/cli/rustBackendPackage.ts +0 -458
- package/src/cli/startupOutput.ts +0 -16
- package/src/cli/templates/codex-skill-onboard.ts +0 -320
- package/src/cli/templates/command-onboard.ts +0 -25
- package/src/cli/templates/skill-onboard.ts +0 -625
- package/src/cli.ts +0 -1433
- package/src/components/OnboardingBanner.tsx +0 -115
- package/src/components/ProxyViewer.tsx +0 -2259
- package/src/components/ProxyViewerContainer.tsx +0 -1076
- package/src/components/alerts/AlertsDialog.tsx +0 -615
- package/src/components/clients/ClientLogo.tsx +0 -175
- package/src/components/ecosystem/AgentLabDialog.tsx +0 -947
- package/src/components/errors/SafeErrorBoundary.tsx +0 -201
- package/src/components/groups/GroupsDialog.tsx +0 -1304
- package/src/components/inspector-pet/InspectorPet.tsx +0 -398
- package/src/components/inspector-pet/InspectorPetCrab3D.tsx +0 -455
- package/src/components/inspector-pet/inspectorPetLogic.ts +0 -272
- package/src/components/pi-agent/PiAgentPanel.tsx +0 -446
- package/src/components/pi-agent/piAgentChatLogic.ts +0 -273
- package/src/components/providers/ImportWizardDialog.tsx +0 -281
- package/src/components/providers/ProviderCard.tsx +0 -347
- package/src/components/providers/ProviderForm.tsx +0 -1183
- package/src/components/providers/ProviderLogo.tsx +0 -122
- package/src/components/providers/ProviderTestResultsView.tsx +0 -734
- package/src/components/providers/ProvidersPanel.tsx +0 -714
- package/src/components/providers/SettingsDialog.tsx +0 -1042
- package/src/components/providers/providerFormCapabilities.ts +0 -36
- package/src/components/proxy-viewer/AgentTraceSummary.tsx +0 -902
- package/src/components/proxy-viewer/AnswerMarkdown.tsx +0 -51
- package/src/components/proxy-viewer/ApplicationBar.tsx +0 -123
- package/src/components/proxy-viewer/CompareDrawer.tsx +0 -984
- package/src/components/proxy-viewer/ConversationGroup.tsx +0 -208
- package/src/components/proxy-viewer/ConversationGroupList.tsx +0 -652
- package/src/components/proxy-viewer/ConversationHeader.tsx +0 -429
- package/src/components/proxy-viewer/LiveConnectionStatus.tsx +0 -186
- package/src/components/proxy-viewer/LogEntry.tsx +0 -1419
- package/src/components/proxy-viewer/LogEntryHeader.tsx +0 -596
- package/src/components/proxy-viewer/ProviderLogoStack.tsx +0 -57
- package/src/components/proxy-viewer/RawExportWarning.tsx +0 -77
- package/src/components/proxy-viewer/ReplayDialog.tsx +0 -636
- package/src/components/proxy-viewer/RequestToolsPanel.tsx +0 -299
- package/src/components/proxy-viewer/ResponseView.tsx +0 -202
- package/src/components/proxy-viewer/SessionLoadProgressBar.tsx +0 -61
- package/src/components/proxy-viewer/StreamingChunkSequence.tsx +0 -265
- package/src/components/proxy-viewer/ThreadConnector.tsx +0 -165
- package/src/components/proxy-viewer/ToolTraceEvents.tsx +0 -64
- package/src/components/proxy-viewer/TurnGroup.tsx +0 -383
- package/src/components/proxy-viewer/TurnGroupList.tsx +0 -156
- package/src/components/proxy-viewer/accessibility.ts +0 -8
- package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +0 -887
- package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +0 -222
- package/src/components/proxy-viewer/anatomy/contextIntelligence.ts +0 -737
- package/src/components/proxy-viewer/anatomy/sessionContextSummary.ts +0 -268
- package/src/components/proxy-viewer/anatomy/tokenEstimate.ts +0 -53
- package/src/components/proxy-viewer/anatomy/types.ts +0 -41
- package/src/components/proxy-viewer/anatomy/useAnatomyJump.ts +0 -114
- package/src/components/proxy-viewer/bodyHydration.ts +0 -123
- package/src/components/proxy-viewer/cacheTrend.ts +0 -50
- package/src/components/proxy-viewer/diff/DiffView.tsx +0 -321
- package/src/components/proxy-viewer/diff/computeDiff.ts +0 -178
- package/src/components/proxy-viewer/diff/index.ts +0 -3
- package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +0 -194
- package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +0 -81
- package/src/components/proxy-viewer/formats/anthropic/thinkingExtract.ts +0 -21
- package/src/components/proxy-viewer/formats/index.tsx +0 -47
- package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +0 -442
- package/src/components/proxy-viewer/index.ts +0 -9
- package/src/components/proxy-viewer/lazy.ts +0 -41
- package/src/components/proxy-viewer/liveConnectionState.ts +0 -158
- package/src/components/proxy-viewer/log-formats/anthropic.ts +0 -191
- package/src/components/proxy-viewer/log-formats/index.ts +0 -23
- package/src/components/proxy-viewer/log-formats/openai.ts +0 -256
- package/src/components/proxy-viewer/log-formats/types.ts +0 -40
- package/src/components/proxy-viewer/log-formats/unknown.ts +0 -18
- package/src/components/proxy-viewer/logEntryVisibility.ts +0 -73
- package/src/components/proxy-viewer/logFocus.ts +0 -54
- package/src/components/proxy-viewer/proxyViewerContainerLogic.ts +0 -124
- package/src/components/proxy-viewer/proxyViewerLogic.ts +0 -488
- package/src/components/proxy-viewer/replayComparison.ts +0 -131
- package/src/components/proxy-viewer/requestDiff.ts +0 -277
- package/src/components/proxy-viewer/requestTools.ts +0 -220
- package/src/components/proxy-viewer/useCopyFeedback.ts +0 -38
- package/src/components/proxy-viewer/useKeyboardNavigation.ts +0 -232
- package/src/components/proxy-viewer/viewerState.ts +0 -176
- package/src/components/ui/badge.tsx +0 -47
- package/src/components/ui/button.tsx +0 -47
- package/src/components/ui/collapsible.tsx +0 -21
- package/src/components/ui/confirm-dialog.tsx +0 -51
- package/src/components/ui/crab-logo.tsx +0 -45
- package/src/components/ui/crab-variants.tsx +0 -467
- package/src/components/ui/dialog.tsx +0 -130
- package/src/components/ui/icon-trigger.ts +0 -2
- package/src/components/ui/json-viewer-bulk.ts +0 -132
- package/src/components/ui/json-viewer.tsx +0 -508
- package/src/components/ui/scroll-area.tsx +0 -54
- package/src/components/ui/select.tsx +0 -178
- package/src/components/ui/separator.tsx +0 -28
- package/src/components/ui/tabs.tsx +0 -88
- package/src/components/ui/tooltip.tsx +0 -51
- package/src/components/ui/transient-toast.tsx +0 -105
- package/src/contracts/anthropic.ts +0 -230
- package/src/contracts/index.ts +0 -59
- package/src/contracts/json.ts +0 -37
- package/src/contracts/log.ts +0 -139
- package/src/contracts/openai.ts +0 -267
- package/src/index.css +0 -11
- package/src/knowledge/candidateStore.ts +0 -94
- package/src/knowledge/distiller.ts +0 -98
- package/src/knowledge/openclawClient.ts +0 -161
- package/src/knowledge/openclawGatewayClient.ts +0 -249
- package/src/knowledge/openclawMarkdown.ts +0 -146
- package/src/knowledge/redactor.ts +0 -80
- package/src/knowledge/types.ts +0 -83
- package/src/lib/alertContract.ts +0 -76
- package/src/lib/apiClient.ts +0 -166
- package/src/lib/apiFormat.ts +0 -29
- package/src/lib/backendImplementation.ts +0 -16
- package/src/lib/basePath.ts +0 -107
- package/src/lib/browserRuntimeContract.ts +0 -124
- package/src/lib/browserRuntimeResolver.ts +0 -333
- package/src/lib/chunkLoadRecovery.ts +0 -83
- package/src/lib/claudeCodeStrip.ts +0 -98
- package/src/lib/clipboard.ts +0 -67
- package/src/lib/codingAgentEndpoints.ts +0 -54
- package/src/lib/ecosystemContract.ts +0 -130
- package/src/lib/export-logs.ts +0 -287
- package/src/lib/groupContract.ts +0 -166
- package/src/lib/instanceContract.ts +0 -239
- package/src/lib/jsonFile.ts +0 -46
- package/src/lib/logImportContract.ts +0 -12
- package/src/lib/managedInstance.ts +0 -112
- package/src/lib/mask.ts +0 -4
- package/src/lib/objectUtils.ts +0 -22
- package/src/lib/piAgentContract.ts +0 -102
- package/src/lib/providerContract.ts +0 -125
- package/src/lib/providerImportContract.ts +0 -27
- package/src/lib/providerModelMetadata.ts +0 -458
- package/src/lib/providerTestContract.ts +0 -170
- package/src/lib/providerTestPrompt.ts +0 -100
- package/src/lib/publicBasePathContext.ts +0 -137
- package/src/lib/resourceLimits.ts +0 -345
- package/src/lib/runContract.ts +0 -164
- package/src/lib/runtimeConfig.ts +0 -43
- package/src/lib/safeDiagnostic.ts +0 -38
- package/src/lib/safeFetch.ts +0 -508
- package/src/lib/serverPort.ts +0 -47
- package/src/lib/sessionInfoContract.ts +0 -78
- package/src/lib/sessionUrl.ts +0 -46
- package/src/lib/ssrfGuard.ts +0 -133
- package/src/lib/stopReason.ts +0 -130
- package/src/lib/themeMode.ts +0 -41
- package/src/lib/timeDisplay.ts +0 -22
- package/src/lib/toolTrace.ts +0 -290
- package/src/lib/uiScale.ts +0 -117
- package/src/lib/unknown.ts +0 -27
- package/src/lib/upstreamUrl.ts +0 -150
- package/src/lib/useAlerts.ts +0 -82
- package/src/lib/useGroupEvidence.ts +0 -37
- package/src/lib/useGroups.ts +0 -32
- package/src/lib/useOnboarding.ts +0 -93
- package/src/lib/useProviders.ts +0 -30
- package/src/lib/useStripConfig.ts +0 -154
- package/src/lib/useThemeMode.ts +0 -40
- package/src/lib/useUiScale.ts +0 -52
- package/src/lib/utils.ts +0 -78
- package/src/mcp/currentContext.ts +0 -65
- package/src/mcp/instanceHandlers.ts +0 -151
- package/src/mcp/loopback.ts +0 -88
- package/src/mcp/mode.ts +0 -75
- package/src/mcp/previewExtractor.ts +0 -233
- package/src/mcp/server.ts +0 -2274
- package/src/mcp/toolHandlers.ts +0 -1533
- package/src/proxy/alerts.ts +0 -664
- package/src/proxy/chunkStorage.ts +0 -123
- package/src/proxy/config.ts +0 -218
- package/src/proxy/constants.ts +0 -66
- package/src/proxy/dataDir.ts +0 -147
- package/src/proxy/ecosystemExecutionConfirmation.ts +0 -114
- package/src/proxy/ecosystemExecutionRoute.ts +0 -116
- package/src/proxy/ecosystemRegistry.ts +0 -296
- package/src/proxy/ecosystemTasks.ts +0 -415
- package/src/proxy/evidenceAnalysis.ts +0 -526
- package/src/proxy/evidenceExporter.ts +0 -235
- package/src/proxy/formats/anthropic/anthropicProvider.ts +0 -75
- package/src/proxy/formats/anthropic/handler.ts +0 -75
- package/src/proxy/formats/anthropic/index.ts +0 -13
- package/src/proxy/formats/anthropic/register.ts +0 -4
- package/src/proxy/formats/anthropic/schemas.ts +0 -6
- package/src/proxy/formats/anthropic/stream.ts +0 -205
- package/src/proxy/formats/handler.ts +0 -46
- package/src/proxy/formats/index.ts +0 -13
- package/src/proxy/formats/jsonSchema.ts +0 -2
- package/src/proxy/formats/openai/alibabaProvider.ts +0 -34
- package/src/proxy/formats/openai/codexMetadata.ts +0 -61
- package/src/proxy/formats/openai/handler.ts +0 -133
- package/src/proxy/formats/openai/index.ts +0 -33
- package/src/proxy/formats/openai/provider.ts +0 -50
- package/src/proxy/formats/openai/register.ts +0 -4
- package/src/proxy/formats/openai/schemas.ts +0 -25
- package/src/proxy/formats/openai/stream.ts +0 -600
- package/src/proxy/formats/openai/zhipuProvider.ts +0 -31
- package/src/proxy/formats/providerAdapter.ts +0 -50
- package/src/proxy/formats/providerRegistry.ts +0 -51
- package/src/proxy/formats/providers/index.ts +0 -3
- package/src/proxy/formats/registry.ts +0 -65
- package/src/proxy/groupEvidenceExporter.ts +0 -371
- package/src/proxy/groupStore.ts +0 -336
- package/src/proxy/handler.ts +0 -729
- package/src/proxy/identityProxy.ts +0 -1842
- package/src/proxy/jsonlRecovery.ts +0 -554
- package/src/proxy/logBodyChunks.ts +0 -91
- package/src/proxy/logFinalizer.ts +0 -777
- package/src/proxy/logFinalizer.worker.ts +0 -24
- package/src/proxy/logImportUpload.ts +0 -128
- package/src/proxy/logImporter.ts +0 -813
- package/src/proxy/logIndex.ts +0 -663
- package/src/proxy/logSearch.ts +0 -122
- package/src/proxy/logger.ts +0 -537
- package/src/proxy/openaiOrphanToolStrip.ts +0 -142
- package/src/proxy/platformCommands.ts +0 -258
- package/src/proxy/privateDataPath.ts +0 -419
- package/src/proxy/providerImporters.ts +0 -578
- package/src/proxy/providerScanStore.ts +0 -87
- package/src/proxy/providerSecretStore.ts +0 -216
- package/src/proxy/providers.ts +0 -998
- package/src/proxy/rawStreamCapture.ts +0 -342
- package/src/proxy/runFailures.ts +0 -94
- package/src/proxy/runStore.ts +0 -214
- package/src/proxy/runtimeAdmission.ts +0 -55
- package/src/proxy/runtimeHealth.ts +0 -221
- package/src/proxy/runtimeMetrics.ts +0 -149
- package/src/proxy/runtimeShutdown.ts +0 -157
- package/src/proxy/schemas.ts +0 -112
- package/src/proxy/sessionArchive.ts +0 -479
- package/src/proxy/sessionInfo.ts +0 -266
- package/src/proxy/sessionProcess.ts +0 -194
- package/src/proxy/sessionRuntime.ts +0 -121
- package/src/proxy/sessionSupervisor.ts +0 -305
- package/src/proxy/sessionWorkerEntry.ts +0 -26
- package/src/proxy/shutdownCoordinator.ts +0 -90
- package/src/proxy/socketTracker.ts +0 -639
- package/src/proxy/sqliteLogIndex.ts +0 -733
- package/src/proxy/storageLifecycle.ts +0 -432
- package/src/proxy/store.ts +0 -1773
- package/src/proxy/streamTiming.ts +0 -31
- package/src/proxy/toolSchemaWarnings.ts +0 -529
- package/src/proxy/uiAssetServer.ts +0 -106
- package/src/proxy/upstream.ts +0 -127
- package/src/services/alerts.ts +0 -12
- package/src/services/groups.ts +0 -119
- package/src/services/piAgent.ts +0 -421
- package/src/services/piAgentRetrieval.ts +0 -1180
- package/src/services/result.ts +0 -17
- package/src/services/runs.ts +0 -76
- package/src/ui/bootstrap.ts +0 -167
- package/src/ui/index.html +0 -38
- package/src/ui/logsStreamClient.ts +0 -20
- package/src/ui/main.tsx +0 -13
- package/src/ui/public/runtime-config.js +0 -2
- package/src/ui/router.tsx +0 -13
- package/src/ui/routes/__root.tsx +0 -69
- package/src/ui/routes/index.tsx +0 -35
- package/src/ui/routes/session/$sessionId.tsx +0 -50
- package/src/ui/runtimeDiscovery.ts +0 -50
|
@@ -1,947 +0,0 @@
|
|
|
1
|
-
import { type JSX, useEffect, useMemo, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
Activity,
|
|
4
|
-
Beaker,
|
|
5
|
-
Check,
|
|
6
|
-
Copy,
|
|
7
|
-
Download,
|
|
8
|
-
FlaskConical,
|
|
9
|
-
History,
|
|
10
|
-
Loader2,
|
|
11
|
-
Network,
|
|
12
|
-
PackageCheck,
|
|
13
|
-
RefreshCw,
|
|
14
|
-
Rocket,
|
|
15
|
-
Sparkles,
|
|
16
|
-
Terminal,
|
|
17
|
-
} from "lucide-react";
|
|
18
|
-
import useSWR from "swr";
|
|
19
|
-
import {
|
|
20
|
-
EcosystemExecutionConfirmationResponseSchema,
|
|
21
|
-
EcosystemPackagesResponseSchema,
|
|
22
|
-
EcosystemTaskResponseSchema,
|
|
23
|
-
EcosystemTasksResponseSchema,
|
|
24
|
-
type EcosystemPackage,
|
|
25
|
-
type EcosystemPackageState,
|
|
26
|
-
type EcosystemRecipe,
|
|
27
|
-
type EcosystemExecutionConfirmation,
|
|
28
|
-
type EcosystemRunnerPreset,
|
|
29
|
-
type EcosystemTask,
|
|
30
|
-
type EcosystemTaskAction,
|
|
31
|
-
} from "../../lib/ecosystemContract";
|
|
32
|
-
import { fetchJson } from "../../lib/apiClient";
|
|
33
|
-
import { copyTextToClipboard } from "../../lib/clipboard";
|
|
34
|
-
import { cn } from "../../lib/utils";
|
|
35
|
-
import { Badge } from "../ui/badge";
|
|
36
|
-
import { Button } from "../ui/button";
|
|
37
|
-
import {
|
|
38
|
-
Dialog,
|
|
39
|
-
DialogContent,
|
|
40
|
-
DialogDescription,
|
|
41
|
-
DialogHeader,
|
|
42
|
-
DialogTitle,
|
|
43
|
-
DialogTrigger,
|
|
44
|
-
} from "../ui/dialog";
|
|
45
|
-
import { INSPECTOR_ICON_TRIGGER_CLASS } from "../ui/icon-trigger";
|
|
46
|
-
|
|
47
|
-
type AgentLabDialogProps = {
|
|
48
|
-
currentSessionId: string | null;
|
|
49
|
-
logCount: number;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
type WorkflowCard = {
|
|
53
|
-
id: string;
|
|
54
|
-
title: string;
|
|
55
|
-
label: string;
|
|
56
|
-
description: string;
|
|
57
|
-
metric: string;
|
|
58
|
-
icon: typeof Activity;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
type PendingEcosystemExecution = {
|
|
62
|
-
endpoint: string;
|
|
63
|
-
confirmation: EcosystemExecutionConfirmation;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const WORKFLOWS: WorkflowCard[] = [
|
|
67
|
-
{
|
|
68
|
-
id: "observe",
|
|
69
|
-
title: "Observe",
|
|
70
|
-
label: "Live",
|
|
71
|
-
description: "Capture IDE, process, session, turn, request, response, tools, and providers.",
|
|
72
|
-
metric: "Inspector core",
|
|
73
|
-
icon: Activity,
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
id: "replay",
|
|
77
|
-
title: "Replay",
|
|
78
|
-
label: "Ready",
|
|
79
|
-
description:
|
|
80
|
-
"Promote real logs into repeatable replay evidence without losing the raw context.",
|
|
81
|
-
metric: "Session asset",
|
|
82
|
-
icon: RefreshCw,
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
id: "evaluate",
|
|
86
|
-
title: "Evaluate",
|
|
87
|
-
label: "Next",
|
|
88
|
-
description: "Use eval-harness to turn sessions into regression cases and provider bakeoffs.",
|
|
89
|
-
metric: "Eval loop",
|
|
90
|
-
icon: Beaker,
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
id: "connect",
|
|
94
|
-
title: "Connect",
|
|
95
|
-
label: "MCP",
|
|
96
|
-
description:
|
|
97
|
-
"Expose Inspector state to coding agents as queryable context and durable evidence.",
|
|
98
|
-
metric: "/api/mcp",
|
|
99
|
-
icon: Network,
|
|
100
|
-
},
|
|
101
|
-
];
|
|
102
|
-
|
|
103
|
-
async function fetchEcosystemPackages(url: string) {
|
|
104
|
-
return fetchJson(
|
|
105
|
-
url,
|
|
106
|
-
EcosystemPackagesResponseSchema,
|
|
107
|
-
undefined,
|
|
108
|
-
(response) => `Failed to load ecosystem packages: ${String(response.status)}`,
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async function fetchEcosystemTask(url: string) {
|
|
113
|
-
return fetchJson(
|
|
114
|
-
url,
|
|
115
|
-
EcosystemTaskResponseSchema,
|
|
116
|
-
undefined,
|
|
117
|
-
(response) => `Failed to load ecosystem task: ${String(response.status)}`,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async function fetchEcosystemTasks(url: string) {
|
|
122
|
-
return fetchJson(
|
|
123
|
-
url,
|
|
124
|
-
EcosystemTasksResponseSchema,
|
|
125
|
-
undefined,
|
|
126
|
-
(response) => `Failed to load ecosystem tasks: ${String(response.status)}`,
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async function prepareEcosystemTask(
|
|
131
|
-
packageId: string,
|
|
132
|
-
action: EcosystemTaskAction,
|
|
133
|
-
): Promise<PendingEcosystemExecution> {
|
|
134
|
-
const endpoint = `/api/ecosystem/packages/${encodeURIComponent(packageId)}/${action}`;
|
|
135
|
-
const response = await fetchJson(
|
|
136
|
-
endpoint,
|
|
137
|
-
EcosystemExecutionConfirmationResponseSchema,
|
|
138
|
-
{
|
|
139
|
-
method: "POST",
|
|
140
|
-
headers: { "content-type": "application/json" },
|
|
141
|
-
body: JSON.stringify({ intent: "prepare" }),
|
|
142
|
-
},
|
|
143
|
-
(result) => `Failed to prepare ecosystem task: ${String(result.status)}`,
|
|
144
|
-
);
|
|
145
|
-
return { endpoint, confirmation: response.confirmation };
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async function prepareEcosystemRecipe(recipeId: string): Promise<PendingEcosystemExecution> {
|
|
149
|
-
const endpoint = `/api/ecosystem/recipes/${encodeURIComponent(recipeId)}/run`;
|
|
150
|
-
const response = await fetchJson(
|
|
151
|
-
endpoint,
|
|
152
|
-
EcosystemExecutionConfirmationResponseSchema,
|
|
153
|
-
{
|
|
154
|
-
method: "POST",
|
|
155
|
-
headers: { "content-type": "application/json" },
|
|
156
|
-
body: JSON.stringify({ intent: "prepare" }),
|
|
157
|
-
},
|
|
158
|
-
(result) => `Failed to prepare ecosystem recipe: ${String(result.status)}`,
|
|
159
|
-
);
|
|
160
|
-
return { endpoint, confirmation: response.confirmation };
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async function confirmEcosystemExecution(
|
|
164
|
-
pending: PendingEcosystemExecution,
|
|
165
|
-
): Promise<EcosystemTask> {
|
|
166
|
-
const response = await fetchJson(
|
|
167
|
-
pending.endpoint,
|
|
168
|
-
EcosystemTaskResponseSchema,
|
|
169
|
-
{
|
|
170
|
-
method: "POST",
|
|
171
|
-
headers: { "content-type": "application/json" },
|
|
172
|
-
body: JSON.stringify({
|
|
173
|
-
intent: "confirm",
|
|
174
|
-
nonce: pending.confirmation.nonce,
|
|
175
|
-
confirmation: pending.confirmation.phrase,
|
|
176
|
-
}),
|
|
177
|
-
},
|
|
178
|
-
(result) => `Failed to start ecosystem task: ${String(result.status)}`,
|
|
179
|
-
);
|
|
180
|
-
return response.task;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function stateLabel(state: EcosystemPackageState): string {
|
|
184
|
-
switch (state) {
|
|
185
|
-
case "installed":
|
|
186
|
-
return "Installed";
|
|
187
|
-
case "update-available":
|
|
188
|
-
return "Update";
|
|
189
|
-
case "available":
|
|
190
|
-
return "Available";
|
|
191
|
-
case "planned":
|
|
192
|
-
return "Planned";
|
|
193
|
-
case "unknown":
|
|
194
|
-
return "Unknown";
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function stateClassName(state: EcosystemPackageState): string {
|
|
199
|
-
switch (state) {
|
|
200
|
-
case "installed":
|
|
201
|
-
return "border-emerald-400/20 bg-emerald-400/8 text-emerald-200";
|
|
202
|
-
case "update-available":
|
|
203
|
-
return "border-amber-400/20 bg-amber-400/8 text-amber-200";
|
|
204
|
-
case "available":
|
|
205
|
-
return "border-sky-400/20 bg-sky-400/8 text-sky-200";
|
|
206
|
-
case "planned":
|
|
207
|
-
return "border-white/10 bg-white/[0.04] text-white/55";
|
|
208
|
-
case "unknown":
|
|
209
|
-
return "border-white/10 bg-white/[0.04] text-white/45";
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function versionLabel(pkg: EcosystemPackage): string {
|
|
214
|
-
if (pkg.installedVersion !== null && pkg.latestVersion !== null) {
|
|
215
|
-
if (pkg.installedVersion === pkg.latestVersion) return `v${pkg.installedVersion}`;
|
|
216
|
-
return `v${pkg.installedVersion} -> v${pkg.latestVersion}`;
|
|
217
|
-
}
|
|
218
|
-
if (pkg.installedVersion !== null) return `v${pkg.installedVersion}`;
|
|
219
|
-
if (pkg.latestVersion !== null) return `latest v${pkg.latestVersion}`;
|
|
220
|
-
return "not published";
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function taskActionLabel(action: EcosystemTaskAction): string {
|
|
224
|
-
switch (action) {
|
|
225
|
-
case "install":
|
|
226
|
-
return "Install";
|
|
227
|
-
case "upgrade":
|
|
228
|
-
return "Upgrade";
|
|
229
|
-
case "help":
|
|
230
|
-
return "Help";
|
|
231
|
-
case "runner-presets":
|
|
232
|
-
return "Presets";
|
|
233
|
-
case "recipe":
|
|
234
|
-
return "Recipe";
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function taskStatusLabel(task: EcosystemTask): string {
|
|
239
|
-
switch (task.status) {
|
|
240
|
-
case "queued":
|
|
241
|
-
return "Queued";
|
|
242
|
-
case "running":
|
|
243
|
-
return `${taskActionLabel(task.action)} running`;
|
|
244
|
-
case "succeeded":
|
|
245
|
-
return `${taskActionLabel(task.action)} complete`;
|
|
246
|
-
case "failed":
|
|
247
|
-
return `${taskActionLabel(task.action)} failed`;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function taskStatusClassName(status: EcosystemTask["status"]): string {
|
|
252
|
-
switch (status) {
|
|
253
|
-
case "queued":
|
|
254
|
-
case "running":
|
|
255
|
-
return "border-cyan-300/20 bg-cyan-300/8 text-cyan-100";
|
|
256
|
-
case "succeeded":
|
|
257
|
-
return "border-emerald-400/20 bg-emerald-400/8 text-emerald-100";
|
|
258
|
-
case "failed":
|
|
259
|
-
return "border-red-400/20 bg-red-400/8 text-red-100";
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function packagePrimaryAction(pkg: EcosystemPackage): EcosystemTaskAction | null {
|
|
264
|
-
switch (pkg.state) {
|
|
265
|
-
case "available":
|
|
266
|
-
return "install";
|
|
267
|
-
case "update-available":
|
|
268
|
-
return "upgrade";
|
|
269
|
-
case "installed":
|
|
270
|
-
case "planned":
|
|
271
|
-
case "unknown":
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function PackageStatusCard({
|
|
277
|
-
pkg,
|
|
278
|
-
activeTask,
|
|
279
|
-
onStartTask,
|
|
280
|
-
}: {
|
|
281
|
-
pkg: EcosystemPackage;
|
|
282
|
-
activeTask: EcosystemTask | null;
|
|
283
|
-
onStartTask: (packageId: string, action: EcosystemTaskAction) => void;
|
|
284
|
-
}): JSX.Element {
|
|
285
|
-
const primaryAction = packagePrimaryAction(pkg);
|
|
286
|
-
const packageTaskRunning =
|
|
287
|
-
activeTask !== null && activeTask.packageId === pkg.id && activeTask.status === "running";
|
|
288
|
-
return (
|
|
289
|
-
<div className="rounded-lg bg-white/[0.025] p-3 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]">
|
|
290
|
-
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
291
|
-
<div className="min-w-0">
|
|
292
|
-
<div className="flex min-w-0 items-start gap-2">
|
|
293
|
-
<PackageCheck className="size-4 shrink-0 text-white/55" />
|
|
294
|
-
<div className="text-sm font-semibold leading-snug">{pkg.name}</div>
|
|
295
|
-
</div>
|
|
296
|
-
<div className="mt-1 break-all font-mono text-[11px] leading-snug text-white/35">
|
|
297
|
-
{pkg.npmName}
|
|
298
|
-
</div>
|
|
299
|
-
</div>
|
|
300
|
-
<Badge className={cn("shrink-0", stateClassName(pkg.state))} variant="outline">
|
|
301
|
-
{stateLabel(pkg.state)}
|
|
302
|
-
</Badge>
|
|
303
|
-
</div>
|
|
304
|
-
<div className="mt-3 text-xs leading-5 text-muted-foreground">{pkg.description}</div>
|
|
305
|
-
<div className="mt-3 flex flex-wrap items-center gap-2 text-[11px]">
|
|
306
|
-
<span className="rounded bg-white/[0.035] px-2 py-1 font-mono text-white/50">
|
|
307
|
-
{versionLabel(pkg)}
|
|
308
|
-
</span>
|
|
309
|
-
<span className="rounded bg-white/[0.035] px-2 py-1 text-white/45">{pkg.capability}</span>
|
|
310
|
-
<span className="rounded bg-white/[0.035] px-2 py-1 font-mono text-white/35">
|
|
311
|
-
{pkg.installCommand}
|
|
312
|
-
</span>
|
|
313
|
-
</div>
|
|
314
|
-
<div className="mt-3 flex flex-wrap items-center gap-2">
|
|
315
|
-
{primaryAction !== null && (
|
|
316
|
-
<Button
|
|
317
|
-
type="button"
|
|
318
|
-
size="sm"
|
|
319
|
-
variant="secondary"
|
|
320
|
-
disabled={packageTaskRunning}
|
|
321
|
-
onClick={() => onStartTask(pkg.id, primaryAction)}
|
|
322
|
-
>
|
|
323
|
-
{packageTaskRunning ? (
|
|
324
|
-
<Loader2 className="size-3.5 animate-spin" />
|
|
325
|
-
) : (
|
|
326
|
-
<Download className="size-3.5" />
|
|
327
|
-
)}
|
|
328
|
-
{taskActionLabel(primaryAction)}
|
|
329
|
-
</Button>
|
|
330
|
-
)}
|
|
331
|
-
<Button
|
|
332
|
-
type="button"
|
|
333
|
-
size="sm"
|
|
334
|
-
variant="outline"
|
|
335
|
-
disabled={packageTaskRunning || pkg.state === "planned"}
|
|
336
|
-
onClick={() => onStartTask(pkg.id, "help")}
|
|
337
|
-
>
|
|
338
|
-
<Terminal className="size-3.5" />
|
|
339
|
-
Help
|
|
340
|
-
</Button>
|
|
341
|
-
{pkg.id === "eval-harness" && (
|
|
342
|
-
<Button
|
|
343
|
-
type="button"
|
|
344
|
-
size="sm"
|
|
345
|
-
variant="ghost"
|
|
346
|
-
disabled={packageTaskRunning || pkg.state === "planned"}
|
|
347
|
-
onClick={() => onStartTask(pkg.id, "runner-presets")}
|
|
348
|
-
>
|
|
349
|
-
<Beaker className="size-3.5" />
|
|
350
|
-
Presets
|
|
351
|
-
</Button>
|
|
352
|
-
)}
|
|
353
|
-
</div>
|
|
354
|
-
</div>
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
function TaskConsole({ task }: { task: EcosystemTask | null }): JSX.Element | null {
|
|
359
|
-
if (task === null) return null;
|
|
360
|
-
const isRunning = task.status === "queued" || task.status === "running";
|
|
361
|
-
return (
|
|
362
|
-
<section className="mt-3 rounded-lg bg-white/[0.025] p-3 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]">
|
|
363
|
-
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
364
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
365
|
-
{isRunning ? (
|
|
366
|
-
<Loader2 className="size-4 animate-spin text-cyan-200/75" />
|
|
367
|
-
) : (
|
|
368
|
-
<Terminal className="size-4 text-white/55" />
|
|
369
|
-
)}
|
|
370
|
-
<div className="min-w-0">
|
|
371
|
-
<div className="text-sm font-semibold">{taskStatusLabel(task)}</div>
|
|
372
|
-
<div className="break-all font-mono text-[11px] text-white/35">{task.command}</div>
|
|
373
|
-
</div>
|
|
374
|
-
</div>
|
|
375
|
-
<Badge variant="outline" className={cn("shrink-0", taskStatusClassName(task.status))}>
|
|
376
|
-
{task.status}
|
|
377
|
-
</Badge>
|
|
378
|
-
</div>
|
|
379
|
-
<pre className="mt-3 max-h-56 overflow-auto whitespace-pre-wrap rounded-md bg-black/30 p-3 font-mono text-[11px] leading-5 text-white/60 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]">
|
|
380
|
-
{task.output.trim().length > 0 ? task.output : "Waiting for npm output..."}
|
|
381
|
-
</pre>
|
|
382
|
-
{task.error !== null && <div className="mt-2 text-xs text-red-100">{task.error}</div>}
|
|
383
|
-
</section>
|
|
384
|
-
);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function WorkflowTile({ workflow }: { workflow: WorkflowCard }): JSX.Element {
|
|
388
|
-
const Icon = workflow.icon;
|
|
389
|
-
return (
|
|
390
|
-
<div className="rounded-lg bg-white/[0.025] p-3 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]">
|
|
391
|
-
<div className="flex items-start justify-between gap-3">
|
|
392
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
393
|
-
<Icon className="size-4 shrink-0 text-cyan-200/75" />
|
|
394
|
-
<div className="text-sm font-semibold">{workflow.title}</div>
|
|
395
|
-
</div>
|
|
396
|
-
<span className="rounded bg-white/[0.04] px-2 py-0.5 font-mono text-[10px] text-white/45">
|
|
397
|
-
{workflow.label}
|
|
398
|
-
</span>
|
|
399
|
-
</div>
|
|
400
|
-
<div className="mt-2 min-h-10 text-xs leading-5 text-muted-foreground">
|
|
401
|
-
{workflow.description}
|
|
402
|
-
</div>
|
|
403
|
-
<div className="mt-3 font-mono text-[11px] text-white/35">{workflow.metric}</div>
|
|
404
|
-
</div>
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
function buildSessionCommand(sessionId: string | null): string {
|
|
409
|
-
if (sessionId === null) {
|
|
410
|
-
return 'npx @tonyclaw/eval-harness inspector-smoke --title "TonyClaw Lab smoke" --latest-log-limit 5';
|
|
411
|
-
}
|
|
412
|
-
return `npx @tonyclaw/eval-harness inspector-smoke --title "TonyClaw Lab smoke ${sessionId}" --latest-log-limit 5`;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
function RunnerPresetCard({ preset }: { preset: EcosystemRunnerPreset }): JSX.Element {
|
|
416
|
-
return (
|
|
417
|
-
<div className="rounded-lg bg-white/[0.025] p-3 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]">
|
|
418
|
-
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
419
|
-
<div className="min-w-0">
|
|
420
|
-
<div className="flex min-w-0 items-start gap-2">
|
|
421
|
-
<Rocket className="size-4 shrink-0 text-cyan-200/75" />
|
|
422
|
-
<div className="text-sm font-semibold leading-snug">{preset.name}</div>
|
|
423
|
-
</div>
|
|
424
|
-
<div className="mt-1 break-all font-mono text-[11px] leading-snug text-white/35">
|
|
425
|
-
{preset.binary} {preset.modelFlag}
|
|
426
|
-
{preset.variantFlag !== null ? ` ${preset.variantFlag}` : ""}
|
|
427
|
-
</div>
|
|
428
|
-
</div>
|
|
429
|
-
<Badge variant="outline" className="border-white/10 bg-white/[0.04] text-white/55">
|
|
430
|
-
v{preset.validatedVersion}
|
|
431
|
-
</Badge>
|
|
432
|
-
</div>
|
|
433
|
-
<div className="mt-3 grid grid-cols-2 gap-2 text-[11px]">
|
|
434
|
-
<div className="rounded bg-black/15 px-2 py-1 text-white/45">logs/{preset.logDir}</div>
|
|
435
|
-
<div className="rounded bg-black/15 px-2 py-1 text-white/45">{preset.tools.join(", ")}</div>
|
|
436
|
-
<div className="rounded bg-black/15 px-2 py-1 font-mono text-white/35">
|
|
437
|
-
{preset.skillsDir}
|
|
438
|
-
</div>
|
|
439
|
-
<div className="rounded bg-black/15 px-2 py-1 font-mono text-white/35">
|
|
440
|
-
{preset.agentsDir}
|
|
441
|
-
</div>
|
|
442
|
-
</div>
|
|
443
|
-
</div>
|
|
444
|
-
);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
function RecipeCard({
|
|
448
|
-
recipe,
|
|
449
|
-
copied,
|
|
450
|
-
running,
|
|
451
|
-
onCopy,
|
|
452
|
-
onRun,
|
|
453
|
-
}: {
|
|
454
|
-
recipe: EcosystemRecipe;
|
|
455
|
-
copied: boolean;
|
|
456
|
-
running: boolean;
|
|
457
|
-
onCopy: (recipe: EcosystemRecipe) => void;
|
|
458
|
-
onRun: (recipe: EcosystemRecipe) => void;
|
|
459
|
-
}): JSX.Element {
|
|
460
|
-
return (
|
|
461
|
-
<div className="rounded-lg bg-white/[0.025] p-3 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]">
|
|
462
|
-
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
463
|
-
<div className="min-w-0">
|
|
464
|
-
<div className="flex min-w-0 items-start gap-2">
|
|
465
|
-
<FlaskConical className="size-4 shrink-0 text-cyan-200/75" />
|
|
466
|
-
<div className="text-sm font-semibold leading-snug">{recipe.title}</div>
|
|
467
|
-
</div>
|
|
468
|
-
<div className="mt-1 text-xs leading-5 text-muted-foreground">{recipe.description}</div>
|
|
469
|
-
</div>
|
|
470
|
-
<Badge variant="outline" className="border-white/10 bg-white/[0.04] text-white/55">
|
|
471
|
-
{recipe.runnable ? recipe.stage : "Template"}
|
|
472
|
-
</Badge>
|
|
473
|
-
</div>
|
|
474
|
-
<div className="mt-3 rounded-md bg-black/20 p-2 font-mono text-[11px] leading-5 text-white/50 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]">
|
|
475
|
-
{recipe.command}
|
|
476
|
-
</div>
|
|
477
|
-
<div className="mt-3 flex items-center justify-between gap-2">
|
|
478
|
-
<span className="rounded bg-white/[0.035] px-2 py-1 font-mono text-[11px] text-white/35">
|
|
479
|
-
{recipe.packageId}
|
|
480
|
-
</span>
|
|
481
|
-
<div className="flex items-center gap-2">
|
|
482
|
-
<Button type="button" size="sm" variant="outline" onClick={() => onCopy(recipe)}>
|
|
483
|
-
{copied ? <Check className="size-3.5" /> : <Copy className="size-3.5" />}
|
|
484
|
-
{copied ? "Copied" : "Copy"}
|
|
485
|
-
</Button>
|
|
486
|
-
{recipe.runnable && (
|
|
487
|
-
<Button
|
|
488
|
-
type="button"
|
|
489
|
-
size="sm"
|
|
490
|
-
variant="secondary"
|
|
491
|
-
disabled={running}
|
|
492
|
-
onClick={() => onRun(recipe)}
|
|
493
|
-
>
|
|
494
|
-
{running ? (
|
|
495
|
-
<Loader2 className="size-3.5 animate-spin" />
|
|
496
|
-
) : (
|
|
497
|
-
<Rocket className="size-3.5" />
|
|
498
|
-
)}
|
|
499
|
-
{running ? "Running" : "Run"}
|
|
500
|
-
</Button>
|
|
501
|
-
)}
|
|
502
|
-
</div>
|
|
503
|
-
</div>
|
|
504
|
-
</div>
|
|
505
|
-
);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
function RecentTaskRow({
|
|
509
|
-
task,
|
|
510
|
-
selected,
|
|
511
|
-
onSelect,
|
|
512
|
-
}: {
|
|
513
|
-
task: EcosystemTask;
|
|
514
|
-
selected: boolean;
|
|
515
|
-
onSelect: (task: EcosystemTask) => void;
|
|
516
|
-
}): JSX.Element {
|
|
517
|
-
const label = task.recipeId ?? taskActionLabel(task.action);
|
|
518
|
-
return (
|
|
519
|
-
<div className="flex items-center justify-between gap-3 rounded-md bg-white/[0.025] px-3 py-2 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]">
|
|
520
|
-
<div className="min-w-0">
|
|
521
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
522
|
-
<History className="size-3.5 shrink-0 text-white/40" />
|
|
523
|
-
<div className="truncate text-xs font-semibold text-white/75">{label}</div>
|
|
524
|
-
<Badge variant="outline" className={cn("shrink-0", taskStatusClassName(task.status))}>
|
|
525
|
-
{task.status}
|
|
526
|
-
</Badge>
|
|
527
|
-
</div>
|
|
528
|
-
<div className="mt-1 flex min-w-0 flex-wrap items-center gap-2 font-mono text-[10px] text-white/35">
|
|
529
|
-
<span>{task.packageId}</span>
|
|
530
|
-
<span>{new Date(task.createdAt).toLocaleTimeString()}</span>
|
|
531
|
-
{task.exitCode !== null && <span>exit {String(task.exitCode)}</span>}
|
|
532
|
-
</div>
|
|
533
|
-
</div>
|
|
534
|
-
<Button
|
|
535
|
-
type="button"
|
|
536
|
-
size="sm"
|
|
537
|
-
variant={selected ? "secondary" : "outline"}
|
|
538
|
-
onClick={() => onSelect(task)}
|
|
539
|
-
>
|
|
540
|
-
{selected ? "Open" : "View"}
|
|
541
|
-
</Button>
|
|
542
|
-
</div>
|
|
543
|
-
);
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
function ExecutionConfirmationDialog({
|
|
547
|
-
pending,
|
|
548
|
-
busy,
|
|
549
|
-
onOpenChange,
|
|
550
|
-
onConfirm,
|
|
551
|
-
}: {
|
|
552
|
-
pending: PendingEcosystemExecution | null;
|
|
553
|
-
busy: boolean;
|
|
554
|
-
onOpenChange: (open: boolean) => void;
|
|
555
|
-
onConfirm: () => void;
|
|
556
|
-
}): JSX.Element {
|
|
557
|
-
const plan = pending?.confirmation.plan ?? null;
|
|
558
|
-
return (
|
|
559
|
-
<Dialog open={pending !== null} onOpenChange={onOpenChange}>
|
|
560
|
-
<DialogContent className="max-w-xl">
|
|
561
|
-
<DialogHeader>
|
|
562
|
-
<DialogTitle>Confirm local command</DialogTitle>
|
|
563
|
-
<DialogDescription>
|
|
564
|
-
Review the exact allowlisted action Agent Inspector will run on this machine.
|
|
565
|
-
</DialogDescription>
|
|
566
|
-
</DialogHeader>
|
|
567
|
-
{plan !== null && (
|
|
568
|
-
<div className="space-y-3">
|
|
569
|
-
<div className="grid gap-2 text-xs sm:grid-cols-2">
|
|
570
|
-
<div className="rounded-md border bg-muted/30 p-3">
|
|
571
|
-
<div className="text-muted-foreground">Source</div>
|
|
572
|
-
<div className="mt-1 break-words font-medium">{plan.source}</div>
|
|
573
|
-
</div>
|
|
574
|
-
<div className="rounded-md border bg-muted/30 p-3">
|
|
575
|
-
<div className="text-muted-foreground">Timeout</div>
|
|
576
|
-
<div className="mt-1 font-medium">{String(plan.timeoutMs / 1000)} seconds</div>
|
|
577
|
-
</div>
|
|
578
|
-
<div className="rounded-md border bg-muted/30 p-3 sm:col-span-2">
|
|
579
|
-
<div className="text-muted-foreground">Affected scope</div>
|
|
580
|
-
<div className="mt-1 font-medium">{plan.scope}</div>
|
|
581
|
-
</div>
|
|
582
|
-
</div>
|
|
583
|
-
<div>
|
|
584
|
-
<div className="mb-1 text-xs font-medium">Resolved command</div>
|
|
585
|
-
<pre className="max-h-32 overflow-auto whitespace-pre-wrap break-all rounded-md bg-black/80 p-3 font-mono text-xs leading-5 text-white/80">
|
|
586
|
-
{plan.command}
|
|
587
|
-
</pre>
|
|
588
|
-
</div>
|
|
589
|
-
<p className="text-xs text-muted-foreground">
|
|
590
|
-
Confirmation phrase: <code>{pending?.confirmation.phrase}</code>. The one-time
|
|
591
|
-
confirmation expires at{" "}
|
|
592
|
-
{new Date(pending?.confirmation.expiresAt ?? "").toLocaleTimeString()}.
|
|
593
|
-
</p>
|
|
594
|
-
</div>
|
|
595
|
-
)}
|
|
596
|
-
<div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
|
|
597
|
-
<Button
|
|
598
|
-
type="button"
|
|
599
|
-
variant="outline"
|
|
600
|
-
disabled={busy}
|
|
601
|
-
onClick={() => onOpenChange(false)}
|
|
602
|
-
>
|
|
603
|
-
Cancel
|
|
604
|
-
</Button>
|
|
605
|
-
<Button
|
|
606
|
-
type="button"
|
|
607
|
-
variant="secondary"
|
|
608
|
-
disabled={busy || plan === null}
|
|
609
|
-
onClick={onConfirm}
|
|
610
|
-
>
|
|
611
|
-
{busy ? (
|
|
612
|
-
<Loader2 className="size-3.5 animate-spin" />
|
|
613
|
-
) : (
|
|
614
|
-
<Terminal className="size-3.5" />
|
|
615
|
-
)}
|
|
616
|
-
{busy ? "Starting" : "Confirm & Run"}
|
|
617
|
-
</Button>
|
|
618
|
-
</div>
|
|
619
|
-
</DialogContent>
|
|
620
|
-
</Dialog>
|
|
621
|
-
);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
export function AgentLabDialog({
|
|
625
|
-
currentSessionId,
|
|
626
|
-
logCount,
|
|
627
|
-
labelledTrigger = false,
|
|
628
|
-
}: AgentLabDialogProps & { labelledTrigger?: boolean }): JSX.Element {
|
|
629
|
-
const [open, setOpen] = useState(false);
|
|
630
|
-
const [copied, setCopied] = useState(false);
|
|
631
|
-
const [copiedPresets, setCopiedPresets] = useState(false);
|
|
632
|
-
const [copiedRecipeId, setCopiedRecipeId] = useState<string | null>(null);
|
|
633
|
-
const [activeTaskId, setActiveTaskId] = useState<string | null>(null);
|
|
634
|
-
const [taskError, setTaskError] = useState<string | null>(null);
|
|
635
|
-
const [pendingExecution, setPendingExecution] = useState<PendingEcosystemExecution | null>(null);
|
|
636
|
-
const [confirmationBusy, setConfirmationBusy] = useState(false);
|
|
637
|
-
const response = useSWR("/api/ecosystem/packages", fetchEcosystemPackages, {
|
|
638
|
-
revalidateOnFocus: false,
|
|
639
|
-
revalidateIfStale: false,
|
|
640
|
-
});
|
|
641
|
-
const activeTaskResponse = useSWR(
|
|
642
|
-
activeTaskId === null ? null : `/api/ecosystem/tasks/${activeTaskId}`,
|
|
643
|
-
fetchEcosystemTask,
|
|
644
|
-
{
|
|
645
|
-
refreshInterval: (taskResponse) => {
|
|
646
|
-
const task = taskResponse?.task;
|
|
647
|
-
return task !== undefined && (task.status === "queued" || task.status === "running")
|
|
648
|
-
? 900
|
|
649
|
-
: 0;
|
|
650
|
-
},
|
|
651
|
-
revalidateOnFocus: false,
|
|
652
|
-
},
|
|
653
|
-
);
|
|
654
|
-
const tasksResponse = useSWR(open ? "/api/ecosystem/tasks" : null, fetchEcosystemTasks, {
|
|
655
|
-
refreshInterval: 2500,
|
|
656
|
-
revalidateOnFocus: false,
|
|
657
|
-
});
|
|
658
|
-
const packages = response.data?.packages ?? [];
|
|
659
|
-
const runnerPresets = response.data?.runnerPresets ?? [];
|
|
660
|
-
const recipes = response.data?.recipes ?? [];
|
|
661
|
-
const recentTasks = (tasksResponse.data?.tasks ?? []).slice(0, 6);
|
|
662
|
-
const installedCount = useMemo(
|
|
663
|
-
() =>
|
|
664
|
-
packages.filter((pkg) => pkg.state === "installed" || pkg.state === "update-available")
|
|
665
|
-
.length,
|
|
666
|
-
[packages],
|
|
667
|
-
);
|
|
668
|
-
const sessionCommand = buildSessionCommand(currentSessionId);
|
|
669
|
-
const presetsCommand = "npx @tonyclaw/eval-harness runner-presets";
|
|
670
|
-
|
|
671
|
-
const copySessionCommand = (): void => {
|
|
672
|
-
void copyTextToClipboard(sessionCommand).then(() => {
|
|
673
|
-
setCopied(true);
|
|
674
|
-
window.setTimeout(() => setCopied(false), 1200);
|
|
675
|
-
});
|
|
676
|
-
};
|
|
677
|
-
const copyPresetsCommand = (): void => {
|
|
678
|
-
void copyTextToClipboard(presetsCommand).then(() => {
|
|
679
|
-
setCopiedPresets(true);
|
|
680
|
-
window.setTimeout(() => setCopiedPresets(false), 1200);
|
|
681
|
-
});
|
|
682
|
-
};
|
|
683
|
-
const copyRecipeCommand = (recipe: EcosystemRecipe): void => {
|
|
684
|
-
void copyTextToClipboard(recipe.command).then(() => {
|
|
685
|
-
setCopiedRecipeId(recipe.id);
|
|
686
|
-
window.setTimeout(() => setCopiedRecipeId(null), 1200);
|
|
687
|
-
});
|
|
688
|
-
};
|
|
689
|
-
const runRecipe = (recipe: EcosystemRecipe): void => {
|
|
690
|
-
setTaskError(null);
|
|
691
|
-
void prepareEcosystemRecipe(recipe.id)
|
|
692
|
-
.then((pending) => {
|
|
693
|
-
setPendingExecution(pending);
|
|
694
|
-
})
|
|
695
|
-
.catch((error: unknown) => {
|
|
696
|
-
setTaskError(error instanceof Error ? error.message : "Failed to prepare ecosystem recipe");
|
|
697
|
-
});
|
|
698
|
-
};
|
|
699
|
-
|
|
700
|
-
const activeTask = activeTaskResponse.data?.task ?? null;
|
|
701
|
-
|
|
702
|
-
useEffect(() => {
|
|
703
|
-
if (activeTask === null) return;
|
|
704
|
-
void tasksResponse.mutate();
|
|
705
|
-
if (activeTask.status !== "succeeded") return;
|
|
706
|
-
void response.mutate();
|
|
707
|
-
}, [activeTask, response, tasksResponse]);
|
|
708
|
-
|
|
709
|
-
const handleStartTask = (packageId: string, action: EcosystemTaskAction): void => {
|
|
710
|
-
setTaskError(null);
|
|
711
|
-
void prepareEcosystemTask(packageId, action)
|
|
712
|
-
.then((pending) => {
|
|
713
|
-
setPendingExecution(pending);
|
|
714
|
-
})
|
|
715
|
-
.catch((error: unknown) => {
|
|
716
|
-
setTaskError(error instanceof Error ? error.message : "Failed to prepare ecosystem task");
|
|
717
|
-
});
|
|
718
|
-
};
|
|
719
|
-
|
|
720
|
-
const confirmPendingExecution = (): void => {
|
|
721
|
-
if (pendingExecution === null) return;
|
|
722
|
-
setTaskError(null);
|
|
723
|
-
setConfirmationBusy(true);
|
|
724
|
-
void confirmEcosystemExecution(pendingExecution)
|
|
725
|
-
.then((task) => {
|
|
726
|
-
setActiveTaskId(task.id);
|
|
727
|
-
setPendingExecution(null);
|
|
728
|
-
void activeTaskResponse.mutate({ task }, { revalidate: true });
|
|
729
|
-
void tasksResponse.mutate();
|
|
730
|
-
})
|
|
731
|
-
.catch((error: unknown) => {
|
|
732
|
-
setTaskError(error instanceof Error ? error.message : "Failed to start ecosystem task");
|
|
733
|
-
})
|
|
734
|
-
.finally(() => {
|
|
735
|
-
setConfirmationBusy(false);
|
|
736
|
-
});
|
|
737
|
-
};
|
|
738
|
-
|
|
739
|
-
return (
|
|
740
|
-
<Dialog open={open} onOpenChange={setOpen}>
|
|
741
|
-
<DialogTrigger asChild>
|
|
742
|
-
<Button
|
|
743
|
-
variant="ghost"
|
|
744
|
-
size={labelledTrigger ? "default" : "icon"}
|
|
745
|
-
className={cn(
|
|
746
|
-
INSPECTOR_ICON_TRIGGER_CLASS,
|
|
747
|
-
labelledTrigger && "w-auto gap-2 px-3 text-xs max-lg:h-11 max-lg:w-auto",
|
|
748
|
-
)}
|
|
749
|
-
aria-label="TonyClaw Lab"
|
|
750
|
-
title="TonyClaw Lab"
|
|
751
|
-
>
|
|
752
|
-
<FlaskConical className="size-4" />
|
|
753
|
-
<span className={labelledTrigger ? "" : "sr-only"}>Lab</span>
|
|
754
|
-
</Button>
|
|
755
|
-
</DialogTrigger>
|
|
756
|
-
<DialogContent className="flex max-h-[84vh] max-w-5xl flex-col overflow-hidden">
|
|
757
|
-
<DialogHeader>
|
|
758
|
-
<DialogTitle className="flex items-center gap-2">
|
|
759
|
-
<Sparkles className="size-4 text-cyan-200/80" />
|
|
760
|
-
TonyClaw Lab
|
|
761
|
-
</DialogTitle>
|
|
762
|
-
</DialogHeader>
|
|
763
|
-
|
|
764
|
-
<div className="overflow-y-auto pr-2">
|
|
765
|
-
<div className="grid gap-3 lg:grid-cols-[1.1fr_0.9fr]">
|
|
766
|
-
<section className="rounded-lg bg-white/[0.025] p-4 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]">
|
|
767
|
-
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
768
|
-
<div>
|
|
769
|
-
<div className="text-sm font-semibold">Session asset pipeline</div>
|
|
770
|
-
<div className="mt-1 max-w-2xl text-xs leading-5 text-muted-foreground">
|
|
771
|
-
Treat captured traffic as durable assets: observe it, replay it, evaluate it,
|
|
772
|
-
and expose it back to agents through MCP.
|
|
773
|
-
</div>
|
|
774
|
-
</div>
|
|
775
|
-
<Badge variant="outline" className="border-cyan-300/20 bg-cyan-300/8 text-cyan-100">
|
|
776
|
-
{String(installedCount)}/{String(packages.length)} packages
|
|
777
|
-
</Badge>
|
|
778
|
-
</div>
|
|
779
|
-
|
|
780
|
-
<div className="mt-4 grid gap-3 sm:grid-cols-2">
|
|
781
|
-
{WORKFLOWS.map((workflow) => (
|
|
782
|
-
<WorkflowTile key={workflow.id} workflow={workflow} />
|
|
783
|
-
))}
|
|
784
|
-
</div>
|
|
785
|
-
</section>
|
|
786
|
-
|
|
787
|
-
<section className="rounded-lg bg-white/[0.025] p-4 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]">
|
|
788
|
-
<div className="flex items-start justify-between gap-3">
|
|
789
|
-
<div>
|
|
790
|
-
<div className="text-sm font-semibold">Current session</div>
|
|
791
|
-
<div className="mt-1 text-xs text-muted-foreground">
|
|
792
|
-
{currentSessionId === null ? "MCP smoke command" : currentSessionId}
|
|
793
|
-
</div>
|
|
794
|
-
</div>
|
|
795
|
-
<Badge variant="outline" className="border-white/10 bg-white/[0.04] text-white/55">
|
|
796
|
-
{String(logCount)} logs
|
|
797
|
-
</Badge>
|
|
798
|
-
</div>
|
|
799
|
-
|
|
800
|
-
<div className="mt-4 rounded-md bg-black/20 p-3 font-mono text-[11px] leading-5 text-white/55 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]">
|
|
801
|
-
{sessionCommand}
|
|
802
|
-
</div>
|
|
803
|
-
|
|
804
|
-
<div className="mt-3 flex flex-wrap items-center gap-2">
|
|
805
|
-
<Button size="sm" variant="secondary" onClick={copySessionCommand}>
|
|
806
|
-
{copied ? <Check className="size-3.5" /> : <Copy className="size-3.5" />}
|
|
807
|
-
{copied ? "Copied" : "Copy"}
|
|
808
|
-
</Button>
|
|
809
|
-
<Button size="sm" variant="outline" onClick={copyPresetsCommand}>
|
|
810
|
-
<Beaker className="size-3.5" />
|
|
811
|
-
{copiedPresets ? "Presets copied" : "Runner Presets"}
|
|
812
|
-
</Button>
|
|
813
|
-
</div>
|
|
814
|
-
</section>
|
|
815
|
-
</div>
|
|
816
|
-
|
|
817
|
-
<section className="mt-3">
|
|
818
|
-
<div className="mb-2 flex items-center justify-between gap-3">
|
|
819
|
-
<div className="text-sm font-semibold">Lab recipes</div>
|
|
820
|
-
<div className="hidden items-center gap-1 font-mono text-[11px] text-muted-foreground sm:flex">
|
|
821
|
-
<Sparkles className="size-3.5" />
|
|
822
|
-
copy-ready workflows
|
|
823
|
-
</div>
|
|
824
|
-
</div>
|
|
825
|
-
<div className="grid gap-3 md:grid-cols-2">
|
|
826
|
-
{recipes.map((recipe) => (
|
|
827
|
-
<RecipeCard
|
|
828
|
-
key={recipe.id}
|
|
829
|
-
recipe={recipe}
|
|
830
|
-
copied={copiedRecipeId === recipe.id}
|
|
831
|
-
running={
|
|
832
|
-
activeTask !== null &&
|
|
833
|
-
activeTask.recipeId === recipe.id &&
|
|
834
|
-
(activeTask.status === "queued" || activeTask.status === "running")
|
|
835
|
-
}
|
|
836
|
-
onCopy={copyRecipeCommand}
|
|
837
|
-
onRun={runRecipe}
|
|
838
|
-
/>
|
|
839
|
-
))}
|
|
840
|
-
{response.isLoading &&
|
|
841
|
-
recipes.length === 0 &&
|
|
842
|
-
[0, 1].map((index) => (
|
|
843
|
-
<div
|
|
844
|
-
key={index}
|
|
845
|
-
className="h-40 animate-pulse rounded-lg bg-white/[0.025] shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]"
|
|
846
|
-
/>
|
|
847
|
-
))}
|
|
848
|
-
</div>
|
|
849
|
-
</section>
|
|
850
|
-
|
|
851
|
-
<section className="mt-3">
|
|
852
|
-
<div className="mb-2 flex items-center justify-between gap-3">
|
|
853
|
-
<div className="text-sm font-semibold">Runner presets</div>
|
|
854
|
-
<div className="hidden items-center gap-1 font-mono text-[11px] text-muted-foreground sm:flex">
|
|
855
|
-
<Terminal className="size-3.5" />
|
|
856
|
-
{presetsCommand}
|
|
857
|
-
</div>
|
|
858
|
-
</div>
|
|
859
|
-
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
|
|
860
|
-
{runnerPresets.map((preset) => (
|
|
861
|
-
<RunnerPresetCard key={preset.id} preset={preset} />
|
|
862
|
-
))}
|
|
863
|
-
{response.isLoading &&
|
|
864
|
-
runnerPresets.length === 0 &&
|
|
865
|
-
[0, 1, 2, 3].map((index) => (
|
|
866
|
-
<div
|
|
867
|
-
key={index}
|
|
868
|
-
className="h-32 animate-pulse rounded-lg bg-white/[0.025] shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]"
|
|
869
|
-
/>
|
|
870
|
-
))}
|
|
871
|
-
</div>
|
|
872
|
-
</section>
|
|
873
|
-
|
|
874
|
-
<section className="mt-3">
|
|
875
|
-
<div className="mb-2 flex items-center justify-between gap-3">
|
|
876
|
-
<div className="text-sm font-semibold">TonyClaw packages</div>
|
|
877
|
-
{response.isLoading && (
|
|
878
|
-
<div className="font-mono text-[11px] text-muted-foreground">checking npm...</div>
|
|
879
|
-
)}
|
|
880
|
-
</div>
|
|
881
|
-
{response.error !== undefined && (
|
|
882
|
-
<div className="rounded-lg bg-red-500/8 p-3 text-xs text-red-100 shadow-[inset_0_0_0_1px_rgba(248,113,113,0.16)]">
|
|
883
|
-
Package status is temporarily unavailable.
|
|
884
|
-
</div>
|
|
885
|
-
)}
|
|
886
|
-
<div className="grid gap-3 md:grid-cols-3">
|
|
887
|
-
{packages.map((pkg) => (
|
|
888
|
-
<PackageStatusCard
|
|
889
|
-
key={pkg.id}
|
|
890
|
-
pkg={pkg}
|
|
891
|
-
activeTask={activeTask}
|
|
892
|
-
onStartTask={handleStartTask}
|
|
893
|
-
/>
|
|
894
|
-
))}
|
|
895
|
-
{response.isLoading &&
|
|
896
|
-
packages.length === 0 &&
|
|
897
|
-
[0, 1, 2].map((index) => (
|
|
898
|
-
<div
|
|
899
|
-
key={index}
|
|
900
|
-
className="h-36 animate-pulse rounded-lg bg-white/[0.025] shadow-[inset_0_0_0_1px_rgba(255,255,255,0.055)]"
|
|
901
|
-
/>
|
|
902
|
-
))}
|
|
903
|
-
</div>
|
|
904
|
-
</section>
|
|
905
|
-
|
|
906
|
-
{taskError !== null && (
|
|
907
|
-
<div className="mt-3 rounded-lg bg-red-500/8 p-3 text-xs text-red-100 shadow-[inset_0_0_0_1px_rgba(248,113,113,0.16)]">
|
|
908
|
-
{taskError}
|
|
909
|
-
</div>
|
|
910
|
-
)}
|
|
911
|
-
{recentTasks.length > 0 && (
|
|
912
|
-
<section className="mt-3">
|
|
913
|
-
<div className="mb-2 flex items-center justify-between gap-3">
|
|
914
|
-
<div className="text-sm font-semibold">Recent Lab runs</div>
|
|
915
|
-
<div className="hidden font-mono text-[11px] text-muted-foreground sm:block">
|
|
916
|
-
last {String(recentTasks.length)}
|
|
917
|
-
</div>
|
|
918
|
-
</div>
|
|
919
|
-
<div className="grid gap-2 md:grid-cols-2">
|
|
920
|
-
{recentTasks.map((task) => (
|
|
921
|
-
<RecentTaskRow
|
|
922
|
-
key={task.id}
|
|
923
|
-
task={task}
|
|
924
|
-
selected={activeTaskId === task.id}
|
|
925
|
-
onSelect={(selectedTask) => {
|
|
926
|
-
setActiveTaskId(selectedTask.id);
|
|
927
|
-
void activeTaskResponse.mutate({ task: selectedTask }, { revalidate: true });
|
|
928
|
-
}}
|
|
929
|
-
/>
|
|
930
|
-
))}
|
|
931
|
-
</div>
|
|
932
|
-
</section>
|
|
933
|
-
)}
|
|
934
|
-
<TaskConsole task={activeTask} />
|
|
935
|
-
</div>
|
|
936
|
-
</DialogContent>
|
|
937
|
-
<ExecutionConfirmationDialog
|
|
938
|
-
pending={pendingExecution}
|
|
939
|
-
busy={confirmationBusy}
|
|
940
|
-
onOpenChange={(confirmationOpen) => {
|
|
941
|
-
if (!confirmationOpen && !confirmationBusy) setPendingExecution(null);
|
|
942
|
-
}}
|
|
943
|
-
onConfirm={confirmPendingExecution}
|
|
944
|
-
/>
|
|
945
|
-
</Dialog>
|
|
946
|
-
);
|
|
947
|
-
}
|