@oscharko-dev/keiko 0.2.0-beta.3 → 0.2.0-beta.5

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.
Files changed (573) hide show
  1. package/README.md +139 -1
  2. package/dist/ui/csp-hashes.json +33 -39
  3. package/dist/ui/static/404.html +1 -1
  4. package/dist/ui/static/__next.__PAGE__.txt +9 -0
  5. package/dist/ui/static/__next._full.txt +18 -0
  6. package/dist/ui/static/__next._head.txt +6 -0
  7. package/dist/ui/static/__next._index.txt +5 -0
  8. package/dist/ui/static/__next._tree.txt +2 -0
  9. package/dist/ui/static/_next/static/chunks/05-c3ty_6dwfk.js +1 -0
  10. package/dist/ui/static/_next/static/chunks/082obv3v03b-9.js +2 -0
  11. package/dist/ui/static/_next/static/chunks/0iq1i69206cyl.js +31 -0
  12. package/dist/ui/static/_next/static/chunks/0uifns067thv8.js +1 -0
  13. package/dist/ui/static/_next/static/chunks/0x31-j53ab1tt.js +1 -0
  14. package/dist/ui/static/_next/static/chunks/14mrh2-p_w84d.js +1 -0
  15. package/dist/ui/static/_next/static/chunks/1m-kvwm6_90_3.css +1 -0
  16. package/dist/ui/static/_next/static/chunks/1v4hrxrm_6_rw.js +1 -0
  17. package/dist/ui/static/_next/static/chunks/27jktro2p5rq9.js +4 -0
  18. package/dist/ui/static/_next/static/chunks/2lypy3ewh0r04.js +1 -0
  19. package/dist/ui/static/_next/static/chunks/2ngm8iwdb1cbv.js +106 -0
  20. package/dist/ui/static/_next/static/chunks/32573pyyglqxl.js +1 -0
  21. package/dist/ui/static/_next/static/chunks/3_t_pzet29qtn.js +1 -0
  22. package/dist/ui/static/_next/static/chunks/3jgg_oe0iok0l.js +1 -0
  23. package/dist/ui/static/_next/static/chunks/3o_oia3vsam60.js +1 -0
  24. package/dist/ui/static/_next/static/chunks/3peubv2924kx4.js +1 -0
  25. package/dist/ui/static/_next/static/chunks/turbopack-2lg1g6kbsfm0x.js +1 -0
  26. package/dist/ui/static/_next/static/hR2gBQqCDKdPdSxBqZhqv/_buildManifest.js +11 -0
  27. package/dist/ui/static/_next/static/hR2gBQqCDKdPdSxBqZhqv/_clientMiddlewareManifest.js +1 -0
  28. package/dist/ui/static/_not-found/__next._full.txt +16 -0
  29. package/dist/ui/static/_not-found/__next._head.txt +6 -0
  30. package/dist/ui/static/_not-found/__next._index.txt +5 -0
  31. package/dist/ui/static/_not-found/__next._not-found.__PAGE__.txt +5 -0
  32. package/dist/ui/static/_not-found/__next._not-found.txt +5 -0
  33. package/dist/ui/static/_not-found/__next._tree.txt +2 -0
  34. package/dist/ui/static/_not-found.html +1 -0
  35. package/dist/ui/static/_not-found.txt +16 -0
  36. package/dist/ui/static/index.html +1 -1
  37. package/dist/ui/static/index.txt +16 -18
  38. package/dist/ui/static/launch/__next._full.txt +20 -0
  39. package/dist/ui/static/launch/__next._head.txt +6 -0
  40. package/dist/ui/static/launch/__next._index.txt +5 -0
  41. package/dist/ui/static/launch/__next._tree.txt +2 -0
  42. package/dist/ui/static/launch/__next.launch.__PAGE__.txt +9 -0
  43. package/dist/ui/static/launch/__next.launch.txt +5 -0
  44. package/dist/ui/static/launch.html +1 -1
  45. package/dist/ui/static/launch.txt +17 -17
  46. package/dist/ui/static/local-knowledge/__next._full.txt +20 -0
  47. package/dist/ui/static/local-knowledge/__next._head.txt +6 -0
  48. package/dist/ui/static/local-knowledge/__next._index.txt +5 -0
  49. package/dist/ui/static/local-knowledge/__next._tree.txt +2 -0
  50. package/dist/ui/static/local-knowledge/__next.local-knowledge.__PAGE__.txt +9 -0
  51. package/dist/ui/static/local-knowledge/__next.local-knowledge.txt +5 -0
  52. package/dist/ui/static/local-knowledge/capsule/__next._full.txt +17 -0
  53. package/dist/ui/static/local-knowledge/capsule/__next._head.txt +6 -0
  54. package/dist/ui/static/local-knowledge/capsule/__next._index.txt +5 -0
  55. package/dist/ui/static/local-knowledge/capsule/__next._tree.txt +2 -0
  56. package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.capsule.__PAGE__.txt +6 -0
  57. package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.capsule.txt +5 -0
  58. package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.txt +5 -0
  59. package/dist/ui/static/local-knowledge/capsule.html +1 -1
  60. package/dist/ui/static/local-knowledge/capsule.txt +14 -14
  61. package/dist/ui/static/local-knowledge.html +1 -1
  62. package/dist/ui/static/local-knowledge.txt +19 -16
  63. package/dist/ui/static/memoriaviva/__next._full.txt +17 -0
  64. package/dist/ui/static/memoriaviva/__next._head.txt +6 -0
  65. package/dist/ui/static/memoriaviva/__next._index.txt +5 -0
  66. package/dist/ui/static/memoriaviva/__next._tree.txt +2 -0
  67. package/dist/ui/static/memoriaviva/__next.memoriaviva.__PAGE__.txt +6 -0
  68. package/dist/ui/static/memoriaviva/__next.memoriaviva.txt +5 -0
  69. package/dist/ui/static/memoriaviva/consolidation/__next._full.txt +17 -0
  70. package/dist/ui/static/memoriaviva/consolidation/__next._head.txt +6 -0
  71. package/dist/ui/static/memoriaviva/consolidation/__next._index.txt +5 -0
  72. package/dist/ui/static/memoriaviva/consolidation/__next._tree.txt +2 -0
  73. package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.consolidation.__PAGE__.txt +6 -0
  74. package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.consolidation.txt +5 -0
  75. package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.txt +5 -0
  76. package/dist/ui/static/memoriaviva/consolidation.html +1 -1
  77. package/dist/ui/static/memoriaviva/consolidation.txt +15 -15
  78. package/dist/ui/static/memoriaviva/detail/__next._full.txt +17 -0
  79. package/dist/ui/static/memoriaviva/detail/__next._head.txt +6 -0
  80. package/dist/ui/static/memoriaviva/detail/__next._index.txt +5 -0
  81. package/dist/ui/static/memoriaviva/detail/__next._tree.txt +2 -0
  82. package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.detail.__PAGE__.txt +6 -0
  83. package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.detail.txt +5 -0
  84. package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.txt +5 -0
  85. package/dist/ui/static/memoriaviva/detail.html +1 -1
  86. package/dist/ui/static/memoriaviva/detail.txt +14 -14
  87. package/dist/ui/static/memoriaviva/review-queue/__next._full.txt +17 -0
  88. package/dist/ui/static/memoriaviva/review-queue/__next._head.txt +6 -0
  89. package/dist/ui/static/memoriaviva/review-queue/__next._index.txt +5 -0
  90. package/dist/ui/static/memoriaviva/review-queue/__next._tree.txt +2 -0
  91. package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.review-queue.__PAGE__.txt +6 -0
  92. package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.review-queue.txt +5 -0
  93. package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.txt +5 -0
  94. package/dist/ui/static/memoriaviva/review-queue.html +1 -1
  95. package/dist/ui/static/memoriaviva/review-queue.txt +15 -15
  96. package/dist/ui/static/memoriaviva.html +1 -1
  97. package/dist/ui/static/memoriaviva.txt +14 -14
  98. package/node_modules/@oscharko-dev/keiko-cli/dist/.tsbuildinfo +1 -1
  99. package/node_modules/@oscharko-dev/keiko-cli/dist/evaluate.d.ts.map +1 -1
  100. package/node_modules/@oscharko-dev/keiko-cli/dist/evaluate.js +61 -2
  101. package/node_modules/@oscharko-dev/keiko-cli/dist/evidence.d.ts.map +1 -1
  102. package/node_modules/@oscharko-dev/keiko-cli/dist/evidence.js +65 -21
  103. package/node_modules/@oscharko-dev/keiko-cli/dist/launcher-platforms.js +3 -3
  104. package/node_modules/@oscharko-dev/keiko-cli/dist/run.d.ts +3 -1
  105. package/node_modules/@oscharko-dev/keiko-cli/dist/run.d.ts.map +1 -1
  106. package/node_modules/@oscharko-dev/keiko-cli/dist/run.js +73 -41
  107. package/node_modules/@oscharko-dev/keiko-cli/dist/ui.d.ts.map +1 -1
  108. package/node_modules/@oscharko-dev/keiko-cli/dist/ui.js +36 -11
  109. package/node_modules/@oscharko-dev/keiko-cli/package.json +2 -2
  110. package/node_modules/@oscharko-dev/keiko-contracts/dist/.tsbuildinfo +1 -1
  111. package/node_modules/@oscharko-dev/keiko-contracts/dist/bff-wire.d.ts +20 -1
  112. package/node_modules/@oscharko-dev/keiko-contracts/dist/bff-wire.d.ts.map +1 -1
  113. package/node_modules/@oscharko-dev/keiko-contracts/dist/connected-context.d.ts +1 -1
  114. package/node_modules/@oscharko-dev/keiko-contracts/dist/connected-context.d.ts.map +1 -1
  115. package/node_modules/@oscharko-dev/keiko-contracts/dist/connected-context.js +256 -75
  116. package/node_modules/@oscharko-dev/keiko-contracts/dist/evidence.d.ts +11 -0
  117. package/node_modules/@oscharko-dev/keiko-contracts/dist/evidence.d.ts.map +1 -1
  118. package/node_modules/@oscharko-dev/keiko-contracts/dist/index.d.ts +6 -6
  119. package/node_modules/@oscharko-dev/keiko-contracts/dist/index.d.ts.map +1 -1
  120. package/node_modules/@oscharko-dev/keiko-contracts/dist/index.js +4 -4
  121. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge-records.d.ts +11 -0
  122. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge-records.d.ts.map +1 -1
  123. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge-records.js +4 -0
  124. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge-schema.d.ts +1 -1
  125. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge-schema.d.ts.map +1 -1
  126. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge-schema.js +109 -4
  127. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge-validation.d.ts +2 -0
  128. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge-validation.d.ts.map +1 -1
  129. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge-validation.js +94 -7
  130. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge.d.ts +5 -0
  131. package/node_modules/@oscharko-dev/keiko-contracts/dist/local-knowledge.d.ts.map +1 -1
  132. package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/bffWire.d.ts +2 -0
  133. package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/bffWire.d.ts.map +1 -1
  134. package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/ids.d.ts.map +1 -1
  135. package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/ids.js +3 -0
  136. package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/sourceEnvelope.d.ts +14 -0
  137. package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/sourceEnvelope.d.ts.map +1 -1
  138. package/node_modules/@oscharko-dev/keiko-contracts/dist/qualityIntelligence/sourceEnvelope.js +53 -5
  139. package/node_modules/@oscharko-dev/keiko-contracts/package.json +2 -2
  140. package/node_modules/@oscharko-dev/keiko-evaluations/dist/.tsbuildinfo +1 -1
  141. package/node_modules/@oscharko-dev/keiko-evaluations/dist/runner.d.ts.map +1 -1
  142. package/node_modules/@oscharko-dev/keiko-evaluations/dist/runner.js +11 -3
  143. package/node_modules/@oscharko-dev/keiko-evaluations/package.json +2 -2
  144. package/node_modules/@oscharko-dev/keiko-evidence/dist/.tsbuildinfo +1 -1
  145. package/node_modules/@oscharko-dev/keiko-evidence/dist/connected-context-evidence.d.ts +20 -1
  146. package/node_modules/@oscharko-dev/keiko-evidence/dist/connected-context-evidence.d.ts.map +1 -1
  147. package/node_modules/@oscharko-dev/keiko-evidence/dist/connected-context-evidence.js +34 -2
  148. package/node_modules/@oscharko-dev/keiko-evidence/dist/index.d.ts +1 -1
  149. package/node_modules/@oscharko-dev/keiko-evidence/dist/index.d.ts.map +1 -1
  150. package/node_modules/@oscharko-dev/keiko-evidence/dist/index.js +1 -1
  151. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/candidatesArtifact.d.ts +1 -0
  152. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/candidatesArtifact.d.ts.map +1 -1
  153. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/candidatesArtifact.js +3 -1
  154. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/companionStore.d.ts +17 -0
  155. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/companionStore.d.ts.map +1 -1
  156. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/companionStore.js +19 -0
  157. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/schema.d.ts +5 -1
  158. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/schema.d.ts.map +1 -1
  159. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.d.ts +32 -2
  160. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.d.ts.map +1 -1
  161. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.js +259 -40
  162. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/index.d.ts +3 -3
  163. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/index.d.ts.map +1 -1
  164. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/index.js +1 -1
  165. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/manifestSchema.d.ts +18 -1
  166. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/manifestSchema.d.ts.map +1 -1
  167. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/retention.d.ts +3 -0
  168. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/retention.d.ts.map +1 -1
  169. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/retention.js +48 -5
  170. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/store.d.ts +33 -0
  171. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/store.d.ts.map +1 -1
  172. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/store.js +99 -13
  173. package/node_modules/@oscharko-dev/keiko-evidence/dist/types.d.ts +1 -1
  174. package/node_modules/@oscharko-dev/keiko-evidence/dist/types.d.ts.map +1 -1
  175. package/node_modules/@oscharko-dev/keiko-evidence/package.json +2 -2
  176. package/node_modules/@oscharko-dev/keiko-harness/dist/.tsbuildinfo +1 -1
  177. package/node_modules/@oscharko-dev/keiko-harness/package.json +2 -2
  178. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/.tsbuildinfo +1 -1
  179. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/capsule-lifecycle.d.ts.map +1 -1
  180. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/capsule-lifecycle.js +25 -1
  181. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/capsule-set-lifecycle.d.ts +1 -1
  182. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/capsule-set-lifecycle.d.ts.map +1 -1
  183. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/capsule-set-lifecycle.js +16 -0
  184. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/chunker-persist.d.ts +3 -1
  185. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/chunker-persist.d.ts.map +1 -1
  186. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/chunker-persist.js +9 -5
  187. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/chunker-runner.d.ts.map +1 -1
  188. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/chunker-runner.js +22 -7
  189. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/chunker.d.ts +4 -1
  190. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/chunker.d.ts.map +1 -1
  191. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/chunker.js +61 -9
  192. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/citation-mapper.d.ts.map +1 -1
  193. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/citation-mapper.js +64 -36
  194. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/index.d.ts +2 -2
  195. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/index.d.ts.map +1 -1
  196. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/index.js +2 -2
  197. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/types.d.ts +7 -1
  198. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/types.d.ts.map +1 -1
  199. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/chunking/types.js +5 -1
  200. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/composition.d.ts +1 -1
  201. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/composition.d.ts.map +1 -1
  202. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/composition.js +27 -4
  203. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/index.d.ts +0 -1
  204. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/index.d.ts.map +1 -1
  205. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/index.js +0 -1
  206. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/model-gateway-answer-generator.d.ts +5 -1
  207. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/model-gateway-answer-generator.d.ts.map +1 -1
  208. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/model-gateway-answer-generator.js +25 -6
  209. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/types.d.ts.map +1 -1
  210. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/types.js +2 -3
  211. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/discovery-runner.d.ts.map +1 -1
  212. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/discovery-runner.js +10 -1
  213. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/extract.d.ts +4 -1
  214. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/extract.d.ts.map +1 -1
  215. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/extract.js +370 -45
  216. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/test-support.d.ts +2 -0
  217. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/test-support.d.ts.map +1 -1
  218. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/test-support.js +8 -4
  219. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/types.d.ts +1 -1
  220. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/types.d.ts.map +1 -1
  221. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/types.js +10 -5
  222. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/walk.d.ts.map +1 -1
  223. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/discovery/walk.js +65 -20
  224. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/evaluations/fixtures.d.ts +1 -0
  225. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/evaluations/fixtures.d.ts.map +1 -1
  226. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/evaluations/fixtures.js +79 -0
  227. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/evaluations/index.d.ts +1 -1
  228. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/evaluations/index.d.ts.map +1 -1
  229. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/evaluations/index.js +1 -1
  230. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/evaluations/runner-seed.d.ts.map +1 -1
  231. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/evaluations/runner-seed.js +4 -0
  232. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/index.d.ts +6 -5
  233. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/index.d.ts.map +1 -1
  234. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/index.js +4 -4
  235. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/indexing/embedding-batcher.d.ts.map +1 -1
  236. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/indexing/embedding-batcher.js +71 -29
  237. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/indexing/orchestrator.d.ts.map +1 -1
  238. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/indexing/orchestrator.js +253 -131
  239. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/indexing/types.d.ts +12 -0
  240. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/indexing/types.d.ts.map +1 -1
  241. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/indexing/vector-persist.d.ts.map +1 -1
  242. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/indexing/vector-persist.js +9 -0
  243. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/_internal.d.ts +3 -1
  244. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/_internal.d.ts.map +1 -1
  245. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/_internal.js +13 -1
  246. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/docx-parser.d.ts.map +1 -1
  247. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/docx-parser.js +86 -46
  248. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/index.d.ts +1 -1
  249. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/index.d.ts.map +1 -1
  250. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/index.js +1 -1
  251. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/json-parser.d.ts.map +1 -1
  252. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/json-parser.js +50 -22
  253. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/pdf-parser.d.ts +21 -1
  254. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/pdf-parser.d.ts.map +1 -1
  255. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/pdf-parser.js +90 -13
  256. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/registry.d.ts.map +1 -1
  257. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/registry.js +3 -1
  258. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/types.d.ts +7 -2
  259. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/types.d.ts.map +1 -1
  260. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/types.js +7 -3
  261. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/privacy/audit-emitter.js +8 -0
  262. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/privacy/diagnostic-redactor.d.ts.map +1 -1
  263. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/privacy/diagnostic-redactor.js +17 -10
  264. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/privacy/retention-applier.d.ts.map +1 -1
  265. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/privacy/retention-applier.js +7 -0
  266. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/privacy/types.d.ts +4 -0
  267. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/privacy/types.d.ts.map +1 -1
  268. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/retrieval/retrieval-runner.js +1 -1
  269. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/retrieval/scoped-vector-search.d.ts +1 -0
  270. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/retrieval/scoped-vector-search.d.ts.map +1 -1
  271. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/retrieval/scoped-vector-search.js +318 -32
  272. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/source-lifecycle.d.ts +1 -1
  273. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/source-lifecycle.d.ts.map +1 -1
  274. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/source-lifecycle.js +46 -16
  275. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/store.d.ts +14 -0
  276. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/store.d.ts.map +1 -1
  277. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/store.js +26 -1
  278. package/node_modules/@oscharko-dev/keiko-local-knowledge/package.json +10 -5
  279. package/node_modules/@oscharko-dev/keiko-memory-capture/dist/.tsbuildinfo +1 -1
  280. package/node_modules/@oscharko-dev/keiko-memory-capture/package.json +2 -2
  281. package/node_modules/@oscharko-dev/keiko-memory-consolidation/dist/.tsbuildinfo +1 -1
  282. package/node_modules/@oscharko-dev/keiko-memory-consolidation/package.json +2 -2
  283. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/.tsbuildinfo +1 -1
  284. package/node_modules/@oscharko-dev/keiko-memory-governance/package.json +2 -2
  285. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/.tsbuildinfo +1 -1
  286. package/node_modules/@oscharko-dev/keiko-memory-retrieval/package.json +2 -2
  287. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/.tsbuildinfo +1 -1
  288. package/node_modules/@oscharko-dev/keiko-memory-vault/package.json +2 -2
  289. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/.tsbuildinfo +1 -1
  290. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/config.d.ts +2 -1
  291. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/config.d.ts.map +1 -1
  292. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/config.js +50 -0
  293. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/http.d.ts +3 -0
  294. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/http.d.ts.map +1 -1
  295. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/http.js +114 -44
  296. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/normalize.d.ts +1 -0
  297. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/normalize.d.ts.map +1 -1
  298. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/normalize.js +22 -1
  299. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/openai-adapter.d.ts.map +1 -1
  300. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/openai-adapter.js +18 -4
  301. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/qualityIntelligence/dispatcher.d.ts +14 -0
  302. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/qualityIntelligence/dispatcher.d.ts.map +1 -1
  303. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/qualityIntelligence/dispatcher.js +14 -0
  304. package/node_modules/@oscharko-dev/keiko-model-gateway/package.json +2 -2
  305. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/.tsbuildinfo +1 -1
  306. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/a11yBaseline.d.ts.map +1 -1
  307. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/a11yBaseline.js +9 -2
  308. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/cleanToScreenIr.js +1 -1
  309. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/emissionPlan.d.ts +9 -1
  310. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/emissionPlan.d.ts.map +1 -1
  311. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/emissionPlan.js +9 -1
  312. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/htmlCssAdapter.d.ts +5 -0
  313. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/htmlCssAdapter.d.ts.map +1 -1
  314. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/htmlCssAdapter.js +229 -33
  315. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/irTypes.d.ts +62 -0
  316. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/irTypes.d.ts.map +1 -1
  317. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/links.d.ts.map +1 -1
  318. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/links.js +24 -4
  319. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/navGraph.d.ts +4 -2
  320. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/navGraph.d.ts.map +1 -1
  321. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/navGraph.js +0 -0
  322. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/normalize.d.ts.map +1 -1
  323. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/normalize.js +119 -5
  324. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/prune.d.ts +2 -1
  325. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/prune.d.ts.map +1 -1
  326. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/prune.js +26 -11
  327. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/screenIrTestBaseline.d.ts.map +1 -1
  328. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/screenIrTestBaseline.js +86 -9
  329. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/tokens.d.ts.map +1 -1
  330. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/figma/tokens.js +10 -3
  331. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/validation.d.ts.map +1 -1
  332. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/domain/validation.js +14 -12
  333. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/alm.d.ts.map +1 -1
  334. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/alm.js +29 -30
  335. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/markdown.d.ts.map +1 -1
  336. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/markdown.js +29 -5
  337. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/qtest.d.ts.map +1 -1
  338. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/qtest.js +29 -29
  339. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/spreadsheetSafeCsv.d.ts +2 -1
  340. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/spreadsheetSafeCsv.d.ts.map +1 -1
  341. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/spreadsheetSafeCsv.js +40 -2
  342. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/xray.d.ts.map +1 -1
  343. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/export/adapters/xray.js +6 -2
  344. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/ingestion/sourceMixPlanning.js +0 -0
  345. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/ingestion/untrustedContentNormalisation.d.ts +1 -1
  346. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/ingestion/untrustedContentNormalisation.d.ts.map +1 -1
  347. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/ingestion/untrustedContentNormalisation.js +9 -1
  348. package/node_modules/@oscharko-dev/keiko-quality-intelligence/package.json +2 -2
  349. package/node_modules/@oscharko-dev/keiko-sdk/dist/.tsbuildinfo +1 -1
  350. package/node_modules/@oscharko-dev/keiko-sdk/package.json +2 -2
  351. package/node_modules/@oscharko-dev/keiko-security/dist/.tsbuildinfo +1 -1
  352. package/node_modules/@oscharko-dev/keiko-security/dist/redaction.d.ts.map +1 -1
  353. package/node_modules/@oscharko-dev/keiko-security/dist/redaction.js +4 -2
  354. package/node_modules/@oscharko-dev/keiko-security/package.json +2 -2
  355. package/node_modules/@oscharko-dev/keiko-server/dist/.tsbuildinfo +1 -1
  356. package/node_modules/@oscharko-dev/keiko-server/dist/assistant-response.d.ts +6 -0
  357. package/node_modules/@oscharko-dev/keiko-server/dist/assistant-response.d.ts.map +1 -0
  358. package/node_modules/@oscharko-dev/keiko-server/dist/assistant-response.js +12 -0
  359. package/node_modules/@oscharko-dev/keiko-server/dist/chat-handlers.d.ts +1 -1
  360. package/node_modules/@oscharko-dev/keiko-server/dist/chat-handlers.d.ts.map +1 -1
  361. package/node_modules/@oscharko-dev/keiko-server/dist/chat-handlers.js +17 -5
  362. package/node_modules/@oscharko-dev/keiko-server/dist/chat-stream-handlers.js +1 -1
  363. package/node_modules/@oscharko-dev/keiko-server/dist/deps.d.ts +2 -0
  364. package/node_modules/@oscharko-dev/keiko-server/dist/deps.d.ts.map +1 -1
  365. package/node_modules/@oscharko-dev/keiko-server/dist/deps.js +59 -9
  366. package/node_modules/@oscharko-dev/keiko-server/dist/evidence.d.ts +1 -1
  367. package/node_modules/@oscharko-dev/keiko-server/dist/evidence.d.ts.map +1 -1
  368. package/node_modules/@oscharko-dev/keiko-server/dist/evidence.js +4 -3
  369. package/node_modules/@oscharko-dev/keiko-server/dist/files.d.ts +18 -3
  370. package/node_modules/@oscharko-dev/keiko-server/dist/files.d.ts.map +1 -1
  371. package/node_modules/@oscharko-dev/keiko-server/dist/files.js +208 -72
  372. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-answer.d.ts.map +1 -1
  373. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-answer.js +7 -2
  374. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-context-index.d.ts +3 -0
  375. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-context-index.d.ts.map +1 -1
  376. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-context-index.js +27 -4
  377. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-handoff.d.ts.map +1 -1
  378. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-handoff.js +46 -14
  379. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-orchestrator.d.ts +1 -1
  380. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-orchestrator.d.ts.map +1 -1
  381. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-orchestrator.js +651 -45
  382. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-prompt.d.ts.map +1 -1
  383. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-prompt.js +5 -3
  384. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa-hybrid.d.ts +9 -0
  385. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa-hybrid.d.ts.map +1 -1
  386. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa-hybrid.js +197 -46
  387. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa-multi-source.d.ts +4 -0
  388. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa-multi-source.d.ts.map +1 -1
  389. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa-multi-source.js +103 -25
  390. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa.d.ts +7 -0
  391. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa.d.ts.map +1 -1
  392. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-qa.js +199 -21
  393. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-turn-registry.d.ts.map +1 -1
  394. package/node_modules/@oscharko-dev/keiko-server/dist/grounded-turn-registry.js +21 -1
  395. package/node_modules/@oscharko-dev/keiko-server/dist/index.d.ts +1 -1
  396. package/node_modules/@oscharko-dev/keiko-server/dist/index.d.ts.map +1 -1
  397. package/node_modules/@oscharko-dev/keiko-server/dist/index.js +1 -1
  398. package/node_modules/@oscharko-dev/keiko-server/dist/local-knowledge-grounded-qa.d.ts +9 -6
  399. package/node_modules/@oscharko-dev/keiko-server/dist/local-knowledge-grounded-qa.d.ts.map +1 -1
  400. package/node_modules/@oscharko-dev/keiko-server/dist/local-knowledge-grounded-qa.js +193 -67
  401. package/node_modules/@oscharko-dev/keiko-server/dist/local-knowledge-handlers.d.ts.map +1 -1
  402. package/node_modules/@oscharko-dev/keiko-server/dist/local-knowledge-handlers.js +189 -72
  403. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/connectorErrors.d.ts.map +1 -1
  404. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/connectorErrors.js +11 -8
  405. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/editRoutes.d.ts.map +1 -1
  406. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/editRoutes.js +1 -0
  407. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/exportRoutes.d.ts.map +1 -1
  408. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/exportRoutes.js +89 -30
  409. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaConnectorErrors.d.ts +10 -2
  410. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaConnectorErrors.d.ts.map +1 -1
  411. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaConnectorErrors.js +110 -30
  412. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaHttpPort.d.ts +13 -4
  413. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaHttpPort.d.ts.map +1 -1
  414. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaHttpPort.js +29 -17
  415. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaRenderPort.d.ts +13 -3
  416. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaRenderPort.d.ts.map +1 -1
  417. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaRenderPort.js +54 -5
  418. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotBuilder.d.ts.map +1 -1
  419. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotBuilder.js +84 -12
  420. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotHash.d.ts.map +1 -1
  421. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotHash.js +16 -8
  422. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotTypes.d.ts +6 -2
  423. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figma/figmaSnapshotTypes.d.ts.map +1 -1
  424. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotAdapter.d.ts +13 -1
  425. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotAdapter.d.ts.map +1 -1
  426. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotAdapter.js +15 -2
  427. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotOrchestration.d.ts +9 -0
  428. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotOrchestration.d.ts.map +1 -1
  429. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotOrchestration.js +2 -2
  430. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts +9 -1
  431. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts.map +1 -1
  432. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.js +138 -19
  433. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/generationPort.d.ts.map +1 -1
  434. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/generationPort.js +38 -8
  435. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/handoffErrors.d.ts +1 -1
  436. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/handoffErrors.d.ts.map +1 -1
  437. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/handoffErrors.js +1 -0
  438. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/handoffRoutes.d.ts.map +1 -1
  439. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/handoffRoutes.js +41 -9
  440. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/index.d.ts +1 -0
  441. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/index.d.ts.map +1 -1
  442. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/index.js +2 -0
  443. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/judgePort.d.ts.map +1 -1
  444. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/judgePort.js +43 -10
  445. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/reCheckRoutes.d.ts.map +1 -1
  446. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/reCheckRoutes.js +3 -1
  447. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/retentionRoutes.d.ts +5 -0
  448. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/retentionRoutes.d.ts.map +1 -0
  449. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/retentionRoutes.js +70 -0
  450. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/reviewRoutes.d.ts.map +1 -1
  451. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/reviewRoutes.js +6 -2
  452. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/reviewStore.d.ts +25 -4
  453. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/reviewStore.d.ts.map +1 -1
  454. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/reviewStore.js +72 -9
  455. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runIngestion.d.ts.map +1 -1
  456. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runIngestion.js +97 -18
  457. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runRegistry.d.ts.map +1 -1
  458. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runRegistry.js +2 -0
  459. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runRoutes.d.ts +4 -1
  460. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runRoutes.d.ts.map +1 -1
  461. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/runRoutes.js +17 -3
  462. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/uiRoutes.d.ts.map +1 -1
  463. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/uiRoutes.js +18 -4
  464. package/node_modules/@oscharko-dev/keiko-server/dist/routes.d.ts.map +1 -1
  465. package/node_modules/@oscharko-dev/keiko-server/dist/routes.js +8 -3
  466. package/node_modules/@oscharko-dev/keiko-server/dist/run-engine.d.ts.map +1 -1
  467. package/node_modules/@oscharko-dev/keiko-server/dist/run-engine.js +6 -1
  468. package/node_modules/@oscharko-dev/keiko-server/dist/store/chats.d.ts +2 -2
  469. package/node_modules/@oscharko-dev/keiko-server/dist/store/chats.d.ts.map +1 -1
  470. package/node_modules/@oscharko-dev/keiko-server/dist/store/chats.js +84 -8
  471. package/node_modules/@oscharko-dev/keiko-server/dist/store/db.d.ts.map +1 -1
  472. package/node_modules/@oscharko-dev/keiko-server/dist/store/db.js +4 -2
  473. package/node_modules/@oscharko-dev/keiko-server/dist/store/index.d.ts +1 -1
  474. package/node_modules/@oscharko-dev/keiko-server/dist/store/index.d.ts.map +1 -1
  475. package/node_modules/@oscharko-dev/keiko-server/dist/store/types.d.ts +5 -1
  476. package/node_modules/@oscharko-dev/keiko-server/dist/store/types.d.ts.map +1 -1
  477. package/node_modules/@oscharko-dev/keiko-server/dist/store-handlers.d.ts.map +1 -1
  478. package/node_modules/@oscharko-dev/keiko-server/dist/store-handlers.js +71 -15
  479. package/node_modules/@oscharko-dev/keiko-server/package.json +2 -2
  480. package/node_modules/@oscharko-dev/keiko-tools/dist/.tsbuildinfo +1 -1
  481. package/node_modules/@oscharko-dev/keiko-tools/package.json +2 -2
  482. package/node_modules/@oscharko-dev/keiko-verification/dist/.tsbuildinfo +1 -1
  483. package/node_modules/@oscharko-dev/keiko-verification/package.json +2 -2
  484. package/node_modules/@oscharko-dev/keiko-workflows/dist/.tsbuildinfo +1 -1
  485. package/node_modules/@oscharko-dev/keiko-workflows/dist/contextpack/assemble.d.ts +2 -0
  486. package/node_modules/@oscharko-dev/keiko-workflows/dist/contextpack/assemble.d.ts.map +1 -1
  487. package/node_modules/@oscharko-dev/keiko-workflows/dist/contextpack/assemble.js +45 -10
  488. package/node_modules/@oscharko-dev/keiko-workflows/dist/contextpack/index.d.ts +1 -1
  489. package/node_modules/@oscharko-dev/keiko-workflows/dist/contextpack/index.d.ts.map +1 -1
  490. package/node_modules/@oscharko-dev/keiko-workflows/dist/contextpack/index.js +1 -1
  491. package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/anchors.d.ts.map +1 -1
  492. package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/anchors.js +68 -0
  493. package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/plan.d.ts.map +1 -1
  494. package/node_modules/@oscharko-dev/keiko-workflows/dist/planner/plan.js +4 -6
  495. package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/__tests__/fixtures/runEntryFixtures.d.ts +30 -0
  496. package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/__tests__/fixtures/runEntryFixtures.d.ts.map +1 -0
  497. package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/__tests__/fixtures/runEntryFixtures.js +114 -0
  498. package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/modelRoutedTestDesign.d.ts.map +1 -1
  499. package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/modelRoutedTestDesign.js +20 -7
  500. package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/runEntries.d.ts.map +1 -1
  501. package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/runEntries.js +15 -7
  502. package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/runtimeCommon.d.ts.map +1 -1
  503. package/node_modules/@oscharko-dev/keiko-workflows/dist/qualityIntelligence/runtimeCommon.js +28 -4
  504. package/node_modules/@oscharko-dev/keiko-workflows/dist/ranking/rank.d.ts.map +1 -1
  505. package/node_modules/@oscharko-dev/keiko-workflows/dist/ranking/rank.js +51 -1
  506. package/node_modules/@oscharko-dev/keiko-workflows/dist/ranking/signals.d.ts.map +1 -1
  507. package/node_modules/@oscharko-dev/keiko-workflows/dist/ranking/signals.js +8 -3
  508. package/node_modules/@oscharko-dev/keiko-workflows/package.json +2 -2
  509. package/node_modules/@oscharko-dev/keiko-workspace/dist/.tsbuildinfo +1 -1
  510. package/node_modules/@oscharko-dev/keiko-workspace/dist/discovery.d.ts.map +1 -1
  511. package/node_modules/@oscharko-dev/keiko-workspace/dist/discovery.js +34 -2
  512. package/node_modules/@oscharko-dev/keiko-workspace/dist/fs.d.ts +1 -0
  513. package/node_modules/@oscharko-dev/keiko-workspace/dist/fs.d.ts.map +1 -1
  514. package/node_modules/@oscharko-dev/keiko-workspace/dist/fs.js +1 -0
  515. package/node_modules/@oscharko-dev/keiko-workspace/dist/gitHistory.d.ts.map +1 -1
  516. package/node_modules/@oscharko-dev/keiko-workspace/dist/gitHistory.js +84 -27
  517. package/node_modules/@oscharko-dev/keiko-workspace/dist/ignore.d.ts.map +1 -1
  518. package/node_modules/@oscharko-dev/keiko-workspace/dist/ignore.js +19 -0
  519. package/node_modules/@oscharko-dev/keiko-workspace/dist/importGraph.d.ts.map +1 -1
  520. package/node_modules/@oscharko-dev/keiko-workspace/dist/importGraph.js +6 -3
  521. package/node_modules/@oscharko-dev/keiko-workspace/dist/realpath.d.ts +1 -0
  522. package/node_modules/@oscharko-dev/keiko-workspace/dist/realpath.d.ts.map +1 -1
  523. package/node_modules/@oscharko-dev/keiko-workspace/dist/realpath.js +2 -2
  524. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearch.d.ts.map +1 -1
  525. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearch.js +72 -25
  526. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchEntries.d.ts +15 -0
  527. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchEntries.d.ts.map +1 -0
  528. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchEntries.js +107 -0
  529. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchLineSelection.d.ts +18 -0
  530. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchLineSelection.d.ts.map +1 -0
  531. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchLineSelection.js +42 -0
  532. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchMatchers.d.ts.map +1 -1
  533. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchMatchers.js +72 -11
  534. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchRegexSafety.d.ts +2 -0
  535. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchRegexSafety.d.ts.map +1 -0
  536. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchRegexSafety.js +15 -0
  537. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchScan.d.ts +2 -2
  538. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchScan.d.ts.map +1 -1
  539. package/node_modules/@oscharko-dev/keiko-workspace/dist/repoSearchScan.js +89 -75
  540. package/node_modules/@oscharko-dev/keiko-workspace/package.json +2 -2
  541. package/node_modules/@types/node/README.md +1 -1
  542. package/node_modules/@types/node/http2.d.ts +1 -0
  543. package/node_modules/@types/node/package.json +2 -2
  544. package/package.json +3 -1
  545. package/dist/ui/static/_next/static/RAzN8WLtYaktD-ZePowXl/_buildManifest.js +0 -1
  546. package/dist/ui/static/_next/static/chunks/18-ac3e3551b4e0ce8a.js +0 -1
  547. package/dist/ui/static/_next/static/chunks/258-e3b5ee46b0669967.js +0 -1
  548. package/dist/ui/static/_next/static/chunks/422-4c94c107b90d3ccc.js +0 -1
  549. package/dist/ui/static/_next/static/chunks/664-6d821dc1aacb6b48.js +0 -1
  550. package/dist/ui/static/_next/static/chunks/87c73c54-24122e7b92478d00.js +0 -1
  551. package/dist/ui/static/_next/static/chunks/982-abc19630e6305864.js +0 -1
  552. package/dist/ui/static/_next/static/chunks/app/_not-found/page-c4d800f366186be0.js +0 -1
  553. package/dist/ui/static/_next/static/chunks/app/launch/page-17ca39367f25f372.js +0 -1
  554. package/dist/ui/static/_next/static/chunks/app/layout-0f75a39edc90325d.js +0 -1
  555. package/dist/ui/static/_next/static/chunks/app/local-knowledge/capsule/page-87a2ea239308ed34.js +0 -1
  556. package/dist/ui/static/_next/static/chunks/app/local-knowledge/page-98bb7704fc7fd0ad.js +0 -1
  557. package/dist/ui/static/_next/static/chunks/app/memoriaviva/consolidation/page-f912263f1ee5d2dd.js +0 -1
  558. package/dist/ui/static/_next/static/chunks/app/memoriaviva/detail/page-fa590f135356e0af.js +0 -1
  559. package/dist/ui/static/_next/static/chunks/app/memoriaviva/page-b8555600c1113f14.js +0 -1
  560. package/dist/ui/static/_next/static/chunks/app/memoriaviva/review-queue/page-85cfbeb3598c0a36.js +0 -1
  561. package/dist/ui/static/_next/static/chunks/app/page-2881856ad25d9935.js +0 -1
  562. package/dist/ui/static/_next/static/chunks/framework-d8f01f7e25201916.js +0 -1
  563. package/dist/ui/static/_next/static/chunks/main-app-5b043f6c611974ae.js +0 -1
  564. package/dist/ui/static/_next/static/chunks/main-bc552b04f2b6dbe2.js +0 -1
  565. package/dist/ui/static/_next/static/chunks/pages/_app-2e239ff05bfdf6d6.js +0 -1
  566. package/dist/ui/static/_next/static/chunks/pages/_error-bda15e7831eec981.js +0 -1
  567. package/dist/ui/static/_next/static/chunks/webpack-0cfe6f51555ca84e.js +0 -1
  568. package/dist/ui/static/_next/static/css/eac94895f3edc5a5.css +0 -1
  569. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/scripted-answer-generator.d.ts +0 -6
  570. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/scripted-answer-generator.d.ts.map +0 -1
  571. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/conversation/scripted-answer-generator.js +0 -49
  572. /package/dist/ui/static/_next/static/chunks/{polyfills-42372ed130431b0a.js → 0cz1d0mv5g_q7.js} +0 -0
  573. /package/dist/ui/static/_next/static/{RAzN8WLtYaktD-ZePowXl → hR2gBQqCDKdPdSxBqZhqv}/_ssgManifest.js +0 -0
@@ -10,20 +10,69 @@
10
10
  // Figma auth header (the ephemeral url is pre-signed), but the seam still forwards whatever
11
11
  // headers the caller supplies so the proxy adapter can add transport headers. The token is
12
12
  // never materialised here and never logged.
13
+ //
14
+ // redirect: "manual" is set so any auth header supplied by the caller cannot follow a
15
+ // cross-origin redirect. A 3xx response surfaces as a non-2xx status; the connector
16
+ // layer treats non-2xx as upstream error.
13
17
  import { classifyFigmaTransportError, FigmaConnectorError } from "./figmaConnectorErrors.js";
14
18
  import { gatewayFetch, } from "@oscharko-dev/keiko-model-gateway/internal/http";
19
+ /** Default request timeout in milliseconds for Figma render downloads. */
20
+ const DEFAULT_TIMEOUT_MS = 60_000;
21
+ /** Default maximum render response body size (32 MiB). */
22
+ const DEFAULT_MAX_RESPONSE_BYTES = 32 * 1024 * 1024;
23
+ /**
24
+ * Read a streaming response body up to `maxBytes`, accumulating into a Uint8Array.
25
+ * Throws a {@link FigmaConnectorError} with `FIGMA_RESPONSE_TOO_LARGE` if the cap is exceeded.
26
+ */
27
+ const readBytesCapped = async (response, maxBytes) => {
28
+ if (response.body === null) {
29
+ const buffer = await response.arrayBuffer();
30
+ return new Uint8Array(buffer);
31
+ }
32
+ const reader = response.body.getReader();
33
+ const chunks = [];
34
+ let total = 0;
35
+ for (;;) {
36
+ const { done, value } = await reader.read();
37
+ if (done)
38
+ break;
39
+ total += value.byteLength;
40
+ if (total > maxBytes) {
41
+ await reader.cancel();
42
+ throw new FigmaConnectorError("FIGMA_RESPONSE_TOO_LARGE");
43
+ }
44
+ chunks.push(value);
45
+ }
46
+ const out = new Uint8Array(total);
47
+ let offset = 0;
48
+ for (const chunk of chunks) {
49
+ out.set(chunk, offset);
50
+ offset += chunk.byteLength;
51
+ }
52
+ return out;
53
+ };
15
54
  /**
16
55
  * Thin default adapter over the platform `fetch`. This is the ONLY place in the render path
17
56
  * `fetch` is named. It forwards the caller-built headers verbatim and reads the body as raw
18
- * bytes; it does not log, retry, or inspect any token. Resilience/backoff is out of scope here
19
- * (#759); the proxy/custom-CA transport is the platform prerequisite (#802) that replaces this.
57
+ * bytes with an explicit byte cap; it does not log, retry, or inspect any token. Resilience/
58
+ * backoff is out of scope here (#759); the proxy/custom-CA transport is the platform
59
+ * prerequisite (#802) that replaces this.
60
+ *
61
+ * `redirect: "manual"` prevents any caller-supplied auth header from following a cross-origin
62
+ * redirect. A 3xx response surfaces as a non-2xx port result; the connector treats it as
63
+ * upstream error.
20
64
  */
21
- export const createDefaultFigmaRenderPort = (egress, fetchImpl) => {
65
+ export const createDefaultFigmaRenderPort = (egress, fetchImpl, options) => {
66
+ const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
67
+ const maxResponseBytes = options?.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
22
68
  return async (request) => {
69
+ const signal = AbortSignal.timeout(timeoutMs);
23
70
  try {
24
71
  const response = await gatewayFetch(request.url, {
25
72
  method: "GET",
26
73
  headers: { ...request.headers },
74
+ redirect: "manual",
75
+ signal,
27
76
  ...(egress !== undefined ? { egress } : {}),
28
77
  ...(fetchImpl !== undefined ? { fetchImpl } : {}),
29
78
  });
@@ -31,8 +80,8 @@ export const createDefaultFigmaRenderPort = (egress, fetchImpl) => {
31
80
  response.headers.forEach((value, name) => {
32
81
  headers[name] = value;
33
82
  });
34
- const buffer = await response.arrayBuffer();
35
- return { status: response.status, bytes: new Uint8Array(buffer), headers };
83
+ const bytes = await readBytesCapped(response, maxResponseBytes);
84
+ return { status: response.status, bytes, headers };
36
85
  }
37
86
  catch (err) {
38
87
  if (err instanceof FigmaConnectorError)
@@ -1 +1 @@
1
- {"version":3,"file":"figmaSnapshotBuilder.d.ts","sourceRoot":"","sources":["../../../src/qualityIntelligence/figma/figmaSnapshotBuilder.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAGV,aAAa,EAEd,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AAWzF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,wBAAwB,CAAC,cAAc,CAAC;IACrD,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,gEAAgE;IAChE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,qEAAqE;IACrE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,wFAAwF;IACxF,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IACxC,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;CAClC;AA+GD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,uBAAuB,KAC7B,OAAO,CAAC,aAAa,CA6BvB,CAAC"}
1
+ {"version":3,"file":"figmaSnapshotBuilder.d.ts","sourceRoot":"","sources":["../../../src/qualityIntelligence/figma/figmaSnapshotBuilder.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAGV,aAAa,EAEd,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AAWzF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,wBAAwB,CAAC,cAAc,CAAC;IACrD,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,gEAAgE;IAChE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,qEAAqE;IACrE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,wFAAwF;IACxF,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IACxC,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;CAClC;AAwLD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,uBAAuB,KAC7B,OAAO,CAAC,aAAa,CA6BvB,CAAC"}
@@ -29,6 +29,37 @@ const chunk = (items, size) => {
29
29
  out.push(items.slice(i, i + size));
30
30
  return out;
31
31
  };
32
+ // Returns true when the hostname is an IP literal or a local/loopback name that must be blocked.
33
+ const isBlockedHostname = (h) => h.length === 0 ||
34
+ /^\d+\.\d+\.\d+\.\d+$/.test(h) ||
35
+ h.startsWith("[") ||
36
+ h === "localhost" ||
37
+ h.endsWith(".localhost") ||
38
+ h.endsWith(".local");
39
+ // Validates that a render URL returned by the Figma API is safe to follow. Blocks http:
40
+ // (plaintext) and IP-literal hostnames (RFC-1918, loopback, link-local) to prevent SSRF via
41
+ // a compromised or MITM'd API response. A broad IP-block is preferred over a tight CDN
42
+ // allowlist because Figma's pre-signed render URLs span multiple AWS S3 regions/CDN fronts.
43
+ const isRenderUrlSafe = (raw) => {
44
+ let url;
45
+ try {
46
+ url = new URL(raw);
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ if (url.protocol !== "https:")
52
+ return false;
53
+ // Normalise: lowercase + strip exactly one trailing dot so "localhost." == "localhost".
54
+ const h = url.hostname.toLowerCase().replace(/\.$/, "");
55
+ if (isBlockedHostname(h))
56
+ return false;
57
+ // Only allow the default HTTPS port (443 or implicit) — non-standard ports indicate an
58
+ // internal service, not a CDN. url.port is "" when the port is the scheme default.
59
+ if (url.port !== "" && url.port !== "443")
60
+ return false;
61
+ return true;
62
+ };
32
63
  const buildImagesUrl = (fileKey, ids, version) => {
33
64
  const url = new URL(`${FIGMA_API_ORIGIN}/v1/images/${encodeURIComponent(fileKey)}`);
34
65
  url.searchParams.set("ids", ids.join(","));
@@ -79,24 +110,65 @@ const requestRenderUrls = async (input, screenIds) => {
79
110
  const skip = (screenId, reason) => ({
80
111
  skipped: { screenId, reason },
81
112
  });
82
- // Downloads one screen's render bytes and classifies the result into a kept screen or a skip. The
83
- // pre-signed byte download is wrapped in the same deterministic 429 backoff; a single screen still
84
- // failing after retries degrades to a skip (partial render), never aborting the whole build.
113
+ // Classifies a finished render download into a skip reason, or null when the bytes are usable.
114
+ const renderSkipReason = (response, maxBytes) => {
115
+ if (response === null)
116
+ return "render-fetch-failed";
117
+ if (response.status < 200 || response.status >= 300)
118
+ return "render-fetch-failed";
119
+ if (response.bytes.length === 0)
120
+ return "render-empty";
121
+ if (response.bytes.length > maxBytes)
122
+ return "render-oversized";
123
+ return null;
124
+ };
125
+ // Hard-egress codes for the render-byte download host (S3/CDN — a DIFFERENT host than
126
+ // api.figma.com). If the render port throws a FigmaConnectorError in this family, it means
127
+ // TLS or proxy is misconfigured for the render CDN; swallowing it would yield a "successful"
128
+ // snapshot with every screen skipped while hiding the root cause. Re-throw to abort the build,
129
+ // consistent with the DEEP_FETCH_ABORT_CODES discipline in figmaScopedPagination.ts.
130
+ // Using ReadonlySet<string> so this set is forward-compatible with the new codes
131
+ // (FIGMA_PROXY_AUTH_REQUIRED, FIGMA_PROXY_BLOCKED_BY_POLICY) landing in a parallel change to
132
+ // figmaConnectorErrors.ts without requiring a re-touch of this file.
133
+ const RENDER_EGRESS_ABORT_CODES = new Set([
134
+ "FIGMA_TLS_CA_FAILURE",
135
+ "FIGMA_PROXY_UNREACHABLE",
136
+ "FIGMA_PROXY_EGRESS_FAILED",
137
+ "FIGMA_PROXY_AUTH_REQUIRED",
138
+ "FIGMA_PROXY_BLOCKED_BY_POLICY",
139
+ ]);
140
+ // Classifies a render-port throw into a re-throw (hard egress abort) or a coded skip outcome.
141
+ // Hard-egress errors abort the whole build — they affect every screen on the same host so
142
+ // swallowing them would silently produce an empty snapshot.
143
+ const classifyRenderError = (screenId, err) => {
144
+ if (err instanceof FigmaConnectorError) {
145
+ if (RENDER_EGRESS_ABORT_CODES.has(err.code))
146
+ throw err;
147
+ return skip(screenId, `render-fetch-failed:${err.code}`);
148
+ }
149
+ return skip(screenId, "render-fetch-failed");
150
+ };
151
+ // Downloads one screen's render bytes and classifies the result into a kept screen or a skip.
152
+ // A single screen failing after retries degrades to a skip (partial render), never aborting.
153
+ // Exception: hard egress errors (TLS/proxy misconfiguration) abort via classifyRenderError.
85
154
  const resolveScreen = async (input, ir, renderUrl) => {
86
155
  if (renderUrl === null)
87
156
  return skip(ir.id, "render-url-missing");
157
+ if (!isRenderUrlSafe(renderUrl))
158
+ return skip(ir.id, "render-url-blocked");
88
159
  const maxBytes = input.maxImageBytes ?? DEFAULT_MAX_IMAGE_BYTES;
89
160
  const policy = input.retryPolicy ?? DEFAULT_FIGMA_RETRY_POLICY;
90
161
  const sleep = input.sleep ?? realFigmaRetrySleep;
91
- const response = await fetchWithBackoff(() => input.renderPort({ url: renderUrl, headers: {} }), policy, sleep).catch(() => null);
92
- if (response === null)
93
- return skip(ir.id, "render-fetch-failed");
94
- if (response.status < 200 || response.status >= 300)
95
- return skip(ir.id, "render-fetch-failed");
96
- if (response.bytes.length === 0)
97
- return skip(ir.id, "render-empty");
98
- if (response.bytes.length > maxBytes)
99
- return skip(ir.id, "render-oversized");
162
+ let response;
163
+ try {
164
+ response = await fetchWithBackoff(() => input.renderPort({ url: renderUrl, headers: {} }), policy, sleep);
165
+ }
166
+ catch (err) {
167
+ return classifyRenderError(ir.id, err);
168
+ }
169
+ const reason = renderSkipReason(response, maxBytes);
170
+ if (reason !== null)
171
+ return skip(ir.id, reason);
100
172
  const sha256 = hashBytes(response.bytes);
101
173
  const screen = {
102
174
  screenId: ir.id,
@@ -1 +1 @@
1
- {"version":3,"file":"figmaSnapshotHash.d.ts","sourceRoot":"","sources":["../../../src/qualityIntelligence/figma/figmaSnapshotHash.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AAEzF,KAAK,QAAQ,GAAG,wBAAwB,CAAC,QAAQ,CAAC;AAyClD,kFAAkF;AAClF,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,EAAE,IAAI,QAAQ,EAAE,aAAa,MAAM,KAAG,MACV,CAAC;AAExE;;;;GAIG;AACH,eAAO,MAAM,YAAY,GACvB,uBAAuB,MAAM,EAC7B,SAAS,MAAM,GAAG,SAAS,EAC3B,WAAW,SAAS;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAAE,EAAE,KAClF,MAKF,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,OAAO,UAAU,KAAG,MACI,CAAC"}
1
+ {"version":3,"file":"figmaSnapshotHash.d.ts","sourceRoot":"","sources":["../../../src/qualityIntelligence/figma/figmaSnapshotHash.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AAEzF,KAAK,QAAQ,GAAG,wBAAwB,CAAC,QAAQ,CAAC;AAwDlD,kFAAkF;AAClF,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,EAAE,IAAI,QAAQ,EAAE,aAAa,MAAM,KAAG,MACV,CAAC;AAExE;;;;GAIG;AACH,eAAO,MAAM,YAAY,GACvB,uBAAuB,MAAM,EAC7B,SAAS,MAAM,GAAG,SAAS,EAC3B,WAAW,SAAS;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAAE,EAAE,KAClF,MAKF,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,OAAO,UAAU,KAAG,MACI,CAAC"}
@@ -23,18 +23,26 @@ const canonical = (value) => {
23
23
  .map((key) => `${JSON.stringify(key)}:${canonical(record[key])}`);
24
24
  return `{${entries.join(",")}}`;
25
25
  };
26
- const stripA11yColors = (node) => {
27
- const projected = {
28
- ...node,
29
- children: node.children.map(stripA11yColors),
26
+ // Keys excluded from the integrity hash. Using a static Set + Object.entries filter avoids both
27
+ // dynamic-delete (no-dynamic-delete) and unused-var issues while keeping the whitelist explicit.
28
+ const HASH_NEUTRAL_KEYS = new Set([
29
+ "textColor",
30
+ "backgroundColor",
31
+ "layout",
32
+ "sizing",
33
+ "cornerRadius",
34
+ "typography",
35
+ ]);
36
+ const stripHashNeutralFields = (node) => {
37
+ const entries = Object.entries(node).filter(([key]) => key !== "children" && !HASH_NEUTRAL_KEYS.has(key));
38
+ return {
39
+ ...Object.fromEntries(entries),
40
+ children: node.children.map(stripHashNeutralFields),
30
41
  };
31
- delete projected.textColor;
32
- delete projected.backgroundColor;
33
- return projected;
34
42
  };
35
43
  const hashStableIr = (ir) => ({
36
44
  ...ir,
37
- root: stripA11yColors(ir.root),
45
+ root: stripHashNeutralFields(ir.root),
38
46
  });
39
47
  /** sha256 over the canonical per-screen identity: {screenId, ir, imageSha256}. */
40
48
  export const hashScreen = (screenId, ir, imageSha256) => sha256Hex(canonical({ imageSha256, ir: hashStableIr(ir), screenId }));
@@ -16,8 +16,12 @@ export interface FigmaSnapshotScreen {
16
16
  /** sha256 over the canonical {screenId, ir, imageSha256} body — the per-screen drift identity. */
17
17
  readonly integrityHash: string;
18
18
  }
19
- /** Why a detected screen produced no render and was excluded from `screens` (partial-render). */
20
- export type FigmaSkippedScreenReason = "render-url-missing" | "render-fetch-failed" | "render-empty" | "render-oversized";
19
+ /** Why a detected screen produced no render and was excluded from `screens` (partial-render).
20
+ * The `render-fetch-failed` member also appears as `render-fetch-failed:<CODE>` when the fetch
21
+ * threw a FigmaConnectorError — the code suffix lets metrics distinguish an egress
22
+ * misconfiguration (e.g. `FIGMA_EGRESS_TIMEOUT`) from an unclassified network flake.
23
+ */
24
+ export type FigmaSkippedScreenReason = "render-url-missing" | "render-url-blocked" | "render-fetch-failed" | `render-fetch-failed:${string}` | "render-empty" | "render-oversized";
21
25
  export interface FigmaSkippedScreen {
22
26
  readonly screenId: string;
23
27
  readonly reason: FigmaSkippedScreenReason;
@@ -1 +1 @@
1
- {"version":3,"file":"figmaSnapshotTypes.d.ts","sourceRoot":"","sources":["../../../src/qualityIntelligence/figma/figmaSnapshotTypes.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,KAAK,QAAQ,GAAG,wBAAwB,CAAC,QAAQ,CAAC;AAElD,+FAA+F;AAC/F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,+DAA+D;AAC/D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,kGAAkG;IAClG,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,iGAAiG;AACjG,MAAM,MAAM,wBAAwB,GAChC,oBAAoB,GACpB,qBAAqB,GACrB,cAAc,GACd,kBAAkB,CAAC;AAEvB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,QAAQ,CAAC,cAAc,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACvD;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,wBAAwB,CAAC,eAAe,EAAE,CAAC;IACrE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC"}
1
+ {"version":3,"file":"figmaSnapshotTypes.d.ts","sourceRoot":"","sources":["../../../src/qualityIntelligence/figma/figmaSnapshotTypes.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,KAAK,QAAQ,GAAG,wBAAwB,CAAC,QAAQ,CAAC;AAElD,+FAA+F;AAC/F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,+DAA+D;AAC/D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,kGAAkG;IAClG,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAChC,oBAAoB,GACpB,oBAAoB,GACpB,qBAAqB,GACrB,uBAAuB,MAAM,EAAE,GAC/B,cAAc,GACd,kBAAkB,CAAC;AAEvB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,QAAQ,CAAC,cAAc,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACvD;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,wBAAwB,CAAC,eAAe,EAAE,CAAC;IACrE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC"}
@@ -2,11 +2,23 @@ import { type FigmaSnapshotRecord } from "@oscharko-dev/keiko-evidence";
2
2
  import type { UiHandlerDeps } from "../deps.js";
3
3
  /** Loads an immutable Figma Snapshot evidence record by runId. Returns `undefined` when not found. */
4
4
  export type FigmaSnapshotLoader = (snapshotRunId: string) => FigmaSnapshotRecord | undefined;
5
+ export interface FigmaSnapshotLoaderOptions {
6
+ /**
7
+ * Drift seam (#735): a figma-snapshot source pins a write-once, content-addressed runId, so its
8
+ * content can never change under its identity — re-checking the pinned record would always
9
+ * report "fresh" even after the board changed and was re-snapshotted. When this flag is set the
10
+ * loader resolves the LATEST snapshot recorded for the same board scope (fileKey + nodeId) and
11
+ * returns it instead of the pinned record whenever its integrity hash differs. Screen atom ids
12
+ * are board-stable (screenId-derived), so compareStaleness sees changed atoms, not orphans.
13
+ * Used by re-check and regenerate-stale ONLY — the generate path keeps exact pinning.
14
+ */
15
+ readonly resolveLatestByScope?: boolean;
16
+ }
5
17
  /**
6
18
  * Build the snapshot loader. Returns `undefined` when `deps.evidenceDir` is not configured so the
7
19
  * ingestion layer maps an attempted figma-snapshot source to QI_FIGMA_SNAPSHOT_UNAVAILABLE.
8
20
  */
9
- export declare function makeFigmaSnapshotLoader(deps: UiHandlerDeps): FigmaSnapshotLoader | undefined;
21
+ export declare function makeFigmaSnapshotLoader(deps: UiHandlerDeps, options?: FigmaSnapshotLoaderOptions): FigmaSnapshotLoader | undefined;
10
22
  /** The image-derived semantics a multimodal model recovered for one screen, as additive hints. */
11
23
  export interface FigmaVisionScreenRequest {
12
24
  readonly screenId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"figmaSnapshotAdapter.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/figmaSnapshotAdapter.ts"],"names":[],"mappings":"AAiBA,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,sGAAsG;AACtG,MAAM,MAAM,mBAAmB,GAAG,CAAC,aAAa,EAAE,MAAM,KAAK,mBAAmB,GAAG,SAAS,CAAC;AAE7F;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,aAAa,GAAG,mBAAmB,GAAG,SAAS,CAY5F;AAED,kGAAkG;AAClG,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uFAAuF;IACvF,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,kGAAkG;IAClG,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,EAAE,wBAAwB,KAAK,SAAS,MAAM,EAAE,CAAC;AAE/F;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAC5B,OAAO,EAAE,wBAAwB,EACjC,OAAO,EAAE,MAAM,KACZ,SAAS,MAAM,EAAE,CAAC;AAOvB;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,aAAa,EACnB,UAAU,CAAC,EAAE,eAAe,GAC3B,uBAAuB,CAazB"}
1
+ {"version":3,"file":"figmaSnapshotAdapter.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/figmaSnapshotAdapter.ts"],"names":[],"mappings":"AAiBA,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,sGAAsG;AACtG,MAAM,MAAM,mBAAmB,GAAG,CAAC,aAAa,EAAE,MAAM,KAAK,mBAAmB,GAAG,SAAS,CAAC;AAE7F,MAAM,WAAW,0BAA0B;IACzC;;;;;;;;OAQG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACzC;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,aAAa,EACnB,OAAO,CAAC,EAAE,0BAA0B,GACnC,mBAAmB,GAAG,SAAS,CA0BjC;AAED,kGAAkG;AAClG,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uFAAuF;IACvF,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,kGAAkG;IAClG,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,EAAE,wBAAwB,KAAK,SAAS,MAAM,EAAE,CAAC;AAE/F;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAC5B,OAAO,EAAE,wBAAwB,EACjC,OAAO,EAAE,MAAM,KACZ,SAAS,MAAM,EAAE,CAAC;AAOvB;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,aAAa,EACnB,UAAU,CAAC,EAAE,eAAe,GAC3B,uBAAuB,CAazB"}
@@ -20,14 +20,27 @@ import { resolveQiMultimodalSelection } from "./modelSelection.js";
20
20
  * Build the snapshot loader. Returns `undefined` when `deps.evidenceDir` is not configured so the
21
21
  * ingestion layer maps an attempted figma-snapshot source to QI_FIGMA_SNAPSHOT_UNAVAILABLE.
22
22
  */
23
- export function makeFigmaSnapshotLoader(deps) {
23
+ export function makeFigmaSnapshotLoader(deps, options) {
24
24
  const evidenceDir = deps.evidenceDir;
25
25
  if (evidenceDir === undefined || evidenceDir.length === 0)
26
26
  return undefined;
27
27
  const store = createNodeFigmaSnapshotStore(evidenceDir);
28
+ const resolveLatest = options?.resolveLatestByScope === true;
28
29
  return (snapshotRunId) => {
29
30
  try {
30
- return store.load(snapshotRunId);
31
+ const pinned = store.load(snapshotRunId);
32
+ if (pinned === undefined || !resolveLatest)
33
+ return pinned;
34
+ const entries = store.listByScope(pinned.provenance.fileKey, pinned.provenance.nodeId);
35
+ const newest = entries[0];
36
+ if (newest === undefined ||
37
+ newest.runId === pinned.runId ||
38
+ newest.integrityHash === pinned.integrityHash) {
39
+ return pinned;
40
+ }
41
+ // Fall back to the pinned record when the newest record fails to load — drift detection
42
+ // must degrade to "fresh", never crash the re-check.
43
+ return store.load(newest.runId) ?? pinned;
31
44
  }
32
45
  catch {
33
46
  // A malformed / unreadable record is treated as "not found"; the caller emits a coded error.
@@ -14,6 +14,15 @@ export interface GovernedSnapshotDeps {
14
14
  readonly pagination?: Partial<ScopedPaginationLimits>;
15
15
  /** Shared enterprise egress settings for Figma API + render downloads (#802). */
16
16
  readonly egress?: OutboundHttpEgressConfig | undefined;
17
+ /**
18
+ * Creation-time overrides forwarded to the default HTTP and render ports when no explicit
19
+ * httpPort/renderPort is injected. Currently only `timeoutMs` (maps to
20
+ * KEIKO_FIGMA_REQUEST_TIMEOUT_MS). Ignored when httpPort/renderPort are injected directly
21
+ * (route tests supply fakes that honour their own timeouts).
22
+ */
23
+ readonly portOptions?: {
24
+ readonly timeoutMs?: number;
25
+ };
17
26
  readonly httpPort?: FigmaHttpPort;
18
27
  readonly renderPort?: FigmaRenderPort;
19
28
  readonly keychainAccess?: FigmaKeychainAccess;
@@ -1 +1 @@
1
- {"version":3,"file":"figmaSnapshotOrchestration.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/figmaSnapshotOrchestration.ts"],"names":[],"mappings":"AAeA,OAAO,EAOL,qBAAqB,EAQrB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iDAAiD,CAAC;AAKhG,KAAK,cAAc,GAAG,wBAAwB,CAAC,cAAc,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,uFAAuF;IACvF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iGAAiG;IACjG,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACtD,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAEvD,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,mBAAmB,CAAC;CAC/C;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;CAClC;AAMD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,oBAAoB,KAAG,MAAM,GAAG,SAWzE,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,kBAAkB,GAC7B,MAAM,IAAI,CAAC,oBAAoB,EAAE,KAAK,GAAG,aAAa,GAAG,gBAAgB,CAAC,KACzE,UAAU,CAAC,OAAO,qBAAqB,CAOzC,CAAC;AAqDF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAChC,WAAW,MAAM,EACjB,MAAM,oBAAoB,EAC1B,sBAAoB,KACnB,OAAO,CAAC,sBAAsB,CAiDhC,CAAC"}
1
+ {"version":3,"file":"figmaSnapshotOrchestration.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/figmaSnapshotOrchestration.ts"],"names":[],"mappings":"AAeA,OAAO,EAOL,qBAAqB,EAQrB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iDAAiD,CAAC;AAKhG,KAAK,cAAc,GAAG,wBAAwB,CAAC,cAAc,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,uFAAuF;IACvF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iGAAiG;IACjG,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACtD,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IACvD;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAEvD,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,mBAAmB,CAAC;CAC/C;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;CAClC;AAMD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,oBAAoB,KAAG,MAAM,GAAG,SAWzE,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,kBAAkB,GAC7B,MAAM,IAAI,CAAC,oBAAoB,EAAE,KAAK,GAAG,aAAa,GAAG,gBAAgB,CAAC,KACzE,UAAU,CAAC,OAAO,qBAAqB,CAOzC,CAAC;AAqDF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAChC,WAAW,MAAM,EACjB,MAAM,oBAAoB,EAC1B,sBAAoB,KACnB,OAAO,CAAC,sBAAsB,CAmDhC,CAAC"}
@@ -91,8 +91,8 @@ export const governedSnapshotBuild = async (boardLink, deps, isResnapshot = fals
91
91
  if (target === null)
92
92
  throw new FigmaConnectorError("FIGMA_MALFORMED_URL");
93
93
  const scopeRef = deriveFigmaScopeRef(target.fileKey, target.nodeId);
94
- const httpPort = deps.httpPort ?? createDefaultFigmaHttpPort(deps.egress);
95
- const renderPort = deps.renderPort ?? createDefaultFigmaRenderPort(deps.egress);
94
+ const httpPort = deps.httpPort ?? createDefaultFigmaHttpPort(deps.egress, undefined, deps.portOptions);
95
+ const renderPort = deps.renderPort ?? createDefaultFigmaRenderPort(deps.egress, undefined, deps.portOptions);
96
96
  const vaultToken = readFigmaVaultToken(deps);
97
97
  gateConsent(deps, scopeRef);
98
98
  // Render-token (vault > config > env). Throws FIGMA_TOKEN_MISSING when nothing is configured.
@@ -51,7 +51,15 @@ export interface FigmaScreenSummary {
51
51
  /** Byte size of the rendered PNG. */
52
52
  readonly imageByteLength: number;
53
53
  }
54
- export declare function handleFigmaTriggerSnapshot(ctx: RouteContext, deps: UiHandlerDeps): Promise<RouteResult>;
54
+ interface CoalescedBuildEntry {
55
+ readonly promise: Promise<RouteResult>;
56
+ }
57
+ /** Injectable for tests — returns the module-level map by default. */
58
+ export declare function makeInFlightMap(): Map<string, CoalescedBuildEntry>;
59
+ /** Reset the module-level coalescing map. Used by tests to ensure isolation. */
60
+ export declare function resetInFlightMap(): void;
61
+ export declare function handleFigmaTriggerSnapshot(ctx: RouteContext, deps: UiHandlerDeps, inFlight?: Map<string, CoalescedBuildEntry>): Promise<RouteResult>;
55
62
  export declare function handleFigmaRevokeToken(ctx: RouteContext, deps: UiHandlerDeps): RouteResult;
56
63
  export declare function handleFigmaLoadSnapshot(ctx: RouteContext, deps: UiHandlerDeps): RouteResult;
64
+ export {};
57
65
  //# sourceMappingURL=figmaSnapshotRoutes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"figmaSnapshotRoutes.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/figmaSnapshotRoutes.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EAOL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EAExB,MAAM,kBAAkB,CAAC;AAgH1B,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,8CAA8C;IAC9C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,2FAA2F;IAC3F,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wFAAwF;IACxF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sDAAsD;IACtD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,kCAAkC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,qCAAqC;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAmMD,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,WAAW,CAAC,CAkCtB;AAID,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,GAAG,WAAW,CA4B1F;AAID,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,GAAG,WAAW,CAwB3F"}
1
+ {"version":3,"file":"figmaSnapshotRoutes.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/figmaSnapshotRoutes.ts"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EAOL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EAExB,MAAM,kBAAkB,CAAC;AAoI1B,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,8CAA8C;IAC9C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,2FAA2F;IAC3F,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wFAAwF;IACxF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sDAAsD;IACtD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,kCAAkC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,qCAAqC;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAgOD,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CACxC;AAMD,sEAAsE;AACtE,wBAAgB,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAElE;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAmED,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,aAAa,EACnB,QAAQ,GAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAsB,GAC9D,OAAO,CAAC,WAAW,CAAC,CAqCtB;AAID,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,GAAG,WAAW,CA4B1F;AAID,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,GAAG,WAAW,CAwB3F"}
@@ -19,6 +19,28 @@
19
19
  //
20
20
  // Both routes honour the existing QI error-envelope convention:
21
21
  // { error: { code: string; message: string } }
22
+ //
23
+ // In-flight coalescing (item 2):
24
+ // Concurrent POSTs for the same scope (fileKey:nodeId) share ONE build promise. The FIRST
25
+ // caller starts the governed build, mints the runId ONCE, persists ONCE (inside the build
26
+ // chain so a deadline-expired-but-completed build still persists and is recoverable via an
27
+ // immediate retry POST). Subsequent callers await the same promise and receive the same
28
+ // runId/response. The entry is removed on settle (finally). Failures propagate to all
29
+ // waiters with the same coded error.
30
+ //
31
+ // Build deadline (item 3):
32
+ // KEIKO_FIGMA_BUILD_DEADLINE_MS (default 600 000 ms). The awaiting handler races the
33
+ // coalesced build promise against a deadline rejection. On deadline the handler responds
34
+ // 504 FIGMA_BUILD_TIMEOUT WITHOUT a runId. The coalesced build itself continues (other
35
+ // waiters may exist); persist is INSIDE the build chain, so if/when the build completes
36
+ // a subsequent POST for the same scope finds the map empty and re-coalesces cheaply.
37
+ // The underlying build is bounded by per-fetch timeouts and pagination budgets.
38
+ //
39
+ // Client disconnect (item 4):
40
+ // The handler listens for the 'close' event on ctx.req. On disconnect the per-waiter
41
+ // race resolves promptly (504 FIGMA_BUILD_TIMEOUT body never sent over the wire).
42
+ // The coalesced build continues — other waiters (if any) are unaffected and will
43
+ // receive the result when the build settles.
22
44
  import { randomUUID } from "node:crypto";
23
45
  import { currentGatewayEgressConfig } from "../deps.js";
24
46
  import { parseFigmaTarget, deriveFigmaScopeRef, observeFigmaRevoke, EXPECTED_FIGMA_SCOPES, FigmaConnectorError, } from "./figma/index.js";
@@ -35,9 +57,16 @@ const FIGMA_ROUTE_ERROR_MESSAGES = {
35
57
  FIGMA_UPSTREAM_UNAVAILABLE: "Figma API is temporarily unavailable. Please try again.",
36
58
  FIGMA_PROXY_EGRESS_FAILED: "The forward proxy rejected the Figma egress request. Check proxy configuration.",
37
59
  FIGMA_PROXY_UNREACHABLE: "The configured forward proxy is unreachable. Check proxy host and port settings.",
60
+ FIGMA_PROXY_AUTH_REQUIRED: "The forward proxy requires authentication. Configure proxy credentials or an allow rule.",
61
+ FIGMA_PROXY_BLOCKED_BY_POLICY: "The forward proxy blocked the Figma egress request. Ask the proxy operator to allow api.figma.com.",
38
62
  FIGMA_TLS_CA_FAILURE: "The Figma egress TLS certificate could not be verified. Check the configured CA bundle.",
39
63
  FIGMA_RATE_LIMITED: "Figma rate-limited the snapshot-build. Please wait a moment and try again.",
40
64
  FIGMA_OVERSIZED_SCOPE: "The selected Figma board section is too large. Select a smaller section (frame or page).",
65
+ FIGMA_RESPONSE_TOO_LARGE: "The Figma API response exceeded the size limit. Select a smaller section.",
66
+ FIGMA_NETWORK_UNREACHABLE: "The outbound request to Figma failed. Check network connectivity and egress policy.",
67
+ FIGMA_EGRESS_TIMEOUT: "The Figma request timed out. Retry or raise KEIKO_FIGMA_REQUEST_TIMEOUT_MS.",
68
+ FIGMA_EGRESS_FAILED: "The outbound request to Figma failed before a response was received.",
69
+ FIGMA_BUILD_TIMEOUT: "The snapshot build exceeded the configured deadline. No partial snapshot was stored.",
41
70
  FIGMA_INTERNAL: "An unexpected error occurred during the snapshot-build.",
42
71
  FIGMA_BAD_LINK: "The board link is not a valid Figma URL, or it is missing a node-id " +
43
72
  "(section/frame anchor required).",
@@ -55,7 +84,7 @@ function figmaErrorBody(code) {
55
84
  // board reference — only the static scope strings.
56
85
  return code === "FIGMA_CONSENT_REQUIRED" ? { ...base, scopes: EXPECTED_FIGMA_SCOPES } : base;
57
86
  }
58
- // Codes that map to 502 (upstream/auth problems, not client errors).
87
+ // Codes that map to 502 (upstream/auth/egress problems, not client errors).
59
88
  const FIGMA_502_CODES = new Set([
60
89
  "FIGMA_TOKEN_MISSING",
61
90
  "FIGMA_TOKEN_INVALID",
@@ -64,8 +93,14 @@ const FIGMA_502_CODES = new Set([
64
93
  "FIGMA_INSUFFICIENT_SCOPE",
65
94
  "FIGMA_PROXY_EGRESS_FAILED",
66
95
  "FIGMA_PROXY_UNREACHABLE",
96
+ "FIGMA_PROXY_AUTH_REQUIRED",
97
+ "FIGMA_PROXY_BLOCKED_BY_POLICY",
67
98
  "FIGMA_TLS_CA_FAILURE",
68
99
  "FIGMA_UPSTREAM_UNAVAILABLE",
100
+ "FIGMA_NETWORK_UNREACHABLE",
101
+ "FIGMA_EGRESS_TIMEOUT",
102
+ "FIGMA_EGRESS_FAILED",
103
+ "FIGMA_RESPONSE_TOO_LARGE",
69
104
  ]);
70
105
  function figmaStatusForCode(code) {
71
106
  if (FIGMA_502_CODES.has(code))
@@ -79,6 +114,8 @@ function figmaStatusForCode(code) {
79
114
  // Precondition Required: the operator must acknowledge the read-only scope before the build (#760).
80
115
  if (code === "FIGMA_CONSENT_REQUIRED")
81
116
  return 428;
117
+ if (code === "FIGMA_BUILD_TIMEOUT")
118
+ return 504;
82
119
  return 500;
83
120
  }
84
121
  // ─── Body reader ───────────────────────────────────────────────────────────────
@@ -245,6 +282,25 @@ function figmaPaginationFromEnv(env) {
245
282
  apply("fetchConcurrency", "KEIKO_FIGMA_FETCH_CONCURRENCY");
246
283
  return overrides;
247
284
  }
285
+ /** Default total snapshot-build deadline in milliseconds (10 minutes). */
286
+ const DEFAULT_BUILD_DEADLINE_MS = 600_000;
287
+ /** Default per-fetch request timeout in milliseconds (1 minute). */
288
+ const DEFAULT_REQUEST_TIMEOUT_MS = 60_000;
289
+ // Parses a positive-integer env var, returning the default when the value is absent or invalid.
290
+ function readPositiveIntEnv(raw, defaultValue) {
291
+ if (raw === undefined)
292
+ return defaultValue;
293
+ const value = Number(raw);
294
+ return Number.isInteger(value) && value > 0 ? value : defaultValue;
295
+ }
296
+ /** KEIKO_FIGMA_BUILD_DEADLINE_MS — total build deadline used by the coalesced promise race. */
297
+ function figmaBuildDeadlineMsFromEnv(env) {
298
+ return readPositiveIntEnv(env.KEIKO_FIGMA_BUILD_DEADLINE_MS, DEFAULT_BUILD_DEADLINE_MS);
299
+ }
300
+ /** KEIKO_FIGMA_REQUEST_TIMEOUT_MS — per-fetch timeout threaded into the transport ports. */
301
+ function figmaRequestTimeoutMsFromEnv(env) {
302
+ return readPositiveIntEnv(env.KEIKO_FIGMA_REQUEST_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS);
303
+ }
248
304
  // Map a thrown error from the governed build to a coded route result: a coded connector error maps to
249
305
  // its status (consent-required → 428, auth → 502, rate-limit → 429, …); anything else is a safe 500.
250
306
  function figmaErrorResult(err) {
@@ -287,8 +343,69 @@ function persistSnapshot(evidenceDir, runId, result) {
287
343
  return { status: 500, body: figmaErrorBody("FIGMA_INTERNAL") };
288
344
  return record;
289
345
  }
346
+ // The map is module-level so it is shared across concurrent requests on the same server instance.
347
+ // It is exposed via makeInFlightMap so tests can inject a fresh map (isolation without mocking).
348
+ let defaultInFlightMap = new Map();
349
+ /** Injectable for tests — returns the module-level map by default. */
350
+ export function makeInFlightMap() {
351
+ return defaultInFlightMap;
352
+ }
353
+ /** Reset the module-level coalescing map. Used by tests to ensure isolation. */
354
+ export function resetInFlightMap() {
355
+ defaultInFlightMap = new Map();
356
+ }
357
+ /** Derive the scope key (fileKey:nodeId) for the in-flight map. */
358
+ function scopeKeyFor(boardLink) {
359
+ const target = parseFigmaTarget(boardLink);
360
+ if (target === null)
361
+ return undefined;
362
+ return `${target.fileKey}:${target.nodeId}`;
363
+ }
364
+ // Starts the governed build + persist and removes the map entry on settle.
365
+ // Persist is INSIDE this chain: if a caller's deadline fires but the build later completes,
366
+ // the record is stored and an immediate retry POST coalesces or finds it via the GET route.
367
+ function startCoalescedBuild(scopeKey, inFlight, boardLink, body, evidenceDir, deps) {
368
+ const buildAndPersist = async () => {
369
+ let result;
370
+ try {
371
+ // The governed build resolves the vault>config>env PAT (#758), gates on recorded read-only
372
+ // consent before any egress + audits the action + computes metrics (#760), and deep-fetches +
373
+ // renders within the snapshot boundary (#837/#759). Errors (incl. consent-required) are coded.
374
+ result = await governedSnapshotBuild(boardLink, {
375
+ evidenceDir,
376
+ env: deps.env,
377
+ now: new Date().toISOString(),
378
+ acknowledgeReadOnly: body.acknowledgeReadOnly,
379
+ pagination: figmaPaginationFromEnv(deps.env),
380
+ egress: currentGatewayEgressConfig(deps),
381
+ portOptions: { timeoutMs: figmaRequestTimeoutMsFromEnv(deps.env) },
382
+ }, body.isResnapshot);
383
+ }
384
+ catch (err) {
385
+ return figmaErrorResult(err);
386
+ }
387
+ const runId = `fs-${randomUUID()}`;
388
+ const stored = persistSnapshot(evidenceDir, runId, result);
389
+ if ("status" in stored)
390
+ return stored;
391
+ return { status: 201, body: recordToSummary(stored, result.coverage, result.metrics) };
392
+ };
393
+ const promise = buildAndPersist().finally(() => {
394
+ inFlight.delete(scopeKey);
395
+ });
396
+ inFlight.set(scopeKey, { promise });
397
+ return promise;
398
+ }
399
+ // Returns a promise that rejects with a FIGMA_BUILD_TIMEOUT error after `ms` milliseconds.
400
+ function deadlineRejection(ms) {
401
+ return new Promise((_resolve, reject) => {
402
+ setTimeout(() => {
403
+ reject(new FigmaConnectorError("FIGMA_BUILD_TIMEOUT"));
404
+ }, ms);
405
+ });
406
+ }
290
407
  // ─── POST /api/figma/snapshots ─────────────────────────────────────────────────
291
- export async function handleFigmaTriggerSnapshot(ctx, deps) {
408
+ export async function handleFigmaTriggerSnapshot(ctx, deps, inFlight = defaultInFlightMap) {
292
409
  const evidenceDir = deps.evidenceDir;
293
410
  if (evidenceDir === undefined || evidenceDir.length === 0) {
294
411
  return { status: 503, body: figmaErrorBody("FIGMA_NO_EVIDENCE_DIR") };
@@ -297,28 +414,30 @@ export async function handleFigmaTriggerSnapshot(ctx, deps) {
297
414
  if ("status" in bodyResult)
298
415
  return bodyResult;
299
416
  const body = bodyResult;
300
- let result;
417
+ const scopeKey = scopeKeyFor(body.boardLink);
418
+ if (scopeKey === undefined) {
419
+ // parseTriggerBody already validates the board link; this is a belt-and-suspenders guard.
420
+ return { status: 400, body: figmaErrorBody("FIGMA_BAD_LINK") };
421
+ }
422
+ // Coalesce: join an existing build for this scope, or start a new one.
423
+ const existing = inFlight.get(scopeKey);
424
+ const buildPromise = existing !== undefined
425
+ ? existing.promise
426
+ : startCoalescedBuild(scopeKey, inFlight, body.boardLink, body, evidenceDir, deps);
427
+ const deadlineMs = figmaBuildDeadlineMsFromEnv(deps.env);
428
+ // Per-waiter race: deadline + client-disconnect both resolve this waiter promptly while the
429
+ // coalesced build (and its persist) continues uninterrupted for other waiters.
430
+ const disconnectPromise = new Promise((_resolve, reject) => {
431
+ ctx.req.once("close", () => {
432
+ reject(new FigmaConnectorError("FIGMA_BUILD_TIMEOUT"));
433
+ });
434
+ });
301
435
  try {
302
- // The governed build resolves the vault>config>env PAT (#758), gates on recorded read-only
303
- // consent before any egress + audits the action + computes metrics (#760), and deep-fetches +
304
- // renders within the snapshot boundary (#837/#759). Errors (incl. consent-required) are coded.
305
- result = await governedSnapshotBuild(body.boardLink, {
306
- evidenceDir,
307
- env: deps.env,
308
- now: new Date().toISOString(),
309
- acknowledgeReadOnly: body.acknowledgeReadOnly,
310
- pagination: figmaPaginationFromEnv(deps.env),
311
- egress: currentGatewayEgressConfig(deps),
312
- }, body.isResnapshot);
436
+ return await Promise.race([buildPromise, deadlineRejection(deadlineMs), disconnectPromise]);
313
437
  }
314
438
  catch (err) {
315
439
  return figmaErrorResult(err);
316
440
  }
317
- const runId = `fs-${randomUUID()}`;
318
- const stored = persistSnapshot(evidenceDir, runId, result);
319
- if ("status" in stored)
320
- return stored;
321
- return { status: 201, body: recordToSummary(stored, result.coverage, result.metrics) };
322
441
  }
323
442
  // ─── DELETE /api/figma/token — revoke the stored PAT (#758 rotation/revocation, #760 audit) ───
324
443
  export function handleFigmaRevokeToken(ctx, deps) {