@tonyclaw/agent-inspector 4.0.1 → 4.0.2
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 +192 -109
- package/.output/server/_ssr/index.mjs +1 -1
- package/.output/server/_ssr/{router-CTHqmroT.mjs → router-BBY_zWRK.mjs} +91 -3
- package/.output/server/index.mjs +1 -1
- package/.output/ui/assets/{CompareDrawer-L3n4J-Or.js → CompareDrawer-rtNElN-B.js} +1 -1
- package/.output/ui/assets/{InspectorPet-D5o_3OZS.js → InspectorPet-QaAiuF3d.js} +1 -1
- package/.output/ui/assets/{ProxyViewerContainer-Ocagx75S.js → ProxyViewerContainer-6twNZHwl.js} +4 -4
- package/.output/ui/assets/{ReplayDialog-Bk7x1h-y.js → ReplayDialog-B7KlziO2.js} +1 -1
- package/.output/ui/assets/{RequestAnatomy-U4lzL7Sc.js → RequestAnatomy-2XVFBrW4.js} +1 -1
- package/.output/ui/assets/{ResponseView-LOWfvBLK.js → ResponseView-BULgzLVB.js} +1 -1
- package/.output/ui/assets/{StreamingChunkSequence-DPfsrrXQ.js → StreamingChunkSequence-DSkvkbns.js} +1 -1
- package/.output/ui/assets/{_sessionId-OdX2Jvt1.js → _sessionId-D2dmJi3G.js} +1 -1
- package/.output/ui/assets/{_sessionId-0MlWS-CO.js → _sessionId-DcS0s1Mr.js} +1 -1
- package/.output/ui/assets/{index-Du4qNOOt.js → index-B0TN1KKO.js} +2 -2
- package/.output/ui/assets/{index-gvFj_9K6.js → index-Bva1zHEs.js} +1 -1
- package/.output/ui/assets/{index-Ea-c8hPg.js → index-BzBExOxu.js} +1 -1
- package/.output/ui/assets/{index-zVVS53Hd.js → index-k6sRQz55.js} +1 -1
- package/.output/ui/assets/{json-viewer-C1WAMzg3.js → json-viewer-CWM4tY-j.js} +1 -1
- package/.output/ui/assets/{jszip.min-B8AKu2zm.js → jszip.min-BkWvRFlo.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,51 +0,0 @@
|
|
|
1
|
-
import type { ProviderAdapter } from "./providerAdapter";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Provider Registry
|
|
5
|
-
*
|
|
6
|
-
* Singleton registry for provider implementations.
|
|
7
|
-
* Providers register themselves at module load time.
|
|
8
|
-
*/
|
|
9
|
-
class ProviderRegistryImpl {
|
|
10
|
-
private providers: ProviderAdapter[] = [];
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Register a provider with the registry.
|
|
14
|
-
* @param provider - Provider implementation to register
|
|
15
|
-
*/
|
|
16
|
-
register(provider: ProviderAdapter): void {
|
|
17
|
-
this.providers.push(provider);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Find the first provider that matches the given model.
|
|
22
|
-
* @param model - Model name to match
|
|
23
|
-
* @returns Matching provider or null if none found
|
|
24
|
-
*/
|
|
25
|
-
findProvider(model: string): ProviderAdapter | null {
|
|
26
|
-
let fallback: ProviderAdapter | null = null;
|
|
27
|
-
|
|
28
|
-
for (const provider of this.providers) {
|
|
29
|
-
if (provider.matches(model)) {
|
|
30
|
-
// Non-anthropic providers win immediately (explicit match)
|
|
31
|
-
if (provider.name !== "anthropic") {
|
|
32
|
-
return provider;
|
|
33
|
-
}
|
|
34
|
-
// Anthropic is the fallback; only use if nothing else matches
|
|
35
|
-
fallback = provider;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return fallback;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Get all registered providers.
|
|
43
|
-
* @returns Array of all registered providers
|
|
44
|
-
*/
|
|
45
|
-
getAll(): ProviderAdapter[] {
|
|
46
|
-
return [...this.providers];
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** Global registry instance */
|
|
51
|
-
export const registry = new ProviderRegistryImpl();
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import type { FormatHandler } from "./handler";
|
|
2
|
-
import type { ApiFormat } from "../schemas";
|
|
3
|
-
import { API_FORMAT_PATH_ENTRIES, apiFormatForPath } from "../../lib/apiFormat";
|
|
4
|
-
|
|
5
|
-
export { apiFormatForPath };
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* API format registry maps request paths and API formats to their FormatHandler.
|
|
9
|
-
*
|
|
10
|
-
* Registered at module load time by each format's init module.
|
|
11
|
-
*/
|
|
12
|
-
class FormatRegistryImpl {
|
|
13
|
-
private handlers = new Map<ApiFormat, FormatHandler>();
|
|
14
|
-
private pathMap = new Map<string, ApiFormat>();
|
|
15
|
-
|
|
16
|
-
register(handler: FormatHandler): void {
|
|
17
|
-
this.handlers.set(handler.format, handler);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
registerPath(path: string, format: ApiFormat): void {
|
|
21
|
-
this.pathMap.set(path, format);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Get handler by format identifier */
|
|
25
|
-
get(format: ApiFormat): FormatHandler | undefined {
|
|
26
|
-
return this.handlers.get(format);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Get handler matching a request path */
|
|
30
|
-
getByPath(path: string): FormatHandler | undefined {
|
|
31
|
-
const messagesPath = path.split("?")[0] ?? "";
|
|
32
|
-
const format = this.pathMap.get(messagesPath);
|
|
33
|
-
return format === undefined ? undefined : this.handlers.get(format);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Get the API format matching a request path without requiring handlers. */
|
|
37
|
-
getApiFormatByPath(path: string): ApiFormat | undefined {
|
|
38
|
-
const messagesPath = path.split("?")[0] ?? "";
|
|
39
|
-
return this.pathMap.get(messagesPath);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Detect API format from request body content */
|
|
43
|
-
detectFormat(rawBody: string | null): ApiFormat {
|
|
44
|
-
if (rawBody === null) return "unknown";
|
|
45
|
-
for (const handler of this.handlers.values()) {
|
|
46
|
-
if (handler.detectFormat(rawBody)) return handler.format;
|
|
47
|
-
}
|
|
48
|
-
return "unknown";
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export const formatRegistry = new FormatRegistryImpl();
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Get the FormatHandler for a request path.
|
|
56
|
-
* Returns null if no format matches the path.
|
|
57
|
-
*/
|
|
58
|
-
export function formatForPath(path: string): FormatHandler | null {
|
|
59
|
-
return formatRegistry.getByPath(path) ?? null;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Register known paths
|
|
63
|
-
for (const [path, format] of API_FORMAT_PATH_ENTRIES) {
|
|
64
|
-
formatRegistry.registerPath(path, format);
|
|
65
|
-
}
|
|
@@ -1,371 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
GroupEvidenceExportResultSchema,
|
|
6
|
-
type GroupEvidenceExportOptions,
|
|
7
|
-
type GroupEvidenceExportResult,
|
|
8
|
-
type InspectorGroup,
|
|
9
|
-
type InspectorGroupEvidence,
|
|
10
|
-
type InspectorGroupEvidenceSummary,
|
|
11
|
-
type InspectorGroupExportMember,
|
|
12
|
-
} from "../lib/groupContract";
|
|
13
|
-
import type { JenkinsReport } from "../lib/runContract";
|
|
14
|
-
import type { SessionInfo, SessionTokenUsage } from "../lib/sessionInfoContract";
|
|
15
|
-
import { getDataDir } from "./dataDir";
|
|
16
|
-
import { getRun } from "./runStore";
|
|
17
|
-
import { getSessionInfo } from "./store";
|
|
18
|
-
import { updateGroupEvidence } from "./groupStore";
|
|
19
|
-
import { readJsonFile } from "../lib/jsonFile";
|
|
20
|
-
import {
|
|
21
|
-
ensurePrivateDirectorySync,
|
|
22
|
-
PRIVATE_FILE_MODE,
|
|
23
|
-
securePrivateFileSync,
|
|
24
|
-
} from "./privateDataPath";
|
|
25
|
-
|
|
26
|
-
type GroupEvidenceDocument = GroupEvidenceExportResult;
|
|
27
|
-
|
|
28
|
-
function groupEvidenceDir(groupId: string): string {
|
|
29
|
-
return join(getDataDir(), "evidence", "groups", groupId);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function jsonPath(groupId: string): string {
|
|
33
|
-
return join(groupEvidenceDir(groupId), "evidence.json");
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function markdownPath(groupId: string): string {
|
|
37
|
-
return join(groupEvidenceDir(groupId), "evidence.md");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function htmlPath(groupId: string): string {
|
|
41
|
-
return join(groupEvidenceDir(groupId), "evidence.html");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function escapeMarkdownCell(value: string): string {
|
|
45
|
-
return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function escapeHtml(value: string): string {
|
|
49
|
-
return value
|
|
50
|
-
.replace(/&/g, "&")
|
|
51
|
-
.replace(/</g, "<")
|
|
52
|
-
.replace(/>/g, ">")
|
|
53
|
-
.replace(/"/g, """);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function formatText(value: string | null | undefined): string {
|
|
57
|
-
if (value === null || value === undefined || value.length === 0) return "n/a";
|
|
58
|
-
return value;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function formatNumber(value: number | null | undefined): string {
|
|
62
|
-
if (value === null || value === undefined) return "n/a";
|
|
63
|
-
return String(value);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function collectSortedValues(values: readonly (string | null | undefined)[]): string[] {
|
|
67
|
-
const set = new Set<string>();
|
|
68
|
-
for (const value of values) {
|
|
69
|
-
if (value !== null && value !== undefined && value.length > 0) {
|
|
70
|
-
set.add(value);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return [...set].sort();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function addTokenUsage(total: SessionTokenUsage, session: SessionInfo | null): SessionTokenUsage {
|
|
77
|
-
if (session === null) return total;
|
|
78
|
-
return {
|
|
79
|
-
input: total.input + session.tokenUsage.input,
|
|
80
|
-
output: total.output + session.tokenUsage.output,
|
|
81
|
-
cacheCreate: total.cacheCreate + session.tokenUsage.cacheCreate,
|
|
82
|
-
cacheRead: total.cacheRead + session.tokenUsage.cacheRead,
|
|
83
|
-
total: total.total + session.tokenUsage.total,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function memberEffectiveStatus(member: InspectorGroupExportMember): string {
|
|
88
|
-
if (member.member.status !== null) return member.member.status;
|
|
89
|
-
if (member.run !== null) return member.run.status;
|
|
90
|
-
return member.session?.status ?? "unknown";
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function isCompletedMember(member: InspectorGroupExportMember): boolean {
|
|
94
|
-
const status = memberEffectiveStatus(member);
|
|
95
|
-
return status === "completed";
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function isFailedMember(member: InspectorGroupExportMember): boolean {
|
|
99
|
-
const status = memberEffectiveStatus(member);
|
|
100
|
-
return status === "failed" || status === "cancelled";
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function isRunningMember(member: InspectorGroupExportMember): boolean {
|
|
104
|
-
const status = memberEffectiveStatus(member);
|
|
105
|
-
return status === "running" || status === "active";
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function latestLogMetric(
|
|
109
|
-
session: SessionInfo | null,
|
|
110
|
-
field: "firstChunkMs" | "totalStreamMs" | "tokensPerSecond",
|
|
111
|
-
): number | null {
|
|
112
|
-
if (session === null) return null;
|
|
113
|
-
for (const log of session.latestLogs) {
|
|
114
|
-
const value = log[field];
|
|
115
|
-
if (value !== undefined && value !== null) return value;
|
|
116
|
-
}
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function buildSummary(
|
|
121
|
-
members: readonly InspectorGroupExportMember[],
|
|
122
|
-
): InspectorGroupEvidenceSummary {
|
|
123
|
-
const tokenUsage = members.reduce<SessionTokenUsage>(
|
|
124
|
-
(total, member) => addTokenUsage(total, member.session),
|
|
125
|
-
{ input: 0, output: 0, cacheCreate: 0, cacheRead: 0, total: 0 },
|
|
126
|
-
);
|
|
127
|
-
const sessionsWithData = members.filter((member) => member.session !== null).length;
|
|
128
|
-
const requestCount = members.reduce(
|
|
129
|
-
(total, member) => total + (member.session?.requestCount ?? 0),
|
|
130
|
-
0,
|
|
131
|
-
);
|
|
132
|
-
const errorCount = members.reduce(
|
|
133
|
-
(total, member) => total + (member.session?.errorCount ?? 0),
|
|
134
|
-
0,
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
memberCount: members.length,
|
|
139
|
-
sessionsWithData,
|
|
140
|
-
missingSessions: members.length - sessionsWithData,
|
|
141
|
-
requestCount,
|
|
142
|
-
errorCount,
|
|
143
|
-
tokenUsage,
|
|
144
|
-
models: collectSortedValues(
|
|
145
|
-
members.flatMap((member) => [member.member.model, ...(member.session?.models ?? [])]),
|
|
146
|
-
),
|
|
147
|
-
providers: collectSortedValues(
|
|
148
|
-
members.flatMap((member) => [member.member.provider, ...(member.session?.providers ?? [])]),
|
|
149
|
-
),
|
|
150
|
-
completedMembers: members.filter(isCompletedMember).length,
|
|
151
|
-
failedMembers: members.filter(isFailedMember).length,
|
|
152
|
-
runningMembers: members.filter(isRunningMember).length,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function buildJenkinsReport(
|
|
157
|
-
group: InspectorGroup,
|
|
158
|
-
summary: InspectorGroupEvidenceSummary,
|
|
159
|
-
): JenkinsReport {
|
|
160
|
-
if (summary.failedMembers > 0 || summary.errorCount > 0 || group.status === "failed") {
|
|
161
|
-
return {
|
|
162
|
-
status: "FAIL",
|
|
163
|
-
summary: `[FAIL] ${summary.failedMembers} failed members, ${summary.errorCount} captured errors.`,
|
|
164
|
-
markdown: `# Jenkins Report: ${group.title}\n\nStatus: FAIL\n\n${summary.failedMembers} failed members and ${summary.errorCount} captured errors need triage.`,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (summary.runningMembers > 0 || group.status === "running") {
|
|
169
|
-
return {
|
|
170
|
-
status: "RUNNING",
|
|
171
|
-
summary: `[RUNNING] ${summary.runningMembers} group members are still active.`,
|
|
172
|
-
markdown: `# Jenkins Report: ${group.title}\n\nStatus: RUNNING\n\n${summary.runningMembers} group members are still active.`,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (
|
|
177
|
-
summary.memberCount > 0 &&
|
|
178
|
-
summary.sessionsWithData > 0 &&
|
|
179
|
-
summary.errorCount === 0 &&
|
|
180
|
-
group.status === "completed"
|
|
181
|
-
) {
|
|
182
|
-
return {
|
|
183
|
-
status: "PASS",
|
|
184
|
-
summary: `[PASS] ${summary.memberCount} group members completed with no captured errors.`,
|
|
185
|
-
markdown: `# Jenkins Report: ${group.title}\n\nStatus: PASS\n\n${summary.memberCount} group members completed with no captured errors.`,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return {
|
|
190
|
-
status: "UNKNOWN",
|
|
191
|
-
summary: `[UNKNOWN] Group has ${summary.memberCount} members and ${summary.missingSessions} missing sessions.`,
|
|
192
|
-
markdown: `# Jenkins Report: ${group.title}\n\nStatus: UNKNOWN\n\nExported group evidence, but the outcome is not conclusive yet.`,
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function buildMemberRows(members: readonly InspectorGroupExportMember[]): string[] {
|
|
197
|
-
if (members.length === 0) return ["No sessions have been attached to this group.", ""];
|
|
198
|
-
|
|
199
|
-
const rows = [
|
|
200
|
-
"| Label | Provider | Model | Session | Run | Status | Requests | Errors | Tokens | First Chunk | Stream Total | TPS | Inspector |",
|
|
201
|
-
"| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |",
|
|
202
|
-
];
|
|
203
|
-
|
|
204
|
-
for (const member of members) {
|
|
205
|
-
const session = member.session;
|
|
206
|
-
rows.push(
|
|
207
|
-
[
|
|
208
|
-
formatText(member.member.label),
|
|
209
|
-
formatText(member.member.provider ?? session?.providers[0]),
|
|
210
|
-
formatText(member.member.model ?? session?.lastModel),
|
|
211
|
-
member.member.sessionId,
|
|
212
|
-
formatText(member.member.runId),
|
|
213
|
-
memberEffectiveStatus(member),
|
|
214
|
-
formatNumber(session?.requestCount),
|
|
215
|
-
formatNumber(session?.errorCount),
|
|
216
|
-
formatNumber(session?.tokenUsage.total),
|
|
217
|
-
formatNumber(latestLogMetric(session, "firstChunkMs")),
|
|
218
|
-
formatNumber(latestLogMetric(session, "totalStreamMs")),
|
|
219
|
-
formatNumber(latestLogMetric(session, "tokensPerSecond")),
|
|
220
|
-
formatText(session?.inspectorUrl),
|
|
221
|
-
]
|
|
222
|
-
.map(escapeMarkdownCell)
|
|
223
|
-
.join(" | ")
|
|
224
|
-
.replace(/^/, "| ")
|
|
225
|
-
.replace(/$/, " |"),
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
rows.push("");
|
|
230
|
-
return rows;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function buildMarkdown(document: GroupEvidenceDocument): string {
|
|
234
|
-
const group = document.group;
|
|
235
|
-
const summary = document.summary;
|
|
236
|
-
const lines = [
|
|
237
|
-
`# ${group.title}`,
|
|
238
|
-
"",
|
|
239
|
-
`- Group ID: ${group.id}`,
|
|
240
|
-
`- Kind: ${group.kind}`,
|
|
241
|
-
`- Status: ${group.status}`,
|
|
242
|
-
`- Project: ${group.project ?? "n/a"}`,
|
|
243
|
-
`- Created: ${group.createdAt}`,
|
|
244
|
-
`- Members: ${summary.memberCount}`,
|
|
245
|
-
`- Sessions With Data: ${summary.sessionsWithData}`,
|
|
246
|
-
`- Missing Sessions: ${summary.missingSessions}`,
|
|
247
|
-
`- Requests: ${summary.requestCount}`,
|
|
248
|
-
`- Errors: ${summary.errorCount}`,
|
|
249
|
-
`- Tokens: ${summary.tokenUsage.total}`,
|
|
250
|
-
`- Models: ${summary.models.length > 0 ? summary.models.join(", ") : "n/a"}`,
|
|
251
|
-
`- Providers: ${summary.providers.length > 0 ? summary.providers.join(", ") : "n/a"}`,
|
|
252
|
-
`- Evidence JSON: ${document.evidence.jsonPath}`,
|
|
253
|
-
`- Evidence HTML: ${document.evidence.htmlPath}`,
|
|
254
|
-
"",
|
|
255
|
-
];
|
|
256
|
-
|
|
257
|
-
if (group.task !== null) {
|
|
258
|
-
lines.push("## Task", "", group.task, "");
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
lines.push("## Evaluation Matrix", "", ...buildMemberRows(document.members));
|
|
262
|
-
lines.push("## Jenkins Report", "", document.jenkinsReport.markdown, "");
|
|
263
|
-
|
|
264
|
-
return `${lines.join("\n")}\n`;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function buildHtml(markdown: string, title: string): string {
|
|
268
|
-
return `<!doctype html>
|
|
269
|
-
<html lang="en">
|
|
270
|
-
<head>
|
|
271
|
-
<meta charset="utf-8">
|
|
272
|
-
<title>${escapeHtml(title)}</title>
|
|
273
|
-
<style>
|
|
274
|
-
body { font-family: system-ui, sans-serif; max-width: 1120px; margin: 40px auto; line-height: 1.5; }
|
|
275
|
-
pre { white-space: pre-wrap; background: #f6f8fa; padding: 16px; border-radius: 8px; }
|
|
276
|
-
</style>
|
|
277
|
-
</head>
|
|
278
|
-
<body>
|
|
279
|
-
<pre>${escapeHtml(markdown)}</pre>
|
|
280
|
-
</body>
|
|
281
|
-
</html>
|
|
282
|
-
`;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
async function buildExportMembers(
|
|
286
|
-
group: InspectorGroup,
|
|
287
|
-
options: GroupEvidenceExportOptions,
|
|
288
|
-
baseUrl: string,
|
|
289
|
-
): Promise<InspectorGroupExportMember[]> {
|
|
290
|
-
const members: InspectorGroupExportMember[] = [];
|
|
291
|
-
for (const member of group.members) {
|
|
292
|
-
const run = member.runId === null ? null : getRun(member.runId);
|
|
293
|
-
const session = await getSessionInfo(member.sessionId, {
|
|
294
|
-
baseUrl,
|
|
295
|
-
includeHistory: options?.includeHistory,
|
|
296
|
-
latestLogLimit: options?.latestLogLimit,
|
|
297
|
-
});
|
|
298
|
-
members.push({ member, run, session });
|
|
299
|
-
}
|
|
300
|
-
return members;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
export async function exportGroupEvidence(
|
|
304
|
-
group: InspectorGroup,
|
|
305
|
-
options: GroupEvidenceExportOptions,
|
|
306
|
-
baseUrl: string,
|
|
307
|
-
): Promise<GroupEvidenceExportResult> {
|
|
308
|
-
const members = await buildExportMembers(group, options, baseUrl);
|
|
309
|
-
const exportedAt = new Date().toISOString();
|
|
310
|
-
const evidence: InspectorGroupEvidence = {
|
|
311
|
-
jsonPath: jsonPath(group.id),
|
|
312
|
-
markdownPath: markdownPath(group.id),
|
|
313
|
-
htmlPath: htmlPath(group.id),
|
|
314
|
-
exportedAt,
|
|
315
|
-
};
|
|
316
|
-
const documentGroup: InspectorGroup = {
|
|
317
|
-
...group,
|
|
318
|
-
evidence,
|
|
319
|
-
updatedAt: exportedAt,
|
|
320
|
-
};
|
|
321
|
-
const summary = buildSummary(members);
|
|
322
|
-
const jenkinsReport = buildJenkinsReport(documentGroup, summary);
|
|
323
|
-
const document: GroupEvidenceDocument = {
|
|
324
|
-
group: documentGroup,
|
|
325
|
-
evidence,
|
|
326
|
-
members,
|
|
327
|
-
summary,
|
|
328
|
-
jenkinsReport,
|
|
329
|
-
};
|
|
330
|
-
const markdown = buildMarkdown(document);
|
|
331
|
-
|
|
332
|
-
assert(
|
|
333
|
-
ensurePrivateDirectorySync(groupEvidenceDir(group.id)),
|
|
334
|
-
"Could not secure group evidence directory",
|
|
335
|
-
);
|
|
336
|
-
writeFileSync(evidence.jsonPath, `${JSON.stringify(document, null, 2)}\n`, {
|
|
337
|
-
encoding: "utf8",
|
|
338
|
-
mode: PRIVATE_FILE_MODE,
|
|
339
|
-
});
|
|
340
|
-
writeFileSync(evidence.markdownPath, markdown, {
|
|
341
|
-
encoding: "utf8",
|
|
342
|
-
mode: PRIVATE_FILE_MODE,
|
|
343
|
-
});
|
|
344
|
-
writeFileSync(evidence.htmlPath, buildHtml(markdown, group.title), {
|
|
345
|
-
encoding: "utf8",
|
|
346
|
-
mode: PRIVATE_FILE_MODE,
|
|
347
|
-
});
|
|
348
|
-
for (const path of [evidence.jsonPath, evidence.markdownPath, evidence.htmlPath]) {
|
|
349
|
-
assert(securePrivateFileSync(path), `Could not secure group evidence file ${path}`);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const updatedGroup = updateGroupEvidence(group.id, evidence) ?? documentGroup;
|
|
353
|
-
return { ...document, group: updatedGroup };
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
export function readGroupEvidenceMarkdown(group: InspectorGroup): string | null {
|
|
357
|
-
const path = group.evidence?.markdownPath;
|
|
358
|
-
if (path === undefined || !existsSync(path)) return null;
|
|
359
|
-
try {
|
|
360
|
-
return readFileSync(path, "utf8");
|
|
361
|
-
} catch {
|
|
362
|
-
return null;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
export function readGroupEvidenceDocument(group: InspectorGroup): GroupEvidenceExportResult | null {
|
|
367
|
-
const path = group.evidence?.jsonPath;
|
|
368
|
-
if (path === undefined) return null;
|
|
369
|
-
const result = readJsonFile(path, GroupEvidenceExportResultSchema);
|
|
370
|
-
return result.ok ? result.data : null;
|
|
371
|
-
}
|