oh-my-opencode 5.1.43 → 5.1.45
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/cli/index.js +948 -416
- package/dist/cli/service-auth/keystore.d.ts +4 -2
- package/dist/cli-node/index.js +948 -416
- package/dist/config-migration/dori-section-rename.d.ts +3 -0
- package/dist/config-migration/index.d.ts +2 -2
- package/dist/config-migration/migration-plans.d.ts +10 -0
- package/dist/features/builtin-commands/templates/hyperplan.d.ts +1 -1
- package/dist/features/builtin-commands/templates/refactor-sections/team-mode-addendum.d.ts +1 -1
- package/dist/features/builtin-commands/templates/remove-ai-slops.d.ts +1 -1
- package/dist/hooks/sisyphus-junior-notepad/constants.d.ts +1 -1
- package/dist/index.js +6369 -3370
- package/dist/oh-my-opencode.schema.json +2 -2
- package/dist/plugin/command-execute-before.d.ts +3 -0
- package/dist/plugin/skill-context.d.ts +2 -0
- package/dist/plugin/skill-security-notice.d.ts +3 -0
- package/dist/plugin-config/omo-config-chain.d.ts +1 -0
- package/dist/skills/browser/SKILL.md +21 -22
- package/dist/skills/browser/references/commands.md +2 -9
- package/dist/skills/browser/references/install.md +1 -2
- package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
- package/dist/skills/browser/scripts/browser-doctor.mjs +2 -2
- package/dist/skills/browser/scripts/browser-engine-guard.mjs +63 -487
- package/dist/skills/browser/scripts/browser-install.mjs +1 -1
- package/dist/skills/browser/scripts/omowright.mjs +1 -10
- package/dist/skills/frontend/SKILL.md +79 -118
- package/dist/skills/frontend/references/design/README.md +75 -224
- package/dist/skills/frontend/references/design/stylegallery.md +32 -27
- package/dist/skills/frontend/references/perfection/README.md +2 -2
- package/dist/skills/frontend/scripts/perfection/check-accent-stripes.ts +8 -24
- package/dist/skills/frontend/scripts/perfection/check-draft-guard.test.ts +101 -0
- package/dist/skills/frontend/scripts/perfection/check-draft-guard.ts +40 -0
- package/dist/skills/frontend/scripts/perfection/collect-files.test.ts +50 -0
- package/dist/skills/frontend/scripts/perfection/collect-files.ts +53 -0
- package/dist/skills/frontend/scripts/perfection/draft-guard/findings.ts +16 -0
- package/dist/skills/frontend/scripts/perfection/draft-guard/lint.ts +38 -0
- package/dist/skills/frontend/scripts/perfection/draft-guard/rules.ts +69 -0
- package/dist/skills/frontend/scripts/perfection/draft-guard/text-nodes.ts +121 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/attr-lookalikes.tsx +10 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/bound-values.tsx +12 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/const-generics.tsx +3 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/generics.tsx +7 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/measured-stats.html +6 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/plain-copy.html +9 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/state-copy.html +11 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/attribute-edges.html +7 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/components.tsx +16 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/decorative-badge.vue +7 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/emoji-icons.tsx +9 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/jsx-edges.tsx +1 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/promo-copy.html +6 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/promo-copy.tsx +8 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/vanity-stats.html +5 -0
- package/dist/skills/programming/SKILL.md +10 -7
- package/dist/skills/programming/references/typescript/README.md +10 -7
- package/dist/skills/programming/references/typescript/bootstrap.md +9 -23
- package/dist/skills/programming/references/typescript/oxc-lint.md +130 -0
- package/dist/skills/programming/references/typescript/tsconfig-strict.md +6 -62
- package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.ts +12 -12
- package/dist/skills/programming/scripts/typescript/new-project.test.ts +162 -0
- package/dist/skills/programming/scripts/typescript/new-project.ts +20 -81
- package/dist/skills/programming/scripts/typescript/oxc/.oxfmtrc.json +9 -0
- package/dist/skills/programming/scripts/typescript/oxc/.oxlintrc.json +46 -0
- package/dist/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/LICENSE +21 -0
- package/dist/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/index.js +10 -0
- package/dist/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/no-em-dash-copy.js +28 -0
- package/dist/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/require-suppression-reason.js +62 -0
- package/dist/skills/programming/scripts/typescript/oxc/tsconfig.json +29 -0
- package/dist/skills/refactor/SKILL.md +13 -13
- package/dist/skills/ulw-execute/SKILL.md +1 -1
- package/dist/skills/ulw-research/AGENTS.md +9 -3
- package/dist/skills/ulw-research/SKILL.md +2 -2
- package/dist/skills/ulw-research/references/deliverable-phase.md +7 -6
- package/dist/skills/ulw-research/references/fact-ledger-grammar.md +116 -0
- package/dist/skills/ulw-research/references/report-gates.md +51 -3
- package/dist/skills/ulw-research/scripts/claims-index.mjs +125 -0
- package/dist/skills/ulw-research/scripts/claims-index.test.ts +149 -0
- package/dist/skills/ulw-research/scripts/contracts.mjs +68 -3
- package/dist/skills/ulw-research/scripts/contracts.test.ts +97 -12
- package/dist/skills/ulw-research/scripts/fact-ledger-grammar.test.ts +190 -0
- package/dist/skills/ulw-research/scripts/fact-ledger-kinds.mjs +136 -0
- package/dist/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +141 -0
- package/dist/skills/ulw-research/scripts/fact-ledger-schema.mjs +204 -0
- package/dist/skills/ulw-research/scripts/fact-ledger-schema.test.ts +43 -0
- package/dist/skills/ulw-research/scripts/fact-ledger.mjs +103 -0
- package/dist/skills/ulw-research/scripts/fact-ledger.test.ts +252 -0
- package/dist/skills/ulw-research/scripts/fidelity-brief.mjs +145 -0
- package/dist/skills/ulw-research/scripts/fidelity-brief.test.ts +179 -0
- package/dist/skills/ulw-research/scripts/fidelity-state.mjs +63 -0
- package/dist/skills/ulw-research/scripts/fidelity-state.test.ts +46 -0
- package/dist/skills/ulw-research/scripts/gates-context.test.ts +64 -0
- package/dist/skills/ulw-research/scripts/gates-static.mjs +1 -1
- package/dist/skills/ulw-research/scripts/gates-structure.mjs +1 -1
- package/dist/skills/ulw-research/scripts/gates-text.mjs +1 -27
- package/dist/skills/ulw-research/scripts/lexicon.mjs +47 -0
- package/dist/skills/ulw-research/scripts/lexicon.test.ts +57 -0
- package/dist/skills/ulw-research/scripts/numerals.mjs +226 -0
- package/dist/skills/ulw-research/scripts/numerals.test.ts +120 -0
- package/dist/skills/ulw-research/scripts/outcome.mjs +2 -3
- package/dist/skills/ulw-research/scripts/outcome.test.ts +29 -0
- package/dist/skills/ulw-research/scripts/particles-ko.mjs +108 -0
- package/dist/skills/ulw-research/scripts/particles-ko.test.ts +86 -0
- package/dist/skills/ulw-research/scripts/rational.mjs +139 -0
- package/dist/skills/ulw-research/scripts/rational.test.ts +46 -0
- package/dist/skills/ulw-research/scripts/report-tools-commands.mjs +2 -2
- package/dist/skills/ulw-research/scripts/sentence-split.mjs +77 -0
- package/dist/skills/ulw-research/scripts/sentence-split.test.ts +109 -0
- package/dist/skills/ulw-research/scripts/tests/fixtures/fidelity/claim-graph.md +13 -0
- package/dist/skills/ulw-research/scripts/tests/fixtures/fidelity-brief-locked.md +17 -0
- package/dist/skills/ulw-research/scripts/tests/fixtures/fidelity-brief-pending.md +17 -0
- package/dist/skills/ulw-research/scripts/text-normalize.mjs +82 -0
- package/dist/skills/ulw-research/scripts/text-normalize.test.ts +73 -0
- package/dist/skills/ulw-research/scripts/text-similarity.mjs +28 -0
- package/dist/skills/ulw-research/scripts/text-similarity.test.ts +38 -0
- package/dist/skills/ulw-research/scripts/units.mjs +105 -0
- package/dist/skills/ulw-research/scripts/units.test.ts +83 -0
- package/dist/skills/visual-qa/SKILL.md +70 -63
- package/dist/skills/visual-qa/scripts/skill-doc-fields.test.ts +34 -0
- package/dist/tools/delegate-task/constants.d.ts +1 -1
- package/dist/tools/session-manager/constants.d.ts +1 -1
- package/dist/tools/session-manager/file-storage.d.ts +9 -2
- package/dist/tools/session-manager/sdk-storage.d.ts +19 -1
- package/dist/tools/session-manager/session-formatter.d.ts +3 -3
- package/dist/tools/session-manager/storage.d.ts +8 -2
- package/dist/tools/skill/mcp-capability-formatter.d.ts +1 -1
- package/dist/tools/skill/native-skills.d.ts +2 -2
- package/dist/tools/skill/skill-mcp-authority.d.ts +3 -0
- package/dist/tui.js +535 -100
- package/docs/reference/web-terminal-visual-qa.md +8 -0
- package/package.json +24 -16
- package/packages/lsp-core/src/lsp/client-wrapper.ts +4 -4
- package/packages/lsp-core/src/post-edit/not-installed.test.ts +2 -2
- package/packages/lsp-daemon/dist/cli.js +4 -4
- package/packages/lsp-daemon/dist/client.js +4 -4
- package/packages/lsp-daemon/dist/index.js +4 -4
- package/packages/lsp-daemon/package.json +3 -3
- package/packages/lsp-tools-mcp/dist/cli.js +4 -4
- package/packages/lsp-tools-mcp/dist/mcp.js +4 -4
- package/packages/lsp-tools-mcp/dist/tools.js +4 -4
- package/packages/lsp-tools-mcp/package.json +3 -3
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +62 -21
- 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/bootstrap/src/hook.ts +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/biome.json +1 -21
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +4 -4
- 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/biome.json +1 -21
- 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 +4 -4
- package/packages/omo-codex/plugin/components/lsp/biome.json +1 -21
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +4 -4
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +4 -4
- package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.mjs +0 -1
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-not-installed.test.ts +1 -1
- package/packages/omo-codex/plugin/components/rules/biome.json +1 -21
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +4 -4
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/biome.json +1 -21
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +90 -1
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +91 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +4 -4
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/biome.json +1 -21
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/biome.json +1 -21
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/directive.md +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 +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/biome.json +1 -21
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +7 -7
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-mutations.mjs +2 -0
- 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 +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +7 -7
- package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +2 -0
- package/packages/omo-codex/plugin/skills/browser/SKILL.md +21 -22
- package/packages/omo-codex/plugin/skills/browser/references/commands.md +2 -9
- package/packages/omo-codex/plugin/skills/browser/references/install.md +1 -2
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/plugin/skills/browser/scripts/browser-doctor.mjs +2 -2
- package/packages/omo-codex/plugin/skills/browser/scripts/browser-engine-guard.mjs +63 -487
- package/packages/omo-codex/plugin/skills/browser/scripts/browser-install.mjs +1 -1
- package/packages/omo-codex/plugin/skills/browser/scripts/omowright.mjs +1 -10
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +79 -118
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +75 -224
- package/packages/omo-codex/plugin/skills/frontend/references/design/stylegallery.md +32 -27
- package/packages/omo-codex/plugin/skills/frontend/references/perfection/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/check-accent-stripes.ts +8 -24
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/check-draft-guard.ts +40 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/collect-files.ts +53 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/draft-guard/findings.ts +16 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/draft-guard/lint.ts +38 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/draft-guard/rules.ts +69 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/draft-guard/text-nodes.ts +121 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/attr-lookalikes.tsx +10 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/bound-values.tsx +12 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/const-generics.tsx +3 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/generics.tsx +7 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/measured-stats.html +6 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/plain-copy.html +9 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/state-copy.html +11 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/attribute-edges.html +7 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/components.tsx +16 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/decorative-badge.vue +7 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/emoji-icons.tsx +9 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/jsx-edges.tsx +1 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/promo-copy.html +6 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/promo-copy.tsx +8 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/vanity-stats.html +5 -0
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +10 -7
- package/packages/omo-codex/plugin/skills/programming/references/typescript/README.md +10 -7
- package/packages/omo-codex/plugin/skills/programming/references/typescript/bootstrap.md +9 -23
- package/packages/omo-codex/plugin/skills/programming/references/typescript/oxc-lint.md +130 -0
- package/packages/omo-codex/plugin/skills/programming/references/typescript/tsconfig-strict.md +6 -62
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +12 -12
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/new-project.ts +20 -81
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/.oxfmtrc.json +9 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/.oxlintrc.json +46 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/LICENSE +21 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/index.js +10 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/no-em-dash-copy.js +28 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/require-suppression-reason.js +62 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/tsconfig.json +29 -0
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +14 -14
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +9 -3
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +7 -6
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +116 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +51 -3
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/claims-index.mjs +125 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +68 -3
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +136 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-schema.mjs +204 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger.mjs +103 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-brief.mjs +145 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-state.mjs +63 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-structure.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-text.mjs +1 -27
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/lexicon.mjs +47 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +226 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +2 -3
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/particles-ko.mjs +108 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/rational.mjs +139 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/sentence-split.mjs +77 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/text-normalize.mjs +82 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/text-similarity.mjs +28 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +105 -0
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +71 -64
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +4 -1
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +6 -6
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +152 -23
- package/packages/shared-skills/skills/browser/SKILL.md +21 -22
- package/packages/shared-skills/skills/browser/references/commands.md +2 -9
- package/packages/shared-skills/skills/browser/references/install.md +1 -2
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/shared-skills/skills/browser/scripts/browser-doctor.mjs +2 -2
- package/packages/shared-skills/skills/browser/scripts/browser-engine-guard.mjs +63 -487
- package/packages/shared-skills/skills/browser/scripts/browser-install.mjs +1 -1
- package/packages/shared-skills/skills/browser/scripts/omowright.mjs +1 -10
- package/packages/shared-skills/skills/frontend/SKILL.md +79 -118
- package/packages/shared-skills/skills/frontend/references/design/README.md +75 -224
- package/packages/shared-skills/skills/frontend/references/design/stylegallery.md +32 -27
- package/packages/shared-skills/skills/frontend/references/perfection/README.md +2 -2
- package/packages/shared-skills/skills/frontend/scripts/perfection/check-accent-stripes.ts +8 -24
- package/packages/shared-skills/skills/frontend/scripts/perfection/check-draft-guard.test.ts +101 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/check-draft-guard.ts +40 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/collect-files.test.ts +50 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/collect-files.ts +53 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/draft-guard/findings.ts +16 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/draft-guard/lint.ts +38 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/draft-guard/rules.ts +69 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/draft-guard/text-nodes.ts +121 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/attr-lookalikes.tsx +10 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/bound-values.tsx +12 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/const-generics.tsx +3 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/generics.tsx +7 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/measured-stats.html +6 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/plain-copy.html +9 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/state-copy.html +11 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/attribute-edges.html +7 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/components.tsx +16 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/decorative-badge.vue +7 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/emoji-icons.tsx +9 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/jsx-edges.tsx +1 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/promo-copy.html +6 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/promo-copy.tsx +8 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/vanity-stats.html +5 -0
- package/packages/shared-skills/skills/programming/SKILL.md +10 -7
- package/packages/shared-skills/skills/programming/references/typescript/README.md +10 -7
- package/packages/shared-skills/skills/programming/references/typescript/bootstrap.md +9 -23
- package/packages/shared-skills/skills/programming/references/typescript/oxc-lint.md +130 -0
- package/packages/shared-skills/skills/programming/references/typescript/tsconfig-strict.md +6 -62
- package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.ts +12 -12
- package/packages/shared-skills/skills/programming/scripts/typescript/new-project.test.ts +162 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/new-project.ts +20 -81
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/.oxfmtrc.json +9 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/.oxlintrc.json +46 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/LICENSE +21 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/index.js +10 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/no-em-dash-copy.js +28 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/require-suppression-reason.js +62 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/tsconfig.json +29 -0
- package/packages/shared-skills/skills/refactor/SKILL.md +13 -13
- package/packages/shared-skills/skills/ulw-execute/SKILL.md +1 -1
- package/packages/shared-skills/skills/ulw-research/AGENTS.md +9 -3
- package/packages/shared-skills/skills/ulw-research/SKILL.md +2 -2
- package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +7 -6
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +116 -0
- package/packages/shared-skills/skills/ulw-research/references/report-gates.md +51 -3
- package/packages/shared-skills/skills/ulw-research/scripts/claims-index.mjs +125 -0
- package/packages/shared-skills/skills/ulw-research/scripts/claims-index.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +68 -3
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +97 -12
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-grammar.test.ts +190 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +136 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +141 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-schema.mjs +204 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-schema.test.ts +43 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger.mjs +103 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger.test.ts +252 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-brief.mjs +145 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-brief.test.ts +179 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-state.mjs +63 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-state.test.ts +46 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-context.test.ts +64 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/gates-structure.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/gates-text.mjs +1 -27
- package/packages/shared-skills/skills/ulw-research/scripts/lexicon.mjs +47 -0
- package/packages/shared-skills/skills/ulw-research/scripts/lexicon.test.ts +57 -0
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +226 -0
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +120 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +2 -3
- package/packages/shared-skills/skills/ulw-research/scripts/outcome.test.ts +29 -0
- package/packages/shared-skills/skills/ulw-research/scripts/particles-ko.mjs +108 -0
- package/packages/shared-skills/skills/ulw-research/scripts/particles-ko.test.ts +86 -0
- package/packages/shared-skills/skills/ulw-research/scripts/rational.mjs +139 -0
- package/packages/shared-skills/skills/ulw-research/scripts/rational.test.ts +46 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +2 -2
- package/packages/shared-skills/skills/ulw-research/scripts/sentence-split.mjs +77 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sentence-split.test.ts +109 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/claim-graph.md +13 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity-brief-locked.md +17 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity-brief-pending.md +17 -0
- package/packages/shared-skills/skills/ulw-research/scripts/text-normalize.mjs +82 -0
- package/packages/shared-skills/skills/ulw-research/scripts/text-normalize.test.ts +73 -0
- package/packages/shared-skills/skills/ulw-research/scripts/text-similarity.mjs +28 -0
- package/packages/shared-skills/skills/ulw-research/scripts/text-similarity.test.ts +38 -0
- package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +105 -0
- package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +83 -0
- package/packages/shared-skills/skills/visual-qa/SKILL.md +70 -63
- package/packages/shared-skills/skills/visual-qa/scripts/skill-doc-fields.test.ts +34 -0
- package/script/qa/web-terminal-visual-qa.mjs +6 -2
- package/script/qa/xterm-live-terminal.mjs +26 -3
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// text-normalize.mjs - text normalization and raw-offset matching for fidelity checks.
|
|
2
|
+
//
|
|
3
|
+
// normalizeText applies NFC, maps curly and CJK quote glyphs to straight quotes, collapses
|
|
4
|
+
// whitespace runs to one space, and trims. findNormalized matches a needle against the
|
|
5
|
+
// normalized haystack and returns offsets into the RAW haystack through an offset map built
|
|
6
|
+
// during normalization. Plain Node ESM, no dependencies.
|
|
7
|
+
|
|
8
|
+
const DOUBLE_QUOTES = new Set([
|
|
9
|
+
"\u201C", "\u201D", "\u201E", "\u201F", "\u00AB", "\u00BB", "\u300C", "\u300D", "\u300E", "\u300F",
|
|
10
|
+
"\u301D", "\u301E", "\u301F", "\uFF02", "\u2033",
|
|
11
|
+
])
|
|
12
|
+
const SINGLE_QUOTES = new Set(["\u2018", "\u2019", "\u201A", "\u201B", "\u2039", "\u203A", "\uFF07", "\u2032"])
|
|
13
|
+
// Combining marks and conjoining Hangul medial/final jamo attach to the preceding code point,
|
|
14
|
+
// so a decomposed syllable is normalized as one unit.
|
|
15
|
+
const JOINS_PREVIOUS = /^[\p{M}\u1160-\u11FF\uD7B0-\uD7FF]$/u
|
|
16
|
+
const WHITESPACE = /^\s+$/u
|
|
17
|
+
const TOKEN_SEPARATOR = /[^\p{L}\p{N}\p{M}]+/u
|
|
18
|
+
|
|
19
|
+
function mapQuote(ch) {
|
|
20
|
+
if (DOUBLE_QUOTES.has(ch)) return '"'
|
|
21
|
+
if (SINGLE_QUOTES.has(ch)) return "'"
|
|
22
|
+
return ch
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function clusters(raw) {
|
|
26
|
+
const out = []
|
|
27
|
+
let at = 0
|
|
28
|
+
for (const ch of raw) {
|
|
29
|
+
const last = out[out.length - 1]
|
|
30
|
+
if (last && JOINS_PREVIOUS.test(ch)) last[1] += ch.length
|
|
31
|
+
else out.push([at, at + ch.length])
|
|
32
|
+
at += ch.length
|
|
33
|
+
}
|
|
34
|
+
return out
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Returns { text, starts, ends }: text[k] came from raw.slice(starts[k], ends[k]).
|
|
38
|
+
function normalizeWithMap(raw) {
|
|
39
|
+
const source = String(raw ?? "")
|
|
40
|
+
let text = ""
|
|
41
|
+
const starts = []
|
|
42
|
+
const ends = []
|
|
43
|
+
for (const [start, end] of clusters(source)) {
|
|
44
|
+
const piece = Array.from(source.slice(start, end).normalize("NFC"), mapQuote).join("")
|
|
45
|
+
if (WHITESPACE.test(piece)) {
|
|
46
|
+
if (text !== "" && !text.endsWith(" ")) {
|
|
47
|
+
text += " "
|
|
48
|
+
starts.push(start)
|
|
49
|
+
ends.push(end)
|
|
50
|
+
}
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
for (let k = 0; k < piece.length; k++) {
|
|
54
|
+
starts.push(start)
|
|
55
|
+
ends.push(end)
|
|
56
|
+
}
|
|
57
|
+
text += piece
|
|
58
|
+
}
|
|
59
|
+
if (text.endsWith(" ")) {
|
|
60
|
+
text = text.slice(0, -1)
|
|
61
|
+
starts.pop()
|
|
62
|
+
ends.pop()
|
|
63
|
+
}
|
|
64
|
+
return { text, starts, ends }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function normalizeText(s) {
|
|
68
|
+
return normalizeWithMap(s).text
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function tokenize(s) {
|
|
72
|
+
return normalizeText(s).split(TOKEN_SEPARATOR).filter((token) => token !== "")
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function findNormalized(hay, needle) {
|
|
76
|
+
const target = normalizeText(needle)
|
|
77
|
+
if (target === "") return null
|
|
78
|
+
const map = normalizeWithMap(hay)
|
|
79
|
+
const at = map.text.indexOf(target)
|
|
80
|
+
if (at === -1) return null
|
|
81
|
+
return { start: map.starts[at], end: map.ends[at + target.length - 1] }
|
|
82
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test"
|
|
2
|
+
|
|
3
|
+
import { findNormalized, normalizeText, tokenize } from "./text-normalize.mjs"
|
|
4
|
+
|
|
5
|
+
describe("normalizeText", () => {
|
|
6
|
+
test("#given NFD and NFC Korean #when normalized #then both are equal NFC strings", () => {
|
|
7
|
+
// given
|
|
8
|
+
const nfc = "매출은 한국어로 적었다"
|
|
9
|
+
const nfd = nfc.normalize("NFD")
|
|
10
|
+
// when
|
|
11
|
+
const a = normalizeText(nfd)
|
|
12
|
+
const b = normalizeText(nfc)
|
|
13
|
+
// then
|
|
14
|
+
expect(nfd).not.toBe(nfc)
|
|
15
|
+
expect(a).toBe(b)
|
|
16
|
+
expect(a).toBe(nfc)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test("#given curly and CJK quote glyphs #when normalized #then they become straight quotes", () => {
|
|
20
|
+
// given
|
|
21
|
+
const raw = "\u201Cgrowth\u201D \u2018ok\u2019 \u300Cquoted\u300D \u300Etitle\u300F \u00ABfr\u00BB"
|
|
22
|
+
// when
|
|
23
|
+
const out = normalizeText(raw)
|
|
24
|
+
// then
|
|
25
|
+
expect(out).toBe("\"growth\" 'ok' \"quoted\" \"title\" \"fr\"")
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test("#given runs of mixed whitespace #when normalized #then they collapse to single spaces and are trimmed", () => {
|
|
29
|
+
// when
|
|
30
|
+
const out = normalizeText(" a \t\n b\u00A0\u00A0c ")
|
|
31
|
+
// then
|
|
32
|
+
expect(out).toBe("a b c")
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe("tokenize", () => {
|
|
37
|
+
test("#given Latin words and Hangul eojeol with punctuation #when tokenized #then tokens split on whitespace and punctuation", () => {
|
|
38
|
+
// when
|
|
39
|
+
const tokens = tokenize("Revenue rose, 매출은 100억 원이다. (\u201Cok\u201D)")
|
|
40
|
+
// then
|
|
41
|
+
expect(tokens).toEqual(["Revenue", "rose", "매출은", "100억", "원이다", "ok"])
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe("findNormalized", () => {
|
|
46
|
+
test("#given raw text with double spaces and curly quotes #when a straight-quoted needle is found #then RAW offsets slice back to the raw substring", () => {
|
|
47
|
+
// given
|
|
48
|
+
const hay = "He said \u201Cgrowth is\n strong\u201D today."
|
|
49
|
+
// when
|
|
50
|
+
const hit = findNormalized(hay, "\"growth is strong\"")
|
|
51
|
+
// then
|
|
52
|
+
if (hit === null) throw new Error("needle not found")
|
|
53
|
+
expect(hay.slice(hit.start, hit.end)).toBe("\u201Cgrowth is\n strong\u201D")
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test("#given NFD Korean raw text with double spaces #when an NFC needle is found #then RAW offsets slice the NFD substring", () => {
|
|
57
|
+
// given
|
|
58
|
+
const rawNfc = "앞 문장. 매출은 100억 원이다. 끝"
|
|
59
|
+
const hay = rawNfc.normalize("NFD")
|
|
60
|
+
const expected = "매출은 100억 원이다".normalize("NFD")
|
|
61
|
+
// when
|
|
62
|
+
const hit = findNormalized(hay, "매출은 100억 원이다")
|
|
63
|
+
// then
|
|
64
|
+
if (hit === null) throw new Error("needle not found")
|
|
65
|
+
expect(hay.slice(hit.start, hit.end)).toBe(expected)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test("#given a needle absent from the text #when searched #then null is returned", () => {
|
|
69
|
+
// when / then
|
|
70
|
+
expect(findNormalized("abc", "zzz")).toBeNull()
|
|
71
|
+
expect(findNormalized("abc", " ")).toBeNull()
|
|
72
|
+
})
|
|
73
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// text-similarity.mjs - similarity in [0, 1] from normalized Levenshtein distance.
|
|
2
|
+
//
|
|
3
|
+
// Both inputs go through normalizeText first (NFC, quote glyphs, whitespace), then the
|
|
4
|
+
// edit distance is computed over code points and divided by the longer length.
|
|
5
|
+
// Plain Node ESM, no dependencies.
|
|
6
|
+
|
|
7
|
+
import { normalizeText } from "./text-normalize.mjs"
|
|
8
|
+
|
|
9
|
+
function levenshtein(a, b) {
|
|
10
|
+
let previous = Array.from({ length: b.length + 1 }, (_, k) => k)
|
|
11
|
+
for (let i = 1; i <= a.length; i++) {
|
|
12
|
+
const current = [i]
|
|
13
|
+
for (let k = 1; k <= b.length; k++) {
|
|
14
|
+
const cost = a[i - 1] === b[k - 1] ? 0 : 1
|
|
15
|
+
current.push(Math.min(previous[k] + 1, current[k - 1] + 1, previous[k - 1] + cost))
|
|
16
|
+
}
|
|
17
|
+
previous = current
|
|
18
|
+
}
|
|
19
|
+
return previous[b.length]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function similarity(a, b) {
|
|
23
|
+
const left = Array.from(normalizeText(a))
|
|
24
|
+
const right = Array.from(normalizeText(b))
|
|
25
|
+
const longest = Math.max(left.length, right.length)
|
|
26
|
+
if (longest === 0) return 1
|
|
27
|
+
return 1 - levenshtein(left, right) / longest
|
|
28
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test"
|
|
2
|
+
|
|
3
|
+
import { similarity } from "./text-similarity.mjs"
|
|
4
|
+
|
|
5
|
+
describe("similarity", () => {
|
|
6
|
+
test("#given identical strings #when compared #then similarity is exactly 1", () => {
|
|
7
|
+
// when / then
|
|
8
|
+
expect(similarity("a", "a")).toBe(1)
|
|
9
|
+
expect(similarity("", "")).toBe(1)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test("#given an OCR-noisy copy of a sentence #when compared #then similarity is at least 0.95", () => {
|
|
13
|
+
// given
|
|
14
|
+
const clean = "The company reported revenue of 100 billion won in the third quarter of 2025."
|
|
15
|
+
const noisy = "The cornpany reported revenue of 100 bi1lion won in the third quarter of 2025. "
|
|
16
|
+
// when
|
|
17
|
+
const score = similarity(clean, noisy)
|
|
18
|
+
// then
|
|
19
|
+
expect(score).toBeGreaterThanOrEqual(0.95)
|
|
20
|
+
expect(score).toBeLessThan(1)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test("#given NFD vs NFC and curly vs straight quotes #when compared #then normalization makes them equal", () => {
|
|
24
|
+
// when / then
|
|
25
|
+
expect(similarity("\u201C매출은 늘었다\u201D".normalize("NFD"), "\"매출은 늘었다\"")).toBe(1)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test("#given a different sentence #when compared #then similarity is below 0.8", () => {
|
|
29
|
+
// given
|
|
30
|
+
const a = "The company reported revenue of 100 billion won in the third quarter of 2025."
|
|
31
|
+
const b = "Analysts expect margins to shrink next year as input costs keep rising."
|
|
32
|
+
// when
|
|
33
|
+
const score = similarity(a, b)
|
|
34
|
+
// then
|
|
35
|
+
expect(score).toBeLessThan(0.8)
|
|
36
|
+
expect(score).toBeGreaterThanOrEqual(0)
|
|
37
|
+
})
|
|
38
|
+
})
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// units.mjs - unit table: normalization, dimensions, exact conversion factors, Korean readings.
|
|
2
|
+
//
|
|
3
|
+
// normalizeUnit maps a raw unit (any spacing or spelling variant) to one canonical token. Each token
|
|
4
|
+
// has a dimension, an exact factor to the dimension's base unit (base = value * factor + offset), and
|
|
5
|
+
// the final-sound class of its Korean reading for the particle rule: "open" (no final consonant),
|
|
6
|
+
// "l" (final rieul), or "closed". Currency is its own dimension per currency, so no exchange rate is
|
|
7
|
+
// ever implied. Data units are decimal (1 KB = 1000 B). Plain Node ESM, sibling imports only.
|
|
8
|
+
|
|
9
|
+
import { div, fromDecimal, sub } from "./rational.mjs"
|
|
10
|
+
|
|
11
|
+
/** [token, dimension, factor, reading, aliases, offset?]; the Korean reading is noted per row. */
|
|
12
|
+
const TABLE = [
|
|
13
|
+
["mm", "length", "0.001", "open", ["millimeter", "millimeters", "\uBC00\uB9AC\uBBF8\uD130"]], // millimiteo
|
|
14
|
+
["cm", "length", "0.01", "open", ["centimeter", "centimeters", "\uC13C\uD2F0\uBBF8\uD130"]], // sentimiteo
|
|
15
|
+
["m", "length", "1", "open", ["meter", "meters", "metre", "metres", "\uBBF8\uD130"]], // miteo
|
|
16
|
+
["km", "length", "1000", "open", ["kilometer", "kilometers", "\uD0AC\uB85C\uBBF8\uD130"]], // killomiteo
|
|
17
|
+
["g", "mass", "1", "closed", ["gram", "grams", "\uADF8\uB7A8"]], // geuraem
|
|
18
|
+
["kg", "mass", "1000", "closed", ["kilogram", "kilograms", "\uD0AC\uB85C\uADF8\uB7A8"]], // killogeuraem
|
|
19
|
+
["t", "mass", "1000000", "closed", ["ton", "tons", "tonne", "tonnes", "\uD1A4"]], // ton
|
|
20
|
+
["ms", "time", "0.001", "open", ["millisecond", "milliseconds", "\uBC00\uB9AC\uCD08"]], // millicho
|
|
21
|
+
["s", "time", "1", "open", ["sec", "secs", "second", "seconds", "\uCD08"]], // cho
|
|
22
|
+
["min", "time", "60", "closed", ["mins", "minute", "minutes", "\uBD84"]], // bun
|
|
23
|
+
["h", "time", "3600", "closed", ["hr", "hrs", "hour", "hours", "\uC2DC\uAC04"]], // sigan
|
|
24
|
+
["B", "data", "1", "open", ["byte", "bytes", "\uBC14\uC774\uD2B8"]], // baiteu
|
|
25
|
+
["KB", "data", "1000", "open", ["\uD0AC\uB85C\uBC14\uC774\uD2B8"]],
|
|
26
|
+
["MB", "data", "1000000", "open", ["\uBA54\uAC00\uBC14\uC774\uD2B8"]],
|
|
27
|
+
["GB", "data", "1000000000", "open", ["\uAE30\uAC00\uBC14\uC774\uD2B8"]],
|
|
28
|
+
["TB", "data", "1000000000000", "open", ["\uD14C\uB77C\uBC14\uC774\uD2B8"]],
|
|
29
|
+
["C", "temperature", "1", "open", ["\u00B0C", "\u2103", "celsius", "\uC12D\uC528"], "0"], // do
|
|
30
|
+
["F", "temperature", "5/9", "open", ["\u00B0F", "\u2109", "fahrenheit", "\uD654\uC528"], "-160/9"], // do
|
|
31
|
+
["%", "percent", "1", "open", ["percent", "\uD37C\uC13C\uD2B8", "\uD504\uB85C"]], // peosenteu
|
|
32
|
+
["\u2030", "percent", "0.1", "l", ["permille", "\uD37C\uBC00"]], // peomil
|
|
33
|
+
["%p", "percentage-point", "1", "open", ["pp", "%pt", "percentage point", "percentage points", "\uD37C\uC13C\uD2B8\uD3EC\uC778\uD2B8", "%\uD3EC\uC778\uD2B8"]],
|
|
34
|
+
["x", "multiple", "1", "open", ["\u00D7", "times", "\uBC30"]], // bae
|
|
35
|
+
["e3", "scale", "1000", "closed", ["k", "thousand", "\uCC9C"]], // cheon
|
|
36
|
+
["e4", "scale", "10000", "closed", ["\uB9CC"]], // man
|
|
37
|
+
["e6", "scale", "1000000", "closed", ["M", "million", "\uBC31\uB9CC"]], // baengman
|
|
38
|
+
["e8", "scale", "100000000", "closed", ["\uC5B5"]], // eok
|
|
39
|
+
["e9", "scale", "1000000000", "closed", ["bn", "billion", "\uC2ED\uC5B5"]], // sibeok
|
|
40
|
+
["e12", "scale", "1000000000000", "open", ["trillion", "\uC870"]], // jo
|
|
41
|
+
["person", "count:person", "1", "closed", ["persons", "people", "\uBA85"]], // myeong
|
|
42
|
+
["case", "count:case", "1", "closed", ["cases", "\uAC74"]], // geon
|
|
43
|
+
["KRW", "currency:KRW", "1", "closed", ["\uC6D0", "\u20A9", "won"]], // won
|
|
44
|
+
["KRW-e3", "currency:KRW", "1000", "closed", ["\uCC9C\uC6D0"]],
|
|
45
|
+
["KRW-e4", "currency:KRW", "10000", "closed", ["\uB9CC\uC6D0"]],
|
|
46
|
+
["KRW-e8", "currency:KRW", "100000000", "closed", ["\uC5B5\uC6D0"]],
|
|
47
|
+
["KRW-e12", "currency:KRW", "1000000000000", "closed", ["\uC870\uC6D0"]],
|
|
48
|
+
["USD", "currency:USD", "1", "open", ["$", "US$", "dollar", "dollars", "\uB2EC\uB7EC"]], // dalleo
|
|
49
|
+
["EUR", "currency:EUR", "1", "open", ["\u20AC", "euro", "euros", "\uC720\uB85C"]], // yuro
|
|
50
|
+
["JPY", "currency:JPY", "1", "closed", ["\u00A5", "yen", "\uC5D4"]], // en
|
|
51
|
+
["GBP", "currency:GBP", "1", "open", ["\u00A3", "pound", "pounds", "\uD30C\uC6B4\uB4DC"]], // paundeu
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
const parse = (text) => (text.includes("/") ? div(fromDecimal(text.split("/")[0]), fromDecimal(text.split("/")[1])) : fromDecimal(text))
|
|
55
|
+
const squash = (raw) => raw.replace(/\s+/g, "")
|
|
56
|
+
|
|
57
|
+
const ENTRIES = new Map()
|
|
58
|
+
/** Exact-case keys: every token and alias with whitespace removed. */
|
|
59
|
+
const EXACT = new Map()
|
|
60
|
+
/** Case-insensitive keys: multi-letter ASCII aliases only, so m/M and B/b never collide. */
|
|
61
|
+
const WORD = new Map()
|
|
62
|
+
for (const [token, dimension, factor, reading, aliases, offset] of TABLE) {
|
|
63
|
+
const entry = Object.freeze({ token, dimension, factor: parse(factor), offset: parse(offset ?? "0"), reading })
|
|
64
|
+
ENTRIES.set(token, entry)
|
|
65
|
+
for (const alias of [token, ...aliases]) {
|
|
66
|
+
const key = squash(alias)
|
|
67
|
+
EXACT.set(key, entry)
|
|
68
|
+
if (key.length > 1 && /^[A-Za-z]+$/.test(key) && !WORD.has(key.toLowerCase())) WORD.set(key.toLowerCase(), entry)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function entryOf(raw) {
|
|
73
|
+
if (typeof raw !== "string") return null
|
|
74
|
+
const key = squash(raw)
|
|
75
|
+
if (!key) return null
|
|
76
|
+
return EXACT.get(key) ?? WORD.get(key.toLowerCase()) ?? null
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Canonical token for a raw unit, or null when the unit is not in the table. */
|
|
80
|
+
export function normalizeUnit(raw) {
|
|
81
|
+
return entryOf(raw)?.token ?? null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Dimension of a unit ("length", "currency:KRW", ...), or null. */
|
|
85
|
+
export function dimensionOf(token) {
|
|
86
|
+
return entryOf(token)?.dimension ?? null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Exact factor from one unit to another of the same dimension: to = from * num / den (+ offset for
|
|
91
|
+
* affine scales). Null across dimensions, across currencies, or for an unknown unit.
|
|
92
|
+
*/
|
|
93
|
+
export function convertFactor(from, to) {
|
|
94
|
+
const a = entryOf(from)
|
|
95
|
+
const b = entryOf(to)
|
|
96
|
+
if (!a || !b || a.dimension !== b.dimension) return null
|
|
97
|
+
const { num, den } = div(a.factor, b.factor)
|
|
98
|
+
const offset = div(sub(a.offset, b.offset), b.factor)
|
|
99
|
+
return offset.num === 0n ? { num, den } : { num, den, offset: { num: offset.num, den: offset.den } }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Final-sound class of the unit's Korean reading: "open", "closed", or "l"; null when unknown. */
|
|
103
|
+
export function koreanReadingOf(token) {
|
|
104
|
+
return entryOf(token)?.reading ?? null
|
|
105
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test"
|
|
2
|
+
|
|
3
|
+
import { convertFactor, dimensionOf, koreanReadingOf, normalizeUnit } from "./units.mjs"
|
|
4
|
+
|
|
5
|
+
describe("normalizeUnit", () => {
|
|
6
|
+
test("ignores whitespace and spelling variants", () => {
|
|
7
|
+
expect(normalizeUnit("억 원")).toBe(normalizeUnit("억원"))
|
|
8
|
+
expect(normalizeUnit("억원")).not.toBeNull()
|
|
9
|
+
expect(normalizeUnit("million")).toBe(normalizeUnit("M"))
|
|
10
|
+
expect(normalizeUnit("USD")).toBe(normalizeUnit("$"))
|
|
11
|
+
expect(normalizeUnit("달러")).toBe(normalizeUnit("USD"))
|
|
12
|
+
expect(normalizeUnit("%")).not.toBe(normalizeUnit("%p"))
|
|
13
|
+
expect(normalizeUnit("m")).not.toBe(normalizeUnit("M"))
|
|
14
|
+
expect(normalizeUnit("furlongs")).toBeNull()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test("a normalized token normalizes to itself", () => {
|
|
18
|
+
for (const raw of ["억 원", "m", "kg", "GB", "%p", "USD", "C", "F"]) {
|
|
19
|
+
const token = normalizeUnit(raw)
|
|
20
|
+
expect(normalizeUnit(token as string)).toBe(token)
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe("dimensionOf and convertFactor", () => {
|
|
26
|
+
test("length, mass, time and data convert exactly", () => {
|
|
27
|
+
expect(convertFactor("m", "mm")).toEqual({ num: 1000n, den: 1n })
|
|
28
|
+
expect(convertFactor("mm", "m")).toEqual({ num: 1n, den: 1000n })
|
|
29
|
+
expect(convertFactor("km", "cm")).toEqual({ num: 100000n, den: 1n })
|
|
30
|
+
expect(convertFactor("kg", "t")).toEqual({ num: 1n, den: 1000n })
|
|
31
|
+
expect(convertFactor("h", "s")).toEqual({ num: 3600n, den: 1n })
|
|
32
|
+
expect(convertFactor("GB", "MB")).toEqual({ num: 1000n, den: 1n })
|
|
33
|
+
expect(dimensionOf(normalizeUnit("cm") as string)).toBe("length")
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test("the Korean currency scales convert within one currency", () => {
|
|
37
|
+
expect(convertFactor("억 원", "원")).toEqual({ num: 100000000n, den: 1n })
|
|
38
|
+
expect(convertFactor("조원", "억원")).toEqual({ num: 10000n, den: 1n })
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test("currency is never converted across currencies, and dimensions never mix", () => {
|
|
42
|
+
expect(convertFactor("USD", "KRW")).toBeNull()
|
|
43
|
+
expect(convertFactor("m", "kg")).toBeNull()
|
|
44
|
+
expect(convertFactor("%", "%p")).toBeNull()
|
|
45
|
+
expect(convertFactor("m", "furlongs")).toBeNull()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test("temperature is affine", () => {
|
|
49
|
+
expect(convertFactor("C", "F")).toEqual({ num: 9n, den: 5n, offset: { num: 32n, den: 1n } })
|
|
50
|
+
expect(convertFactor("F", "C")).toEqual({ num: 5n, den: 9n, offset: { num: -160n, den: 9n } })
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
describe("koreanReadingOf", () => {
|
|
55
|
+
const cases: Array<[string, string]> = [
|
|
56
|
+
["%", "open"],
|
|
57
|
+
["%p", "open"],
|
|
58
|
+
["m", "open"],
|
|
59
|
+
["km", "open"],
|
|
60
|
+
["원", "closed"],
|
|
61
|
+
["달러", "open"],
|
|
62
|
+
["유로", "open"],
|
|
63
|
+
["엔", "closed"],
|
|
64
|
+
["배", "open"],
|
|
65
|
+
["건", "closed"],
|
|
66
|
+
["명", "closed"],
|
|
67
|
+
["조", "open"],
|
|
68
|
+
["억", "closed"],
|
|
69
|
+
["만", "closed"],
|
|
70
|
+
["천", "closed"],
|
|
71
|
+
["kg", "closed"],
|
|
72
|
+
["GB", "open"],
|
|
73
|
+
]
|
|
74
|
+
for (const [raw, reading] of cases) {
|
|
75
|
+
test(`${raw} reads ${reading}`, () => {
|
|
76
|
+
expect(koreanReadingOf(raw)).toBe(reading)
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
test("unknown units have no reading", () => {
|
|
81
|
+
expect(koreanReadingOf("furlongs")).toBeNull()
|
|
82
|
+
})
|
|
83
|
+
})
|