@nebulacomponents/citable 1.19.0 → 1.21.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 (360) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +12 -1
  3. package/dist/universal/.agents/skills/citable/SKILL.md +11 -2
  4. package/dist/universal/.agents/skills/citable/VERSION +1 -1
  5. package/dist/universal/.agents/skills/citable/manifest.json +24 -12
  6. package/dist/universal/.agents/skills/citable/schemas/action-plan.schema.json +38 -1
  7. package/dist/universal/.agents/skills/citable/schemas/audit-coverage.schema.json +118 -0
  8. package/dist/universal/.agents/skills/citable/schemas/claim-evidence.schema.json +21 -0
  9. package/dist/universal/.agents/skills/citable/schemas/claim-verification.schema.json +18 -0
  10. package/dist/universal/.agents/skills/citable/schemas/collection-result.schema.json +35 -0
  11. package/dist/universal/.agents/skills/citable/schemas/config.schema.json +2 -0
  12. package/dist/universal/.agents/skills/citable/schemas/cro-report.schema.json +8 -1
  13. package/dist/universal/.agents/skills/citable/schemas/derivation.schema.json +18 -0
  14. package/dist/universal/.agents/skills/citable/schemas/external-comparison.schema.json +16 -0
  15. package/dist/universal/.agents/skills/citable/schemas/external-observation.schema.json +32 -0
  16. package/dist/universal/.agents/skills/citable/schemas/finding.schema.json +105 -2
  17. package/dist/universal/.agents/skills/citable/schemas/prompt-set.schema.json +47 -0
  18. package/dist/universal/.agents/skills/citable/schemas/remediation-verification.schema.json +12 -1
  19. package/dist/universal/.agents/skills/citable/schemas/representation-data.schema.json +21 -0
  20. package/dist/universal/.agents/skills/citable/schemas/research-dataset.schema.json +27 -0
  21. package/dist/universal/.agents/skills/citable/schemas/run.schema.json +15 -2
  22. package/dist/universal/.agents/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  23. package/dist/universal/.agents/skills/citable/schemas/search-report.schema.json +8 -1
  24. package/dist/universal/.agents/skills/citable/schemas/summary.schema.json +41 -0
  25. package/dist/universal/.claude/agents/citable/manifest.json +2 -2
  26. package/dist/universal/.claude/skills/citable/SKILL.md +11 -2
  27. package/dist/universal/.claude/skills/citable/VERSION +1 -1
  28. package/dist/universal/.claude/skills/citable/manifest.json +24 -12
  29. package/dist/universal/.claude/skills/citable/schemas/action-plan.schema.json +38 -1
  30. package/dist/universal/.claude/skills/citable/schemas/audit-coverage.schema.json +118 -0
  31. package/dist/universal/.claude/skills/citable/schemas/claim-evidence.schema.json +21 -0
  32. package/dist/universal/.claude/skills/citable/schemas/claim-verification.schema.json +18 -0
  33. package/dist/universal/.claude/skills/citable/schemas/collection-result.schema.json +35 -0
  34. package/dist/universal/.claude/skills/citable/schemas/config.schema.json +2 -0
  35. package/dist/universal/.claude/skills/citable/schemas/cro-report.schema.json +8 -1
  36. package/dist/universal/.claude/skills/citable/schemas/derivation.schema.json +18 -0
  37. package/dist/universal/.claude/skills/citable/schemas/external-comparison.schema.json +16 -0
  38. package/dist/universal/.claude/skills/citable/schemas/external-observation.schema.json +32 -0
  39. package/dist/universal/.claude/skills/citable/schemas/finding.schema.json +105 -2
  40. package/dist/universal/.claude/skills/citable/schemas/prompt-set.schema.json +47 -0
  41. package/dist/universal/.claude/skills/citable/schemas/remediation-verification.schema.json +12 -1
  42. package/dist/universal/.claude/skills/citable/schemas/representation-data.schema.json +21 -0
  43. package/dist/universal/.claude/skills/citable/schemas/research-dataset.schema.json +27 -0
  44. package/dist/universal/.claude/skills/citable/schemas/run.schema.json +15 -2
  45. package/dist/universal/.claude/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  46. package/dist/universal/.claude/skills/citable/schemas/search-report.schema.json +8 -1
  47. package/dist/universal/.claude/skills/citable/schemas/summary.schema.json +41 -0
  48. package/dist/universal/.cursor/skills/citable/SKILL.md +11 -2
  49. package/dist/universal/.cursor/skills/citable/VERSION +1 -1
  50. package/dist/universal/.cursor/skills/citable/manifest.json +24 -12
  51. package/dist/universal/.cursor/skills/citable/schemas/action-plan.schema.json +38 -1
  52. package/dist/universal/.cursor/skills/citable/schemas/audit-coverage.schema.json +118 -0
  53. package/dist/universal/.cursor/skills/citable/schemas/claim-evidence.schema.json +21 -0
  54. package/dist/universal/.cursor/skills/citable/schemas/claim-verification.schema.json +18 -0
  55. package/dist/universal/.cursor/skills/citable/schemas/collection-result.schema.json +35 -0
  56. package/dist/universal/.cursor/skills/citable/schemas/config.schema.json +2 -0
  57. package/dist/universal/.cursor/skills/citable/schemas/cro-report.schema.json +8 -1
  58. package/dist/universal/.cursor/skills/citable/schemas/derivation.schema.json +18 -0
  59. package/dist/universal/.cursor/skills/citable/schemas/external-comparison.schema.json +16 -0
  60. package/dist/universal/.cursor/skills/citable/schemas/external-observation.schema.json +32 -0
  61. package/dist/universal/.cursor/skills/citable/schemas/finding.schema.json +105 -2
  62. package/dist/universal/.cursor/skills/citable/schemas/prompt-set.schema.json +47 -0
  63. package/dist/universal/.cursor/skills/citable/schemas/remediation-verification.schema.json +12 -1
  64. package/dist/universal/.cursor/skills/citable/schemas/representation-data.schema.json +21 -0
  65. package/dist/universal/.cursor/skills/citable/schemas/research-dataset.schema.json +27 -0
  66. package/dist/universal/.cursor/skills/citable/schemas/run.schema.json +15 -2
  67. package/dist/universal/.cursor/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  68. package/dist/universal/.cursor/skills/citable/schemas/search-report.schema.json +8 -1
  69. package/dist/universal/.cursor/skills/citable/schemas/summary.schema.json +41 -0
  70. package/dist/universal/.gemini/skills/citable/SKILL.md +11 -2
  71. package/dist/universal/.gemini/skills/citable/VERSION +1 -1
  72. package/dist/universal/.gemini/skills/citable/manifest.json +24 -12
  73. package/dist/universal/.gemini/skills/citable/schemas/action-plan.schema.json +38 -1
  74. package/dist/universal/.gemini/skills/citable/schemas/audit-coverage.schema.json +118 -0
  75. package/dist/universal/.gemini/skills/citable/schemas/claim-evidence.schema.json +21 -0
  76. package/dist/universal/.gemini/skills/citable/schemas/claim-verification.schema.json +18 -0
  77. package/dist/universal/.gemini/skills/citable/schemas/collection-result.schema.json +35 -0
  78. package/dist/universal/.gemini/skills/citable/schemas/config.schema.json +2 -0
  79. package/dist/universal/.gemini/skills/citable/schemas/cro-report.schema.json +8 -1
  80. package/dist/universal/.gemini/skills/citable/schemas/derivation.schema.json +18 -0
  81. package/dist/universal/.gemini/skills/citable/schemas/external-comparison.schema.json +16 -0
  82. package/dist/universal/.gemini/skills/citable/schemas/external-observation.schema.json +32 -0
  83. package/dist/universal/.gemini/skills/citable/schemas/finding.schema.json +105 -2
  84. package/dist/universal/.gemini/skills/citable/schemas/prompt-set.schema.json +47 -0
  85. package/dist/universal/.gemini/skills/citable/schemas/remediation-verification.schema.json +12 -1
  86. package/dist/universal/.gemini/skills/citable/schemas/representation-data.schema.json +21 -0
  87. package/dist/universal/.gemini/skills/citable/schemas/research-dataset.schema.json +27 -0
  88. package/dist/universal/.gemini/skills/citable/schemas/run.schema.json +15 -2
  89. package/dist/universal/.gemini/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  90. package/dist/universal/.gemini/skills/citable/schemas/search-report.schema.json +8 -1
  91. package/dist/universal/.gemini/skills/citable/schemas/summary.schema.json +41 -0
  92. package/dist/universal/.github/skills/citable/SKILL.md +11 -2
  93. package/dist/universal/.github/skills/citable/VERSION +1 -1
  94. package/dist/universal/.github/skills/citable/manifest.json +24 -12
  95. package/dist/universal/.github/skills/citable/schemas/action-plan.schema.json +38 -1
  96. package/dist/universal/.github/skills/citable/schemas/audit-coverage.schema.json +118 -0
  97. package/dist/universal/.github/skills/citable/schemas/claim-evidence.schema.json +21 -0
  98. package/dist/universal/.github/skills/citable/schemas/claim-verification.schema.json +18 -0
  99. package/dist/universal/.github/skills/citable/schemas/collection-result.schema.json +35 -0
  100. package/dist/universal/.github/skills/citable/schemas/config.schema.json +2 -0
  101. package/dist/universal/.github/skills/citable/schemas/cro-report.schema.json +8 -1
  102. package/dist/universal/.github/skills/citable/schemas/derivation.schema.json +18 -0
  103. package/dist/universal/.github/skills/citable/schemas/external-comparison.schema.json +16 -0
  104. package/dist/universal/.github/skills/citable/schemas/external-observation.schema.json +32 -0
  105. package/dist/universal/.github/skills/citable/schemas/finding.schema.json +105 -2
  106. package/dist/universal/.github/skills/citable/schemas/prompt-set.schema.json +47 -0
  107. package/dist/universal/.github/skills/citable/schemas/remediation-verification.schema.json +12 -1
  108. package/dist/universal/.github/skills/citable/schemas/representation-data.schema.json +21 -0
  109. package/dist/universal/.github/skills/citable/schemas/research-dataset.schema.json +27 -0
  110. package/dist/universal/.github/skills/citable/schemas/run.schema.json +15 -2
  111. package/dist/universal/.github/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  112. package/dist/universal/.github/skills/citable/schemas/search-report.schema.json +8 -1
  113. package/dist/universal/.github/skills/citable/schemas/summary.schema.json +41 -0
  114. package/dist/universal/.kiro/skills/citable/SKILL.md +11 -2
  115. package/dist/universal/.kiro/skills/citable/VERSION +1 -1
  116. package/dist/universal/.kiro/skills/citable/manifest.json +24 -12
  117. package/dist/universal/.kiro/skills/citable/schemas/action-plan.schema.json +38 -1
  118. package/dist/universal/.kiro/skills/citable/schemas/audit-coverage.schema.json +118 -0
  119. package/dist/universal/.kiro/skills/citable/schemas/claim-evidence.schema.json +21 -0
  120. package/dist/universal/.kiro/skills/citable/schemas/claim-verification.schema.json +18 -0
  121. package/dist/universal/.kiro/skills/citable/schemas/collection-result.schema.json +35 -0
  122. package/dist/universal/.kiro/skills/citable/schemas/config.schema.json +2 -0
  123. package/dist/universal/.kiro/skills/citable/schemas/cro-report.schema.json +8 -1
  124. package/dist/universal/.kiro/skills/citable/schemas/derivation.schema.json +18 -0
  125. package/dist/universal/.kiro/skills/citable/schemas/external-comparison.schema.json +16 -0
  126. package/dist/universal/.kiro/skills/citable/schemas/external-observation.schema.json +32 -0
  127. package/dist/universal/.kiro/skills/citable/schemas/finding.schema.json +105 -2
  128. package/dist/universal/.kiro/skills/citable/schemas/prompt-set.schema.json +47 -0
  129. package/dist/universal/.kiro/skills/citable/schemas/remediation-verification.schema.json +12 -1
  130. package/dist/universal/.kiro/skills/citable/schemas/representation-data.schema.json +21 -0
  131. package/dist/universal/.kiro/skills/citable/schemas/research-dataset.schema.json +27 -0
  132. package/dist/universal/.kiro/skills/citable/schemas/run.schema.json +15 -2
  133. package/dist/universal/.kiro/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  134. package/dist/universal/.kiro/skills/citable/schemas/search-report.schema.json +8 -1
  135. package/dist/universal/.kiro/skills/citable/schemas/summary.schema.json +41 -0
  136. package/dist/universal/.opencode/skills/citable/SKILL.md +11 -2
  137. package/dist/universal/.opencode/skills/citable/VERSION +1 -1
  138. package/dist/universal/.opencode/skills/citable/manifest.json +24 -12
  139. package/dist/universal/.opencode/skills/citable/schemas/action-plan.schema.json +38 -1
  140. package/dist/universal/.opencode/skills/citable/schemas/audit-coverage.schema.json +118 -0
  141. package/dist/universal/.opencode/skills/citable/schemas/claim-evidence.schema.json +21 -0
  142. package/dist/universal/.opencode/skills/citable/schemas/claim-verification.schema.json +18 -0
  143. package/dist/universal/.opencode/skills/citable/schemas/collection-result.schema.json +35 -0
  144. package/dist/universal/.opencode/skills/citable/schemas/config.schema.json +2 -0
  145. package/dist/universal/.opencode/skills/citable/schemas/cro-report.schema.json +8 -1
  146. package/dist/universal/.opencode/skills/citable/schemas/derivation.schema.json +18 -0
  147. package/dist/universal/.opencode/skills/citable/schemas/external-comparison.schema.json +16 -0
  148. package/dist/universal/.opencode/skills/citable/schemas/external-observation.schema.json +32 -0
  149. package/dist/universal/.opencode/skills/citable/schemas/finding.schema.json +105 -2
  150. package/dist/universal/.opencode/skills/citable/schemas/prompt-set.schema.json +47 -0
  151. package/dist/universal/.opencode/skills/citable/schemas/remediation-verification.schema.json +12 -1
  152. package/dist/universal/.opencode/skills/citable/schemas/representation-data.schema.json +21 -0
  153. package/dist/universal/.opencode/skills/citable/schemas/research-dataset.schema.json +27 -0
  154. package/dist/universal/.opencode/skills/citable/schemas/run.schema.json +15 -2
  155. package/dist/universal/.opencode/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  156. package/dist/universal/.opencode/skills/citable/schemas/search-report.schema.json +8 -1
  157. package/dist/universal/.opencode/skills/citable/schemas/summary.schema.json +41 -0
  158. package/dist/universal/.pi/agent/skills/citable/SKILL.md +11 -2
  159. package/dist/universal/.pi/agent/skills/citable/VERSION +1 -1
  160. package/dist/universal/.pi/agent/skills/citable/manifest.json +24 -12
  161. package/dist/universal/.pi/agent/skills/citable/schemas/action-plan.schema.json +38 -1
  162. package/dist/universal/.pi/agent/skills/citable/schemas/audit-coverage.schema.json +118 -0
  163. package/dist/universal/.pi/agent/skills/citable/schemas/claim-evidence.schema.json +21 -0
  164. package/dist/universal/.pi/agent/skills/citable/schemas/claim-verification.schema.json +18 -0
  165. package/dist/universal/.pi/agent/skills/citable/schemas/collection-result.schema.json +35 -0
  166. package/dist/universal/.pi/agent/skills/citable/schemas/config.schema.json +2 -0
  167. package/dist/universal/.pi/agent/skills/citable/schemas/cro-report.schema.json +8 -1
  168. package/dist/universal/.pi/agent/skills/citable/schemas/derivation.schema.json +18 -0
  169. package/dist/universal/.pi/agent/skills/citable/schemas/external-comparison.schema.json +16 -0
  170. package/dist/universal/.pi/agent/skills/citable/schemas/external-observation.schema.json +32 -0
  171. package/dist/universal/.pi/agent/skills/citable/schemas/finding.schema.json +105 -2
  172. package/dist/universal/.pi/agent/skills/citable/schemas/prompt-set.schema.json +47 -0
  173. package/dist/universal/.pi/agent/skills/citable/schemas/remediation-verification.schema.json +12 -1
  174. package/dist/universal/.pi/agent/skills/citable/schemas/representation-data.schema.json +21 -0
  175. package/dist/universal/.pi/agent/skills/citable/schemas/research-dataset.schema.json +27 -0
  176. package/dist/universal/.pi/agent/skills/citable/schemas/run.schema.json +15 -2
  177. package/dist/universal/.pi/agent/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  178. package/dist/universal/.pi/agent/skills/citable/schemas/search-report.schema.json +8 -1
  179. package/dist/universal/.pi/agent/skills/citable/schemas/summary.schema.json +41 -0
  180. package/dist/universal/.qoder/skills/citable/SKILL.md +11 -2
  181. package/dist/universal/.qoder/skills/citable/VERSION +1 -1
  182. package/dist/universal/.qoder/skills/citable/manifest.json +24 -12
  183. package/dist/universal/.qoder/skills/citable/schemas/action-plan.schema.json +38 -1
  184. package/dist/universal/.qoder/skills/citable/schemas/audit-coverage.schema.json +118 -0
  185. package/dist/universal/.qoder/skills/citable/schemas/claim-evidence.schema.json +21 -0
  186. package/dist/universal/.qoder/skills/citable/schemas/claim-verification.schema.json +18 -0
  187. package/dist/universal/.qoder/skills/citable/schemas/collection-result.schema.json +35 -0
  188. package/dist/universal/.qoder/skills/citable/schemas/config.schema.json +2 -0
  189. package/dist/universal/.qoder/skills/citable/schemas/cro-report.schema.json +8 -1
  190. package/dist/universal/.qoder/skills/citable/schemas/derivation.schema.json +18 -0
  191. package/dist/universal/.qoder/skills/citable/schemas/external-comparison.schema.json +16 -0
  192. package/dist/universal/.qoder/skills/citable/schemas/external-observation.schema.json +32 -0
  193. package/dist/universal/.qoder/skills/citable/schemas/finding.schema.json +105 -2
  194. package/dist/universal/.qoder/skills/citable/schemas/prompt-set.schema.json +47 -0
  195. package/dist/universal/.qoder/skills/citable/schemas/remediation-verification.schema.json +12 -1
  196. package/dist/universal/.qoder/skills/citable/schemas/representation-data.schema.json +21 -0
  197. package/dist/universal/.qoder/skills/citable/schemas/research-dataset.schema.json +27 -0
  198. package/dist/universal/.qoder/skills/citable/schemas/run.schema.json +15 -2
  199. package/dist/universal/.qoder/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  200. package/dist/universal/.qoder/skills/citable/schemas/search-report.schema.json +8 -1
  201. package/dist/universal/.qoder/skills/citable/schemas/summary.schema.json +41 -0
  202. package/dist/universal/.rovodev/skills/citable/SKILL.md +11 -2
  203. package/dist/universal/.rovodev/skills/citable/VERSION +1 -1
  204. package/dist/universal/.rovodev/skills/citable/manifest.json +24 -12
  205. package/dist/universal/.rovodev/skills/citable/schemas/action-plan.schema.json +38 -1
  206. package/dist/universal/.rovodev/skills/citable/schemas/audit-coverage.schema.json +118 -0
  207. package/dist/universal/.rovodev/skills/citable/schemas/claim-evidence.schema.json +21 -0
  208. package/dist/universal/.rovodev/skills/citable/schemas/claim-verification.schema.json +18 -0
  209. package/dist/universal/.rovodev/skills/citable/schemas/collection-result.schema.json +35 -0
  210. package/dist/universal/.rovodev/skills/citable/schemas/config.schema.json +2 -0
  211. package/dist/universal/.rovodev/skills/citable/schemas/cro-report.schema.json +8 -1
  212. package/dist/universal/.rovodev/skills/citable/schemas/derivation.schema.json +18 -0
  213. package/dist/universal/.rovodev/skills/citable/schemas/external-comparison.schema.json +16 -0
  214. package/dist/universal/.rovodev/skills/citable/schemas/external-observation.schema.json +32 -0
  215. package/dist/universal/.rovodev/skills/citable/schemas/finding.schema.json +105 -2
  216. package/dist/universal/.rovodev/skills/citable/schemas/prompt-set.schema.json +47 -0
  217. package/dist/universal/.rovodev/skills/citable/schemas/remediation-verification.schema.json +12 -1
  218. package/dist/universal/.rovodev/skills/citable/schemas/representation-data.schema.json +21 -0
  219. package/dist/universal/.rovodev/skills/citable/schemas/research-dataset.schema.json +27 -0
  220. package/dist/universal/.rovodev/skills/citable/schemas/run.schema.json +15 -2
  221. package/dist/universal/.rovodev/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  222. package/dist/universal/.rovodev/skills/citable/schemas/search-report.schema.json +8 -1
  223. package/dist/universal/.rovodev/skills/citable/schemas/summary.schema.json +41 -0
  224. package/dist/universal/.trae/skills/citable/SKILL.md +11 -2
  225. package/dist/universal/.trae/skills/citable/VERSION +1 -1
  226. package/dist/universal/.trae/skills/citable/manifest.json +24 -12
  227. package/dist/universal/.trae/skills/citable/schemas/action-plan.schema.json +38 -1
  228. package/dist/universal/.trae/skills/citable/schemas/audit-coverage.schema.json +118 -0
  229. package/dist/universal/.trae/skills/citable/schemas/claim-evidence.schema.json +21 -0
  230. package/dist/universal/.trae/skills/citable/schemas/claim-verification.schema.json +18 -0
  231. package/dist/universal/.trae/skills/citable/schemas/collection-result.schema.json +35 -0
  232. package/dist/universal/.trae/skills/citable/schemas/config.schema.json +2 -0
  233. package/dist/universal/.trae/skills/citable/schemas/cro-report.schema.json +8 -1
  234. package/dist/universal/.trae/skills/citable/schemas/derivation.schema.json +18 -0
  235. package/dist/universal/.trae/skills/citable/schemas/external-comparison.schema.json +16 -0
  236. package/dist/universal/.trae/skills/citable/schemas/external-observation.schema.json +32 -0
  237. package/dist/universal/.trae/skills/citable/schemas/finding.schema.json +105 -2
  238. package/dist/universal/.trae/skills/citable/schemas/prompt-set.schema.json +47 -0
  239. package/dist/universal/.trae/skills/citable/schemas/remediation-verification.schema.json +12 -1
  240. package/dist/universal/.trae/skills/citable/schemas/representation-data.schema.json +21 -0
  241. package/dist/universal/.trae/skills/citable/schemas/research-dataset.schema.json +27 -0
  242. package/dist/universal/.trae/skills/citable/schemas/run.schema.json +15 -2
  243. package/dist/universal/.trae/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  244. package/dist/universal/.trae/skills/citable/schemas/search-report.schema.json +8 -1
  245. package/dist/universal/.trae/skills/citable/schemas/summary.schema.json +41 -0
  246. package/dist/universal/.trae-cn/skills/citable/SKILL.md +11 -2
  247. package/dist/universal/.trae-cn/skills/citable/VERSION +1 -1
  248. package/dist/universal/.trae-cn/skills/citable/manifest.json +24 -12
  249. package/dist/universal/.trae-cn/skills/citable/schemas/action-plan.schema.json +38 -1
  250. package/dist/universal/.trae-cn/skills/citable/schemas/audit-coverage.schema.json +118 -0
  251. package/dist/universal/.trae-cn/skills/citable/schemas/claim-evidence.schema.json +21 -0
  252. package/dist/universal/.trae-cn/skills/citable/schemas/claim-verification.schema.json +18 -0
  253. package/dist/universal/.trae-cn/skills/citable/schemas/collection-result.schema.json +35 -0
  254. package/dist/universal/.trae-cn/skills/citable/schemas/config.schema.json +2 -0
  255. package/dist/universal/.trae-cn/skills/citable/schemas/cro-report.schema.json +8 -1
  256. package/dist/universal/.trae-cn/skills/citable/schemas/derivation.schema.json +18 -0
  257. package/dist/universal/.trae-cn/skills/citable/schemas/external-comparison.schema.json +16 -0
  258. package/dist/universal/.trae-cn/skills/citable/schemas/external-observation.schema.json +32 -0
  259. package/dist/universal/.trae-cn/skills/citable/schemas/finding.schema.json +105 -2
  260. package/dist/universal/.trae-cn/skills/citable/schemas/prompt-set.schema.json +47 -0
  261. package/dist/universal/.trae-cn/skills/citable/schemas/remediation-verification.schema.json +12 -1
  262. package/dist/universal/.trae-cn/skills/citable/schemas/representation-data.schema.json +21 -0
  263. package/dist/universal/.trae-cn/skills/citable/schemas/research-dataset.schema.json +27 -0
  264. package/dist/universal/.trae-cn/skills/citable/schemas/run.schema.json +15 -2
  265. package/dist/universal/.trae-cn/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  266. package/dist/universal/.trae-cn/skills/citable/schemas/search-report.schema.json +8 -1
  267. package/dist/universal/.trae-cn/skills/citable/schemas/summary.schema.json +41 -0
  268. package/dist/universal/manifest.json +292 -148
  269. package/package.json +1 -1
  270. package/schemas/action-plan.schema.json +38 -1
  271. package/schemas/audit-coverage.schema.json +118 -0
  272. package/schemas/claim-evidence.schema.json +21 -0
  273. package/schemas/claim-verification.schema.json +18 -0
  274. package/schemas/collection-result.schema.json +35 -0
  275. package/schemas/config.schema.json +2 -0
  276. package/schemas/cro-report.schema.json +8 -1
  277. package/schemas/derivation.schema.json +18 -0
  278. package/schemas/external-comparison.schema.json +16 -0
  279. package/schemas/external-observation.schema.json +32 -0
  280. package/schemas/finding.schema.json +105 -2
  281. package/schemas/prompt-set.schema.json +47 -0
  282. package/schemas/remediation-verification.schema.json +12 -1
  283. package/schemas/representation-data.schema.json +21 -0
  284. package/schemas/research-dataset.schema.json +27 -0
  285. package/schemas/run.schema.json +15 -2
  286. package/schemas/search-discovery-data.schema.json +20 -0
  287. package/schemas/search-report.schema.json +8 -1
  288. package/schemas/summary.schema.json +41 -0
  289. package/skill/SKILL.md +11 -2
  290. package/src/acceptance/reproducibility.js +5 -25
  291. package/src/analysis/croRoadmap.js +3 -3
  292. package/src/analysis/strategicRoadmap.js +3 -3
  293. package/src/artifacts/interchange.js +2 -6
  294. package/src/cli/index.js +15 -3
  295. package/src/commands/actionPlan.js +46 -5
  296. package/src/commands/applyRemediation.js +5 -5
  297. package/src/commands/audit.js +75 -8
  298. package/src/commands/ciWorkflow.js +7 -2
  299. package/src/commands/compareSnapshots.js +155 -47
  300. package/src/commands/connect.js +24 -4
  301. package/src/commands/context.js +41 -2
  302. package/src/commands/croSuite.js +51 -13
  303. package/src/commands/delivery.js +7 -7
  304. package/src/commands/governance.js +9 -10
  305. package/src/commands/implementationKit.js +2 -1
  306. package/src/commands/init.js +8 -1
  307. package/src/commands/previewCro.js +1 -1
  308. package/src/commands/prioritize.js +3 -2
  309. package/src/commands/reviews.js +31 -5
  310. package/src/commands/roadmapCmd.js +7 -13
  311. package/src/commands/sweep.js +15 -2
  312. package/src/commands/verifyRemediation.js +94 -19
  313. package/src/connectors/collectionResult.js +80 -0
  314. package/src/connectors/ga4.js +46 -11
  315. package/src/connectors/gsc.js +45 -6
  316. package/src/connectors/index.js +1 -1
  317. package/src/connectors/webflow.js +140 -10
  318. package/src/connectors/wordpress.js +92 -8
  319. package/src/crawler/fetch.js +220 -24
  320. package/src/crawler/resourceValidity.js +119 -0
  321. package/src/crawler/sitemap.js +435 -16
  322. package/src/crawler/sitemapCollector.js +364 -0
  323. package/src/crawler/urlIdentity.js +97 -0
  324. package/src/detectors/agent.js +11 -0
  325. package/src/detectors/ans.js +16 -1
  326. package/src/detectors/arch.js +6 -0
  327. package/src/detectors/claim.js +9 -0
  328. package/src/detectors/crawl.js +7 -0
  329. package/src/detectors/cro.js +21 -0
  330. package/src/detectors/cwv.js +4 -0
  331. package/src/detectors/entity.js +7 -0
  332. package/src/detectors/evd.js +9 -0
  333. package/src/detectors/framework.js +28 -2
  334. package/src/detectors/geoReco.js +16 -0
  335. package/src/detectors/hreflang.js +3 -0
  336. package/src/detectors/lifeMeas.js +9 -0
  337. package/src/detectors/link.js +6 -1
  338. package/src/detectors/page.js +11 -0
  339. package/src/detectors/schemaData.js +16 -1
  340. package/src/detectors/tech.js +34 -3
  341. package/src/discovery/searchConsole.js +186 -0
  342. package/src/evidence/coverage.js +448 -0
  343. package/src/evidence/determination.js +157 -0
  344. package/src/evidence/downstream.js +110 -0
  345. package/src/evidence/external.js +251 -0
  346. package/src/evidence/hashes.js +109 -0
  347. package/src/evidence/run.js +68 -8
  348. package/src/extractor/page.js +29 -2
  349. package/src/extractor/site.js +298 -50
  350. package/src/reporting/executiveCroReport.js +36 -13
  351. package/src/reporting/executiveExport.js +45 -16
  352. package/src/reporting/executiveSearchReport.js +56 -22
  353. package/src/reporting/report.js +56 -9
  354. package/src/representation/prompts.js +117 -0
  355. package/src/representation/representation.js +186 -0
  356. package/src/shared/epistemicLanguage.js +86 -0
  357. package/src/shared/evidenceSourceResolver.js +48 -17
  358. package/src/shared/htmlEscape.js +8 -4
  359. package/src/shared/runPackageVerifier.js +99 -8
  360. package/src/shared/verifiedRunLoader.js +129 -0
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Helpers for keeping presentation language within the scope of its evidence.
3
+ *
4
+ * These checks intentionally target assurance phrases, rather than individual
5
+ * words such as `complete` or `verified` which are also legitimate schema and
6
+ * lifecycle states. A report may say that a package is checksum-verified or
7
+ * that a collection completed; it may not turn that fact into an unsupported
8
+ * corpus-wide assurance.
9
+ */
10
+
11
+ const UNSUPPORTED_ASSURANCE_PATTERNS = Object.freeze([
12
+ /\ball\s+(?:conversion\s+pathways|pages?|resources?|checks?|findings?).{0,40}\b(?:verified|clean|passed|complete)\b/i,
13
+ /\b(?:verified[- ]clean|clean\s+and\s+verified|no\s+issues)\b/i,
14
+ /\b100%\s+(?:clean|verified|complete|pass(?:ed)?|coverage|conversion|funnel)/i,
15
+ /\b(?:site[- ]wide|entire\s+(?:site|corpus|population))\s+(?:clean|verified|complete|resolved|no\s+issues)/i,
16
+ /\b(?:all|entire)\s+(?:site|corpus|population)\s+(?:passed|verified|clean|complete)\b/i,
17
+ /(?:^|\n)\s*(?:verified|clean|resolved|optimal|complete|site[- ]wide|entire|none|all|passed)\b/im,
18
+ /<(?:h[1-6]|span|strong|div)[^>]*>\s*(?:verified|clean|resolved|optimal|complete|site[- ]wide|entire|none|all|passed)\b/i,
19
+ ]);
20
+
21
+ function normaliseContext(context = {}) {
22
+ const coverage = context.coverage_status || context.coverageStatus || 'indeterminate';
23
+ const determination = context.determination_status || context.determinationStatus || 'indeterminate';
24
+ const evaluated = Number.isInteger(context.evaluated) ? context.evaluated : null;
25
+ const eligible = Number.isInteger(context.eligible) ? context.eligible : null;
26
+ const packageVerified = context.package_verified ?? context.packageVerified ?? false;
27
+ const legacy = context.legacy === true || context.integrity_mode === 'legacy_unverified';
28
+ return { coverage, determination, evaluated, eligible, packageVerified, legacy };
29
+ }
30
+
31
+ export function hasVerifiedEvidenceScope(context = {}) {
32
+ const state = normaliseContext(context);
33
+ return state.packageVerified === true
34
+ && context.integrity_mode === 'sealed'
35
+ && !state.legacy
36
+ && state.coverage === 'complete'
37
+ && state.determination === 'supported'
38
+ && Number.isInteger(state.evaluated)
39
+ && Number.isInteger(state.eligible)
40
+ && state.evaluated > 0
41
+ && state.eligible > 0
42
+ && state.evaluated === state.eligible;
43
+ }
44
+
45
+ /**
46
+ * Find assurance phrases that are unsafe for a presentation context.
47
+ * Complete, supported, verified packages may use the phrases when the caller
48
+ * supplies an explicit population; incomplete/legacy/empty evidence may not.
49
+ */
50
+ export function findEpistemicLanguageViolations(text, context = {}) {
51
+ const value = String(text ?? '');
52
+ const state = normaliseContext(context);
53
+ const cannotClaimCorpus = !hasVerifiedEvidenceScope(context);
54
+ if (!cannotClaimCorpus) return [];
55
+ return UNSUPPORTED_ASSURANCE_PATTERNS
56
+ .map((pattern) => {
57
+ const match = value.match(pattern);
58
+ return match ? { phrase: match[0], index: match.index ?? 0, pattern: pattern.source } : null;
59
+ })
60
+ .filter(Boolean);
61
+ }
62
+
63
+ export function assertEpistemicLanguage(text, context = {}) {
64
+ const violations = findEpistemicLanguageViolations(text, context);
65
+ if (violations.length) {
66
+ throw new Error(`unsupported assurance language: ${violations.map((item) => item.phrase).join('; ')}`);
67
+ }
68
+ return text;
69
+ }
70
+
71
+ /** A short, reusable disclosure for reports and machine-readable exports. */
72
+ export function evidenceScopeStatement(context = {}) {
73
+ const state = normaliseContext(context);
74
+ if (state.evaluated === 0 || state.eligible === 0) {
75
+ return 'No determination is available because no eligible resource was evaluated.';
76
+ }
77
+ if (state.coverage !== 'complete' || state.determination !== 'supported' || state.legacy || !state.packageVerified) {
78
+ const population = state.evaluated == null ? 'the evaluated subset' : `${state.evaluated} evaluated resource(s)`;
79
+ const denominator = state.eligible == null ? '' : ` of ${state.eligible} eligible`;
80
+ return `Coverage is ${state.coverage}; this statement applies only to ${population}${denominator}. Corpus-wide absence or cleanliness is not established.`;
81
+ }
82
+ const population = state.evaluated == null ? 'the evaluated population' : `${state.evaluated} evaluated resource(s)`;
83
+ return `This statement applies to ${population} under the supported evidence contract.`;
84
+ }
85
+
86
+ export const EPISTEMIC_LANGUAGE_PATTERNS = UNSUPPORTED_ASSURANCE_PATTERNS;
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { readJson, sha256, sha256File } from './io.js';
4
- import { verifyRunPackage, RunVerificationError } from './runPackageVerifier.js';
3
+ import { readJson, sha256 } from './io.js';
4
+ import { loadVerifiedRun } from './verifiedRunLoader.js';
5
5
  import { buildContext } from '../commands/context.js';
6
6
  import { selectDetectors } from '../detectors/index.js';
7
7
  import { runDetectors, indexTargets } from '../detectors/framework.js';
@@ -161,6 +161,12 @@ export async function resolveEvidenceSource(root, options = {}) {
161
161
  integrity_hash: sha256(findingsJson),
162
162
  generation_mode: generationMode,
163
163
  run_metadata: null,
164
+ package_verified: false,
165
+ integrity_mode: 'in_memory_unsealed',
166
+ legacy: false,
167
+ coverage: null,
168
+ coverage_status: 'indeterminate',
169
+ determination_status: 'indeterminate',
164
170
  };
165
171
  }
166
172
 
@@ -177,10 +183,14 @@ export async function resolveEvidenceSource(root, options = {}) {
177
183
  }
178
184
 
179
185
  try {
180
- const verification = verifyRunPackage(runPath, {
181
- requireFindings: true,
182
- requireCompleted: generationMode === 'CONTRACTUAL',
183
- requireChecksums: true,
186
+ // Historical packages are explicitly opened in legacy mode until all
187
+ // producers persist coverage.json. The loader still verifies the sealed
188
+ // package and marks their coverage indeterminate; it never invents a
189
+ // complete corpus.
190
+ const verification = loadVerifiedRun(runPath, {
191
+ requireCompletedExecution: generationMode === 'CONTRACTUAL',
192
+ allowLegacy: true,
193
+ requireCoverage: false,
184
194
  });
185
195
 
186
196
  return {
@@ -188,16 +198,19 @@ export async function resolveEvidenceSource(root, options = {}) {
188
198
  source_identifier: runId,
189
199
  findings: verification.findings,
190
200
  findings_count: verification.findingsCount,
191
- integrity_hash: sha256File(findPath),
201
+ integrity_hash: verification.package_hash,
192
202
  generation_mode: generationMode,
193
203
  run_metadata: verification.manifest,
194
204
  checksums_verified: verification.checksumsVerified,
205
+ package_verified: verification.verified === true && verification.integrity_mode === 'sealed',
206
+ integrity_mode: verification.integrity_mode,
207
+ legacy: verification.legacy === true,
208
+ coverage: verification.coverage,
209
+ coverage_status: verification.coverage_status,
210
+ determination_status: verification.determination_status,
195
211
  };
196
212
  } catch (err) {
197
- if (err instanceof RunVerificationError) {
198
- throw new FindingsInvalidError(runId, err.message);
199
- }
200
- throw err;
213
+ throw new FindingsInvalidError(runId, err.message);
201
214
  }
202
215
  }
203
216
 
@@ -225,6 +238,12 @@ export async function resolveEvidenceSource(root, options = {}) {
225
238
  generation_mode: generationMode,
226
239
  run_metadata: null,
227
240
  context: ctx,
241
+ package_verified: false,
242
+ integrity_mode: 'live_unsealed',
243
+ legacy: false,
244
+ coverage: ctx.coverage || null,
245
+ coverage_status: ctx.coverage?.coverage_status || 'indeterminate',
246
+ determination_status: ctx.coverage?.determination_status || 'indeterminate',
228
247
  };
229
248
  } catch (err) {
230
249
  throw new LiveInspectionFailedError(target, err.message);
@@ -243,12 +262,11 @@ export async function resolveEvidenceSource(root, options = {}) {
243
262
  const sorted = sortRunCandidatesChronologically(runsDir, candidateDirs);
244
263
  for (const candidateId of sorted) {
245
264
  const runPath = path.join(runsDir, candidateId);
246
- const findPath = path.join(runPath, 'findings.json');
247
265
  try {
248
- const verification = verifyRunPackage(runPath, {
249
- requireFindings: true,
250
- requireCompleted: false, // allow non-completed in discovery if valid
251
- requireChecksums: false,
266
+ const verification = loadVerifiedRun(runPath, {
267
+ requireCompletedExecution: false,
268
+ allowLegacy: true,
269
+ requireCoverage: false,
252
270
  });
253
271
 
254
272
  return {
@@ -256,9 +274,16 @@ export async function resolveEvidenceSource(root, options = {}) {
256
274
  source_identifier: candidateId,
257
275
  findings: verification.findings,
258
276
  findings_count: verification.findingsCount,
259
- integrity_hash: sha256File(findPath),
277
+ integrity_hash: verification.package_hash,
260
278
  generation_mode: generationMode,
261
279
  run_metadata: verification.manifest,
280
+ checksums_verified: verification.checksumsVerified,
281
+ package_verified: verification.verified === true && verification.integrity_mode === 'sealed',
282
+ integrity_mode: verification.integrity_mode,
283
+ legacy: verification.legacy === true,
284
+ coverage: verification.coverage,
285
+ coverage_status: verification.coverage_status,
286
+ determination_status: verification.determination_status,
262
287
  };
263
288
  } catch {
264
289
  // Try next candidate
@@ -278,6 +303,12 @@ export async function resolveEvidenceSource(root, options = {}) {
278
303
  integrity_hash: null,
279
304
  generation_mode: 'NON_CONTRACTUAL_SAMPLE',
280
305
  run_metadata: null,
306
+ package_verified: false,
307
+ integrity_mode: 'sample_unverified',
308
+ legacy: false,
309
+ coverage: null,
310
+ coverage_status: 'indeterminate',
311
+ determination_status: 'indeterminate',
281
312
  };
282
313
  }
283
314
 
@@ -26,7 +26,7 @@ export function escapeHtmlAttr(str) {
26
26
  return escapeHtml(str);
27
27
  }
28
28
 
29
- const SAFE_PROTOCOLS = new Set(['http:', 'https:', 'mailto:']);
29
+ const SAFE_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'ftp:']);
30
30
 
31
31
  export function sanitizeUrl(urlStr, fallback = '#') {
32
32
  if (!urlStr || typeof urlStr !== 'string') return fallback;
@@ -38,11 +38,15 @@ export function sanitizeUrl(urlStr, fallback = '#') {
38
38
  try {
39
39
  const parsed = new URL(trimmed);
40
40
  if (SAFE_PROTOCOLS.has(parsed.protocol)) {
41
- return escapeHtmlAttr(trimmed);
41
+ // Additional substring sanitization: ensure no CRLF injection via encoded newlines
42
+ const normalized = parsed.href.replace(/\r\n|\r/g, '\n');
43
+ return escapeHtmlAttr(normalized);
42
44
  }
43
- return fallback;
45
+ // Unsafe protocol: return fully sanitized fallback
46
+ return escapeHtmlAttr(fallback);
44
47
  } catch {
45
- return fallback;
48
+ // Invalid URL: return sanitized fallback
49
+ return escapeHtmlAttr(fallback);
46
50
  }
47
51
  }
48
52
 
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { readJson, sha256File } from './io.js';
3
+ import { sha256 } from './io.js';
4
4
  import { validateAgainst } from './schemaValidator.js';
5
5
 
6
6
  export class RunVerificationError extends Error {
@@ -12,6 +12,17 @@ export class RunVerificationError extends Error {
12
12
  }
13
13
  }
14
14
 
15
+ function readStableBytes(file, runDir, relative) {
16
+ const first = fs.readFileSync(file);
17
+ const second = fs.readFileSync(file);
18
+ if (!first.equals(second)) {
19
+ throw new RunVerificationError(`Artifact changed while being verified: ${relative}`, {
20
+ code: 'PACKAGE_MUTATION', runDir, file: relative,
21
+ });
22
+ }
23
+ return first;
24
+ }
25
+
15
26
  /**
16
27
  * Verifies the cryptographic and structural integrity of an audit run evidence package.
17
28
  *
@@ -28,13 +39,24 @@ export function verifyRunPackage(runDir, options = {}) {
28
39
  requireFindings = true,
29
40
  requireCompleted = false,
30
41
  requireChecksums = true,
42
+ ignoredFiles = [],
31
43
  } = options;
32
44
 
33
45
  if (!runDir || !fs.existsSync(runDir)) {
34
46
  throw new RunVerificationError(`Run directory not found: ${runDir}`, { code: 'RUN_NOT_FOUND', runDir });
35
47
  }
48
+ let rootStat;
49
+ try { rootStat = fs.lstatSync(runDir); } catch (error) {
50
+ throw new RunVerificationError(`Run directory cannot be inspected: ${error.message}`, { code: 'RUN_NOT_FOUND', runDir });
51
+ }
52
+ if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
53
+ throw new RunVerificationError(`Run path is not a real directory: ${runDir}`, { code: 'RUN_PATH_INVALID', runDir });
54
+ }
36
55
 
37
56
  const manifestPath = path.join(runDir, 'manifest.json');
57
+ if (fs.existsSync(manifestPath) && fs.lstatSync(manifestPath).isSymbolicLink()) {
58
+ throw new RunVerificationError('Run manifest.json is a symbolic link', { code: 'PACKAGE_SYMLINK', runDir, file: 'manifest.json' });
59
+ }
38
60
  if (!fs.existsSync(manifestPath)) {
39
61
  throw new RunVerificationError(`Run package is missing manifest.json at ${manifestPath}`, {
40
62
  code: 'MANIFEST_MISSING',
@@ -44,7 +66,7 @@ export function verifyRunPackage(runDir, options = {}) {
44
66
 
45
67
  let manifest;
46
68
  try {
47
- manifest = readJson(manifestPath);
69
+ manifest = JSON.parse(readStableBytes(manifestPath, runDir, 'manifest.json').toString('utf8'));
48
70
  } catch (err) {
49
71
  throw new RunVerificationError(`Run manifest.json is invalid JSON: ${err.message}`, {
50
72
  code: 'MANIFEST_INVALID',
@@ -53,6 +75,12 @@ export function verifyRunPackage(runDir, options = {}) {
53
75
  }
54
76
 
55
77
  const schemaValidation = validateAgainst('run.schema.json', manifest);
78
+ if (Object.prototype.hasOwnProperty.call(manifest, 'schema_version')
79
+ && ![1, 2].includes(manifest.schema_version)) {
80
+ throw new RunVerificationError(`Unsupported run manifest schema_version: ${String(manifest.schema_version)}`, {
81
+ code: 'MANIFEST_SCHEMA_UNSUPPORTED', runDir, schema_version: manifest.schema_version,
82
+ });
83
+ }
56
84
  if (!schemaValidation.valid) {
57
85
  throw new RunVerificationError(`Run manifest violates run.schema.json: ${schemaValidation.errors.join('; ')}`, {
58
86
  code: 'MANIFEST_SCHEMA_INVALID',
@@ -69,42 +97,94 @@ export function verifyRunPackage(runDir, options = {}) {
69
97
  });
70
98
  }
71
99
 
100
+ // A sealed run is closed-world: every regular file except the checksum
101
+ // index itself must be listed, and every listed path must be safe. Do not
102
+ // use stat() here because it follows symlinks and could verify bytes outside
103
+ // the package directory.
104
+ const packageFiles = [];
105
+ const walk = (directory) => {
106
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
107
+ const absolute = path.join(directory, entry.name);
108
+ const relative = path.relative(runDir, absolute).split(path.sep).join('/');
109
+ if (entry.isSymbolicLink()) {
110
+ throw new RunVerificationError(`Run package contains symbolic link: ${relative}`, {
111
+ code: 'PACKAGE_SYMLINK', runDir, file: relative,
112
+ });
113
+ }
114
+ if (entry.isDirectory()) walk(absolute);
115
+ else if (entry.isFile()) packageFiles.push(relative);
116
+ else throw new RunVerificationError(`Run package contains unsupported filesystem entry: ${relative}`, {
117
+ code: 'PACKAGE_ENTRY_INVALID', runDir, file: relative,
118
+ });
119
+ }
120
+ };
121
+ walk(runDir);
122
+ const ignored = new Set(ignoredFiles);
123
+
72
124
  // Verify checksums.json
73
125
  const checksumsPath = path.join(runDir, 'checksums.json');
74
126
  let checksumsVerified = false;
127
+ let artifactHashes = {};
128
+ const artifactBytes = new Map();
129
+ const retainedArtifactNames = new Set(['findings.json', 'coverage.json', 'summary.json']);
75
130
  if (fs.existsSync(checksumsPath)) {
131
+ if (fs.lstatSync(checksumsPath).isSymbolicLink()) throw new RunVerificationError('checksums.json is a symbolic link', { code: 'PACKAGE_SYMLINK', runDir, file: 'checksums.json' });
76
132
  let checksums;
77
133
  try {
78
- checksums = readJson(checksumsPath);
134
+ checksums = JSON.parse(readStableBytes(checksumsPath, runDir, 'checksums.json').toString('utf8'));
79
135
  } catch (err) {
80
136
  throw new RunVerificationError(`checksums.json is invalid JSON: ${err.message}`, {
81
137
  code: 'CHECKSUMS_INVALID',
82
138
  runDir,
83
139
  });
84
140
  }
141
+ artifactHashes = checksums;
85
142
 
86
143
  const tamperedFiles = [];
87
144
  const missingFiles = [];
88
145
 
146
+ const safePath = (value) => typeof value === 'string'
147
+ && value.length > 0
148
+ && !path.isAbsolute(value)
149
+ && !value.includes('\\')
150
+ && !value.split('/').includes('..')
151
+ && !value.split('/').includes('')
152
+ && !/^[a-z][a-z0-9+.-]*:/i.test(value);
89
153
  for (const [relPath, expectedHash] of Object.entries(checksums)) {
154
+ if (!safePath(relPath) || relPath === 'checksums.json') {
155
+ throw new RunVerificationError(`unsafe checksum path (escapes the run package): ${relPath}`, {
156
+ code: 'CHECKSUM_PATH_INVALID', runDir, file: relPath,
157
+ });
158
+ }
90
159
  const artifactPath = path.join(runDir, relPath);
91
160
  if (!fs.existsSync(artifactPath)) {
92
161
  missingFiles.push(relPath);
93
162
  continue;
94
163
  }
95
- const actualHash = sha256File(artifactPath);
164
+ const artifactStat = fs.lstatSync(artifactPath);
165
+ if (artifactStat.isSymbolicLink() || !artifactStat.isFile()) {
166
+ throw new RunVerificationError(`checksum artifact is not a regular file: ${relPath}`, { code: 'PACKAGE_SYMLINK', runDir, file: relPath });
167
+ }
168
+ const bytes = readStableBytes(artifactPath, runDir, relPath);
169
+ if (retainedArtifactNames.has(relPath)) artifactBytes.set(relPath, bytes);
170
+ const actualHash = sha256(bytes);
96
171
  if (actualHash !== expectedHash) {
97
172
  tamperedFiles.push({ file: relPath, expected: expectedHash, actual: actualHash });
98
173
  }
99
174
  }
100
175
 
101
- if (tamperedFiles.length > 0 || missingFiles.length > 0) {
176
+ const expectedFiles = Object.keys(checksums).sort();
177
+ const actualFiles = packageFiles.filter((file) => file !== 'checksums.json' && !ignored.has(file)).sort();
178
+ const unexpectedFiles = actualFiles.filter((file) => !expectedFiles.includes(file));
179
+ const unlistedFiles = expectedFiles.filter((file) => !actualFiles.includes(file));
180
+ if (tamperedFiles.length > 0 || missingFiles.length > 0 || unexpectedFiles.length > 0 || unlistedFiles.length > 0) {
102
181
  throw new RunVerificationError(
103
- `Cryptographic verification failed for run package: ${tamperedFiles.length} tampered files, ${missingFiles.length} missing files`,
182
+ `Cryptographic verification failed for run package (checksum mismatch; integrity failed; completeness failure; unsealed): ${tamperedFiles.length} tampered files, ${missingFiles.length + unlistedFiles.length} missing files, ${unexpectedFiles.length} unexpected files`,
104
183
  {
105
184
  code: 'CHECKSUM_MISMATCH',
106
185
  tamperedFiles,
107
- missingFiles,
186
+ missingFiles: [...missingFiles, ...unlistedFiles],
187
+ unexpectedFiles,
108
188
  runDir,
109
189
  }
110
190
  );
@@ -122,10 +202,19 @@ export function verifyRunPackage(runDir, options = {}) {
122
202
  let findings = null;
123
203
  if (fs.existsSync(findingsPath)) {
124
204
  try {
125
- findings = readJson(findingsPath);
205
+ if (fs.lstatSync(findingsPath).isSymbolicLink()) throw new Error('findings.json is a symbolic link');
206
+ const findingsBytes = artifactBytes.get('findings.json') || readStableBytes(findingsPath, runDir, 'findings.json');
207
+ artifactBytes.set('findings.json', findingsBytes);
208
+ findings = JSON.parse(findingsBytes.toString('utf8'));
126
209
  if (!Array.isArray(findings)) {
127
210
  throw new Error('findings.json must contain an array of findings');
128
211
  }
212
+ for (const [index, finding] of findings.entries()) {
213
+ const findingValidation = validateAgainst('finding.schema.json', finding);
214
+ if (!findingValidation.valid) {
215
+ throw new Error(`finding[${index}] violates finding.schema.json: ${findingValidation.errors.join('; ')}`);
216
+ }
217
+ }
129
218
  } catch (err) {
130
219
  throw new RunVerificationError(`findings.json is malformed: ${err.message}`, {
131
220
  code: 'FINDINGS_MALFORMED',
@@ -149,5 +238,7 @@ export function verifyRunPackage(runDir, options = {}) {
149
238
  findingsPath: fs.existsSync(findingsPath) ? findingsPath : null,
150
239
  findingsCount: Array.isArray(findings) ? findings.length : 0,
151
240
  findings,
241
+ artifactHashes,
242
+ artifactBytes,
152
243
  };
153
244
  }
@@ -0,0 +1,129 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { readJson, sha256File } from './io.js';
4
+ import { verifyRunPackage, RunVerificationError } from './runPackageVerifier.js';
5
+ import { validateAgainst } from './schemaValidator.js';
6
+
7
+ export const VERIFIED_RUN_LOADER_VERSION = 'verified-run-loader-v1';
8
+
9
+ export class VerifiedRunLoadError extends Error {
10
+ constructor(message, details = {}) {
11
+ super(message);
12
+ this.name = 'VerifiedRunLoadError';
13
+ this.code = details.code || 'VERIFIED_RUN_LOAD_FAILED';
14
+ this.details = details;
15
+ }
16
+ }
17
+
18
+ function readContractArtifact(runDir, file, schema, { required = true, bytes = null } = {}) {
19
+ const filePath = path.join(runDir, file);
20
+ if (!fs.existsSync(filePath)) {
21
+ if (required) throw new VerifiedRunLoadError(`Verified run is missing ${file}`, { code: 'ARTIFACT_MISSING', file });
22
+ return null;
23
+ }
24
+ if (fs.lstatSync(filePath).isSymbolicLink()) {
25
+ throw new VerifiedRunLoadError(`${file} is a symbolic link`, { code: 'PACKAGE_SYMLINK', file });
26
+ }
27
+ let value;
28
+ try {
29
+ value = bytes ? JSON.parse(bytes.toString('utf8')) : readJson(filePath);
30
+ } catch (error) {
31
+ throw new VerifiedRunLoadError(`${file} is invalid JSON: ${error.message}`, { code: 'ARTIFACT_INVALID', file });
32
+ }
33
+ const validation = schema ? validateAgainst(schema, value) : { valid: true, errors: [] };
34
+ if (!validation.valid) {
35
+ throw new VerifiedRunLoadError(`${file} violates ${schema}: ${validation.errors.join('; ')}`, {
36
+ code: 'ARTIFACT_SCHEMA_INVALID', file, errors: validation.errors,
37
+ });
38
+ }
39
+ return value;
40
+ }
41
+
42
+ function readFindingsArtifact(runDir, bytes = null) {
43
+ const findings = readContractArtifact(runDir, 'findings.json', null, { bytes });
44
+ if (!Array.isArray(findings)) throw new VerifiedRunLoadError('findings.json must contain an array of findings', { code: 'ARTIFACT_SCHEMA_INVALID', file: 'findings.json' });
45
+ for (const [index, finding] of findings.entries()) {
46
+ const validation = validateAgainst('finding.schema.json', finding);
47
+ if (!validation.valid) throw new VerifiedRunLoadError(`findings.json finding[${index}] violates finding.schema.json: ${validation.errors.join('; ')}`, { code: 'ARTIFACT_SCHEMA_INVALID', file: 'findings.json' });
48
+ }
49
+ return findings;
50
+ }
51
+
52
+ /**
53
+ * Load a run only after its closed-world checksum seal and execution contracts
54
+ * have been verified. Consumers must use this API rather than reading
55
+ * findings.json directly: the returned findings are bound to the verified
56
+ * package, manifest, and (when present) coverage artifact.
57
+ *
58
+ * Legacy packages can be opened explicitly for migration. Their coverage is
59
+ * indeterminate and never receives a synthesized complete default.
60
+ */
61
+ export function loadVerifiedRun(runDir, {
62
+ requireCompletedExecution = true,
63
+ allowLegacy = false,
64
+ requireCoverage = !allowLegacy,
65
+ } = {}) {
66
+ try {
67
+ let verification;
68
+ try {
69
+ verification = verifyRunPackage(runDir, {
70
+ requireFindings: true,
71
+ requireCompleted: requireCompletedExecution,
72
+ requireChecksums: !allowLegacy,
73
+ });
74
+ } catch (error) {
75
+ if (!allowLegacy || !['CHECKSUMS_MISSING', 'MANIFEST_MISSING'].includes(error.code)) throw error;
76
+ const manifestPath = path.join(runDir, 'manifest.json');
77
+ const manifest = fs.existsSync(manifestPath) ? readJson(manifestPath) : { run_id: path.basename(runDir), status: 'incomplete' };
78
+ const findings = readFindingsArtifact(runDir);
79
+ const coverageFile = path.join(runDir, 'coverage.json');
80
+ const coverage = fs.existsSync(coverageFile) ? readContractArtifact(runDir, 'coverage.json', 'audit-coverage.schema.json') : null;
81
+ const summary = readContractArtifact(runDir, 'summary.json', 'summary.schema.json', { required: false });
82
+ return {
83
+ verified: false, verification_version: VERIFIED_RUN_LOADER_VERSION,
84
+ integrity_mode: 'legacy_unverified', package_dir: path.resolve(runDir),
85
+ package_hash: null, manifest, findings, findingsCount: findings.length,
86
+ coverage, summary, legacy: true,
87
+ coverage_status: coverage?.coverage_status || 'indeterminate', determination_status: 'indeterminate',
88
+ checksumsVerified: false,
89
+ artifactHashes: {
90
+ ...(fs.existsSync(path.join(runDir, 'manifest.json')) ? { 'manifest.json': sha256File(path.join(runDir, 'manifest.json')) } : {}),
91
+ 'findings.json': sha256File(path.join(runDir, 'findings.json')),
92
+ ...(fs.existsSync(coverageFile) ? { 'coverage.json': sha256File(coverageFile) } : {}),
93
+ },
94
+ };
95
+ }
96
+
97
+ const coveragePath = path.join(runDir, 'coverage.json');
98
+ const hasCoverage = fs.existsSync(coveragePath);
99
+ if (!hasCoverage && !allowLegacy && requireCoverage) {
100
+ throw new VerifiedRunLoadError('Verified run is missing coverage.json; use explicit legacy mode to open historical packages', {
101
+ code: 'COVERAGE_MISSING',
102
+ });
103
+ }
104
+ const coverage = hasCoverage ? readContractArtifact(runDir, 'coverage.json', 'audit-coverage.schema.json', { bytes: verification.artifactBytes.get('coverage.json') }) : null;
105
+ const summary = readContractArtifact(runDir, 'summary.json', 'summary.schema.json', { required: false, bytes: verification.artifactBytes.get('summary.json') });
106
+
107
+ return {
108
+ ...verification,
109
+ verified: hasCoverage,
110
+ verification_version: VERIFIED_RUN_LOADER_VERSION,
111
+ integrity_mode: hasCoverage ? 'sealed' : 'legacy_unverified',
112
+ package_dir: path.resolve(runDir),
113
+ package_hash: verification.checksumsVerified ? sha256File(path.join(runDir, 'checksums.json')) : null,
114
+ findings: verification.findings,
115
+ coverage,
116
+ summary,
117
+ legacy: !hasCoverage,
118
+ coverage_status: coverage?.coverage_status || 'indeterminate',
119
+ determination_status: coverage ? verification.manifest.determination_status : 'indeterminate',
120
+ artifactHashes: verification.artifactHashes,
121
+ };
122
+ } catch (error) {
123
+ if (error instanceof VerifiedRunLoadError) throw error;
124
+ if (error instanceof RunVerificationError) {
125
+ throw new VerifiedRunLoadError(error.message, { code: error.code, cause: error });
126
+ }
127
+ throw new VerifiedRunLoadError(error.message, { cause: error });
128
+ }
129
+ }