@oscharko-dev/keiko-server 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/assistant-response.d.ts +6 -0
  3. package/dist/assistant-response.d.ts.map +1 -0
  4. package/dist/assistant-response.js +12 -0
  5. package/dist/browser.d.ts +11 -0
  6. package/dist/browser.d.ts.map +1 -0
  7. package/dist/browser.js +245 -0
  8. package/dist/chat-handlers.d.ts +48 -0
  9. package/dist/chat-handlers.d.ts.map +1 -0
  10. package/dist/chat-handlers.js +821 -0
  11. package/dist/chat-stream-handlers.d.ts +4 -0
  12. package/dist/chat-stream-handlers.d.ts.map +1 -0
  13. package/dist/chat-stream-handlers.js +136 -0
  14. package/dist/conversation-prompt.d.ts +8 -0
  15. package/dist/conversation-prompt.d.ts.map +1 -0
  16. package/dist/conversation-prompt.js +36 -0
  17. package/dist/conversation-validation.d.ts +26 -0
  18. package/dist/conversation-validation.d.ts.map +1 -0
  19. package/dist/conversation-validation.js +125 -0
  20. package/dist/credentialPersistence.d.ts +23 -0
  21. package/dist/credentialPersistence.d.ts.map +1 -0
  22. package/dist/credentialPersistence.js +93 -0
  23. package/dist/credentialVault.d.ts +30 -0
  24. package/dist/credentialVault.d.ts.map +1 -0
  25. package/dist/credentialVault.js +206 -0
  26. package/dist/csp.d.ts +3 -0
  27. package/dist/csp.d.ts.map +1 -0
  28. package/dist/csp.js +75 -0
  29. package/dist/deps.d.ts +78 -0
  30. package/dist/deps.d.ts.map +1 -0
  31. package/dist/deps.js +457 -0
  32. package/dist/editor/agentRoutes.d.ts +7 -0
  33. package/dist/editor/agentRoutes.d.ts.map +1 -0
  34. package/dist/editor/agentRoutes.js +197 -0
  35. package/dist/editor/assuredGateRunner.d.ts +36 -0
  36. package/dist/editor/assuredGateRunner.d.ts.map +1 -0
  37. package/dist/editor/assuredGateRunner.js +100 -0
  38. package/dist/editor/assuredPreFilter.d.ts +34 -0
  39. package/dist/editor/assuredPreFilter.d.ts.map +1 -0
  40. package/dist/editor/assuredPreFilter.js +134 -0
  41. package/dist/editor/assuredPreFilterRunner.d.ts +31 -0
  42. package/dist/editor/assuredPreFilterRunner.d.ts.map +1 -0
  43. package/dist/editor/assuredPreFilterRunner.js +312 -0
  44. package/dist/editor/builtinLanguageProviders.d.ts +6 -0
  45. package/dist/editor/builtinLanguageProviders.d.ts.map +1 -0
  46. package/dist/editor/builtinLanguageProviders.js +221 -0
  47. package/dist/editor/codingContext.d.ts +12 -0
  48. package/dist/editor/codingContext.d.ts.map +1 -0
  49. package/dist/editor/codingContext.js +121 -0
  50. package/dist/editor/codingContextEvidence.d.ts +7 -0
  51. package/dist/editor/codingContextEvidence.d.ts.map +1 -0
  52. package/dist/editor/codingContextEvidence.js +52 -0
  53. package/dist/editor/codingContextProviders.d.ts +36 -0
  54. package/dist/editor/codingContextProviders.d.ts.map +1 -0
  55. package/dist/editor/codingContextProviders.js +348 -0
  56. package/dist/editor/completionModelEvidence.d.ts +16 -0
  57. package/dist/editor/completionModelEvidence.d.ts.map +1 -0
  58. package/dist/editor/completionModelEvidence.js +50 -0
  59. package/dist/editor/completionRoutes.d.ts +37 -0
  60. package/dist/editor/completionRoutes.d.ts.map +1 -0
  61. package/dist/editor/completionRoutes.js +411 -0
  62. package/dist/editor/contextRoutes.d.ts +6 -0
  63. package/dist/editor/contextRoutes.d.ts.map +1 -0
  64. package/dist/editor/contextRoutes.js +411 -0
  65. package/dist/editor/disposableAssuredExecution.d.ts +22 -0
  66. package/dist/editor/disposableAssuredExecution.d.ts.map +1 -0
  67. package/dist/editor/disposableAssuredExecution.js +57 -0
  68. package/dist/editor/editorCompletionModel.d.ts +47 -0
  69. package/dist/editor/editorCompletionModel.d.ts.map +1 -0
  70. package/dist/editor/editorCompletionModel.js +156 -0
  71. package/dist/editor/editorInlineCompletionModel.d.ts +34 -0
  72. package/dist/editor/editorInlineCompletionModel.d.ts.map +1 -0
  73. package/dist/editor/editorInlineCompletionModel.js +112 -0
  74. package/dist/editor/editorModelTokenBudget.d.ts +46 -0
  75. package/dist/editor/editorModelTokenBudget.d.ts.map +1 -0
  76. package/dist/editor/editorModelTokenBudget.js +121 -0
  77. package/dist/editor/inlineCompletionRateLimiter.d.ts +19 -0
  78. package/dist/editor/inlineCompletionRateLimiter.d.ts.map +1 -0
  79. package/dist/editor/inlineCompletionRateLimiter.js +46 -0
  80. package/dist/editor/inlineCompletionRoutes.d.ts +26 -0
  81. package/dist/editor/inlineCompletionRoutes.d.ts.map +1 -0
  82. package/dist/editor/inlineCompletionRoutes.js +404 -0
  83. package/dist/editor/inlineCompletionTelemetryEvidence.d.ts +5 -0
  84. package/dist/editor/inlineCompletionTelemetryEvidence.d.ts.map +1 -0
  85. package/dist/editor/inlineCompletionTelemetryEvidence.js +42 -0
  86. package/dist/editor/languageCancellation.d.ts +19 -0
  87. package/dist/editor/languageCancellation.d.ts.map +1 -0
  88. package/dist/editor/languageCancellation.js +48 -0
  89. package/dist/editor/languageProvider.d.ts +39 -0
  90. package/dist/editor/languageProvider.d.ts.map +1 -0
  91. package/dist/editor/languageProvider.js +11 -0
  92. package/dist/editor/languageRoutes.d.ts +15 -0
  93. package/dist/editor/languageRoutes.d.ts.map +1 -0
  94. package/dist/editor/languageRoutes.js +106 -0
  95. package/dist/editor/languageSanitize.d.ts +8 -0
  96. package/dist/editor/languageSanitize.d.ts.map +1 -0
  97. package/dist/editor/languageSanitize.js +101 -0
  98. package/dist/editor/languageService.d.ts +36 -0
  99. package/dist/editor/languageService.d.ts.map +1 -0
  100. package/dist/editor/languageService.js +93 -0
  101. package/dist/editor/languageServiceHost.d.ts +14 -0
  102. package/dist/editor/languageServiceHost.d.ts.map +1 -0
  103. package/dist/editor/languageServiceHost.js +242 -0
  104. package/dist/editor/localKnowledgeRetrieval.d.ts +21 -0
  105. package/dist/editor/localKnowledgeRetrieval.d.ts.map +1 -0
  106. package/dist/editor/localKnowledgeRetrieval.js +44 -0
  107. package/dist/editor/patchApplyEvidence.d.ts +21 -0
  108. package/dist/editor/patchApplyEvidence.d.ts.map +1 -0
  109. package/dist/editor/patchApplyEvidence.js +87 -0
  110. package/dist/editor/patchApplyRoutes.d.ts +16 -0
  111. package/dist/editor/patchApplyRoutes.d.ts.map +1 -0
  112. package/dist/editor/patchApplyRoutes.js +307 -0
  113. package/dist/editor/postApplyVerification.d.ts +42 -0
  114. package/dist/editor/postApplyVerification.d.ts.map +1 -0
  115. package/dist/editor/postApplyVerification.js +177 -0
  116. package/dist/editor/testGenerationEvidence.d.ts +6 -0
  117. package/dist/editor/testGenerationEvidence.d.ts.map +1 -0
  118. package/dist/editor/testGenerationEvidence.js +72 -0
  119. package/dist/editor/testGenerationPatch.d.ts +10 -0
  120. package/dist/editor/testGenerationPatch.d.ts.map +1 -0
  121. package/dist/editor/testGenerationPatch.js +66 -0
  122. package/dist/editor/testGenerationRoutes.d.ts +21 -0
  123. package/dist/editor/testGenerationRoutes.d.ts.map +1 -0
  124. package/dist/editor/testGenerationRoutes.js +254 -0
  125. package/dist/editor/testGenerationRunner.d.ts +23 -0
  126. package/dist/editor/testGenerationRunner.d.ts.map +1 -0
  127. package/dist/editor/testGenerationRunner.js +120 -0
  128. package/dist/editor/textOffsets.d.ts +6 -0
  129. package/dist/editor/textOffsets.d.ts.map +1 -0
  130. package/dist/editor/textOffsets.js +82 -0
  131. package/dist/editor/typescriptLanguageProvider.d.ts +3 -0
  132. package/dist/editor/typescriptLanguageProvider.d.ts.map +1 -0
  133. package/dist/editor/typescriptLanguageProvider.js +217 -0
  134. package/dist/evidence.d.ts +28 -0
  135. package/dist/evidence.d.ts.map +1 -0
  136. package/dist/evidence.js +145 -0
  137. package/dist/files-deny.d.ts +3 -0
  138. package/dist/files-deny.d.ts.map +1 -0
  139. package/dist/files-deny.js +12 -0
  140. package/dist/files.d.ts +97 -0
  141. package/dist/files.d.ts.map +1 -0
  142. package/dist/files.js +733 -0
  143. package/dist/gateway-setup.d.ts +10 -0
  144. package/dist/gateway-setup.d.ts.map +1 -0
  145. package/dist/gateway-setup.js +896 -0
  146. package/dist/governed-workflow.d.ts +17 -0
  147. package/dist/governed-workflow.d.ts.map +1 -0
  148. package/dist/governed-workflow.js +147 -0
  149. package/dist/grounded-answer.d.ts +12 -0
  150. package/dist/grounded-answer.d.ts.map +1 -0
  151. package/dist/grounded-answer.js +69 -0
  152. package/dist/grounded-context-index.d.ts +25 -0
  153. package/dist/grounded-context-index.d.ts.map +1 -0
  154. package/dist/grounded-context-index.js +169 -0
  155. package/dist/grounded-document-evidence.d.ts +28 -0
  156. package/dist/grounded-document-evidence.d.ts.map +1 -0
  157. package/dist/grounded-document-evidence.js +430 -0
  158. package/dist/grounded-handoff.d.ts +4 -0
  159. package/dist/grounded-handoff.d.ts.map +1 -0
  160. package/dist/grounded-handoff.js +445 -0
  161. package/dist/grounded-orchestrator.d.ts +43 -0
  162. package/dist/grounded-orchestrator.d.ts.map +1 -0
  163. package/dist/grounded-orchestrator.js +1445 -0
  164. package/dist/grounded-prompt.d.ts +2 -0
  165. package/dist/grounded-prompt.d.ts.map +1 -0
  166. package/dist/grounded-prompt.js +17 -0
  167. package/dist/grounded-qa-hybrid.d.ts +36 -0
  168. package/dist/grounded-qa-hybrid.d.ts.map +1 -0
  169. package/dist/grounded-qa-hybrid.js +762 -0
  170. package/dist/grounded-qa-multi-source.d.ts +38 -0
  171. package/dist/grounded-qa-multi-source.d.ts.map +1 -0
  172. package/dist/grounded-qa-multi-source.js +461 -0
  173. package/dist/grounded-qa.d.ts +45 -0
  174. package/dist/grounded-qa.d.ts.map +1 -0
  175. package/dist/grounded-qa.js +877 -0
  176. package/dist/grounded-rerank.d.ts +26 -0
  177. package/dist/grounded-rerank.d.ts.map +1 -0
  178. package/dist/grounded-rerank.js +72 -0
  179. package/dist/grounded-turn-registry.d.ts +23 -0
  180. package/dist/grounded-turn-registry.d.ts.map +1 -0
  181. package/dist/grounded-turn-registry.js +102 -0
  182. package/dist/headers.d.ts +3 -0
  183. package/dist/headers.d.ts.map +1 -0
  184. package/dist/headers.js +22 -0
  185. package/dist/host-check.d.ts +3 -0
  186. package/dist/host-check.d.ts.map +1 -0
  187. package/dist/host-check.js +58 -0
  188. package/dist/index.d.ts +26 -0
  189. package/dist/index.d.ts.map +1 -0
  190. package/dist/index.js +33 -0
  191. package/dist/load-csp.d.ts +3 -0
  192. package/dist/load-csp.d.ts.map +1 -0
  193. package/dist/load-csp.js +100 -0
  194. package/dist/local-knowledge-grounded-qa.d.ts +42 -0
  195. package/dist/local-knowledge-grounded-qa.d.ts.map +1 -0
  196. package/dist/local-knowledge-grounded-qa.js +678 -0
  197. package/dist/local-knowledge-handlers.d.ts +24 -0
  198. package/dist/local-knowledge-handlers.d.ts.map +1 -0
  199. package/dist/local-knowledge-handlers.js +1285 -0
  200. package/dist/local-knowledge-indexing-registry.d.ts +13 -0
  201. package/dist/local-knowledge-indexing-registry.d.ts.map +1 -0
  202. package/dist/local-knowledge-indexing-registry.js +53 -0
  203. package/dist/localKnowledgeKeyProvider.d.ts +11 -0
  204. package/dist/localKnowledgeKeyProvider.d.ts.map +1 -0
  205. package/dist/localKnowledgeKeyProvider.js +48 -0
  206. package/dist/memory-audit-event-builders.d.ts +21 -0
  207. package/dist/memory-audit-event-builders.d.ts.map +1 -0
  208. package/dist/memory-audit-event-builders.js +187 -0
  209. package/dist/memory-audit-handler.d.ts +23 -0
  210. package/dist/memory-audit-handler.d.ts.map +1 -0
  211. package/dist/memory-audit-handler.js +191 -0
  212. package/dist/memory-capture-policy.d.ts +10 -0
  213. package/dist/memory-capture-policy.d.ts.map +1 -0
  214. package/dist/memory-capture-policy.js +44 -0
  215. package/dist/memory-consolidation-handlers.d.ts +6 -0
  216. package/dist/memory-consolidation-handlers.d.ts.map +1 -0
  217. package/dist/memory-consolidation-handlers.js +491 -0
  218. package/dist/memory-consolidation-registry.d.ts +47 -0
  219. package/dist/memory-consolidation-registry.d.ts.map +1 -0
  220. package/dist/memory-consolidation-registry.js +106 -0
  221. package/dist/memory-conv-handlers.d.ts +8 -0
  222. package/dist/memory-conv-handlers.d.ts.map +1 -0
  223. package/dist/memory-conv-handlers.js +369 -0
  224. package/dist/memory-conversation-context.d.ts +13 -0
  225. package/dist/memory-conversation-context.d.ts.map +1 -0
  226. package/dist/memory-conversation-context.js +22 -0
  227. package/dist/memory-diagnostics.d.ts +29 -0
  228. package/dist/memory-diagnostics.d.ts.map +1 -0
  229. package/dist/memory-diagnostics.js +122 -0
  230. package/dist/memory-embedding.d.ts +21 -0
  231. package/dist/memory-embedding.d.ts.map +1 -0
  232. package/dist/memory-embedding.js +264 -0
  233. package/dist/memory-handlers.d.ts +19 -0
  234. package/dist/memory-handlers.d.ts.map +1 -0
  235. package/dist/memory-handlers.js +1204 -0
  236. package/dist/memory-maintenance-handlers.d.ts +35 -0
  237. package/dist/memory-maintenance-handlers.d.ts.map +1 -0
  238. package/dist/memory-maintenance-handlers.js +219 -0
  239. package/dist/memory-record-builders.d.ts +4 -0
  240. package/dist/memory-record-builders.d.ts.map +1 -0
  241. package/dist/memory-record-builders.js +19 -0
  242. package/dist/memory-retention.d.ts +31 -0
  243. package/dist/memory-retention.d.ts.map +1 -0
  244. package/dist/memory-retention.js +151 -0
  245. package/dist/memory-retrieval-signals.d.ts +12 -0
  246. package/dist/memory-retrieval-signals.d.ts.map +1 -0
  247. package/dist/memory-retrieval-signals.js +100 -0
  248. package/dist/memory-salience.d.ts +12 -0
  249. package/dist/memory-salience.d.ts.map +1 -0
  250. package/dist/memory-salience.js +154 -0
  251. package/dist/memory-scope-sanitizer.d.ts +6 -0
  252. package/dist/memory-scope-sanitizer.d.ts.map +1 -0
  253. package/dist/memory-scope-sanitizer.js +106 -0
  254. package/dist/memory-target-resolver.d.ts +4 -0
  255. package/dist/memory-target-resolver.d.ts.map +1 -0
  256. package/dist/memory-target-resolver.js +73 -0
  257. package/dist/memory-workflow-port.d.ts +14 -0
  258. package/dist/memory-workflow-port.d.ts.map +1 -0
  259. package/dist/memory-workflow-port.js +186 -0
  260. package/dist/private-json.d.ts +3 -0
  261. package/dist/private-json.d.ts.map +1 -0
  262. package/dist/private-json.js +62 -0
  263. package/dist/promptEnhancer/index.d.ts +3 -0
  264. package/dist/promptEnhancer/index.d.ts.map +1 -0
  265. package/dist/promptEnhancer/index.js +5 -0
  266. package/dist/promptEnhancer/orchestrate.d.ts +2 -0
  267. package/dist/promptEnhancer/orchestrate.d.ts.map +1 -0
  268. package/dist/promptEnhancer/orchestrate.js +5 -0
  269. package/dist/promptEnhancer/routes.d.ts +9 -0
  270. package/dist/promptEnhancer/routes.d.ts.map +1 -0
  271. package/dist/promptEnhancer/routes.js +205 -0
  272. package/dist/qualityIntelligence/capsuleAdapter.d.ts +27 -0
  273. package/dist/qualityIntelligence/capsuleAdapter.d.ts.map +1 -0
  274. package/dist/qualityIntelligence/capsuleAdapter.js +57 -0
  275. package/dist/qualityIntelligence/connectorAuthorization.d.ts +22 -0
  276. package/dist/qualityIntelligence/connectorAuthorization.d.ts.map +1 -0
  277. package/dist/qualityIntelligence/connectorAuthorization.js +35 -0
  278. package/dist/qualityIntelligence/connectorErrors.d.ts +16 -0
  279. package/dist/qualityIntelligence/connectorErrors.d.ts.map +1 -0
  280. package/dist/qualityIntelligence/connectorErrors.js +56 -0
  281. package/dist/qualityIntelligence/connectorRoutes.d.ts +7 -0
  282. package/dist/qualityIntelligence/connectorRoutes.d.ts.map +1 -0
  283. package/dist/qualityIntelligence/connectorRoutes.js +167 -0
  284. package/dist/qualityIntelligence/editRoutes.d.ts +5 -0
  285. package/dist/qualityIntelligence/editRoutes.d.ts.map +1 -0
  286. package/dist/qualityIntelligence/editRoutes.js +293 -0
  287. package/dist/qualityIntelligence/exportAssembly.d.ts +22 -0
  288. package/dist/qualityIntelligence/exportAssembly.d.ts.map +1 -0
  289. package/dist/qualityIntelligence/exportAssembly.js +352 -0
  290. package/dist/qualityIntelligence/exportRoutes.d.ts +5 -0
  291. package/dist/qualityIntelligence/exportRoutes.d.ts.map +1 -0
  292. package/dist/qualityIntelligence/exportRoutes.js +320 -0
  293. package/dist/qualityIntelligence/figma/figmaConcurrency.d.ts +8 -0
  294. package/dist/qualityIntelligence/figma/figmaConcurrency.d.ts.map +1 -0
  295. package/dist/qualityIntelligence/figma/figmaConcurrency.js +34 -0
  296. package/dist/qualityIntelligence/figma/figmaConnector.d.ts +65 -0
  297. package/dist/qualityIntelligence/figma/figmaConnector.d.ts.map +1 -0
  298. package/dist/qualityIntelligence/figma/figmaConnector.js +184 -0
  299. package/dist/qualityIntelligence/figma/figmaConnectorAudit.d.ts +52 -0
  300. package/dist/qualityIntelligence/figma/figmaConnectorAudit.d.ts.map +1 -0
  301. package/dist/qualityIntelligence/figma/figmaConnectorAudit.js +63 -0
  302. package/dist/qualityIntelligence/figma/figmaConnectorErrors.d.ts +31 -0
  303. package/dist/qualityIntelligence/figma/figmaConnectorErrors.d.ts.map +1 -0
  304. package/dist/qualityIntelligence/figma/figmaConnectorErrors.js +220 -0
  305. package/dist/qualityIntelligence/figma/figmaConnectorMetrics.d.ts +44 -0
  306. package/dist/qualityIntelligence/figma/figmaConnectorMetrics.d.ts.map +1 -0
  307. package/dist/qualityIntelligence/figma/figmaConnectorMetrics.js +49 -0
  308. package/dist/qualityIntelligence/figma/figmaConsent.d.ts +39 -0
  309. package/dist/qualityIntelligence/figma/figmaConsent.d.ts.map +1 -0
  310. package/dist/qualityIntelligence/figma/figmaConsent.js +62 -0
  311. package/dist/qualityIntelligence/figma/figmaHttpPort.d.ts +28 -0
  312. package/dist/qualityIntelligence/figma/figmaHttpPort.d.ts.map +1 -0
  313. package/dist/qualityIntelligence/figma/figmaHttpPort.js +70 -0
  314. package/dist/qualityIntelligence/figma/figmaObservedActions.d.ts +49 -0
  315. package/dist/qualityIntelligence/figma/figmaObservedActions.d.ts.map +1 -0
  316. package/dist/qualityIntelligence/figma/figmaObservedActions.js +89 -0
  317. package/dist/qualityIntelligence/figma/figmaReadiness.d.ts +32 -0
  318. package/dist/qualityIntelligence/figma/figmaReadiness.d.ts.map +1 -0
  319. package/dist/qualityIntelligence/figma/figmaReadiness.js +67 -0
  320. package/dist/qualityIntelligence/figma/figmaRenderPort.d.ts +29 -0
  321. package/dist/qualityIntelligence/figma/figmaRenderPort.d.ts.map +1 -0
  322. package/dist/qualityIntelligence/figma/figmaRenderPort.js +93 -0
  323. package/dist/qualityIntelligence/figma/figmaResnapshot.d.ts +28 -0
  324. package/dist/qualityIntelligence/figma/figmaResnapshot.d.ts.map +1 -0
  325. package/dist/qualityIntelligence/figma/figmaResnapshot.js +38 -0
  326. package/dist/qualityIntelligence/figma/figmaRetry.d.ts +31 -0
  327. package/dist/qualityIntelligence/figma/figmaRetry.d.ts.map +1 -0
  328. package/dist/qualityIntelligence/figma/figmaRetry.js +62 -0
  329. package/dist/qualityIntelligence/figma/figmaScopeRef.d.ts +9 -0
  330. package/dist/qualityIntelligence/figma/figmaScopeRef.d.ts.map +1 -0
  331. package/dist/qualityIntelligence/figma/figmaScopeRef.js +18 -0
  332. package/dist/qualityIntelligence/figma/figmaScopedPagination.d.ts +86 -0
  333. package/dist/qualityIntelligence/figma/figmaScopedPagination.d.ts.map +1 -0
  334. package/dist/qualityIntelligence/figma/figmaScopedPagination.js +308 -0
  335. package/dist/qualityIntelligence/figma/figmaSnapshotBuilder.d.ts +31 -0
  336. package/dist/qualityIntelligence/figma/figmaSnapshotBuilder.d.ts.map +1 -0
  337. package/dist/qualityIntelligence/figma/figmaSnapshotBuilder.js +314 -0
  338. package/dist/qualityIntelligence/figma/figmaSnapshotHash.d.ts +18 -0
  339. package/dist/qualityIntelligence/figma/figmaSnapshotHash.d.ts.map +1 -0
  340. package/dist/qualityIntelligence/figma/figmaSnapshotHash.js +63 -0
  341. package/dist/qualityIntelligence/figma/figmaSnapshotTypes.d.ts +65 -0
  342. package/dist/qualityIntelligence/figma/figmaSnapshotTypes.d.ts.map +1 -0
  343. package/dist/qualityIntelligence/figma/figmaSnapshotTypes.js +13 -0
  344. package/dist/qualityIntelligence/figma/figmaTokenSource.d.ts +9 -0
  345. package/dist/qualityIntelligence/figma/figmaTokenSource.d.ts.map +1 -0
  346. package/dist/qualityIntelligence/figma/figmaTokenSource.js +61 -0
  347. package/dist/qualityIntelligence/figma/figmaTokenStore.d.ts +19 -0
  348. package/dist/qualityIntelligence/figma/figmaTokenStore.d.ts.map +1 -0
  349. package/dist/qualityIntelligence/figma/figmaTokenStore.js +156 -0
  350. package/dist/qualityIntelligence/figma/figmaUrl.d.ts +6 -0
  351. package/dist/qualityIntelligence/figma/figmaUrl.d.ts.map +1 -0
  352. package/dist/qualityIntelligence/figma/figmaUrl.js +36 -0
  353. package/dist/qualityIntelligence/figma/index.d.ts +20 -0
  354. package/dist/qualityIntelligence/figma/index.d.ts.map +1 -0
  355. package/dist/qualityIntelligence/figma/index.js +26 -0
  356. package/dist/qualityIntelligence/figmaCodegenRoutes.d.ts +28 -0
  357. package/dist/qualityIntelligence/figmaCodegenRoutes.d.ts.map +1 -0
  358. package/dist/qualityIntelligence/figmaCodegenRoutes.js +165 -0
  359. package/dist/qualityIntelligence/figmaSnapshotAdapter.d.ts +55 -0
  360. package/dist/qualityIntelligence/figmaSnapshotAdapter.d.ts.map +1 -0
  361. package/dist/qualityIntelligence/figmaSnapshotAdapter.js +219 -0
  362. package/dist/qualityIntelligence/figmaSnapshotOrchestration.d.ts +64 -0
  363. package/dist/qualityIntelligence/figmaSnapshotOrchestration.d.ts.map +1 -0
  364. package/dist/qualityIntelligence/figmaSnapshotOrchestration.js +203 -0
  365. package/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts +112 -0
  366. package/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts.map +1 -0
  367. package/dist/qualityIntelligence/figmaSnapshotRoutes.js +1063 -0
  368. package/dist/qualityIntelligence/figmaSnapshotScreenIds.d.ts +19 -0
  369. package/dist/qualityIntelligence/figmaSnapshotScreenIds.d.ts.map +1 -0
  370. package/dist/qualityIntelligence/figmaSnapshotScreenIds.js +75 -0
  371. package/dist/qualityIntelligence/generationPort.d.ts +15 -0
  372. package/dist/qualityIntelligence/generationPort.d.ts.map +1 -0
  373. package/dist/qualityIntelligence/generationPort.js +185 -0
  374. package/dist/qualityIntelligence/handoffErrors.d.ts +9 -0
  375. package/dist/qualityIntelligence/handoffErrors.d.ts.map +1 -0
  376. package/dist/qualityIntelligence/handoffErrors.js +21 -0
  377. package/dist/qualityIntelligence/handoffRoutes.d.ts +15 -0
  378. package/dist/qualityIntelligence/handoffRoutes.d.ts.map +1 -0
  379. package/dist/qualityIntelligence/handoffRoutes.js +341 -0
  380. package/dist/qualityIntelligence/index.d.ts +17 -0
  381. package/dist/qualityIntelligence/index.d.ts.map +1 -0
  382. package/dist/qualityIntelligence/index.js +36 -0
  383. package/dist/qualityIntelligence/judgePort.d.ts +30 -0
  384. package/dist/qualityIntelligence/judgePort.d.ts.map +1 -0
  385. package/dist/qualityIntelligence/judgePort.js +326 -0
  386. package/dist/qualityIntelligence/modelSelection.d.ts +58 -0
  387. package/dist/qualityIntelligence/modelSelection.d.ts.map +1 -0
  388. package/dist/qualityIntelligence/modelSelection.js +148 -0
  389. package/dist/qualityIntelligence/reCheckRoutes.d.ts +6 -0
  390. package/dist/qualityIntelligence/reCheckRoutes.d.ts.map +1 -0
  391. package/dist/qualityIntelligence/reCheckRoutes.js +1157 -0
  392. package/dist/qualityIntelligence/retentionEnforcement.d.ts +13 -0
  393. package/dist/qualityIntelligence/retentionEnforcement.d.ts.map +1 -0
  394. package/dist/qualityIntelligence/retentionEnforcement.js +47 -0
  395. package/dist/qualityIntelligence/retentionRoutes.d.ts +8 -0
  396. package/dist/qualityIntelligence/retentionRoutes.d.ts.map +1 -0
  397. package/dist/qualityIntelligence/retentionRoutes.js +74 -0
  398. package/dist/qualityIntelligence/reviewRoutes.d.ts +5 -0
  399. package/dist/qualityIntelligence/reviewRoutes.d.ts.map +1 -0
  400. package/dist/qualityIntelligence/reviewRoutes.js +145 -0
  401. package/dist/qualityIntelligence/reviewStore.d.ts +75 -0
  402. package/dist/qualityIntelligence/reviewStore.d.ts.map +1 -0
  403. package/dist/qualityIntelligence/reviewStore.js +170 -0
  404. package/dist/qualityIntelligence/runExecution.d.ts +36 -0
  405. package/dist/qualityIntelligence/runExecution.d.ts.map +1 -0
  406. package/dist/qualityIntelligence/runExecution.js +180 -0
  407. package/dist/qualityIntelligence/runIngestion.d.ts +70 -0
  408. package/dist/qualityIntelligence/runIngestion.d.ts.map +1 -0
  409. package/dist/qualityIntelligence/runIngestion.js +1235 -0
  410. package/dist/qualityIntelligence/runRegistry.d.ts +31 -0
  411. package/dist/qualityIntelligence/runRegistry.d.ts.map +1 -0
  412. package/dist/qualityIntelligence/runRegistry.js +66 -0
  413. package/dist/qualityIntelligence/runRoutes.d.ts +16 -0
  414. package/dist/qualityIntelligence/runRoutes.d.ts.map +1 -0
  415. package/dist/qualityIntelligence/runRoutes.js +357 -0
  416. package/dist/qualityIntelligence/traceabilityRoutes.d.ts +5 -0
  417. package/dist/qualityIntelligence/traceabilityRoutes.d.ts.map +1 -0
  418. package/dist/qualityIntelligence/traceabilityRoutes.js +173 -0
  419. package/dist/qualityIntelligence/uiRoutes.d.ts +7 -0
  420. package/dist/qualityIntelligence/uiRoutes.d.ts.map +1 -0
  421. package/dist/qualityIntelligence/uiRoutes.js +336 -0
  422. package/dist/read-handlers.d.ts +9 -0
  423. package/dist/read-handlers.d.ts.map +1 -0
  424. package/dist/read-handlers.js +265 -0
  425. package/dist/relationship-handlers.d.ts +191 -0
  426. package/dist/relationship-handlers.d.ts.map +1 -0
  427. package/dist/relationship-handlers.js +0 -0
  428. package/dist/routes.d.ts +37 -0
  429. package/dist/routes.d.ts.map +1 -0
  430. package/dist/routes.js +507 -0
  431. package/dist/run-engine.d.ts +25 -0
  432. package/dist/run-engine.d.ts.map +1 -0
  433. package/dist/run-engine.js +385 -0
  434. package/dist/run-handlers.d.ts +9 -0
  435. package/dist/run-handlers.d.ts.map +1 -0
  436. package/dist/run-handlers.js +465 -0
  437. package/dist/run-request.d.ts +17 -0
  438. package/dist/run-request.d.ts.map +1 -0
  439. package/dist/run-request.js +219 -0
  440. package/dist/runs.d.ts +47 -0
  441. package/dist/runs.d.ts.map +1 -0
  442. package/dist/runs.js +100 -0
  443. package/dist/server.d.ts +13 -0
  444. package/dist/server.d.ts.map +1 -0
  445. package/dist/server.js +152 -0
  446. package/dist/sink.d.ts +28 -0
  447. package/dist/sink.d.ts.map +1 -0
  448. package/dist/sink.js +80 -0
  449. package/dist/sse-write.d.ts +9 -0
  450. package/dist/sse-write.d.ts.map +1 -0
  451. package/dist/sse-write.js +26 -0
  452. package/dist/sse.d.ts +8 -0
  453. package/dist/sse.d.ts.map +1 -0
  454. package/dist/sse.js +27 -0
  455. package/dist/static.d.ts +5 -0
  456. package/dist/static.d.ts.map +1 -0
  457. package/dist/static.js +76 -0
  458. package/dist/store/chats.d.ts +17 -0
  459. package/dist/store/chats.d.ts.map +1 -0
  460. package/dist/store/chats.js +624 -0
  461. package/dist/store/db.d.ts +11 -0
  462. package/dist/store/db.d.ts.map +1 -0
  463. package/dist/store/db.js +203 -0
  464. package/dist/store/errors.d.ts +13 -0
  465. package/dist/store/errors.d.ts.map +1 -0
  466. package/dist/store/errors.js +30 -0
  467. package/dist/store/index.d.ts +7 -0
  468. package/dist/store/index.d.ts.map +1 -0
  469. package/dist/store/index.js +6 -0
  470. package/dist/store/messages.d.ts +8 -0
  471. package/dist/store/messages.d.ts.map +1 -0
  472. package/dist/store/messages.js +149 -0
  473. package/dist/store/paths.d.ts +5 -0
  474. package/dist/store/paths.d.ts.map +1 -0
  475. package/dist/store/paths.js +84 -0
  476. package/dist/store/projects.d.ts +8 -0
  477. package/dist/store/projects.d.ts.map +1 -0
  478. package/dist/store/projects.js +59 -0
  479. package/dist/store/relationship-audit.d.ts +42 -0
  480. package/dist/store/relationship-audit.d.ts.map +1 -0
  481. package/dist/store/relationship-audit.js +155 -0
  482. package/dist/store/relationships.d.ts +191 -0
  483. package/dist/store/relationships.d.ts.map +1 -0
  484. package/dist/store/relationships.js +724 -0
  485. package/dist/store/schema.d.ts +4 -0
  486. package/dist/store/schema.d.ts.map +1 -0
  487. package/dist/store/schema.js +220 -0
  488. package/dist/store/types.d.ts +29 -0
  489. package/dist/store/types.d.ts.map +1 -0
  490. package/dist/store/types.js +8 -0
  491. package/dist/store/validation.d.ts +7 -0
  492. package/dist/store/validation.d.ts.map +1 -0
  493. package/dist/store/validation.js +117 -0
  494. package/dist/store-handlers.d.ts +17 -0
  495. package/dist/store-handlers.d.ts.map +1 -0
  496. package/dist/store-handlers.js +872 -0
  497. package/dist/terminal-errors.d.ts +22 -0
  498. package/dist/terminal-errors.d.ts.map +1 -0
  499. package/dist/terminal-errors.js +45 -0
  500. package/dist/terminal-evidence.d.ts +21 -0
  501. package/dist/terminal-evidence.d.ts.map +1 -0
  502. package/dist/terminal-evidence.js +65 -0
  503. package/dist/terminal-routes.d.ts +10 -0
  504. package/dist/terminal-routes.d.ts.map +1 -0
  505. package/dist/terminal-routes.js +219 -0
  506. package/dist/terminal.d.ts +68 -0
  507. package/dist/terminal.d.ts.map +1 -0
  508. package/dist/terminal.js +855 -0
  509. package/package.json +52 -0
@@ -0,0 +1,320 @@
1
+ // Quality Intelligence export BFF route (Epic #270, Issue #283 + #711).
2
+ //
3
+ // * POST /api/quality-intelligence/runs/:id/export — serialise a run's candidates for export
4
+ //
5
+ // Local formats (csv / spreadsheet-safe-csv / json / markdown / plain-text) return the serialised
6
+ // body for a same-origin download — no external credentials. Binary formats (pdf / zip-bundle) are
7
+ // assembled server-side and returned as base64 in the JSON envelope. External TMS adapters
8
+ // (jira / qtest / xray / polarion / alm / quality-center) are DISABLED for actual writes: they
9
+ // only return a dry-run preview, require approved candidates, and never perform an outbound call.
10
+ // The candidate bodies were already redacted at persist time; the bundle attests redaction so the
11
+ // contract invariant holds. Path-/formula-safety lives in the pure adapters.
12
+ import { QualityIntelligence } from "@oscharko-dev/keiko-contracts";
13
+ import { sha256Hex } from "@oscharko-dev/keiko-security";
14
+ import { QualityIntelligenceExport } from "@oscharko-dev/keiko-quality-intelligence";
15
+ import { appendQualityIntelligenceExportRow, loadQualityIntelligenceRun, loadQualityIntelligenceCandidates, } from "@oscharko-dev/keiko-evidence";
16
+ import { loadRunReviewState, candidateReviewStateOf, runReviewStateOf } from "./reviewStore.js";
17
+ import { assemblePdf, assembleZipBundle } from "./exportAssembly.js";
18
+ const ADAPTERS = new Set([
19
+ ...QualityIntelligence.QUALITY_INTELLIGENCE_EXPORT_ADAPTERS,
20
+ "pdf",
21
+ "zip-bundle",
22
+ ]);
23
+ const MAX_BODY_BYTES = 16 * 1024;
24
+ const LOCAL_META = {
25
+ csv: { contentType: "text/csv", ext: "csv" },
26
+ "spreadsheet-safe-csv": { contentType: "text/csv", ext: "csv" },
27
+ json: { contentType: "application/json", ext: "json" },
28
+ markdown: { contentType: "text/markdown", ext: "md" },
29
+ "plain-text": { contentType: "text/plain", ext: "txt" },
30
+ // NOTE: no "quality-center" entry — it is a TMS adapter, so a non-dry-run request is rejected with
31
+ // 403 before LOCAL_META is consulted, and the dry-run path returns a preview object that never
32
+ // reads LOCAL_META. The `?? { text/plain, txt }` fallback at the materialised-response site covers
33
+ // any future non-TMS text adapter.
34
+ pdf: { contentType: "application/pdf", ext: "pdf" },
35
+ "zip-bundle": { contentType: "application/zip", ext: "zip" },
36
+ };
37
+ const errorResult = (status, code, message) => ({
38
+ status,
39
+ body: { error: { code, message } },
40
+ });
41
+ const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
42
+ const readBody = (req) => new Promise((resolve, reject) => {
43
+ const chunks = [];
44
+ let total = 0;
45
+ let capped = false;
46
+ req.on("data", (chunk) => {
47
+ total += chunk.length;
48
+ if (total > MAX_BODY_BYTES) {
49
+ if (!capped) {
50
+ capped = true;
51
+ chunks.length = 0;
52
+ reject(new Error("body too large"));
53
+ req.resume();
54
+ }
55
+ return;
56
+ }
57
+ chunks.push(chunk);
58
+ });
59
+ req.on("end", () => {
60
+ if (!capped)
61
+ resolve(Buffer.concat(chunks).toString("utf8"));
62
+ });
63
+ req.on("error", reject);
64
+ });
65
+ function rowToCandidate(row, runId) {
66
+ return {
67
+ id: QualityIntelligence.asQualityIntelligenceTestCaseId(row.id),
68
+ runId,
69
+ derivedFromAtomIds: row.derivedFromAtomIds.map((a) => QualityIntelligence.asQualityIntelligenceEvidenceAtomId(a)),
70
+ title: row.title,
71
+ preconditions: row.preconditions,
72
+ steps: row.steps,
73
+ expectedResults: row.expectedResults,
74
+ priority: row.priority,
75
+ riskClass: row.riskClass,
76
+ tags: row.tags,
77
+ status: row.status,
78
+ };
79
+ }
80
+ function buildBundle(runId, adapter, candidates, createdAt) {
81
+ const contents = candidates.map((c) => ({
82
+ candidateId: c.id,
83
+ coverageMapRefs: Object.freeze([]),
84
+ findingRefs: Object.freeze([]),
85
+ }));
86
+ const integrity = sha256Hex(JSON.stringify(candidates.map((c) => String(c.id))));
87
+ return {
88
+ id: QualityIntelligence.asQualityIntelligenceExportBundleId(`qi-export-${sha256Hex(`${runId}|${adapter}`).slice(0, 24)}`),
89
+ runId: QualityIntelligence.asQualityIntelligenceRunId(runId),
90
+ targetAdapter: adapter,
91
+ createdAt,
92
+ integrityHashSha256Hex: integrity,
93
+ redactionAttested: true,
94
+ contents,
95
+ };
96
+ }
97
+ /**
98
+ * Build the export-evidence row for an export action (Issue #283, AC4). Records the target type, a
99
+ * deterministic artifact id, an integrity hash over the exported candidate ids, the redaction
100
+ * attestation (candidates were redacted at persist time), and whether the action was a dry-run.
101
+ */
102
+ function buildExportEvidenceRow(runId, target, rows, dryRun) {
103
+ return {
104
+ id: `qi-export-${sha256Hex(`${runId}|${target}`).slice(0, 24)}`,
105
+ targetAdapter: target,
106
+ integrityHash: sha256Hex(JSON.stringify(rows.map((r) => r.id))),
107
+ redactionAttested: true,
108
+ dryRun,
109
+ };
110
+ }
111
+ /**
112
+ * Best-effort append of an export-evidence row for a 200 export action (Issue #283, AC4). A failed
113
+ * audit write must NOT withhold an already-computed local export from the user: the artifact has no
114
+ * external side effect, the run already exists on disk, and the manifest write is atomic so this path
115
+ * is rare. Swallow on failure rather than turning a successful export into a 500. No-op for error
116
+ * responses and for the disabled external-TMS path (which produces no artifact).
117
+ */
118
+ function recordExportEvidence(runId, outcome, evidenceDir) {
119
+ if (outcome.evidence === undefined || outcome.result.status !== 200) {
120
+ return;
121
+ }
122
+ try {
123
+ appendQualityIntelligenceExportRow({ runId, export: outcome.evidence }, { evidenceDir });
124
+ }
125
+ catch {
126
+ // intentionally swallowed — see doc comment
127
+ }
128
+ }
129
+ function parseExportBody(body) {
130
+ const adapter = body.adapter;
131
+ if (typeof adapter !== "string" || !ADAPTERS.has(adapter))
132
+ return undefined;
133
+ return {
134
+ adapter: adapter,
135
+ dryRun: body.dryRun === true,
136
+ approvedOnly: body.approvedOnly === true,
137
+ };
138
+ }
139
+ function selectRows(rows, approvedOnly, runId, evidenceDir) {
140
+ if (!approvedOnly)
141
+ return rows;
142
+ const review = loadRunReviewState(runId, evidenceDir);
143
+ // FIX E (Issue #282) — a reviewer can approve the whole RUN instead of each candidate. A
144
+ // run-level approval is an explicit approval of every candidate, so it satisfies approvedOnly
145
+ // (incl. the TMS adapters that force it). Otherwise fall back to the per-candidate filter.
146
+ if (runReviewStateOf(review) === "approved")
147
+ return rows;
148
+ return rows.filter((r) => candidateReviewStateOf(review, r.id) === "approved");
149
+ }
150
+ async function readExportRequest(req) {
151
+ let raw;
152
+ try {
153
+ raw = await readBody(req);
154
+ }
155
+ catch {
156
+ return {
157
+ ok: false,
158
+ result: errorResult(413, "QI_BODY_TOO_LARGE", "Export body is too large."),
159
+ };
160
+ }
161
+ let parsed;
162
+ try {
163
+ parsed = JSON.parse(raw);
164
+ }
165
+ catch {
166
+ return {
167
+ ok: false,
168
+ result: errorResult(400, "QI_BAD_REQUEST", "Export body is not valid JSON."),
169
+ };
170
+ }
171
+ if (!isObject(parsed)) {
172
+ return {
173
+ ok: false,
174
+ result: errorResult(400, "QI_BAD_REQUEST", "Export body must be an object."),
175
+ };
176
+ }
177
+ const request = parseExportBody(parsed);
178
+ if (request === undefined) {
179
+ return {
180
+ ok: false,
181
+ result: errorResult(400, "QI_BAD_ADAPTER", "A valid export adapter is required."),
182
+ };
183
+ }
184
+ return { ok: true, request };
185
+ }
186
+ export async function handleQiExport(ctx, deps) {
187
+ const { id } = ctx.params;
188
+ if (id === undefined || id.trim().length === 0) {
189
+ return errorResult(400, "QI_BAD_REQUEST", "Run id is required.");
190
+ }
191
+ const evidenceDir = deps.evidenceDir;
192
+ if (evidenceDir === undefined) {
193
+ return errorResult(500, "QI_NO_EVIDENCE_DIR", "The evidence directory is not configured.");
194
+ }
195
+ const parsed = await readExportRequest(ctx.req);
196
+ if (!parsed.ok)
197
+ return parsed.result;
198
+ try {
199
+ if (loadQualityIntelligenceRun(id, { evidenceDir }) === undefined) {
200
+ return errorResult(404, "QI_NOT_FOUND", "Quality Intelligence run not found.");
201
+ }
202
+ const artifact = loadQualityIntelligenceCandidates(id, { evidenceDir });
203
+ if (artifact === undefined || artifact.candidates.length === 0) {
204
+ return errorResult(409, "QI_NO_CANDIDATES", "This run has no candidates to export.");
205
+ }
206
+ const outcome = serialiseExport(id, parsed.request, artifact.candidates, evidenceDir);
207
+ // Emit audit evidence for every materialised export or dry-run preview (Issue #283, AC4). The
208
+ // append is best-effort and must not turn a successful export into a 500 — see recordExportEvidence.
209
+ recordExportEvidence(id, outcome, evidenceDir);
210
+ return outcome.result;
211
+ }
212
+ catch {
213
+ return errorResult(500, "QI_EXPORT_FAILED", "Failed to build the export.");
214
+ }
215
+ }
216
+ function binaryResponse(runId, mode, rows) {
217
+ const brandedRunId = QualityIntelligence.asQualityIntelligenceRunId(runId);
218
+ const candidates = rows.map((r) => rowToCandidate(r, brandedRunId));
219
+ const createdAt = new Date().toISOString();
220
+ const meta = LOCAL_META[mode] ?? { contentType: "application/octet-stream", ext: "bin" };
221
+ let bytes;
222
+ if (mode === "pdf") {
223
+ const bundle = buildBundle(runId, "plain-text", candidates, createdAt);
224
+ const serialized = QualityIntelligenceExport.serializeExportBundle(bundle, candidates);
225
+ bytes = assemblePdf(serialized.body, runId);
226
+ }
227
+ else {
228
+ const enc = new TextEncoder();
229
+ // Only timestamp-free serializers go into the bundle so the ZIP is byte-deterministic (its
230
+ // integrity feeds the Living-Tests drift epic #735). JSON is intentionally excluded: its body
231
+ // embeds the export `createdAt`, so a JSON-in-ZIP would differ on every export. JSON stays
232
+ // available as a standalone export.
233
+ const formats = ["csv", "markdown", "plain-text"];
234
+ const entries = formats.map((fmt) => {
235
+ const bundle = buildBundle(runId, fmt, candidates, createdAt);
236
+ const serialized = QualityIntelligenceExport.serializeExportBundle(bundle, candidates);
237
+ const ext = LOCAL_META[fmt]?.ext ?? "txt";
238
+ return { name: `${runId}.${ext}`, bytes: enc.encode(serialized.body) };
239
+ });
240
+ bytes = assembleZipBundle(entries);
241
+ }
242
+ return {
243
+ result: {
244
+ status: 200,
245
+ body: {
246
+ dryRun: false,
247
+ adapter: mode,
248
+ filename: `${runId}.${meta.ext}`,
249
+ contentType: meta.contentType,
250
+ byteLen: bytes.length,
251
+ encoding: "base64",
252
+ body: Buffer.from(bytes).toString("base64"),
253
+ },
254
+ },
255
+ evidence: buildExportEvidenceRow(runId, mode, rows, false),
256
+ };
257
+ }
258
+ function serialisedResponse(runId, request, rows) {
259
+ const adapter = request.adapter;
260
+ if (adapter === "pdf" || adapter === "zip-bundle") {
261
+ return binaryResponse(runId, adapter, rows);
262
+ }
263
+ const brandedRunId = QualityIntelligence.asQualityIntelligenceRunId(runId);
264
+ const candidates = rows.map((r) => rowToCandidate(r, brandedRunId));
265
+ const bundle = buildBundle(runId, adapter, candidates, new Date().toISOString());
266
+ const serialized = QualityIntelligenceExport.serializeExportBundle(bundle, candidates);
267
+ if (request.dryRun) {
268
+ return {
269
+ result: {
270
+ status: 200,
271
+ body: {
272
+ dryRun: true,
273
+ adapter,
274
+ candidateCount: rows.length,
275
+ byteLen: serialized.byteLen,
276
+ preview: serialized.body.slice(0, 1200),
277
+ },
278
+ },
279
+ evidence: buildExportEvidenceRow(runId, adapter, rows, true),
280
+ };
281
+ }
282
+ const meta = LOCAL_META[adapter] ?? { contentType: "text/plain", ext: "txt" };
283
+ return {
284
+ result: {
285
+ status: 200,
286
+ body: {
287
+ dryRun: false,
288
+ adapter,
289
+ filename: `${runId}.${meta.ext}`,
290
+ contentType: meta.contentType,
291
+ byteLen: serialized.byteLen,
292
+ body: serialized.body,
293
+ },
294
+ },
295
+ evidence: buildExportEvidenceRow(runId, adapter, rows, false),
296
+ };
297
+ }
298
+ function serialiseExport(runId, request, allRows, evidenceDir) {
299
+ const adapter = request.adapter;
300
+ const isBinary = adapter === "pdf" || adapter === "zip-bundle";
301
+ const isTms = !isBinary && QualityIntelligence.QUALITY_INTELLIGENCE_TMS_ADAPTERS.has(adapter);
302
+ const approvedOnly = isTms ? true : request.approvedOnly;
303
+ const rows = selectRows(allRows, approvedOnly, runId, evidenceDir);
304
+ if (rows.length === 0) {
305
+ return {
306
+ result: errorResult(409, "QI_NOTHING_TO_EXPORT", approvedOnly ? "No approved candidates to export." : "No candidates to export."),
307
+ };
308
+ }
309
+ if (isTms && !request.dryRun) {
310
+ // External TMS write is disabled — no artifact is produced, so no export-evidence row is
311
+ // recorded for this rejected action.
312
+ return {
313
+ result: errorResult(403, "QI_EXTERNAL_EXPORT_DISABLED", "External TMS export is disabled. Configure the connector and use a dry-run preview."),
314
+ };
315
+ }
316
+ return serialisedResponse(runId, request, rows);
317
+ }
318
+ export const QI_EXPORT_ROUTE_GROUP = [
319
+ { method: "POST", pattern: "/api/quality-intelligence/runs/:id/export", handler: handleQiExport },
320
+ ];
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Map `items` through `worker` with at most `limit` invocations in flight at once, preserving
3
+ * input order in the result. `limit` is clamped to `[1, items.length]`. If any worker rejects the
4
+ * whole operation rejects (the snapshot builder turns a per-screen failure into a skip BEFORE it
5
+ * reaches here, so a rejection is a genuine fault, not a partial-render case).
6
+ */
7
+ export declare const mapWithConcurrency: <T, R>(items: readonly T[], limit: number, worker: (item: T, index: number) => Promise<R>) => Promise<readonly R[]>;
8
+ //# sourceMappingURL=figmaConcurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figmaConcurrency.d.ts","sourceRoot":"","sources":["../../../src/qualityIntelligence/figma/figmaConcurrency.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAU,CAAC,EAAE,CAAC,EAC3C,OAAO,SAAS,CAAC,EAAE,EACnB,OAAO,MAAM,EACb,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,KAC7C,OAAO,CAAC,SAAS,CAAC,EAAE,CAoBtB,CAAC"}
@@ -0,0 +1,34 @@
1
+ // Bounded-concurrency worker pool for the Figma snapshot-build (Epic #750, Issue #759).
2
+ //
3
+ // A huge enterprise board has many screens to render and download. Firing every byte-download at
4
+ // once would burst the API (inviting 429s) and the host. This runs the per-screen work through a
5
+ // fixed, small concurrency cap — order-preserving so the assembled Snapshot is deterministic — and
6
+ // is generic over the work it drives (no Figma specifics, no timers, no scheduler).
7
+ /**
8
+ * Map `items` through `worker` with at most `limit` invocations in flight at once, preserving
9
+ * input order in the result. `limit` is clamped to `[1, items.length]`. If any worker rejects the
10
+ * whole operation rejects (the snapshot builder turns a per-screen failure into a skip BEFORE it
11
+ * reaches here, so a rejection is a genuine fault, not a partial-render case).
12
+ */
13
+ export const mapWithConcurrency = async (items, limit, worker) => {
14
+ if (items.length === 0)
15
+ return [];
16
+ const safeLimit = Number.isInteger(limit) && limit >= 1 ? limit : 1;
17
+ const cap = Math.max(1, Math.min(safeLimit, items.length));
18
+ const results = new Array(items.length);
19
+ let next = 0;
20
+ const runLane = async () => {
21
+ for (;;) {
22
+ const index = next;
23
+ next += 1;
24
+ if (index >= items.length)
25
+ return;
26
+ const item = items[index];
27
+ if (item === undefined)
28
+ continue;
29
+ results[index] = await worker(item, index);
30
+ }
31
+ };
32
+ await Promise.all(Array.from({ length: cap }, () => runLane()));
33
+ return results;
34
+ };
@@ -0,0 +1,65 @@
1
+ import type { FigmaHttpPort } from "./figmaHttpPort.js";
2
+ import { type FigmaRetryPolicy, type FigmaRetrySleep } from "./figmaRetry.js";
3
+ import { type FigmaNode, type ReadinessSignal } from "./figmaReadiness.js";
4
+ import { type FigmaScopeCoverage, type ScopedPaginationLimits } from "./figmaScopedPagination.js";
5
+ export interface FigmaConnectorConfig {
6
+ /**
7
+ * Optional config-key PAT alternate (#751 AC2). Sits between the vault and env sources in the
8
+ * vault > config > env precedence. It is only honoured when the connector is constructed directly
9
+ * with a config token; the governed production build ({@link governedSnapshotBuild}) resolves
10
+ * vault > env (no config token), so this field stays inert there by design.
11
+ */
12
+ readonly accessToken?: string;
13
+ readonly depth?: number;
14
+ readonly releaseMarker?: string;
15
+ readonly maxNodeCount?: number;
16
+ /**
17
+ * Per-deployment overrides for the deep scoped-pagination budgets (#837). Any omitted field falls
18
+ * back to {@link DEFAULT_SCOPED_PAGINATION_LIMITS}. Generic budgets — never tuned to a sample board.
19
+ */
20
+ readonly pagination?: Partial<ScopedPaginationLimits>;
21
+ }
22
+ export interface FigmaEnv {
23
+ readonly FIGMA_ACCESS_TOKEN?: string;
24
+ }
25
+ export interface FigmaConnectorDeps {
26
+ readonly http: FigmaHttpPort;
27
+ readonly env: FigmaEnv;
28
+ readonly config?: FigmaConnectorConfig;
29
+ readonly vaultToken?: string;
30
+ readonly retryPolicy?: FigmaRetryPolicy;
31
+ readonly sleep?: FigmaRetrySleep;
32
+ }
33
+ export interface FigmaFetchOptions {
34
+ readonly version?: string;
35
+ readonly fetchedAt?: string;
36
+ }
37
+ export interface FigmaProvenance {
38
+ readonly fileKey: string;
39
+ readonly nodeId: string;
40
+ readonly version: string | undefined;
41
+ readonly fetchedAt: string;
42
+ }
43
+ export interface FigmaScopedResult {
44
+ readonly nodes: FigmaNode;
45
+ readonly provenance: FigmaProvenance;
46
+ readonly readiness: ReadinessSignal;
47
+ /**
48
+ * Coverage telemetry, present only on the deep (`fetchScopedNodesDeep`) path (#837). Reports how
49
+ * many screens were deep-fetched / truncated and the assembled node + fetch counts, so the build
50
+ * can surface honest coverage instead of silently under-feeding the IR.
51
+ */
52
+ readonly coverage?: FigmaScopeCoverage;
53
+ }
54
+ export interface FigmaConnector {
55
+ /** Single shallow scoped fetch (depth cap + oversize guard). Backwards-compatible entry point. */
56
+ fetchScopedNodes(url: string, options?: FigmaFetchOptions): Promise<FigmaScopedResult>;
57
+ /**
58
+ * Bounded per-screen scoped-pagination fetch (#837): one shallow discovery fetch to enumerate
59
+ * screens, then a bounded breadth-first deepening of each screen subtree so in-screen text survives
60
+ * into the IR. Stays within the snapshot-build boundary; reports {@link FigmaScopeCoverage}.
61
+ */
62
+ fetchScopedNodesDeep(url: string, options?: FigmaFetchOptions): Promise<FigmaScopedResult>;
63
+ }
64
+ export declare const createFigmaConnector: (deps: FigmaConnectorDeps) => FigmaConnector;
65
+ //# sourceMappingURL=figmaConnector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figmaConnector.d.ts","sourceRoot":"","sources":["../../../src/qualityIntelligence/figma/figmaConnector.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE7F,OAAO,EAIL,KAAK,kBAAkB,EAGvB,KAAK,sBAAsB,EAC5B,MAAM,4BAA4B,CAAC;AAYpC,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAIvC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAE7B,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAExC,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,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;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC7B,kGAAkG;IAClG,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACvF;;;;OAIG;IACH,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC5F;AAgOD,eAAO,MAAM,oBAAoB,GAAI,MAAM,kBAAkB,KAAG,cAiB/D,CAAC"}
@@ -0,0 +1,184 @@
1
+ // Figma connector — scoped fetch + ready-signal resolution (Epic #750, Issue #751).
2
+ //
3
+ // Server-side only, read-only PAT, REST API only (no SDK, no MCP, no OAuth, no webhooks).
4
+ // From a pasted board/section link it fetches ONLY the scoped node subtree via
5
+ // `GET /v1/files/:key/nodes?ids=&depth=[&version=]` — never the whole-file endpoint — and
6
+ // resolves an advisory readiness signal. Output is the raw scoped node tree (handed to the
7
+ // IR cleaner in #752) plus token-free provenance.
8
+ //
9
+ // Token handling: the PAT is resolved from an injected config override or the
10
+ // `FIGMA_ACCESS_TOKEN` env var. It is materialised into the `X-Figma-Token` header at the
11
+ // transport boundary only; it is never logged, never returned, and never placed in any
12
+ // error or provenance. The HTTP transport is the injectable FigmaHttpPort so a future
13
+ // proxy/custom-CA client (#802) slots in without touching this logic.
14
+ import { FigmaConnectorError } from "./figmaConnectorErrors.js";
15
+ import { DEFAULT_FIGMA_RETRY_POLICY, fetchWithBackoff, realFigmaRetrySleep, } from "./figmaRetry.js";
16
+ import { parseFigmaTarget } from "./figmaUrl.js";
17
+ import { resolveReadiness } from "./figmaReadiness.js";
18
+ import { classifyTokenFailure, resolveFigmaToken } from "./figmaTokenSource.js";
19
+ import { DEFAULT_SCOPED_PAGINATION_LIMITS, paginateScopedDocument, resolveScopedPaginationLimits, } from "./figmaScopedPagination.js";
20
+ const FIGMA_API_ORIGIN = "https://api.figma.com";
21
+ const DEFAULT_DEPTH = 2;
22
+ const DEFAULT_MAX_NODE_COUNT = 5000;
23
+ const EPOCH = "1970-01-01T00:00:00.000Z";
24
+ const DEEP_FETCH_FAIL_SOFT_RETRY_POLICY = {
25
+ maxRetries: 0,
26
+ baseDelayMs: 500,
27
+ maxDelayMs: 500,
28
+ };
29
+ const resolveToken = (deps) => resolveFigmaToken({
30
+ vaultToken: deps.vaultToken,
31
+ configToken: deps.config?.accessToken,
32
+ envToken: deps.env.FIGMA_ACCESS_TOKEN,
33
+ });
34
+ const buildScopedUrl = (fileKey, nodeId, depth, version) => {
35
+ const url = new URL(`${FIGMA_API_ORIGIN}/v1/files/${encodeURIComponent(fileKey)}/nodes`);
36
+ url.searchParams.set("ids", nodeId);
37
+ url.searchParams.set("depth", String(depth));
38
+ if (version !== undefined && version.length > 0)
39
+ url.searchParams.set("version", version);
40
+ return url.toString();
41
+ };
42
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
43
+ // Figma error bodies carry a short reason in `err` (occasionally `message`). We pass only that
44
+ // generic string to the structural classifier so a 403 resolves to the most specific coded error
45
+ // (expired / revoked / insufficient-scope) without ever surfacing the raw payload. The token is
46
+ // never part of a response body, so this cannot leak it.
47
+ const extractFigmaReason = (body) => {
48
+ if (!isRecord(body))
49
+ return undefined;
50
+ const reason = body.err ?? body.message;
51
+ return typeof reason === "string" ? reason : undefined;
52
+ };
53
+ const statusToError = (status, body) => classifyTokenFailure(status, extractFigmaReason(body));
54
+ const extractDocument = (body, nodeId) => {
55
+ if (!isRecord(body) || !isRecord(body.nodes))
56
+ throw new FigmaConnectorError("FIGMA_INTERNAL");
57
+ const entry = body.nodes[nodeId];
58
+ if (entry === undefined)
59
+ throw new FigmaConnectorError("FIGMA_NOT_FOUND");
60
+ if (!isRecord(entry) || !isRecord(entry.document)) {
61
+ throw new FigmaConnectorError("FIGMA_INTERNAL");
62
+ }
63
+ return entry.document;
64
+ };
65
+ const countNodes = (node) => {
66
+ let total = 1;
67
+ for (const child of Array.isArray(node.children) ? node.children : [])
68
+ total += countNodes(child);
69
+ return total;
70
+ };
71
+ const guardScopeSize = (node, maxNodeCount) => {
72
+ if (countNodes(node) > maxNodeCount)
73
+ throw new FigmaConnectorError("FIGMA_OVERSIZED_SCOPE");
74
+ };
75
+ // A per-node deep fetch that hits one of these codes means the WHOLE build is compromised (auth lost,
76
+ // rate-limit exhausted, egress/TLS broken) — it must abort, not silently degrade a branch to shallow.
77
+ // Any other per-node failure (a transient 5xx or a vanished sub-node) is soft: that branch keeps its
78
+ // shallow content and the build proceeds with a truncation-aware coverage report.
79
+ // The proxy family is covered in full — symmetric with RENDER_EGRESS_ABORT_CODES in
80
+ // figmaSnapshotBuilder.ts — so a forward-proxy that requires auth (FIGMA_PROXY_AUTH_REQUIRED) or
81
+ // denies the request by policy (FIGMA_PROXY_BLOCKED_BY_POLICY) on a per-screen fetch aborts the build
82
+ // instead of silently degrading that screen to shallow content.
83
+ // Rate-limit exhaustion is deliberately NOT in this hard-abort set. The discovery fetch still aborts
84
+ // on FIGMA_RATE_LIMITED before this fetcher is constructed, but a single per-screen deepening fetch
85
+ // that exhausts retries can safely degrade to the already-fetched shallow screen while coverage marks
86
+ // it truncated. That keeps large boards reviewable instead of failing the whole snapshot after one
87
+ // expensive branch hits Figma's cost-based limit.
88
+ const DEEP_FETCH_ABORT_CODES = new Set([
89
+ "FIGMA_TOKEN_MISSING",
90
+ "FIGMA_TOKEN_INVALID",
91
+ "FIGMA_TOKEN_EXPIRED",
92
+ "FIGMA_TOKEN_REVOKED",
93
+ "FIGMA_INSUFFICIENT_SCOPE",
94
+ "FIGMA_CONSENT_REQUIRED",
95
+ "FIGMA_PROXY_EGRESS_FAILED",
96
+ "FIGMA_PROXY_UNREACHABLE",
97
+ "FIGMA_PROXY_AUTH_REQUIRED",
98
+ "FIGMA_PROXY_BLOCKED_BY_POLICY",
99
+ "FIGMA_TLS_CA_FAILURE",
100
+ ]);
101
+ // One scoped `nodes?ids=&depth=` fetch (with 429 backoff), returning the raw document. No oversize
102
+ // guard here — the shallow path applies it; the deep path is bounded by the pagination budgets. The
103
+ // token flows into the header only.
104
+ const fetchDocumentAt = async (rt, token, fileKey, nodeId, fetchDepth, version, retryPolicy = rt.retryPolicy) => {
105
+ const requestUrl = buildScopedUrl(fileKey, nodeId, fetchDepth, version);
106
+ const response = await fetchWithBackoff(() => rt.deps.http({ url: requestUrl, headers: { "X-Figma-Token": token } }), retryPolicy, rt.sleep);
107
+ if (response.status < 200 || response.status >= 300) {
108
+ throw statusToError(response.status, response.json);
109
+ }
110
+ return extractDocument(response.json, nodeId);
111
+ };
112
+ const provenanceFor = (target, options) => ({
113
+ fileKey: target.fileKey,
114
+ nodeId: target.nodeId,
115
+ version: options.version,
116
+ fetchedAt: options.fetchedAt ?? EPOCH,
117
+ });
118
+ // RawFigmaNode → FigmaNode is a safe widening for the readiness reader (which tolerates absent fields).
119
+ const readinessFor = (rt, document, version) => resolveReadiness(document, { version, releaseMarker: rt.releaseMarker });
120
+ const resolveTarget = (url) => {
121
+ const target = parseFigmaTarget(url);
122
+ if (target === null)
123
+ throw new FigmaConnectorError("FIGMA_MALFORMED_URL");
124
+ return target;
125
+ };
126
+ const doFetchScopedNodes = async (rt, url, options) => {
127
+ const token = resolveToken(rt.deps);
128
+ const target = resolveTarget(url);
129
+ const document = await fetchDocumentAt(rt, token, target.fileKey, target.nodeId, rt.depth, options.version);
130
+ guardScopeSize(document, rt.maxNodeCount);
131
+ return {
132
+ nodes: document,
133
+ provenance: provenanceFor(target, options),
134
+ readiness: readinessFor(rt, document, options.version),
135
+ };
136
+ };
137
+ // The per-screen deepening fetcher: a hard (auth/rate/egress) code aborts the build; any other
138
+ // per-node failure degrades that branch to its shallow content (recorded as truncation in coverage).
139
+ const makeDeepFetcher = (rt, token, target, version) => {
140
+ return async (nodeId) => {
141
+ try {
142
+ return await fetchDocumentAt(rt, token, target.fileKey, nodeId, rt.paginationLimits.pageDepth, version, DEEP_FETCH_FAIL_SOFT_RETRY_POLICY);
143
+ }
144
+ catch (err) {
145
+ if (err instanceof FigmaConnectorError && DEEP_FETCH_ABORT_CODES.has(err.code))
146
+ throw err;
147
+ return undefined;
148
+ }
149
+ };
150
+ };
151
+ const doFetchScopedNodesDeep = async (rt, url, options) => {
152
+ const token = resolveToken(rt.deps);
153
+ const target = resolveTarget(url);
154
+ // One shallow discovery fetch enumerates the screens (and resolves advisory readiness). No oversize
155
+ // guard: a wide canvas is exactly what the deep path paginates. This is the FIRST, auth-establishing
156
+ // egress; a hard failure here aborts before any per-screen fetch.
157
+ const discovery = await fetchDocumentAt(rt, token, target.fileKey, target.nodeId, rt.depth, options.version);
158
+ const fetchNode = makeDeepFetcher(rt, token, target, options.version);
159
+ const { document, coverage } = await paginateScopedDocument(discovery, fetchNode, rt.paginationLimits);
160
+ return {
161
+ nodes: document,
162
+ provenance: provenanceFor(target, options),
163
+ readiness: readinessFor(rt, document, options.version),
164
+ coverage,
165
+ };
166
+ };
167
+ export const createFigmaConnector = (deps) => {
168
+ const rt = {
169
+ deps,
170
+ depth: deps.config?.depth ?? DEFAULT_DEPTH,
171
+ releaseMarker: deps.config?.releaseMarker,
172
+ maxNodeCount: deps.config?.maxNodeCount ?? DEFAULT_MAX_NODE_COUNT,
173
+ retryPolicy: deps.retryPolicy ?? DEFAULT_FIGMA_RETRY_POLICY,
174
+ sleep: deps.sleep ?? realFigmaRetrySleep,
175
+ paginationLimits: resolveScopedPaginationLimits({
176
+ ...DEFAULT_SCOPED_PAGINATION_LIMITS,
177
+ ...deps.config?.pagination,
178
+ }),
179
+ };
180
+ return {
181
+ fetchScopedNodes: (url, options = {}) => doFetchScopedNodes(rt, url, options),
182
+ fetchScopedNodesDeep: (url, options = {}) => doFetchScopedNodesDeep(rt, url, options),
183
+ };
184
+ };