@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,293 @@
1
+ // Quality Intelligence inline-edit BFF route (Epic #712, Issue #726).
2
+ //
3
+ // * POST /api/quality-intelligence/runs/:id/edit — edit a generated candidate's fields inline
4
+ //
5
+ // Updates the candidate row in place inside the MUTABLE candidates artifact (redacted, with
6
+ // provenance appended to `editedRevisions[]`) and records an `edit` audit entry. The IMMUTABLE run
7
+ // manifest (`<runId>.qi.json`) is never touched. CSRF is enforced by the dispatch layer for POST
8
+ // (mirrors reviewRoutes); the body is capped at 16KB and every field is validated before persist.
9
+ import { applyQualityIntelligenceCandidateEdit, loadQualityIntelligenceRun, } from "@oscharko-dev/keiko-evidence";
10
+ import { QualityIntelligence, } from "@oscharko-dev/keiko-contracts";
11
+ import { normaliseCandidateText } from "@oscharko-dev/keiko-quality-intelligence";
12
+ import { appendEditAudit, candidateReviewStateOf, loadRunReviewState } from "./reviewStore.js";
13
+ const MAX_BODY_BYTES = 16 * 1024;
14
+ const MAX_TITLE_LEN = 256;
15
+ const MAX_LIST_ITEMS = 100;
16
+ const MAX_LABEL_LEN = 80;
17
+ const PRIORITIES = new Set(QualityIntelligence.QUALITY_INTELLIGENCE_PRIORITIES);
18
+ const RISK_CLASSES = new Set(QualityIntelligence.QUALITY_INTELLIGENCE_RISK_CLASSES);
19
+ const readBody = (req) => new Promise((resolve, reject) => {
20
+ const chunks = [];
21
+ let total = 0;
22
+ let capped = false;
23
+ req.on("data", (chunk) => {
24
+ total += chunk.length;
25
+ if (total > MAX_BODY_BYTES) {
26
+ if (!capped) {
27
+ capped = true;
28
+ chunks.length = 0;
29
+ reject(new Error("body too large"));
30
+ req.resume();
31
+ }
32
+ return;
33
+ }
34
+ chunks.push(chunk);
35
+ });
36
+ req.on("end", () => {
37
+ if (!capped)
38
+ resolve(Buffer.concat(chunks).toString("utf8"));
39
+ });
40
+ req.on("error", reject);
41
+ });
42
+ const errorResult = (status, code, message) => ({
43
+ status,
44
+ body: { error: { code, message } },
45
+ });
46
+ const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
47
+ // A list field is an array (≤ MAX_LIST_ITEMS) of non-blank strings. `minItems` separates the two
48
+ // domain shapes: steps and expected results are the load-bearing body of a test case and must carry
49
+ // at least one entry (clearing them produces an empty, meaningless test case → reject); preconditions
50
+ // and tags are legitimately optional and may be cleared. Blank ("") items are rejected for every list
51
+ // field (a blank step / tag is never meaningful), keeping the persisted body clean.
52
+ const isListField = (value, minItems) => Array.isArray(value) &&
53
+ value.length >= minItems &&
54
+ value.length <= MAX_LIST_ITEMS &&
55
+ value.every((item) => typeof item === "string" && item.length > 0);
56
+ const isValidTitle = (value) => typeof value === "string" && value.length >= 1 && value.length <= MAX_TITLE_LEN;
57
+ // Per-field validators keyed by field name. Keeping the branching in a data table (not a switch)
58
+ // holds the validator helper's cyclomatic complexity low while still rejecting any malformed value.
59
+ const FIELD_VALIDATORS = {
60
+ title: isValidTitle,
61
+ preconditions: (value) => isListField(value, 0),
62
+ steps: (value) => isListField(value, 1),
63
+ expectedResults: (value) => isListField(value, 1),
64
+ priority: (value) => typeof value === "string" && PRIORITIES.has(value),
65
+ riskClass: (value) => typeof value === "string" && RISK_CLASSES.has(value),
66
+ tags: (value) => isListField(value, 0),
67
+ };
68
+ // Validate one editable field. Returns `false` for a malformed value so the caller rejects the whole
69
+ // edit (no partial persist). Unknown keys are ignored by the caller (only EDITABLE_KEYS are read).
70
+ function isValidField(key, value) {
71
+ return FIELD_VALIDATORS[key]?.(value) ?? false;
72
+ }
73
+ const EDITABLE_KEYS = [
74
+ "title",
75
+ "preconditions",
76
+ "steps",
77
+ "expectedResults",
78
+ "priority",
79
+ "riskClass",
80
+ "tags",
81
+ ];
82
+ function parseEditorLabel(value) {
83
+ if (typeof value !== "string")
84
+ return undefined;
85
+ // Strip bidi/zero-width/control spoofing code points (+ NFKC + trim) before length-capping so the
86
+ // persisted provenance `editorLabel` and the `.review.json` `reviewerLabel` (both derived from this
87
+ // one value) get the same content-safety treatment as generated candidate text. A label of only
88
+ // format characters normalises to "" and is rejected as a missing reviewer label.
89
+ const cleaned = normaliseCandidateText(value);
90
+ return cleaned.length > 0 ? cleaned.slice(0, MAX_LABEL_LEN) : undefined;
91
+ }
92
+ // The editable fields whose value is an array of candidate body-text lines. `title` (single string)
93
+ // and the closed enums (priority / riskClass) are handled separately in normaliseEditedValue.
94
+ const TEXT_LIST_KEYS = new Set([
95
+ "preconditions",
96
+ "steps",
97
+ "expectedResults",
98
+ "tags",
99
+ ]);
100
+ // Strip bidi / zero-width / control spoofing code points (+ NFKC + trim) from every human-supplied
101
+ // text field BEFORE validation, so an inline edit persists through the SAME candidate-text
102
+ // normalisation as the generation path (parseGeneratedCandidates → normaliseCandidateText — the
103
+ // documented single chokepoint for persisted candidate text). Closed enums (priority / riskClass) and
104
+ // any non-string shape pass through untouched; their validators reject anything off-list. A title or
105
+ // list item whose only content was format characters normalises to "" and is then rejected by the
106
+ // non-blank validators (an actionable 400) rather than persisted as junk. Normalising first also means
107
+ // MAX_TITLE_LEN is measured on the cleaned text, so padding a title with zero-width marks cannot
108
+ // smuggle it past the length cap.
109
+ function normaliseEditedValue(key, value) {
110
+ if (key === "title") {
111
+ return typeof value === "string" ? normaliseCandidateText(value) : value;
112
+ }
113
+ if (TEXT_LIST_KEYS.has(key) && Array.isArray(value)) {
114
+ // `Array.isArray` narrows `unknown` to `any[]`; widen back to `unknown[]` so each item is typed
115
+ // (no unsafe `any`). Non-string items pass through for the list validator to reject.
116
+ return value.map((item) => typeof item === "string" ? normaliseCandidateText(item) : item);
117
+ }
118
+ return value;
119
+ }
120
+ function collectEditedFields(edited) {
121
+ const collected = {};
122
+ let fieldCount = 0;
123
+ for (const key of EDITABLE_KEYS) {
124
+ const raw = edited[key];
125
+ if (raw === undefined)
126
+ continue;
127
+ const value = normaliseEditedValue(key, raw);
128
+ if (!isValidField(key, value))
129
+ return { ok: false, invalidField: key };
130
+ collected[key] = value;
131
+ fieldCount += 1;
132
+ }
133
+ return fieldCount > 0
134
+ ? { ok: true, fields: collected }
135
+ : { ok: false, invalidField: undefined };
136
+ }
137
+ // Returns the parsed edit, or a field-specific rejection message so the reviewer learns WHICH field
138
+ // is invalid (a generic "edit is invalid" is not actionable). Any failing field rejects the whole
139
+ // edit (no partial persist).
140
+ function parseEdit(body) {
141
+ const candidateId = body.candidateId;
142
+ if (typeof candidateId !== "string" || candidateId.trim().length === 0) {
143
+ return { ok: false, message: "A candidate id is required." };
144
+ }
145
+ const editorLabel = parseEditorLabel(body.editorLabel);
146
+ if (editorLabel === undefined) {
147
+ return { ok: false, message: "A non-empty reviewer label is required." };
148
+ }
149
+ const edited = body.edited;
150
+ if (!isObject(edited)) {
151
+ return { ok: false, message: "An `edited` object with the changed fields is required." };
152
+ }
153
+ const collected = collectEditedFields(edited);
154
+ if (!collected.ok) {
155
+ return {
156
+ ok: false,
157
+ message: collected.invalidField === undefined
158
+ ? "At least one editable field must be supplied."
159
+ : `The "${collected.invalidField}" field is empty or invalid.`,
160
+ };
161
+ }
162
+ return { ok: true, edit: { candidateId, edited: collected.fields, editorLabel } };
163
+ }
164
+ async function readEdit(req) {
165
+ let raw;
166
+ try {
167
+ raw = await readBody(req);
168
+ }
169
+ catch {
170
+ return { ok: false, result: errorResult(413, "QI_BODY_TOO_LARGE", "Edit body is too large.") };
171
+ }
172
+ let parsed;
173
+ try {
174
+ parsed = JSON.parse(raw);
175
+ }
176
+ catch {
177
+ return {
178
+ ok: false,
179
+ result: errorResult(400, "QI_BAD_REQUEST", "Edit body is not valid JSON."),
180
+ };
181
+ }
182
+ if (!isObject(parsed)) {
183
+ return {
184
+ ok: false,
185
+ result: errorResult(400, "QI_BAD_REQUEST", "Edit body must be an object."),
186
+ };
187
+ }
188
+ const edit = parseEdit(parsed);
189
+ if (!edit.ok) {
190
+ return { ok: false, result: errorResult(400, "QI_BAD_EDIT", edit.message) };
191
+ }
192
+ return { ok: true, edit: edit.edit };
193
+ }
194
+ // Project the edited row for the immediate POST response. This intentionally omits `weakTestFlag`
195
+ // (the adversarial-judge badge): that flag is derived from the run MANIFEST findings, not the
196
+ // candidate row, and recomputing it here would duplicate the run-detail GET's manifest read
197
+ // (uiRoutes.ts) and risk drift. AC1 scopes "reflected" to the next run-detail fetch, where the GET
198
+ // projection re-attaches `weakTestFlag`; clients refresh the badge from that fetch.
199
+ function projectCandidate(row, evidenceDir, runId) {
200
+ const reviewArtifact = loadRunReviewState(runId, evidenceDir);
201
+ return {
202
+ id: row.id,
203
+ title: row.title,
204
+ preconditions: row.preconditions,
205
+ steps: row.steps,
206
+ expectedResults: row.expectedResults,
207
+ priority: row.priority,
208
+ riskClass: row.riskClass,
209
+ tags: row.tags,
210
+ status: row.status,
211
+ reviewState: candidateReviewStateOf(reviewArtifact, row.id),
212
+ derivedFromAtomIds: row.derivedFromAtomIds,
213
+ };
214
+ }
215
+ // Apply a validated edit (redacted, in-place), append the audit entry, and project the updated
216
+ // candidate for the wire. Split out of the handler to keep the handler within the line budget.
217
+ function recordEdit(runId, edit, evidenceDir, deps) {
218
+ const result = applyQualityIntelligenceCandidateEdit({
219
+ runId,
220
+ candidateId: edit.candidateId,
221
+ editedFields: edit.edited,
222
+ provenance: {
223
+ editedAt: new Date().toISOString(),
224
+ editedBy: "human",
225
+ editorLabel: edit.editorLabel,
226
+ },
227
+ evidenceDir,
228
+ redact: deps.redactor,
229
+ });
230
+ if (!result.ok) {
231
+ if (result.reason === "no-edited-fields") {
232
+ return errorResult(400, "QI_BAD_EDIT", "At least one editable field must be supplied.");
233
+ }
234
+ if (result.reason === "artifact-not-found") {
235
+ // The run manifest exists but its candidates companion is missing — a distinct, observable
236
+ // failure (corruption / partial state) rather than an unknown candidate id.
237
+ return errorResult(404, "QI_CANDIDATES_NOT_FOUND", "No candidates artifact exists for this run.");
238
+ }
239
+ return errorResult(404, "QI_NOT_FOUND", "Candidate not found for this run.");
240
+ }
241
+ if (result.changed) {
242
+ // Append the consolidated `.review.json` audit entry. The atomic, per-edit record is the
243
+ // `editedRevisions[]` provenance just written WITH the candidate change (a single candidates.json
244
+ // write inside applyQualityIntelligenceCandidateEdit); this is a second, separate companion write.
245
+ // If it throws (e.g. disk failure) the outer handler returns 500, but the edit is still recorded
246
+ // in editedRevisions[] provenance — an edit is never fully unaudited. The trade-off: the
247
+ // consolidated audit log can lag the per-artifact provenance on a partial-write failure, and a
248
+ // retry with identical fields is a no-op (changed === false) that won't backfill it. Cross-artifact
249
+ // write atomicity is a tracked follow-up; it is not introduced here to avoid touching the shared
250
+ // companion store used by every QI route.
251
+ appendEditAudit({
252
+ runId,
253
+ evidenceDir,
254
+ candidateId: edit.candidateId,
255
+ reviewerLabel: edit.editorLabel,
256
+ now: new Date().toISOString(),
257
+ redact: deps.redactor,
258
+ });
259
+ }
260
+ return {
261
+ status: 200,
262
+ body: { candidate: projectCandidate(result.candidate, evidenceDir, runId) },
263
+ };
264
+ }
265
+ export async function handleQiEditCandidate(ctx, deps) {
266
+ const { id } = ctx.params;
267
+ if (id === undefined || id.trim().length === 0) {
268
+ return errorResult(400, "QI_BAD_REQUEST", "Run id is required.");
269
+ }
270
+ const evidenceDir = deps.evidenceDir;
271
+ if (evidenceDir === undefined) {
272
+ return errorResult(500, "QI_NO_EVIDENCE_DIR", "The evidence directory is not configured.");
273
+ }
274
+ const parsed = await readEdit(ctx.req);
275
+ if (!parsed.ok)
276
+ return parsed.result;
277
+ try {
278
+ if (loadQualityIntelligenceRun(id, { evidenceDir }) === undefined) {
279
+ return errorResult(404, "QI_RUN_NOT_FOUND", "Quality Intelligence run not found.");
280
+ }
281
+ return recordEdit(id, parsed.edit, evidenceDir, deps);
282
+ }
283
+ catch {
284
+ return errorResult(500, "QI_EDIT_FAILED", "Failed to record the candidate edit.");
285
+ }
286
+ }
287
+ export const QI_EDIT_ROUTE_GROUP = [
288
+ {
289
+ method: "POST",
290
+ pattern: "/api/quality-intelligence/runs/:id/edit",
291
+ handler: handleQiEditCandidate,
292
+ },
293
+ ];
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Reduce an entry name to a contained, single-segment file name. Defense-in-depth: the run id is
3
+ * already brand-validated (no "/", "\\", ".." — see keiko-contracts ids.ts) before it reaches this
4
+ * helper, but the ZIP writer must not depend on its caller for containment. Strips any directory
5
+ * component, collapses traversal dot-runs, and rejects an empty result.
6
+ */
7
+ export declare function safeZipEntryName(name: string): string;
8
+ /**
9
+ * Assembles a deterministic STORE (no-compression) ZIP from the given entries.
10
+ * DOS date/time fields are zeroed for byte-stable output across runs. Entry names are reduced to a
11
+ * contained basename so a bundle can never write outside its own archive root.
12
+ */
13
+ export declare function assembleZipBundle(entries: readonly {
14
+ readonly name: string;
15
+ readonly bytes: Uint8Array;
16
+ }[]): Uint8Array;
17
+ /**
18
+ * Assembles a deterministic, multi-page, text-only PDF from the given plain-text body. The entire
19
+ * body is rendered across as many pages as needed (no truncation). Byte-stable across identical runs.
20
+ */
21
+ export declare function assemblePdf(body: string, runId: string): Uint8Array;
22
+ //# sourceMappingURL=exportAssembly.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exportAssembly.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/exportAssembly.ts"],"names":[],"mappings":"AA6FA;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,EAAE,GACxE,UAAU,CA+BZ;AA+KD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAmDnE"}
@@ -0,0 +1,352 @@
1
+ // Binary export assembly helpers (Epic #711).
2
+ //
3
+ // Produces deterministic binary artifacts — a minimal text-only PDF and a STORE
4
+ // (no-compression) ZIP — with zero new runtime dependencies. Both formats are
5
+ // assembled by hand to guarantee byte-stable output: no /CreationDate, no UUIDs,
6
+ // no timestamps, no Math.random.
7
+ //
8
+ // PDF determinism: fixed object offsets, static trailer, no metadata objects.
9
+ // ZIP determinism: DOS date/time zeroed, STORE method (no compression), CRC32
10
+ // computed from content bytes, central directory built from the same metadata.
11
+ // ─── Shared ───────────────────────────────────────────────────────────────────
12
+ const TEXT_ENC = new TextEncoder();
13
+ // ─── CRC32 ────────────────────────────────────────────────────────────────────
14
+ const CRC32_TABLE = (() => {
15
+ const t = new Uint32Array(256);
16
+ for (let i = 0; i < 256; i++) {
17
+ let c = i;
18
+ for (let k = 0; k < 8; k++) {
19
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
20
+ }
21
+ t[i] = c >>> 0;
22
+ }
23
+ return t;
24
+ })();
25
+ function crc32(bytes) {
26
+ let c = 0xffffffff;
27
+ for (const byte of bytes) {
28
+ c = (CRC32_TABLE[(c ^ byte) & 0xff] ?? 0) ^ (c >>> 8);
29
+ }
30
+ return (c ^ 0xffffffff) >>> 0;
31
+ }
32
+ // ─── Little-endian integer helpers ───────────────────────────────────────────
33
+ function u16le(n) {
34
+ return [n & 0xff, (n >>> 8) & 0xff];
35
+ }
36
+ function u32le(n) {
37
+ return [n & 0xff, (n >>> 8) & 0xff, (n >>> 16) & 0xff, (n >>> 24) & 0xff];
38
+ }
39
+ // ─── ZIP assembly ─────────────────────────────────────────────────────────────
40
+ const ZIP_LOCAL_HEADER_SIG = [0x50, 0x4b, 0x03, 0x04];
41
+ const ZIP_CENTRAL_SIG = [0x50, 0x4b, 0x01, 0x02];
42
+ const ZIP_EOCD_SIG = [0x50, 0x4b, 0x05, 0x06];
43
+ function buildLocalHeader(name, size, crc) {
44
+ return [
45
+ ...ZIP_LOCAL_HEADER_SIG,
46
+ ...u16le(20), // version needed
47
+ ...u16le(0), // flags
48
+ ...u16le(0), // STORE method
49
+ ...u16le(0), // last mod time (zeroed)
50
+ ...u16le(0), // last mod date (zeroed)
51
+ ...u32le(crc),
52
+ ...u32le(size), // compressed size
53
+ ...u32le(size), // uncompressed size
54
+ ...u16le(name.length),
55
+ ...u16le(0), // extra field length
56
+ ...name,
57
+ ];
58
+ }
59
+ function buildCentralEntry(name, size, crc, offset) {
60
+ return [
61
+ ...ZIP_CENTRAL_SIG,
62
+ ...u16le(20), // version made by
63
+ ...u16le(20), // version needed
64
+ ...u16le(0), // flags
65
+ ...u16le(0), // STORE method
66
+ ...u16le(0), // last mod time (zeroed)
67
+ ...u16le(0), // last mod date (zeroed)
68
+ ...u32le(crc),
69
+ ...u32le(size), // compressed size
70
+ ...u32le(size), // uncompressed size
71
+ ...u16le(name.length),
72
+ ...u16le(0), // extra field length
73
+ ...u16le(0), // file comment length
74
+ ...u16le(0), // disk number start
75
+ ...u16le(0), // internal attributes
76
+ ...u32le(0), // external attributes
77
+ ...u32le(offset),
78
+ ...name,
79
+ ];
80
+ }
81
+ /**
82
+ * Reduce an entry name to a contained, single-segment file name. Defense-in-depth: the run id is
83
+ * already brand-validated (no "/", "\\", ".." — see keiko-contracts ids.ts) before it reaches this
84
+ * helper, but the ZIP writer must not depend on its caller for containment. Strips any directory
85
+ * component, collapses traversal dot-runs, and rejects an empty result.
86
+ */
87
+ export function safeZipEntryName(name) {
88
+ const base = name
89
+ .replace(/^.*[\\/]/u, "") // drop any directory prefix (POSIX or Windows separators)
90
+ .replace(/\.{2,}/gu, "."); // collapse ".." (and longer dot-runs) so no traversal token survives
91
+ return base.length > 0 ? base : "export.bin";
92
+ }
93
+ /**
94
+ * Assembles a deterministic STORE (no-compression) ZIP from the given entries.
95
+ * DOS date/time fields are zeroed for byte-stable output across runs. Entry names are reduced to a
96
+ * contained basename so a bundle can never write outside its own archive root.
97
+ */
98
+ export function assembleZipBundle(entries) {
99
+ const localHeaders = [];
100
+ const centralEntries = [];
101
+ const dataChunks = [];
102
+ const offsets = [];
103
+ let offset = 0;
104
+ for (const entry of entries) {
105
+ const nameBytes = TEXT_ENC.encode(safeZipEntryName(entry.name));
106
+ const crc = crc32(entry.bytes);
107
+ const local = buildLocalHeader(nameBytes, entry.bytes.length, crc);
108
+ offsets.push(offset);
109
+ localHeaders.push(local);
110
+ dataChunks.push(entry.bytes);
111
+ offset += local.length + entry.bytes.length;
112
+ centralEntries.push(buildCentralEntry(nameBytes, entry.bytes.length, crc, offsets.at(-1) ?? 0));
113
+ }
114
+ const centralStart = offset;
115
+ const centralFlat = centralEntries.flatMap((e) => e);
116
+ const eocd = [
117
+ ...ZIP_EOCD_SIG,
118
+ ...u16le(0), // disk number
119
+ ...u16le(0), // central dir start disk
120
+ ...u16le(entries.length), // entries on disk
121
+ ...u16le(entries.length), // total entries
122
+ ...u32le(centralFlat.length),
123
+ ...u32le(centralStart),
124
+ ...u16le(0), // comment length
125
+ ];
126
+ return concatZipBytes(localHeaders, dataChunks, centralFlat, eocd);
127
+ }
128
+ // Interleave [localHeader, data] pairs, then the central directory and EOCD, into one buffer.
129
+ function concatZipBytes(localHeaders, dataChunks, centralFlat, eocd) {
130
+ const totalLen = localHeaders.reduce((s, h) => s + h.length, 0) +
131
+ dataChunks.reduce((s, d) => s + d.length, 0) +
132
+ centralFlat.length +
133
+ eocd.length;
134
+ const out = new Uint8Array(totalLen);
135
+ let pos = 0;
136
+ for (let i = 0; i < localHeaders.length; i++) {
137
+ const hdr = localHeaders[i];
138
+ const dat = dataChunks[i];
139
+ if (hdr === undefined || dat === undefined)
140
+ continue;
141
+ out.set(hdr, pos);
142
+ pos += hdr.length;
143
+ out.set(dat, pos);
144
+ pos += dat.length;
145
+ }
146
+ out.set(centralFlat, pos);
147
+ pos += centralFlat.length;
148
+ out.set(eocd, pos);
149
+ return out;
150
+ }
151
+ // ─── PDF assembly ─────────────────────────────────────────────────────────────
152
+ //
153
+ // A minimal, dependency-free, multi-page text PDF. The whole candidate body is rendered (no
154
+ // arbitrary truncation): lines are wrapped to the page width and paginated across as many A4 pages
155
+ // as needed. Text is encoded as single-byte WinAnsi (CP1252) and the Courier font declares
156
+ // /Encoding /WinAnsiEncoding, so German umlauts (ä ö ü Ä Ö Ü ß), the euro sign, and common
157
+ // typographic punctuation render correctly instead of as UTF-8 mojibake. No /CreationDate,
158
+ // no Producer, no random — byte-stable across identical runs.
159
+ const PDF_FONT_SIZE = 10;
160
+ const PDF_LEADING = 14;
161
+ const PDF_MARGIN_X = 50;
162
+ const PDF_TOP_Y = 792; // 842 page height − 50 top margin
163
+ const PDF_BOTTOM_Y = 56; // keep the last baseline above the bottom margin
164
+ const PDF_MAX_CHARS = 80; // Courier @10pt is 6pt/glyph → ~82 glyphs fit in 495pt; 80 leaves a margin
165
+ const PDF_LINES_PER_PAGE = Math.floor((PDF_TOP_Y - PDF_BOTTOM_Y) / PDF_LEADING); // 52
166
+ function pdfStr(s) {
167
+ return TEXT_ENC.encode(s);
168
+ }
169
+ function escapePdf(s) {
170
+ return s.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)");
171
+ }
172
+ // WinAnsi (CP1252) bytes for the code points that differ from Latin-1 in the 0x80–0x9F window.
173
+ const CP1252_HIGH = {
174
+ 0x20ac: 0x80,
175
+ 0x201a: 0x82,
176
+ 0x0192: 0x83,
177
+ 0x201e: 0x84,
178
+ 0x2026: 0x85,
179
+ 0x2020: 0x86,
180
+ 0x2021: 0x87,
181
+ 0x02c6: 0x88,
182
+ 0x2030: 0x89,
183
+ 0x0160: 0x8a,
184
+ 0x2039: 0x8b,
185
+ 0x0152: 0x8c,
186
+ 0x017d: 0x8e,
187
+ 0x2018: 0x91,
188
+ 0x2019: 0x92,
189
+ 0x201c: 0x93,
190
+ 0x201d: 0x94,
191
+ 0x2022: 0x95,
192
+ 0x2013: 0x96,
193
+ 0x2014: 0x97,
194
+ 0x02dc: 0x98,
195
+ 0x2122: 0x99,
196
+ 0x0161: 0x9a,
197
+ 0x203a: 0x9b,
198
+ 0x0153: 0x9c,
199
+ 0x017e: 0x9e,
200
+ 0x0178: 0x9f,
201
+ };
202
+ // Best-effort ASCII fold for common punctuation outside CP1252, so they degrade legibly (not to '?').
203
+ const PDF_ASCII_FOLD = {
204
+ 0x2010: 0x2d,
205
+ 0x2011: 0x2d,
206
+ 0x2012: 0x2d, // hyphen/figure/non-breaking dashes → '-'
207
+ 0x00a0: 0x20,
208
+ 0x2007: 0x20,
209
+ 0x202f: 0x20, // no-break / figure / narrow spaces → ' '
210
+ };
211
+ function winAnsiByte(cp) {
212
+ if (cp === 0x09)
213
+ return 0x20; // tab → space
214
+ if (cp < 0x20)
215
+ return 0x3f; // other C0 controls → '?'
216
+ if (cp <= 0x7e)
217
+ return cp; // printable ASCII
218
+ if (cp === 0x7f)
219
+ return 0x3f; // DEL
220
+ if (cp >= 0xa0 && cp <= 0xff)
221
+ return cp; // Latin-1 printable (umlauts, ß, accented letters)
222
+ return CP1252_HIGH[cp] ?? PDF_ASCII_FOLD[cp] ?? 0x3f;
223
+ }
224
+ function winAnsiEncode(text) {
225
+ const codePoints = Array.from(text); // iterate by code point (surrogate-safe)
226
+ const out = new Uint8Array(codePoints.length);
227
+ for (let i = 0; i < codePoints.length; i++) {
228
+ out[i] = winAnsiByte(codePoints[i]?.codePointAt(0) ?? 0x3f);
229
+ }
230
+ return out;
231
+ }
232
+ // Greedy word-aware wrap to `maxChars`; a single over-long token is hard-broken. Preserves blanks.
233
+ function wrapText(line, maxChars) {
234
+ if (line.length <= maxChars)
235
+ return [line];
236
+ const out = [];
237
+ let current = "";
238
+ for (const word of line.split(" ")) {
239
+ if (word.length > maxChars) {
240
+ if (current.length > 0)
241
+ out.push(current);
242
+ let rest = word;
243
+ while (rest.length > maxChars) {
244
+ out.push(rest.slice(0, maxChars));
245
+ rest = rest.slice(maxChars);
246
+ }
247
+ current = rest;
248
+ continue;
249
+ }
250
+ const candidate = current.length === 0 ? word : `${current} ${word}`;
251
+ if (candidate.length > maxChars) {
252
+ out.push(current);
253
+ current = word;
254
+ }
255
+ else {
256
+ current = candidate;
257
+ }
258
+ }
259
+ if (current.length > 0)
260
+ out.push(current);
261
+ return out.length > 0 ? out : [""];
262
+ }
263
+ function wrapBody(body) {
264
+ const out = [];
265
+ for (const line of body.split(/\r\n|\r|\n/u)) {
266
+ for (const wrapped of wrapText(line, PDF_MAX_CHARS))
267
+ out.push(wrapped);
268
+ }
269
+ return out;
270
+ }
271
+ function paginate(lines, perPage) {
272
+ const pages = [];
273
+ for (let i = 0; i < lines.length; i += perPage) {
274
+ pages.push(lines.slice(i, i + perPage));
275
+ }
276
+ return pages.length > 0 ? pages : [[""]];
277
+ }
278
+ // Build one page's content stream: position the text cursor, then emit each (escaped, WinAnsi) line.
279
+ function buildPageContent(lines) {
280
+ const chunks = [
281
+ pdfStr(`BT\n/F1 ${String(PDF_FONT_SIZE)} Tf\n${String(PDF_LEADING)} TL\n`),
282
+ pdfStr(`${String(PDF_MARGIN_X)} ${String(PDF_TOP_Y)} Td\n`),
283
+ ];
284
+ let first = true;
285
+ for (const line of lines) {
286
+ chunks.push(pdfStr(first ? "(" : "T* ("));
287
+ chunks.push(winAnsiEncode(escapePdf(line)));
288
+ chunks.push(pdfStr(") Tj\n"));
289
+ first = false;
290
+ }
291
+ chunks.push(pdfStr("ET"));
292
+ return concatBytes(chunks);
293
+ }
294
+ /**
295
+ * Assembles a deterministic, multi-page, text-only PDF from the given plain-text body. The entire
296
+ * body is rendered across as many pages as needed (no truncation). Byte-stable across identical runs.
297
+ */
298
+ export function assemblePdf(body, runId) {
299
+ const rawLines = [`Run: ${runId}`, "", ...wrapBody(body)];
300
+ const pages = paginate(rawLines, PDF_LINES_PER_PAGE);
301
+ const pageObjNums = pages.map((_, i) => 4 + 2 * i);
302
+ const maxObjNum = 3 + 2 * pages.length;
303
+ const objects = [
304
+ pdfStr("1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n"),
305
+ pdfStr(`2 0 obj\n<< /Type /Pages /Kids [${pageObjNums.map((n) => `${String(n)} 0 R`).join(" ")}]` +
306
+ ` /Count ${String(pages.length)} >>\nendobj\n`),
307
+ pdfStr("3 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Courier" +
308
+ " /Encoding /WinAnsiEncoding >>\nendobj\n"),
309
+ ];
310
+ pages.forEach((pageLines, i) => {
311
+ const pageNum = 4 + 2 * i;
312
+ const contentNum = pageNum + 1;
313
+ objects.push(pdfStr(`${String(pageNum)} 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842]` +
314
+ ` /Contents ${String(contentNum)} 0 R` +
315
+ ` /Resources << /Font << /F1 3 0 R >> >> >>\nendobj\n`));
316
+ const content = buildPageContent(pageLines);
317
+ objects.push(concatBytes([
318
+ pdfStr(`${String(contentNum)} 0 obj\n<< /Length ${String(content.length)} >>\nstream\n`),
319
+ content,
320
+ pdfStr("\nendstream\nendobj\n"),
321
+ ]));
322
+ });
323
+ const header = pdfStr("%PDF-1.4\n");
324
+ const offsets = [];
325
+ let pos = header.length;
326
+ for (const obj of objects) {
327
+ offsets.push(pos);
328
+ pos += obj.length;
329
+ }
330
+ const xrefOffset = pos;
331
+ const xref = buildPdfXref(offsets);
332
+ const trailer = pdfStr(`trailer\n<< /Size ${String(maxObjNum + 1)} /Root 1 0 R >>\n` +
333
+ `startxref\n${String(xrefOffset)}\n%%EOF\n`);
334
+ return concatBytes([header, ...objects, xref, trailer]);
335
+ }
336
+ // Build the PDF cross-reference table for the given object byte-offsets (object 0 is the free head).
337
+ function buildPdfXref(offsets) {
338
+ const rows = offsets.map((o) => `${String(o).padStart(10, "0")} 00000 n `);
339
+ const lines = ["xref", `0 ${String(offsets.length + 1)}`, "0000000000 65535 f ", ...rows];
340
+ return pdfStr(lines.join("\n") + "\n");
341
+ }
342
+ // Concatenate byte chunks into a single buffer.
343
+ function concatBytes(chunks) {
344
+ const totalLen = chunks.reduce((s, c) => s + c.length, 0);
345
+ const out = new Uint8Array(totalLen);
346
+ let pos = 0;
347
+ for (const chunk of chunks) {
348
+ out.set(chunk, pos);
349
+ pos += chunk.length;
350
+ }
351
+ return out;
352
+ }
@@ -0,0 +1,5 @@
1
+ import type { RouteContext, RouteResult, RouteDefinition } from "../routes.js";
2
+ import type { UiHandlerDeps } from "../deps.js";
3
+ export declare function handleQiExport(ctx: RouteContext, deps: UiHandlerDeps): Promise<RouteResult>;
4
+ export declare const QI_EXPORT_ROUTE_GROUP: readonly RouteDefinition[];
5
+ //# sourceMappingURL=exportRoutes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exportRoutes.d.ts","sourceRoot":"","sources":["../../src/qualityIntelligence/exportRoutes.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA8NhD,wBAAsB,cAAc,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CA2BjG;AA+HD,eAAO,MAAM,qBAAqB,EAAE,SAAS,eAAe,EAE3D,CAAC"}