oh-my-opencode 5.1.48 → 5.1.51

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 (495) hide show
  1. package/dist/agents/refusal-rule.d.ts +7 -0
  2. package/dist/cli/index.js +1194 -752
  3. package/dist/cli/service-auth/accounts-gate.d.ts +11 -0
  4. package/dist/cli/service-auth/commands.d.ts +2 -4
  5. package/dist/cli/service-auth/index.d.ts +1 -1
  6. package/dist/cli/service-auth/keystore.d.ts +26 -2
  7. package/dist/cli/service-auth/protocol.d.ts +7 -1
  8. package/dist/cli/service-auth/session.d.ts +6 -0
  9. package/dist/cli/service-auth/signed-out-marker.d.ts +11 -0
  10. package/dist/cli-node/index.js +1194 -752
  11. package/dist/config/schema/hooks.d.ts +1 -0
  12. package/dist/create-hooks.d.ts +1 -0
  13. package/dist/features/boulder-state/storage.d.ts +1 -1
  14. package/dist/features/boulder-state/types.d.ts +1 -1
  15. package/dist/hooks/atlas/idle-continuation.d.ts +2 -1
  16. package/dist/hooks/atlas/types.d.ts +9 -1
  17. package/dist/hooks/index.d.ts +1 -0
  18. package/dist/hooks/momus-review-persistence/hook.d.ts +19 -0
  19. package/dist/hooks/momus-review-persistence/index.d.ts +1 -0
  20. package/dist/hooks/momus-review-persistence/review-resolution.d.ts +20 -0
  21. package/dist/hooks/prometheus-md-only/constants.d.ts +2 -0
  22. package/dist/hooks/prometheus-md-only/fixtures/denial-log.d.ts +1 -0
  23. package/dist/hooks/prometheus-md-only/fixtures/guarded-hashline.d.ts +1 -0
  24. package/dist/hooks/prometheus-md-only/fixtures/invoke-before.d.ts +7 -0
  25. package/dist/hooks/prometheus-md-only/fixtures/opencode-patch-parser.d.ts +2 -0
  26. package/dist/hooks/prometheus-md-only/hook.d.ts +5 -1
  27. package/dist/hooks/prometheus-md-only/path-policy.d.ts +2 -9
  28. package/dist/hooks/prometheus-md-only/vendor/opencode-patch-parser.d.ts +22 -0
  29. package/dist/index.js +2322 -1045
  30. package/dist/plugin/hooks/create-core-hooks.d.ts +1 -0
  31. package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +2 -1
  32. package/dist/shared/posthog-activity-state.d.ts +1 -0
  33. package/dist/shared/posthog.d.ts +1 -2
  34. package/dist/shared/resolve-file-write-path.d.ts +6 -0
  35. package/dist/skills/ast-grep/README.md +1 -1
  36. package/dist/skills/ast-grep/install.ps1 +5 -3
  37. package/dist/skills/ast-grep/install.sh +4 -5
  38. package/dist/skills/ast-grep/references/install.md +2 -2
  39. package/dist/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  40. package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
  41. package/dist/skills/coding-agent-sessions/AGENTS.md +5 -4
  42. package/dist/skills/coding-agent-sessions/SKILL.md +11 -11
  43. package/dist/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  44. package/dist/skills/coding-agent-sessions/references/codex.md +4 -4
  45. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  46. package/dist/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  47. package/dist/skills/frontend/ATTRIBUTION.md +1 -1
  48. package/dist/skills/frontend/SKILL.md +34 -12
  49. package/dist/skills/frontend/references/design/README.md +2 -2
  50. package/dist/skills/frontend/references/design/_INDEX.md +2 -1
  51. package/dist/skills/frontend/references/design/component-catalogs.md +14 -10
  52. package/dist/skills/frontend/references/design/design-system-architecture.md +19 -6
  53. package/dist/skills/frontend/references/design/grounding.md +29 -0
  54. package/dist/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  55. package/dist/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  56. package/dist/skills/ultimate-browsing/SKILL.md +5 -4
  57. package/dist/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  58. package/dist/skills/ultimate-browsing/engine/__main__.py +9 -6
  59. package/dist/skills/ultimate-browsing/engine/summary.py +1 -1
  60. package/dist/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  61. package/dist/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  62. package/dist/skills/ulw-research/AGENTS.md +8 -4
  63. package/dist/skills/ulw-research/SKILL.md +7 -316
  64. package/dist/skills/ulw-research/references/deliverable-phase.md +23 -21
  65. package/dist/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  66. package/dist/skills/ulw-research/references/fact-ledger.md +42 -8
  67. package/dist/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  68. package/dist/skills/ulw-research/references/markdown-blocks.md +12 -0
  69. package/dist/skills/ulw-research/references/report-gates.md +12 -5
  70. package/dist/skills/ulw-research/references/research-collection.md +195 -0
  71. package/dist/skills/ulw-research/references/research-delivery.md +123 -0
  72. package/dist/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  73. package/dist/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
  74. package/dist/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
  75. package/dist/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
  76. package/dist/skills/ulw-research/scripts/contracts.mjs +13 -4
  77. package/dist/skills/ulw-research/scripts/contracts.test.ts +6 -110
  78. package/dist/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
  79. package/dist/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
  80. package/dist/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
  81. package/dist/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  82. package/dist/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
  83. package/dist/skills/ulw-research/scripts/copy-returns-polish.test.ts +4 -3
  84. package/dist/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  85. package/dist/skills/ulw-research/scripts/css-lite.mjs +4 -2
  86. package/dist/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
  87. package/dist/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
  88. package/dist/skills/ulw-research/scripts/entities.mjs +13 -4
  89. package/dist/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
  90. package/dist/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
  91. package/dist/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
  92. package/dist/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
  93. package/dist/skills/ulw-research/scripts/fact-commands.mjs +35 -16
  94. package/dist/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
  95. package/dist/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  96. package/dist/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
  97. package/dist/skills/ulw-research/scripts/fact-fill.mjs +6 -4
  98. package/dist/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  99. package/dist/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
  100. package/dist/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
  101. package/dist/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  102. package/dist/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
  103. package/dist/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
  104. package/dist/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
  105. package/dist/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  106. package/dist/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  107. package/dist/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  108. package/dist/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  109. package/dist/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
  110. package/dist/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  111. package/dist/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  112. package/dist/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  113. package/dist/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  114. package/dist/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  115. package/dist/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  116. package/dist/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
  117. package/dist/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  118. package/dist/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
  119. package/dist/skills/ulw-research/scripts/gates-static.mjs +10 -1
  120. package/dist/skills/ulw-research/scripts/html-lite.mjs +6 -2
  121. package/dist/skills/ulw-research/scripts/html-markup.mjs +2 -2
  122. package/dist/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  123. package/dist/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
  124. package/dist/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  125. package/dist/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
  126. package/dist/skills/ulw-research/scripts/md-lite.mjs +1 -1
  127. package/dist/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  128. package/dist/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
  129. package/dist/skills/ulw-research/scripts/numerals.mjs +18 -7
  130. package/dist/skills/ulw-research/scripts/numerals.test.ts +3 -0
  131. package/dist/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  132. package/dist/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
  133. package/dist/skills/ulw-research/scripts/outcome.mjs +11 -22
  134. package/dist/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
  135. package/dist/skills/ulw-research/scripts/placeholder.mjs +18 -6
  136. package/dist/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  137. package/dist/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
  138. package/dist/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
  139. package/dist/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  140. package/dist/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  141. package/dist/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
  142. package/dist/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
  143. package/dist/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
  144. package/dist/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
  145. package/dist/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
  146. package/dist/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  147. package/dist/skills/ulw-research/scripts/report-tools.mjs +7 -1
  148. package/dist/skills/ulw-research/scripts/report-tools.test.ts +5 -800
  149. package/dist/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
  150. package/dist/skills/ulw-research/scripts/source-commands.mjs +79 -26
  151. package/dist/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
  152. package/dist/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  153. package/dist/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  154. package/dist/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
  155. package/dist/skills/ulw-research/scripts/source-view.mjs +89 -0
  156. package/dist/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  157. package/dist/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
  158. package/dist/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
  159. package/dist/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
  160. package/dist/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
  161. package/dist/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
  162. package/dist/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
  163. package/dist/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
  164. package/dist/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
  165. package/dist/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
  166. package/dist/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
  167. package/dist/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
  168. package/dist/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
  169. package/dist/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
  170. package/dist/skills/ulw-research/scripts/units.mjs +14 -3
  171. package/dist/skills/ulw-research/scripts/units.test.ts +10 -0
  172. package/dist/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
  173. package/dist/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
  174. package/dist/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
  175. package/dist/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
  176. package/dist/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
  177. package/dist/tools/delegate-task/executor-types.d.ts +1 -0
  178. package/dist/tools/delegate-task/sync-session-existence.d.ts +4 -0
  179. package/dist/tools/delegate-task/types.d.ts +1 -0
  180. package/dist/tools/skill/description-formatter.d.ts +2 -1
  181. package/dist/tools/skill/types.d.ts +6 -0
  182. package/dist/tui.js +131 -33
  183. package/package.json +18 -15
  184. package/packages/git-bash-mcp/package.json +1 -1
  185. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  186. package/packages/omo-codex/plugin/README.md +1 -1
  187. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  188. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  189. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  190. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  191. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  192. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  193. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  194. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  195. package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
  196. package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  197. package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/SKILL.md +7 -7
  198. package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/agents/openai.yaml +1 -1
  199. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  200. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  201. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  202. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  203. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  204. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  205. package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
  206. package/packages/omo-codex/plugin/components/telemetry/README.md +2 -2
  207. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +52 -15
  208. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +52 -19
  209. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  210. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  211. package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +2 -9
  212. package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -13
  213. package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +0 -2
  214. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook-diagnostics.test.ts +0 -3
  215. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +3 -8
  216. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +3 -0
  217. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  218. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  219. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
  220. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  221. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  222. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -0
  223. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  224. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  225. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  226. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  227. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  228. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  229. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  230. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  231. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  232. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  233. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  234. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  235. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  236. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  237. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  238. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  239. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  240. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  241. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  242. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  243. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  244. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  245. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  246. package/packages/omo-codex/plugin/package-lock.json +16 -16
  247. package/packages/omo-codex/plugin/package.json +1 -1
  248. package/packages/omo-codex/plugin/shared/package.json +1 -1
  249. package/packages/omo-codex/plugin/skills/ast-grep/README.md +1 -1
  250. package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +5 -3
  251. package/packages/omo-codex/plugin/skills/ast-grep/install.sh +4 -5
  252. package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
  253. package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  254. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  255. package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +5 -4
  256. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +11 -11
  257. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  258. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +4 -4
  259. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  260. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  261. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +1 -1
  262. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +34 -12
  263. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
  264. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -1
  265. package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +14 -10
  266. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +19 -6
  267. package/packages/omo-codex/plugin/skills/frontend/references/design/grounding.md +29 -0
  268. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  269. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  270. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
  271. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  272. package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +7 -7
  273. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  274. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +5 -4
  275. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  276. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +9 -6
  277. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +1 -1
  278. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  279. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  280. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -0
  281. package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +8 -4
  282. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +7 -316
  283. package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +23 -21
  284. package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  285. package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +42 -8
  286. package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  287. package/packages/omo-codex/plugin/skills/ulw-research/references/markdown-blocks.md +12 -0
  288. package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +12 -5
  289. package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +195 -0
  290. package/packages/omo-codex/plugin/skills/ulw-research/references/research-delivery.md +123 -0
  291. package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  292. package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +13 -4
  293. package/packages/omo-codex/plugin/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  294. package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  295. package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-lite.mjs +4 -2
  296. package/packages/omo-codex/plugin/skills/ulw-research/scripts/entities.mjs +13 -4
  297. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
  298. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
  299. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
  300. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
  301. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +35 -16
  302. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  303. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +6 -4
  304. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  305. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  306. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  307. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  308. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  309. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  310. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
  311. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  312. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  313. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  314. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  315. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  316. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  317. package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  318. package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +10 -1
  319. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +6 -2
  320. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +2 -2
  321. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  322. package/packages/omo-codex/plugin/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  323. package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +1 -1
  324. package/packages/omo-codex/plugin/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  325. package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +18 -7
  326. package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  327. package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +11 -22
  328. package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +18 -6
  329. package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  330. package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  331. package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  332. package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  333. package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +7 -1
  334. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +79 -26
  335. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  336. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  337. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-view.mjs +89 -0
  338. package/packages/omo-codex/plugin/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  339. package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +14 -3
  340. package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +6 -4
  341. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -3
  342. package/packages/omo-codex/scripts/install-dist/install-local.mjs +338 -237
  343. package/packages/prompts-core/prompts/ultrawork/codex.md +3 -0
  344. package/packages/shared-skills/skill-source-filter.mjs +6 -2
  345. package/packages/shared-skills/skills/ast-grep/README.md +1 -1
  346. package/packages/shared-skills/skills/ast-grep/install.ps1 +5 -3
  347. package/packages/shared-skills/skills/ast-grep/install.sh +4 -5
  348. package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
  349. package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  350. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
  351. package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +5 -4
  352. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +11 -11
  353. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  354. package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +4 -4
  355. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  356. package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  357. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +1 -1
  358. package/packages/shared-skills/skills/frontend/SKILL.md +34 -12
  359. package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
  360. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -1
  361. package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +14 -10
  362. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +19 -6
  363. package/packages/shared-skills/skills/frontend/references/design/grounding.md +29 -0
  364. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  365. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  366. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +5 -4
  367. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  368. package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +9 -6
  369. package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +1 -1
  370. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  371. package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  372. package/packages/shared-skills/skills/ulw-research/AGENTS.md +8 -4
  373. package/packages/shared-skills/skills/ulw-research/SKILL.md +7 -316
  374. package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +23 -21
  375. package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  376. package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +42 -8
  377. package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  378. package/packages/shared-skills/skills/ulw-research/references/markdown-blocks.md +12 -0
  379. package/packages/shared-skills/skills/ulw-research/references/report-gates.md +12 -5
  380. package/packages/shared-skills/skills/ulw-research/references/research-collection.md +195 -0
  381. package/packages/shared-skills/skills/ulw-research/references/research-delivery.md +123 -0
  382. package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  383. package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
  384. package/packages/shared-skills/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
  385. package/packages/shared-skills/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
  386. package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +13 -4
  387. package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -110
  388. package/packages/shared-skills/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
  389. package/packages/shared-skills/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
  390. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
  391. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  392. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
  393. package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +4 -3
  394. package/packages/shared-skills/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  395. package/packages/shared-skills/skills/ulw-research/scripts/css-lite.mjs +4 -2
  396. package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
  397. package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
  398. package/packages/shared-skills/skills/ulw-research/scripts/entities.mjs +13 -4
  399. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
  400. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
  401. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
  402. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
  403. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +35 -16
  404. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
  405. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  406. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
  407. package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +6 -4
  408. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  409. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
  410. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
  411. package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  412. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
  413. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
  414. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
  415. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  416. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  417. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  418. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  419. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
  420. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  421. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  422. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  423. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  424. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  425. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  426. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
  427. package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  428. package/packages/shared-skills/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
  429. package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +10 -1
  430. package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +6 -2
  431. package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +2 -2
  432. package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  433. package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
  434. package/packages/shared-skills/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  435. package/packages/shared-skills/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
  436. package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +1 -1
  437. package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  438. package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
  439. package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +18 -7
  440. package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +3 -0
  441. package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  442. package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
  443. package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +11 -22
  444. package/packages/shared-skills/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
  445. package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +18 -6
  446. package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  447. package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
  448. package/packages/shared-skills/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
  449. package/packages/shared-skills/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  450. package/packages/shared-skills/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  451. package/packages/shared-skills/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
  452. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
  453. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
  454. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
  455. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
  456. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  457. package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +7 -1
  458. package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +5 -800
  459. package/packages/shared-skills/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
  460. package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +79 -26
  461. package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
  462. package/packages/shared-skills/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  463. package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  464. package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
  465. package/packages/shared-skills/skills/ulw-research/scripts/source-view.mjs +89 -0
  466. package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  467. package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
  468. package/packages/shared-skills/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
  469. package/packages/shared-skills/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
  470. package/packages/shared-skills/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
  471. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
  472. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
  473. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
  474. package/packages/shared-skills/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
  475. package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
  476. package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
  477. package/packages/shared-skills/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
  478. package/packages/shared-skills/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
  479. package/packages/shared-skills/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
  480. package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +14 -3
  481. package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +10 -0
  482. package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
  483. package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
  484. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
  485. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
  486. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
  487. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +0 -7
  488. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +0 -19
  489. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +0 -1
  490. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +0 -1128
  491. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +0 -77
  492. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +0 -86
  493. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +0 -279
  494. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +0 -252
  495. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +0 -78
@@ -1,14 +1,16 @@
1
1
  // placeholder.mjs - the fact pointer grammar of the fill step and its render helpers.
2
2
  // Value pointers: {{F12:label}}, {{F12:label:value}}, {{F12:label:unit}}, {{F12:label:q}}.
3
+ // Claim prefixes from CLAIM_KINDS (V, D, A) precede any one pointer: {{D:F12:label:value}}, {{V:Q7:label:lead=18}}.
3
4
  // Quote pointers: {{Q7:label}}, {{Q7:label:lead=18}}, {{Q7:label:from="x":to="y"}} (anchors are
4
5
  // JSON strings, so they may hold a colon or an escaped quote). Labels are compared exactly by the
5
6
  // caller; this module never guesses an id. Pure functions; node: builtins only.
6
7
 
7
8
  import { parseNumeral } from "./numerals.mjs"
9
+ import { CLAIM_KINDS } from "./claim-kinds.mjs"
8
10
 
9
11
  export const ELLIPSIS = "\u2026"
10
12
 
11
- const ID = /^([FQ])\d+$/
13
+ const ID = /^([FQ])[1-9]\d*$/
12
14
  const LABEL = /^[^\s:{}"]+$/
13
15
  const VALUE_MODES = new Set(["value", "unit", "q"])
14
16
  const LEAD = /^lead=([1-9]\d*)$/
@@ -45,6 +47,12 @@ function parseAnchors(tail) {
45
47
  export function parsePlaceholder(token) {
46
48
  if (!token.startsWith("{{") || !token.endsWith("}}")) return { error: "a placeholder is {{ID:label...}}" }
47
49
  const body = token.slice(2, -2)
50
+ const marked = Object.entries(CLAIM_KINDS).find(([, entry]) => entry.prefix && body.startsWith(`${entry.prefix}:`))
51
+ if (marked) {
52
+ const [claimKind, entry] = marked
53
+ const parsed = parsePlaceholder(`{{${body.slice(entry.prefix.length + 1)}}}`)
54
+ return parsed.error || parsed.claimKind ? { error: "a claim prefix must precede one fact or quote pointer" } : { ...parsed, claimKind }
55
+ }
48
56
  const colon = body.indexOf(":")
49
57
  const id = colon === -1 ? body : body.slice(0, colon)
50
58
  const idMatch = ID.exec(id)
@@ -130,7 +138,7 @@ export function lead(quote, n) {
130
138
  /** The value and unit parts of a row's raw text ("4.2 eok won" -> value "4.2 eok", unit "won"). */
131
139
  export function valueParts(row) {
132
140
  const unitText = parseNumeral(row.raw)?.unitRaw ?? row.unit
133
- const valueText = unitText && row.raw.endsWith(unitText) ? row.raw.slice(0, -unitText.length).trimEnd() : (row.value ?? row.raw)
141
+ const valueText = unitText && row.raw.endsWith(unitText) ? row.raw.slice(0, -unitText.length).trimEnd() : row.raw
134
142
  return { valueText, unitText: unitText ?? "" }
135
143
  }
136
144
 
@@ -156,15 +164,19 @@ export function escapeHtml(text) {
156
164
  /** The elements the renderers below emit as fact spans; recognizers build their patterns from this. */
157
165
  export const FACT_ELEMENT_TAGS = Object.freeze(["data", "q", "blockquote"])
158
166
 
159
- export function renderValueHtml(row, text) {
167
+ /** `mode` "value" marks a bare value whose unit verify checks beside it; `claimKind` is the claim mark. */
168
+ export function renderValueHtml(row, text, { mode = "full", claimKind = null } = {}) {
160
169
  const unit = row.unit === null ? "" : ` data-unit="${escapeHtml(row.unit)}"`
161
- return `<data class="fact" value="${escapeHtml(row.value)}" data-fact="${row.fact_id}"${unit} data-lineage="${LINEAGE[row.kind]}">${escapeHtml(text)}</data>`
170
+ const marker = mode === "value" ? ' data-fact-mode="value"' : ""
171
+ const mark = claimKind === null ? "" : ` data-claim-kind="${escapeHtml(claimKind)}"`
172
+ return `<data class="fact" value="${escapeHtml(row.value)}" data-fact="${row.fact_id}"${unit}${marker}${mark} data-lineage="${LINEAGE[row.kind]}">${escapeHtml(text)}</data>`
162
173
  }
163
174
 
164
- export function renderQuote(row, selector, text, format) {
175
+ export function renderQuote(row, selector, text, format, claimKind = null) {
165
176
  const marker = `[${row.source_id}]`
166
177
  if (format === "md") return `"${text}" ${marker}`
167
- return `<q data-fact="${row.fact_id}" data-quote-sel="${escapeHtml(selector)}">${escapeHtml(text)}</q> ${marker}`
178
+ const mark = claimKind === null ? "" : ` data-claim-kind="${escapeHtml(claimKind)}"`
179
+ return `<q data-fact="${row.fact_id}"${mark} data-quote-sel="${escapeHtml(selector)}">${escapeHtml(text)}</q> ${marker}`
168
180
  }
169
181
 
170
182
  const RENDERED_MD_QUOTE = /^"([\s\S]*)" (\[S\d+\])$/u
@@ -54,9 +54,10 @@ export const POLISH_REFERENCE_REASON = "edit touches a character reference: rout
54
54
  /** True when [start, end) overlaps a character reference of html or starts inside one. */
55
55
  export function touchesReference(html, start, end) {
56
56
  for (const match of String(html).matchAll(CHARACTER_REFERENCE)) {
57
- if (match.index < end && match.index + match[0].length > start) return true
57
+ const stop = match.index + match[0].length
58
+ if (match.index < end && (stop > start || (stop === start && !match[0].endsWith(";")))) return true
58
59
  }
59
- return /&[#\w]*$/.test(html.slice(Math.max(0, start - 16), start))
60
+ return false
60
61
  }
61
62
 
62
63
  const escape = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
@@ -0,0 +1,110 @@
1
+ // raw-decode.mjs - decode a source's raw bytes in their declared encoding and keep a byte map.
2
+ //
3
+ // decodeRaw returns { text, encoding, bytes } where bytes[i] is the raw byte offset at which UTF-16
4
+ // unit i of `text` starts and bytes[text.length] === raw.length, so any text range maps back to the
5
+ // bytes the source actually holds (never to a lossy UTF-8 re-encode). The encoding comes from a
6
+ // BOM, then the caller's declared charset (HTTP header or meta.json), then an HTML <meta> charset,
7
+ // and defaults to UTF-8. node: builtins only (TextDecoder).
8
+
9
+ const SNIFF_BYTES = 1024
10
+ const META_CHARSET = /<meta\b[^>]*?charset\s*=\s*["']?\s*([\w.:-]+)/i
11
+
12
+ /** The WHATWG encoding name for a label, or null when the runtime does not know it. */
13
+ export function encodingOf(label) {
14
+ if (typeof label !== "string" || label.trim() === "") return null
15
+ try {
16
+ return new TextDecoder(label.trim()).encoding
17
+ } catch {
18
+ return null
19
+ }
20
+ }
21
+
22
+ /** charset=... from a Content-Type header value, as an encoding name, or null. */
23
+ export function headerCharset(contentType) {
24
+ const match = /charset\s*=\s*["']?([\w.:-]+)/i.exec(String(contentType ?? ""))
25
+ return match ? encodingOf(match[1]) : null
26
+ }
27
+
28
+ function bomOf(raw) {
29
+ if (raw[0] === 0xef && raw[1] === 0xbb && raw[2] === 0xbf) return { encoding: "utf-8", skip: 3 }
30
+ if (raw[0] === 0xff && raw[1] === 0xfe) return { encoding: "utf-16le", skip: 2 }
31
+ if (raw[0] === 0xfe && raw[1] === 0xff) return { encoding: "utf-16be", skip: 2 }
32
+ return null
33
+ }
34
+
35
+ /** BOM, then the declared charset, then (for markup) a <meta> charset in the first 1 KiB, then UTF-8. */
36
+ export function detectEncoding(raw, declared = null, markup = false) {
37
+ const bom = bomOf(raw)
38
+ if (bom) return bom.encoding
39
+ const given = encodingOf(declared)
40
+ if (given) return given
41
+ if (markup) {
42
+ const sniffed = META_CHARSET.exec(Buffer.from(raw.subarray(0, SNIFF_BYTES)).toString("latin1"))
43
+ const named = sniffed ? encodingOf(sniffed[1]) : null
44
+ // A page that is already decoded to UTF-16 cannot declare a UTF-16 charset in ASCII bytes.
45
+ if (named && !named.startsWith("utf-16")) return named
46
+ }
47
+ return "utf-8"
48
+ }
49
+
50
+ function utf8Map(text, bytes, from) {
51
+ let at = from
52
+ for (let i = 0; i < text.length; i++) {
53
+ bytes[i] = at
54
+ const code = text.charCodeAt(i)
55
+ if (code >= 0xd800 && code <= 0xdbff && i + 1 < text.length) {
56
+ bytes[++i] = at
57
+ at += 4
58
+ } else at += code < 0x80 ? 1 : code < 0x800 ? 2 : 3
59
+ }
60
+ return at
61
+ }
62
+
63
+ /** Byte-at-a-time streaming decode: correct for any encoding, used when no shortcut applies. */
64
+ function streamMap(raw, encoding, from) {
65
+ const decoder = new TextDecoder(encoding)
66
+ const units = []
67
+ const starts = []
68
+ let pending = from
69
+ for (let i = from; i < raw.length; i++) {
70
+ const out = decoder.decode(raw.subarray(i, i + 1), { stream: true })
71
+ if (out.length === 0) continue
72
+ // A replacement for an earlier broken sequence can arrive with this byte's own character.
73
+ const own = out.length > 1 && raw[i] < 0x80 ? 1 : 0
74
+ for (let k = 0; k < out.length; k++) starts.push(k >= out.length - own ? i : pending)
75
+ units.push(out)
76
+ pending = i + 1
77
+ }
78
+ const tail = decoder.decode()
79
+ for (let k = 0; k < tail.length; k++) starts.push(pending)
80
+ units.push(tail)
81
+ return { text: units.join(""), starts }
82
+ }
83
+
84
+ /** Decode raw bytes; bytes is an Int32Array of length text.length + 1 (see the file comment). */
85
+ export function decodeRaw(raw, declared = null, markup = false) {
86
+ const buffer = Buffer.from(raw)
87
+ const encoding = detectEncoding(buffer, declared, markup)
88
+ const skip = bomOf(buffer)?.encoding === encoding ? bomOf(buffer).skip : 0
89
+ if (encoding === "utf-8") {
90
+ try {
91
+ const text = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(buffer.subarray(skip))
92
+ const bytes = new Int32Array(text.length + 1)
93
+ bytes[text.length] = utf8Map(text, bytes, skip)
94
+ return { text, encoding, bytes }
95
+ } catch {
96
+ // invalid UTF-8: fall through to the streaming map, which counts each broken byte once
97
+ }
98
+ }
99
+ if (encoding !== "utf-8" && !encoding.startsWith("utf-16")) {
100
+ const text = new TextDecoder(encoding).decode(buffer.subarray(skip))
101
+ if (text.length === buffer.length - skip) {
102
+ const bytes = new Int32Array(text.length + 1)
103
+ for (let i = 0; i <= text.length; i++) bytes[i] = skip + i
104
+ return { text, encoding, bytes }
105
+ }
106
+ }
107
+ const { text, starts } = streamMap(buffer, encoding, skip)
108
+ const bytes = Int32Array.from([...starts, buffer.length])
109
+ return { text, encoding, bytes }
110
+ }
@@ -0,0 +1,47 @@
1
+ // Byte locators over a source view (source-view.mjs) and exact, context-bound re-anchoring.
2
+ // Matching always happens on the view's text (text nodes of a page, never markup); only the
3
+ // stored offsets are bytes of the view's artifact. value_span remains quote-relative text.
4
+
5
+ const chars = (text) => [...text]
6
+
7
+ /** Context is copied before normalization, around the value (or the whole quote for Q rows). */
8
+ export function quoteContext(text, start, end) {
9
+ return { prefix: chars(text.slice(0, start)).slice(-32).join(""), suffix: chars(text.slice(end)).slice(0, 32).join("") }
10
+ }
11
+
12
+ /** Convert a text-space locator from fact-locate.mjs into artifact byte offsets. */
13
+ export function rawLocated(view, found) {
14
+ if (found.error) return found
15
+ const { char_start: start, char_end: end } = found.locator
16
+ const from = start + (found.value_span?.[0] ?? 0)
17
+ const to = found.value_span ? start + found.value_span[1] : end
18
+ const [byteStart, byteEnd] = view.byteSpan(start, end)
19
+ return {
20
+ ...found,
21
+ context: quoteContext(view.text, from, to),
22
+ locator: { ...found.locator, artifact: view.artifact, unit: "bytes", char_start: byteStart, char_end: byteEnd },
23
+ }
24
+ }
25
+
26
+ function contextMatches(text, row, start, end) {
27
+ if (!row.context) return false
28
+ const from = row.value_span ? start + row.value_span[0] : start
29
+ const to = row.value_span ? start + row.value_span[1] : end
30
+ const { prefix, suffix } = row.context
31
+ return from >= prefix.length && text.slice(from - prefix.length, from) === prefix && text.slice(to, to + suffix.length) === suffix
32
+ }
33
+
34
+ /**
35
+ * The row's quote in the view: unchanged when an exact occurrence sits at the pinned byte range,
36
+ * else exactly one occurrence whose context matches (relocated), else null. Never rewrites the row.
37
+ */
38
+ export function reanchor(view, row) {
39
+ const quote = String(row.quote ?? "")
40
+ if (quote === "" || !view.byteSpan) return null
41
+ const { char_start: start, char_end: end } = row.locator
42
+ const hits = []
43
+ for (let at = view.text.indexOf(quote); at !== -1; at = view.text.indexOf(quote, at + 1)) hits.push({ at, span: view.byteSpan(at, at + quote.length) })
44
+ if (hits.some(({ span }) => span[0] === start && span[1] === end)) return { start, end, relocated: false }
45
+ const matching = hits.filter(({ at }) => contextMatches(view.text, row, at, at + quote.length))
46
+ return matching.length === 1 ? { start: matching[0].span[0], end: matching[0].span[1], relocated: true } : null
47
+ }
@@ -133,7 +133,7 @@ export async function runOutcome(argv) {
133
133
  switch (sub) {
134
134
  case "init": {
135
135
  const promised = args.required("promised").split(",").map((s) => s.trim()).filter(Boolean)
136
- const manifest = outcome.initManifest({ sessionDir: sessionDirFrom(args.flags), promised, lane: args.flags.lane ?? null, now: nowFrom(args.flags) })
136
+ const manifest = outcome.initManifest({ sessionDir: sessionDirFrom(args.flags), promised, lane: args.flags.lane ?? null, now: nowFrom(args.flags), startedAt: args.flags["started-at"] })
137
137
  outcome.writeManifest(file, manifest)
138
138
  return { json: { command: "outcome init", path: file, deliverables: manifest.deliverables }, exitCode: 0 }
139
139
  }
@@ -28,6 +28,8 @@ export const COMMANDS = Object.freeze([
28
28
  "fact verify",
29
29
  "fact derive",
30
30
  "source snapshot",
31
+ "source refresh",
32
+ "source probe-conversion",
31
33
  "claims index",
32
34
  ])
33
35
 
@@ -53,7 +55,11 @@ export async function run(argv) {
53
55
  return (await import("./source-commands.mjs")).runClaims(rest)
54
56
  case "--help":
55
57
  case "help":
56
- if (rest.includes("--json")) return { json: { commands: COMMANDS }, exitCode: 0 }
58
+ if (rest.includes("--json")) {
59
+ const { SNAPSHOT_USAGE } = await import("./source-commands.mjs")
60
+ const { REFRESH_USAGE } = await import("./source-refresh.mjs")
61
+ return { json: { commands: COMMANDS, usage: { "source snapshot": SNAPSHOT_USAGE, "source refresh": REFRESH_USAGE } }, exitCode: 0 }
62
+ }
57
63
  return { text: `report-tools <command>\n${COMMANDS.map((name) => ` ${name}`).join("\n")}`, exitCode: 0 }
58
64
  default:
59
65
  throw new CliError(`usage: report-tools <${COMMANDS.join(" | ")}> (run --help)`)
@@ -1,9 +1,13 @@
1
- // source-commands.mjs - the `source snapshot` and `claims index` subcommands of report-tools.
2
- // A source dir is immutable: the same id with identical text is a no-op, different text fails
3
- // (exit 1, snapshot_exists), because ledger rows pin the old hash. `--url` fetches with plain
4
- // fetch (30 s timeout, no browser) and records extractor tool:source-snapshot@1; `--html` and
5
- // `--text` import a browser-lane capture and record extractor model (lower trust), or the named
6
- // extractor for `--text --extractor NAME@VERSION`; `--command` runs an argv without a shell and
1
+ // source-commands.mjs - the `source snapshot`, `source refresh` and `claims index` subcommands of
2
+ // report-tools. A source dir is immutable: the same id with identical bytes is a no-op, different
3
+ // bytes fail (exit 1, snapshot_exists), because ledger rows pin the old hash; `source refresh`
4
+ // (source-refresh.mjs) is the one explicit repin. `--replace` swaps in a corrected capture under the
5
+ // same id (the conversion_altered_number recovery) only while no active ledger row cites the id
6
+ // (exit 1, snapshot_pinned, listing them). `--url` fetches with plain fetch (30 s timeout,
7
+ // no browser) and records extractor tool:source-snapshot@1; `--html` imports a browser-lane page
8
+ // capture and `--raw` alone a saved file's bytes (extractor model). `--text` alone registers a converted-only source (no raw bytes:
9
+ // quotes only); `--raw <bytes> --text <extraction> --extractor NAME@VERSION` keeps the original
10
+ // bytes and declares the text their extraction. `--command` runs an argv without a shell and
7
11
  // snapshots its stdout, with the argv, cwd, exit status, and output hashes in command.json.
8
12
  // node: builtins and sibling imports only.
9
13
 
@@ -13,14 +17,18 @@ import { join, resolve } from "node:path"
13
17
 
14
18
  import { indexClaims } from "./claims-index.mjs"
15
19
  import { CliError, parseArgs, sha256Of, writeJsonAtomic } from "./cli-support.mjs"
20
+ import { runConversionProbe } from "./conversion-probe.mjs"
21
+ import { readLedger } from "./fact-ledger.mjs"
16
22
  import { parseFidelityBlock } from "./fidelity-brief.mjs"
17
23
  import { parseSourceFloor } from "./fidelity-policy.mjs"
24
+ import { encodingOf, headerCharset } from "./raw-decode.mjs"
18
25
  import { writeSnapshot } from "./source-snapshot.mjs"
26
+ import { readSnapshot } from "./source-view.mjs"
19
27
 
20
28
  const FETCH_TIMEOUT_MS = 30_000
21
29
  const TOOL_EXTRACTOR = "tool:source-snapshot@1"
22
- const SNAPSHOT_USAGE =
23
- "usage: source snapshot --id S<n> (--url <u> | --html <file> | --text <file> [--extractor NAME@VERSION] | --command '<argv json>' --cwd DIR) [--kind page|command|document] [--provenance primary|secondary] [--revision R] --session-dir D"
30
+ export const SNAPSHOT_USAGE =
31
+ "usage: source probe-conversion <raw-file> <converted-file> | source snapshot --id S<n> (--url <u> | --html <file> | --raw <file> [--text <file> --extractor NAME@VERSION] | --text <file> (converted-only) | --command '<argv json>' --cwd DIR) [--charset NAME] [--kind page|command|document|converted-only] [--provenance primary|secondary] [--revision R] [--replace] --session-dir D"
24
32
 
25
33
  function readInput(path) {
26
34
  try {
@@ -37,12 +45,15 @@ export function sessionDirOf(flags) {
37
45
  return resolve(dir)
38
46
  }
39
47
 
40
- /** The snapshot of one source: meta.json, text.txt, and source.html when the source was a page. */
48
+ /** The snapshot as source-view.mjs reads it ({ meta, raw, sha256, drift, view }); unreadable is a usage error. */
41
49
  export function snapshotOf(sessionDir, id) {
42
50
  const dir = join(sessionDir, "sources", String(id))
43
51
  if (!existsSync(join(dir, "meta.json"))) throw new CliError(`source ${id} has no snapshot; run source snapshot --id ${id} first`)
44
- const html = join(dir, "source.html")
45
- return { meta: JSON.parse(readInput(join(dir, "meta.json"))), text: readInput(join(dir, "text.txt")), html: existsSync(html) ? readInput(html) : null }
52
+ try {
53
+ return readSnapshot(dir)
54
+ } catch (error) {
55
+ throw new CliError(`source ${id}: ${error.message}`)
56
+ }
46
57
  }
47
58
 
48
59
  /**
@@ -72,10 +83,10 @@ async function fetchSource(url) {
72
83
  const type = response.headers.get("content-type") ?? ""
73
84
  if (/pdf/i.test(type)) {
74
85
  await response.body?.cancel()
75
- throw new CliError(`pdf response: ${url}; extract its text and use --text <file> --extractor NAME@VERSION`)
86
+ throw new CliError(`pdf response: ${url}; save the bytes and use --raw <file.pdf> --text <extracted.txt> --extractor NAME@VERSION`)
76
87
  }
77
- const body = await response.text()
78
- return /html|xml/i.test(type) || /^\s*</.test(body) ? { url, html: body } : { url, text: body }
88
+ const raw = Buffer.from(await response.arrayBuffer())
89
+ return { url, raw, charset: headerCharset(type), markup: /html|xml/i.test(type) || /^\s*</.test(raw.subarray(0, 1024).toString("latin1")) }
79
90
  }
80
91
 
81
92
  function runCommand(argvJson, cwd) {
@@ -89,35 +100,76 @@ function runCommand(argvJson, cwd) {
89
100
  throw new CliError("--command must be a non-empty JSON array of non-empty strings")
90
101
  }
91
102
  if (!cwd || cwd === true) throw new CliError("--command needs --cwd DIR")
92
- const proc = spawnSync(argv[0], argv.slice(1), { cwd: resolve(cwd), encoding: "utf8", shell: false, maxBuffer: 64 * 1024 * 1024 })
103
+ const proc = spawnSync(argv[0], argv.slice(1), { cwd: resolve(cwd), shell: false, maxBuffer: 64 * 1024 * 1024 })
93
104
  if (proc.error) throw new CliError(`--command could not start: ${proc.error.message}`)
94
105
  const receipt = { argv, cwd: resolve(cwd), exit_status: proc.status, stdout_sha256: sha256Of(proc.stdout), stderr_sha256: sha256Of(proc.stderr) }
95
- return { path: `command:${argv.join(" ")}`, text: proc.stdout, kind: "command", receipt }
106
+ return { path: `command:${argv.join(" ")}`, raw: proc.stdout, kind: "command", receipt }
107
+ }
108
+
109
+ function readBytes(path) {
110
+ try {
111
+ return readFileSync(path)
112
+ } catch (error) {
113
+ throw new CliError(`cannot read ${path}: ${error.code ?? error.message}`)
114
+ }
96
115
  }
97
116
 
98
- async function acquire(flags) {
117
+ /** The snapshot input the flags describe; shared by `source snapshot` and `source refresh`. */
118
+ export async function acquire(flags) {
99
119
  const given = ["url", "html", "text", "command"].filter((name) => flags[name] !== undefined)
100
- if (given.length !== 1) throw new CliError(SNAPSHOT_USAGE)
120
+ if (flags.raw !== undefined && given.some((name) => name !== "text")) throw new CliError("--raw goes alone or with --text (--url, --html and --command already keep the raw bytes)")
121
+ if (given.length + (flags.raw !== undefined && flags.text === undefined ? 1 : 0) !== 1) throw new CliError(SNAPSHOT_USAGE)
101
122
  if (flags.extractor !== undefined && flags.text === undefined) throw new CliError("--extractor goes with --text only")
102
- if (flags.url !== undefined) return { ...(await fetchSource(flags.url)), extractor: TOOL_EXTRACTOR }
103
- if (flags.html !== undefined) return { path: resolve(flags.html), html: readInput(flags.html), extractor: "model" }
104
- if (flags.text !== undefined) return { path: resolve(flags.text), text: readInput(flags.text), extractor: flags.extractor === undefined ? "model" : `extractor:${flags.extractor}` }
123
+ if (flags.charset !== undefined && encodingOf(flags.charset) === null) throw new CliError(`--charset ${flags.charset} is not a known encoding`)
124
+ const charset = flags.charset === undefined ? {} : { charset: encodingOf(flags.charset) }
125
+ if (flags.url !== undefined) return { ...(await fetchSource(flags.url)), ...charset, extractor: TOOL_EXTRACTOR }
126
+ if (flags.html !== undefined) return { path: resolve(flags.html), raw: readBytes(flags.html), markup: true, ...charset, extractor: "model" }
127
+ if (flags.raw !== undefined && flags.text === undefined) return { path: resolve(flags.raw), raw: readBytes(flags.raw), ...charset, extractor: "model" }
128
+ if (flags.text !== undefined) {
129
+ const extractor = flags.extractor === undefined ? "model" : `extractor:${flags.extractor}`
130
+ if (flags.raw !== undefined) return { path: resolve(flags.raw), raw: readBytes(flags.raw), text: readInput(flags.text), ...charset, extractor }
131
+ if (flags.kind !== undefined && flags.kind !== "converted-only") throw new CliError("--text without --raw registers a converted-only source; pass --raw <original bytes> to keep a measurable snapshot")
132
+ return { path: resolve(flags.text), text: readInput(flags.text), kind: "converted-only", extractor }
133
+ }
105
134
  return { ...runCommand(flags.command, flags.cwd), extractor: TOOL_EXTRACTOR }
106
135
  }
107
136
 
137
+ /**
138
+ * `--replace` with `--text` alone (the conversion_altered_number recovery) keeps the source's raw.bin and
139
+ * declares the verified text its extraction, so value rows locate in text.txt while the original bytes stay
140
+ * pinned; plain `--text` without `--replace`, or over an id with no raw.bin, stays converted-only.
141
+ */
142
+ function declareOverKeptRaw(sourcesDir, id, input) {
143
+ const dir = join(sourcesDir, String(id))
144
+ if (input.kind !== "converted-only" || !existsSync(join(dir, "raw.bin")) || !existsSync(join(dir, "meta.json"))) return
145
+ const before = JSON.parse(readFileSync(join(dir, "meta.json"), "utf8"))
146
+ Object.assign(input, { url: before.url, raw: readFileSync(join(dir, "raw.bin")), kind: before.kind, declared: true })
147
+ delete input.path
148
+ }
149
+
108
150
  export async function runSource(argv) {
109
151
  const [sub, ...rest] = argv
152
+ if (sub === "refresh") return (await import("./source-refresh.mjs")).runRefresh(rest)
153
+ if (sub === "probe-conversion") return runConversionProbe(rest)
110
154
  if (sub !== "snapshot") throw new CliError(SNAPSHOT_USAGE)
111
- const args = parseArgs(rest)
155
+ const args = parseArgs(rest, { booleans: ["replace"] })
112
156
  const id = args.required("id")
113
- const sourcesDir = join(sessionDirOf(args.flags), "sources")
157
+ const sessionDir = sessionDirOf(args.flags)
158
+ const sourcesDir = join(sessionDir, "sources")
159
+ const replace = args.flags.replace === true
160
+ const pinned = replace ? readLedger(sessionDir).rows.filter((row) => row.source_id === id && (row.status ?? "active") === "active").map((row) => row.fact_id) : []
161
+ if (pinned.length > 0) {
162
+ const message = `${id} is cited by active row(s) ${pinned.join(", ")}; retract them first, or snapshot the corrected text under a new id`
163
+ return { json: { command: "source snapshot", status: "fail", exitCode: 1, error: "snapshot_pinned", message, rows: pinned }, summary: `source snapshot: ${message}`, exitCode: 1 }
164
+ }
114
165
  const { receipt, ...input } = await acquire(args.flags)
166
+ if (replace) declareOverKeptRaw(sourcesDir, id, input)
115
167
  if (args.flags.kind !== undefined) input.kind = args.flags.kind
116
168
  if (args.flags.provenance !== undefined) input.provenance = args.flags.provenance
117
169
  if (args.flags.revision !== undefined) input.revision = args.flags.revision
118
170
  let written
119
171
  try {
120
- written = writeSnapshot(sourcesDir, id, input)
172
+ written = writeSnapshot(sourcesDir, id, input, { replace })
121
173
  } catch (error) {
122
174
  if (String(error.message).startsWith("snapshot_exists")) {
123
175
  return { json: { command: "source snapshot", status: "fail", exitCode: 1, error: "snapshot_exists", message: error.message }, summary: `source snapshot: ${error.message}`, exitCode: 1 }
@@ -127,8 +179,9 @@ export async function runSource(argv) {
127
179
  }
128
180
  if (receipt) writeFileSync(join(written.dir, "command.json"), `${JSON.stringify(receipt, null, 2)}\n`)
129
181
  const meta = JSON.parse(readFileSync(join(written.dir, "meta.json"), "utf8"))
130
- const data = { source_id: id, directory: written.dir, snapshot_sha256: written.sha256, extractor: meta.extractor, kind: meta.kind, provenance: meta.provenance }
131
- return { json: { command: "source snapshot", status: "pass", exitCode: 0, data }, summary: `source snapshot: ${id} ${written.sha256.slice(0, 12)} (${meta.extractor})`, exitCode: 0 }
182
+ const data = { source_id: id, directory: written.dir, snapshot_sha256: written.sha256, extractor: meta.extractor, kind: meta.kind, provenance: meta.provenance, text_source: meta.text_source, ...(written.altered ? { conversion_altered_numbers: written.altered } : {}) }
183
+ const probe = written.altered ? `; conversion ${written.altered.length} altered${written.altered.length ? ` (${written.altered.join(", ")}): fact add refuses those numbers` : ""}` : ""
184
+ return { json: { command: "source snapshot", status: "pass", exitCode: 0, data }, summary: `source snapshot: ${id} ${written.sha256.slice(0, 12)} (${meta.extractor}, ${meta.text_source})${probe}`, exitCode: 0 }
132
185
  }
133
186
 
134
187
  export function runClaims(argv) {
@@ -0,0 +1,82 @@
1
+ // source-refresh.mjs - `source refresh <S<n>>`: the one explicit repin of a source snapshot.
2
+ //
3
+ // Re-fetches meta.url (or reads the new capture given with the source snapshot input flags),
4
+ // replaces the snapshot, and re-anchors every active byte-located ledger row on that source by its
5
+ // exact quote plus its stored context (raw-locator.mjs reanchor): a row found once gets the new
6
+ // snapshot_sha256 and keeps its old locator, so `fact verify` then reports minor `relocated` with
7
+ // the old and new byte offsets; a row whose quote is gone keeps its old pin, is reported as
8
+ // quote_not_verbatim here, and stays a snapshot_hash_mismatch blocker until it is retracted or
9
+ // re-added. A legacy text.txt row on the source (no byte locator) cannot be re-anchored: it is
10
+ // listed as legacy_not_reanchored and stays a blocker. Exit 0 when every row re-anchored, 1 otherwise. node: builtins and sibling imports only.
11
+
12
+ import { writeFileSync } from "node:fs"
13
+ import { join } from "node:path"
14
+
15
+ import { CliError, parseArgs } from "./cli-support.mjs"
16
+ import { DEFECT_CODES } from "./contracts.mjs"
17
+ import { readLedger, writeLedger } from "./fact-ledger.mjs"
18
+ import { reanchor } from "./raw-locator.mjs"
19
+ import { acquire, sessionDirOf, snapshotOf } from "./source-commands.mjs"
20
+ import { writeSnapshot } from "./source-snapshot.mjs"
21
+
22
+ export const REFRESH_USAGE =
23
+ "usage: source refresh S<n> [--url <u> | --html <file> | --raw <file> [--text <file> --extractor NAME@VERSION] | --text <file> | --command '<argv json>' --cwd DIR] [--charset NAME] --session-dir D (no input flag re-fetches the source's http(s) url)"
24
+
25
+ const INPUTS = ["url", "html", "raw", "text", "command"]
26
+
27
+ const defect = (code, message) => ({ code, severity: DEFECT_CODES[code].severity, integrity: DEFECT_CODES[code].integrity, message })
28
+
29
+ export async function runRefresh(argv) {
30
+ const args = parseArgs(argv)
31
+ const id = args.positionals[0] ?? args.flags.id
32
+ if (!id || id === true) throw new CliError(REFRESH_USAGE)
33
+ const sessionDir = sessionDirOf(args.flags)
34
+ const before = snapshotOf(sessionDir, id)
35
+ const flags = { ...args.flags }
36
+ if (!INPUTS.some((name) => flags[name] !== undefined)) {
37
+ if (!/^https?:\/\//i.test(String(before.meta.url))) throw new CliError(`${id} was not fetched from an http(s) url; pass its new capture. ${REFRESH_USAGE}`)
38
+ flags.url = before.meta.url
39
+ }
40
+ const { receipt, ...input } = await acquire(flags)
41
+ input.kind ??= flags.kind ?? before.meta.kind
42
+ input.provenance = flags.provenance ?? before.meta.provenance
43
+ input.revision = flags.revision ?? before.meta.revision ?? undefined
44
+ let written
45
+ try {
46
+ written = writeSnapshot(join(sessionDir, "sources"), id, input, { replace: true })
47
+ } catch (error) {
48
+ if (error instanceof TypeError) throw new CliError(error.message)
49
+ throw error
50
+ }
51
+ if (receipt) writeFileSync(join(written.dir, "command.json"), `${JSON.stringify(receipt, null, 2)}\n`)
52
+ const after = snapshotOf(sessionDir, id)
53
+ const ledger = readLedger(sessionDir)
54
+ const rows = []
55
+ const defects = []
56
+ for (const row of ledger.rows) {
57
+ if (row.source_id !== id || row.status !== "active") continue
58
+ if (row.locator?.unit === undefined) {
59
+ rows.push({ fact_id: row.fact_id, status: "legacy_not_reanchored" })
60
+ defects.push(defect("snapshot_hash_mismatch", `${row.fact_id}: a legacy text.txt row has no byte locator to re-anchor on refreshed ${id}; add it again from the new snapshot or retract it`))
61
+ continue
62
+ }
63
+ if (row.locator.unit !== "bytes") continue
64
+ const anchor = row.locator.artifact === after.view.artifact ? reanchor(after.view, row) : null
65
+ const span = `${row.locator.char_start}:${row.locator.char_end}`
66
+ if (!anchor) {
67
+ rows.push({ fact_id: row.fact_id, status: "not_found", from: span })
68
+ defects.push(defect("quote_not_verbatim", `${row.fact_id}: its quote and context are not found once in refreshed ${id}; retract it or add it again from the new snapshot`))
69
+ continue
70
+ }
71
+ row.snapshot_sha256 = after.sha256
72
+ rows.push({ fact_id: row.fact_id, status: anchor.relocated ? "relocated" : "unchanged", from: span, to: `${anchor.start}:${anchor.end}` })
73
+ if (anchor.relocated) defects.push(defect("relocated", `${row.fact_id}: ${span} -> ${anchor.start}:${anchor.end} (bytes of ${id}/${after.view.artifact})`))
74
+ }
75
+ writeLedger(sessionDir, ledger)
76
+ const failed = rows.filter((row) => row.status === "not_found" || row.status === "legacy_not_reanchored").length
77
+ const exitCode = failed > 0 ? 1 : 0
78
+ const data = { source_id: id, previous_sha256: before.sha256, snapshot_sha256: after.sha256, text_source: after.view.mode, rows }
79
+ const json = { command: "source refresh", status: exitCode === 0 ? "pass" : "fail", exitCode, defects, data }
80
+ const moved = rows.filter((row) => row.status === "relocated").length
81
+ return { json, summary: `source refresh: ${id} ${before.sha256.slice(0, 12)} -> ${after.sha256.slice(0, 12)}; ${rows.length - failed} row(s) re-anchored (${moved} relocated), ${failed} not re-anchored`, exitCode }
82
+ }