lazycodex-ai 5.1.44 → 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/docs/reference/web-terminal-visual-qa.md +8 -0
- package/package.json +1 -1
- 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,40 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// The draft guard in one command: accent stripes plus generated-look copy and markup (promo copy, emoji icons, hype badges, vanity stats).
|
|
3
|
+
// Usage: bun check-draft-guard.ts [--json] <file-or-dir>... Exit 0 clean, 1 findings, 2 usage or unreadable target.
|
|
4
|
+
import { readFileSync } from "node:fs"
|
|
5
|
+
import { RULE_MESSAGES } from "./accent-stripes/findings"
|
|
6
|
+
import { lintFiles, type SourceFile } from "./accent-stripes/lint"
|
|
7
|
+
import { collectFiles } from "./collect-files"
|
|
8
|
+
import { DRAFT_RULE_MESSAGES } from "./draft-guard/findings"
|
|
9
|
+
import { lintDraft } from "./draft-guard/lint"
|
|
10
|
+
|
|
11
|
+
const MESSAGES: Readonly<Record<string, string>> = { ...RULE_MESSAGES, ...DRAFT_RULE_MESSAGES }
|
|
12
|
+
|
|
13
|
+
function main(argv: readonly string[]): number {
|
|
14
|
+
const json = argv.includes("--json")
|
|
15
|
+
const targets = argv.filter((a) => a !== "--json")
|
|
16
|
+
if (targets.length === 0) {
|
|
17
|
+
process.stderr.write("usage: check-draft-guard.ts [--json] <file-or-dir>...\n")
|
|
18
|
+
return 2
|
|
19
|
+
}
|
|
20
|
+
const { paths, missing } = collectFiles(targets)
|
|
21
|
+
if (missing.length > 0) {
|
|
22
|
+
process.stderr.write(`check-draft-guard: cannot read ${missing.join(", ")}\n`)
|
|
23
|
+
return 2
|
|
24
|
+
}
|
|
25
|
+
const files: SourceFile[] = paths.map((path) => ({ path, text: readFileSync(path, "utf8") }))
|
|
26
|
+
const findings = [...lintFiles(files), ...lintDraft(files)].sort(
|
|
27
|
+
(a, b) => a.file.localeCompare(b.file) || a.line - b.line || a.column - b.column,
|
|
28
|
+
)
|
|
29
|
+
if (json) process.stdout.write(`${JSON.stringify(findings, null, 2)}\n`)
|
|
30
|
+
else {
|
|
31
|
+
for (const f of findings) {
|
|
32
|
+
process.stdout.write(`${f.file}:${f.line}:${f.column} ${f.rule} ${MESSAGES[f.rule]}\n > ${f.excerpt}\n`)
|
|
33
|
+
}
|
|
34
|
+
const summary = findings.length === 0 ? "clean" : `${findings.length} finding(s); fix each before visual QA`
|
|
35
|
+
process.stdout.write(`check-draft-guard: ${paths.length} file(s), ${summary}\n`)
|
|
36
|
+
}
|
|
37
|
+
return findings.length === 0 ? 0 : 1
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
process.exitCode = main(process.argv.slice(2))
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { readdirSync, statSync, type Stats } from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
|
|
4
|
+
const SCANNED = /\.(?:css|scss|less|pcss|postcss|html?|[cm]?[jt]sx?|vue|svelte|astro)$/i
|
|
5
|
+
const SKIPPED_DIRS = new Set([
|
|
6
|
+
"node_modules", ".git", "dist", "build", "out", ".next", ".nuxt", ".svelte-kit", ".astro",
|
|
7
|
+
".turbo", ".cache", "coverage", "vendor", ".vercel", ".output",
|
|
8
|
+
])
|
|
9
|
+
const MAX_BYTES = 1_000_000
|
|
10
|
+
|
|
11
|
+
function statOrNull(path: string): Stats | null {
|
|
12
|
+
try {
|
|
13
|
+
return statSync(path)
|
|
14
|
+
} catch {
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function entriesOrNull(path: string): string[] | null {
|
|
20
|
+
try {
|
|
21
|
+
return readdirSync(path)
|
|
22
|
+
} catch {
|
|
23
|
+
return null
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Lintable source files under the targets; dangling links and unreadable entries are skipped, an unreadable explicit target is reported. */
|
|
28
|
+
export function collectFiles(targets: readonly string[]): { readonly paths: string[]; readonly missing: string[] } {
|
|
29
|
+
const paths: string[] = []
|
|
30
|
+
const missing: string[] = []
|
|
31
|
+
const walk = (path: string, explicit: boolean): void => {
|
|
32
|
+
const stat = statOrNull(path)
|
|
33
|
+
if (!stat) {
|
|
34
|
+
if (explicit) missing.push(path)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
if (stat.isDirectory()) {
|
|
38
|
+
const entries = entriesOrNull(path)
|
|
39
|
+
if (entries === null) {
|
|
40
|
+
if (explicit) missing.push(path)
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
if (!SKIPPED_DIRS.has(entry)) walk(join(path, entry), false)
|
|
45
|
+
}
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
const minified = /\.min\.[a-z]+$/i.test(path) || path.endsWith(".d.ts")
|
|
49
|
+
if (SCANNED.test(path) && !minified && stat.size <= MAX_BYTES) paths.push(path)
|
|
50
|
+
}
|
|
51
|
+
for (const target of targets) walk(target, true)
|
|
52
|
+
return { paths, missing }
|
|
53
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type DraftRuleId = "promo-copy" | "emoji-icon" | "decorative-badge" | "vanity-stat"
|
|
2
|
+
|
|
3
|
+
export type DraftFinding = {
|
|
4
|
+
readonly file: string
|
|
5
|
+
readonly line: number
|
|
6
|
+
readonly column: number
|
|
7
|
+
readonly rule: DraftRuleId
|
|
8
|
+
readonly excerpt: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const DRAFT_RULE_MESSAGES: Readonly<Record<DraftRuleId, string>> = {
|
|
12
|
+
"promo-copy": "promotional filler in visible copy; say what the screen does or shows instead",
|
|
13
|
+
"emoji-icon": "emoji used as an icon or bullet; use an SVG icon from the project's icon set, or nothing",
|
|
14
|
+
"decorative-badge": "badge or chip carrying a hype label instead of a state; remove it or show a real status",
|
|
15
|
+
"vanity-stat": "stat tile with a marketing-form number (10x, 500+, 24/7); show the measured figure with its unit and period, or remove the tile",
|
|
16
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { lineLocator } from "../accent-stripes/findings"
|
|
2
|
+
import type { SourceFile } from "../accent-stripes/lint"
|
|
3
|
+
import type { DraftFinding } from "./findings"
|
|
4
|
+
import { checkNode } from "./rules"
|
|
5
|
+
import { type MarkupKind, textNodes } from "./text-nodes"
|
|
6
|
+
|
|
7
|
+
function markupKind(path: string): MarkupKind | null {
|
|
8
|
+
if (/\.html?$/i.test(path)) return "html"
|
|
9
|
+
if (/\.[cm]?[jt]sx$/i.test(path)) return "jsx"
|
|
10
|
+
if (/\.(?:vue|svelte|astro)$/i.test(path)) return "sfc"
|
|
11
|
+
return null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function excerptAt(text: string, offset: number): string {
|
|
15
|
+
const lineStart = text.lastIndexOf("\n", offset - 1) + 1
|
|
16
|
+
const lineEnd = text.indexOf("\n", offset)
|
|
17
|
+
return text.slice(lineStart, lineEnd < 0 ? undefined : lineEnd).trim().slice(0, 140)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function lintDraft(files: readonly SourceFile[]): DraftFinding[] {
|
|
21
|
+
const findings: DraftFinding[] = []
|
|
22
|
+
for (const file of files) {
|
|
23
|
+
const kind = markupKind(file.path)
|
|
24
|
+
if (kind === null) continue
|
|
25
|
+
const locate = lineLocator(file.text)
|
|
26
|
+
const seen = new Set<string>()
|
|
27
|
+
for (const node of textNodes(file.text, kind)) {
|
|
28
|
+
for (const hit of checkNode(node)) {
|
|
29
|
+
const at = locate(hit.offset)
|
|
30
|
+
const key = `${hit.offset}:${hit.rule}`
|
|
31
|
+
if (seen.has(key)) continue
|
|
32
|
+
seen.add(key)
|
|
33
|
+
findings.push({ file: file.path, ...at, rule: hit.rule, excerpt: excerptAt(file.text, hit.offset) })
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return findings.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line || a.column - b.column)
|
|
38
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { DraftRuleId } from "./findings"
|
|
2
|
+
import { type Element, isStatElement, type TextNode } from "./text-nodes"
|
|
3
|
+
|
|
4
|
+
export type RuleHit = { readonly rule: DraftRuleId; readonly offset: number }
|
|
5
|
+
|
|
6
|
+
const PROMO_PHRASES = new RegExp(
|
|
7
|
+
[
|
|
8
|
+
String.raw`\bseamless(?:ly)?\b`,
|
|
9
|
+
String.raw`\beffortless(?:ly)?\b`,
|
|
10
|
+
String.raw`\bsupercharge[sd]?\b`,
|
|
11
|
+
String.raw`\bunlock (?:the (?:full )?power|the full potential|your (?:full )?potential)\b`,
|
|
12
|
+
String.raw`\bat a glance\b`,
|
|
13
|
+
String.raw`\bcutting[- ]edge\b`,
|
|
14
|
+
String.raw`\bgame[- ]chang(?:er|ing)\b`,
|
|
15
|
+
String.raw`\brevolutioni[sz]e\b`,
|
|
16
|
+
String.raw`\bnext[- ]level\b`,
|
|
17
|
+
String.raw`\bworld[- ]class\b`,
|
|
18
|
+
String.raw`\belevate your\b`,
|
|
19
|
+
"한눈에",
|
|
20
|
+
"손쉽게",
|
|
21
|
+
"스마트한",
|
|
22
|
+
"혁신적인",
|
|
23
|
+
].join("|"),
|
|
24
|
+
"giu",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
const EMOJI = /\p{Emoji_Presentation}|\p{Extended_Pictographic}\uFE0F/u
|
|
28
|
+
const EMOJI_ALL = /\p{Emoji_Presentation}|\p{Extended_Pictographic}\uFE0F?/gu
|
|
29
|
+
const NUMERIC_ENTITY = /&#(?:x([0-9a-f]+)|(\d+));/gi
|
|
30
|
+
const BADGE_CLASS = /^(?:badge|chip|pill|tag)(?:$|[-_])/
|
|
31
|
+
const BADGE_COMPONENT = /^(?:Badge|Chip|Pill|Tag)$/
|
|
32
|
+
const HYPE_LABEL = /^(?:new!?|hot|trending|popular|featured|ai|ai[- ]powered|premium|recommended|best|신규|인기|추천|베스트)$/i
|
|
33
|
+
const AMOUNT = String.raw`(?:\d{1,3}(?:[.,]\d{3})+|\d+)(?:[.,]\d+)?`
|
|
34
|
+
const MARKETING_NUMBER = new RegExp(String.raw`^(?:[$€£¥₩]?${AMOUNT}\s*(?:[kmb]|%)?\s*\+|${AMOUNT}\s*[x×]|24\/7)$`, "i")
|
|
35
|
+
|
|
36
|
+
const isBadge = (element: Element | undefined): boolean =>
|
|
37
|
+
element !== undefined && !element.stateful && (BADGE_COMPONENT.test(element.name) || element.classes.some((c) => BADGE_CLASS.test(c)))
|
|
38
|
+
|
|
39
|
+
function leadingOffset(node: TextNode): number {
|
|
40
|
+
return node.offset + (node.text.length - node.text.trimStart().length)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function emojiOffset(text: string): number | null {
|
|
44
|
+
const direct = EMOJI.exec(text)
|
|
45
|
+
if (direct) return direct.index
|
|
46
|
+
for (const m of text.matchAll(NUMERIC_ENTITY)) {
|
|
47
|
+
const code = m[1] === undefined ? Number(m[2]) : Number.parseInt(m[1], 16)
|
|
48
|
+
if (Number.isInteger(code) && code <= 0x10ffff && EMOJI.test(String.fromCodePoint(code))) return m.index ?? 0
|
|
49
|
+
}
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** A stat is a vanity number only in marketing form (10x, 500+, $2M+, 24/7); a measured figure such as 42% or 1.2k passes. */
|
|
54
|
+
export function checkNode(node: TextNode): RuleHit[] {
|
|
55
|
+
const hits: RuleHit[] = []
|
|
56
|
+
const label = node.text.trim()
|
|
57
|
+
if (node.kind !== "value") {
|
|
58
|
+
for (const m of node.text.matchAll(PROMO_PHRASES)) hits.push({ rule: "promo-copy", offset: node.offset + (m.index ?? 0) })
|
|
59
|
+
const emoji = emojiOffset(node.text)
|
|
60
|
+
if (emoji !== null) hits.push({ rule: "emoji-icon", offset: node.offset + emoji })
|
|
61
|
+
}
|
|
62
|
+
if (node.kind === "text" && isBadge(node.stack.at(-1)) && HYPE_LABEL.test(label.replace(EMOJI_ALL, "").trim())) {
|
|
63
|
+
hits.push({ rule: "decorative-badge", offset: leadingOffset(node) })
|
|
64
|
+
}
|
|
65
|
+
if (node.kind !== "label" && node.stack.some(isStatElement) && MARKETING_NUMBER.test(label)) {
|
|
66
|
+
hits.push({ rule: "vanity-stat", offset: leadingOffset(node) })
|
|
67
|
+
}
|
|
68
|
+
return hits
|
|
69
|
+
}
|
package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/draft-guard/text-nodes.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export type Element = {
|
|
2
|
+
readonly tag: string
|
|
3
|
+
readonly name: string
|
|
4
|
+
readonly classes: readonly string[]
|
|
5
|
+
readonly stateful: boolean
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** `text` is visible copy, `label` an announced attribute (aria-label, title, alt, placeholder), `value` a stat component's value prop. */
|
|
9
|
+
export type NodeKind = "text" | "label" | "value"
|
|
10
|
+
export type TextNode = { readonly kind: NodeKind; readonly text: string; readonly offset: number; readonly stack: readonly Element[] }
|
|
11
|
+
|
|
12
|
+
export type MarkupKind = "html" | "jsx" | "sfc"
|
|
13
|
+
|
|
14
|
+
const NEVER_RENDERED = /<(script|style|pre|code|textarea|noscript)\b[^>]*>[\s\S]*?<\/\1\s*>|<!--[\s\S]*?-->|\{\/\*[\s\S]*?\*\/\}/gi
|
|
15
|
+
const HTML_TEMPLATE = /<template\b(?![^>]*\s(?:x-[\w-]+|v-[\w-]+|[:@#][\w.-]+))[^>]*>[\s\S]*?<\/template\s*>/gi
|
|
16
|
+
const TAG = /<(\/?)([A-Za-z][\w.:-]*)((?:[^>"'{}]|"[^"]*"|'[^']*'|\{(?:[^{}]|\{[^{}]*\})*\})*)>/g
|
|
17
|
+
const CLASS_ATTR = /\b(?:class|className)\s*=\s*(?:"([^"]*)"|'([^']*)'|\{((?:[^{}]|\{[^{}]*\})*)\})/
|
|
18
|
+
const STRING_LITERAL = /["'`]([^"'`]*)["'`]/g
|
|
19
|
+
const ANNOUNCED_NAME = /(?:^|\s)(?:aria-label|title|alt|placeholder)\s*=/g
|
|
20
|
+
const VALUE_NAME = /(?:^|\s)value\s*=/
|
|
21
|
+
const LITERAL_VALUE = /^\s*(?:"([^"]*)"|'([^']*)'|\{\s*["'`]([^"'`]*)["'`]\s*\})/
|
|
22
|
+
const HIDDEN_ATTR = /(?:^|\s)hidden(?=\s|=|\/|$)/
|
|
23
|
+
const STATE_ATTR = /(?:^|\s)(?:data-status|data-state|aria-(?:current|selected|pressed|checked|expanded|busy|invalid|disabled|valuenow))\s*=/
|
|
24
|
+
const ATTR_VALUES = /"[^"]*"|'[^']*'|\{(?:[^{}]|\{[^{}]*\})*\}/g
|
|
25
|
+
const STAT_COMPONENT = /^(?:Stats?|Metrics?|Kpis?|KPIs?)(?:[A-Z]\w*)?$/
|
|
26
|
+
const STAT_CLASS = /^(?:stat|stats|metric|metrics|kpi)(?:$|[-_])/
|
|
27
|
+
const VOID_TAGS = new Set(["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "source", "track", "wbr"])
|
|
28
|
+
const JSX_LEAD = new Set(["(", "[", "{", "}", ",", ":", "?", "=", ">", "&", "|", ";"])
|
|
29
|
+
|
|
30
|
+
function blank(text: string, pattern: RegExp): string {
|
|
31
|
+
return text.replace(pattern, (m) => m.replace(/[^\n]/g, " "))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function classesOf(attrs: string): string[] {
|
|
35
|
+
const m = CLASS_ATTR.exec(attrs)
|
|
36
|
+
if (!m) return []
|
|
37
|
+
const literal = m[1] ?? m[2]
|
|
38
|
+
const raw = literal ?? [...(m[3] ?? "").matchAll(STRING_LITERAL)].map((s) => s[1] ?? "").join(" ")
|
|
39
|
+
return raw.split(/\s+/).filter(Boolean)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function isStatElement(element: Element): boolean {
|
|
43
|
+
return STAT_COMPONENT.test(element.name) || element.classes.some((c) => STAT_CLASS.test(c))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function closeTo(stack: Element[], tag: string): void {
|
|
47
|
+
const at = stack.map((e) => e.tag).lastIndexOf(tag)
|
|
48
|
+
if (at >= 0) stack.length = at
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** In a script, `<` opens JSX only where an expression can start; `Array<string>`, `pick<T>(` and `a<b` stay code. */
|
|
52
|
+
function opensJsx(text: string, start: number, name: string, attrs: string): boolean {
|
|
53
|
+
if (/^\s*,|^\s+extends\b/.test(attrs)) return false
|
|
54
|
+
if (/^(?:const|in|out)$/.test(name) && /^\s+[A-Za-z_$]/.test(attrs)) return false
|
|
55
|
+
const before = text.slice(0, start).trimEnd()
|
|
56
|
+
if (before === "" || /\b(?:return|yield|default)$/.test(before)) return true
|
|
57
|
+
return JSX_LEAD.has(before.at(-1) ?? "")
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function literalAfter(attrs: string, from: number): { readonly value: string; readonly at: number } | null {
|
|
61
|
+
const m = LITERAL_VALUE.exec(attrs.slice(from))
|
|
62
|
+
if (!m) return null
|
|
63
|
+
const value = m[1] ?? m[2] ?? m[3] ?? ""
|
|
64
|
+
return { value, at: from + m[0].lastIndexOf(value) }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function keepLiterals(segment: string): string {
|
|
68
|
+
return segment.replace(/\{[^{}]*\}/g, (m) => {
|
|
69
|
+
const lit = /^\{\s*(["'`])([^"'`]*)\1\s*\}$/.exec(m)
|
|
70
|
+
if (!lit) return " ".repeat(m.length)
|
|
71
|
+
const inner = lit[2] ?? ""
|
|
72
|
+
const at = m.indexOf(lit[1] ?? "") + 1
|
|
73
|
+
return " ".repeat(at) + inner + " ".repeat(m.length - at - inner.length)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Copy a reader sees or hears, each piece with the elements open around it. Code, hidden elements and never-rendered blocks are skipped. */
|
|
78
|
+
export function textNodes(source: string, kind: MarkupKind): TextNode[] {
|
|
79
|
+
const text = kind === "html" ? blank(blank(source, NEVER_RENDERED), HTML_TEMPLATE) : blank(source, NEVER_RENDERED)
|
|
80
|
+
const nodes: TextNode[] = []
|
|
81
|
+
const stack: Element[] = []
|
|
82
|
+
let hiddenDepth = 0
|
|
83
|
+
let cursor = 0
|
|
84
|
+
const flush = (end: number) => {
|
|
85
|
+
if (stack.length === 0 || hiddenDepth > 0) return
|
|
86
|
+
const segment = keepLiterals(text.slice(cursor, end))
|
|
87
|
+
if (segment.trim()) nodes.push({ kind: "text", text: segment, offset: cursor, stack: [...stack] })
|
|
88
|
+
}
|
|
89
|
+
for (const m of text.matchAll(TAG)) {
|
|
90
|
+
const start = m.index ?? 0
|
|
91
|
+
const [whole, closing, rawName = "", attrs = ""] = m
|
|
92
|
+
const end = start + whole.length
|
|
93
|
+
if (kind === "jsx" && !closing && stack.length === 0 && !opensJsx(text, start, rawName, attrs)) continue
|
|
94
|
+
flush(start)
|
|
95
|
+
cursor = end
|
|
96
|
+
const tag = rawName.toLowerCase()
|
|
97
|
+
if (closing) {
|
|
98
|
+
const at = stack.map((e) => e.tag).lastIndexOf(tag)
|
|
99
|
+
if (at >= 0 && hiddenDepth > at) hiddenDepth = 0
|
|
100
|
+
closeTo(stack, tag)
|
|
101
|
+
continue
|
|
102
|
+
}
|
|
103
|
+
const names = attrs.replace(ATTR_VALUES, (v) => " ".repeat(v.length))
|
|
104
|
+
const element: Element = { tag, name: rawName, classes: classesOf(attrs), stateful: STATE_ATTR.test(names) }
|
|
105
|
+
const attrsAt = start + 1 + rawName.length
|
|
106
|
+
const hidden = hiddenDepth > 0 || HIDDEN_ATTR.test(names)
|
|
107
|
+
if (!hidden) {
|
|
108
|
+
for (const a of names.matchAll(ANNOUNCED_NAME)) {
|
|
109
|
+
const lit = literalAfter(attrs, (a.index ?? 0) + a[0].length)
|
|
110
|
+
if (lit?.value.trim()) nodes.push({ kind: "label", text: lit.value, offset: attrsAt + lit.at, stack: [...stack, element] })
|
|
111
|
+
}
|
|
112
|
+
const v = isStatElement(element) ? VALUE_NAME.exec(names) : null
|
|
113
|
+
const lit = v ? literalAfter(attrs, v.index + v[0].length) : null
|
|
114
|
+
if (lit?.value.trim()) nodes.push({ kind: "value", text: lit.value, offset: attrsAt + lit.at, stack: [...stack, element] })
|
|
115
|
+
}
|
|
116
|
+
if (VOID_TAGS.has(tag) || attrs.trimEnd().endsWith("/")) continue
|
|
117
|
+
stack.push(element)
|
|
118
|
+
if (hiddenDepth === 0 && HIDDEN_ATTR.test(names)) hiddenDepth = stack.length
|
|
119
|
+
}
|
|
120
|
+
return nodes
|
|
121
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function Bar() {
|
|
2
|
+
return (
|
|
3
|
+
<div data-title="Supercharge your team">
|
|
4
|
+
<StatusBar><span>24/7</span></StatusBar>
|
|
5
|
+
<span className="badge" aria-current="page">New</span>
|
|
6
|
+
<div data-x="a title='Supercharge your team'" />
|
|
7
|
+
<Stat data-value="10x" />
|
|
8
|
+
</div>
|
|
9
|
+
)
|
|
10
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function Summary({ count, status, uptime }: { count: number; status: string; uptime: string }) {
|
|
2
|
+
return (
|
|
3
|
+
<section>
|
|
4
|
+
<div className="stat"><span className="stat-value">{count}</span><span>open tickets</span></div>
|
|
5
|
+
<div className="metric">{uptime}</div>
|
|
6
|
+
<span className="badge" data-status={status}>{status}</span>
|
|
7
|
+
<span className="badge">3</span>
|
|
8
|
+
<span className="chip">Failed</span>
|
|
9
|
+
<p>Seams in the fabric are reinforced.</p>
|
|
10
|
+
</section>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const labels: Array<string> = ["Unlock the power", "🚀 launch"]
|
|
2
|
+
export const pick = <T,>(xs: T[]): T | undefined => xs[0]
|
|
3
|
+
export const first = <T extends object>(xs: T[]) => xs[0]
|
|
4
|
+
export const flag = (a: number, b: number) => (a<b && b>a ? "seamless sync" : "x")
|
|
5
|
+
export function Saved() {
|
|
6
|
+
return <p>Saved 3 files</p>
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<main>
|
|
2
|
+
<h1>Monthly revenue</h1>
|
|
3
|
+
<p>Revenue rose 4% after the refund fix shipped on 3 June.</p>
|
|
4
|
+
<pre><code>const seamless = "Supercharge"</code></pre>
|
|
5
|
+
<footer>© 2026 Example Inc. Next page →</footer>
|
|
6
|
+
<script>const label = "Unlock the power of your data 🚀"</script>
|
|
7
|
+
<style>.stat::after { content: "10x"; }</style>
|
|
8
|
+
<!-- 한눈에 보는 메모 -->
|
|
9
|
+
</main>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<main>
|
|
2
|
+
<p>Unlock your account to continue.</p>
|
|
3
|
+
<p>최적의 경로를 계산합니다.</p>
|
|
4
|
+
<p>Docs ↗</p>
|
|
5
|
+
<p>▶ Play</p>
|
|
6
|
+
<li>Inbox <span class="badge" data-status="unread">New</span></li>
|
|
7
|
+
<span class="pill">Pro</span>
|
|
8
|
+
<div hidden>Seamless onboarding</div>
|
|
9
|
+
<noscript>Supercharge your browser</noscript>
|
|
10
|
+
<template><p>Unlock the power of templates</p></template>
|
|
11
|
+
</main>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<main>
|
|
2
|
+
<div class="block hidden md:flex"><p>Seamless sync</p></div>
|
|
3
|
+
<button title="Show hidden files"><span>Supercharge your team</span></button>
|
|
4
|
+
<div class="stat"><span>1,000,000+</span></div>
|
|
5
|
+
<span class="badge" aria-hidden="true">New</span>
|
|
6
|
+
<template x-if="open"><p>Effortless setup</p></template>
|
|
7
|
+
</main>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const cn = (...names: string[]) => names.join(" ")
|
|
2
|
+
export function Page() {
|
|
3
|
+
return (
|
|
4
|
+
<main>
|
|
5
|
+
<Badge>New</Badge>
|
|
6
|
+
<span className={cn("badge", "badge--hot")}>Hot</span>
|
|
7
|
+
<span className="badge">✨ New</span>
|
|
8
|
+
<p>Launch 🚀 today</p>
|
|
9
|
+
<button type="button" aria-label="🚀 Launch">Go</button>
|
|
10
|
+
<Stat value="10x" />
|
|
11
|
+
<StatCard><p>10x</p></StatCard>
|
|
12
|
+
<div className="metric">{"500+"}</div>
|
|
13
|
+
<input placeholder="Supercharge your search" />
|
|
14
|
+
</main>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const Beta = () => <p>(beta) Seamless sync</p>
|
|
@@ -22,7 +22,7 @@ Codex exposes ONE of two subagent tool surfaces per session; check your own tool
|
|
|
22
22
|
|
|
23
23
|
When translating `load_skills=[...]`, include the requested skill names in the spawned agent's `message`. If a code block below conflicts with this section, this section wins.
|
|
24
24
|
|
|
25
|
-
Omit optional keys you do not set. Never send `items: []`, `message: ""`, `model: ""`, `reasoning_effort: ""`, or `service_tier: ""
|
|
25
|
+
Omit optional keys you do not set. Never send `items: []`, `message: ""`, `model: ""`, `reasoning_effort: ""`, or `service_tier: ""`. Codex rejects them (`Items can't be empty`, `reasoning_effort must not be empty`).
|
|
26
26
|
|
|
27
27
|
For work likely to exceed one wait cycle, require the child to send `WORKING: <task> - <current phase>` before long passes and `BLOCKED: <reason>` only when progress stops. A `multi_agent_v1.wait_agent` timeout only means no new mailbox update arrived; back off between waits (double the timeout up to ~5 minutes) instead of spinning short cycles. Treat a running child as alive. Fallback only when the child is completed without the deliverable, ack-only after followup, explicitly `BLOCKED:`, or no longer running.
|
|
28
28
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: programming
|
|
3
|
-
description: "Applies strict, modern language practice (typed errors, exhaustive match, tests that can fail) for Python, Rust, TypeScript, and Go. Use for work on .py, .rs, .ts, or .go files."
|
|
3
|
+
description: "Applies strict, modern language practice (typed errors, exhaustive match, tests that can fail) for Python, Rust, TypeScript, JavaScript, and Go. Use for work on .py, .rs, .ts, .js, or .go files."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Programming
|
|
@@ -22,7 +22,7 @@ This skill is an index. The hard per-language rules live under `references/`. Lo
|
|
|
22
22
|
|---|---|
|
|
23
23
|
| `.py`, `.pyi`, "Python" | `references/python/README.md` + every file under `references/python/` that the README tells you to load on demand |
|
|
24
24
|
| `.rs`, `Cargo.toml`, "Rust" | `references/rust/README.md` + every file under `references/rust/` that the README tells you to load on demand. **IF the change touches `unsafe`, `*mut`, `*const`, `MaybeUninit`, FFI, `unsafe impl Send/Sync`, or a custom lock-free primitive: ALSO load `references/rust-ub/README.md` plus every file under `references/rust-ub/`.** |
|
|
25
|
-
| `.ts`, `.tsx`, `.mts`, `.cts`, "TypeScript" | `references/typescript/README.md` + every file under `references/typescript/` that the README tells you to load on demand |
|
|
25
|
+
| `.ts`, `.tsx`, `.mts`, `.cts`, `.js`, `.jsx`, `.mjs`, `.cjs`, "TypeScript" / "JavaScript" | `references/typescript/README.md` + every file under `references/typescript/` that the README tells you to load on demand |
|
|
26
26
|
| `.go`, `go.mod`, `go.sum`, `.golangci.yml`, `*.proto` next to a Go module, "Go" / "Golang" | `references/go/README.md` + every file under `references/go/` that the README tells you to load on demand |
|
|
27
27
|
|
|
28
28
|
3. Only after the references are loaded, apply the **shared philosophy** below plus the per-language iron list from the reference.
|
|
@@ -176,12 +176,14 @@ A bare default constructor for any of these (no timeouts, no pool tuning, no sch
|
|
|
176
176
|
|---|---|---|---|---|
|
|
177
177
|
| Package / project manager | **uv** (NEVER pip/poetry/conda) | **cargo** + `cargo-nextest` + `cargo-machete` + `cargo-deny` | **Bun** (runtime + package manager); pnpm if Node is forced | **`go modules`** + `go work` for monorepos |
|
|
178
178
|
| Type checker | **basedpyright** with `typeCheckingMode = "all"` | the Rust compiler with `-D warnings` + clippy `pedantic` + `nursery` + `cargo` groups | `tsc --noEmit` (or `tsgo` when available) with `strict` + `noUncheckedIndexedAccess` + `exactOptionalPropertyTypes` + `verbatimModuleSyntax` | the Go compiler + **`golangci-lint v2`** with the strict bundle + **`nilaway`** (nil-deref static analysis) |
|
|
179
|
-
| Linter + formatter | **ruff** with `select = ["ALL"]` | `clippy` + `rustfmt` | **
|
|
179
|
+
| Linter + formatter | **ruff** with `select = ["ALL"]` | `clippy` + `rustfmt` | **oxlint + oxfmt**, with the local copy and suppression-reason rules | **`gofumpt`** (stricter gofmt) + `goimports -local` + `golangci-lint v2` |
|
|
180
180
|
| Test runner | **pytest** | **cargo-nextest** | `bun test` / `vitest` | stdlib `go test -race -shuffle=on -count=1` + `goleak` |
|
|
181
181
|
| UB / soundness gate | (n/a) | **nightly miri** with strict provenance + Tree Borrows pass | (n/a) | **`nilaway`** + `-race` detector + `goleak` are the equivalent gate |
|
|
182
182
|
| Disposable scripts | **PEP 723** inline metadata + `uv run script.py` | **rust-script** with inline `Cargo.toml` block | `bun run script.ts` | `//go:build ignore` + `go run script.go` |
|
|
183
183
|
| Bootstrap a new project | `scripts/python/new-project.py` | `scripts/rust/new-project.py` | `scripts/typescript/new-project.ts` | `scripts/go/new-project.py` |
|
|
184
|
-
| Pre-commit / CI gate | `ruff check . && basedpyright && pytest` | `cargo clippy --all-targets -- -D warnings && cargo nextest run && cargo test --doc && cargo +nightly miri nextest run` | `bunx
|
|
184
|
+
| Pre-commit / CI gate | `ruff check . && basedpyright && pytest` | `cargo clippy --all-targets -- -D warnings && cargo nextest run && cargo test --doc && cargo +nightly miri nextest run` | `bunx oxlint --type-aware --deny-warnings && bunx oxfmt --check && bunx tsc --noEmit && bun test` | `gofumpt -l . && golangci-lint run ./... && nilaway ./... && go test -race -shuffle=on -count=1 ./...` |
|
|
185
|
+
|
|
186
|
+
For TS/JS, **use oxlint + oxfmt with these two rules by default**: `no-em-dash-copy` and `require-suppression-reason`. Strongly prefer this OXC toolchain for new projects; retain ESLint, Prettier, or Biome only when the repository already uses them. Load [`references/typescript/oxc-lint.md`](references/typescript/oxc-lint.md) for the complete configs, plugin, and type-aware support requirements. Rewrite paired em dashes as asides using parentheses or commas, not colon chains.
|
|
185
187
|
|
|
186
188
|
A `tsconfig.json` with `"strict": true` alone is **not** strict. The reference enumerates the additional flags. Same for `pyproject.toml` and `Cargo.toml` - the references contain the canonical full configuration.
|
|
187
189
|
|
|
@@ -348,13 +350,14 @@ These two skills are not optional cosmetics. They are the recovery path for the
|
|
|
348
350
|
| Canonical library defaults | `references/rust/libraries.md` |
|
|
349
351
|
| **ANY `unsafe` / FFI / `MaybeUninit` / lock-free work** | **`references/rust-ub/` (full directory)** |
|
|
350
352
|
|
|
351
|
-
### TypeScript (`.ts`, `.tsx`, `.mts`, `.cts`)
|
|
353
|
+
### TypeScript / JavaScript (`.ts`, `.tsx`, `.mts`, `.cts`, `.js`, `.jsx`, `.mjs`, `.cjs`)
|
|
352
354
|
|
|
353
355
|
**READ `references/typescript/README.md` FIRST.** Then load on demand:
|
|
354
356
|
|
|
355
357
|
| Need | Load |
|
|
356
358
|
|---|---|
|
|
357
|
-
| Strict tsconfig
|
|
359
|
+
| Strict tsconfig | `references/typescript/tsconfig-strict.md` |
|
|
360
|
+
| Default oxlint + oxfmt configs and copy rules | `references/typescript/oxc-lint.md` |
|
|
358
361
|
| Type patterns (branded types, `as const`, `satisfies`, narrowing, `assertNever`) | `references/typescript/type-patterns.md` |
|
|
359
362
|
| Data modeling (type vs interface vs Zod, readonly, parse-don't-validate) | `references/typescript/data-modeling.md` |
|
|
360
363
|
| Error handling (Result, typed errors, union vs throw, AbortSignal timeouts) | `references/typescript/error-handling.md` |
|
|
@@ -386,6 +389,6 @@ These two skills are not optional cosmetics. They are the recovery path for the
|
|
|
386
389
|
|
|
387
390
|
## Activation
|
|
388
391
|
|
|
389
|
-
This skill activates whenever you are writing or modifying any `.py`, `.pyi`, `.rs`, `.ts`, `.tsx`, `.mts`, `.cts`, `.go` file, or any project manifest (`pyproject.toml`, `Cargo.toml`, `package.json`, `tsconfig.json`,
|
|
392
|
+
This skill activates whenever you are writing or modifying any `.py`, `.pyi`, `.rs`, `.ts`, `.tsx`, `.mts`, `.cts`, `.js`, `.jsx`, `.mjs`, `.cjs`, `.go` file, or any project manifest (`pyproject.toml`, `Cargo.toml`, `package.json`, `tsconfig.json`, `.oxlintrc.json`, `.oxfmtrc.json`, `go.mod`, `go.sum`, `.golangci.yml`, `Taskfile.yml`, `buf.yaml`, `sqlc.yaml`). **Even one-off scripts get the full treatment** - that is the whole point of `uv run` + PEP 723, `rust-script`, `bun run`, and `go run` + `//go:build ignore`: production hygiene with throwaway ergonomics.
|
|
390
393
|
|
|
391
394
|
The references contain the recipes. **Read them before writing code. Re-read them when the model drifts.** The post-write review loop is non-negotiable.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
# TypeScript Programmer
|
|
2
|
+
# TypeScript / JavaScript Programmer
|
|
3
3
|
|
|
4
4
|
Modern TypeScript. Type-strict, stack-first, async-correct.
|
|
5
5
|
|
|
@@ -17,7 +17,7 @@ These are deliberate project choices. Violations are always wrong, not "style pr
|
|
|
17
17
|
|---|---|---|
|
|
18
18
|
| Runtime | Bun (native TS, single binary) | ts-node, tsx |
|
|
19
19
|
| Package manager | `pnpm` | npm, yarn (unless workspace requires it) |
|
|
20
|
-
| Linter + formatter |
|
|
20
|
+
| Linter + formatter | **oxlint + oxfmt**, with both local copy rules | New ESLint, Prettier, or Biome setups; retain them only in repositories already using them |
|
|
21
21
|
| Type checker | `tsc --noEmit` with strict config | skip type checking |
|
|
22
22
|
| Web framework | Hono | Express |
|
|
23
23
|
| Validation | Zod | joi, yup, class-validator |
|
|
@@ -125,7 +125,9 @@ bun run ../../scripts/typescript/new-project.ts my-api
|
|
|
125
125
|
bun run ../../scripts/typescript/new-project.ts my-api --path ./projects
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
Creates: `package.json` (Hono + Zod +
|
|
128
|
+
Creates: `package.json` (Hono + Zod + oxlint + oxfmt + oxlint-tsgolint), strict `tsconfig.json`, `.oxlintrc.json`, `.oxfmtrc.json`, `lint/oxlint-plugin/` including its MIT license, `src/index.ts`, and `.gitignore`. Works on macOS, Linux, Windows.
|
|
129
|
+
|
|
130
|
+
**Use oxlint + oxfmt with `no-em-dash-copy` and `require-suppression-reason` by default for TS and JS.** Load [oxc-lint.md](oxc-lint.md) for the complete setup. Use `--type-aware` with its installed companion where supported; keep `tsc --noEmit` as the type gate. Rewrite paired em dashes as parenthetical or comma-delimited asides, not colon chains.
|
|
129
131
|
|
|
130
132
|
For manual setup: `bunx tsc --init`, then load `tsconfig-strict.md` for the full strict config.
|
|
131
133
|
|
|
@@ -145,7 +147,8 @@ Load on demand — not all at once.
|
|
|
145
147
|
|
|
146
148
|
| Need | Load |
|
|
147
149
|
|---|---|
|
|
148
|
-
| Strict tsconfig
|
|
150
|
+
| Strict tsconfig | `tsconfig-strict.md` |
|
|
151
|
+
| Default oxlint + oxfmt configs, rule mappings, and local JS plugin | `oxc-lint.md` |
|
|
149
152
|
| Type patterns (branded, as const, satisfies, narrowing, assertNever) | `type-patterns.md` |
|
|
150
153
|
| Data modeling (type vs interface vs Zod, readonly, parse-don't-validate) | `data-modeling.md` |
|
|
151
154
|
| Error handling (Result, typed errors, union vs throw) | `error-handling.md` |
|
|
@@ -171,11 +174,11 @@ Violations caught by `../../scripts/typescript/check-no-excuse-rules.ts`. Run af
|
|
|
171
174
|
| `empty-catch` | `catch { }` or `catch (e) { }` with empty body | `// no-excuse-ok: catch` |
|
|
172
175
|
| `catch-without-narrowing` | `catch (e)` used without `instanceof` or re-throw | `// no-excuse-ok: catch` |
|
|
173
176
|
|
|
174
|
-
|
|
177
|
+
Oxlint enforces explicit-any, non-null-assertion, default-export, and type-only-import rules; see [the verified mapping](oxc-lint.md). The audit script retains the checks not covered by those rules, including assertion and enum bans and catch narrowing.
|
|
175
178
|
|
|
176
179
|
## In tests
|
|
177
180
|
|
|
178
|
-
Tests are strict too, with these exceptions (configure in
|
|
181
|
+
Tests are strict too, with these exceptions (configure in `.oxlintrc.json` overrides):
|
|
179
182
|
|
|
180
183
|
| In tests you may | Why |
|
|
181
184
|
|---|---|
|
|
@@ -192,4 +195,4 @@ When editing an existing file that doesn't follow these rules: **write new code
|
|
|
192
195
|
|
|
193
196
|
## Activation
|
|
194
197
|
|
|
195
|
-
This
|
|
198
|
+
This reference applies to `.ts`, `.tsx`, `.mts`, `.cts`, `.js`, `.jsx`, `.mjs`, and `.cjs`. JavaScript uses the same lint, formatting, and copy rules; TypeScript-only syntax and compiler gates apply to TS or checked JS projects. Even one-off scripts get the strict treatment.
|