@oscharko-dev/keiko-server 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -0
- package/dist/assistant-response.d.ts +6 -0
- package/dist/assistant-response.d.ts.map +1 -0
- package/dist/assistant-response.js +12 -0
- package/dist/browser.d.ts +11 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +245 -0
- package/dist/chat-handlers.d.ts +48 -0
- package/dist/chat-handlers.d.ts.map +1 -0
- package/dist/chat-handlers.js +821 -0
- package/dist/chat-stream-handlers.d.ts +4 -0
- package/dist/chat-stream-handlers.d.ts.map +1 -0
- package/dist/chat-stream-handlers.js +136 -0
- package/dist/conversation-prompt.d.ts +8 -0
- package/dist/conversation-prompt.d.ts.map +1 -0
- package/dist/conversation-prompt.js +36 -0
- package/dist/conversation-validation.d.ts +26 -0
- package/dist/conversation-validation.d.ts.map +1 -0
- package/dist/conversation-validation.js +125 -0
- package/dist/credentialPersistence.d.ts +23 -0
- package/dist/credentialPersistence.d.ts.map +1 -0
- package/dist/credentialPersistence.js +93 -0
- package/dist/credentialVault.d.ts +30 -0
- package/dist/credentialVault.d.ts.map +1 -0
- package/dist/credentialVault.js +206 -0
- package/dist/csp.d.ts +3 -0
- package/dist/csp.d.ts.map +1 -0
- package/dist/csp.js +75 -0
- package/dist/deps.d.ts +78 -0
- package/dist/deps.d.ts.map +1 -0
- package/dist/deps.js +457 -0
- package/dist/editor/agentRoutes.d.ts +7 -0
- package/dist/editor/agentRoutes.d.ts.map +1 -0
- package/dist/editor/agentRoutes.js +197 -0
- package/dist/editor/assuredGateRunner.d.ts +36 -0
- package/dist/editor/assuredGateRunner.d.ts.map +1 -0
- package/dist/editor/assuredGateRunner.js +100 -0
- package/dist/editor/assuredPreFilter.d.ts +34 -0
- package/dist/editor/assuredPreFilter.d.ts.map +1 -0
- package/dist/editor/assuredPreFilter.js +134 -0
- package/dist/editor/assuredPreFilterRunner.d.ts +31 -0
- package/dist/editor/assuredPreFilterRunner.d.ts.map +1 -0
- package/dist/editor/assuredPreFilterRunner.js +312 -0
- package/dist/editor/builtinLanguageProviders.d.ts +6 -0
- package/dist/editor/builtinLanguageProviders.d.ts.map +1 -0
- package/dist/editor/builtinLanguageProviders.js +221 -0
- package/dist/editor/codingContext.d.ts +12 -0
- package/dist/editor/codingContext.d.ts.map +1 -0
- package/dist/editor/codingContext.js +121 -0
- package/dist/editor/codingContextEvidence.d.ts +7 -0
- package/dist/editor/codingContextEvidence.d.ts.map +1 -0
- package/dist/editor/codingContextEvidence.js +52 -0
- package/dist/editor/codingContextProviders.d.ts +36 -0
- package/dist/editor/codingContextProviders.d.ts.map +1 -0
- package/dist/editor/codingContextProviders.js +348 -0
- package/dist/editor/completionModelEvidence.d.ts +16 -0
- package/dist/editor/completionModelEvidence.d.ts.map +1 -0
- package/dist/editor/completionModelEvidence.js +50 -0
- package/dist/editor/completionRoutes.d.ts +37 -0
- package/dist/editor/completionRoutes.d.ts.map +1 -0
- package/dist/editor/completionRoutes.js +411 -0
- package/dist/editor/contextRoutes.d.ts +6 -0
- package/dist/editor/contextRoutes.d.ts.map +1 -0
- package/dist/editor/contextRoutes.js +411 -0
- package/dist/editor/disposableAssuredExecution.d.ts +22 -0
- package/dist/editor/disposableAssuredExecution.d.ts.map +1 -0
- package/dist/editor/disposableAssuredExecution.js +57 -0
- package/dist/editor/editorCompletionModel.d.ts +47 -0
- package/dist/editor/editorCompletionModel.d.ts.map +1 -0
- package/dist/editor/editorCompletionModel.js +156 -0
- package/dist/editor/editorInlineCompletionModel.d.ts +34 -0
- package/dist/editor/editorInlineCompletionModel.d.ts.map +1 -0
- package/dist/editor/editorInlineCompletionModel.js +112 -0
- package/dist/editor/editorModelTokenBudget.d.ts +46 -0
- package/dist/editor/editorModelTokenBudget.d.ts.map +1 -0
- package/dist/editor/editorModelTokenBudget.js +121 -0
- package/dist/editor/inlineCompletionRateLimiter.d.ts +19 -0
- package/dist/editor/inlineCompletionRateLimiter.d.ts.map +1 -0
- package/dist/editor/inlineCompletionRateLimiter.js +46 -0
- package/dist/editor/inlineCompletionRoutes.d.ts +26 -0
- package/dist/editor/inlineCompletionRoutes.d.ts.map +1 -0
- package/dist/editor/inlineCompletionRoutes.js +404 -0
- package/dist/editor/inlineCompletionTelemetryEvidence.d.ts +5 -0
- package/dist/editor/inlineCompletionTelemetryEvidence.d.ts.map +1 -0
- package/dist/editor/inlineCompletionTelemetryEvidence.js +42 -0
- package/dist/editor/languageCancellation.d.ts +19 -0
- package/dist/editor/languageCancellation.d.ts.map +1 -0
- package/dist/editor/languageCancellation.js +48 -0
- package/dist/editor/languageProvider.d.ts +39 -0
- package/dist/editor/languageProvider.d.ts.map +1 -0
- package/dist/editor/languageProvider.js +11 -0
- package/dist/editor/languageRoutes.d.ts +15 -0
- package/dist/editor/languageRoutes.d.ts.map +1 -0
- package/dist/editor/languageRoutes.js +106 -0
- package/dist/editor/languageSanitize.d.ts +8 -0
- package/dist/editor/languageSanitize.d.ts.map +1 -0
- package/dist/editor/languageSanitize.js +101 -0
- package/dist/editor/languageService.d.ts +36 -0
- package/dist/editor/languageService.d.ts.map +1 -0
- package/dist/editor/languageService.js +93 -0
- package/dist/editor/languageServiceHost.d.ts +14 -0
- package/dist/editor/languageServiceHost.d.ts.map +1 -0
- package/dist/editor/languageServiceHost.js +242 -0
- package/dist/editor/localKnowledgeRetrieval.d.ts +21 -0
- package/dist/editor/localKnowledgeRetrieval.d.ts.map +1 -0
- package/dist/editor/localKnowledgeRetrieval.js +44 -0
- package/dist/editor/patchApplyEvidence.d.ts +21 -0
- package/dist/editor/patchApplyEvidence.d.ts.map +1 -0
- package/dist/editor/patchApplyEvidence.js +87 -0
- package/dist/editor/patchApplyRoutes.d.ts +16 -0
- package/dist/editor/patchApplyRoutes.d.ts.map +1 -0
- package/dist/editor/patchApplyRoutes.js +307 -0
- package/dist/editor/postApplyVerification.d.ts +42 -0
- package/dist/editor/postApplyVerification.d.ts.map +1 -0
- package/dist/editor/postApplyVerification.js +177 -0
- package/dist/editor/testGenerationEvidence.d.ts +6 -0
- package/dist/editor/testGenerationEvidence.d.ts.map +1 -0
- package/dist/editor/testGenerationEvidence.js +72 -0
- package/dist/editor/testGenerationPatch.d.ts +10 -0
- package/dist/editor/testGenerationPatch.d.ts.map +1 -0
- package/dist/editor/testGenerationPatch.js +66 -0
- package/dist/editor/testGenerationRoutes.d.ts +21 -0
- package/dist/editor/testGenerationRoutes.d.ts.map +1 -0
- package/dist/editor/testGenerationRoutes.js +254 -0
- package/dist/editor/testGenerationRunner.d.ts +23 -0
- package/dist/editor/testGenerationRunner.d.ts.map +1 -0
- package/dist/editor/testGenerationRunner.js +120 -0
- package/dist/editor/textOffsets.d.ts +6 -0
- package/dist/editor/textOffsets.d.ts.map +1 -0
- package/dist/editor/textOffsets.js +82 -0
- package/dist/editor/typescriptLanguageProvider.d.ts +3 -0
- package/dist/editor/typescriptLanguageProvider.d.ts.map +1 -0
- package/dist/editor/typescriptLanguageProvider.js +217 -0
- package/dist/evidence.d.ts +28 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +145 -0
- package/dist/files-deny.d.ts +3 -0
- package/dist/files-deny.d.ts.map +1 -0
- package/dist/files-deny.js +12 -0
- package/dist/files.d.ts +97 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +733 -0
- package/dist/gateway-setup.d.ts +10 -0
- package/dist/gateway-setup.d.ts.map +1 -0
- package/dist/gateway-setup.js +896 -0
- package/dist/governed-workflow.d.ts +17 -0
- package/dist/governed-workflow.d.ts.map +1 -0
- package/dist/governed-workflow.js +147 -0
- package/dist/grounded-answer.d.ts +12 -0
- package/dist/grounded-answer.d.ts.map +1 -0
- package/dist/grounded-answer.js +69 -0
- package/dist/grounded-context-index.d.ts +25 -0
- package/dist/grounded-context-index.d.ts.map +1 -0
- package/dist/grounded-context-index.js +169 -0
- package/dist/grounded-document-evidence.d.ts +28 -0
- package/dist/grounded-document-evidence.d.ts.map +1 -0
- package/dist/grounded-document-evidence.js +430 -0
- package/dist/grounded-handoff.d.ts +4 -0
- package/dist/grounded-handoff.d.ts.map +1 -0
- package/dist/grounded-handoff.js +445 -0
- package/dist/grounded-orchestrator.d.ts +43 -0
- package/dist/grounded-orchestrator.d.ts.map +1 -0
- package/dist/grounded-orchestrator.js +1445 -0
- package/dist/grounded-prompt.d.ts +2 -0
- package/dist/grounded-prompt.d.ts.map +1 -0
- package/dist/grounded-prompt.js +17 -0
- package/dist/grounded-qa-hybrid.d.ts +36 -0
- package/dist/grounded-qa-hybrid.d.ts.map +1 -0
- package/dist/grounded-qa-hybrid.js +762 -0
- package/dist/grounded-qa-multi-source.d.ts +38 -0
- package/dist/grounded-qa-multi-source.d.ts.map +1 -0
- package/dist/grounded-qa-multi-source.js +461 -0
- package/dist/grounded-qa.d.ts +45 -0
- package/dist/grounded-qa.d.ts.map +1 -0
- package/dist/grounded-qa.js +877 -0
- package/dist/grounded-rerank.d.ts +26 -0
- package/dist/grounded-rerank.d.ts.map +1 -0
- package/dist/grounded-rerank.js +72 -0
- package/dist/grounded-turn-registry.d.ts +23 -0
- package/dist/grounded-turn-registry.d.ts.map +1 -0
- package/dist/grounded-turn-registry.js +102 -0
- package/dist/headers.d.ts +3 -0
- package/dist/headers.d.ts.map +1 -0
- package/dist/headers.js +22 -0
- package/dist/host-check.d.ts +3 -0
- package/dist/host-check.d.ts.map +1 -0
- package/dist/host-check.js +58 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/load-csp.d.ts +3 -0
- package/dist/load-csp.d.ts.map +1 -0
- package/dist/load-csp.js +100 -0
- package/dist/local-knowledge-grounded-qa.d.ts +42 -0
- package/dist/local-knowledge-grounded-qa.d.ts.map +1 -0
- package/dist/local-knowledge-grounded-qa.js +678 -0
- package/dist/local-knowledge-handlers.d.ts +24 -0
- package/dist/local-knowledge-handlers.d.ts.map +1 -0
- package/dist/local-knowledge-handlers.js +1285 -0
- package/dist/local-knowledge-indexing-registry.d.ts +13 -0
- package/dist/local-knowledge-indexing-registry.d.ts.map +1 -0
- package/dist/local-knowledge-indexing-registry.js +53 -0
- package/dist/localKnowledgeKeyProvider.d.ts +11 -0
- package/dist/localKnowledgeKeyProvider.d.ts.map +1 -0
- package/dist/localKnowledgeKeyProvider.js +48 -0
- package/dist/memory-audit-event-builders.d.ts +21 -0
- package/dist/memory-audit-event-builders.d.ts.map +1 -0
- package/dist/memory-audit-event-builders.js +187 -0
- package/dist/memory-audit-handler.d.ts +23 -0
- package/dist/memory-audit-handler.d.ts.map +1 -0
- package/dist/memory-audit-handler.js +191 -0
- package/dist/memory-capture-policy.d.ts +10 -0
- package/dist/memory-capture-policy.d.ts.map +1 -0
- package/dist/memory-capture-policy.js +44 -0
- package/dist/memory-consolidation-handlers.d.ts +6 -0
- package/dist/memory-consolidation-handlers.d.ts.map +1 -0
- package/dist/memory-consolidation-handlers.js +491 -0
- package/dist/memory-consolidation-registry.d.ts +47 -0
- package/dist/memory-consolidation-registry.d.ts.map +1 -0
- package/dist/memory-consolidation-registry.js +106 -0
- package/dist/memory-conv-handlers.d.ts +8 -0
- package/dist/memory-conv-handlers.d.ts.map +1 -0
- package/dist/memory-conv-handlers.js +369 -0
- package/dist/memory-conversation-context.d.ts +13 -0
- package/dist/memory-conversation-context.d.ts.map +1 -0
- package/dist/memory-conversation-context.js +22 -0
- package/dist/memory-diagnostics.d.ts +29 -0
- package/dist/memory-diagnostics.d.ts.map +1 -0
- package/dist/memory-diagnostics.js +122 -0
- package/dist/memory-embedding.d.ts +21 -0
- package/dist/memory-embedding.d.ts.map +1 -0
- package/dist/memory-embedding.js +264 -0
- package/dist/memory-handlers.d.ts +19 -0
- package/dist/memory-handlers.d.ts.map +1 -0
- package/dist/memory-handlers.js +1204 -0
- package/dist/memory-maintenance-handlers.d.ts +35 -0
- package/dist/memory-maintenance-handlers.d.ts.map +1 -0
- package/dist/memory-maintenance-handlers.js +219 -0
- package/dist/memory-record-builders.d.ts +4 -0
- package/dist/memory-record-builders.d.ts.map +1 -0
- package/dist/memory-record-builders.js +19 -0
- package/dist/memory-retention.d.ts +31 -0
- package/dist/memory-retention.d.ts.map +1 -0
- package/dist/memory-retention.js +151 -0
- package/dist/memory-retrieval-signals.d.ts +12 -0
- package/dist/memory-retrieval-signals.d.ts.map +1 -0
- package/dist/memory-retrieval-signals.js +100 -0
- package/dist/memory-salience.d.ts +12 -0
- package/dist/memory-salience.d.ts.map +1 -0
- package/dist/memory-salience.js +154 -0
- package/dist/memory-scope-sanitizer.d.ts +6 -0
- package/dist/memory-scope-sanitizer.d.ts.map +1 -0
- package/dist/memory-scope-sanitizer.js +106 -0
- package/dist/memory-target-resolver.d.ts +4 -0
- package/dist/memory-target-resolver.d.ts.map +1 -0
- package/dist/memory-target-resolver.js +73 -0
- package/dist/memory-workflow-port.d.ts +14 -0
- package/dist/memory-workflow-port.d.ts.map +1 -0
- package/dist/memory-workflow-port.js +186 -0
- package/dist/private-json.d.ts +3 -0
- package/dist/private-json.d.ts.map +1 -0
- package/dist/private-json.js +62 -0
- package/dist/promptEnhancer/index.d.ts +3 -0
- package/dist/promptEnhancer/index.d.ts.map +1 -0
- package/dist/promptEnhancer/index.js +5 -0
- package/dist/promptEnhancer/orchestrate.d.ts +2 -0
- package/dist/promptEnhancer/orchestrate.d.ts.map +1 -0
- package/dist/promptEnhancer/orchestrate.js +5 -0
- package/dist/promptEnhancer/routes.d.ts +9 -0
- package/dist/promptEnhancer/routes.d.ts.map +1 -0
- package/dist/promptEnhancer/routes.js +205 -0
- package/dist/qualityIntelligence/capsuleAdapter.d.ts +27 -0
- package/dist/qualityIntelligence/capsuleAdapter.d.ts.map +1 -0
- package/dist/qualityIntelligence/capsuleAdapter.js +57 -0
- package/dist/qualityIntelligence/connectorAuthorization.d.ts +22 -0
- package/dist/qualityIntelligence/connectorAuthorization.d.ts.map +1 -0
- package/dist/qualityIntelligence/connectorAuthorization.js +35 -0
- package/dist/qualityIntelligence/connectorErrors.d.ts +16 -0
- package/dist/qualityIntelligence/connectorErrors.d.ts.map +1 -0
- package/dist/qualityIntelligence/connectorErrors.js +56 -0
- package/dist/qualityIntelligence/connectorRoutes.d.ts +7 -0
- package/dist/qualityIntelligence/connectorRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/connectorRoutes.js +167 -0
- package/dist/qualityIntelligence/editRoutes.d.ts +5 -0
- package/dist/qualityIntelligence/editRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/editRoutes.js +293 -0
- package/dist/qualityIntelligence/exportAssembly.d.ts +22 -0
- package/dist/qualityIntelligence/exportAssembly.d.ts.map +1 -0
- package/dist/qualityIntelligence/exportAssembly.js +352 -0
- package/dist/qualityIntelligence/exportRoutes.d.ts +5 -0
- package/dist/qualityIntelligence/exportRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/exportRoutes.js +320 -0
- package/dist/qualityIntelligence/figma/figmaConcurrency.d.ts +8 -0
- package/dist/qualityIntelligence/figma/figmaConcurrency.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaConcurrency.js +34 -0
- package/dist/qualityIntelligence/figma/figmaConnector.d.ts +65 -0
- package/dist/qualityIntelligence/figma/figmaConnector.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaConnector.js +184 -0
- package/dist/qualityIntelligence/figma/figmaConnectorAudit.d.ts +52 -0
- package/dist/qualityIntelligence/figma/figmaConnectorAudit.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaConnectorAudit.js +63 -0
- package/dist/qualityIntelligence/figma/figmaConnectorErrors.d.ts +31 -0
- package/dist/qualityIntelligence/figma/figmaConnectorErrors.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaConnectorErrors.js +220 -0
- package/dist/qualityIntelligence/figma/figmaConnectorMetrics.d.ts +44 -0
- package/dist/qualityIntelligence/figma/figmaConnectorMetrics.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaConnectorMetrics.js +49 -0
- package/dist/qualityIntelligence/figma/figmaConsent.d.ts +39 -0
- package/dist/qualityIntelligence/figma/figmaConsent.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaConsent.js +62 -0
- package/dist/qualityIntelligence/figma/figmaHttpPort.d.ts +28 -0
- package/dist/qualityIntelligence/figma/figmaHttpPort.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaHttpPort.js +70 -0
- package/dist/qualityIntelligence/figma/figmaObservedActions.d.ts +49 -0
- package/dist/qualityIntelligence/figma/figmaObservedActions.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaObservedActions.js +89 -0
- package/dist/qualityIntelligence/figma/figmaReadiness.d.ts +32 -0
- package/dist/qualityIntelligence/figma/figmaReadiness.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaReadiness.js +67 -0
- package/dist/qualityIntelligence/figma/figmaRenderPort.d.ts +29 -0
- package/dist/qualityIntelligence/figma/figmaRenderPort.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaRenderPort.js +93 -0
- package/dist/qualityIntelligence/figma/figmaResnapshot.d.ts +28 -0
- package/dist/qualityIntelligence/figma/figmaResnapshot.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaResnapshot.js +38 -0
- package/dist/qualityIntelligence/figma/figmaRetry.d.ts +31 -0
- package/dist/qualityIntelligence/figma/figmaRetry.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaRetry.js +62 -0
- package/dist/qualityIntelligence/figma/figmaScopeRef.d.ts +9 -0
- package/dist/qualityIntelligence/figma/figmaScopeRef.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaScopeRef.js +18 -0
- package/dist/qualityIntelligence/figma/figmaScopedPagination.d.ts +86 -0
- package/dist/qualityIntelligence/figma/figmaScopedPagination.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaScopedPagination.js +308 -0
- package/dist/qualityIntelligence/figma/figmaSnapshotBuilder.d.ts +31 -0
- package/dist/qualityIntelligence/figma/figmaSnapshotBuilder.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaSnapshotBuilder.js +314 -0
- package/dist/qualityIntelligence/figma/figmaSnapshotHash.d.ts +18 -0
- package/dist/qualityIntelligence/figma/figmaSnapshotHash.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaSnapshotHash.js +63 -0
- package/dist/qualityIntelligence/figma/figmaSnapshotTypes.d.ts +65 -0
- package/dist/qualityIntelligence/figma/figmaSnapshotTypes.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaSnapshotTypes.js +13 -0
- package/dist/qualityIntelligence/figma/figmaTokenSource.d.ts +9 -0
- package/dist/qualityIntelligence/figma/figmaTokenSource.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaTokenSource.js +61 -0
- package/dist/qualityIntelligence/figma/figmaTokenStore.d.ts +19 -0
- package/dist/qualityIntelligence/figma/figmaTokenStore.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaTokenStore.js +156 -0
- package/dist/qualityIntelligence/figma/figmaUrl.d.ts +6 -0
- package/dist/qualityIntelligence/figma/figmaUrl.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/figmaUrl.js +36 -0
- package/dist/qualityIntelligence/figma/index.d.ts +20 -0
- package/dist/qualityIntelligence/figma/index.d.ts.map +1 -0
- package/dist/qualityIntelligence/figma/index.js +26 -0
- package/dist/qualityIntelligence/figmaCodegenRoutes.d.ts +28 -0
- package/dist/qualityIntelligence/figmaCodegenRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/figmaCodegenRoutes.js +165 -0
- package/dist/qualityIntelligence/figmaSnapshotAdapter.d.ts +55 -0
- package/dist/qualityIntelligence/figmaSnapshotAdapter.d.ts.map +1 -0
- package/dist/qualityIntelligence/figmaSnapshotAdapter.js +219 -0
- package/dist/qualityIntelligence/figmaSnapshotOrchestration.d.ts +64 -0
- package/dist/qualityIntelligence/figmaSnapshotOrchestration.d.ts.map +1 -0
- package/dist/qualityIntelligence/figmaSnapshotOrchestration.js +203 -0
- package/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts +112 -0
- package/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/figmaSnapshotRoutes.js +1063 -0
- package/dist/qualityIntelligence/figmaSnapshotScreenIds.d.ts +19 -0
- package/dist/qualityIntelligence/figmaSnapshotScreenIds.d.ts.map +1 -0
- package/dist/qualityIntelligence/figmaSnapshotScreenIds.js +75 -0
- package/dist/qualityIntelligence/generationPort.d.ts +15 -0
- package/dist/qualityIntelligence/generationPort.d.ts.map +1 -0
- package/dist/qualityIntelligence/generationPort.js +185 -0
- package/dist/qualityIntelligence/handoffErrors.d.ts +9 -0
- package/dist/qualityIntelligence/handoffErrors.d.ts.map +1 -0
- package/dist/qualityIntelligence/handoffErrors.js +21 -0
- package/dist/qualityIntelligence/handoffRoutes.d.ts +15 -0
- package/dist/qualityIntelligence/handoffRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/handoffRoutes.js +341 -0
- package/dist/qualityIntelligence/index.d.ts +17 -0
- package/dist/qualityIntelligence/index.d.ts.map +1 -0
- package/dist/qualityIntelligence/index.js +36 -0
- package/dist/qualityIntelligence/judgePort.d.ts +30 -0
- package/dist/qualityIntelligence/judgePort.d.ts.map +1 -0
- package/dist/qualityIntelligence/judgePort.js +326 -0
- package/dist/qualityIntelligence/modelSelection.d.ts +58 -0
- package/dist/qualityIntelligence/modelSelection.d.ts.map +1 -0
- package/dist/qualityIntelligence/modelSelection.js +148 -0
- package/dist/qualityIntelligence/reCheckRoutes.d.ts +6 -0
- package/dist/qualityIntelligence/reCheckRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/reCheckRoutes.js +1157 -0
- package/dist/qualityIntelligence/retentionEnforcement.d.ts +13 -0
- package/dist/qualityIntelligence/retentionEnforcement.d.ts.map +1 -0
- package/dist/qualityIntelligence/retentionEnforcement.js +47 -0
- package/dist/qualityIntelligence/retentionRoutes.d.ts +8 -0
- package/dist/qualityIntelligence/retentionRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/retentionRoutes.js +74 -0
- package/dist/qualityIntelligence/reviewRoutes.d.ts +5 -0
- package/dist/qualityIntelligence/reviewRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/reviewRoutes.js +145 -0
- package/dist/qualityIntelligence/reviewStore.d.ts +75 -0
- package/dist/qualityIntelligence/reviewStore.d.ts.map +1 -0
- package/dist/qualityIntelligence/reviewStore.js +170 -0
- package/dist/qualityIntelligence/runExecution.d.ts +36 -0
- package/dist/qualityIntelligence/runExecution.d.ts.map +1 -0
- package/dist/qualityIntelligence/runExecution.js +180 -0
- package/dist/qualityIntelligence/runIngestion.d.ts +70 -0
- package/dist/qualityIntelligence/runIngestion.d.ts.map +1 -0
- package/dist/qualityIntelligence/runIngestion.js +1235 -0
- package/dist/qualityIntelligence/runRegistry.d.ts +31 -0
- package/dist/qualityIntelligence/runRegistry.d.ts.map +1 -0
- package/dist/qualityIntelligence/runRegistry.js +66 -0
- package/dist/qualityIntelligence/runRoutes.d.ts +16 -0
- package/dist/qualityIntelligence/runRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/runRoutes.js +357 -0
- package/dist/qualityIntelligence/traceabilityRoutes.d.ts +5 -0
- package/dist/qualityIntelligence/traceabilityRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/traceabilityRoutes.js +173 -0
- package/dist/qualityIntelligence/uiRoutes.d.ts +7 -0
- package/dist/qualityIntelligence/uiRoutes.d.ts.map +1 -0
- package/dist/qualityIntelligence/uiRoutes.js +336 -0
- package/dist/read-handlers.d.ts +9 -0
- package/dist/read-handlers.d.ts.map +1 -0
- package/dist/read-handlers.js +265 -0
- package/dist/relationship-handlers.d.ts +191 -0
- package/dist/relationship-handlers.d.ts.map +1 -0
- package/dist/relationship-handlers.js +0 -0
- package/dist/routes.d.ts +37 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +507 -0
- package/dist/run-engine.d.ts +25 -0
- package/dist/run-engine.d.ts.map +1 -0
- package/dist/run-engine.js +385 -0
- package/dist/run-handlers.d.ts +9 -0
- package/dist/run-handlers.d.ts.map +1 -0
- package/dist/run-handlers.js +465 -0
- package/dist/run-request.d.ts +17 -0
- package/dist/run-request.d.ts.map +1 -0
- package/dist/run-request.js +219 -0
- package/dist/runs.d.ts +47 -0
- package/dist/runs.d.ts.map +1 -0
- package/dist/runs.js +100 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +152 -0
- package/dist/sink.d.ts +28 -0
- package/dist/sink.d.ts.map +1 -0
- package/dist/sink.js +80 -0
- package/dist/sse-write.d.ts +9 -0
- package/dist/sse-write.d.ts.map +1 -0
- package/dist/sse-write.js +26 -0
- package/dist/sse.d.ts +8 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +27 -0
- package/dist/static.d.ts +5 -0
- package/dist/static.d.ts.map +1 -0
- package/dist/static.js +76 -0
- package/dist/store/chats.d.ts +17 -0
- package/dist/store/chats.d.ts.map +1 -0
- package/dist/store/chats.js +624 -0
- package/dist/store/db.d.ts +11 -0
- package/dist/store/db.d.ts.map +1 -0
- package/dist/store/db.js +203 -0
- package/dist/store/errors.d.ts +13 -0
- package/dist/store/errors.d.ts.map +1 -0
- package/dist/store/errors.js +30 -0
- package/dist/store/index.d.ts +7 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +6 -0
- package/dist/store/messages.d.ts +8 -0
- package/dist/store/messages.d.ts.map +1 -0
- package/dist/store/messages.js +149 -0
- package/dist/store/paths.d.ts +5 -0
- package/dist/store/paths.d.ts.map +1 -0
- package/dist/store/paths.js +84 -0
- package/dist/store/projects.d.ts +8 -0
- package/dist/store/projects.d.ts.map +1 -0
- package/dist/store/projects.js +59 -0
- package/dist/store/relationship-audit.d.ts +42 -0
- package/dist/store/relationship-audit.d.ts.map +1 -0
- package/dist/store/relationship-audit.js +155 -0
- package/dist/store/relationships.d.ts +191 -0
- package/dist/store/relationships.d.ts.map +1 -0
- package/dist/store/relationships.js +724 -0
- package/dist/store/schema.d.ts +4 -0
- package/dist/store/schema.d.ts.map +1 -0
- package/dist/store/schema.js +220 -0
- package/dist/store/types.d.ts +29 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/types.js +8 -0
- package/dist/store/validation.d.ts +7 -0
- package/dist/store/validation.d.ts.map +1 -0
- package/dist/store/validation.js +117 -0
- package/dist/store-handlers.d.ts +17 -0
- package/dist/store-handlers.d.ts.map +1 -0
- package/dist/store-handlers.js +872 -0
- package/dist/terminal-errors.d.ts +22 -0
- package/dist/terminal-errors.d.ts.map +1 -0
- package/dist/terminal-errors.js +45 -0
- package/dist/terminal-evidence.d.ts +21 -0
- package/dist/terminal-evidence.d.ts.map +1 -0
- package/dist/terminal-evidence.js +65 -0
- package/dist/terminal-routes.d.ts +10 -0
- package/dist/terminal-routes.d.ts.map +1 -0
- package/dist/terminal-routes.js +219 -0
- package/dist/terminal.d.ts +68 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +855 -0
- package/package.json +52 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { QualityIntelligenceUiRunSummary } from "@oscharko-dev/keiko-contracts";
|
|
2
|
+
export type QiActiveRunStatus = "running" | "succeeded" | "failed" | "cancelled";
|
|
3
|
+
interface QiActiveRun {
|
|
4
|
+
readonly runId: string;
|
|
5
|
+
status: QiActiveRunStatus;
|
|
6
|
+
readonly requestedAt: string;
|
|
7
|
+
readonly controller: AbortController;
|
|
8
|
+
totals: {
|
|
9
|
+
candidates: number;
|
|
10
|
+
findings: number;
|
|
11
|
+
exports: number;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare class QiRunRegistry {
|
|
15
|
+
private readonly runs;
|
|
16
|
+
/** Register a starting run and return its AbortController so the executor can wire cancellation. */
|
|
17
|
+
register(runId: string, requestedAt: string): AbortController;
|
|
18
|
+
updateTotals(runId: string, totals: Partial<QiActiveRun["totals"]>): void;
|
|
19
|
+
/** Mark terminal and drop the run from the active set (it is now durable in evidence). */
|
|
20
|
+
complete(runId: string, status: Exclude<QiActiveRunStatus, "running">): void;
|
|
21
|
+
/** Request cancellation. Returns false when the run is unknown/already finished. */
|
|
22
|
+
cancel(runId: string): boolean;
|
|
23
|
+
isActive(runId: string): boolean;
|
|
24
|
+
/** Active-run summaries for merging into the run list (status always "running"). */
|
|
25
|
+
listActiveSummaries(): readonly QualityIntelligenceUiRunSummary[];
|
|
26
|
+
/** Test seam: clear all active runs. */
|
|
27
|
+
reset(): void;
|
|
28
|
+
}
|
|
29
|
+
export declare const qiRunRegistry: QiRunRegistry;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=runRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runRegistry.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/runRegistry.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAErF,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEjF,UAAU,WAAW;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACnE;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkC;IAEvD,oGAAoG;IACpG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,eAAe;IAY7D,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI;IAMzE,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,iBAAiB,EAAE,SAAS,CAAC,GAAG,IAAI;IAM5E,oFAAoF;IACpF,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAO9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIhC,oFAAoF;IACpF,mBAAmB,IAAI,SAAS,+BAA+B,EAAE;IAYjE,wCAAwC;IACxC,KAAK,IAAI,IAAI;CAId;AAGD,eAAO,MAAM,aAAa,eAAsB,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Quality Intelligence in-memory active-run registry (Epic #270, Issue #273/#280).
|
|
2
|
+
//
|
|
3
|
+
// Tracks runs that are CURRENTLY executing so the UI can (a) see a run as "running" in the run list
|
|
4
|
+
// before it lands in evidence and (b) cancel it. Completed runs live in evidence (restart-safe);
|
|
5
|
+
// the registry only holds in-flight runs and is intentionally process-local — on restart, in-flight
|
|
6
|
+
// runs are gone (they were never persisted) while completed runs survive. This is the QI counterpart
|
|
7
|
+
// of the harness RunRegistry, kept separate because QI runs carry the QI run-event envelope.
|
|
8
|
+
export class QiRunRegistry {
|
|
9
|
+
runs = new Map();
|
|
10
|
+
/** Register a starting run and return its AbortController so the executor can wire cancellation. */
|
|
11
|
+
register(runId, requestedAt) {
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
this.runs.set(runId, {
|
|
14
|
+
runId,
|
|
15
|
+
status: "running",
|
|
16
|
+
requestedAt,
|
|
17
|
+
controller,
|
|
18
|
+
totals: { candidates: 0, findings: 0, exports: 0 },
|
|
19
|
+
});
|
|
20
|
+
return controller;
|
|
21
|
+
}
|
|
22
|
+
updateTotals(runId, totals) {
|
|
23
|
+
const run = this.runs.get(runId);
|
|
24
|
+
if (run === undefined)
|
|
25
|
+
return;
|
|
26
|
+
run.totals = { ...run.totals, ...totals };
|
|
27
|
+
}
|
|
28
|
+
/** Mark terminal and drop the run from the active set (it is now durable in evidence). */
|
|
29
|
+
complete(runId, status) {
|
|
30
|
+
const run = this.runs.get(runId);
|
|
31
|
+
if (run !== undefined)
|
|
32
|
+
run.status = status;
|
|
33
|
+
this.runs.delete(runId);
|
|
34
|
+
}
|
|
35
|
+
/** Request cancellation. Returns false when the run is unknown/already finished. */
|
|
36
|
+
cancel(runId) {
|
|
37
|
+
const run = this.runs.get(runId);
|
|
38
|
+
if (run === undefined)
|
|
39
|
+
return false;
|
|
40
|
+
run.controller.abort();
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
isActive(runId) {
|
|
44
|
+
return this.runs.has(runId);
|
|
45
|
+
}
|
|
46
|
+
/** Active-run summaries for merging into the run list (status always "running"). */
|
|
47
|
+
listActiveSummaries() {
|
|
48
|
+
return [...this.runs.values()].map((run) => ({
|
|
49
|
+
id: run.runId,
|
|
50
|
+
status: "running",
|
|
51
|
+
requestedAt: run.requestedAt,
|
|
52
|
+
completedAt: null,
|
|
53
|
+
totals: { ...run.totals },
|
|
54
|
+
// An in-flight run is not yet persisted and cannot have been reviewed (Issue #282 FIX A11y-2).
|
|
55
|
+
reviewState: "open",
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
/** Test seam: clear all active runs. */
|
|
59
|
+
reset() {
|
|
60
|
+
for (const run of this.runs.values())
|
|
61
|
+
run.controller.abort();
|
|
62
|
+
this.runs.clear();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Process-local singleton shared by the start, cancel, and list routes.
|
|
66
|
+
export const qiRunRegistry = new QiRunRegistry();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { QualityIntelligenceRunStreamMessage } from "@oscharko-dev/keiko-contracts";
|
|
2
|
+
import type { QualityIntelligence as QI } from "@oscharko-dev/keiko-contracts";
|
|
3
|
+
import { type HandlerOutcome, type RouteContext, type RouteResult, type RouteDefinition } from "../routes.js";
|
|
4
|
+
import type { Redactor, UiHandlerDeps } from "../deps.js";
|
|
5
|
+
import { executeQiRun } from "./runExecution.js";
|
|
6
|
+
export declare function toStreamEvent(event: QI.QualityIntelligenceRunEvent, redact: Redactor): QualityIntelligenceRunStreamMessage;
|
|
7
|
+
type QiExecutionSummary = Awaited<ReturnType<typeof executeQiRun>>;
|
|
8
|
+
type StreamTotals = Extract<QualityIntelligenceRunStreamMessage, {
|
|
9
|
+
type: "done";
|
|
10
|
+
}>["totals"];
|
|
11
|
+
export declare function doneFrameForSummary(deps: UiHandlerDeps, runId: string, summary: QiExecutionSummary, totals: StreamTotals): QualityIntelligenceRunStreamMessage;
|
|
12
|
+
export declare function handleStartQiRun(ctx: RouteContext, deps: UiHandlerDeps): Promise<HandlerOutcome>;
|
|
13
|
+
export declare function handleCancelQiRun(ctx: RouteContext, _deps: UiHandlerDeps): RouteResult;
|
|
14
|
+
export declare const QI_RUN_EXECUTION_ROUTE_GROUP: readonly RouteDefinition[];
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=runRoutes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runRoutes.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/runRoutes.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAMV,mCAAmC,EAGpC,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,mBAAmB,IAAI,EAAE,EAAE,MAAM,+BAA+B,CAAC;AAG/E,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EACL,YAAY,EAIb,MAAM,mBAAmB,CAAC;AA4Q3B,wBAAgB,aAAa,CAC3B,KAAK,EAAE,EAAE,CAAC,2BAA2B,EACrC,MAAM,EAAE,QAAQ,GACf,mCAAmC,CAgBrC;AAkBD,KAAK,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC;AACnE,KAAK,YAAY,GAAG,OAAO,CAAC,mCAAmC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;AA0B7F,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,YAAY,GACnB,mCAAmC,CAiBrC;AAuCD,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,cAAc,CAAC,CAoBzB;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,GAAG,WAAW,CAStF;AAED,eAAO,MAAM,4BAA4B,EAAE,SAAS,eAAe,EAOlE,CAAC"}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
// Quality Intelligence run start + cancel BFF routes (Epic #270, Issue #273/#280).
|
|
2
|
+
//
|
|
3
|
+
// * POST /api/quality-intelligence/runs — start a run; responds with an SSE progress stream
|
|
4
|
+
// * POST /api/quality-intelligence/runs/:id/cancel — cancel an in-flight run
|
|
5
|
+
//
|
|
6
|
+
// The start route validates the body, then writes a `text/event-stream` of
|
|
7
|
+
// `QualityIntelligenceRunStreamMessage`s as the run progresses (accepted → events → done|error).
|
|
8
|
+
// All stream payloads carry only ids / counts / safe enums — never prompts, model output, source
|
|
9
|
+
// content, or credentials. A client disconnect aborts the run via the registry.
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
11
|
+
import { isAbsolute } from "node:path";
|
|
12
|
+
import { SSE_HEADERS } from "../sse.js";
|
|
13
|
+
import { writeOrDestroy } from "../sse-write.js";
|
|
14
|
+
import { STREAMING, } from "../routes.js";
|
|
15
|
+
import { executeQiRun, QiGenerationError, QiIngestionError, } from "./runExecution.js";
|
|
16
|
+
import { parseFigmaSnapshotScreenIds } from "./figmaSnapshotScreenIds.js";
|
|
17
|
+
import { qiRunRegistry } from "./runRegistry.js";
|
|
18
|
+
const MAX_BODY_BYTES = 2 * 1024 * 1024;
|
|
19
|
+
class BodyTooLargeError extends Error {
|
|
20
|
+
}
|
|
21
|
+
const readBody = (req) => new Promise((resolve, reject) => {
|
|
22
|
+
const chunks = [];
|
|
23
|
+
let total = 0;
|
|
24
|
+
let capped = false;
|
|
25
|
+
req.on("data", (chunk) => {
|
|
26
|
+
total += chunk.length;
|
|
27
|
+
if (total > MAX_BODY_BYTES) {
|
|
28
|
+
if (!capped) {
|
|
29
|
+
capped = true;
|
|
30
|
+
chunks.length = 0;
|
|
31
|
+
reject(new BodyTooLargeError());
|
|
32
|
+
req.resume();
|
|
33
|
+
}
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
chunks.push(chunk);
|
|
37
|
+
});
|
|
38
|
+
req.on("end", () => {
|
|
39
|
+
if (!capped)
|
|
40
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
41
|
+
});
|
|
42
|
+
req.on("error", reject);
|
|
43
|
+
});
|
|
44
|
+
const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45
|
+
const errorResult = (status, code, message) => ({
|
|
46
|
+
status,
|
|
47
|
+
body: { error: { code, message } },
|
|
48
|
+
});
|
|
49
|
+
function validateCapsuleSource(label, raw) {
|
|
50
|
+
if (typeof raw.capsuleId !== "string" || raw.capsuleId.trim().length === 0) {
|
|
51
|
+
return errorResult(400, "QI_BAD_REQUEST", "A capsule source requires a non-empty capsuleId.");
|
|
52
|
+
}
|
|
53
|
+
return { kind: "capsule", label, capsuleId: raw.capsuleId };
|
|
54
|
+
}
|
|
55
|
+
function validateCapsuleSetSource(label, raw) {
|
|
56
|
+
if (typeof raw.capsuleSetId !== "string" || raw.capsuleSetId.trim().length === 0) {
|
|
57
|
+
return errorResult(400, "QI_BAD_REQUEST", "A capsule-set source requires a non-empty capsuleSetId.");
|
|
58
|
+
}
|
|
59
|
+
return { kind: "capsule-set", label, capsuleSetId: raw.capsuleSetId };
|
|
60
|
+
}
|
|
61
|
+
function validateFigmaSnapshotSource(label, raw) {
|
|
62
|
+
if (typeof raw.snapshotRunId !== "string" || raw.snapshotRunId.trim().length === 0) {
|
|
63
|
+
return errorResult(400, "QI_BAD_REQUEST", "A figma-snapshot source requires a non-empty snapshotRunId.");
|
|
64
|
+
}
|
|
65
|
+
// Single source of truth shared with the re-check route so run/recheck never diverge. An absent
|
|
66
|
+
// field stays a whole-snapshot source; a present field must be a non-empty, bounded, canonicalised
|
|
67
|
+
// scope — an explicit empty array is rejected here so it can never silently widen to the whole board.
|
|
68
|
+
const parsed = parseFigmaSnapshotScreenIds(raw.screenIds);
|
|
69
|
+
if (!parsed.ok) {
|
|
70
|
+
return errorResult(400, "QI_BAD_REQUEST", parsed.reason);
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
kind: "figma-snapshot",
|
|
74
|
+
label,
|
|
75
|
+
snapshotRunId: raw.snapshotRunId,
|
|
76
|
+
...(parsed.screenIds !== undefined ? { screenIds: parsed.screenIds } : {}),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function validateImageSource(label, raw) {
|
|
80
|
+
if (raw.sourceKind !== "figma-snapshot-screen") {
|
|
81
|
+
return errorResult(400, "QI_BAD_REQUEST", "An image source requires sourceKind figma-snapshot-screen.");
|
|
82
|
+
}
|
|
83
|
+
if (typeof raw.snapshotRunId !== "string" || raw.snapshotRunId.trim().length === 0) {
|
|
84
|
+
return errorResult(400, "QI_BAD_REQUEST", "An image source requires a non-empty snapshotRunId.");
|
|
85
|
+
}
|
|
86
|
+
if (typeof raw.screenId !== "string" || raw.screenId.trim().length === 0) {
|
|
87
|
+
return errorResult(400, "QI_BAD_REQUEST", "An image source requires a non-empty screenId.");
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
kind: "image",
|
|
91
|
+
label,
|
|
92
|
+
sourceKind: "figma-snapshot-screen",
|
|
93
|
+
snapshotRunId: raw.snapshotRunId,
|
|
94
|
+
screenId: raw.screenId,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// Connector sources (Local Knowledge capsule / capsule-set, Figma snapshot). Split out so
|
|
98
|
+
// validateSource stays under the complexity budget as the source-kind union grows (Epic #710/#750).
|
|
99
|
+
function validateConnectorSource(label, raw) {
|
|
100
|
+
if (raw.kind === "capsule") {
|
|
101
|
+
return validateCapsuleSource(label, raw);
|
|
102
|
+
}
|
|
103
|
+
if (raw.kind === "capsule-set") {
|
|
104
|
+
return validateCapsuleSetSource(label, raw);
|
|
105
|
+
}
|
|
106
|
+
if (raw.kind === "figma-snapshot") {
|
|
107
|
+
return validateFigmaSnapshotSource(label, raw);
|
|
108
|
+
}
|
|
109
|
+
if (raw.kind === "image") {
|
|
110
|
+
return validateImageSource(label, raw);
|
|
111
|
+
}
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
function validateSource(raw) {
|
|
115
|
+
if (!isObject(raw) || typeof raw.label !== "string")
|
|
116
|
+
return undefined;
|
|
117
|
+
const label = raw.label;
|
|
118
|
+
if (raw.kind === "requirements" && typeof raw.text === "string") {
|
|
119
|
+
return { kind: "requirements", label, text: raw.text };
|
|
120
|
+
}
|
|
121
|
+
if (raw.kind === "workspace" && typeof raw.path === "string") {
|
|
122
|
+
return { kind: "workspace", label, path: raw.path };
|
|
123
|
+
}
|
|
124
|
+
if (raw.kind === "file" && typeof raw.path === "string") {
|
|
125
|
+
return { kind: "file", label, path: raw.path };
|
|
126
|
+
}
|
|
127
|
+
return validateConnectorSource(label, raw);
|
|
128
|
+
}
|
|
129
|
+
function isRouteResult(v) {
|
|
130
|
+
return isObject(v) && typeof v.status === "number";
|
|
131
|
+
}
|
|
132
|
+
function validateSourceEntry(raw) {
|
|
133
|
+
const source = validateSource(raw);
|
|
134
|
+
if (source === undefined) {
|
|
135
|
+
return errorResult(400, "QI_BAD_SOURCE", "A source entry is malformed.");
|
|
136
|
+
}
|
|
137
|
+
// A capsule (or other) field-level validation failure surfaces as a RouteResult — propagate it.
|
|
138
|
+
if (isRouteResult(source)) {
|
|
139
|
+
return source;
|
|
140
|
+
}
|
|
141
|
+
if (source.kind === "file" && !isAbsolute(source.path)) {
|
|
142
|
+
return errorResult(400, "QI_BAD_SOURCE", "File source paths must be absolute local paths.");
|
|
143
|
+
}
|
|
144
|
+
return source;
|
|
145
|
+
}
|
|
146
|
+
function collectSources(rawSources) {
|
|
147
|
+
const sources = [];
|
|
148
|
+
for (const raw of rawSources) {
|
|
149
|
+
// validateSourceEntry adds the absolute-path guard for file sources (#791) on top of the
|
|
150
|
+
// shape + capsule validation, surfacing any failure as a RouteResult.
|
|
151
|
+
const source = validateSourceEntry(raw);
|
|
152
|
+
if (isRouteResult(source)) {
|
|
153
|
+
return { ok: false, result: source };
|
|
154
|
+
}
|
|
155
|
+
sources.push(source);
|
|
156
|
+
}
|
|
157
|
+
return { ok: true, sources };
|
|
158
|
+
}
|
|
159
|
+
function parseOptionalSeed(value) {
|
|
160
|
+
if (value === undefined)
|
|
161
|
+
return undefined;
|
|
162
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
163
|
+
}
|
|
164
|
+
function buildStartRequest(sources, profileId, modelId, seed) {
|
|
165
|
+
return {
|
|
166
|
+
sources,
|
|
167
|
+
...(profileId ? { profileId } : {}),
|
|
168
|
+
...(modelId ? { modelId } : {}),
|
|
169
|
+
...(seed !== undefined ? { seed } : {}),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function validateRequest(parsed) {
|
|
173
|
+
if (!isObject(parsed) || !Array.isArray(parsed.sources) || parsed.sources.length === 0) {
|
|
174
|
+
return {
|
|
175
|
+
ok: false,
|
|
176
|
+
result: errorResult(400, "QI_BAD_REQUEST", "At least one source is required."),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const collected = collectSources(parsed.sources);
|
|
180
|
+
if (!collected.ok)
|
|
181
|
+
return collected;
|
|
182
|
+
const profileId = typeof parsed.profileId === "string" ? parsed.profileId : undefined;
|
|
183
|
+
const modelId = typeof parsed.modelId === "string" ? parsed.modelId : undefined;
|
|
184
|
+
const seed = parseOptionalSeed(parsed.seed);
|
|
185
|
+
if (seed === null) {
|
|
186
|
+
return {
|
|
187
|
+
ok: false,
|
|
188
|
+
result: errorResult(400, "QI_BAD_REQUEST", "Seed must be a non-negative safe integer when provided."),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
ok: true,
|
|
193
|
+
request: buildStartRequest(collected.sources, profileId, modelId, seed),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
async function parseStartBody(req) {
|
|
197
|
+
let raw;
|
|
198
|
+
try {
|
|
199
|
+
raw = await readBody(req);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
return error instanceof BodyTooLargeError
|
|
203
|
+
? { ok: false, result: errorResult(413, "QI_BODY_TOO_LARGE", "Request body is too large.") }
|
|
204
|
+
: { ok: false, result: errorResult(400, "QI_BAD_REQUEST", "Could not read request body.") };
|
|
205
|
+
}
|
|
206
|
+
let parsed;
|
|
207
|
+
try {
|
|
208
|
+
parsed = JSON.parse(raw);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return {
|
|
212
|
+
ok: false,
|
|
213
|
+
result: errorResult(400, "QI_BAD_REQUEST", "Request body is not valid JSON."),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return validateRequest(parsed);
|
|
217
|
+
}
|
|
218
|
+
// Exported for unit testing of the reasonSummary redaction backstop (#279 AC3); not part of the
|
|
219
|
+
// package public surface (the QI index re-exports only the route handlers, not this helper).
|
|
220
|
+
export function toStreamEvent(event, redact) {
|
|
221
|
+
const p = event.payload;
|
|
222
|
+
return {
|
|
223
|
+
type: "event",
|
|
224
|
+
kind: p.kind,
|
|
225
|
+
sequence: event.sequence,
|
|
226
|
+
...("stageName" in p ? { stageName: p.stageName } : {}),
|
|
227
|
+
...("candidateId" in p ? { candidateId: String(p.candidateId) } : {}),
|
|
228
|
+
...("findingId" in p ? { findingId: String(p.findingId) } : {}),
|
|
229
|
+
// `reasonSummary` is the only free-text field on the QI event envelope. The workflow already
|
|
230
|
+
// produces a fail-closed, secret-free summary (see `safeReasonSummary`), but pass it through the
|
|
231
|
+
// live-payload redactor too so this SSE writer — the one QI surface with no other redaction —
|
|
232
|
+
// can never stream a credential/endpoint substring should a future code path widen the field
|
|
233
|
+
// (#279 AC3, defence-in-depth; mirrors the Conversation Center SSE redaction posture).
|
|
234
|
+
...("reasonSummary" in p ? { reasonSummary: applyRedactor(redact, p.reasonSummary) } : {}),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
// Apply the live-payload redactor to a string field. The redactor is typed `(unknown) => unknown`
|
|
238
|
+
// (it walks arbitrary structures); for a string input it returns the redacted string. Fall back to
|
|
239
|
+
// the already-safe input on the impossible non-string return so the field type stays `string`.
|
|
240
|
+
function applyRedactor(redact, value) {
|
|
241
|
+
const out = redact(value);
|
|
242
|
+
return typeof out === "string" ? out : value;
|
|
243
|
+
}
|
|
244
|
+
function classifyStartError(error) {
|
|
245
|
+
if (error instanceof QiIngestionError || error instanceof QiGenerationError) {
|
|
246
|
+
return { code: error.code, message: error.message };
|
|
247
|
+
}
|
|
248
|
+
return { code: "QI_RUN_FAILED", message: "The Quality Intelligence run failed to complete." };
|
|
249
|
+
}
|
|
250
|
+
// Project the internal QiSkippedSource[] (which also carries a free-text `message`) to exactly the
|
|
251
|
+
// wire contract QualityIntelligenceSkippedSource[] ({label, kind, code}). Streaming `message`
|
|
252
|
+
// verbatim would widen the browser-facing SSE surface — the `accepted` frame bypasses deps.redactor,
|
|
253
|
+
// unlike `event` — so it is dropped here (Issue #730).
|
|
254
|
+
function toWireSkippedSources(skipped) {
|
|
255
|
+
return skipped.map((s) => ({ label: s.label, kind: s.kind, code: s.code }));
|
|
256
|
+
}
|
|
257
|
+
function writeAcceptedFrame(write, accepted) {
|
|
258
|
+
write({
|
|
259
|
+
type: "accepted",
|
|
260
|
+
runId: accepted.runId,
|
|
261
|
+
requestedAt: accepted.requestedAt,
|
|
262
|
+
sourceCount: accepted.sourceCount,
|
|
263
|
+
atomCount: accepted.atomCount,
|
|
264
|
+
...(accepted.droppedSourceCount > 0 ? { droppedSourceCount: accepted.droppedSourceCount } : {}),
|
|
265
|
+
...(accepted.skippedSources.length > 0
|
|
266
|
+
? { skippedSources: toWireSkippedSources(accepted.skippedSources) }
|
|
267
|
+
: {}),
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
export function doneFrameForSummary(deps, runId, summary, totals) {
|
|
271
|
+
// Surface the bounded reasonSummary for BOTH a terminal failed run and a succeeded-but-degraded run
|
|
272
|
+
// (model/parser fell back to the deterministic baseline). The reason is already safeReasonSummary-
|
|
273
|
+
// bounded server-side; re-redact defensively before it reaches the wire.
|
|
274
|
+
const reasonSummary = summary.reasonSummary !== undefined
|
|
275
|
+
? applyRedactor(deps.redactor, summary.reasonSummary)
|
|
276
|
+
: undefined;
|
|
277
|
+
const degraded = summary.status === "succeeded" && reasonSummary !== undefined ? true : undefined;
|
|
278
|
+
return {
|
|
279
|
+
type: "done",
|
|
280
|
+
runId,
|
|
281
|
+
status: summary.status,
|
|
282
|
+
totals,
|
|
283
|
+
...(reasonSummary !== undefined ? { reasonSummary } : {}),
|
|
284
|
+
...(degraded !== undefined ? { degraded } : {}),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
async function streamRunExecution(deps, request, runId, registeredAt, signal, write) {
|
|
288
|
+
const totals = { candidates: 0, findings: 0, exports: 0 };
|
|
289
|
+
let terminal = "failed";
|
|
290
|
+
try {
|
|
291
|
+
const summary = await executeQiRun({
|
|
292
|
+
request,
|
|
293
|
+
runId,
|
|
294
|
+
deps,
|
|
295
|
+
registeredAt,
|
|
296
|
+
signal,
|
|
297
|
+
onAccepted: (accepted) => {
|
|
298
|
+
writeAcceptedFrame(write, accepted);
|
|
299
|
+
},
|
|
300
|
+
onEvent: (event) => {
|
|
301
|
+
if (event.payload.kind === "candidate:proposed")
|
|
302
|
+
totals.candidates += 1;
|
|
303
|
+
if (event.payload.kind === "finding:recorded")
|
|
304
|
+
totals.findings += 1;
|
|
305
|
+
qiRunRegistry.updateTotals(runId, totals);
|
|
306
|
+
write(toStreamEvent(event, deps.redactor));
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
terminal = summary.status;
|
|
310
|
+
write(doneFrameForSummary(deps, runId, summary, totals));
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
const { code, message } = classifyStartError(error);
|
|
314
|
+
write({ type: "error", code, message });
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
qiRunRegistry.complete(runId, terminal);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
export async function handleStartQiRun(ctx, deps) {
|
|
321
|
+
const parsed = await parseStartBody(ctx.req);
|
|
322
|
+
if (!parsed.ok)
|
|
323
|
+
return parsed.result;
|
|
324
|
+
const runId = `qi-run-${randomUUID()}`;
|
|
325
|
+
const registeredAt = new Date().toISOString();
|
|
326
|
+
// Register and wire the disconnect listener BEFORE writeHead to close the narrow race where a
|
|
327
|
+
// client disconnects after parsing succeeds but before the response is committed.
|
|
328
|
+
const controller = qiRunRegistry.register(runId, registeredAt);
|
|
329
|
+
ctx.res.on("close", () => {
|
|
330
|
+
controller.abort();
|
|
331
|
+
});
|
|
332
|
+
ctx.res.writeHead(200, { ...SSE_HEADERS, "X-Accel-Buffering": "no" });
|
|
333
|
+
const write = (message) => {
|
|
334
|
+
writeOrDestroy(ctx.res, `data: ${JSON.stringify(message)}\n\n`, controller);
|
|
335
|
+
};
|
|
336
|
+
await streamRunExecution(deps, parsed.request, runId, registeredAt, controller.signal, write);
|
|
337
|
+
ctx.res.end();
|
|
338
|
+
return STREAMING;
|
|
339
|
+
}
|
|
340
|
+
export function handleCancelQiRun(ctx, _deps) {
|
|
341
|
+
const { id } = ctx.params;
|
|
342
|
+
if (id === undefined || id.trim().length === 0) {
|
|
343
|
+
return errorResult(400, "QI_BAD_REQUEST", "Run id is required.");
|
|
344
|
+
}
|
|
345
|
+
const cancelled = qiRunRegistry.cancel(id);
|
|
346
|
+
return cancelled
|
|
347
|
+
? { status: 200, body: { cancelled: true, runId: id } }
|
|
348
|
+
: errorResult(404, "QI_NOT_ACTIVE", "No in-flight run with that id.");
|
|
349
|
+
}
|
|
350
|
+
export const QI_RUN_EXECUTION_ROUTE_GROUP = [
|
|
351
|
+
{ method: "POST", pattern: "/api/quality-intelligence/runs", handler: handleStartQiRun },
|
|
352
|
+
{
|
|
353
|
+
method: "POST",
|
|
354
|
+
pattern: "/api/quality-intelligence/runs/:id/cancel",
|
|
355
|
+
handler: handleCancelQiRun,
|
|
356
|
+
},
|
|
357
|
+
];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RouteContext, RouteResult, RouteDefinition } from "../routes.js";
|
|
2
|
+
import type { UiHandlerDeps } from "../deps.js";
|
|
3
|
+
export declare function handleQiTraceabilityExport(ctx: RouteContext, deps: UiHandlerDeps): Promise<RouteResult>;
|
|
4
|
+
export declare const QI_TRACEABILITY_ROUTE_GROUP: readonly RouteDefinition[];
|
|
5
|
+
//# sourceMappingURL=traceabilityRoutes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceabilityRoutes.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/traceabilityRoutes.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAyHhD,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,WAAW,CAAC,CA+CtB;AAED,eAAO,MAAM,2BAA2B,EAAE,SAAS,eAAe,EAMjE,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// Quality Intelligence requirement↔test traceability export route (Epic #734, Issue #740).
|
|
2
|
+
//
|
|
3
|
+
// * POST /api/quality-intelligence/runs/:id/traceability — export the persisted coverage matrix
|
|
4
|
+
// as an audit-ready requirement↔test traceability matrix (CSV or Markdown).
|
|
5
|
+
//
|
|
6
|
+
// A dedicated route (not folded into the generic export route) so the matrix-driven serializer,
|
|
7
|
+
// which needs the coverage matrix rather than the candidate bodies, stays self-contained. The
|
|
8
|
+
// matrix carries refs + status plus an optional already-redacted requirement excerpt (#790); the
|
|
9
|
+
// reverse direction is enriched with the run's redacted candidate titles when the candidate
|
|
10
|
+
// artifact is loadable. The serializers are deterministic and formula-injection safe.
|
|
11
|
+
import { sha256Hex } from "@oscharko-dev/keiko-security";
|
|
12
|
+
import { appendQualityIntelligenceExportRow, loadQualityIntelligenceCandidates, loadQualityIntelligenceRun, } from "@oscharko-dev/keiko-evidence";
|
|
13
|
+
import { QualityIntelligenceExport } from "@oscharko-dev/keiko-quality-intelligence";
|
|
14
|
+
const MAX_BODY_BYTES = 4 * 1024;
|
|
15
|
+
const FORMAT_META = {
|
|
16
|
+
csv: { contentType: "text/csv", ext: "csv" },
|
|
17
|
+
markdown: { contentType: "text/markdown", ext: "md" },
|
|
18
|
+
};
|
|
19
|
+
const errorResult = (status, code, message) => ({
|
|
20
|
+
status,
|
|
21
|
+
body: { error: { code, message } },
|
|
22
|
+
});
|
|
23
|
+
const readBody = (req) => new Promise((resolve, reject) => {
|
|
24
|
+
const chunks = [];
|
|
25
|
+
let total = 0;
|
|
26
|
+
let capped = false;
|
|
27
|
+
req.on("data", (chunk) => {
|
|
28
|
+
total += chunk.length;
|
|
29
|
+
if (total > MAX_BODY_BYTES) {
|
|
30
|
+
if (!capped) {
|
|
31
|
+
capped = true;
|
|
32
|
+
chunks.length = 0;
|
|
33
|
+
reject(new Error("body too large"));
|
|
34
|
+
req.resume();
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
chunks.push(chunk);
|
|
39
|
+
});
|
|
40
|
+
req.on("end", () => {
|
|
41
|
+
if (!capped)
|
|
42
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
43
|
+
});
|
|
44
|
+
req.on("error", reject);
|
|
45
|
+
});
|
|
46
|
+
// Parse the requested format from the (optional) JSON body; defaults to CSV. An unreadable or
|
|
47
|
+
// malformed body falls back to CSV rather than failing — the run id alone is a valid request.
|
|
48
|
+
async function parseFormat(req) {
|
|
49
|
+
let raw;
|
|
50
|
+
try {
|
|
51
|
+
raw = await readBody(req);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return "csv";
|
|
55
|
+
}
|
|
56
|
+
if (raw.trim().length === 0)
|
|
57
|
+
return "csv";
|
|
58
|
+
try {
|
|
59
|
+
const parsed = JSON.parse(raw);
|
|
60
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
61
|
+
const fmt = parsed.format;
|
|
62
|
+
if (fmt === "markdown")
|
|
63
|
+
return "markdown";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return "csv";
|
|
68
|
+
}
|
|
69
|
+
return "csv";
|
|
70
|
+
}
|
|
71
|
+
// Project persisted matrix rows onto adapter rows; the redacted excerpt (#790) is optional and
|
|
72
|
+
// absent on runs recorded before it existed.
|
|
73
|
+
function toTraceabilityRows(matrix) {
|
|
74
|
+
return matrix.map((r) => ({
|
|
75
|
+
atomId: r.atomId,
|
|
76
|
+
status: r.status,
|
|
77
|
+
confidence: r.confidence,
|
|
78
|
+
coveringCandidateIds: r.coveringCandidateIds,
|
|
79
|
+
...(r.requirementExcerptRedacted !== undefined
|
|
80
|
+
? { requirementExcerptRedacted: r.requirementExcerptRedacted }
|
|
81
|
+
: {}),
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
// Candidate id -> redacted title for the tests->requirements direction (#790). Best-effort: a
|
|
85
|
+
// missing/unreadable candidate artifact only drops the titles, never the export.
|
|
86
|
+
function candidateTitlesFor(id, evidenceDir) {
|
|
87
|
+
const titles = new Map();
|
|
88
|
+
try {
|
|
89
|
+
const artifact = loadQualityIntelligenceCandidates(id, { evidenceDir });
|
|
90
|
+
for (const candidate of artifact?.candidates ?? []) {
|
|
91
|
+
titles.set(candidate.id, candidate.title);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Titles are a display enrichment; the matrix itself is loaded and validated separately.
|
|
96
|
+
}
|
|
97
|
+
return titles;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Best-effort append of an export-evidence row after a successful traceability matrix download
|
|
101
|
+
* (Epic #734, Issue #740). A failed audit write must NOT withhold the already-computed body from
|
|
102
|
+
* the caller: the matrix is deterministic, has no external side effect, and the manifest write is
|
|
103
|
+
* atomic so failures are rare. Swallow on failure rather than turning a 200 into a 500.
|
|
104
|
+
*/
|
|
105
|
+
function recordTraceabilityExportEvidence(id, target, body, evidenceDir) {
|
|
106
|
+
const row = {
|
|
107
|
+
id: `qi-export-${sha256Hex(`${id}|${target}`).slice(0, 24)}`,
|
|
108
|
+
targetAdapter: target,
|
|
109
|
+
integrityHash: sha256Hex(body),
|
|
110
|
+
redactionAttested: true,
|
|
111
|
+
dryRun: false,
|
|
112
|
+
};
|
|
113
|
+
try {
|
|
114
|
+
appendQualityIntelligenceExportRow({ runId: id, export: row }, { evidenceDir });
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// intentionally swallowed — see doc comment
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export async function handleQiTraceabilityExport(ctx, deps) {
|
|
121
|
+
const { id } = ctx.params;
|
|
122
|
+
if (id === undefined || id.trim().length === 0) {
|
|
123
|
+
return errorResult(400, "QI_BAD_REQUEST", "Run id is required.");
|
|
124
|
+
}
|
|
125
|
+
const evidenceDir = deps.evidenceDir;
|
|
126
|
+
if (evidenceDir === undefined) {
|
|
127
|
+
return errorResult(500, "QI_NO_EVIDENCE_DIR", "The evidence directory is not configured.");
|
|
128
|
+
}
|
|
129
|
+
const format = await parseFormat(ctx.req);
|
|
130
|
+
let manifest;
|
|
131
|
+
try {
|
|
132
|
+
manifest = loadQualityIntelligenceRun(id, { evidenceDir });
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// CWE-209: never surface the underlying filesystem/parse error detail to the client; a
|
|
136
|
+
// corrupt or unreadable manifest is reported as an opaque 500 (mirrors uiRoutes.ts).
|
|
137
|
+
return errorResult(500, "QI_LOAD_FAILED", "Failed to load the Quality Intelligence run.");
|
|
138
|
+
}
|
|
139
|
+
if (manifest === undefined) {
|
|
140
|
+
return errorResult(404, "QI_NOT_FOUND", "Quality Intelligence run not found.");
|
|
141
|
+
}
|
|
142
|
+
const matrix = manifest.coverageMatrix ?? [];
|
|
143
|
+
if (matrix.length === 0) {
|
|
144
|
+
return errorResult(409, "QI_NO_COVERAGE", "This run has no coverage matrix to export.");
|
|
145
|
+
}
|
|
146
|
+
const rows = toTraceabilityRows(matrix);
|
|
147
|
+
const display = { candidateTitleById: candidateTitlesFor(id, evidenceDir) };
|
|
148
|
+
const body = format === "markdown"
|
|
149
|
+
? QualityIntelligenceExport.adaptToTraceabilityMarkdown(rows, display)
|
|
150
|
+
: QualityIntelligenceExport.adaptToTraceabilityCsv(rows, display);
|
|
151
|
+
const target = format === "markdown" ? "traceability-markdown" : "traceability-csv";
|
|
152
|
+
// Emit audit evidence for the materialised download (Epic #734, Issue #740). Best-effort: see
|
|
153
|
+
// recordTraceabilityExportEvidence for the swallow rationale.
|
|
154
|
+
recordTraceabilityExportEvidence(id, target, body, evidenceDir);
|
|
155
|
+
const meta = FORMAT_META[format];
|
|
156
|
+
return {
|
|
157
|
+
status: 200,
|
|
158
|
+
body: {
|
|
159
|
+
format,
|
|
160
|
+
filename: `${id}-traceability.${meta.ext}`,
|
|
161
|
+
contentType: meta.contentType,
|
|
162
|
+
byteLen: Buffer.byteLength(body, "utf8"),
|
|
163
|
+
body,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export const QI_TRACEABILITY_ROUTE_GROUP = [
|
|
168
|
+
{
|
|
169
|
+
method: "POST",
|
|
170
|
+
pattern: "/api/quality-intelligence/runs/:id/traceability",
|
|
171
|
+
handler: handleQiTraceabilityExport,
|
|
172
|
+
},
|
|
173
|
+
];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RouteContext, RouteResult } from "../routes.js";
|
|
2
|
+
import type { UiHandlerDeps } from "../deps.js";
|
|
3
|
+
export declare const QI_RUN_LIST_DEFAULT_LIMIT = 100;
|
|
4
|
+
export declare const QI_RUN_LIST_MAX_LIMIT = 500;
|
|
5
|
+
export declare function handleListQiRuns(ctx: RouteContext, deps: UiHandlerDeps): RouteResult;
|
|
6
|
+
export declare function handleGetQiRun(ctx: RouteContext, deps: UiHandlerDeps): RouteResult;
|
|
7
|
+
//# sourceMappingURL=uiRoutes.d.ts.map
|