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
|
@@ -9,8 +9,10 @@ import { finalReading, rewriteParticle } from "./particles-ko.mjs"
|
|
|
9
9
|
import { failureCount, markReplaced, sentenceKey } from "./fidelity-state.mjs"
|
|
10
10
|
import { findPlaceholders, lead, qualifiedText, renderBlockquote, renderQuote, renderValueHtml, subSpan, valueParts } from "./placeholder.mjs"
|
|
11
11
|
import { splitSentences } from "./sentence-split.mjs"
|
|
12
|
+
import { CLAIM_KINDS } from "./claim-kinds.mjs"
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
/** The output formats fill renders. */
|
|
15
|
+
export const FILL_FORMATS = Object.freeze(["html", "md"])
|
|
14
16
|
const TRANSLATION = Object.freeze({
|
|
15
17
|
html: /^\s*<span data-translates="(Q\d+)">[\s\S]*?<\/span>/u,
|
|
16
18
|
md: /^\s*<!-- translates: (Q\d+) -->[^\n]*/u,
|
|
@@ -23,7 +25,7 @@ function resolveValue(row, parsed, format) {
|
|
|
23
25
|
const { valueText, unitText } = valueParts(row)
|
|
24
26
|
const text = { full: row.raw, value: valueText, unit: unitText, q: qualifiedText(row) }[parsed.mode]
|
|
25
27
|
if (text === null) return { code: "quote_anchor_unresolved", message: `${row.fact_id} has qualifier ${row.qualifier}, but its quote holds no qualifier beside "${row.raw}"` }
|
|
26
|
-
return { row, parsed, visible: text, rendered: format === "html" ? renderValueHtml(row, text) : text }
|
|
28
|
+
return { row, parsed, visible: text, rendered: format === "html" ? renderValueHtml(row, text, { mode: parsed.mode, claimKind: parsed.claimKind ?? null }) : text }
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
function resolveQuote(row, parsed, format) {
|
|
@@ -32,17 +34,18 @@ function resolveQuote(row, parsed, format) {
|
|
|
32
34
|
if (selection === null) {
|
|
33
35
|
return { code: "quote_anchor_unresolved", message: `from "${parsed.from}" and to "${parsed.to}" must each occur exactly once in ${row.fact_id}'s quote, in that order` }
|
|
34
36
|
}
|
|
35
|
-
const rendered = renderQuote(row, parsed.selector, selection.text, format)
|
|
37
|
+
const rendered = renderQuote(row, parsed.selector, selection.text, format, parsed.claimKind)
|
|
36
38
|
return { row, parsed, visible: `[${row.source_id}]`, rendered, selector: parsed.selector, quote_span: [selection.start, selection.end] }
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
function resolve(found, rows, format) {
|
|
40
42
|
const { parsed } = found
|
|
41
|
-
if (parsed.error) return { code: "unresolved_placeholder", message: parsed.error }
|
|
43
|
+
if (parsed.error) return { code: "unresolved_placeholder", message: `${parsed.error}; for literal opening braces, write {{ instead of {{ (including in code spans)` }
|
|
42
44
|
const row = rows.get(parsed.id)
|
|
43
45
|
if (row === undefined) return { code: "unresolved_placeholder", message: `${parsed.id} is not in the fact ledger` }
|
|
44
46
|
if (row.status !== "active") return { code: "unresolved_placeholder", message: `${parsed.id} is ${row.status}; cite its replacement` }
|
|
45
47
|
if (row.label !== parsed.label) return { code: "pointer_label_mismatch", message: `${parsed.id} has label "${row.label}", not "${parsed.label}"` }
|
|
48
|
+
if (parsed.claimKind && !CLAIM_KINDS[parsed.claimKind].rowKinds.includes(row.kind)) return { code: CLAIM_KINDS[parsed.claimKind].defect, message: `${parsed.claimKind} does not accept a ${row.kind} row (${parsed.id})` }
|
|
46
49
|
return parsed.kind === "Q" ? resolveQuote(row, parsed, format) : resolveValue(row, parsed, format)
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -145,7 +148,7 @@ function assemble(text, parts, context) {
|
|
|
145
148
|
flush(part.start)
|
|
146
149
|
const start = context.out.length
|
|
147
150
|
if (part.parsed) {
|
|
148
|
-
const extra = part.selector === undefined ? {} : { selector: part.selector, quote_span: part.quote_span }
|
|
151
|
+
const extra = { ...(part.selector === undefined ? {} : { selector: part.selector, quote_span: part.quote_span }), ...(part.parsed.claimKind ? { claimKind: part.parsed.claimKind } : {}), ...(part.parsed.mode === "value" ? { mode: "value" } : {}) }
|
|
149
152
|
context.fillMap.push({ token: part.token, fact_id: part.row.fact_id, start, end: start + part.rendered.length, rendered: part.rendered, ...extra })
|
|
150
153
|
} else if (part.rendered !== "") {
|
|
151
154
|
context.fillMap.push({ token: null, fact_id: part.source.fact_id, replaced: part.key, start, end: start + part.rendered.length, rendered: part.rendered })
|
|
@@ -166,7 +169,7 @@ function assemble(text, parts, context) {
|
|
|
166
169
|
*/
|
|
167
170
|
export function fill(sourceText, ledger, options = {}) {
|
|
168
171
|
const format = options.format ?? "html"
|
|
169
|
-
if (!
|
|
172
|
+
if (!FILL_FORMATS.includes(format)) throw new TypeError(`format must be one of ${FILL_FORMATS.join(", ")}`)
|
|
170
173
|
const rows = new Map(ledger.rows.map((row) => [row.fact_id, row]))
|
|
171
174
|
const found = findPlaceholders(sourceText)
|
|
172
175
|
const errors = []
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// per-kind choices (id prefix, measured exact) from it, and the per-kind table in
|
|
4
4
|
// references/fact-ledger-grammar.md is rendered from it (`node fact-ledger-kinds.mjs --render-grammar`).
|
|
5
5
|
// Also the value primitives the schema shares. Pure functions with no IO; node: builtins only.
|
|
6
|
-
|
|
7
6
|
import { isCliEntry } from "./entry-guard.mjs"
|
|
8
7
|
import { canonicalUnit, inputScale, RuleError } from "./unit-algebra.mjs"
|
|
9
8
|
import { metadataErrors } from "./unit-metadata.mjs"
|
|
@@ -15,7 +14,6 @@ export const DECIMAL = /^-?\d+(?:\.\d+)?$/
|
|
|
15
14
|
const INTEGER = /^-?\d+$/
|
|
16
15
|
const SHA256 = /^[0-9a-f]{64}$/
|
|
17
16
|
const SOURCE_ID = /^S\d+$/
|
|
18
|
-
|
|
19
17
|
export const isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value)
|
|
20
18
|
export const isString = (value) => typeof value === "string"
|
|
21
19
|
export const isNonEmpty = (value) => typeof value === "string" && value.length > 0
|
|
@@ -48,6 +46,7 @@ export function locatorErrors(locator, at) {
|
|
|
48
46
|
const errors = []
|
|
49
47
|
if (!isObject(locator)) return errors
|
|
50
48
|
if (!isNonEmpty(locator.artifact)) errors.push(`${at}.artifact must be a non-empty string`)
|
|
49
|
+
if (locator.unit !== undefined && locator.unit !== "bytes") errors.push(`${at}.unit must be bytes`)
|
|
51
50
|
if (!(isCount(locator.char_start) && isCount(locator.char_end) && locator.char_start <= locator.char_end)) errors.push(`${at}.char_start/char_end must be integers with start <= end`)
|
|
52
51
|
for (const key of ["page", "line"]) {
|
|
53
52
|
if (locator[key] !== undefined && !(Number.isInteger(locator[key]) && locator[key] >= 1)) errors.push(`${at}.${key} must be an integer >= 1`)
|
|
@@ -87,6 +86,7 @@ export const RULES = Object.freeze({
|
|
|
87
86
|
rational_or_null: { cell: "rational or null", says: "null or { num: integer string, den: positive integer string }", test: orNull(isRational) },
|
|
88
87
|
by_derive: { cell: "reduced rational", says: "a reduced { num: integer string, den: positive integer string }", test: isRational },
|
|
89
88
|
context_by_derive: { cell: "written by derive (object or null)", says: "null or an object", test: orNull(isObject) },
|
|
89
|
+
source_context: { cell: "quote context or null (legacy)", says: "null or { prefix, suffix } up to 32 characters each", test: orNull((v) => isObject(v) && Object.keys(v).sort().join(",") === "prefix,suffix" && [v.prefix, v.suffix].every((s) => isString(s) && [...s].length <= 32)) },
|
|
90
90
|
derived_operation: { cell: "sum/diff/growth/share/ratio/expr", says: "a derived operation", test: (v) => Object.hasOwn(OPERATION_RULES, v) && OPERATION_RULES[v].kind === "derived" },
|
|
91
91
|
convert_operation: { cell: "`convert`", says: "convert", test: (v) => Object.hasOwn(OPERATION_RULES, v) && OPERATION_RULES[v].kind === "converted" },
|
|
92
92
|
precision: { cell: "`{ places, sigfigs }`", says: "nonnegative places and positive sigfigs", test: (v) => isObject(v) && Object.keys(v).sort().join(",") === "places,sigfigs" && Number.isSafeInteger(v.places) && v.places >= 0 && Number.isSafeInteger(v.sigfigs) && v.sigfigs >= 1 },
|
|
@@ -101,14 +101,13 @@ const unsourced = { source_id: "source_or_null", locator: "locator_or_null", sna
|
|
|
101
101
|
const row = (cells) => Object.freeze(Object.fromEntries(KIND_COLUMNS.map((column) => [column, cells[column] ?? (["precision", "compatibility"].includes(column) && cells.operation !== "null" ? column : "null")])))
|
|
102
102
|
|
|
103
103
|
export const KIND_RULES = Object.freeze({
|
|
104
|
-
measured: row({ fact_id: "f_id", value: "decimal", ...sourced, rationale: "string_or_null", exact: "from_value", context: "
|
|
105
|
-
quote: row({ fact_id: "q_id", value: "null", ...sourced, rationale: "string_or_null", exact: "null", context: "
|
|
104
|
+
measured: row({ fact_id: "f_id", value: "decimal", ...sourced, rationale: "string_or_null", exact: "from_value", context: "source_context", operation: "null" }),
|
|
105
|
+
quote: row({ fact_id: "q_id", value: "null", ...sourced, rationale: "string_or_null", exact: "null", context: "source_context", operation: "null" }),
|
|
106
106
|
derived: row({ fact_id: "f_id", value: "decimal", ...unsourced, rationale: "string_or_null", exact: "by_derive", context: "context_by_derive", operation: "derived_operation" }),
|
|
107
107
|
assumed: row({ fact_id: "f_id", value: "decimal", ...unsourced, rationale: "non_empty", exact: "rational_or_null", context: "null", operation: "null" }),
|
|
108
108
|
converted: row({ fact_id: "f_id", value: "decimal", ...unsourced, rationale: "string_or_null", exact: "by_derive", context: "context_by_derive", operation: "convert_operation" }),
|
|
109
109
|
})
|
|
110
110
|
|
|
111
|
-
/** The id prefix nextId assigns for a kind; an unknown kind gets F and fails validation later. */
|
|
112
111
|
export function idPrefix(kind) {
|
|
113
112
|
return RULES[KIND_RULES[kind]?.fact_id ?? "f_id"].prefix
|
|
114
113
|
}
|
|
@@ -169,7 +168,7 @@ const carriesDerivation = (row) => row.operation !== null || row.operands?.lengt
|
|
|
169
168
|
/** Dimension 32: a stored exact must equal the row's own value at the value's decimal places. */
|
|
170
169
|
function valueExactDisagreement(row) {
|
|
171
170
|
const exact = readExact(row.exact)
|
|
172
|
-
const value = readDecimal(row.value)
|
|
171
|
+
const value = isString(row.value) ? readDecimal(row.value).replace(/^-(0+(?:\.0+)?)$/, "$1") : row.value
|
|
173
172
|
if (!isRational(exact) || !isDecimal(value) || roundPlaces(toBig(exact), placesOf(value)) === value) return null
|
|
174
173
|
return `value ${value} disagrees with exact ${exact.num}/${exact.den} at ${placesOf(value)} decimal places`
|
|
175
174
|
}
|
|
@@ -212,7 +211,7 @@ export function kindRuleErrors(candidate, at) {
|
|
|
212
211
|
const value = candidate[column] === undefined && LATER_COLUMNS.includes(column) ? null : candidate[column]
|
|
213
212
|
const rule = RULES[legacy && column === "exact" ? "rational_or_null" : rules[column]]
|
|
214
213
|
// An exact with unknown keys loads as written (never stripped); readFlaws refuses it at use and at write.
|
|
215
|
-
if (column === "exact" && hasUnknownExactKeys(value) && !isCurrentDerived(candidate)) continue
|
|
214
|
+
if (column === "exact" && rules[column] !== "null" && hasUnknownExactKeys(value) && !isCurrentDerived(candidate)) continue
|
|
216
215
|
if (rule.test(value, candidate)) continue
|
|
217
216
|
errors.push(`${at}.${column} must be ${rule.says} for a ${candidate.kind} row`)
|
|
218
217
|
if (rule.detail) errors.push(...rule.detail(value, `${at}.${column}`))
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
// fact-locate.mjs - deterministic fact locators over a source snapshot.
|
|
1
|
+
// fact-locate.mjs - deterministic fact locators over a source snapshot's locator text.
|
|
2
2
|
//
|
|
3
3
|
// Each locator returns { value, unit, raw, quote, value_span, sentence_id, qualifier, locator } or
|
|
4
4
|
// { error: "fact_not_located" | "fact_ambiguous", candidates }; it never guesses. `quote` is the
|
|
5
|
-
// whole containing sentence, cell, or line of text.
|
|
6
|
-
//
|
|
7
|
-
//
|
|
5
|
+
// whole containing sentence, cell, or line of the view text (source-view.mjs: the visible text
|
|
6
|
+
// nodes of a page, never markup), `value_span` is [start, end] inside `quote` with
|
|
7
|
+
// quote.slice(...value_span) === raw, and locator.char_start/char_end place `quote` in that text;
|
|
8
|
+
// raw-locator.mjs turns them into bytes. Every call takes `sourceId` (S<n>) so sentence ids match
|
|
9
|
+
// sentences.jsonl, which indexes the same text.
|
|
8
10
|
// Plain Node ESM, sibling imports only; no network, no OCR.
|
|
9
11
|
|
|
10
12
|
import { proseText } from "./html-lite.mjs"
|
|
@@ -101,7 +103,8 @@ export function locateFind(text, { find, unitExpected, sourceId }) {
|
|
|
101
103
|
return result.unit === expected ? result : { error: "unit_expected_mismatch", expected, found: result.unit, candidates: [result] }
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
/** A row's cells by visual column (a colspan cell repeats). */
|
|
107
|
+
export function cellsOf(row) {
|
|
105
108
|
const cells = []
|
|
106
109
|
for (const cell of row.children.filter((child) => child.tag === "td" || child.tag === "th")) {
|
|
107
110
|
const span = Math.max(1, Number.parseInt(cell.attrs.colspan ?? "1", 10) || 1)
|
|
@@ -110,7 +113,7 @@ function cellsOf(row) {
|
|
|
110
113
|
return cells
|
|
111
114
|
}
|
|
112
115
|
|
|
113
|
-
function rowsOf(table) {
|
|
116
|
+
export function rowsOf(table) {
|
|
114
117
|
const rows = []
|
|
115
118
|
const walk = (node) => {
|
|
116
119
|
for (const child of node.children) {
|
|
@@ -142,10 +145,13 @@ function tablesOf(root) {
|
|
|
142
145
|
const cellLabel = (cell) => label(proseText(cell))
|
|
143
146
|
const indexesOf = (labels, wanted) => labels.flatMap((value, index) => (value === wanted ? [index] : []))
|
|
144
147
|
|
|
145
|
-
/**
|
|
146
|
-
|
|
148
|
+
/**
|
|
149
|
+
* --table/--row/--col: the table by id, caption, or a header label; row and column by normalized label,
|
|
150
|
+
* never by index. `source` is page html or an extracted view ({ root, text, blocks }) of one.
|
|
151
|
+
*/
|
|
152
|
+
export function locateTable(source, { table, row, col, sourceId }) {
|
|
147
153
|
requireSource(sourceId)
|
|
148
|
-
const { root, text, blocks } = snapshotBlocks(
|
|
154
|
+
const { root, text, blocks } = typeof source === "string" ? snapshotBlocks(source) : source
|
|
149
155
|
const key = label(table)
|
|
150
156
|
const tables = tablesOf(root).filter((entry) => entry.table.attrs.id === table || entry.caption === key || (entry.header && cellsOf(entry.header).map(cellLabel).includes(key)))
|
|
151
157
|
if (tables.length !== 1) return tables.length === 0 ? notLocated() : ambiguous(tables.map((entry) => ({ table: entry.table.attrs.id ?? entry.caption })))
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { CLAIM_ATTRIBUTE, CLAIM_KINDS, claimSatisfied, unmarkedKinds, unmarkedRequires } from "./claim-kinds.mjs"
|
|
15
15
|
import { proseSentences } from "./fidelity-binding.mjs"
|
|
16
16
|
import { clip } from "./fidelity-trace.mjs"
|
|
17
|
+
import { isClaimSegment } from "./sources-citation.mjs"
|
|
17
18
|
import { proseText } from "./html-lite.mjs"
|
|
18
19
|
|
|
19
20
|
const marked = (node) => node.attrs?.[CLAIM_ATTRIBUTE] !== undefined
|
|
@@ -63,7 +64,7 @@ export function claimChecks(ctx, rows, provenanceOf, flag) {
|
|
|
63
64
|
const id = fact.attrs["data-fact"]
|
|
64
65
|
if (!nearest) {
|
|
65
66
|
const need = unmarkedRequires(rows.get(id))
|
|
66
|
-
const mark = need && `{{${CLAIM_KINDS[need].prefix}:${id}}} (${CLAIM_ATTRIBUTE}="${need}")`
|
|
67
|
+
const mark = need && `{{${CLAIM_KINDS[need].prefix}:${id}:${rows.get(id).label}}} (${CLAIM_ATTRIBUTE}="${need}")`
|
|
67
68
|
if (need) flag("claim_kind_mismatch", fact, `${id} is a ${rows.get(id).kind} row cited with no mark; an unmarked numeral reads as a fact, so mark it ${mark}`)
|
|
68
69
|
continue
|
|
69
70
|
}
|
|
@@ -77,8 +78,8 @@ export function claimChecks(ctx, rows, provenanceOf, flag) {
|
|
|
77
78
|
flag(entry.defect, fact, `${row.fact_id} is marked ${name}, but it is a ${row.kind} row${source}`)
|
|
78
79
|
}
|
|
79
80
|
for (const block of proseSentences(ctx)) {
|
|
80
|
-
if (block.kind === "
|
|
81
|
-
for (const sentence of block.sentences) {
|
|
81
|
+
if (block.kind === "toc") continue
|
|
82
|
+
for (const sentence of block.kind === "sources" ? block.sentences.filter((s) => isClaimSegment(s.text)) : block.sentences) {
|
|
82
83
|
for (const name of unmarkedKinds(sentence.text)) {
|
|
83
84
|
const covered = sentence.facts.length > 0 ? sentence.facts.every((fact) => nearestKind(fact.node) === name) : nearestKind(block.owner) === name
|
|
84
85
|
if (covered) continue
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Read fact export CSV records, including quoted commas, escaped quotes and newlines.
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
3
|
+
|
|
4
|
+
export function readCsv(path) {
|
|
5
|
+
if (!existsSync(path)) return null
|
|
6
|
+
const text = readFileSync(path, "utf8")
|
|
7
|
+
const records = []
|
|
8
|
+
let cells = []
|
|
9
|
+
let cell = ""
|
|
10
|
+
let quoted = false
|
|
11
|
+
for (let i = 0; i <= text.length; i++) {
|
|
12
|
+
const char = text[i]
|
|
13
|
+
if (char === '"') {
|
|
14
|
+
if (quoted && text[i + 1] === '"') {
|
|
15
|
+
cell += '"'
|
|
16
|
+
i++
|
|
17
|
+
} else quoted = !quoted
|
|
18
|
+
} else if (!quoted && (char === "," || char === "\n" || char === undefined)) {
|
|
19
|
+
cells.push(cell.trim())
|
|
20
|
+
cell = ""
|
|
21
|
+
if (char !== ",") {
|
|
22
|
+
if (cells.some((value) => value !== "")) records.push(cells)
|
|
23
|
+
cells = []
|
|
24
|
+
}
|
|
25
|
+
} else if (char !== undefined) cell += char
|
|
26
|
+
}
|
|
27
|
+
if (quoted) return null
|
|
28
|
+
const [head = [], ...rows] = records
|
|
29
|
+
const [id, value, unit] = ["fact_id", "plot_value", "unit"].map((name) => head.indexOf(name))
|
|
30
|
+
if (id < 0 || value < 0 || unit < 0 || rows.length === 0) return null
|
|
31
|
+
return rows.map((c) => ({ fact_id: c[id], plot_value: c[value], unit: c[unit] ?? "" }))
|
|
32
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// causality_added, qualifier_dropped (six-token window around the fact span; a :q rendering puts
|
|
5
5
|
// the qualifier inside the span), scope_widened_warn, and the acronym-aware name_outside_quote.
|
|
6
6
|
// The hedge-position heuristic never yields a code; it only sets force_strong for the meaning
|
|
7
|
-
// verifier
|
|
7
|
+
// verifier; name_outside_quote and scope_widened_warn also emit minor defects. Latin terms match whole words (terms
|
|
8
8
|
// of four or more letters also match their inflections); Korean terms match as substrings, single
|
|
9
9
|
// syllables as tokens. No model, no IO. Plain Node ESM; Korean strings are \u escapes.
|
|
10
10
|
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Check displayed conversion originals against their operands, not the mutable render field.
|
|
2
|
+
import { sameValue, unitKey } from "./fidelity-binding.mjs"
|
|
3
|
+
import { proseText } from "./html-lite.mjs"
|
|
4
|
+
import { parseNumeral } from "./numerals.mjs"
|
|
5
|
+
import { normalizeText } from "./text-normalize.mjs"
|
|
6
|
+
import { display } from "./unit-precision.mjs"
|
|
7
|
+
import { dimensionOf } from "./units.mjs"
|
|
8
|
+
|
|
9
|
+
const DERIVED = new Set(["converted", "derived"])
|
|
10
|
+
/**
|
|
11
|
+
* The one bracket grammar of the skill. After NFKC (fullwidth parentheses and square brackets fold
|
|
12
|
+
* to ASCII), an original is a () [] 【】 「」 or 〔〕 group. Inside a derived or converted element every
|
|
13
|
+
* group is an original, never prose; a dash separator is not an original.
|
|
14
|
+
*/
|
|
15
|
+
const PAIRS = [["(", ")"], ["[", "]"], ["\u3010", "\u3011"], ["\u300C", "\u300D"], ["\u3014", "\u3015"]]
|
|
16
|
+
const [OPEN, CLOSE] = [PAIRS.map((pair) => pair[0]).join(""), PAIRS.map((pair) => pair[1]).join("")]
|
|
17
|
+
const inClass = (chars) => chars.replace(/[\\\]\[^-]/g, "\\$&")
|
|
18
|
+
const literal = (chars) => chars.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
19
|
+
const ANY = inClass(OPEN + CLOSE)
|
|
20
|
+
const GROUP = new RegExp(PAIRS.map(([open, close]) => `${literal(open)}([^${ANY}]*)${literal(close)}`).join("|"), "gu")
|
|
21
|
+
const BRACKET = new RegExp(`[${ANY}]`, "u")
|
|
22
|
+
const folded = (text) => String(text).normalize("NFKC")
|
|
23
|
+
const innerOf = (match) => match.slice(1).find((part) => part !== undefined)
|
|
24
|
+
const mismatch = (message) => ["value_mismatch", message, "original"]
|
|
25
|
+
|
|
26
|
+
const halfFits = (row, half) => {
|
|
27
|
+
const expected = normalizeText(folded(display(String(row.value), row.unit ?? null)))
|
|
28
|
+
const text = normalizeText(half)
|
|
29
|
+
return text === expected || (text.endsWith(` ${expected}`) && !/\d/.test(text.slice(0, -expected.length)))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The converted half (the text outside the originals) equals display(row.value, row.unit), rebuilt from the row. */
|
|
33
|
+
export function convertedHalfFits(row, shown) {
|
|
34
|
+
if (!DERIVED.has(row.kind) || row.value === null || row.value === undefined) return false
|
|
35
|
+
return halfFits(row, folded(shown).replace(GROUP, ""))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A second number outside the value verify reads and its originals ("320,000 mm - 999 m"). */
|
|
39
|
+
function strayNumber(row, half) {
|
|
40
|
+
if (row.value === null || row.value === undefined || halfFits(row, half)) return null
|
|
41
|
+
const read = parseNumeral(half)
|
|
42
|
+
if (!read || !sameValue(read.value, row.value)) return null
|
|
43
|
+
const rest = half.slice(0, read.span[0]) + half.slice(read.span[1])
|
|
44
|
+
return /\d/.test(row.unit ? rest.split(row.unit).join("") : rest) ? mismatch(`"${half.trim()}" carries a number besides the value and its originals`) : null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** `valueMode`: the element shows the bare value ({{F:x:value}}), so no original is due. */
|
|
48
|
+
export function originalProblem(row, shown, rows, valueMode = false) {
|
|
49
|
+
if (!DERIVED.has(row.kind)) return null
|
|
50
|
+
const text = folded(shown)
|
|
51
|
+
const groups = [...text.matchAll(GROUP)]
|
|
52
|
+
const half = text.replace(GROUP, "")
|
|
53
|
+
if (BRACKET.test(half)) return mismatch("original brackets are malformed or nested")
|
|
54
|
+
const operands = (row.derived_from ?? []).map((id) => rows.get(id))
|
|
55
|
+
for (const [index, match] of groups.entries()) {
|
|
56
|
+
const [inner, operand] = [innerOf(match), operands[index]]
|
|
57
|
+
const parsed = parseNumeral(inner)
|
|
58
|
+
if (!operand) return mismatch(`original "${inner}" has no operand of ${row.fact_id}`)
|
|
59
|
+
if (!parsed || !sameValue(parsed.value, operand.value)) return mismatch(`original "${inner}" differs from operand ${operand.fact_id}`)
|
|
60
|
+
if (unitKey(parsed.unitRaw ?? "") !== unitKey(operand.unit ?? "")) return ["unit_mismatch", `original "${inner}" is not in ${operand.unit}`, "original"]
|
|
61
|
+
const expected = normalizeText(folded(display(operand.value, operand.unit ?? null)))
|
|
62
|
+
if (normalizeText(inner) !== expected) return mismatch(`original "${inner}" differs from "${expected}"`)
|
|
63
|
+
}
|
|
64
|
+
if (groups.length > 0 && !/\d/.test(text.slice(0, groups[0].index))) return mismatch(`original "${innerOf(groups[0])}" precedes the value`)
|
|
65
|
+
if (row.kind === "converted" && !valueMode && /\d/.test(half) && groups.length < operands.length) return mismatch(`the original of ${row.derived_from[groups.length]} is missing after the value`)
|
|
66
|
+
return strayNumber(row, half)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Stands for a filled element or another fill-map value in the text after a fill site. */
|
|
70
|
+
const FILLED = "\uFFFC"
|
|
71
|
+
/** After a fill site the grammar also reads the brackets an element never carries as originals. */
|
|
72
|
+
const FOLLOW = [...PAIRS, ["\u300E", "\u300F"], ["\u300A", "\u300B"], ["\u3008", "\u3009"], ["\u27E8", "\u27E9"]]
|
|
73
|
+
const dimension = (unit) => dimensionOf(String(unit).replace(/-e\d+$/u, "")) ?? unitKey(unit)
|
|
74
|
+
|
|
75
|
+
/** What the text after a fill site opens: a bracket group's content, or the clause after a separator (`open`); else null. */
|
|
76
|
+
function openedGroup(text) {
|
|
77
|
+
const rest = folded(text).trimStart()
|
|
78
|
+
const pair = FOLLOW.find(([open]) => rest.startsWith(open))
|
|
79
|
+
const close = pair ? rest.indexOf(pair[1], 1) : -1
|
|
80
|
+
if (pair) return { group: rest.slice(1, close === -1 ? undefined : close).trim(), open: false }
|
|
81
|
+
return /^[-\u2013\u2014/]/u.test(rest) ? { group: rest.slice(1).split(/[,;:!?)\]]|\.(?!\d)/u)[0].trim(), open: true } : null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Whether the text right after a fill site of `row` opens another original: a bracket group or a
|
|
86
|
+
* separator clause that is exactly a numeral with a unit of the row's or an operand's dimension (a
|
|
87
|
+
* separator clause may end in a glued particle, as Korean writes "- 999 m\uC774\uB2E4").
|
|
88
|
+
* A filled element, a fill-map value (`fills`), a placeholder, a unitless number (a year, a
|
|
89
|
+
* footnote) and prose with digits are not originals; untraceable_number still reads a stray number.
|
|
90
|
+
*/
|
|
91
|
+
export const followsOriginal = (row, rows, fills = []) => (text) => {
|
|
92
|
+
if (!DERIVED.has(row?.kind)) return false
|
|
93
|
+
const after = [...fills].filter(Boolean).sort((a, b) => b.length - a.length).reduce((cur, fill) => cur.split(fill).join(FILLED), String(text))
|
|
94
|
+
const { group, open } = openedGroup(after) ?? { group: "" }
|
|
95
|
+
if (!group || group.includes(FILLED) || group.includes("{{")) return false
|
|
96
|
+
const units = [row.unit, ...(row.derived_from ?? []).map((id) => rows.get(id)?.unit)].filter(Boolean)
|
|
97
|
+
return [group, ...(open ? [group.replace(/[\uAC00-\uD7A3]+$/u, "").trim()] : [])].some((body) => {
|
|
98
|
+
const read = parseNumeral(body, 0)
|
|
99
|
+
return Boolean(read?.unitRaw) && read.span[0] === 0 && read.span[1] === body.length && units.some((unit) => dimension(unit) === dimension(read.unitRaw))
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** The prose after `node` in its parent, each filled element (data-fact) read as one FILLED mark. */
|
|
104
|
+
export const textAfter = (node) => {
|
|
105
|
+
const siblings = node.parent?.children.slice(node.parent.children.indexOf(node) + 1) ?? []
|
|
106
|
+
return proseText({ children: siblings.map((child) => (child.attrs?.["data-fact"] === undefined ? child : { tag: "#text", text: FILLED })) })
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const SPACE = "[\\s\\u3000]"
|
|
110
|
+
const DIGIT = "[0-9\\uFF10-\\uFF19]"
|
|
111
|
+
/** Each character with the fullwidth form NFKC folds onto it. */
|
|
112
|
+
const wide = (chars) => [...chars].map((ch) => ch + (/[!-~]/.test(ch) ? String.fromCharCode(ch.charCodeAt(0) + 0xfee0) : "")).join("")
|
|
113
|
+
const [WIDE_OPEN, WIDE_CLOSE] = [inClass(wide(OPEN)), inClass(wide(CLOSE))]
|
|
114
|
+
|
|
115
|
+
/** A pattern reading `rendered` modulo the bracket grammar: NFKC fullwidth forms, bracket style, spacing around brackets. */
|
|
116
|
+
function renderPattern(rendered) {
|
|
117
|
+
const text = folded(rendered).trim()
|
|
118
|
+
let body = ""
|
|
119
|
+
for (let at = 0; at < text.length; at += 1) {
|
|
120
|
+
const ch = text[at]
|
|
121
|
+
const beside = (OPEN + CLOSE).includes(text.slice(at).trimStart()[0]) || OPEN.includes(text[at - 1])
|
|
122
|
+
if (/\s/.test(ch)) body += beside ? "" : `${SPACE}+`
|
|
123
|
+
else if (OPEN.includes(ch)) body += `${SPACE}*([${WIDE_OPEN}])${SPACE}*`
|
|
124
|
+
else if (CLOSE.includes(ch)) body += `${SPACE}*([${WIDE_CLOSE}])`
|
|
125
|
+
else body += `[${inClass(wide(ch))}]`
|
|
126
|
+
}
|
|
127
|
+
// A digit may not run into a render's leading or trailing digit ("1,320 m" holds no "320 m"); a bracket ends the render.
|
|
128
|
+
return new RegExp(`${/^\d/.test(text) ? `(?<!${DIGIT})` : ""}${body}${/\d$/.test(text) ? `(?!${DIGIT})` : ""}`, "gu")
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const pairIndex = (ch, side) => [...side].findIndex((open) => open === folded(ch))
|
|
132
|
+
/** [start, end) of `rendered` in `text` from `from` under the bracket grammar, not followed by another original (`follows`); or null. */
|
|
133
|
+
export function findRender(text, rendered, from = 0, follows = () => false) {
|
|
134
|
+
const pattern = renderPattern(rendered)
|
|
135
|
+
pattern.lastIndex = from
|
|
136
|
+
for (let match = pattern.exec(text); match; match = pattern.exec(text)) {
|
|
137
|
+
const marks = match.slice(1)
|
|
138
|
+
const paired = marks.every((mark, i) => i % 2 === 1 || pairIndex(mark, OPEN) === pairIndex(marks[i + 1] ?? "", CLOSE))
|
|
139
|
+
const end = match.index + match[0].length
|
|
140
|
+
if (paired && !follows(text.slice(end))) return [match.index, end]
|
|
141
|
+
pattern.lastIndex = match.index + 1
|
|
142
|
+
}
|
|
143
|
+
return null
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Where a stale fill-map entry's text sits: derived and converted renders are read under the bracket grammar. */
|
|
147
|
+
export const renderLocator = (rows, fillMap) => (entry, text, from) => {
|
|
148
|
+
const row = rows.get(entry.fact_id)
|
|
149
|
+
if (DERIVED.has(row?.kind)) return findRender(text, entry.rendered, from, followsOriginal(row, rows, (fillMap ?? []).map((other) => other.rendered)))
|
|
150
|
+
const hit = text.indexOf(entry.rendered, from)
|
|
151
|
+
return hit === -1 ? null : [hit, hit + entry.rendered.length]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Null when a stale derived render is still in the report; "original" when only its converted half is; "gone" otherwise. */
|
|
155
|
+
export function staleRender(row, rendered, text, follows) {
|
|
156
|
+
if (findRender(text, rendered, 0, follows) !== null) return null
|
|
157
|
+
const half = folded(rendered).replace(GROUP, "").trim()
|
|
158
|
+
return half !== "" && /\d/.test(half) && findRender(text, half) !== null ? "original" : "gone"
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export const isDerivedRow = (row) => DERIVED.has(row?.kind)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// fidelity-policy.mjs - what the locked `## Fidelity` block of brief.md means to the CLI stages.
|
|
2
|
+
//
|
|
3
|
+
// lockedBrief is the gate the six reader-facing stages (fact fill, verify, pairs, meaning-check,
|
|
4
|
+
// polish-apply, polish-diff) run before reading or writing anything: an unlocked brief returns
|
|
5
|
+
// one fidelity_interview_incomplete defect (exit 1), a malformed block is a usage error (exit 2).
|
|
6
|
+
// fillPolicy reads the fields fact fill consumes (a value off its table is a usage error, exit 2),
|
|
7
|
+
// and policyErrors refuses a placeholder whose row the brief forbids: derived_not_allowed
|
|
8
|
+
// (`derived numbers: none` against a derived, converted, or assumed row) and source_outside_floor
|
|
9
|
+
// (the source floor is evaluated live against each source's meta.json at every fill and verify;
|
|
10
|
+
// under any floor but `standard` a row resting on no source is refused too; a row's outside_floor
|
|
11
|
+
// is only the cached result). briefHashOf binds the locked block into the fill map, and
|
|
12
|
+
// briefBindingErrors refuses an edition whose map was filled under another brief (brief_changed).
|
|
13
|
+
// Collection stages never call this module. node: builtins and sibling imports only.
|
|
14
|
+
|
|
15
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
16
|
+
import { join, resolve } from "node:path"
|
|
17
|
+
|
|
18
|
+
import { CliError, sha256Of } from "./cli-support.mjs"
|
|
19
|
+
import { DEFECT_CODES } from "./contracts.mjs"
|
|
20
|
+
import { KIND_RULES } from "./fact-ledger-kinds.mjs"
|
|
21
|
+
import { FIDELITY_FIELDS, meaningCheckEnabled, requireLockedBrief } from "./fidelity-brief.mjs"
|
|
22
|
+
|
|
23
|
+
export { meaningCheckEnabled }
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Ledger kinds a brief with `derived numbers: none` refuses. A policy list, not the ledger's
|
|
27
|
+
* derivation set: it also names assumed. Every name must be a KIND_RULES kind (checked at load).
|
|
28
|
+
*/
|
|
29
|
+
const DERIVED_KINDS = Object.freeze(["derived", "converted", "assumed"])
|
|
30
|
+
for (const kind of DERIVED_KINDS) {
|
|
31
|
+
if (!Object.hasOwn(KIND_RULES, kind)) throw new Error(`fidelity-policy: ${kind} is not a KIND_RULES kind`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Fields whose only legal values are a closed table: value (any case) -> its reading. */
|
|
35
|
+
const VALUE_TABLES = Object.freeze({
|
|
36
|
+
"derived numbers": Object.freeze({ allowed: false, none: true }),
|
|
37
|
+
fallback: Object.freeze({ "block-quote": "quote", omit: "omit" }),
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
/** The reading of a table value; any other text is a usage error naming the field and the value. */
|
|
41
|
+
function tableValue(field, value) {
|
|
42
|
+
const table = VALUE_TABLES[field]
|
|
43
|
+
const key = value.trim().toLowerCase()
|
|
44
|
+
if (Object.hasOwn(table, key)) return table[key]
|
|
45
|
+
throw new CliError(`${field} "${value}" is not ${Object.keys(table).join(", ")}`)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** How each field value the fill stages consume is read; the single owner of those readings. */
|
|
49
|
+
export const FIDELITY_VALUE_RULES = Object.freeze({
|
|
50
|
+
tables: VALUE_TABLES,
|
|
51
|
+
derivedKinds: DERIVED_KINDS,
|
|
52
|
+
derivedRefused: (kind) => DERIVED_KINDS.includes(kind),
|
|
53
|
+
derivedNone: (value) => tableValue("derived numbers", value),
|
|
54
|
+
fallback: (value) => tableValue("fallback", value),
|
|
55
|
+
translations: (value) => /with translation beside/iu.test(value),
|
|
56
|
+
meaningCheck: (value) => meaningCheckEnabled({ fields: { "meaning check": value } }),
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
/** The `source floor` forms: `pattern` reads one, `listed` forms carry a comma list. */
|
|
60
|
+
export const SOURCE_FLOOR_RULES = Object.freeze([
|
|
61
|
+
Object.freeze({ kind: "standard", form: "standard", pattern: /^standard$/iu, listed: false }),
|
|
62
|
+
Object.freeze({ kind: "primary", form: "primary only", pattern: /^primary only$/iu, listed: false }),
|
|
63
|
+
Object.freeze({ kind: "pointed", form: "pointed only: <list>", pattern: /^pointed only:\s*(.+)$/iu, listed: true }),
|
|
64
|
+
Object.freeze({ kind: "classes", form: "classes: <list>", pattern: /^classes:\s*(.+)$/iu, listed: true }),
|
|
65
|
+
])
|
|
66
|
+
const lineOf = (text, at) => text.slice(0, at).split("\n").length
|
|
67
|
+
const listOf = (text) => text.split(",").map((entry) => entry.trim()).filter(Boolean)
|
|
68
|
+
|
|
69
|
+
/** brief.md from --brief, else the session's; a usage error when neither is known. */
|
|
70
|
+
export function briefPathOf(flags) {
|
|
71
|
+
if (flags.brief !== undefined && flags.brief !== true) return resolve(flags.brief)
|
|
72
|
+
const dir = flags["session-dir"] ?? process.env.SESSION_DIR
|
|
73
|
+
if (!dir || dir === true) throw new CliError("--brief is required without --session-dir (or SESSION_DIR)")
|
|
74
|
+
return join(resolve(dir), "brief.md")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @returns {{ parsed: object, refusal: null } | { parsed: null, refusal: { json: object, summary: string, exitCode: 1 } }}
|
|
79
|
+
*/
|
|
80
|
+
export function lockedBrief(command, flags) {
|
|
81
|
+
const path = briefPathOf(flags)
|
|
82
|
+
const lock = requireLockedBrief(path)
|
|
83
|
+
if (lock.exitCode === 2) throw new CliError(`${path}: ${lock.errors.join("; ")}`)
|
|
84
|
+
if (lock.locked) return { parsed: lock.parsed, refusal: null }
|
|
85
|
+
const json = { command, status: "fail", exitCode: 1, defects: lock.defects }
|
|
86
|
+
return { parsed: null, refusal: { json, summary: `${command}: ${lock.defects[0].message}`, exitCode: 1 } }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The source floor as a rule, or null for `standard`; a usage error for any other text.
|
|
91
|
+
* @returns {null | { kind: "primary" } | { kind: "pointed" | "classes", list: string[] }}
|
|
92
|
+
*/
|
|
93
|
+
export function parseSourceFloor(value) {
|
|
94
|
+
const text = value.trim()
|
|
95
|
+
for (const rule of SOURCE_FLOOR_RULES) {
|
|
96
|
+
const match = rule.pattern.exec(text)
|
|
97
|
+
if (!match) continue
|
|
98
|
+
if (rule.kind === "standard") return null
|
|
99
|
+
return rule.listed ? { kind: rule.kind, list: listOf(match[1]) } : { kind: rule.kind }
|
|
100
|
+
}
|
|
101
|
+
throw new CliError(`source floor "${value}" is not ${SOURCE_FLOOR_RULES.map((rule) => rule.form).join(", ")}`)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function hostOf(url) {
|
|
105
|
+
return typeof url === "string" && URL.canParse(url) ? new URL(url).hostname.toLowerCase() : null
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Whether one source (id and meta.json) satisfies a parsed floor rule. */
|
|
109
|
+
export function sourceInsideFloor(rule, sourceId, meta) {
|
|
110
|
+
if (rule.kind === "primary") return meta.provenance === "primary"
|
|
111
|
+
if (rule.kind === "pointed") return rule.list.includes(sourceId) || rule.list.includes(meta.url)
|
|
112
|
+
const host = hostOf(meta.url)
|
|
113
|
+
return host !== null && rule.list.some((entry) => host === entry.toLowerCase() || host.endsWith(`.${entry.toLowerCase()}`))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** The fields fact fill consumes: the fallback form and whether a translation binds to its quote. */
|
|
117
|
+
export function fillPolicy(parsed) {
|
|
118
|
+
const field = (name) => parsed.fields[name]
|
|
119
|
+
return {
|
|
120
|
+
fallback: FIDELITY_VALUE_RULES.fallback(field("fallback")),
|
|
121
|
+
translations: FIDELITY_VALUE_RULES.translations(field("languages")),
|
|
122
|
+
derivedNone: FIDELITY_VALUE_RULES.derivedNone(field("derived numbers")),
|
|
123
|
+
floor: parseSourceFloor(field("source floor")),
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Source ids behind a row: its own, or for a derived row its operands' sources; null marks a leaf with no source. */
|
|
128
|
+
function sourcesOf(row, rows, seen = new Set()) {
|
|
129
|
+
if (seen.has(row.fact_id)) return []
|
|
130
|
+
seen.add(row.fact_id)
|
|
131
|
+
if (row.source_id) return [row.source_id]
|
|
132
|
+
const inputs = [...(row.operands ?? []), ...(row.derived_from ?? [])]
|
|
133
|
+
if (inputs.length === 0) return [null]
|
|
134
|
+
return inputs.flatMap((id) => (rows.has(id) ? sourcesOf(rows.get(id), rows, seen) : [null]))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** sha256 of the locked `## Fidelity` block normalized: the seven fields in FIDELITY_FIELDS order, `field: value` per line. */
|
|
138
|
+
export const briefHashOf = (parsed) => sha256Of(FIDELITY_FIELDS.map((field) => `${field}: ${parsed.fields[field]}`).join("\n"))
|
|
139
|
+
|
|
140
|
+
/** brief_changed when there is no fill map (map null) or it was not written under the current brief (or predates the binding). */
|
|
141
|
+
export function briefBindingErrors(map, mapPath, parsed) {
|
|
142
|
+
if (map?.brief_sha256 === briefHashOf(parsed)) return []
|
|
143
|
+
const why = map === null ? `no fill map at ${mapPath}` : `${mapPath} ${typeof map.brief_sha256 === "string" ? "was filled under a different ## Fidelity block" : "records no brief_sha256"}`
|
|
144
|
+
return [{ code: "brief_changed", token: null, line: null, message: `${why}; re-run fact fill under the current brief`, severity: DEFECT_CODES.brief_changed.severity, integrity: DEFECT_CODES.brief_changed.integrity, hint: DEFECT_CODES.brief_changed.hint }]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function metaOf(sessionDir, sourceId, cache) {
|
|
148
|
+
if (!cache.has(sourceId)) {
|
|
149
|
+
const file = join(sessionDir, "sources", sourceId, "meta.json")
|
|
150
|
+
cache.set(sourceId, existsSync(file) ? JSON.parse(readFileSync(file, "utf8")) : { url: null, provenance: "unknown" })
|
|
151
|
+
}
|
|
152
|
+
return cache.get(sourceId)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const defect = (code, pointer, text, message) => ({ code, token: pointer.token, line: lineOf(text, pointer.start), message, severity: DEFECT_CODES[code].severity, hint: DEFECT_CODES[code].hint })
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Refusals for the placeholders of one fill source (or the data-fact elements of one edition at
|
|
159
|
+
* verify). Sets each referenced row's outside_floor to this evaluation and reports whether any
|
|
160
|
+
* cached value changed.
|
|
161
|
+
* @param {{ token: string, start: number, parsed: { id?: string } }[]} found findPlaceholders output
|
|
162
|
+
* @returns {{ errors: object[], cacheChanged: boolean }}
|
|
163
|
+
*/
|
|
164
|
+
export function policyErrors(text, found, ledger, sessionDir, policy) {
|
|
165
|
+
const rows = new Map(ledger.rows.map((row) => [row.fact_id, row]))
|
|
166
|
+
const metas = new Map()
|
|
167
|
+
const errors = []
|
|
168
|
+
let cacheChanged = false
|
|
169
|
+
for (const pointer of found) {
|
|
170
|
+
const row = rows.get(pointer.parsed?.id)
|
|
171
|
+
if (row === undefined || row.status !== "active") continue
|
|
172
|
+
if (policy.derivedNone && FIDELITY_VALUE_RULES.derivedRefused(row.kind)) {
|
|
173
|
+
errors.push(defect("derived_not_allowed", pointer, text, `${row.fact_id} is ${row.kind}; the brief records derived numbers: none`))
|
|
174
|
+
}
|
|
175
|
+
const sources = sourcesOf(row, rows)
|
|
176
|
+
const outside = policy.floor === null ? [] : [...new Set(sources.filter((id) => id === null || !sourceInsideFloor(policy.floor, id, metaOf(sessionDir, id, metas))))]
|
|
177
|
+
if (row.outside_floor !== outside.length > 0) cacheChanged = true
|
|
178
|
+
row.outside_floor = outside.length > 0
|
|
179
|
+
const named = outside.map((id) => id ?? "no source").join(", ")
|
|
180
|
+
if (outside.length > 0) errors.push(defect("source_outside_floor", pointer, text, `${row.fact_id} rests on ${named}, outside the source floor`))
|
|
181
|
+
}
|
|
182
|
+
return { errors, cacheChanged }
|
|
183
|
+
}
|