oh-my-opencode 5.1.47 → 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.
- package/dist/agents/refusal-rule.d.ts +7 -0
- package/dist/cli/index.js +1194 -752
- package/dist/cli/service-auth/accounts-gate.d.ts +11 -0
- package/dist/cli/service-auth/commands.d.ts +2 -4
- package/dist/cli/service-auth/index.d.ts +1 -1
- package/dist/cli/service-auth/keystore.d.ts +26 -2
- package/dist/cli/service-auth/protocol.d.ts +7 -1
- package/dist/cli/service-auth/session.d.ts +6 -0
- package/dist/cli/service-auth/signed-out-marker.d.ts +11 -0
- package/dist/cli-node/index.js +1194 -752
- package/dist/config/schema/hooks.d.ts +1 -0
- package/dist/create-hooks.d.ts +1 -0
- package/dist/features/boulder-state/storage.d.ts +1 -1
- package/dist/features/boulder-state/types.d.ts +1 -1
- package/dist/hooks/atlas/idle-continuation.d.ts +2 -1
- package/dist/hooks/atlas/types.d.ts +9 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/momus-review-persistence/hook.d.ts +19 -0
- package/dist/hooks/momus-review-persistence/index.d.ts +1 -0
- package/dist/hooks/momus-review-persistence/review-resolution.d.ts +20 -0
- package/dist/hooks/prometheus-md-only/constants.d.ts +2 -0
- package/dist/hooks/prometheus-md-only/fixtures/denial-log.d.ts +1 -0
- package/dist/hooks/prometheus-md-only/fixtures/guarded-hashline.d.ts +1 -0
- package/dist/hooks/prometheus-md-only/fixtures/invoke-before.d.ts +7 -0
- package/dist/hooks/prometheus-md-only/fixtures/opencode-patch-parser.d.ts +2 -0
- package/dist/hooks/prometheus-md-only/hook.d.ts +5 -1
- package/dist/hooks/prometheus-md-only/path-policy.d.ts +2 -9
- package/dist/hooks/prometheus-md-only/vendor/opencode-patch-parser.d.ts +22 -0
- package/dist/index.js +2322 -1045
- package/dist/plugin/hooks/create-core-hooks.d.ts +1 -0
- package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +2 -1
- package/dist/shared/posthog-activity-state.d.ts +1 -0
- package/dist/shared/posthog.d.ts +1 -2
- package/dist/shared/resolve-file-write-path.d.ts +6 -0
- package/dist/skills/ast-grep/README.md +1 -1
- package/dist/skills/ast-grep/install.ps1 +5 -3
- package/dist/skills/ast-grep/install.sh +4 -5
- package/dist/skills/ast-grep/references/install.md +2 -2
- package/dist/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
- package/dist/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/dist/skills/coding-agent-sessions/SKILL.md +11 -11
- package/dist/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/dist/skills/coding-agent-sessions/references/codex.md +4 -4
- package/dist/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/dist/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/dist/skills/frontend/ATTRIBUTION.md +1 -1
- package/dist/skills/frontend/SKILL.md +34 -12
- package/dist/skills/frontend/references/design/README.md +2 -2
- package/dist/skills/frontend/references/design/_INDEX.md +2 -1
- package/dist/skills/frontend/references/design/component-catalogs.md +14 -10
- package/dist/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/dist/skills/frontend/references/design/grounding.md +29 -0
- package/dist/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/dist/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/dist/skills/ultimate-browsing/SKILL.md +5 -4
- package/dist/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/dist/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/dist/skills/ultimate-browsing/engine/summary.py +1 -1
- package/dist/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/dist/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/dist/skills/ulw-research/AGENTS.md +8 -4
- package/dist/skills/ulw-research/SKILL.md +7 -259
- package/dist/skills/ulw-research/references/deliverable-phase.md +68 -24
- package/dist/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/dist/skills/ulw-research/references/fact-ledger.md +42 -8
- package/dist/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/dist/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/dist/skills/ulw-research/references/report-gates.md +14 -6
- package/dist/skills/ulw-research/references/research-collection.md +195 -0
- package/dist/skills/ulw-research/references/research-delivery.md +123 -0
- package/dist/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/dist/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
- package/dist/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
- package/dist/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
- package/dist/skills/ulw-research/scripts/contracts.mjs +16 -15
- package/dist/skills/ulw-research/scripts/contracts.test.ts +6 -109
- package/dist/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
- package/dist/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
- package/dist/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
- package/dist/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/dist/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
- package/dist/skills/ulw-research/scripts/copy-returns-fidelity-policy.test.ts +156 -0
- package/dist/skills/ulw-research/scripts/copy-returns-polish.test.ts +10 -9
- package/dist/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/dist/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/dist/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
- package/dist/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
- package/dist/skills/ulw-research/scripts/entities.mjs +13 -4
- package/dist/skills/ulw-research/scripts/fact-commands-fill.mjs +96 -0
- package/dist/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
- package/dist/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
- package/dist/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
- package/dist/skills/ulw-research/scripts/fact-commands.mjs +40 -62
- package/dist/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
- package/dist/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/dist/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
- package/dist/skills/ulw-research/scripts/fact-fill.mjs +9 -6
- package/dist/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/dist/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
- package/dist/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
- package/dist/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/dist/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
- package/dist/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
- package/dist/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
- package/dist/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/dist/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/dist/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/dist/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/dist/skills/ulw-research/scripts/fidelity-policy.mjs +183 -0
- package/dist/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/dist/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/dist/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/dist/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/dist/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/dist/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/dist/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
- package/dist/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/dist/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
- package/dist/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/dist/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/dist/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/dist/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/dist/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
- package/dist/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/dist/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
- package/dist/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/dist/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/dist/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
- package/dist/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/dist/skills/ulw-research/scripts/numerals.test.ts +3 -0
- package/dist/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/dist/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
- package/dist/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/dist/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
- package/dist/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/dist/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/dist/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
- package/dist/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
- package/dist/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/dist/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/dist/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
- package/dist/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
- package/dist/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
- package/dist/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
- package/dist/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
- package/dist/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/dist/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/dist/skills/ulw-research/scripts/report-tools.test.ts +6 -560
- package/dist/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
- package/dist/skills/ulw-research/scripts/source-commands.mjs +87 -29
- package/dist/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
- package/dist/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/dist/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/dist/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
- package/dist/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/dist/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/dist/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
- package/dist/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
- package/dist/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
- package/dist/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
- package/dist/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
- package/dist/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
- package/dist/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
- package/dist/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
- package/dist/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
- package/dist/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
- package/dist/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
- package/dist/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
- package/dist/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
- package/dist/skills/ulw-research/scripts/units.mjs +14 -3
- package/dist/skills/ulw-research/scripts/units.test.ts +10 -0
- package/dist/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
- package/dist/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
- package/dist/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
- package/dist/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
- package/dist/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
- package/dist/tools/delegate-task/executor-types.d.ts +1 -0
- package/dist/tools/delegate-task/sync-session-existence.d.ts +4 -0
- package/dist/tools/delegate-task/types.d.ts +1 -0
- package/dist/tools/skill/description-formatter.d.ts +2 -1
- package/dist/tools/skill/types.d.ts +6 -0
- package/dist/tui.js +131 -33
- package/package.json +18 -15
- package/packages/git-bash-mcp/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/README.md +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/SKILL.md +7 -7
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
- package/packages/omo-codex/plugin/components/telemetry/README.md +2 -2
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +52 -15
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +52 -19
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +2 -9
- package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -13
- package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +0 -2
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook-diagnostics.test.ts +0 -3
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +3 -8
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +3 -0
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +16 -16
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/shared/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ast-grep/README.md +1 -1
- package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +5 -3
- package/packages/omo-codex/plugin/skills/ast-grep/install.sh +4 -5
- package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
- package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +11 -11
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +4 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +34 -12
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +14 -10
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/packages/omo-codex/plugin/skills/frontend/references/design/grounding.md +29 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +7 -7
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +5 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -0
- package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +8 -4
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +7 -259
- package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +68 -24
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +42 -8
- package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +14 -6
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +195 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-delivery.md +123 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +16 -15
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/entities.mjs +13 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-fill.mjs +96 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +40 -62
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +9 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-policy.mjs +183 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +87 -29
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +14 -3
- package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +6 -4
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -3
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +338 -237
- package/packages/prompts-core/prompts/ultrawork/codex.md +3 -0
- package/packages/shared-skills/skill-source-filter.mjs +6 -2
- package/packages/shared-skills/skills/ast-grep/README.md +1 -1
- package/packages/shared-skills/skills/ast-grep/install.ps1 +5 -3
- package/packages/shared-skills/skills/ast-grep/install.sh +4 -5
- package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
- package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +11 -11
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +4 -4
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +1 -1
- package/packages/shared-skills/skills/frontend/SKILL.md +34 -12
- package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -1
- package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +14 -10
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/packages/shared-skills/skills/frontend/references/design/grounding.md +29 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +5 -4
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/packages/shared-skills/skills/ulw-research/AGENTS.md +8 -4
- package/packages/shared-skills/skills/ulw-research/SKILL.md +7 -259
- package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +68 -24
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +42 -8
- package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/packages/shared-skills/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/packages/shared-skills/skills/ulw-research/references/report-gates.md +14 -6
- package/packages/shared-skills/skills/ulw-research/references/research-collection.md +195 -0
- package/packages/shared-skills/skills/ulw-research/references/research-delivery.md +123 -0
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
- package/packages/shared-skills/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +16 -15
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -109
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
- package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-fidelity-policy.test.ts +156 -0
- package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +10 -9
- package/packages/shared-skills/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/packages/shared-skills/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
- package/packages/shared-skills/skills/ulw-research/scripts/entities.mjs +13 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-fill.mjs +96 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +40 -62
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
- package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +9 -6
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-policy.mjs +183 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
- package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
- package/packages/shared-skills/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +3 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/packages/shared-skills/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
- package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
- package/packages/shared-skills/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +6 -560
- package/packages/shared-skills/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +87 -29
- package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
- package/packages/shared-skills/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
- package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +14 -3
- package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +10 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +0 -7
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +0 -19
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +0 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +0 -1128
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +0 -77
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +0 -86
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +0 -279
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +0 -252
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +0 -78
|
@@ -7,12 +7,16 @@
|
|
|
7
7
|
// No model, no network.
|
|
8
8
|
|
|
9
9
|
import { existsSync, readFileSync } from "node:fs"
|
|
10
|
-
import {
|
|
10
|
+
import { resolve, sep } from "node:path"
|
|
11
11
|
|
|
12
|
-
import { sha256Of } from "./cli-support.mjs"
|
|
13
12
|
import { sameValue, unitKey } from "./fidelity-binding.mjs"
|
|
13
|
+
import { readCsv } from "./fidelity-csv.mjs"
|
|
14
14
|
import { claimChecks } from "./fidelity-claims.mjs"
|
|
15
|
+
import { sourceChecks } from "./fidelity-sources.mjs"
|
|
16
|
+
import { convertedHalfFits, followsOriginal, isDerivedRow, originalProblem, renderLocator, staleRender, textAfter } from "./fidelity-originals.mjs"
|
|
17
|
+
import { snapshotCause, unreadableSnapshots } from "./fidelity-snapshot-readability.mjs"
|
|
15
18
|
import { STRUCTURAL, clip, traceChecks } from "./fidelity-trace.mjs"
|
|
19
|
+
import { fillEntriesByNode, valueUnitProblem } from "./fidelity-value-unit.mjs"
|
|
16
20
|
import { parseHtml, proseText } from "./html-lite.mjs"
|
|
17
21
|
import { parseNumeral } from "./numerals.mjs"
|
|
18
22
|
import { div, fromDecimal, sub } from "./rational.mjs"
|
|
@@ -45,11 +49,14 @@ function quoteProblem(row, shown, selector) {
|
|
|
45
49
|
return bare(shown) === bare(want) ? null : ["quote_not_verbatim", `"${clip(shown)}" is not the ${selector} selection of ${row.fact_id}: "${clip(want)}"`]
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
function factProblem(row, shown, attrs = {}) {
|
|
52
|
+
function factProblem(row, shown, attrs = {}, rows = new Map()) {
|
|
53
|
+
const original = originalProblem(row, shown, rows, attrs["data-fact-mode"] === "value")
|
|
54
|
+
if (original) return original
|
|
49
55
|
if (attrs["data-unit"] !== undefined && unitKey(attrs["data-unit"]) !== unitKey(row.unit)) return ["unit_mismatch", `data-unit "${attrs["data-unit"]}" but ${row.fact_id} is in "${row.unit}"`]
|
|
50
56
|
if (attrs.value !== undefined && !sameValue(attrs.value, row.value)) return ["value_mismatch", `value="${attrs.value}" but ${row.fact_id} is ${row.value}`]
|
|
57
|
+
if (convertedHalfFits(row, shown)) return null
|
|
51
58
|
const text = normalizeText(shown)
|
|
52
|
-
const forms = [row.raw, row.render, row.value, row.unit && `${row.value} ${row.unit}`].filter(Boolean).map(normalizeText)
|
|
59
|
+
const forms = [...(["converted", "derived"].includes(row.kind) ? [] : [row.raw, row.render]), row.value, row.unit && `${row.value} ${row.unit}`].filter(Boolean).map(normalizeText)
|
|
53
60
|
if (forms.some((form) => text === form || (text.endsWith(` ${form}`) && !/\d/.test(text.slice(0, -form.length))))) return null
|
|
54
61
|
const parsed = parseNumeral(text)
|
|
55
62
|
if (!parsed) return unitKey(text) === unitKey(row.unit) ? null : ["value_mismatch", `"${clip(shown)}" shows no value of ${row.fact_id} (${row.value})`]
|
|
@@ -73,16 +80,6 @@ export function exportRows(ledger) {
|
|
|
73
80
|
return (ledger?.rows ?? []).filter((row) => row.status === "active" && row.kind !== "quote" && row.value !== null).map((row) => ({ fact_id: row.fact_id, label: row.label, plot_value: row.value, unit: row.unit ?? "" }))
|
|
74
81
|
}
|
|
75
82
|
|
|
76
|
-
function readCsv(path) {
|
|
77
|
-
if (!existsSync(path)) return null
|
|
78
|
-
const lines = readFileSync(path, "utf8").split(/\r?\n/).filter((line) => line.trim() !== "")
|
|
79
|
-
const cells = (line) => line.split(",").map((cell) => cell.trim().replace(/^"(.*)"$/, "$1"))
|
|
80
|
-
const head = cells(lines[0] ?? "")
|
|
81
|
-
const [id, value, unit] = ["fact_id", "plot_value", "unit"].map((name) => head.indexOf(name))
|
|
82
|
-
if (id < 0 || value < 0 || unit < 0 || lines.length < 2) return null
|
|
83
|
-
return lines.slice(1).map((line) => cells(line)).map((c) => ({ fact_id: c[id], plot_value: c[value], unit: c[unit] ?? "" }))
|
|
84
|
-
}
|
|
85
|
-
|
|
86
83
|
const walk = (node) => node.children.filter((child) => child.tag !== "#text").flatMap((child) => [child, ...walk(child)])
|
|
87
84
|
|
|
88
85
|
/** SVG text nodes of a chart: data labels, or ticks with their declared grid. */
|
|
@@ -140,46 +137,57 @@ function chartProblem(ctx, fig, labels, ledger) {
|
|
|
140
137
|
* @param {object} ctx buildContext(...) from gates-static.mjs
|
|
141
138
|
* @param {{ rows: object[] }} ledger
|
|
142
139
|
* @param {{ fact_id: string, rendered: string, selector?: string }[] | null} fillMap Markdown fill map, or null
|
|
143
|
-
* @param {string | null} sourcesDir directory of <S-id>/
|
|
140
|
+
* @param {string | null} sourcesDir directory of <S-id>/ snapshots (source-view.mjs reads them)
|
|
144
141
|
* @param {{ recompute?: (ledger: object, row: object) => { ok: boolean }, asOf?: string | null }} options
|
|
145
142
|
*/
|
|
146
143
|
export function valueChecks(ctx, ledger, fillMap, sourcesDir, options = {}) {
|
|
147
144
|
const out = []
|
|
148
|
-
const flag = (code, node, message) => out.push(ctx.defect(code, node, message))
|
|
145
|
+
const flag = (code, node, message, extra = {}) => out.push({ ...ctx.defect(code, node, message), ...extra })
|
|
149
146
|
const rows = new Map((ledger?.rows ?? []).map((row) => [row.fact_id, row]))
|
|
150
147
|
const cited = new Map()
|
|
148
|
+
const fills = (fillMap ?? []).map((entry) => entry.rendered)
|
|
151
149
|
const check = (id, node, problemOf) => {
|
|
152
150
|
const row = rows.get(id)
|
|
153
151
|
if (!row) return flag("unresolved_placeholder", node, `${id} names no ledger row`)
|
|
154
152
|
if (!cited.has(id)) cited.set(id, node)
|
|
155
153
|
const problem = problemOf(row)
|
|
156
|
-
if (problem)
|
|
154
|
+
if (problem) out.push({ ...ctx.defect(problem[0], node, problem[1]), ...(problem[2] ? { part: problem[2] } : {}) })
|
|
157
155
|
}
|
|
158
156
|
for (const node of ctx.all.filter((cur) => cur.attrs["data-fact"] !== undefined)) {
|
|
159
157
|
const selector = node.attrs["data-quote-sel"] ?? "full"
|
|
160
|
-
|
|
158
|
+
const glued = (row) => isDerivedRow(row) && node.attrs["data-fact-mode"] !== "value" && followsOriginal(row, rows, fills)(textAfter(node)) ? ["value_mismatch", `another original follows ${row.fact_id}: "${clip(textAfter(node))}"`, "original"] : null
|
|
159
|
+
check(node.attrs["data-fact"], node, (row) => (row.kind === "quote" ? quoteProblem(row, withoutFooter(node), selector) : (factProblem(row, proseText(node), node.attrs, rows) ?? glued(row))))
|
|
161
160
|
}
|
|
162
161
|
const docText = bare(proseText(ctx.body))
|
|
163
162
|
for (const entry of fillMap ?? []) {
|
|
164
163
|
check(entry.fact_id, ctx.body, (row) => {
|
|
165
|
-
const problem = row.kind === "quote" ? quoteProblem(row, entry.rendered, entry.selector ?? "full") : factProblem(row, entry.rendered)
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
const problem = row.kind === "quote" ? quoteProblem(row, entry.rendered, entry.selector ?? "full") : factProblem(row, entry.rendered, { "data-fact-mode": entry.mode }, rows)
|
|
165
|
+
const stale = isDerivedRow(row) ? staleRender(row, entry.rendered, proseText(ctx.body), followsOriginal(row, rows, fills)) : docText.includes(bare(entry.rendered)) ? null : "gone"
|
|
166
|
+
if (problem || stale === null) return problem
|
|
167
|
+
return [row.kind === "quote" ? "quote_not_verbatim" : "value_mismatch", `filled text "${clip(entry.rendered)}" of ${row.fact_id} is no longer in the report${stale === "original" ? " (its original was edited)" : ""}`, ...(stale === "original" ? ["original"] : [])]
|
|
168
168
|
})
|
|
169
169
|
}
|
|
170
170
|
rowChecks(ctx, ledger, rows, cited, options, flag)
|
|
171
|
+
// options.fillEntries: the edition's fill-map entries whose element is in the checked HTML (value mode, fill's unit_bound).
|
|
172
|
+
const facts = ctx.all.filter((cur) => cur.attrs["data-fact"] !== undefined)
|
|
173
|
+
const entries = fillEntriesByNode(facts, options.fillEntries)
|
|
174
|
+
for (const node of facts) {
|
|
175
|
+
const row = rows.get(node.attrs["data-fact"])
|
|
176
|
+
const problem = row && row.kind !== "quote" && !factProblem(row, proseText(node), node.attrs, rows) && valueUnitProblem(node, row, entries.get(node))
|
|
177
|
+
if (problem) flag(problem[0], node, problem[1])
|
|
178
|
+
}
|
|
171
179
|
for (const tr of ctx.all.filter((node) => node.tag === "tr" && node.attrs["data-row-kind"] !== "comparison")) {
|
|
172
180
|
const groups = new Set(ctx.util.descendants(tr).map((node) => rows.get(node.attrs["data-fact"])?.observation_id).filter(Boolean))
|
|
173
181
|
if (groups.size > 1) flag("join_integrity_fail", tr, `one table row joins observations ${[...groups].join(", ")}`)
|
|
174
182
|
}
|
|
175
|
-
const meta = sourceChecks(ctx, rows, cited, sourcesDir, flag)
|
|
183
|
+
const meta = sourceChecks(ctx, rows, cited, sourcesDir, flag, unreadableSnapshots(ctx, rows, cited, sourcesDir, out))
|
|
176
184
|
claimChecks(ctx, rows, (row) => provenance(sourcesDir, meta, row), flag)
|
|
177
185
|
const charts = chartFigures(ctx)
|
|
178
186
|
for (const { node, scope } of ctx.elements) {
|
|
179
187
|
const kind = ctx.kindOf(scope)
|
|
180
188
|
if ((node.tag === "q" || node.tag === "blockquote") && node.attrs["data-fact"] === undefined && kind !== "sources" && kind !== "toc") flag("quote_unbound", node, `<${node.tag}> with no Q row: "${clip(proseText(node))}"`)
|
|
181
189
|
}
|
|
182
|
-
traceChecks(ctx, charts, fillMap, flag, fillSiteFits(rows))
|
|
190
|
+
traceChecks(ctx, charts, fillMap, flag, fillSiteFits(rows), renderLocator(rows, fillMap))
|
|
183
191
|
for (const [fig, labels] of charts) {
|
|
184
192
|
const problem = chartProblem(ctx, fig, labels, ledger)
|
|
185
193
|
if (problem) flag("chart_value_untraceable", fig, problem)
|
|
@@ -190,16 +198,23 @@ export function valueChecks(ctx, ledger, fillMap, sourcesDir, options = {}) {
|
|
|
190
198
|
function rowChecks(ctx, ledger, rows, cited, options, flag) {
|
|
191
199
|
// An as-of of "latest ..." or "... per snapshot" names no fixed revision, so quote_stale_version is skipped.
|
|
192
200
|
const asOf = options.asOf && !/^latest\b|per snapshot/i.test(options.asOf) ? options.asOf : null
|
|
201
|
+
// A sentence-final period ("release v1.2.") is punctuation, not part of the revision token.
|
|
202
|
+
const target = asOf?.replace(/\.(?=\s|$)/gu, "")
|
|
193
203
|
for (const [id, node] of cited) {
|
|
194
204
|
const row = rows.get(id)
|
|
195
205
|
if (row.fuzzy === true) flag("quote_fuzzy_match", node, `${id} was registered from a similarity match on an OCR-noisy snapshot`)
|
|
196
206
|
const revision = typeof row.revision === "string" ? row.revision : (row.revision?.id ?? row.revision?.tag ?? null)
|
|
197
|
-
|
|
207
|
+
const revisionPattern = revision && new RegExp(`(?<![\\w.-])${revision.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w.-])`, "u")
|
|
208
|
+
if (asOf && revisionPattern && !revisionPattern.test(target)) flag("quote_stale_version", node, `${id} is from revision ${revision}; the brief targets "${asOf}"`)
|
|
198
209
|
if ((row.kind === "derived" || row.kind === "converted") && options.recompute?.(ledger, row)?.ok === false) flag("value_mismatch", node, `${id} does not recompute from its operands`)
|
|
199
210
|
const window = row.snapshot_window
|
|
200
211
|
if (window && typeof window === "object" && window.start && window.end) {
|
|
201
212
|
const [start, end] = [Date.parse(window.start), Date.parse(window.end)]
|
|
202
|
-
const
|
|
213
|
+
const [absent, present] = [(row.operands ?? []).filter((op) => !rows.has(op)), (row.operands ?? []).filter((op) => rows.has(op))]
|
|
214
|
+
for (const op of absent) flag("operand_missing", node, `operand ${op} of ${id} is not in the fact ledger`)
|
|
215
|
+
const missing = present.filter((op) => !rows.get(op).observed_at)
|
|
216
|
+
for (const op of missing) flag("operand_timestamp_missing", node, `operand ${op} of ${id} has no observed_at timestamp`)
|
|
217
|
+
const outside = present.find((op) => !missing.includes(op) && !(Date.parse(rows.get(op).observed_at) >= start && Date.parse(rows.get(op).observed_at) < end))
|
|
203
218
|
if (outside) flag("snapshot_mismatch", node, `operand ${outside} of ${id} was observed outside ${window.start} to ${window.end}`)
|
|
204
219
|
}
|
|
205
220
|
}
|
|
@@ -213,17 +228,3 @@ function provenance(sourcesDir, meta, row) {
|
|
|
213
228
|
const path = resolve(dir, artifact)
|
|
214
229
|
return path.startsWith(`${dir}${sep}`) && existsSync(path) ? meta.get(row.source_id)?.kind : undefined
|
|
215
230
|
}
|
|
216
|
-
|
|
217
|
-
function sourceChecks(ctx, rows, cited, sourcesDir, flag) {
|
|
218
|
-
const ids = new Set([...cited.keys()].map((id) => rows.get(id)?.source_id).filter(Boolean))
|
|
219
|
-
for (const match of proseText(ctx.body).matchAll(/\[S(\d+)\]/g)) ids.add(`S${match[1]}`)
|
|
220
|
-
const meta = new Map()
|
|
221
|
-
for (const id of sourcesDir ? ids : []) {
|
|
222
|
-
const [metaPath, textPath] = [join(sourcesDir, id, "meta.json"), join(sourcesDir, id, "text.txt")]
|
|
223
|
-
if (!existsSync(metaPath) || !existsSync(textPath)) continue
|
|
224
|
-
meta.set(id, JSON.parse(readFileSync(metaPath, "utf8")))
|
|
225
|
-
const actual = sha256Of(readFileSync(textPath))
|
|
226
|
-
if (meta.get(id).sha256 !== actual) flag("snapshot_hash_mismatch", ctx.body, `${id}/text.txt changed after its snapshot was pinned`)
|
|
227
|
-
}
|
|
228
|
-
return meta
|
|
229
|
-
}
|
|
@@ -20,11 +20,13 @@ import { parseHtml } from "./html-lite.mjs"
|
|
|
20
20
|
|
|
21
21
|
/** Every code this gate can raise. */
|
|
22
22
|
export const FIDELITY_GATE_CODES = Object.freeze([
|
|
23
|
+
"unit_unbound",
|
|
23
24
|
"fidelity_interview_incomplete", "unresolved_placeholder", "value_mismatch", "unit_mismatch", "quote_not_verbatim",
|
|
24
25
|
"quote_unbound", "claim_status_invalid", "snapshot_hash_mismatch", "chart_value_untraceable", "untraceable_number",
|
|
25
26
|
"unsupported_verification", "conflicting_readings", "hedge_dropped", "direction_flipped", "causality_added",
|
|
26
|
-
"qualifier_dropped", "unbound_sentence", "snapshot_mismatch", "join_integrity_fail", "quote_stale_version",
|
|
27
|
+
"qualifier_dropped", "unbound_sentence", "snapshot_mismatch", "operand_timestamp_missing", "operand_missing", "join_integrity_fail", "quote_stale_version",
|
|
27
28
|
"quote_fuzzy_match", "name_outside_quote", "scope_widened_warn", "claim_kind_mismatch", "verification_claim_unmarked",
|
|
29
|
+
"snapshot_not_raw", "relocated", "quote_converted_only",
|
|
28
30
|
])
|
|
29
31
|
const RANK = { blocker: 0, major: 1, minor: 2 }
|
|
30
32
|
|
|
@@ -40,8 +42,8 @@ export function deliveryBlockReason(defect) {
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
function withIntegrity(defect) {
|
|
43
|
-
const { code, severity, selector, line, message, hint } = defect
|
|
44
|
-
return { code, severity, integrity: DEFECT_CODES[code].integrity, selector, line, message, hint }
|
|
45
|
+
const { code, severity, selector, line, message, hint, part, fact_id } = defect
|
|
46
|
+
return { code, severity, integrity: DEFECT_CODES[code].integrity, selector, line, message, hint, ...(part ? { part } : {}), ...(fact_id ? { fact_id } : {}) }
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
function compareDefects(a, b) {
|
|
@@ -93,17 +95,17 @@ function incomplete(parsed) {
|
|
|
93
95
|
|
|
94
96
|
/**
|
|
95
97
|
* @param {string} html the filled report
|
|
96
|
-
* @param {{ ledger: { rows: object[] }, sourcesDir?: string | null, claims?: object | null, fillMap?: object[] | null,
|
|
98
|
+
* @param {{ ledger: { rows: object[] }, sourcesDir?: string | null, claims?: object | null, fillMap?: object[] | null, fillEntries?: object[] | null,
|
|
97
99
|
* brief: string | object, baseDir?: string, recompute?: (ledger: object, row: object) => { ok: boolean } }} options
|
|
98
100
|
* `brief` is the brief.md text or parseFidelityBlock output; `baseDir` resolves data-chart-source paths.
|
|
99
101
|
* @returns {{ defects: object[], gatesRun: string[] }}
|
|
100
102
|
*/
|
|
101
|
-
export function checkFidelity(html, { ledger, sourcesDir = null, claims = null, fillMap = null, brief, baseDir, recompute } = {}) {
|
|
103
|
+
export function checkFidelity(html, { ledger, sourcesDir = null, claims = null, fillMap = null, fillEntries = null, brief, baseDir, recompute } = {}) {
|
|
102
104
|
const parsed = brief && typeof brief === "object" ? brief : parseFidelityBlock(String(brief ?? ""))
|
|
103
105
|
if (!isLocked(parsed)) return { defects: [incomplete(parsed)], gatesRun: ["fidelity_interview_incomplete"] }
|
|
104
106
|
const ctx = buildContext(parseHtml(html), { baseDir })
|
|
105
107
|
const defects = [
|
|
106
|
-
...valueChecks(ctx, ledger, fillMap, sourcesDir, { recompute, asOf: parsed.fields["as of"] }),
|
|
108
|
+
...valueChecks(ctx, ledger, fillMap, sourcesDir, { recompute, asOf: parsed.fields["as of"], fillEntries }),
|
|
107
109
|
...bindingChecks(ctx, claims, ledger),
|
|
108
110
|
]
|
|
109
111
|
const pairs = fidelityPairs(ctx, ledger, sourcesDir)
|
|
@@ -14,6 +14,7 @@ import { figureGates } from "./gates-figures.mjs"
|
|
|
14
14
|
import { structureGates } from "./gates-structure.mjs"
|
|
15
15
|
import { textGates } from "./gates-text.mjs"
|
|
16
16
|
import { PROSE_TAGS, proseText, selectorPath } from "./html-lite.mjs"
|
|
17
|
+
import { sourcesClaims } from "./sources-citation.mjs"
|
|
17
18
|
|
|
18
19
|
const CITATION_MARKER = /\[S\d+\]|\[Source\s*\d+\]|\[\uCD9C\uCC98[^\]]*\]|\[\^\d+\]/i
|
|
19
20
|
const ANCHOR_HREF = /^#(?:s|src|source|ref|fn)/i
|
|
@@ -65,6 +66,11 @@ function hasCitation(node) {
|
|
|
65
66
|
return CITATION_MARKER.test(proseText(node)) || descendants(node).some(isCitationAnchor)
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
function proseScope(scope, owner) {
|
|
70
|
+
if (scope.section?.kind !== "sources" || !owner || sourcesClaims(owner).length === 0) return scope
|
|
71
|
+
return { ...scope, section: { ...scope.section, kind: null } }
|
|
72
|
+
}
|
|
73
|
+
|
|
68
74
|
function toRegExp(pattern) {
|
|
69
75
|
const re = pattern instanceof RegExp ? pattern : new RegExp(String(pattern), "i")
|
|
70
76
|
return new RegExp(re.source, re.flags.replace(/[gy]/g, ""))
|
|
@@ -181,7 +187,10 @@ export function checkStatic(doc, options = {}) {
|
|
|
181
187
|
continue
|
|
182
188
|
}
|
|
183
189
|
gatesRun.push(...gate.codes)
|
|
184
|
-
|
|
190
|
+
const context = gate.codes.includes("unsourced_number")
|
|
191
|
+
? { ...ctx, elements: ctx.elements.map(({ node, scope }) => ({ node, scope: proseScope(scope, node) })) }
|
|
192
|
+
: ctx
|
|
193
|
+
defects.push(...gate.run(context))
|
|
185
194
|
}
|
|
186
195
|
return { defects, gatesRun, gatesSkipped }
|
|
187
196
|
}
|
|
@@ -23,7 +23,7 @@ const PROSE_SKIP = new Set(["code", "pre", "kbd", "samp", "script", "style", "sv
|
|
|
23
23
|
const SAFE_ID = /^[A-Za-z_][\w-]*$/
|
|
24
24
|
|
|
25
25
|
export const PROSE_TAGS = new Set(["p", "li", ...HEADINGS, "td", "th", "figcaption", "blockquote", "dd", "dt"])
|
|
26
|
-
const PROSE_BREAKS = new Set([...P_CLOSERS, ...PROSE_TAGS, "br", "tr"])
|
|
26
|
+
export const PROSE_BREAKS = new Set([...P_CLOSERS, ...PROSE_TAGS, "br", "tr"])
|
|
27
27
|
|
|
28
28
|
function makeNode(tag, attrs, parent, line) {
|
|
29
29
|
return { tag, attrs, children: [], parent, line, text: "", raw: null }
|
|
@@ -130,6 +130,8 @@ export function parseHtml(source) {
|
|
|
130
130
|
const flushText = (to) => {
|
|
131
131
|
if (to > textStart) {
|
|
132
132
|
const node = makeNode("#text", {}, top(), lineAt(starts, textStart))
|
|
133
|
+
node.source_start = textStart
|
|
134
|
+
node.source_end = to
|
|
133
135
|
node.text = decodeEntities(src.slice(textStart, to))
|
|
134
136
|
top().children.push(node)
|
|
135
137
|
}
|
|
@@ -157,7 +159,7 @@ export function parseHtml(source) {
|
|
|
157
159
|
const tag = readTag(src, lt + 2)
|
|
158
160
|
if (tag.name !== "body" && tag.name !== "html") {
|
|
159
161
|
for (let k = stack.length - 1; k > 0; k--) {
|
|
160
|
-
if (stack[k].tag === tag.name) { stack.length = k; break }
|
|
162
|
+
if (stack[k].tag === tag.name) { stack[k].source_end = lt; stack.length = k; break }
|
|
161
163
|
}
|
|
162
164
|
}
|
|
163
165
|
at = textStart = tag.end
|
|
@@ -169,6 +171,8 @@ export function parseHtml(source) {
|
|
|
169
171
|
if (P_CLOSERS.has(tag.name)) closeWithin("p", P_SCOPE)
|
|
170
172
|
if (tag.name === "li") closeWithin("li", LI_SCOPE)
|
|
171
173
|
const node = makeNode(tag.name, tag.attrs, top(), lineAt(starts, lt))
|
|
174
|
+
node.source_start = tag.end
|
|
175
|
+
node.source_end = src.length
|
|
172
176
|
top().children.push(node)
|
|
173
177
|
if (tag.name === "body") sawBody = true
|
|
174
178
|
if (tag.attrs.id) root.ids.set(tag.attrs.id, (root.ids.get(tag.attrs.id) ?? 0) + 1)
|
|
@@ -61,10 +61,10 @@ function scriptEnd(src, from) {
|
|
|
61
61
|
function closeOf(src, from, name) {
|
|
62
62
|
if (name === "script") return scriptEnd(src, from)
|
|
63
63
|
if (RAW.has(name)) {
|
|
64
|
-
const close = new RegExp(`</${name}(?=[\\s/>])
|
|
64
|
+
const close = new RegExp(`</${name}(?=[\\s/>])`, "gi")
|
|
65
65
|
close.lastIndex = from
|
|
66
66
|
const match = close.exec(src)
|
|
67
|
-
return match ? match.index +
|
|
67
|
+
return match ? readTag(src, match.index + 2).end : src.length
|
|
68
68
|
}
|
|
69
69
|
let depth = 0
|
|
70
70
|
let stop = src.length
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// html-text-map.mjs - the reader-visible text of a page, with a source map back into the markup.
|
|
2
|
+
//
|
|
3
|
+
// extractHtml(html) returns { root, text, blocks, starts, ends }: `text` is one line per block
|
|
4
|
+
// (prose blocks and table cells; whitespace collapsed, entities decoded) and text unit k came from
|
|
5
|
+
// html.slice(starts[k], ends[k]). Only text nodes are read: attribute values, CSS, scripts, and
|
|
6
|
+
// anything a reader never sees (head, script, style, svg, noscript, template, code-like elements,
|
|
7
|
+
// aria-hidden="true" and their descendants, and what the page's CSS hides: css-hiding.mjs)
|
|
8
|
+
// contribute nothing, so a locator over `text` can never land in markup. A synthetic separator
|
|
9
|
+
// (collapsed break, line feed) maps to an empty range at the previous character's end.
|
|
10
|
+
// Plain Node ESM, sibling imports only.
|
|
11
|
+
|
|
12
|
+
import { cssVisibility } from "./css-hiding.mjs"
|
|
13
|
+
import { decodeOne } from "./entities.mjs"
|
|
14
|
+
import { parseHtml, PROSE_BREAKS, PROSE_TAGS } from "./html-lite.mjs"
|
|
15
|
+
|
|
16
|
+
const SKIP = new Set(["head", "script", "style", "svg", "code", "pre", "kbd", "samp", "template", "noscript"])
|
|
17
|
+
const INLINE = new Set([
|
|
18
|
+
"a", "abbr", "b", "bdi", "bdo", "cite", "data", "del", "dfn", "em", "font", "i", "ins", "label", "mark", "q", "s",
|
|
19
|
+
"small", "span", "strong", "sub", "sup", "time", "u", "var",
|
|
20
|
+
])
|
|
21
|
+
const SPACE = /\s/
|
|
22
|
+
|
|
23
|
+
/** null when a reader never sees the element or anything inside it, else whether its own text shows (css: cssVisibility). */
|
|
24
|
+
function shownState(node, css, parentShown) {
|
|
25
|
+
if (SKIP.has(node.tag) || String(node.attrs?.["aria-hidden"] ?? "").trim().toLowerCase() === "true") return null
|
|
26
|
+
return css(node, parentShown)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function newLine() {
|
|
30
|
+
return { node: null, text: "", starts: [], ends: [], space: null }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function put(line, unit, start, end) {
|
|
34
|
+
if (SPACE.test(unit)) {
|
|
35
|
+
if (line.text !== "" && line.space === null) line.space = [start, end]
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
if (line.space !== null) {
|
|
39
|
+
line.text += " "
|
|
40
|
+
line.starts.push(line.space[0])
|
|
41
|
+
line.ends.push(line.space[1])
|
|
42
|
+
line.space = null
|
|
43
|
+
}
|
|
44
|
+
line.text += unit
|
|
45
|
+
line.starts.push(start)
|
|
46
|
+
line.ends.push(end)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** A collapsible break with no source character of its own. */
|
|
50
|
+
function softBreak(line) {
|
|
51
|
+
if (line.text !== "" && line.space === null) {
|
|
52
|
+
const at = line.ends[line.ends.length - 1]
|
|
53
|
+
line.space = [at, at]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Append a text node's source range, decoding entities exactly as decodeEntities does. */
|
|
58
|
+
function putText(line, src, from, to) {
|
|
59
|
+
for (let at = from; at < to; ) {
|
|
60
|
+
if (src[at] === "&") {
|
|
61
|
+
const semi = src.indexOf(";", at + 1)
|
|
62
|
+
const decoded = semi !== -1 && semi < to && semi - at <= 12 ? decodeOne(src.slice(at + 1, semi)) : null
|
|
63
|
+
if (decoded !== null) {
|
|
64
|
+
for (let k = 0; k < decoded.length; k++) put(line, decoded[k], at, semi + 1)
|
|
65
|
+
at = semi + 1
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
put(line, src[at], at, at + 1)
|
|
70
|
+
at++
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function putProse(line, src, node, css, shown) {
|
|
75
|
+
for (const child of node.children) {
|
|
76
|
+
if (child.tag === "#text") {
|
|
77
|
+
if (shown) putText(line, src, child.source_start, child.source_end)
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
const state = shownState(child, css, shown)
|
|
81
|
+
if (state === null) continue
|
|
82
|
+
const breaks = PROSE_BREAKS.has(child.tag)
|
|
83
|
+
if (breaks) softBreak(line)
|
|
84
|
+
putProse(line, src, child, css, state)
|
|
85
|
+
if (breaks) softBreak(line)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** See the file comment. blocks: [{ node, start, end }] with text.slice(start, end) one block line. */
|
|
90
|
+
export function extractHtml(html) {
|
|
91
|
+
const src = String(html)
|
|
92
|
+
const root = parseHtml(src)
|
|
93
|
+
const css = cssVisibility(root)
|
|
94
|
+
const lines = []
|
|
95
|
+
let line = newLine()
|
|
96
|
+
const flush = (node) => {
|
|
97
|
+
if (line.text !== "") lines.push({ ...line, node })
|
|
98
|
+
line = newLine()
|
|
99
|
+
}
|
|
100
|
+
const walk = (node, shown) => {
|
|
101
|
+
for (const child of node.children) {
|
|
102
|
+
if (child.tag === "#text") {
|
|
103
|
+
if (shown) putText(line, src, child.source_start, child.source_end)
|
|
104
|
+
continue
|
|
105
|
+
}
|
|
106
|
+
const state = shownState(child, css, shown)
|
|
107
|
+
if (state === null) continue
|
|
108
|
+
if (child.tag === "br") flush(node)
|
|
109
|
+
else if (INLINE.has(child.tag)) walk(child, state)
|
|
110
|
+
else if (PROSE_TAGS.has(child.tag)) {
|
|
111
|
+
flush(node)
|
|
112
|
+
putProse(line, src, child, css, state)
|
|
113
|
+
flush(child)
|
|
114
|
+
} else {
|
|
115
|
+
flush(node)
|
|
116
|
+
walk(child, state)
|
|
117
|
+
flush(child)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
walk(root, true)
|
|
122
|
+
flush(root)
|
|
123
|
+
const blocks = []
|
|
124
|
+
const starts = []
|
|
125
|
+
const ends = []
|
|
126
|
+
let text = ""
|
|
127
|
+
for (const entry of lines) {
|
|
128
|
+
if (text !== "") {
|
|
129
|
+
const at = ends[ends.length - 1]
|
|
130
|
+
text += "\n"
|
|
131
|
+
starts.push(at)
|
|
132
|
+
ends.push(at)
|
|
133
|
+
}
|
|
134
|
+
blocks.push({ node: entry.node, start: text.length, end: text.length + entry.text.length })
|
|
135
|
+
text += entry.text
|
|
136
|
+
starts.push(...entry.starts)
|
|
137
|
+
ends.push(...entry.ends)
|
|
138
|
+
}
|
|
139
|
+
return { root, text, blocks, starts, ends }
|
|
140
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// markdown-closers.mjs - the Markdown closer runs a converter writes after a piece of text, read with
|
|
2
|
+
// the CommonMark inline grammar instead of a hand-written pattern. A closer run is any sequence of:
|
|
3
|
+
// an inline link ending `](dest "title")` (the destination either in <...> or bare with balanced
|
|
4
|
+
// parentheses, the optional title in "...", '...' or (...), backslash escapes inside both), a full or
|
|
5
|
+
// collapsed reference ending `][ref]` / `][]`, a whole image `` or `![alt][ref]` (its alt
|
|
6
|
+
// text is not context), the `[` that opened a link whose text is all markup (`[](/p)`),
|
|
7
|
+
// an emphasis, strike or code delimiter, a bare `)`, `]` or `>`, and a backslash-escaped closer
|
|
8
|
+
// (`\*`, `\_`, `\]`, `\)`, `\~`, a backtick), which stands for the raw character and is skipped like
|
|
9
|
+
// it. An escaped opener (`\[`, `\(`) is a real character and ends the run. Shared by the conversion
|
|
10
|
+
// probe's sign reading and its link-syntax spans. Pure; no imports.
|
|
11
|
+
|
|
12
|
+
const SIMPLE = new Set(["*", "_", "~", "`", ")", "]", ">"])
|
|
13
|
+
const BREAK = "\u0001"
|
|
14
|
+
|
|
15
|
+
/** Whether the character at `index` is backslash-escaped (an odd run of backslashes before it). */
|
|
16
|
+
export function escapedAt(text, index) {
|
|
17
|
+
let count = 0
|
|
18
|
+
for (let i = index - 1; i >= 0 && text[i] === "\\"; i--) count++
|
|
19
|
+
return count % 2 === 1
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The end (exclusive) of an inline link target `dest "title")` that starts right after its "(", or -1. */
|
|
23
|
+
export function inlineTargetEnd(text, from) {
|
|
24
|
+
let i = from
|
|
25
|
+
const space = () => {
|
|
26
|
+
while (text[i] === " " || text[i] === "\t") i++
|
|
27
|
+
}
|
|
28
|
+
space()
|
|
29
|
+
if (text[i] === "<") {
|
|
30
|
+
for (i++; i < text.length && text[i] !== ">"; i++) {
|
|
31
|
+
if (text[i] === "\\") i++
|
|
32
|
+
else if (text[i] === "<" || text[i] === BREAK) return -1
|
|
33
|
+
}
|
|
34
|
+
if (text[i++] !== ">") return -1
|
|
35
|
+
} else {
|
|
36
|
+
let depth = 0
|
|
37
|
+
for (; i < text.length; i++) {
|
|
38
|
+
const ch = text[i]
|
|
39
|
+
if (ch === "\\") i++
|
|
40
|
+
else if (ch === "(") depth++
|
|
41
|
+
else if (ch === ")" && depth === 0) break
|
|
42
|
+
else if (ch === ")") depth--
|
|
43
|
+
else if (ch === " " || ch === "\t" || ch === BREAK) break
|
|
44
|
+
}
|
|
45
|
+
if (depth !== 0) return -1
|
|
46
|
+
}
|
|
47
|
+
const destEnd = i
|
|
48
|
+
space()
|
|
49
|
+
const open = text[i]
|
|
50
|
+
if (i > destEnd && (open === '"' || open === "'" || open === "(")) {
|
|
51
|
+
const close = open === "(" ? ")" : open
|
|
52
|
+
for (i++; i < text.length && text[i] !== close; i++) {
|
|
53
|
+
if (text[i] === "\\") i++
|
|
54
|
+
else if (text[i] === BREAK || (open === "(" && text[i] === "(")) return -1
|
|
55
|
+
}
|
|
56
|
+
if (text[i++] !== close) return -1
|
|
57
|
+
space()
|
|
58
|
+
}
|
|
59
|
+
return text[i] === ")" ? i + 1 : -1
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The unescaped "[" that the unescaped "]" at `close` closes (brackets balance), or -1. */
|
|
63
|
+
function openerOf(text, close) {
|
|
64
|
+
let depth = 0
|
|
65
|
+
for (let i = close; i >= 0 && text[i] !== BREAK; i--) {
|
|
66
|
+
if ((text[i] !== "[" && text[i] !== "]") || escapedAt(text, i)) continue
|
|
67
|
+
depth += text[i] === "]" ? 1 : -1
|
|
68
|
+
if (depth === 0) return i
|
|
69
|
+
}
|
|
70
|
+
return -1
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The "](" positions whose inline target ends exactly at `end`, leftmost first (so a title holding "](" is not cut). */
|
|
74
|
+
function inlineLinkClose(text, end) {
|
|
75
|
+
const from = Math.max(0, text.lastIndexOf(BREAK, end - 1))
|
|
76
|
+
for (let k = text.indexOf("](", from); k !== -1 && k < end; k = text.indexOf("](", k + 1)) {
|
|
77
|
+
if (!escapedAt(text, k) && inlineTargetEnd(text, k + 2) === end) return k
|
|
78
|
+
}
|
|
79
|
+
return -1
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Where the link or image tail ending at `end` starts, and whether its "[" is still open; null when none ends there. */
|
|
83
|
+
function linkTail(text, end) {
|
|
84
|
+
let close = -1
|
|
85
|
+
if (text[end - 1] === ")") close = inlineLinkClose(text, end)
|
|
86
|
+
else if (text[end - 1] === "]" && !escapedAt(text, end - 1)) {
|
|
87
|
+
const ref = openerOf(text, end - 1)
|
|
88
|
+
if (ref > 0 && text[ref - 1] === "]" && !escapedAt(text, ref - 1)) close = ref - 1
|
|
89
|
+
}
|
|
90
|
+
if (close === -1) return null
|
|
91
|
+
const open = openerOf(text, close)
|
|
92
|
+
if (open > 0 && text[open - 1] === "!" && !escapedAt(text, open - 1)) return { start: open - 1, opened: 0 }
|
|
93
|
+
return { start: close, opened: open === -1 ? 0 : 1 }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** `text` without the Markdown closer run it ends with. */
|
|
97
|
+
export function stripClosers(text) {
|
|
98
|
+
let end = text.length
|
|
99
|
+
let owed = 0
|
|
100
|
+
for (;;) {
|
|
101
|
+
const tail = linkTail(text, end)
|
|
102
|
+
if (tail) {
|
|
103
|
+
end = tail.start
|
|
104
|
+
owed += tail.opened
|
|
105
|
+
continue
|
|
106
|
+
}
|
|
107
|
+
const ch = text[end - 1]
|
|
108
|
+
if (SIMPLE.has(ch)) end -= escapedAt(text, end - 1) ? 2 : 1
|
|
109
|
+
else if (ch === "[" && owed > 0 && !escapedAt(text, end - 1)) {
|
|
110
|
+
end--
|
|
111
|
+
owed--
|
|
112
|
+
} else return text.slice(0, end)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** [start, end) spans of every inline link or image with its target (an image from its "!"), for link-syntax cover. */
|
|
117
|
+
export function inlineLinkSpans(text) {
|
|
118
|
+
const spans = []
|
|
119
|
+
for (let k = text.indexOf("]("); k !== -1; k = text.indexOf("](", k + 1)) {
|
|
120
|
+
const end = escapedAt(text, k) ? -1 : inlineTargetEnd(text, k + 2)
|
|
121
|
+
if (end === -1) continue
|
|
122
|
+
const open = openerOf(text, k)
|
|
123
|
+
spans.push([open > 0 && text[open - 1] === "!" ? open - 1 : k, end])
|
|
124
|
+
}
|
|
125
|
+
return spans
|
|
126
|
+
}
|
|
@@ -113,7 +113,7 @@ export function parseMarkdown(text) {
|
|
|
113
113
|
const codeStart = Math.min(line.next, source.length)
|
|
114
114
|
let close = lines.length
|
|
115
115
|
for (let k = i + 1; k < lines.length; k++) {
|
|
116
|
-
const candidate = lines[k].raw.
|
|
116
|
+
const candidate = lines[k].raw.replace(/^ {0,3}/, "").trimEnd()
|
|
117
117
|
if (candidate.startsWith(open[0].repeat(open.length)) && /^(`+|~+)$/.test(candidate)) {
|
|
118
118
|
close = k
|
|
119
119
|
break
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// number-grammar.mjs - the one grouped-number grammar. A grouped number is a 1-3 digit leading
|
|
2
|
+
// group, then one or more 3-digit groups joined by ONE separator type, with no digit right after the
|
|
3
|
+
// last group, then an optional decimal part. "12,3451" is therefore not "12,345" plus "1". A period
|
|
4
|
+
// groups only when the reading is unambiguous: two or more period groups ("1.234.567") or one group
|
|
5
|
+
// before a decimal comma ("1.234,5"); a lone "1.234" is a decimal, as numerals.mjs reads it. Shared by
|
|
6
|
+
// numerals.mjs (comma grouping), the conversion probe (every separator), the value-mode unit check,
|
|
7
|
+
// and the converted-half display check. Pure; no imports.
|
|
8
|
+
|
|
9
|
+
/** Separators a thousands group may use: comma, period, space, NBSP, narrow NBSP, thin space, figure space. */
|
|
10
|
+
export const GROUP_SEPARATORS = Object.freeze([",", ".", " ", "\u00A0", "\u202F", "\u2009", "\u2007"])
|
|
11
|
+
|
|
12
|
+
const literal = (sep) => (sep === "." ? "\\." : sep === " " ? " " : sep === "," ? "," : `\\u${sep.charCodeAt(0).toString(16).padStart(4, "0")}`)
|
|
13
|
+
const decimalAfter = (sep) => (sep === "," ? "\\." : sep === "." ? "," : "[.,]")
|
|
14
|
+
|
|
15
|
+
/** Regex source of one grouped number using any of `separators` (one type per number); no flags needed. */
|
|
16
|
+
export function groupedNumberSource(separators = GROUP_SEPARATORS) {
|
|
17
|
+
const one = (sep) => sep === "."
|
|
18
|
+
? "\\d{1,3}(?:(?:\\.\\d{3}(?!\\d)){2,}(?:,\\d+)?|\\.\\d{3}(?!\\d),\\d+)"
|
|
19
|
+
: `\\d{1,3}(?:${literal(sep)}\\d{3}(?!\\d))+(?:${decimalAfter(sep)}\\d+)?`
|
|
20
|
+
return `(?<!\\d)(?:${separators.map(one).join("|")})`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** A grouped number or a plain one ("4.22", "12,3451" read as 12.3451), as regex source. */
|
|
24
|
+
export const NUMBER_SOURCE = `(?:${groupedNumberSource()}|(?<!\\d)\\d+(?:[.,]\\d+)?)`
|
|
25
|
+
|
|
26
|
+
const WHOLE = new Map(GROUP_SEPARATORS.map((sep) => [sep, new RegExp(`^${groupedNumberSource([sep])}$`)]))
|
|
27
|
+
|
|
28
|
+
/** The plain decimal a number token spells: group separators dropped, a decimal comma read as a point. */
|
|
29
|
+
export function plainDecimal(token) {
|
|
30
|
+
const sep = GROUP_SEPARATORS.find((candidate) => WHOLE.get(candidate).test(token))
|
|
31
|
+
const ungrouped = sep === undefined ? token : token.split(sep).join("")
|
|
32
|
+
return ungrouped.replace(",", ".")
|
|
33
|
+
}
|