@oscharko-dev/keiko 0.2.0-beta.8 → 0.2.0-beta.9
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/ui/csp-hashes.json +14 -14
- package/dist/ui/static/404.html +1 -1
- package/dist/ui/static/__next.__PAGE__.txt +2 -2
- package/dist/ui/static/__next._full.txt +3 -3
- package/dist/ui/static/__next._head.txt +1 -1
- package/dist/ui/static/__next._index.txt +2 -2
- package/dist/ui/static/__next._tree.txt +2 -2
- package/dist/ui/static/_next/static/chunks/06-q1ntr51v8r.js +1 -0
- package/dist/ui/static/_next/static/chunks/0y9qlvrxsyign.js +109 -0
- package/dist/ui/static/_next/static/chunks/1h0v66-p9cx19.css +1 -0
- package/dist/ui/static/_next/static/chunks/3ewv4mguqzooj.js +1 -0
- package/dist/ui/static/_not-found/__next._full.txt +2 -2
- package/dist/ui/static/_not-found/__next._head.txt +1 -1
- package/dist/ui/static/_not-found/__next._index.txt +2 -2
- package/dist/ui/static/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/ui/static/_not-found/__next._not-found.txt +1 -1
- package/dist/ui/static/_not-found/__next._tree.txt +2 -2
- package/dist/ui/static/_not-found.html +1 -1
- package/dist/ui/static/_not-found.txt +2 -2
- package/dist/ui/static/index.html +1 -1
- package/dist/ui/static/index.txt +3 -3
- package/dist/ui/static/launch/__next._full.txt +3 -3
- package/dist/ui/static/launch/__next._head.txt +1 -1
- package/dist/ui/static/launch/__next._index.txt +2 -2
- package/dist/ui/static/launch/__next._tree.txt +2 -2
- package/dist/ui/static/launch/__next.launch.__PAGE__.txt +2 -2
- package/dist/ui/static/launch/__next.launch.txt +1 -1
- package/dist/ui/static/launch.html +1 -1
- package/dist/ui/static/launch.txt +3 -3
- package/dist/ui/static/local-knowledge/__next._full.txt +3 -3
- package/dist/ui/static/local-knowledge/__next._head.txt +1 -1
- package/dist/ui/static/local-knowledge/__next._index.txt +2 -2
- package/dist/ui/static/local-knowledge/__next._tree.txt +2 -2
- package/dist/ui/static/local-knowledge/__next.local-knowledge.__PAGE__.txt +2 -2
- package/dist/ui/static/local-knowledge/__next.local-knowledge.txt +1 -1
- package/dist/ui/static/local-knowledge/capsule/__next._full.txt +3 -3
- package/dist/ui/static/local-knowledge/capsule/__next._head.txt +1 -1
- package/dist/ui/static/local-knowledge/capsule/__next._index.txt +2 -2
- package/dist/ui/static/local-knowledge/capsule/__next._tree.txt +2 -2
- package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.capsule.__PAGE__.txt +2 -2
- package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.capsule.txt +1 -1
- package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.txt +1 -1
- package/dist/ui/static/local-knowledge/capsule.html +1 -1
- package/dist/ui/static/local-knowledge/capsule.txt +3 -3
- package/dist/ui/static/local-knowledge.html +1 -1
- package/dist/ui/static/local-knowledge.txt +3 -3
- package/dist/ui/static/memoriaviva/__next._full.txt +2 -2
- package/dist/ui/static/memoriaviva/__next._head.txt +1 -1
- package/dist/ui/static/memoriaviva/__next._index.txt +2 -2
- package/dist/ui/static/memoriaviva/__next._tree.txt +2 -2
- package/dist/ui/static/memoriaviva/__next.memoriaviva.__PAGE__.txt +1 -1
- package/dist/ui/static/memoriaviva/__next.memoriaviva.txt +1 -1
- package/dist/ui/static/memoriaviva/consolidation/__next._full.txt +2 -2
- package/dist/ui/static/memoriaviva/consolidation/__next._head.txt +1 -1
- package/dist/ui/static/memoriaviva/consolidation/__next._index.txt +2 -2
- package/dist/ui/static/memoriaviva/consolidation/__next._tree.txt +2 -2
- package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.consolidation.__PAGE__.txt +1 -1
- package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.consolidation.txt +1 -1
- package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.txt +1 -1
- package/dist/ui/static/memoriaviva/consolidation.html +1 -1
- package/dist/ui/static/memoriaviva/consolidation.txt +2 -2
- package/dist/ui/static/memoriaviva/detail/__next._full.txt +2 -2
- package/dist/ui/static/memoriaviva/detail/__next._head.txt +1 -1
- package/dist/ui/static/memoriaviva/detail/__next._index.txt +2 -2
- package/dist/ui/static/memoriaviva/detail/__next._tree.txt +2 -2
- package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.detail.__PAGE__.txt +1 -1
- package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.detail.txt +1 -1
- package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.txt +1 -1
- package/dist/ui/static/memoriaviva/detail.html +1 -1
- package/dist/ui/static/memoriaviva/detail.txt +2 -2
- package/dist/ui/static/memoriaviva/review-queue/__next._full.txt +2 -2
- package/dist/ui/static/memoriaviva/review-queue/__next._head.txt +1 -1
- package/dist/ui/static/memoriaviva/review-queue/__next._index.txt +2 -2
- package/dist/ui/static/memoriaviva/review-queue/__next._tree.txt +2 -2
- package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.review-queue.__PAGE__.txt +1 -1
- package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.review-queue.txt +1 -1
- package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.txt +1 -1
- package/dist/ui/static/memoriaviva/review-queue.html +1 -1
- package/dist/ui/static/memoriaviva/review-queue.txt +2 -2
- package/dist/ui/static/memoriaviva.html +1 -1
- package/dist/ui/static/memoriaviva.txt +2 -2
- package/node_modules/@oscharko-dev/keiko-cli/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-cli/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/dist/index.d.ts +2 -2
- package/node_modules/@oscharko-dev/keiko-contracts/dist/index.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/dist/index.js +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/bffWire.d.ts +36 -4
- package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/bffWire.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/index.d.ts +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/index.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-evaluations/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-evaluations/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-evidence/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-evidence/dist/index.d.ts +1 -1
- package/node_modules/@oscharko-dev/keiko-evidence/dist/index.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/schema.d.ts +15 -0
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/schema.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/schema.js +13 -3
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.d.ts +8 -0
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.js +30 -2
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/index.d.ts +2 -2
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/index.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-evidence/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-harness/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-harness/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-local-knowledge/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-capture/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-consolidation/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-governance/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-model-gateway/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-model-gateway/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/screenIrTestBaseline.d.ts +8 -0
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/screenIrTestBaseline.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/screenIrTestBaseline.js +9 -5
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/testDesignModel.d.ts +6 -0
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/testDesignModel.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/testDesignModel.js +116 -21
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/testQualityRubric.d.ts +6 -0
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/testQualityRubric.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/testQualityRubric.js +12 -0
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/validation.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/validation.js +8 -7
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/generation/parseGeneratedCandidates.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/generation/parseGeneratedCandidates.js +29 -7
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/generation/prompt.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/generation/prompt.js +61 -24
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/index.d.ts +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/index.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/index.js +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-sdk/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-sdk/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-security/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-security/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/conversation-prompt.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/conversation-prompt.js +2 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/gateway-setup.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/gateway-setup.js +30 -6
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-orchestrator.d.ts +1 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-orchestrator.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-orchestrator.js +410 -18
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-prompt.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-prompt.js +1 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa-hybrid.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa-hybrid.js +7 -5
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa-multi-source.js +4 -3
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa.d.ts +1 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa.js +4 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/local-knowledge-grounded-qa.d.ts +1 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/local-knowledge-grounded-qa.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/local-knowledge-grounded-qa.js +8 -3
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaConnector.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaConnector.js +9 -4
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaScopedPagination.d.ts +6 -5
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaScopedPagination.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaScopedPagination.js +10 -9
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotBuilder.d.ts +2 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotBuilder.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotBuilder.js +62 -26
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotHash.d.ts +2 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotHash.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotHash.js +6 -3
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotTypes.d.ts +14 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotTypes.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts +18 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.js +159 -6
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotScreenIds.d.ts +19 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotScreenIds.d.ts.map +1 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotScreenIds.js +75 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/judgePort.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/judgePort.js +13 -12
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/modelSelection.d.ts +6 -6
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/modelSelection.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/modelSelection.js +12 -7
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/reCheckRoutes.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/reCheckRoutes.js +34 -3
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runIngestion.d.ts +4 -2
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runIngestion.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runIngestion.js +222 -35
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runRoutes.d.ts +7 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runRoutes.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runRoutes.js +68 -16
- package/node_modules/@oscharko-dev/keiko-server/dist/routes.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/routes.js +6 -1
- package/node_modules/@oscharko-dev/keiko-server/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-tools/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-tools/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-verification/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-verification/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-workflows/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/anchors.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/anchors.js +45 -0
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/index.d.ts +2 -0
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/index.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/index.js +1 -0
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/intent.d.ts +8 -0
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/intent.d.ts.map +1 -0
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/intent.js +140 -0
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/plan.d.ts +2 -0
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/plan.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/plan.js +21 -5
- package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/modelRoutedTestDesign.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/modelRoutedTestDesign.js +86 -40
- package/node_modules/@oscharko-dev/keiko-workflows/dist/ranking/rank.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-workflows/dist/ranking/rank.js +9 -0
- package/node_modules/@oscharko-dev/keiko-workflows/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-workspace/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-workspace/dist/index.d.ts +1 -0
- package/node_modules/@oscharko-dev/keiko-workspace/dist/index.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearch.d.ts +3 -0
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearch.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearch.js +23 -6
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchMatchers.d.ts +1 -1
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchMatchers.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchMatchers.js +24 -3
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchPolicy.d.ts +34 -0
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchPolicy.d.ts.map +1 -0
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchPolicy.js +342 -0
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchScan.d.ts +6 -1
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchScan.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchScan.js +57 -9
- package/node_modules/@oscharko-dev/keiko-workspace/package.json +1 -1
- package/package.json +1 -1
- package/dist/ui/static/_next/static/chunks/0i3jzgrj42so8.css +0 -1
- package/dist/ui/static/_next/static/chunks/1ru_021szp0u7.js +0 -1
- package/dist/ui/static/_next/static/chunks/1t7vb5d9ed2e7.js +0 -1
- package/dist/ui/static/_next/static/chunks/23o2c6pyjq92z.js +0 -109
- /package/dist/ui/static/_next/static/{Ppze_8n_i3yc1FS_Qdj0I → a5sUbXeTgQ9A2LRTMu_Q_}/_buildManifest.js +0 -0
- /package/dist/ui/static/_next/static/{Ppze_8n_i3yc1FS_Qdj0I → a5sUbXeTgQ9A2LRTMu_Q_}/_clientMiddlewareManifest.js +0 -0
- /package/dist/ui/static/_next/static/{Ppze_8n_i3yc1FS_Qdj0I → a5sUbXeTgQ9A2LRTMu_Q_}/_ssgManifest.js +0 -0
|
@@ -623,7 +623,9 @@ function mergeFigmaVisionHints(baselineText, hints) {
|
|
|
623
623
|
/** Vision-augment one screen's baseline text without ever overriding it (additive only). */
|
|
624
624
|
function visionAugmentedScreenText(baseline, ir, record, screen, vision) {
|
|
625
625
|
const baselineText = QualityIntelligenceFigma.renderBaselineText(baseline);
|
|
626
|
-
if (vision === undefined ||
|
|
626
|
+
if (vision === undefined ||
|
|
627
|
+
!isRenderedScreenRow(screen) ||
|
|
628
|
+
!screenNeedsVisionAugmentation(ir, baseline)) {
|
|
627
629
|
return { text: baselineText, fingerprintText: baselineText };
|
|
628
630
|
}
|
|
629
631
|
const hints = vision(figmaVisionRequest(record, screen, baselineText));
|
|
@@ -633,22 +635,128 @@ function visionAugmentedScreenText(baseline, ir, record, screen, vision) {
|
|
|
633
635
|
}
|
|
634
636
|
async function visionAugmentedScreenTextAsync(baseline, ir, record, screen, vision) {
|
|
635
637
|
const baselineText = QualityIntelligenceFigma.renderBaselineText(baseline);
|
|
636
|
-
if (vision === undefined ||
|
|
638
|
+
if (vision === undefined ||
|
|
639
|
+
!isRenderedScreenRow(screen) ||
|
|
640
|
+
!screenNeedsVisionAugmentation(ir, baseline)) {
|
|
637
641
|
return { text: baselineText, fingerprintText: baselineText };
|
|
638
642
|
}
|
|
639
643
|
const hints = await vision(figmaVisionRequest(record, screen, baselineText));
|
|
640
644
|
return mergeFigmaVisionHints(baselineText, hints);
|
|
641
645
|
}
|
|
646
|
+
function isRenderedScreenRow(row) {
|
|
647
|
+
return "image" in row;
|
|
648
|
+
}
|
|
642
649
|
// Parse every screen's opaque irJson once; an unparseable screen is dropped (never crashes the run).
|
|
650
|
+
// Rendered screens win if a corrupt record ever duplicates an id; structural-only rows then fill
|
|
651
|
+
// the non-rendered/capped coverage gap for QI.
|
|
643
652
|
function parseScreens(record) {
|
|
644
653
|
const parsed = [];
|
|
654
|
+
const seen = new Set();
|
|
645
655
|
for (const row of record.screens) {
|
|
646
656
|
const ir = QualityIntelligenceFigma.parseScreenIr(row.irJson);
|
|
647
|
-
if (ir !== undefined)
|
|
657
|
+
if (ir !== undefined) {
|
|
648
658
|
parsed.push({ row, ir });
|
|
659
|
+
seen.add(row.screenId);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
for (const row of record.structuralScreens ?? []) {
|
|
663
|
+
if (seen.has(row.screenId))
|
|
664
|
+
continue;
|
|
665
|
+
const ir = QualityIntelligenceFigma.parseScreenIr(row.irJson);
|
|
666
|
+
if (ir !== undefined) {
|
|
667
|
+
parsed.push({ row, ir });
|
|
668
|
+
seen.add(row.screenId);
|
|
669
|
+
}
|
|
649
670
|
}
|
|
650
671
|
return parsed;
|
|
651
672
|
}
|
|
673
|
+
function scopedParsedScreens(record, screenIds) {
|
|
674
|
+
const parsed = parseScreens(record);
|
|
675
|
+
// Absent screenIds → whole snapshot (the contract's "absent = whole"). An explicitly EMPTY scope
|
|
676
|
+
// matches NOTHING — it must NEVER widen to the whole board. The route layer already rejects an empty
|
|
677
|
+
// array; this is the defense-in-depth invariant guaranteeing a scoped request can never silently fall
|
|
678
|
+
// back to every screen even if an internal caller passes an empty list.
|
|
679
|
+
if (screenIds === undefined)
|
|
680
|
+
return parsed;
|
|
681
|
+
if (screenIds.length === 0)
|
|
682
|
+
return [];
|
|
683
|
+
const wanted = new Set(screenIds);
|
|
684
|
+
return parsed.filter((screen) => wanted.has(screen.row.screenId));
|
|
685
|
+
}
|
|
686
|
+
// Canonicalise a scoped screen-id list (trim → drop empties → dedupe → sort) so the derived envelope
|
|
687
|
+
// id / provenance ref is stable regardless of the order or duplicates a caller passed. The route layer
|
|
688
|
+
// already canonicalises incoming requests; this keeps direct/internal callers consistent too.
|
|
689
|
+
function canonicalFigmaScreenIds(screenIds) {
|
|
690
|
+
return [...new Set(screenIds.map((id) => id.trim()).filter((id) => id.length > 0))].sort();
|
|
691
|
+
}
|
|
692
|
+
function figmaSnapshotSourceRef(source) {
|
|
693
|
+
if (source.screenIds === undefined)
|
|
694
|
+
return source.snapshotRunId;
|
|
695
|
+
const canonical = canonicalFigmaScreenIds(source.screenIds);
|
|
696
|
+
return canonical.length === 0
|
|
697
|
+
? source.snapshotRunId
|
|
698
|
+
: `${source.snapshotRunId}#${canonical.join(",")}`;
|
|
699
|
+
}
|
|
700
|
+
function imageSourceRef(source) {
|
|
701
|
+
return `${source.sourceKind}:${source.snapshotRunId}#${source.screenId}`;
|
|
702
|
+
}
|
|
703
|
+
function imageDescriptionBaseline(screenId, screenName) {
|
|
704
|
+
return ("No structural JSON is attached to this source. Describe the visible UI screenshot for " +
|
|
705
|
+
"test generation. Focus on user-visible purpose, controls, form fields, labels, states, " +
|
|
706
|
+
`layout groups, and likely validation affordances.\nScreen id: ${screenId}\nScreen name: ${screenName}`);
|
|
707
|
+
}
|
|
708
|
+
function imageDescriptionText(screenId, screenName, hints) {
|
|
709
|
+
const cleaned = hints
|
|
710
|
+
.map((hint) => redactFigmaAtomText(hint).trim())
|
|
711
|
+
.filter((hint) => hint.length > 0);
|
|
712
|
+
if (cleaned.length === 0)
|
|
713
|
+
return undefined;
|
|
714
|
+
return [
|
|
715
|
+
`Image description for ${screenName} (${screenId})`,
|
|
716
|
+
"",
|
|
717
|
+
...cleaned.map((hint) => `- ${hint}`),
|
|
718
|
+
].join("\n");
|
|
719
|
+
}
|
|
720
|
+
function parsedRenderedScreenForImageSource(record, source, label) {
|
|
721
|
+
const parsed = parseScreens(record).find((screen) => screen.row.screenId === source.screenId);
|
|
722
|
+
if (parsed === undefined || !isRenderedScreenRow(parsed.row)) {
|
|
723
|
+
throw new QiIngestionError("QI_IMAGE_UNAVAILABLE", `Image "${label}" could not be found in the stored Figma snapshot.`);
|
|
724
|
+
}
|
|
725
|
+
return { row: parsed.row, ir: parsed.ir };
|
|
726
|
+
}
|
|
727
|
+
function imageDescriptionUnavailable(label) {
|
|
728
|
+
return new QiIngestionError("QI_IMAGE_DESCRIPTION_UNAVAILABLE", `Image "${label}" could not be described. Configure an image-input capable model for Quality Intelligence image sources.`);
|
|
729
|
+
}
|
|
730
|
+
function imageDescriptionDocFromHints(screenId, screenName, hints, byteBudget) {
|
|
731
|
+
const text = imageDescriptionText(screenId, screenName, hints);
|
|
732
|
+
if (text === undefined)
|
|
733
|
+
return undefined;
|
|
734
|
+
const perDocBudget = Math.min(CAPSULE_MAX_BYTES_PER_DOCUMENT, byteBudget);
|
|
735
|
+
const capped = truncateToUtf8Bytes(redactFigmaAtomText(text), perDocBudget);
|
|
736
|
+
if (capped.trim().length === 0)
|
|
737
|
+
return undefined;
|
|
738
|
+
return {
|
|
739
|
+
documentId: `Image description: ${figmaDocumentId(screenId, screenName)}`,
|
|
740
|
+
text: capped,
|
|
741
|
+
fingerprintText: capped,
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
// Distinguish "the selected screens are not present in this snapshot" from "the snapshot produced no
|
|
745
|
+
// usable baseline" so a scoped run surfaces a precise, user-actionable reason (audit: clear
|
|
746
|
+
// screen-not-found error) in the streamed skippedSources notice. The code stays QI_SOURCE_EMPTY so the
|
|
747
|
+
// N+1-resilience skip and the drift "all orphaned" allowance keep their existing control flow — only
|
|
748
|
+
// the message is sharpened.
|
|
749
|
+
function figmaSnapshotEmptyError(record, source, label) {
|
|
750
|
+
if (source.screenIds !== undefined) {
|
|
751
|
+
const requested = canonicalFigmaScreenIds(source.screenIds);
|
|
752
|
+
const present = new Set(parseScreens(record).map((screen) => screen.row.screenId));
|
|
753
|
+
const missing = requested.filter((id) => !present.has(id));
|
|
754
|
+
if (requested.length > 0 && missing.length === requested.length) {
|
|
755
|
+
return new QiIngestionError("QI_SOURCE_EMPTY", `Figma snapshot "${label}": none of the selected screens (${missing.join(", ")}) exist in this snapshot.`);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
return new QiIngestionError("QI_SOURCE_EMPTY", `Figma snapshot "${label}" produced no usable screen baseline.`);
|
|
759
|
+
}
|
|
652
760
|
// Derive the deterministic navigation/flow/coverage test items per screen from the parsed screens +
|
|
653
761
|
// the snapshot's raw inter-screen links (#811). Composes into the baseline below through #754's
|
|
654
762
|
// `extraItems` seam. When the snapshot carries no `links` (an older record), every screen maps to no
|
|
@@ -719,13 +827,13 @@ function figmaDocFitsBudget(docs, totalBytes, nextBytes, perRunBudget) {
|
|
|
719
827
|
// the cumulative corpus so an oversized board never hard-fails on QI_PROMPT_TOO_LARGE.
|
|
720
828
|
// The byteBudget is the caller's fair share of the global evidence pool (Epic #729 N+1 split)
|
|
721
829
|
// so a figma-snapshot source never consumes more than its fair slice alongside other sources.
|
|
722
|
-
function figmaScreenDocs(record, vision, byteBudget) {
|
|
830
|
+
function figmaScreenDocs(record, vision, byteBudget, screenIds) {
|
|
723
831
|
// Mirror processCapsuleDocs (:558-563): the per-run corpus budget is the smaller of the capsule's
|
|
724
832
|
// own ceiling and this source's fair share of the global evidence byte budget (Epic #729 N+1
|
|
725
833
|
// split). The per-document cap is likewise never larger than the per-run budget.
|
|
726
834
|
const perRunBudget = Math.min(CAPSULE_BUDGET_BYTES, byteBudget);
|
|
727
835
|
const perDocBudget = Math.min(CAPSULE_MAX_BYTES_PER_DOCUMENT, perRunBudget);
|
|
728
|
-
const parsed =
|
|
836
|
+
const parsed = scopedParsedScreens(record, screenIds);
|
|
729
837
|
const navItems = navItemsByScreen(parsed, record.links ?? []);
|
|
730
838
|
const a11yItems = a11yItemsByScreen(parsed);
|
|
731
839
|
const docs = [];
|
|
@@ -734,7 +842,9 @@ function figmaScreenDocs(record, vision, byteBudget) {
|
|
|
734
842
|
for (const { row, ir } of parsed) {
|
|
735
843
|
const extraItems = [...(navItems.get(ir.id) ?? []), ...(a11yItems.get(ir.id) ?? [])];
|
|
736
844
|
const baseline = QualityIntelligenceFigma.deriveScreenTestBaseline(ir, extraItems);
|
|
737
|
-
const visionSlot =
|
|
845
|
+
const visionSlot = isRenderedScreenRow(row)
|
|
846
|
+
? consumeVisionProviderForScreen(vision, remainingVisionScreens, ir, baseline)
|
|
847
|
+
: { provider: undefined, remaining: remainingVisionScreens };
|
|
738
848
|
remainingVisionScreens = visionSlot.remaining;
|
|
739
849
|
const augmented = visionAugmentedScreenText(baseline, ir, record, row, visionSlot.provider);
|
|
740
850
|
const nextDoc = corpusDocFromFigmaScreen(row, ir, augmented, perDocBudget);
|
|
@@ -747,10 +857,10 @@ function figmaScreenDocs(record, vision, byteBudget) {
|
|
|
747
857
|
}
|
|
748
858
|
return docs;
|
|
749
859
|
}
|
|
750
|
-
async function figmaScreenDocsAsync(record, vision, byteBudget) {
|
|
860
|
+
async function figmaScreenDocsAsync(record, vision, byteBudget, screenIds) {
|
|
751
861
|
const perRunBudget = Math.min(CAPSULE_BUDGET_BYTES, byteBudget);
|
|
752
862
|
const perDocBudget = Math.min(CAPSULE_MAX_BYTES_PER_DOCUMENT, perRunBudget);
|
|
753
|
-
const parsed =
|
|
863
|
+
const parsed = scopedParsedScreens(record, screenIds);
|
|
754
864
|
const navItems = navItemsByScreen(parsed, record.links ?? []);
|
|
755
865
|
const a11yItems = a11yItemsByScreen(parsed);
|
|
756
866
|
const docs = [];
|
|
@@ -759,7 +869,9 @@ async function figmaScreenDocsAsync(record, vision, byteBudget) {
|
|
|
759
869
|
for (const { row, ir } of parsed) {
|
|
760
870
|
const extraItems = [...(navItems.get(ir.id) ?? []), ...(a11yItems.get(ir.id) ?? [])];
|
|
761
871
|
const baseline = QualityIntelligenceFigma.deriveScreenTestBaseline(ir, extraItems);
|
|
762
|
-
const visionSlot =
|
|
872
|
+
const visionSlot = isRenderedScreenRow(row)
|
|
873
|
+
? consumeVisionProviderForScreen(vision, remainingVisionScreens, ir, baseline)
|
|
874
|
+
: { provider: undefined, remaining: remainingVisionScreens };
|
|
763
875
|
remainingVisionScreens = visionSlot.remaining;
|
|
764
876
|
const augmented = await visionAugmentedScreenTextAsync(baseline, ir, record, row, visionSlot.provider);
|
|
765
877
|
const nextDoc = corpusDocFromFigmaScreen(row, ir, augmented, perDocBudget);
|
|
@@ -778,15 +890,16 @@ function ingestFigmaSnapshot(source, index, registeredAt, loader, vision, byteBu
|
|
|
778
890
|
if (record === undefined) {
|
|
779
891
|
throw new QiIngestionError("QI_FIGMA_SNAPSHOT_UNAVAILABLE", `Figma snapshot "${label}" could not be found or read. Build the snapshot first.`);
|
|
780
892
|
}
|
|
781
|
-
if (record.screens.length === 0) {
|
|
893
|
+
if (record.screens.length === 0 && (record.structuralScreens?.length ?? 0) === 0) {
|
|
782
894
|
throw new QiIngestionError("QI_SOURCE_EMPTY", `Figma snapshot "${label}" has no screens.`);
|
|
783
895
|
}
|
|
784
|
-
const docs = figmaScreenDocs(record, vision, byteBudget);
|
|
896
|
+
const docs = figmaScreenDocs(record, vision, byteBudget, source.screenIds);
|
|
785
897
|
if (docs.length === 0) {
|
|
786
|
-
throw
|
|
898
|
+
throw figmaSnapshotEmptyError(record, source, label);
|
|
787
899
|
}
|
|
788
900
|
const joinedFingerprintText = docs.map((d) => d.fingerprintText ?? d.text).join("\n");
|
|
789
|
-
const
|
|
901
|
+
const sourceRef = figmaSnapshotSourceRef(source);
|
|
902
|
+
const envelopeId = envelopeIdFor(index, label, sourceRef);
|
|
790
903
|
// A stored Figma Snapshot is figma evidence, not repository context. Use the dedicated
|
|
791
904
|
// `figma-evidence` envelope kind (#278 AC2 "represented as an explicit connector-backed source"
|
|
792
905
|
// + AC4 citation/audit attribution) so the persisted envelope, source-mix priority, and any
|
|
@@ -796,11 +909,11 @@ function ingestFigmaSnapshot(source, index, registeredAt, loader, vision, byteBu
|
|
|
796
909
|
kind: "figma-evidence",
|
|
797
910
|
displayLabel: label,
|
|
798
911
|
provenance: {
|
|
799
|
-
origin: `figma-snapshot:${
|
|
912
|
+
origin: `figma-snapshot:${sourceRef}`,
|
|
800
913
|
registeredAt,
|
|
801
914
|
integrityHashSha256Hex: sha256Hex(joinedFingerprintText),
|
|
802
915
|
},
|
|
803
|
-
localRef: stableLocalRef("figma-snapshot",
|
|
916
|
+
localRef: stableLocalRef("figma-snapshot", sourceRef),
|
|
804
917
|
};
|
|
805
918
|
const atoms = docs.map((d) => capsuleDocAtom(d.documentId, d.text, envelopeId, d.fingerprintText ?? d.text));
|
|
806
919
|
return { envelope, atoms };
|
|
@@ -811,29 +924,107 @@ async function ingestFigmaSnapshotAsync(source, index, registeredAt, loader, vis
|
|
|
811
924
|
if (record === undefined) {
|
|
812
925
|
throw new QiIngestionError("QI_FIGMA_SNAPSHOT_UNAVAILABLE", `Figma snapshot "${label}" could not be found or read. Build the snapshot first.`);
|
|
813
926
|
}
|
|
814
|
-
if (record.screens.length === 0) {
|
|
927
|
+
if (record.screens.length === 0 && (record.structuralScreens?.length ?? 0) === 0) {
|
|
815
928
|
throw new QiIngestionError("QI_SOURCE_EMPTY", `Figma snapshot "${label}" has no screens.`);
|
|
816
929
|
}
|
|
817
|
-
const docs = await figmaScreenDocsAsync(record, vision, byteBudget);
|
|
930
|
+
const docs = await figmaScreenDocsAsync(record, vision, byteBudget, source.screenIds);
|
|
818
931
|
if (docs.length === 0) {
|
|
819
|
-
throw
|
|
932
|
+
throw figmaSnapshotEmptyError(record, source, label);
|
|
820
933
|
}
|
|
821
934
|
const joinedFingerprintText = docs.map((d) => d.fingerprintText ?? d.text).join("\n");
|
|
822
|
-
const
|
|
935
|
+
const sourceRef = figmaSnapshotSourceRef(source);
|
|
936
|
+
const envelopeId = envelopeIdFor(index, label, sourceRef);
|
|
823
937
|
const envelope = {
|
|
824
938
|
id: envelopeId,
|
|
825
939
|
kind: "figma-evidence",
|
|
826
940
|
displayLabel: label,
|
|
827
941
|
provenance: {
|
|
828
|
-
origin: `figma-snapshot:${
|
|
942
|
+
origin: `figma-snapshot:${sourceRef}`,
|
|
829
943
|
registeredAt,
|
|
830
944
|
integrityHashSha256Hex: sha256Hex(joinedFingerprintText),
|
|
831
945
|
},
|
|
832
|
-
localRef: stableLocalRef("figma-snapshot",
|
|
946
|
+
localRef: stableLocalRef("figma-snapshot", sourceRef),
|
|
833
947
|
};
|
|
834
948
|
const atoms = docs.map((d) => capsuleDocAtom(d.documentId, d.text, envelopeId, d.fingerprintText ?? d.text));
|
|
835
949
|
return { envelope, atoms };
|
|
836
950
|
}
|
|
951
|
+
function buildImageSourceEnvelope(source, label, index, registeredAt, doc) {
|
|
952
|
+
const sourceRef = imageSourceRef(source);
|
|
953
|
+
const envelopeId = envelopeIdFor(index, label, sourceRef);
|
|
954
|
+
const envelope = {
|
|
955
|
+
id: envelopeId,
|
|
956
|
+
kind: "figma-evidence",
|
|
957
|
+
displayLabel: label,
|
|
958
|
+
provenance: {
|
|
959
|
+
origin: `image:${sourceRef}`,
|
|
960
|
+
registeredAt,
|
|
961
|
+
integrityHashSha256Hex: sha256Hex(doc.fingerprintText ?? doc.text),
|
|
962
|
+
},
|
|
963
|
+
localRef: stableLocalRef("image", sourceRef),
|
|
964
|
+
};
|
|
965
|
+
return {
|
|
966
|
+
envelope,
|
|
967
|
+
atoms: [capsuleDocAtom(doc.documentId, doc.text, envelopeId, doc.fingerprintText ?? doc.text)],
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
function imageDescriptionDoc(record, source, label, vision, byteBudget) {
|
|
971
|
+
if (vision === undefined)
|
|
972
|
+
return undefined;
|
|
973
|
+
const { row, ir } = parsedRenderedScreenForImageSource(record, source, label);
|
|
974
|
+
const hints = vision(figmaVisionRequest(record, row, imageDescriptionBaseline(row.screenId, ir.name)));
|
|
975
|
+
if (isPromiseLike(hints))
|
|
976
|
+
return undefined;
|
|
977
|
+
return imageDescriptionDocFromHints(row.screenId, ir.name, hints, byteBudget);
|
|
978
|
+
}
|
|
979
|
+
async function imageDescriptionDocAsync(record, source, label, vision, byteBudget) {
|
|
980
|
+
if (vision === undefined)
|
|
981
|
+
return undefined;
|
|
982
|
+
const { row, ir } = parsedRenderedScreenForImageSource(record, source, label);
|
|
983
|
+
const hints = await vision(figmaVisionRequest(record, row, imageDescriptionBaseline(row.screenId, ir.name)));
|
|
984
|
+
return imageDescriptionDocFromHints(row.screenId, ir.name, hints, byteBudget);
|
|
985
|
+
}
|
|
986
|
+
function ingestImageSource(source, index, registeredAt, loader, vision, byteBudget) {
|
|
987
|
+
const label = sanitiseLabel(source.label);
|
|
988
|
+
const record = loader(source.snapshotRunId);
|
|
989
|
+
if (record === undefined) {
|
|
990
|
+
throw new QiIngestionError("QI_IMAGE_UNAVAILABLE", `Image "${label}" could not be found or read. Build the Figma snapshot first.`);
|
|
991
|
+
}
|
|
992
|
+
const doc = imageDescriptionDoc(record, source, label, vision, byteBudget);
|
|
993
|
+
if (doc === undefined)
|
|
994
|
+
throw imageDescriptionUnavailable(label);
|
|
995
|
+
return buildImageSourceEnvelope(source, label, index, registeredAt, doc);
|
|
996
|
+
}
|
|
997
|
+
async function ingestImageSourceAsync(source, index, registeredAt, loader, vision, byteBudget) {
|
|
998
|
+
const label = sanitiseLabel(source.label);
|
|
999
|
+
const record = loader(source.snapshotRunId);
|
|
1000
|
+
if (record === undefined) {
|
|
1001
|
+
throw new QiIngestionError("QI_IMAGE_UNAVAILABLE", `Image "${label}" could not be found or read. Build the Figma snapshot first.`);
|
|
1002
|
+
}
|
|
1003
|
+
const doc = await imageDescriptionDocAsync(record, source, label, vision, byteBudget);
|
|
1004
|
+
if (doc === undefined)
|
|
1005
|
+
throw imageDescriptionUnavailable(label);
|
|
1006
|
+
return buildImageSourceEnvelope(source, label, index, registeredAt, doc);
|
|
1007
|
+
}
|
|
1008
|
+
function ingestCapsuleSource(source, index, registeredAt, capsuleResolver, byteBudget) {
|
|
1009
|
+
if (capsuleResolver === undefined) {
|
|
1010
|
+
throw new QiIngestionError("QI_CAPSULE_UNAVAILABLE", source.kind === "capsule"
|
|
1011
|
+
? "Capsule sources are unavailable: the Local Knowledge store is not configured."
|
|
1012
|
+
: "Capsule-set sources are unavailable: the Local Knowledge store is not configured.");
|
|
1013
|
+
}
|
|
1014
|
+
return source.kind === "capsule"
|
|
1015
|
+
? ingestCapsule(source, index, registeredAt, capsuleResolver, byteBudget)
|
|
1016
|
+
: ingestCapsuleSet(source, index, registeredAt, capsuleResolver, byteBudget);
|
|
1017
|
+
}
|
|
1018
|
+
function ingestStoredFigmaSource(source, index, registeredAt, figmaSnapshotLoader, figmaVision, byteBudget) {
|
|
1019
|
+
if (figmaSnapshotLoader === undefined) {
|
|
1020
|
+
throw new QiIngestionError(source.kind === "image" ? "QI_IMAGE_UNAVAILABLE" : "QI_FIGMA_SNAPSHOT_UNAVAILABLE", source.kind === "image"
|
|
1021
|
+
? "Image sources are unavailable: the evidence directory is not configured."
|
|
1022
|
+
: "Figma-snapshot sources are unavailable: the evidence directory is not configured.");
|
|
1023
|
+
}
|
|
1024
|
+
return source.kind === "image"
|
|
1025
|
+
? ingestImageSource(source, index, registeredAt, figmaSnapshotLoader, figmaVision, byteBudget)
|
|
1026
|
+
: ingestFigmaSnapshot(source, index, registeredAt, figmaSnapshotLoader, figmaVision, byteBudget);
|
|
1027
|
+
}
|
|
837
1028
|
function ingestOne(source, index, registeredAt, capsuleResolver, figmaSnapshotLoader, figmaVision, byteBudget) {
|
|
838
1029
|
switch (source.kind) {
|
|
839
1030
|
case "requirements":
|
|
@@ -843,28 +1034,24 @@ function ingestOne(source, index, registeredAt, capsuleResolver, figmaSnapshotLo
|
|
|
843
1034
|
case "file":
|
|
844
1035
|
return ingestFile(source, index, registeredAt, byteBudget);
|
|
845
1036
|
case "capsule":
|
|
846
|
-
if (capsuleResolver === undefined) {
|
|
847
|
-
throw new QiIngestionError("QI_CAPSULE_UNAVAILABLE", "Capsule sources are unavailable: the Local Knowledge store is not configured.");
|
|
848
|
-
}
|
|
849
|
-
return ingestCapsule(source, index, registeredAt, capsuleResolver, byteBudget);
|
|
850
1037
|
case "capsule-set":
|
|
851
|
-
|
|
852
|
-
throw new QiIngestionError("QI_CAPSULE_UNAVAILABLE", "Capsule-set sources are unavailable: the Local Knowledge store is not configured.");
|
|
853
|
-
}
|
|
854
|
-
return ingestCapsuleSet(source, index, registeredAt, capsuleResolver, byteBudget);
|
|
1038
|
+
return ingestCapsuleSource(source, index, registeredAt, capsuleResolver, byteBudget);
|
|
855
1039
|
case "figma-snapshot":
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
}
|
|
859
|
-
return ingestFigmaSnapshot(source, index, registeredAt, figmaSnapshotLoader, figmaVision, byteBudget);
|
|
1040
|
+
case "image":
|
|
1041
|
+
return ingestStoredFigmaSource(source, index, registeredAt, figmaSnapshotLoader, figmaVision, byteBudget);
|
|
860
1042
|
}
|
|
861
1043
|
}
|
|
862
1044
|
async function ingestOneAsync(source, index, registeredAt, capsuleResolver, figmaSnapshotLoader, figmaVision, byteBudget) {
|
|
863
|
-
if (source.kind !== "figma-snapshot") {
|
|
1045
|
+
if (source.kind !== "figma-snapshot" && source.kind !== "image") {
|
|
864
1046
|
return ingestOne(source, index, registeredAt, capsuleResolver, figmaSnapshotLoader, figmaVision, byteBudget);
|
|
865
1047
|
}
|
|
866
1048
|
if (figmaSnapshotLoader === undefined) {
|
|
867
|
-
throw new QiIngestionError("
|
|
1049
|
+
throw new QiIngestionError(source.kind === "image" ? "QI_IMAGE_UNAVAILABLE" : "QI_FIGMA_SNAPSHOT_UNAVAILABLE", source.kind === "image"
|
|
1050
|
+
? "Image sources are unavailable: the evidence directory is not configured."
|
|
1051
|
+
: "Figma-snapshot sources are unavailable: the evidence directory is not configured.");
|
|
1052
|
+
}
|
|
1053
|
+
if (source.kind === "image") {
|
|
1054
|
+
return ingestImageSourceAsync(source, index, registeredAt, figmaSnapshotLoader, figmaVision, byteBudget);
|
|
868
1055
|
}
|
|
869
1056
|
return ingestFigmaSnapshotAsync(source, index, registeredAt, figmaSnapshotLoader, figmaVision, byteBudget);
|
|
870
1057
|
}
|
|
@@ -2,8 +2,15 @@ import type { QualityIntelligenceRunStreamMessage } from "@oscharko-dev/keiko-co
|
|
|
2
2
|
import type { QualityIntelligence as QI } from "@oscharko-dev/keiko-contracts";
|
|
3
3
|
import { type HandlerOutcome, type RouteContext, type RouteResult, type RouteDefinition } from "../routes.js";
|
|
4
4
|
import type { Redactor, UiHandlerDeps } from "../deps.js";
|
|
5
|
+
import { executeQiRun } from "./runExecution.js";
|
|
5
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;
|
|
6
12
|
export declare function handleStartQiRun(ctx: RouteContext, deps: UiHandlerDeps): Promise<HandlerOutcome>;
|
|
7
13
|
export declare function handleCancelQiRun(ctx: RouteContext, _deps: UiHandlerDeps): RouteResult;
|
|
8
14
|
export declare const QI_RUN_EXECUTION_ROUTE_GROUP: readonly RouteDefinition[];
|
|
15
|
+
export {};
|
|
9
16
|
//# sourceMappingURL=runRoutes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runRoutes.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/runRoutes.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,
|
|
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"}
|
|
@@ -12,7 +12,8 @@ import { isAbsolute } from "node:path";
|
|
|
12
12
|
import { SSE_HEADERS } from "../sse.js";
|
|
13
13
|
import { writeOrDestroy } from "../sse-write.js";
|
|
14
14
|
import { STREAMING, } from "../routes.js";
|
|
15
|
-
import { executeQiRun, QiGenerationError, QiIngestionError } from "./runExecution.js";
|
|
15
|
+
import { executeQiRun, QiGenerationError, QiIngestionError, } from "./runExecution.js";
|
|
16
|
+
import { parseFigmaSnapshotScreenIds } from "./figmaSnapshotScreenIds.js";
|
|
16
17
|
import { qiRunRegistry } from "./runRegistry.js";
|
|
17
18
|
const MAX_BODY_BYTES = 2 * 1024 * 1024;
|
|
18
19
|
class BodyTooLargeError extends Error {
|
|
@@ -61,7 +62,37 @@ function validateFigmaSnapshotSource(label, raw) {
|
|
|
61
62
|
if (typeof raw.snapshotRunId !== "string" || raw.snapshotRunId.trim().length === 0) {
|
|
62
63
|
return errorResult(400, "QI_BAD_REQUEST", "A figma-snapshot source requires a non-empty snapshotRunId.");
|
|
63
64
|
}
|
|
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
|
+
};
|
|
65
96
|
}
|
|
66
97
|
// Connector sources (Local Knowledge capsule / capsule-set, Figma snapshot). Split out so
|
|
67
98
|
// validateSource stays under the complexity budget as the source-kind union grows (Epic #710/#750).
|
|
@@ -75,6 +106,9 @@ function validateConnectorSource(label, raw) {
|
|
|
75
106
|
if (raw.kind === "figma-snapshot") {
|
|
76
107
|
return validateFigmaSnapshotSource(label, raw);
|
|
77
108
|
}
|
|
109
|
+
if (raw.kind === "image") {
|
|
110
|
+
return validateImageSource(label, raw);
|
|
111
|
+
}
|
|
78
112
|
return undefined;
|
|
79
113
|
}
|
|
80
114
|
function validateSource(raw) {
|
|
@@ -220,6 +254,36 @@ function classifyStartError(error) {
|
|
|
220
254
|
function toWireSkippedSources(skipped) {
|
|
221
255
|
return skipped.map((s) => ({ label: s.label, kind: s.kind, code: s.code }));
|
|
222
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
|
+
}
|
|
223
287
|
async function streamRunExecution(deps, request, runId, registeredAt, signal, write) {
|
|
224
288
|
const totals = { candidates: 0, findings: 0, exports: 0 };
|
|
225
289
|
let terminal = "failed";
|
|
@@ -231,19 +295,7 @@ async function streamRunExecution(deps, request, runId, registeredAt, signal, wr
|
|
|
231
295
|
registeredAt,
|
|
232
296
|
signal,
|
|
233
297
|
onAccepted: (accepted) => {
|
|
234
|
-
write
|
|
235
|
-
type: "accepted",
|
|
236
|
-
runId: accepted.runId,
|
|
237
|
-
requestedAt: accepted.requestedAt,
|
|
238
|
-
sourceCount: accepted.sourceCount,
|
|
239
|
-
atomCount: accepted.atomCount,
|
|
240
|
-
...(accepted.droppedSourceCount > 0
|
|
241
|
-
? { droppedSourceCount: accepted.droppedSourceCount }
|
|
242
|
-
: {}),
|
|
243
|
-
...(accepted.skippedSources.length > 0
|
|
244
|
-
? { skippedSources: toWireSkippedSources(accepted.skippedSources) }
|
|
245
|
-
: {}),
|
|
246
|
-
});
|
|
298
|
+
writeAcceptedFrame(write, accepted);
|
|
247
299
|
},
|
|
248
300
|
onEvent: (event) => {
|
|
249
301
|
if (event.payload.kind === "candidate:proposed")
|
|
@@ -255,7 +307,7 @@ async function streamRunExecution(deps, request, runId, registeredAt, signal, wr
|
|
|
255
307
|
},
|
|
256
308
|
});
|
|
257
309
|
terminal = summary.status;
|
|
258
|
-
write(
|
|
310
|
+
write(doneFrameForSummary(deps, runId, summary, totals));
|
|
259
311
|
}
|
|
260
312
|
catch (error) {
|
|
261
313
|
const { code, message } = classifyStartError(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AA0I/C,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE;AAID,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,SAAS,eAAsB,CAAC;AAC7C,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,OAAO,SAAS,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAElD,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;CACnB;AAED,MAAM,MAAM,YAAY,GAAG,CACzB,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,aAAa,KAChB,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;CAChC;AAUD,eAAO,MAAM,UAAU,EAAE,SAAS,eAAe,EA4ShD,CAAC;AA6BF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAKD,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,UAAU,GAAG,oBAAoB,GAAG,SAAS,CA2B/C;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,CAEjE;AAED,wBAAgB,YAAY,IAAI,QAAQ,CAEvC;AAED,wBAAgB,oBAAoB,IAAI,QAAQ,CAE/C"}
|
|
@@ -23,7 +23,7 @@ import { handleBrowserApplyScreenshot, handleBrowserContent, handleBrowserEvents
|
|
|
23
23
|
import { handleCancelLocalKnowledgeCapsuleIndexing, handleConnectLocalKnowledgeCapsule, handleCreateLocalKnowledgeCapsule, handleCreateLocalKnowledgeCapsuleSet, handleDeleteLocalKnowledgeCapsule, handleDisconnectLocalKnowledgeCapsule, handleGetLocalKnowledgeCapsule, handleListLocalKnowledgeCapsules, handleListLocalKnowledgeCapsuleSets, handleReindexLocalKnowledgeCapsule, handleStartLocalKnowledgeCapsuleIndexing, handleUpdateLocalKnowledgeCapsule, } from "./local-knowledge-handlers.js";
|
|
24
24
|
import { handleRelationshipCreate, handleRelationshipDelete, handleRelationshipDependencies, handleRelationshipEvents, handleRelationshipExplain, handleRelationshipGet, handleRelationshipHealth, handleRelationshipImpact, handleRelationshipList, handleRelationshipPatch, handleRelationshipValidate, } from "./relationship-handlers.js";
|
|
25
25
|
import { handleQiCapabilities, handleQiDryRunFigma, handleQiDryRunJira, handleQiSourceSelect, handleListQiRuns, handleGetQiRun, QI_HANDOFF_ROUTE_GROUP, QI_RUN_EXECUTION_ROUTE_GROUP, QI_REVIEW_ROUTE_GROUP, QI_EXPORT_ROUTE_GROUP, QI_EDIT_ROUTE_GROUP, QI_RETENTION_ROUTE_GROUP, QI_TRACEABILITY_ROUTE_GROUP, QI_RECHECK_ROUTE_GROUP, } from "./qualityIntelligence/index.js";
|
|
26
|
-
import { handleFigmaListSnapshots, handleFigmaTriggerSnapshot, handleFigmaLoadSnapshot, handleFigmaLoadSnapshotImage, handleFigmaRevokeToken, } from "./qualityIntelligence/figmaSnapshotRoutes.js";
|
|
26
|
+
import { handleFigmaListSnapshots, handleFigmaInspectSnapshotScreenJson, handleFigmaTriggerSnapshot, handleFigmaLoadSnapshot, handleFigmaLoadSnapshotImage, handleFigmaRevokeToken, } from "./qualityIntelligence/figmaSnapshotRoutes.js";
|
|
27
27
|
import { handleFigmaGenerateCode } from "./qualityIntelligence/figmaCodegenRoutes.js";
|
|
28
28
|
export const STREAMING = Symbol("streaming");
|
|
29
29
|
function health() {
|
|
@@ -314,6 +314,11 @@ export const API_ROUTES = [
|
|
|
314
314
|
{ method: "POST", pattern: "/api/figma/snapshots", handler: handleFigmaTriggerSnapshot },
|
|
315
315
|
{ method: "GET", pattern: "/api/figma/snapshots", handler: handleFigmaListSnapshots },
|
|
316
316
|
{ method: "GET", pattern: "/api/figma/snapshots/:runId", handler: handleFigmaLoadSnapshot },
|
|
317
|
+
{
|
|
318
|
+
method: "GET",
|
|
319
|
+
pattern: "/api/figma/snapshots/:runId/screens/:screenId/json",
|
|
320
|
+
handler: handleFigmaInspectSnapshotScreenJson,
|
|
321
|
+
},
|
|
317
322
|
{
|
|
318
323
|
method: "GET",
|
|
319
324
|
pattern: "/api/figma/snapshots/:runId/screens/:screenIndex/image",
|