@nebulacomponents/citable 1.13.1 → 1.15.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 (359) hide show
  1. package/CHANGELOG.md +312 -0
  2. package/README.md +44 -6
  3. package/dist/universal/.agents/skills/citable/SKILL.md +22 -8
  4. package/dist/universal/.agents/skills/citable/VERSION +1 -1
  5. package/dist/universal/.agents/skills/citable/agents/citable-auditor.md +64 -0
  6. package/dist/universal/.agents/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  7. package/dist/universal/.agents/skills/citable/commands/README.md +4 -1
  8. package/dist/universal/.agents/skills/citable/commands/action-findings.md +9 -1
  9. package/dist/universal/.agents/skills/citable/commands/observe-and-act.md +62 -8
  10. package/dist/universal/.agents/skills/citable/commands/plan-audit.md +35 -0
  11. package/dist/universal/.agents/skills/citable/commands/reporting.md +57 -0
  12. package/dist/universal/.agents/skills/citable/manifest.json +29 -16
  13. package/dist/universal/.agents/skills/citable/schemas/action-plan.schema.json +13 -0
  14. package/dist/universal/.agents/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  15. package/dist/universal/.agents/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  16. package/dist/universal/.agents/skills/citable/schemas/common.defs.json +12 -1
  17. package/dist/universal/.agents/skills/citable/schemas/corroboration-import.schema.json +48 -0
  18. package/dist/universal/.agents/skills/citable/schemas/entity-graph.schema.json +75 -0
  19. package/dist/universal/.agents/skills/citable/schemas/entity.schema.json +13 -0
  20. package/dist/universal/.agents/skills/citable/schemas/observation.schema.json +1 -1
  21. package/dist/universal/.agents/skills/citable/schemas/page.schema.json +3 -0
  22. package/dist/universal/.agents/skills/citable/schemas/regional-network-import.schema.json +55 -0
  23. package/dist/universal/.agents/skills/citable/schemas/schedule.schema.json +1 -1
  24. package/dist/universal/.agents/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  25. package/dist/universal/.agents/skills/citable/scripts/README.md +3 -1
  26. package/dist/universal/.claude/agents/citable/citable-auditor.md +64 -0
  27. package/dist/universal/.claude/agents/citable/citable-semantic-reviewer.md +66 -0
  28. package/dist/universal/.claude/agents/citable/manifest.json +12 -0
  29. package/dist/universal/.claude/skills/citable/SKILL.md +22 -8
  30. package/dist/universal/.claude/skills/citable/VERSION +1 -1
  31. package/dist/universal/.claude/skills/citable/agents/citable-auditor.md +64 -0
  32. package/dist/universal/.claude/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  33. package/dist/universal/.claude/skills/citable/commands/README.md +4 -1
  34. package/dist/universal/.claude/skills/citable/commands/action-findings.md +9 -1
  35. package/dist/universal/.claude/skills/citable/commands/observe-and-act.md +62 -8
  36. package/dist/universal/.claude/skills/citable/commands/plan-audit.md +35 -0
  37. package/dist/universal/.claude/skills/citable/commands/reporting.md +57 -0
  38. package/dist/universal/.claude/skills/citable/manifest.json +34 -16
  39. package/dist/universal/.claude/skills/citable/schemas/action-plan.schema.json +13 -0
  40. package/dist/universal/.claude/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  41. package/dist/universal/.claude/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  42. package/dist/universal/.claude/skills/citable/schemas/common.defs.json +12 -1
  43. package/dist/universal/.claude/skills/citable/schemas/corroboration-import.schema.json +48 -0
  44. package/dist/universal/.claude/skills/citable/schemas/entity-graph.schema.json +75 -0
  45. package/dist/universal/.claude/skills/citable/schemas/entity.schema.json +13 -0
  46. package/dist/universal/.claude/skills/citable/schemas/observation.schema.json +1 -1
  47. package/dist/universal/.claude/skills/citable/schemas/page.schema.json +3 -0
  48. package/dist/universal/.claude/skills/citable/schemas/regional-network-import.schema.json +55 -0
  49. package/dist/universal/.claude/skills/citable/schemas/schedule.schema.json +1 -1
  50. package/dist/universal/.claude/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  51. package/dist/universal/.claude/skills/citable/scripts/README.md +3 -1
  52. package/dist/universal/.cursor/skills/citable/SKILL.md +22 -8
  53. package/dist/universal/.cursor/skills/citable/VERSION +1 -1
  54. package/dist/universal/.cursor/skills/citable/agents/citable-auditor.md +64 -0
  55. package/dist/universal/.cursor/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  56. package/dist/universal/.cursor/skills/citable/commands/README.md +4 -1
  57. package/dist/universal/.cursor/skills/citable/commands/action-findings.md +9 -1
  58. package/dist/universal/.cursor/skills/citable/commands/observe-and-act.md +62 -8
  59. package/dist/universal/.cursor/skills/citable/commands/plan-audit.md +35 -0
  60. package/dist/universal/.cursor/skills/citable/commands/reporting.md +57 -0
  61. package/dist/universal/.cursor/skills/citable/manifest.json +29 -16
  62. package/dist/universal/.cursor/skills/citable/schemas/action-plan.schema.json +13 -0
  63. package/dist/universal/.cursor/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  64. package/dist/universal/.cursor/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  65. package/dist/universal/.cursor/skills/citable/schemas/common.defs.json +12 -1
  66. package/dist/universal/.cursor/skills/citable/schemas/corroboration-import.schema.json +48 -0
  67. package/dist/universal/.cursor/skills/citable/schemas/entity-graph.schema.json +75 -0
  68. package/dist/universal/.cursor/skills/citable/schemas/entity.schema.json +13 -0
  69. package/dist/universal/.cursor/skills/citable/schemas/observation.schema.json +1 -1
  70. package/dist/universal/.cursor/skills/citable/schemas/page.schema.json +3 -0
  71. package/dist/universal/.cursor/skills/citable/schemas/regional-network-import.schema.json +55 -0
  72. package/dist/universal/.cursor/skills/citable/schemas/schedule.schema.json +1 -1
  73. package/dist/universal/.cursor/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  74. package/dist/universal/.cursor/skills/citable/scripts/README.md +3 -1
  75. package/dist/universal/.gemini/skills/citable/SKILL.md +22 -8
  76. package/dist/universal/.gemini/skills/citable/VERSION +1 -1
  77. package/dist/universal/.gemini/skills/citable/agents/citable-auditor.md +64 -0
  78. package/dist/universal/.gemini/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  79. package/dist/universal/.gemini/skills/citable/commands/README.md +4 -1
  80. package/dist/universal/.gemini/skills/citable/commands/action-findings.md +9 -1
  81. package/dist/universal/.gemini/skills/citable/commands/observe-and-act.md +62 -8
  82. package/dist/universal/.gemini/skills/citable/commands/plan-audit.md +35 -0
  83. package/dist/universal/.gemini/skills/citable/commands/reporting.md +57 -0
  84. package/dist/universal/.gemini/skills/citable/manifest.json +29 -16
  85. package/dist/universal/.gemini/skills/citable/schemas/action-plan.schema.json +13 -0
  86. package/dist/universal/.gemini/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  87. package/dist/universal/.gemini/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  88. package/dist/universal/.gemini/skills/citable/schemas/common.defs.json +12 -1
  89. package/dist/universal/.gemini/skills/citable/schemas/corroboration-import.schema.json +48 -0
  90. package/dist/universal/.gemini/skills/citable/schemas/entity-graph.schema.json +75 -0
  91. package/dist/universal/.gemini/skills/citable/schemas/entity.schema.json +13 -0
  92. package/dist/universal/.gemini/skills/citable/schemas/observation.schema.json +1 -1
  93. package/dist/universal/.gemini/skills/citable/schemas/page.schema.json +3 -0
  94. package/dist/universal/.gemini/skills/citable/schemas/regional-network-import.schema.json +55 -0
  95. package/dist/universal/.gemini/skills/citable/schemas/schedule.schema.json +1 -1
  96. package/dist/universal/.gemini/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  97. package/dist/universal/.gemini/skills/citable/scripts/README.md +3 -1
  98. package/dist/universal/.github/skills/citable/SKILL.md +22 -8
  99. package/dist/universal/.github/skills/citable/VERSION +1 -1
  100. package/dist/universal/.github/skills/citable/agents/citable-auditor.md +64 -0
  101. package/dist/universal/.github/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  102. package/dist/universal/.github/skills/citable/commands/README.md +4 -1
  103. package/dist/universal/.github/skills/citable/commands/action-findings.md +9 -1
  104. package/dist/universal/.github/skills/citable/commands/observe-and-act.md +62 -8
  105. package/dist/universal/.github/skills/citable/commands/plan-audit.md +35 -0
  106. package/dist/universal/.github/skills/citable/commands/reporting.md +57 -0
  107. package/dist/universal/.github/skills/citable/manifest.json +29 -16
  108. package/dist/universal/.github/skills/citable/schemas/action-plan.schema.json +13 -0
  109. package/dist/universal/.github/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  110. package/dist/universal/.github/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  111. package/dist/universal/.github/skills/citable/schemas/common.defs.json +12 -1
  112. package/dist/universal/.github/skills/citable/schemas/corroboration-import.schema.json +48 -0
  113. package/dist/universal/.github/skills/citable/schemas/entity-graph.schema.json +75 -0
  114. package/dist/universal/.github/skills/citable/schemas/entity.schema.json +13 -0
  115. package/dist/universal/.github/skills/citable/schemas/observation.schema.json +1 -1
  116. package/dist/universal/.github/skills/citable/schemas/page.schema.json +3 -0
  117. package/dist/universal/.github/skills/citable/schemas/regional-network-import.schema.json +55 -0
  118. package/dist/universal/.github/skills/citable/schemas/schedule.schema.json +1 -1
  119. package/dist/universal/.github/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  120. package/dist/universal/.github/skills/citable/scripts/README.md +3 -1
  121. package/dist/universal/.kiro/skills/citable/SKILL.md +22 -8
  122. package/dist/universal/.kiro/skills/citable/VERSION +1 -1
  123. package/dist/universal/.kiro/skills/citable/agents/citable-auditor.md +64 -0
  124. package/dist/universal/.kiro/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  125. package/dist/universal/.kiro/skills/citable/commands/README.md +4 -1
  126. package/dist/universal/.kiro/skills/citable/commands/action-findings.md +9 -1
  127. package/dist/universal/.kiro/skills/citable/commands/observe-and-act.md +62 -8
  128. package/dist/universal/.kiro/skills/citable/commands/plan-audit.md +35 -0
  129. package/dist/universal/.kiro/skills/citable/commands/reporting.md +57 -0
  130. package/dist/universal/.kiro/skills/citable/manifest.json +29 -16
  131. package/dist/universal/.kiro/skills/citable/schemas/action-plan.schema.json +13 -0
  132. package/dist/universal/.kiro/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  133. package/dist/universal/.kiro/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  134. package/dist/universal/.kiro/skills/citable/schemas/common.defs.json +12 -1
  135. package/dist/universal/.kiro/skills/citable/schemas/corroboration-import.schema.json +48 -0
  136. package/dist/universal/.kiro/skills/citable/schemas/entity-graph.schema.json +75 -0
  137. package/dist/universal/.kiro/skills/citable/schemas/entity.schema.json +13 -0
  138. package/dist/universal/.kiro/skills/citable/schemas/observation.schema.json +1 -1
  139. package/dist/universal/.kiro/skills/citable/schemas/page.schema.json +3 -0
  140. package/dist/universal/.kiro/skills/citable/schemas/regional-network-import.schema.json +55 -0
  141. package/dist/universal/.kiro/skills/citable/schemas/schedule.schema.json +1 -1
  142. package/dist/universal/.kiro/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  143. package/dist/universal/.kiro/skills/citable/scripts/README.md +3 -1
  144. package/dist/universal/.opencode/skills/citable/SKILL.md +22 -8
  145. package/dist/universal/.opencode/skills/citable/VERSION +1 -1
  146. package/dist/universal/.opencode/skills/citable/agents/citable-auditor.md +64 -0
  147. package/dist/universal/.opencode/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  148. package/dist/universal/.opencode/skills/citable/commands/README.md +4 -1
  149. package/dist/universal/.opencode/skills/citable/commands/action-findings.md +9 -1
  150. package/dist/universal/.opencode/skills/citable/commands/observe-and-act.md +62 -8
  151. package/dist/universal/.opencode/skills/citable/commands/plan-audit.md +35 -0
  152. package/dist/universal/.opencode/skills/citable/commands/reporting.md +57 -0
  153. package/dist/universal/.opencode/skills/citable/manifest.json +29 -16
  154. package/dist/universal/.opencode/skills/citable/schemas/action-plan.schema.json +13 -0
  155. package/dist/universal/.opencode/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  156. package/dist/universal/.opencode/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  157. package/dist/universal/.opencode/skills/citable/schemas/common.defs.json +12 -1
  158. package/dist/universal/.opencode/skills/citable/schemas/corroboration-import.schema.json +48 -0
  159. package/dist/universal/.opencode/skills/citable/schemas/entity-graph.schema.json +75 -0
  160. package/dist/universal/.opencode/skills/citable/schemas/entity.schema.json +13 -0
  161. package/dist/universal/.opencode/skills/citable/schemas/observation.schema.json +1 -1
  162. package/dist/universal/.opencode/skills/citable/schemas/page.schema.json +3 -0
  163. package/dist/universal/.opencode/skills/citable/schemas/regional-network-import.schema.json +55 -0
  164. package/dist/universal/.opencode/skills/citable/schemas/schedule.schema.json +1 -1
  165. package/dist/universal/.opencode/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  166. package/dist/universal/.opencode/skills/citable/scripts/README.md +3 -1
  167. package/dist/universal/.pi/agent/skills/citable/SKILL.md +22 -8
  168. package/dist/universal/.pi/agent/skills/citable/VERSION +1 -1
  169. package/dist/universal/.pi/agent/skills/citable/agents/citable-auditor.md +64 -0
  170. package/dist/universal/.pi/agent/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  171. package/dist/universal/.pi/agent/skills/citable/commands/README.md +4 -1
  172. package/dist/universal/.pi/agent/skills/citable/commands/action-findings.md +9 -1
  173. package/dist/universal/.pi/agent/skills/citable/commands/observe-and-act.md +62 -8
  174. package/dist/universal/.pi/agent/skills/citable/commands/plan-audit.md +35 -0
  175. package/dist/universal/.pi/agent/skills/citable/commands/reporting.md +57 -0
  176. package/dist/universal/.pi/agent/skills/citable/manifest.json +29 -16
  177. package/dist/universal/.pi/agent/skills/citable/schemas/action-plan.schema.json +13 -0
  178. package/dist/universal/.pi/agent/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  179. package/dist/universal/.pi/agent/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  180. package/dist/universal/.pi/agent/skills/citable/schemas/common.defs.json +12 -1
  181. package/dist/universal/.pi/agent/skills/citable/schemas/corroboration-import.schema.json +48 -0
  182. package/dist/universal/.pi/agent/skills/citable/schemas/entity-graph.schema.json +75 -0
  183. package/dist/universal/.pi/agent/skills/citable/schemas/entity.schema.json +13 -0
  184. package/dist/universal/.pi/agent/skills/citable/schemas/observation.schema.json +1 -1
  185. package/dist/universal/.pi/agent/skills/citable/schemas/page.schema.json +3 -0
  186. package/dist/universal/.pi/agent/skills/citable/schemas/regional-network-import.schema.json +55 -0
  187. package/dist/universal/.pi/agent/skills/citable/schemas/schedule.schema.json +1 -1
  188. package/dist/universal/.pi/agent/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  189. package/dist/universal/.pi/agent/skills/citable/scripts/README.md +3 -1
  190. package/dist/universal/.qoder/skills/citable/SKILL.md +22 -8
  191. package/dist/universal/.qoder/skills/citable/VERSION +1 -1
  192. package/dist/universal/.qoder/skills/citable/agents/citable-auditor.md +64 -0
  193. package/dist/universal/.qoder/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  194. package/dist/universal/.qoder/skills/citable/commands/README.md +4 -1
  195. package/dist/universal/.qoder/skills/citable/commands/action-findings.md +9 -1
  196. package/dist/universal/.qoder/skills/citable/commands/observe-and-act.md +62 -8
  197. package/dist/universal/.qoder/skills/citable/commands/plan-audit.md +35 -0
  198. package/dist/universal/.qoder/skills/citable/commands/reporting.md +57 -0
  199. package/dist/universal/.qoder/skills/citable/manifest.json +29 -16
  200. package/dist/universal/.qoder/skills/citable/schemas/action-plan.schema.json +13 -0
  201. package/dist/universal/.qoder/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  202. package/dist/universal/.qoder/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  203. package/dist/universal/.qoder/skills/citable/schemas/common.defs.json +12 -1
  204. package/dist/universal/.qoder/skills/citable/schemas/corroboration-import.schema.json +48 -0
  205. package/dist/universal/.qoder/skills/citable/schemas/entity-graph.schema.json +75 -0
  206. package/dist/universal/.qoder/skills/citable/schemas/entity.schema.json +13 -0
  207. package/dist/universal/.qoder/skills/citable/schemas/observation.schema.json +1 -1
  208. package/dist/universal/.qoder/skills/citable/schemas/page.schema.json +3 -0
  209. package/dist/universal/.qoder/skills/citable/schemas/regional-network-import.schema.json +55 -0
  210. package/dist/universal/.qoder/skills/citable/schemas/schedule.schema.json +1 -1
  211. package/dist/universal/.qoder/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  212. package/dist/universal/.qoder/skills/citable/scripts/README.md +3 -1
  213. package/dist/universal/.rovodev/skills/citable/SKILL.md +22 -8
  214. package/dist/universal/.rovodev/skills/citable/VERSION +1 -1
  215. package/dist/universal/.rovodev/skills/citable/agents/citable-auditor.md +64 -0
  216. package/dist/universal/.rovodev/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  217. package/dist/universal/.rovodev/skills/citable/commands/README.md +4 -1
  218. package/dist/universal/.rovodev/skills/citable/commands/action-findings.md +9 -1
  219. package/dist/universal/.rovodev/skills/citable/commands/observe-and-act.md +62 -8
  220. package/dist/universal/.rovodev/skills/citable/commands/plan-audit.md +35 -0
  221. package/dist/universal/.rovodev/skills/citable/commands/reporting.md +57 -0
  222. package/dist/universal/.rovodev/skills/citable/manifest.json +29 -16
  223. package/dist/universal/.rovodev/skills/citable/schemas/action-plan.schema.json +13 -0
  224. package/dist/universal/.rovodev/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  225. package/dist/universal/.rovodev/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  226. package/dist/universal/.rovodev/skills/citable/schemas/common.defs.json +12 -1
  227. package/dist/universal/.rovodev/skills/citable/schemas/corroboration-import.schema.json +48 -0
  228. package/dist/universal/.rovodev/skills/citable/schemas/entity-graph.schema.json +75 -0
  229. package/dist/universal/.rovodev/skills/citable/schemas/entity.schema.json +13 -0
  230. package/dist/universal/.rovodev/skills/citable/schemas/observation.schema.json +1 -1
  231. package/dist/universal/.rovodev/skills/citable/schemas/page.schema.json +3 -0
  232. package/dist/universal/.rovodev/skills/citable/schemas/regional-network-import.schema.json +55 -0
  233. package/dist/universal/.rovodev/skills/citable/schemas/schedule.schema.json +1 -1
  234. package/dist/universal/.rovodev/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  235. package/dist/universal/.rovodev/skills/citable/scripts/README.md +3 -1
  236. package/dist/universal/.trae/skills/citable/SKILL.md +22 -8
  237. package/dist/universal/.trae/skills/citable/VERSION +1 -1
  238. package/dist/universal/.trae/skills/citable/agents/citable-auditor.md +64 -0
  239. package/dist/universal/.trae/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  240. package/dist/universal/.trae/skills/citable/commands/README.md +4 -1
  241. package/dist/universal/.trae/skills/citable/commands/action-findings.md +9 -1
  242. package/dist/universal/.trae/skills/citable/commands/observe-and-act.md +62 -8
  243. package/dist/universal/.trae/skills/citable/commands/plan-audit.md +35 -0
  244. package/dist/universal/.trae/skills/citable/commands/reporting.md +57 -0
  245. package/dist/universal/.trae/skills/citable/manifest.json +29 -16
  246. package/dist/universal/.trae/skills/citable/schemas/action-plan.schema.json +13 -0
  247. package/dist/universal/.trae/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  248. package/dist/universal/.trae/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  249. package/dist/universal/.trae/skills/citable/schemas/common.defs.json +12 -1
  250. package/dist/universal/.trae/skills/citable/schemas/corroboration-import.schema.json +48 -0
  251. package/dist/universal/.trae/skills/citable/schemas/entity-graph.schema.json +75 -0
  252. package/dist/universal/.trae/skills/citable/schemas/entity.schema.json +13 -0
  253. package/dist/universal/.trae/skills/citable/schemas/observation.schema.json +1 -1
  254. package/dist/universal/.trae/skills/citable/schemas/page.schema.json +3 -0
  255. package/dist/universal/.trae/skills/citable/schemas/regional-network-import.schema.json +55 -0
  256. package/dist/universal/.trae/skills/citable/schemas/schedule.schema.json +1 -1
  257. package/dist/universal/.trae/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  258. package/dist/universal/.trae/skills/citable/scripts/README.md +3 -1
  259. package/dist/universal/.trae-cn/skills/citable/SKILL.md +22 -8
  260. package/dist/universal/.trae-cn/skills/citable/VERSION +1 -1
  261. package/dist/universal/.trae-cn/skills/citable/agents/citable-auditor.md +64 -0
  262. package/dist/universal/.trae-cn/skills/citable/agents/citable-semantic-reviewer.md +66 -0
  263. package/dist/universal/.trae-cn/skills/citable/commands/README.md +4 -1
  264. package/dist/universal/.trae-cn/skills/citable/commands/action-findings.md +9 -1
  265. package/dist/universal/.trae-cn/skills/citable/commands/observe-and-act.md +62 -8
  266. package/dist/universal/.trae-cn/skills/citable/commands/plan-audit.md +35 -0
  267. package/dist/universal/.trae-cn/skills/citable/commands/reporting.md +57 -0
  268. package/dist/universal/.trae-cn/skills/citable/manifest.json +29 -16
  269. package/dist/universal/.trae-cn/skills/citable/schemas/action-plan.schema.json +13 -0
  270. package/dist/universal/.trae-cn/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
  271. package/dist/universal/.trae-cn/skills/citable/schemas/canonical-index-import.schema.json +30 -0
  272. package/dist/universal/.trae-cn/skills/citable/schemas/common.defs.json +12 -1
  273. package/dist/universal/.trae-cn/skills/citable/schemas/corroboration-import.schema.json +48 -0
  274. package/dist/universal/.trae-cn/skills/citable/schemas/entity-graph.schema.json +75 -0
  275. package/dist/universal/.trae-cn/skills/citable/schemas/entity.schema.json +13 -0
  276. package/dist/universal/.trae-cn/skills/citable/schemas/observation.schema.json +1 -1
  277. package/dist/universal/.trae-cn/skills/citable/schemas/page.schema.json +3 -0
  278. package/dist/universal/.trae-cn/skills/citable/schemas/regional-network-import.schema.json +55 -0
  279. package/dist/universal/.trae-cn/skills/citable/schemas/schedule.schema.json +1 -1
  280. package/dist/universal/.trae-cn/skills/citable/schemas/source-identity-chain.schema.json +83 -0
  281. package/dist/universal/.trae-cn/skills/citable/scripts/README.md +3 -1
  282. package/dist/universal/manifest.json +306 -195
  283. package/package.json +1 -1
  284. package/schemas/action-plan.schema.json +13 -0
  285. package/schemas/browser-evidence-plan.schema.json +14 -0
  286. package/schemas/canonical-index-import.schema.json +30 -0
  287. package/schemas/common.defs.json +12 -1
  288. package/schemas/corroboration-import.schema.json +48 -0
  289. package/schemas/entity-graph.schema.json +75 -0
  290. package/schemas/entity.schema.json +13 -0
  291. package/schemas/observation.schema.json +1 -1
  292. package/schemas/page.schema.json +3 -0
  293. package/schemas/regional-network-import.schema.json +55 -0
  294. package/schemas/schedule.schema.json +1 -1
  295. package/schemas/source-identity-chain.schema.json +83 -0
  296. package/scripts/build-dist.js +36 -3
  297. package/skill/SKILL.md +22 -8
  298. package/skill/agents/citable-auditor.md +64 -0
  299. package/skill/agents/citable-semantic-reviewer.md +66 -0
  300. package/skill/commands/README.md +4 -1
  301. package/skill/commands/action-findings.md +9 -1
  302. package/skill/commands/observe-and-act.md +62 -8
  303. package/skill/commands/plan-audit.md +35 -0
  304. package/skill/commands/reporting.md +57 -0
  305. package/src/cli/index.js +115 -15
  306. package/src/commands/actionPlan.js +12 -1
  307. package/src/commands/audit.js +4 -0
  308. package/src/commands/connect.js +29 -0
  309. package/src/commands/context.js +15 -0
  310. package/src/commands/delivery.js +86 -2
  311. package/src/commands/demo.js +36 -0
  312. package/src/commands/fixtures/demo/.citable/claims.yaml +27 -0
  313. package/src/commands/fixtures/demo/.citable/competitors.yaml +3 -0
  314. package/src/commands/fixtures/demo/.citable/config.yaml +18 -0
  315. package/src/commands/fixtures/demo/.citable/crawlers.yaml +30 -0
  316. package/src/commands/fixtures/demo/.citable/entities.yaml +28 -0
  317. package/src/commands/fixtures/demo/.citable/evidence.yaml +19 -0
  318. package/src/commands/fixtures/demo/.citable/experiments.yaml +3 -0
  319. package/src/commands/fixtures/demo/.citable/pages.yaml +54 -0
  320. package/src/commands/fixtures/demo/.citable/prompts.yaml +11 -0
  321. package/src/commands/fixtures/demo/.citable/queries.yaml +10 -0
  322. package/src/commands/fixtures/demo/site/index.html +12 -0
  323. package/src/commands/fixtures/demo/site/learn/execution-governance/index.html +14 -0
  324. package/src/commands/fixtures/demo/site/pricing/index.html +10 -0
  325. package/src/commands/fixtures/demo/site/products/gatekeeper/index.html +15 -0
  326. package/src/commands/fixtures/demo/site/robots.txt +7 -0
  327. package/src/commands/fixtures/demo/site/sitemap.xml +7 -0
  328. package/src/commands/init.js +5 -2
  329. package/src/commands/monitor.js +35 -0
  330. package/src/commands/observe.js +315 -15
  331. package/src/commands/planAudit.js +151 -0
  332. package/src/commands/reportDashboard.js +21 -0
  333. package/src/commands/reportShareOfVoice.js +60 -0
  334. package/src/commands/schemaCmd.js +5 -1
  335. package/src/commands/substantiate.js +22 -10
  336. package/src/connectors/http.js +6 -3
  337. package/src/connectors/index.js +3 -1
  338. package/src/connectors/webflow.js +224 -0
  339. package/src/connectors/wordpress.js +226 -0
  340. package/src/crawler/fetch.js +34 -6
  341. package/src/detectors/geoReco.js +101 -0
  342. package/src/extractor/page.js +17 -0
  343. package/src/installer/index.js +282 -28
  344. package/src/installer/providers.js +11 -0
  345. package/src/monitoring/alertDelivery.js +98 -0
  346. package/src/observations/browserJourney.js +15 -7
  347. package/src/observations/claimDiff.js +83 -0
  348. package/src/observations/common.js +25 -0
  349. package/src/observations/entityGraph.js +89 -0
  350. package/src/observations/renderParity.js +49 -0
  351. package/src/observations/sourceIdentity.js +62 -0
  352. package/src/observations/stance.js +261 -0
  353. package/src/registries/seed.js +95 -0
  354. package/src/registries/seeds/saas-pricing/claims.yaml +18 -0
  355. package/src/registries/seeds/saas-pricing/entities.yaml +20 -0
  356. package/src/registries/seeds/saas-pricing/seed.json +6 -0
  357. package/src/reporting/dashboard.js +254 -0
  358. package/src/reporting/shareOfVoice.js +362 -0
  359. package/src/shared/checklist.js +19 -0
@@ -0,0 +1,60 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import {
4
+ calculateShareOfVoice,
5
+ extractDomain,
6
+ loadCitationRuns,
7
+ renderShareOfVoiceHtml,
8
+ renderShareOfVoiceMarkdown,
9
+ } from '../reporting/shareOfVoice.js';
10
+ import { loadRegistries } from '../registries/index.js';
11
+
12
+ /**
13
+ * `citable report share-of-voice` — compute first-party and competitor citation share
14
+ * across recorded observation runs. Never invents competitor citations; unevidenced
15
+ * prompts and competitors are reported plainly.
16
+ */
17
+ export function reportShareOfVoice(root, { since, last } = {}) {
18
+ if (last != null && (!Number.isInteger(last) || last < 1)) {
19
+ throw new Error('--last must be a positive integer');
20
+ }
21
+
22
+ const { registries } = loadRegistries(root);
23
+ const competitors = registries.competitors?.entries || [];
24
+
25
+ const firstPartyDomains = new Set();
26
+ if (registries.config?.site?.base_url) {
27
+ const d = extractDomain(registries.config.site.base_url);
28
+ if (d) firstPartyDomains.add(d);
29
+ }
30
+ if (registries.pages?.entries) {
31
+ for (const p of registries.pages.entries) {
32
+ if (p.url) {
33
+ const d = extractDomain(p.url);
34
+ if (d) firstPartyDomains.add(d);
35
+ }
36
+ }
37
+ }
38
+
39
+ const { included, skipped } = loadCitationRuns(root, { since, last });
40
+ const data = calculateShareOfVoice(included, competitors, firstPartyDomains);
41
+
42
+ const dir = path.join(root, '.citable', 'reports');
43
+ const pathMd = path.join(dir, 'share-of-voice.md');
44
+ const pathHtml = path.join(dir, 'share-of-voice.html');
45
+
46
+ fs.mkdirSync(dir, { recursive: true });
47
+ fs.writeFileSync(pathMd, renderShareOfVoiceMarkdown(data, skipped));
48
+ fs.writeFileSync(pathHtml, renderShareOfVoiceHtml(data, skipped));
49
+
50
+ return {
51
+ dir,
52
+ included: included.length,
53
+ skipped: skipped.length,
54
+ competitors_evaluated: competitors.length,
55
+ prompts_evaluated: data.prompts.length,
56
+ total_citations: data.total_citations_recorded,
57
+ path_md: pathMd,
58
+ path_html: pathHtml,
59
+ };
60
+ }
@@ -1,6 +1,7 @@
1
1
  import { buildContext } from './context.js';
2
2
  import { selectDetectors } from '../detectors/index.js';
3
3
  import { runDetectors, sitePageFor } from '../detectors/framework.js';
4
+ import { checklistItem, toStringArray } from '../shared/checklist.js';
4
5
 
5
6
  /**
6
7
  * `citable schema` — derive JSON-LD proposals from registry data and validate deployed schema.
@@ -28,7 +29,10 @@ export async function schemaCommand(root, { target, baseUrl, refDate } = {}) {
28
29
  if (!e.canonical_url) missing.push('canonical_url');
29
30
  if (!e.definition && ['proprietary_concept', 'category'].includes(e.entity_type)) missing.push('definition');
30
31
  if (missing.length) {
31
- blocked.push({ entity_id: e.entity_id, status: 'blocked', reason: 'entity record incomplete; schema would require invented facts', required_input: missing });
32
+ blocked.push({
33
+ entity_id: e.entity_id, status: 'blocked', reason: 'entity record incomplete; schema would require invented facts',
34
+ required_input: toStringArray(missing.map((field) => checklistItem(field, field))),
35
+ });
32
36
  continue;
33
37
  }
34
38
  const id = `${e.canonical_url}#${e.entity_type}`;
@@ -1,5 +1,6 @@
1
1
  import { loadRegistries, saveRegistry, diffRegistries } from '../registries/index.js';
2
2
  import { isPastDate, nowIso, parseRefDate } from '../shared/io.js';
3
+ import { checklistItem, toStringArray } from '../shared/checklist.js';
3
4
 
4
5
  const REGULATED = new Set(['legal_regulatory', 'security', 'commercial']);
5
6
 
@@ -37,7 +38,7 @@ export function substantiate(root, { write = false, refDate } = {}) {
37
38
  } else if (REGULATED.has(c.claim_type) && (!c.legal_status || c.legal_status === 'not_assessed')) {
38
39
  a.outcome = 'review_required';
39
40
  a.reasons.push(`${c.claim_type} claim requires legal/SME review before any verified status`);
40
- a.required_input.push('legal or subject-matter review decision');
41
+ a.required_input.push(checklistItem('legal-review', 'legal or subject-matter review decision'));
41
42
  } else if (['opinion', 'position', 'aspirational'].includes(c.claim_type)) {
42
43
  // Opinions and aspirations are positions, not verifiable facts; they never enter the verified track.
43
44
  a.outcome = c.status === 'candidate' ? 'candidate' : 'unverified';
@@ -54,19 +55,23 @@ export function substantiate(root, { write = false, refDate } = {}) {
54
55
  } else if (live.length === 0) {
55
56
  a.outcome = 'insufficient_evidence';
56
57
  a.reasons.push('all attached evidence is expired, unverified, revoked, or inaccessible');
57
- a.required_input.push('current, verified evidence');
58
+ a.required_input.push(checklistItem('current-verified-evidence', 'current, verified evidence'));
58
59
  } else if (['performance', 'comparative', 'security'].includes(c.claim_type) && live.every((e) => e.primary_or_secondary === 'secondary')) {
59
60
  a.outcome = 'insufficient_evidence';
60
61
  a.reasons.push(`${c.claim_type} claims require primary evidence; only secondary evidence attached`);
61
- a.required_input.push('primary evidence (test result, benchmark, specification, certification)');
62
+ a.required_input.push(checklistItem('primary-evidence', 'primary evidence (test result, benchmark, specification, certification)'));
62
63
  } else if (['performance'].includes(c.claim_type) && live.every((e) => !e.methodology)) {
63
64
  a.outcome = 'insufficient_evidence';
64
65
  a.reasons.push('performance evidence lacks methodology');
65
- a.required_input.push('methodology', 'test conditions', 'measurement period');
66
+ a.required_input.push(
67
+ checklistItem('methodology', 'methodology'),
68
+ checklistItem('test-conditions', 'test conditions'),
69
+ checklistItem('measurement-period', 'measurement period'),
70
+ );
66
71
  } else if ((c.scope || []).length === 0 && ['capability', 'performance', 'comparative'].includes(c.claim_type)) {
67
72
  a.outcome = 'verified_narrowed';
68
73
  a.reasons.push('evidence exists but claim declares no scope; treat as verified only with narrowed scope pending scope definition');
69
- a.required_input.push('explicit scope and exclusions');
74
+ a.required_input.push(checklistItem('scope-exclusions', 'explicit scope and exclusions'));
70
75
  } else {
71
76
  // Deterministic conditions passed. Verified status additionally requires a recorded
72
77
  // semantic support assessment (entailment) by a named assessor — evidence linkage
@@ -82,7 +87,7 @@ export function substantiate(root, { write = false, refDate } = {}) {
82
87
  } else {
83
88
  a.outcome = 'review_required';
84
89
  a.reasons.push('verified status held without an adequate semantic support assessment; entailment review required (evidence-strength rubric)');
85
- a.required_input.push('support_assessment with named assessor');
90
+ a.required_input.push(checklistItem('support-assessment', 'support_assessment with named assessor'));
86
91
  }
87
92
  } else {
88
93
  a.outcome = 'review_required';
@@ -90,6 +95,7 @@ export function substantiate(root, { write = false, refDate } = {}) {
90
95
  }
91
96
  }
92
97
  }
98
+ a.required_input = toStringArray(a.required_input);
93
99
  assessments.push(a);
94
100
  }
95
101
 
@@ -114,8 +120,14 @@ export function substantiate(root, { write = false, refDate } = {}) {
114
120
  }
115
121
 
116
122
  function requiredInputFor(c) {
117
- if (c.claim_type === 'performance') return ['baseline', 'measurement period', 'test population/conditions', 'methodology', 'result source'];
118
- if (c.claim_type === 'comparative') return ['comparison set', 'comparison criteria', 'evidence for each compared dimension'];
119
- if (c.claim_type === 'security') return ['test report, certification, or architecture evidence'];
120
- return ['supporting evidence with an accountable owner'];
123
+ if (c.claim_type === 'performance') {
124
+ return ['baseline', 'measurement period', 'test population/conditions', 'methodology', 'result source']
125
+ .map((label) => checklistItem(label.replace(/[^a-z0-9]+/gi, '-').toLowerCase(), label));
126
+ }
127
+ if (c.claim_type === 'comparative') {
128
+ return ['comparison set', 'comparison criteria', 'evidence for each compared dimension']
129
+ .map((label) => checklistItem(label.replace(/[^a-z0-9]+/gi, '-').toLowerCase(), label));
130
+ }
131
+ if (c.claim_type === 'security') return [checklistItem('security-evidence', 'test report, certification, or architecture evidence')];
132
+ return [checklistItem('owned-evidence', 'supporting evidence with an accountable owner')];
121
133
  }
@@ -1,15 +1,18 @@
1
1
  const RETRYABLE = new Set([429, 500, 502, 503, 504]);
2
2
 
3
- export async function providerRequest(url, { token, fetchImpl = globalThis.fetch, method = 'GET', body, attempts = 3 } = {}) {
3
+ export async function providerRequest(url, { token, fetchImpl = globalThis.fetch, method = 'GET', body, headers = {}, attempts = 3, rawResponse = false } = {}) {
4
4
  if (!token) throw Object.assign(new Error('authorization is not configured'), { connectorState: 'not_configured' });
5
5
  let response;
6
6
  for (let attempt = 1; attempt <= attempts; attempt++) {
7
7
  response = await fetchImpl(url, {
8
8
  method,
9
- headers: { authorization: `Bearer ${token}`, accept: 'application/json', ...(body ? { 'content-type': 'application/json' } : {}) },
9
+ headers: { authorization: `Bearer ${token}`, accept: 'application/json', ...(body ? { 'content-type': 'application/json' } : {}), ...headers },
10
10
  body: body ? JSON.stringify(body) : undefined,
11
11
  });
12
- if (response.ok) return response.json();
12
+ if (response.ok) {
13
+ if (rawResponse) return response;
14
+ return response.json();
15
+ }
13
16
  const detail = (await response.text()).slice(0, 300);
14
17
  if (!RETRYABLE.has(response.status) || attempt === attempts) {
15
18
  const states = { 401: 'authorization_expired', 403: 'permission_denied', 429: 'quota_limited' };
@@ -1,7 +1,9 @@
1
1
  import { gscConnector } from './gsc.js';
2
2
  import { ga4Connector } from './ga4.js';
3
+ import { wordpressConnector } from './wordpress.js';
4
+ import { webflowConnector } from './webflow.js';
3
5
 
4
- const CONNECTORS = new Map([gscConnector, ga4Connector].map((connector) => [connector.provider, connector]));
6
+ const CONNECTORS = new Map([gscConnector, ga4Connector, wordpressConnector, webflowConnector].map((connector) => [connector.provider, connector]));
5
7
 
6
8
  export function getConnector(provider) {
7
9
  const connector = CONNECTORS.get(String(provider).toLowerCase());
@@ -0,0 +1,224 @@
1
+ import { providerRequest } from './http.js';
2
+ import { sha256, nowIso } from '../shared/io.js';
3
+
4
+ const BASE = 'https://api.webflow.com/v2';
5
+
6
+ const METRICS = {
7
+ pages: { unit: 'count', value_type: 'integer' },
8
+ collections: { unit: 'count', value_type: 'integer' },
9
+ items: { unit: 'count', value_type: 'integer' },
10
+ };
11
+
12
+ function computeWebflowPayloadHash(payload) {
13
+ const canonical = {
14
+ target_id: String(payload.target_id || payload.id),
15
+ site_id: String(payload.site_id || ''),
16
+ title: String(payload.title || ''),
17
+ slug: String(payload.slug || ''),
18
+ meta_title: String(payload.meta_title || ''),
19
+ meta_description: String(payload.meta_description || ''),
20
+ open_graph_title: String(payload.open_graph_title || ''),
21
+ open_graph_description: String(payload.open_graph_description || ''),
22
+ body: String(payload.body || ''),
23
+ };
24
+ return sha256(JSON.stringify(canonical));
25
+ }
26
+
27
+ export const webflowConnector = {
28
+ provider: 'webflow',
29
+ defaultCredentialEnv: 'WEBFLOW_API_TOKEN',
30
+ readOnlyScopes: ['sites:read', 'pages:read', 'cms:read'],
31
+ writeScopes: ['pages:write', 'cms:write'],
32
+
33
+ describeMetrics() {
34
+ return METRICS;
35
+ },
36
+
37
+ async discoverProperties(context) {
38
+ const result = await providerRequest(`${BASE}/sites`, context);
39
+ const sites = result.sites || [];
40
+ return sites.map((site) => ({
41
+ property_id: site.id,
42
+ display_name: site.displayName || site.id,
43
+ custom_domains: (site.customDomains || []).map((d) => d.url || d.host || d),
44
+ time_zone: site.timeZone || null,
45
+ created_on: site.createdOn || null,
46
+ permission: 'administrator',
47
+ }));
48
+ },
49
+
50
+ async validateConnection(connection, context) {
51
+ const site = await providerRequest(`${BASE}/sites/${encodeURIComponent(connection.property_id)}`, context);
52
+ const valid = Boolean(site && site.id === connection.property_id);
53
+ return {
54
+ valid,
55
+ site_id: site?.id || connection.property_id,
56
+ display_name: site?.displayName || null,
57
+ last_published: site?.lastPublished || null,
58
+ };
59
+ },
60
+
61
+ async sync(connection, metrics, { startDate, endDate, ...context }) {
62
+ const siteId = connection.property_id;
63
+ const rows = [];
64
+ const metricNames = new Set(metrics.map((m) => m.external_name));
65
+
66
+ if (metricNames.has('pages')) {
67
+ const pageResult = await providerRequest(`${BASE}/sites/${encodeURIComponent(siteId)}/pages`, context);
68
+ const pages = pageResult.pages || [];
69
+ const pageMetric = metrics.find((m) => m.external_name === 'pages');
70
+ rows.push({
71
+ metric: pageMetric,
72
+ value: pages.length,
73
+ dimensions: { date: endDate },
74
+ observed_at: `${endDate}T00:00:00.000Z`,
75
+ });
76
+ }
77
+
78
+ if (metricNames.has('collections') || metricNames.has('items')) {
79
+ const collectionsResult = await providerRequest(`${BASE}/sites/${encodeURIComponent(siteId)}/collections`, context);
80
+ const collections = collectionsResult.collections || [];
81
+
82
+ if (metricNames.has('collections')) {
83
+ const colMetric = metrics.find((m) => m.external_name === 'collections');
84
+ rows.push({
85
+ metric: colMetric,
86
+ value: collections.length,
87
+ dimensions: { date: endDate },
88
+ observed_at: `${endDate}T00:00:00.000Z`,
89
+ });
90
+ }
91
+
92
+ if (metricNames.has('items')) {
93
+ let totalItems = 0;
94
+ for (const col of collections) {
95
+ const itemsResult = await providerRequest(`${BASE}/collections/${encodeURIComponent(col.id)}/items?limit=100`, context);
96
+ totalItems += (itemsResult.items || []).length;
97
+ }
98
+ const itemMetric = metrics.find((m) => m.external_name === 'items');
99
+ rows.push({
100
+ metric: itemMetric,
101
+ value: totalItems,
102
+ dimensions: { date: endDate },
103
+ observed_at: `${endDate}T00:00:00.000Z`,
104
+ });
105
+ }
106
+ }
107
+
108
+ return {
109
+ rows,
110
+ cursor: endDate,
111
+ limitations: [
112
+ 'Webflow API enforces rate limits of 60 requests per minute.',
113
+ 'Staged CMS changes require site publish to appear on live domains.',
114
+ ],
115
+ };
116
+ },
117
+
118
+ /**
119
+ * Read Webflow page or collection item content and SEO metadata with hash integrity.
120
+ */
121
+ async readContent(connection, targetId, context) {
122
+ if (!targetId) throw new Error('Webflow readContent requires targetId');
123
+ const page = await providerRequest(`${BASE}/pages/${encodeURIComponent(targetId)}`, context);
124
+
125
+ const payload = {
126
+ target_id: String(page.id),
127
+ site_id: page.siteId || connection.property_id,
128
+ title: page.title || '',
129
+ slug: page.slug || '',
130
+ meta_title: page.seo?.title || page.title || '',
131
+ meta_description: page.seo?.description || '',
132
+ open_graph_title: page.openGraph?.title || null,
133
+ open_graph_description: page.openGraph?.description || null,
134
+ body: page.body || '',
135
+ draft: Boolean(page.draft),
136
+ archived: Boolean(page.archived),
137
+ published: Boolean(page.published),
138
+ };
139
+
140
+ const contentHash = computeWebflowPayloadHash(payload);
141
+ return { ...payload, content_hash: contentHash };
142
+ },
143
+
144
+ /**
145
+ * Apply reviewed, hash-locked remediation to a Webflow page.
146
+ */
147
+ async applyRemediation(connection, remediation, context = {}) {
148
+ if (!remediation.reviewer) {
149
+ throw new Error('CMS remediation requires a named human reviewer per governance rules');
150
+ }
151
+ if (!remediation.expected_hash) {
152
+ throw new Error('CMS remediation requires expected_hash for hash-locking');
153
+ }
154
+ if (!remediation.target_id) {
155
+ throw new Error('CMS remediation requires target_id');
156
+ }
157
+
158
+ const current = await this.readContent(connection, remediation.target_id, context);
159
+ if (current.content_hash !== remediation.expected_hash) {
160
+ throw new Error(`stale remediation refused for Webflow ${remediation.target_id}: content hash changed (${current.content_hash} !== ${remediation.expected_hash})`);
161
+ }
162
+
163
+ const updates = remediation.updates || {};
164
+ const candidatePayload = {
165
+ ...current,
166
+ title: updates.title !== undefined ? updates.title : current.title,
167
+ slug: updates.slug !== undefined ? updates.slug : current.slug,
168
+ meta_title: updates.meta_title !== undefined ? updates.meta_title : current.meta_title,
169
+ meta_description: updates.meta_description !== undefined ? updates.meta_description : current.meta_description,
170
+ open_graph_title: updates.open_graph_title !== undefined ? updates.open_graph_title : current.open_graph_title,
171
+ open_graph_description: updates.open_graph_description !== undefined ? updates.open_graph_description : current.open_graph_description,
172
+ body: updates.body !== undefined ? updates.body : current.body,
173
+ };
174
+ const simulatedHash = computeWebflowPayloadHash(candidatePayload);
175
+
176
+ // Dry-run mode by default
177
+ if (!context.write) {
178
+ return {
179
+ status: 'proposed',
180
+ dry_run: true,
181
+ target_id: remediation.target_id,
182
+ before_hash: current.content_hash,
183
+ after_hash: simulatedHash,
184
+ updates,
185
+ reviewer: remediation.reviewer,
186
+ };
187
+ }
188
+
189
+ // Live update via PATCH
190
+ const body = {};
191
+ if (updates.title !== undefined) body.title = updates.title;
192
+ if (updates.slug !== undefined) body.slug = updates.slug;
193
+ if (updates.body !== undefined) body.body = updates.body;
194
+ if (updates.meta_title !== undefined || updates.meta_description !== undefined) {
195
+ body.seo = {
196
+ title: updates.meta_title !== undefined ? updates.meta_title : current.meta_title,
197
+ description: updates.meta_description !== undefined ? updates.meta_description : current.meta_description,
198
+ };
199
+ }
200
+ if (updates.open_graph_title !== undefined || updates.open_graph_description !== undefined) {
201
+ body.openGraph = {
202
+ title: updates.open_graph_title !== undefined ? updates.open_graph_title : current.open_graph_title,
203
+ description: updates.open_graph_description !== undefined ? updates.open_graph_description : current.open_graph_description,
204
+ };
205
+ }
206
+
207
+ await providerRequest(`${BASE}/pages/${encodeURIComponent(remediation.target_id)}`, {
208
+ ...context,
209
+ method: 'PATCH',
210
+ body,
211
+ });
212
+
213
+ const updated = await this.readContent(connection, remediation.target_id, context);
214
+ return {
215
+ status: 'applied',
216
+ dry_run: false,
217
+ target_id: remediation.target_id,
218
+ before_hash: current.content_hash,
219
+ after_hash: updated.content_hash,
220
+ updated_at: nowIso(),
221
+ reviewer: remediation.reviewer,
222
+ };
223
+ },
224
+ };
@@ -0,0 +1,226 @@
1
+ import { providerRequest } from './http.js';
2
+ import { sha256, nowIso } from '../shared/io.js';
3
+
4
+ const METRICS = {
5
+ published_posts: { unit: 'count', value_type: 'integer' },
6
+ published_pages: { unit: 'count', value_type: 'integer' },
7
+ };
8
+
9
+ function normalizeBaseUrl(propertyId) {
10
+ if (!propertyId) throw new Error('WordPress property_id must be the base site or API URL');
11
+ return String(propertyId).replace(/\/+$/, '');
12
+ }
13
+
14
+ function computeCmsPayloadHash(payload) {
15
+ const canonical = {
16
+ target_id: String(payload.target_id || payload.id),
17
+ title: String(payload.title || ''),
18
+ content: String(payload.content || ''),
19
+ excerpt: String(payload.excerpt || ''),
20
+ slug: String(payload.slug || ''),
21
+ status: String(payload.status || 'publish'),
22
+ meta: payload.meta || {},
23
+ schema_data: payload.schema_data || null,
24
+ };
25
+ return sha256(JSON.stringify(canonical));
26
+ }
27
+
28
+ export const wordpressConnector = {
29
+ provider: 'wordpress',
30
+ defaultCredentialEnv: 'WORDPRESS_AUTH_TOKEN',
31
+ readOnlyScopes: [
32
+ 'https://api.wordpress.org/auth/posts.readonly',
33
+ 'https://api.wordpress.org/auth/pages.readonly',
34
+ ],
35
+ writeScopes: [
36
+ 'https://api.wordpress.org/auth/posts.edit',
37
+ 'https://api.wordpress.org/auth/pages.edit',
38
+ ],
39
+
40
+ describeMetrics() {
41
+ return METRICS;
42
+ },
43
+
44
+ async discoverProperties(context) {
45
+ const targetUrl = context.property_id || context.siteUrl || context.url;
46
+ if (!targetUrl) {
47
+ return [{
48
+ property_id: 'https://example.test',
49
+ display_name: 'WordPress Site (configure with site URL)',
50
+ permission: 'administrator',
51
+ }];
52
+ }
53
+ const base = normalizeBaseUrl(targetUrl);
54
+ const siteInfo = await providerRequest(`${base}/wp-json`, context);
55
+ return [{
56
+ property_id: siteInfo.url || base,
57
+ display_name: siteInfo.name || base,
58
+ description: siteInfo.description || null,
59
+ home: siteInfo.home || null,
60
+ permission: 'administrator',
61
+ }];
62
+ },
63
+
64
+ async validateConnection(connection, context) {
65
+ const base = normalizeBaseUrl(connection.property_id);
66
+ const user = await providerRequest(`${base}/wp-json/wp/v2/users/me?context=edit`, context);
67
+ const valid = Boolean(user && (user.id || user.name));
68
+ return {
69
+ valid,
70
+ user: user?.name || null,
71
+ roles: user?.roles || [],
72
+ capabilities: user?.capabilities || {},
73
+ };
74
+ },
75
+
76
+ async sync(connection, metrics, { startDate, endDate, ...context }) {
77
+ const base = normalizeBaseUrl(connection.property_id);
78
+ const rows = [];
79
+ const metricNames = new Set(metrics.map((m) => m.external_name));
80
+
81
+ if (metricNames.has('published_posts')) {
82
+ const posts = await providerRequest(`${base}/wp-json/wp/v2/posts?per_page=100&status=publish`, context);
83
+ const postMetric = metrics.find((m) => m.external_name === 'published_posts');
84
+ rows.push({
85
+ metric: postMetric,
86
+ value: Array.isArray(posts) ? posts.length : 0,
87
+ dimensions: { date: endDate },
88
+ observed_at: `${endDate}T00:00:00.000Z`,
89
+ });
90
+ }
91
+
92
+ if (metricNames.has('published_pages')) {
93
+ const pages = await providerRequest(`${base}/wp-json/wp/v2/pages?per_page=100&status=publish`, context);
94
+ const pageMetric = metrics.find((m) => m.external_name === 'published_pages');
95
+ rows.push({
96
+ metric: pageMetric,
97
+ value: Array.isArray(pages) ? pages.length : 0,
98
+ dimensions: { date: endDate },
99
+ observed_at: `${endDate}T00:00:00.000Z`,
100
+ });
101
+ }
102
+
103
+ return {
104
+ rows,
105
+ cursor: endDate,
106
+ limitations: [
107
+ 'WordPress REST API collection is bounded to accessible posts and pages.',
108
+ 'Custom post types outside standard posts and pages require dedicated endpoint parameters.',
109
+ ],
110
+ };
111
+ },
112
+
113
+ /**
114
+ * Read CMS page/post content, metadata, and structured data with hash integrity.
115
+ */
116
+ async readContent(connection, targetId, context) {
117
+ if (!targetId) throw new Error('WordPress readContent requires targetId');
118
+ const base = normalizeBaseUrl(connection.property_id);
119
+ let item;
120
+ try {
121
+ item = await providerRequest(`${base}/wp-json/wp/v2/pages/${encodeURIComponent(targetId)}?context=edit`, context);
122
+ } catch {
123
+ // Fall back to posts if not a page
124
+ item = await providerRequest(`${base}/wp-json/wp/v2/posts/${encodeURIComponent(targetId)}?context=edit`, context);
125
+ }
126
+
127
+ const payload = {
128
+ target_id: String(item.id),
129
+ type: item.type || 'page',
130
+ url: item.link || '',
131
+ slug: item.slug || '',
132
+ status: item.status || 'publish',
133
+ title: item.title?.raw ?? item.title?.rendered ?? '',
134
+ content: item.content?.raw ?? item.content?.rendered ?? '',
135
+ excerpt: item.excerpt?.raw ?? item.excerpt?.rendered ?? '',
136
+ meta: item.meta || {},
137
+ schema_data: item.meta?.schema_data || null,
138
+ yoast_title: item.meta?._yoast_wpseo_title || null,
139
+ yoast_metadesc: item.meta?._yoast_wpseo_metadesc || null,
140
+ modified_gmt: item.modified_gmt || null,
141
+ };
142
+
143
+ const contentHash = computeCmsPayloadHash(payload);
144
+ return { ...payload, content_hash: contentHash };
145
+ },
146
+
147
+ /**
148
+ * Apply reviewed, hash-locked remediation to WordPress page or post.
149
+ */
150
+ async applyRemediation(connection, remediation, context = {}) {
151
+ if (!remediation.reviewer) {
152
+ throw new Error('CMS remediation requires a named human reviewer per governance rules');
153
+ }
154
+ if (!remediation.expected_hash) {
155
+ throw new Error('CMS remediation requires expected_hash for hash-locking');
156
+ }
157
+ if (!remediation.target_id) {
158
+ throw new Error('CMS remediation requires target_id');
159
+ }
160
+
161
+ const current = await this.readContent(connection, remediation.target_id, context);
162
+ if (current.content_hash !== remediation.expected_hash) {
163
+ throw new Error(`stale remediation refused for WordPress ${remediation.target_id}: content hash changed (${current.content_hash} !== ${remediation.expected_hash})`);
164
+ }
165
+
166
+ const updates = remediation.updates || {};
167
+ const candidatePayload = {
168
+ ...current,
169
+ title: updates.title !== undefined ? updates.title : current.title,
170
+ content: updates.content !== undefined ? updates.content : current.content,
171
+ excerpt: updates.excerpt !== undefined ? updates.excerpt : current.excerpt,
172
+ slug: updates.slug !== undefined ? updates.slug : current.slug,
173
+ status: updates.status !== undefined ? updates.status : current.status,
174
+ meta: updates.meta !== undefined ? updates.meta : current.meta,
175
+ schema_data: updates.schema_data !== undefined ? updates.schema_data : current.schema_data,
176
+ };
177
+ const simulatedHash = computeCmsPayloadHash(candidatePayload);
178
+
179
+ // Dry-run mode by default
180
+ if (!context.write) {
181
+ return {
182
+ status: 'proposed',
183
+ dry_run: true,
184
+ target_id: remediation.target_id,
185
+ before_hash: current.content_hash,
186
+ after_hash: simulatedHash,
187
+ updates,
188
+ reviewer: remediation.reviewer,
189
+ };
190
+ }
191
+
192
+ // Live update
193
+ const base = normalizeBaseUrl(connection.property_id);
194
+ const endpoint = current.type === 'post' ? 'posts' : 'pages';
195
+ const body = {};
196
+ if (updates.title !== undefined) body.title = updates.title;
197
+ if (updates.content !== undefined) body.content = updates.content;
198
+ if (updates.excerpt !== undefined) body.excerpt = updates.excerpt;
199
+ if (updates.slug !== undefined) body.slug = updates.slug;
200
+ if (updates.status !== undefined) body.status = updates.status;
201
+ if (updates.meta !== undefined || updates.schema_data !== undefined) {
202
+ body.meta = {
203
+ ...(current.meta || {}),
204
+ ...(updates.meta || {}),
205
+ ...(updates.schema_data !== undefined ? { schema_data: updates.schema_data } : {}),
206
+ };
207
+ }
208
+
209
+ await providerRequest(`${base}/wp-json/wp/v2/${endpoint}/${encodeURIComponent(remediation.target_id)}`, {
210
+ ...context,
211
+ method: 'POST',
212
+ body,
213
+ });
214
+
215
+ const updated = await this.readContent(connection, remediation.target_id, context);
216
+ return {
217
+ status: 'applied',
218
+ dry_run: false,
219
+ target_id: remediation.target_id,
220
+ before_hash: current.content_hash,
221
+ after_hash: updated.content_hash,
222
+ updated_at: nowIso(),
223
+ reviewer: remediation.reviewer,
224
+ };
225
+ },
226
+ };