@chemx/starter-kit 26.10.8-344 → 26.10.10-75
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/AGENTS.md +135 -32
- package/README.md +253 -199
- package/blueprints/atoms/a-button.svelte +11 -9
- package/blueprints/atoms/a-button.vue +2 -1
- package/blueprints/molecule-capsule/m-chemx-badge/m-chemx-badge.svelte +8 -4
- package/blueprints/molecule-capsule/m-chemx-badge/m-chemx-badge.tsx +8 -4
- package/blueprints/molecule-capsule/m-chemx-badge/m-chemx-badge.vue +8 -4
- package/blueprints/molecule-capsule/m-sample-card.svelte +2 -1
- package/blueprints/molecule-capsule/m-sample-card.tsx +2 -1
- package/blueprints/molecule-capsule/m-sample-card.vue +4 -2
- package/blueprints/workflows/chemx-audit.yml +15 -46
- package/cli/agent-json.js +40 -0
- package/cli/apply-edits.js +195 -0
- package/cli/audit/ai-slop-detector.js +62 -35
- package/cli/audit/ast-passes.js +52 -0
- package/cli/audit/ast-visitors.js +142 -83
- package/cli/audit/audit-plain.js +26 -0
- package/cli/audit/audit-summary.js +16 -3
- package/cli/audit/autofix-content.js +122 -0
- package/cli/audit/autofix.js +74 -159
- package/cli/audit/budget-rules.js +84 -0
- package/cli/audit/catch-predicates.js +51 -0
- package/cli/audit/chemx-dir.js +76 -0
- package/cli/audit/clone-detector.js +4 -2
- package/cli/audit/comment-regions.js +83 -0
- package/cli/audit/coverage.js +48 -0
- package/cli/audit/csharp-analyzer.js +47 -22
- package/cli/audit/discussion-store.js +9 -4
- package/cli/audit/extended-text-patterns.js +104 -54
- package/cli/audit/extended-visitors.js +26 -12
- package/cli/audit/feed.d.ts +77 -0
- package/cli/audit/feed.js +146 -0
- package/cli/audit/gate-delta.js +91 -0
- package/cli/audit/gate-verdict.js +25 -3
- package/cli/audit/history.d.ts +14 -2
- package/cli/audit/history.js +89 -101
- package/cli/audit/hook-shape-validator.js +18 -9
- package/cli/audit/lexicon-predicates.js +125 -0
- package/cli/audit/lifecycle-predicates.js +106 -0
- package/cli/audit/line-budgets.js +154 -0
- package/cli/audit/metrics.js +56 -37
- package/cli/audit/mutable-ref-predicate.js +54 -0
- package/cli/audit/parseable-code.js +11 -0
- package/cli/audit/pattern-detector.js +56 -28
- package/cli/audit/project-figures.js +28 -0
- package/cli/audit/prompt-rule-lines.js +46 -0
- package/cli/audit/prompts.js +74 -46
- package/cli/audit/prop-surface.js +74 -0
- package/cli/audit/ratchet.js +112 -23
- package/cli/audit/render-depth.js +79 -0
- package/cli/audit/reporter-banner.js +7 -4
- package/cli/audit/reporter-grades.js +52 -34
- package/cli/audit/reporter-grouping.js +10 -5
- package/cli/audit/reporter-markdown.js +16 -8
- package/cli/audit/reporter-sections.js +31 -16
- package/cli/audit/reporter-summary.js +28 -16
- package/cli/audit/reporter-utils.js +54 -30
- package/cli/audit/roadmap.js +20 -15
- package/cli/audit/rule-overrides.js +78 -0
- package/cli/audit/rule-pillars.js +43 -0
- package/cli/audit/rule-revisions.js +42 -0
- package/cli/audit/rules-helpers.js +13 -63
- package/cli/audit/rules-predicates.d.ts +1 -0
- package/cli/audit/rules-predicates.js +84 -64
- package/cli/audit/rules-registry.js +94 -10
- package/cli/audit/rules.js +92 -171
- package/cli/audit/shallow-catch-csharp.js +49 -0
- package/cli/audit/shallow-catch-escalation.js +157 -0
- package/cli/audit/shallow-catch-reads.js +116 -0
- package/cli/audit/social-gh.js +18 -9
- package/cli/audit/social-git.js +82 -40
- package/cli/audit/social-http.js +17 -9
- package/cli/audit/social-publisher.js +14 -7
- package/cli/audit/social.js +39 -30
- package/cli/audit/staged-delta.js +67 -0
- package/cli/audit/status-file.js +67 -0
- package/cli/audit/structural-weight-evaluator.js +17 -29
- package/cli/audit/structural-weight.js +30 -13
- package/cli/audit/suppressions.js +130 -0
- package/cli/audit/template-rules.js +82 -0
- package/cli/audit/types.d.ts +24 -1
- package/cli/audit-engine.js +128 -0
- package/cli/audit-preflight-git.js +15 -1
- package/cli/audit-preflight.js +6 -4
- package/cli/audit-scan.js +180 -0
- package/cli/audit-scope.js +31 -14
- package/cli/audit.js +6 -201
- package/cli/babel-lazy.js +41 -0
- package/cli/badge.js +9 -6
- package/cli/banner.js +37 -0
- package/cli/build/child-registry.js +57 -0
- package/cli/build/executor.js +122 -48
- package/cli/build.js +75 -25
- package/cli/cli-args.js +107 -0
- package/cli/columnar.js +6 -3
- package/cli/commands/cmd-audit-each.js +164 -0
- package/cli/commands/cmd-audit-feed.js +78 -0
- package/cli/commands/cmd-audit.js +136 -57
- package/cli/commands/cmd-batch.js +60 -0
- package/cli/commands/cmd-check.js +74 -0
- package/cli/commands/cmd-project.js +18 -9
- package/cli/commands/cmd-router.js +148 -32
- package/cli/commands/cmd-show.js +56 -0
- package/cli/commands/cmd-staged-delta.js +27 -0
- package/cli/commands/cmd-wrappers-files.js +77 -0
- package/cli/commands/cmd-wrappers-git.js +122 -0
- package/cli/commands/cmd-wrappers-json.js +101 -0
- package/cli/commands/cmd-wrappers.js +7 -322
- package/cli/commands/unknown-flags.js +228 -0
- package/cli/commands-schema-badge.js +73 -0
- package/cli/commands-schema-commit.js +21 -0
- package/cli/commands-schema-edit.js +106 -0
- package/cli/commands-schema-host.js +65 -0
- package/cli/commands-schema-ops.js +127 -0
- package/cli/commands-schema-patterns.js +69 -0
- package/cli/commands-schema-report.js +18 -0
- package/cli/commands-schema-search.js +121 -0
- package/cli/commands-schema-setup.js +30 -0
- package/cli/commands-schema-verify.js +89 -0
- package/cli/commands-schema-wrappers.js +131 -0
- package/cli/commands-schema.js +26 -408
- package/cli/comment-ranges.js +108 -0
- package/cli/commit/commit-args.js +73 -0
- package/cli/commit/commit-cli.js +25 -0
- package/cli/commit/commit-facts.js +49 -0
- package/cli/commit/commit-git.js +98 -0
- package/cli/commit/commit-index.js +35 -0
- package/cli/commit/commit-message.js +52 -0
- package/cli/commit/commit-record.js +68 -0
- package/cli/commit/commit-run.js +160 -0
- package/cli/commit/commit-validate.js +62 -0
- package/cli/config/index.js +54 -8
- package/cli/config/loader.js +77 -8
- package/cli/config/profiles.js +7 -0
- package/cli/conflicts-cli.js +118 -0
- package/cli/conflicts.js +104 -0
- package/cli/create.js +11 -6
- package/cli/db-project-stamp.js +124 -0
- package/cli/docs-check/command-tree.js +27 -0
- package/cli/docs-check/extract.js +151 -0
- package/cli/docs-check/resolve.js +85 -0
- package/cli/docs-check/run.js +88 -0
- package/cli/doctor/check-env.js +43 -0
- package/cli/doctor/check-host.js +115 -0
- package/cli/doctor/check-index.js +93 -0
- package/cli/doctor/check-mcp.js +78 -0
- package/cli/doctor/doctor-cli.js +60 -0
- package/cli/doctor/kit-locate.js +40 -0
- package/cli/doctor/proc-scan.js +66 -0
- package/cli/edit-atomic.js +75 -0
- package/cli/edit-diff.js +98 -0
- package/cli/edit-guardrails.js +77 -0
- package/cli/edit-locks.js +128 -0
- package/cli/embeddings/vectorizer.js +9 -5
- package/cli/errors/catcher.js +45 -52
- package/cli/errors/formatter.js +14 -10
- package/cli/errors/policy.js +26 -0
- package/cli/errors/publisher.js +5 -1
- package/cli/errors/report-output.js +67 -0
- package/cli/errors/sanitizer.js +52 -3
- package/cli/errors/storage.js +17 -5
- package/cli/explode-importers.js +102 -0
- package/cli/explode-path-args.js +115 -0
- package/cli/explode-plan.js +153 -0
- package/cli/explode-prologue.js +43 -0
- package/cli/explode-relocate.js +73 -0
- package/cli/exploder.js +205 -193
- package/cli/forge/anchors.js +50 -0
- package/cli/forge/audit-forge.js +58 -0
- package/cli/forge/binding-walk.js +84 -0
- package/cli/forge/bindings.js +238 -0
- package/cli/forge/blueprint-cli.js +153 -0
- package/cli/forge/blueprint-context.js +69 -0
- package/cli/forge/blueprint-members.js +82 -0
- package/cli/forge/blueprint-store.js +106 -0
- package/cli/forge/blueprint-target.js +44 -0
- package/cli/forge/blueprint.js +276 -0
- package/cli/forge/body-end-cache.js +34 -0
- package/cli/forge/body-ends.js +86 -0
- package/cli/forge/canon-inline.js +342 -0
- package/cli/forge/canon-logic.js +106 -0
- package/cli/forge/canon-nodes.js +270 -0
- package/cli/forge/canon-print.js +120 -0
- package/cli/forge/canonicalize.js +49 -0
- package/cli/forge/conventions.js +51 -0
- package/cli/forge/drift.js +120 -0
- package/cli/forge/exclusions.js +21 -0
- package/cli/forge/exits.js +76 -0
- package/cli/forge/facets.js +86 -0
- package/cli/forge/file-units.js +53 -0
- package/cli/forge/fingerprint-file.js +52 -0
- package/cli/forge/fingerprint-session.js +215 -0
- package/cli/forge/fingerprint-sync.js +74 -0
- package/cli/forge/fingerprint-visitors.js +66 -0
- package/cli/forge/fixtures/heal/a7-dry-run.diff.txt +179 -0
- package/cli/forge/fixtures/heal/cli/commit/commit-facts.js.txt +49 -0
- package/cli/forge/fixtures/heal/cli/doctor/check-host.js.txt +117 -0
- package/cli/forge/fixtures/heal/cli/doctor/kit-locate.js.txt +42 -0
- package/cli/forge/fixtures/heal/cli/hooks/guard-paths.js.txt +80 -0
- package/cli/forge/fixtures/heal/cli/hooks/project-status.js.txt +62 -0
- package/cli/forge/fixtures/heal/cli/main.js.txt +169 -0
- package/cli/forge/fixtures/heal/cli/mcp/context.js.txt +81 -0
- package/cli/forge/fixtures/heal/cli/mcp/installer-report.js.txt +47 -0
- package/cli/forge/fixtures/heal/cli/path-scope.js.txt +169 -0
- package/cli/forge/fixtures/heal/cli/project-detector.js.txt +364 -0
- package/cli/forge/fixtures/heal/cli/project-markers.js.txt +42 -0
- package/cli/forge/fixtures/heal/cli/team/coordination-root.js.txt +161 -0
- package/cli/forge/fixtures/heal/cli/team/usage-reader.js.txt +109 -0
- package/cli/forge/fixtures/heal/cli/test-slots.js.txt +129 -0
- package/cli/forge/fixtures/social-gh.js.txt +131 -0
- package/cli/forge/fixtures/team-flags.js.txt +214 -0
- package/cli/forge/fold.js +199 -0
- package/cli/forge/forge-groups.js +200 -0
- package/cli/forge/forge-report.js +73 -0
- package/cli/forge/fuzz/binding-hook.js +36 -0
- package/cli/forge/fuzz/choices.js +40 -0
- package/cli/forge/fuzz/classes.js +41 -0
- package/cli/forge/fuzz/coverage.js +26 -0
- package/cli/forge/fuzz/gen-alias.js +61 -0
- package/cli/forge/fuzz/gen-control.js +73 -0
- package/cli/forge/fuzz/gen-kit.js +75 -0
- package/cli/forge/fuzz/gen-logic.js +77 -0
- package/cli/forge/fuzz/gen-mixed.js +204 -0
- package/cli/forge/fuzz/gen-modules.js +80 -0
- package/cli/forge/fuzz/gen-objects.js +92 -0
- package/cli/forge/fuzz/gen-scope.js +131 -0
- package/cli/forge/fuzz/gen-templates.js +87 -0
- package/cli/forge/fuzz/harness.js +314 -0
- package/cli/forge/fuzz/pair-check.js +115 -0
- package/cli/forge/fuzz/resolve.js +32 -0
- package/cli/forge/fuzz/run.js +121 -0
- package/cli/forge/fuzz/sandbox.js +108 -0
- package/cli/forge/fuzz/seeds.js +119 -0
- package/cli/forge/fuzz/slow-shard.js +60 -0
- package/cli/forge/fuzz/template-oracle.js +148 -0
- package/cli/forge/fuzz/transpile.js +61 -0
- package/cli/forge/gates.js +115 -0
- package/cli/forge/group-shape.js +137 -0
- package/cli/forge/group-store.js +160 -0
- package/cli/forge/group.js +280 -0
- package/cli/forge/gt-sandbox.js +83 -0
- package/cli/forge/gt-scaffold.js +110 -0
- package/cli/forge/hash-labels.js +117 -0
- package/cli/forge/hash.js +119 -0
- package/cli/forge/heal-apply.js +170 -0
- package/cli/forge/heal-cli.js +132 -0
- package/cli/forge/heal-leases.js +52 -0
- package/cli/forge/heal-locate.js +70 -0
- package/cli/forge/heal-match.js +208 -0
- package/cli/forge/heal-ops.js +197 -0
- package/cli/forge/heal-plan.js +143 -0
- package/cli/forge/heal-sandbox.js +126 -0
- package/cli/forge/heal-specs.js +80 -0
- package/cli/forge/heal-store.js +80 -0
- package/cli/forge/heal-text.js +60 -0
- package/cli/forge/heal-typecheck.js +108 -0
- package/cli/forge/heal-undo.js +74 -0
- package/cli/forge/heal-verify.js +148 -0
- package/cli/forge/hole-kinds.js +126 -0
- package/cli/forge/inline-mode.js +6 -0
- package/cli/forge/inline-on.setup.js +4 -0
- package/cli/forge/lgg-stage.js +125 -0
- package/cli/forge/lgg.js +197 -0
- package/cli/forge/library-match.js +74 -0
- package/cli/forge/murmur.js +86 -0
- package/cli/forge/naming.js +101 -0
- package/cli/forge/pattern-schema-ddl.js +157 -0
- package/cli/forge/placement.js +165 -0
- package/cli/forge/rank.js +174 -0
- package/cli/forge/refine.js +93 -0
- package/cli/forge/rejected-members.js +92 -0
- package/cli/forge/rejects.js +77 -0
- package/cli/forge/root-shapes.js +84 -0
- package/cli/forge/run-cache.js +145 -0
- package/cli/forge/sibling-blocks.js +41 -0
- package/cli/forge/siblings.js +140 -0
- package/cli/forge/store.js +180 -0
- package/cli/forge/template-normalize.js +209 -0
- package/cli/forge/template-roles.js +86 -0
- package/cli/forge/template-units.js +148 -0
- package/cli/forge/templates.js +42 -0
- package/cli/forge/unify-step.js +65 -0
- package/cli/forge/unit-floor.js +74 -0
- package/cli/forge/unit-hash.js +229 -0
- package/cli/forge/unit-trees.js +153 -0
- package/cli/forge/units.js +261 -0
- package/cli/forge/windows.js +129 -0
- package/cli/friction/friction-cli.js +71 -0
- package/cli/friction/friction-export.js +54 -0
- package/cli/friction/friction-log.js +54 -0
- package/cli/friction/usage-classify.js +56 -0
- package/cli/friction/usage-report.js +86 -0
- package/cli/friction/wrong-call.js +12 -0
- package/cli/fs-json.js +17 -0
- package/cli/generator-compact.js +55 -0
- package/cli/generator-help.js +16 -15
- package/cli/generator-indexer.js +2 -1
- package/cli/generator-jig-cli.js +11 -7
- package/cli/generator-jig.js +38 -33
- package/cli/generator-templates/archetypes/index.js +30 -13
- package/cli/generator-templates/archetypes/vector-matcher.js +8 -4
- package/cli/generator-templates/compact.js +4 -2
- package/cli/generator-templates/controller-converters.js +23 -14
- package/cli/generator-templates/controller.js +10 -5
- package/cli/generator-templates/hooks.js +4 -2
- package/cli/generator-templates/naming.js +2 -1
- package/cli/generator-templates/react.js +2 -1
- package/cli/generator-templates/specs.js +4 -2
- package/cli/generator-templates/svelte.js +4 -2
- package/cli/generator-templates/types.js +6 -3
- package/cli/generator-templates/views.js +4 -2
- package/cli/generator-templates/vue.js +4 -2
- package/cli/generator-writes.js +24 -0
- package/cli/generator.d.ts +1 -1
- package/cli/generator.js +86 -127
- package/cli/git-file-listing.js +69 -0
- package/cli/help-args.js +18 -0
- package/cli/help.d.ts +7 -3
- package/cli/help.js +94 -149
- package/cli/hooks/bypass-log.js +44 -0
- package/cli/hooks/claude-post-edit.js +79 -0
- package/cli/hooks/claude-pre-tool.js +178 -0
- package/cli/hooks/claude-settings-merge.js +101 -0
- package/cli/hooks/dispatch-identity.js +125 -0
- package/cli/hooks/entry.js +181 -0
- package/cli/hooks/foreign-identity.js +60 -0
- package/cli/hooks/guard-args.js +55 -0
- package/cli/hooks/guard-cases.js +94 -0
- package/cli/hooks/guard-config.js +43 -0
- package/cli/hooks/guard-invocation.js +106 -0
- package/cli/hooks/guard-paths.js +80 -0
- package/cli/hooks/guard-route.js +211 -0
- package/cli/hooks/guard-rules-nudge.js +37 -0
- package/cli/hooks/guard-rules-reads.js +66 -0
- package/cli/hooks/guard-rules-shell.js +239 -0
- package/cli/hooks/guard-rules.js +114 -0
- package/cli/hooks/hook-commands.js +21 -0
- package/cli/hooks/install-hooks-apply.js +36 -0
- package/cli/hooks/install-hooks-cli.js +100 -0
- package/cli/hooks/install-hooks-config.js +48 -0
- package/cli/hooks/install-hooks-pins.js +66 -0
- package/cli/hooks/install-hooks-plan.js +56 -0
- package/cli/hooks/install-hooks-status.js +7 -0
- package/cli/hooks/interpreter-writes.js +195 -0
- package/cli/hooks/launcher.js +60 -0
- package/cli/hooks/mcp-json-merge.js +39 -0
- package/cli/hooks/native-edit-lock.js +40 -0
- package/cli/hooks/native-tool-policy.js +152 -0
- package/cli/hooks/out-of-band-edits.js +141 -0
- package/cli/hooks/post-edit-scope.js +43 -0
- package/cli/hooks/project-status.js +59 -0
- package/cli/hooks/repo-membership.js +32 -0
- package/cli/hooks/run-hook.js +79 -0
- package/cli/hooks/session-identity.js +153 -0
- package/cli/hooks/session-start.js +50 -0
- package/cli/hooks/shell-lexer-readers.js +76 -0
- package/cli/hooks/shell-lexer-state.js +59 -0
- package/cli/hooks/shell-lexer.js +110 -0
- package/cli/hooks/shell-parse.js +232 -0
- package/cli/hooks/statusline.js +27 -0
- package/cli/hooks/xatoms-hints.js +38 -0
- package/cli/host-protocol.js +109 -0
- package/cli/host-shims.js +9 -8
- package/cli/index-admission.js +41 -0
- package/cli/index-freshness.js +83 -0
- package/cli/index-row-check.js +58 -0
- package/cli/index.js +52 -150
- package/cli/installer-templates.js +67 -75
- package/cli/installer.d.ts +16 -1
- package/cli/installer.js +159 -58
- package/cli/languages.js +8 -4
- package/cli/lattice-directives.js +24 -0
- package/cli/lattice-payload.js +34 -0
- package/cli/{tesseract-state.js → lattice-state.js} +8 -4
- package/cli/lease-view.js +48 -0
- package/cli/library/entry-fp.js +42 -0
- package/cli/library/entry-schema.js +90 -0
- package/cli/library/library-tasks.js +25 -0
- package/cli/library/registry.js +56 -0
- package/cli/library/reverify.js +56 -0
- package/cli/library/verify-checks.js +89 -0
- package/cli/library/verify.js +81 -0
- package/cli/license-config.js +124 -0
- package/cli/license.js +168 -135
- package/cli/line-count.js +23 -0
- package/cli/literal-replace.js +107 -0
- package/cli/main.js +166 -0
- package/cli/mcp/antigravity.js +11 -9
- package/cli/mcp/batch.js +59 -0
- package/cli/mcp/call-args.js +75 -0
- package/cli/mcp/call-effects.js +57 -0
- package/cli/mcp/call-scope.js +70 -62
- package/cli/mcp/context.js +81 -0
- package/cli/mcp/envelope.js +62 -0
- package/cli/mcp/fingerprint.js +26 -0
- package/cli/mcp/fresh-entry.js +34 -0
- package/cli/mcp/fresh-protocol.js +37 -0
- package/cli/mcp/fresh-runner.js +40 -0
- package/cli/mcp/help.js +53 -0
- package/cli/mcp/index.js +9 -5
- package/cli/mcp/inflight.js +47 -0
- package/cli/mcp/installer-jsonc.js +64 -0
- package/cli/mcp/installer-package.js +54 -0
- package/cli/mcp/installer-report.js +47 -0
- package/cli/mcp/installer-write.js +117 -0
- package/cli/mcp/installer.js +88 -187
- package/cli/mcp/manifests-analysis.js +156 -0
- package/cli/mcp/manifests-runners.js +48 -0
- package/cli/mcp/manifests-team.js +100 -0
- package/cli/mcp/manifests.js +69 -309
- package/cli/mcp/offload-worker.js +11 -0
- package/cli/mcp/offload.js +18 -0
- package/cli/mcp/patterns-cli.js +76 -0
- package/cli/mcp/patterns-forge-cli.js +120 -0
- package/cli/mcp/prompts.js +13 -10
- package/cli/mcp/resources.js +8 -35
- package/cli/mcp/roots.js +46 -0
- package/cli/mcp/scorecard-worker.js +7 -0
- package/cli/mcp/scorecard.js +42 -0
- package/cli/mcp/server-info.js +28 -0
- package/cli/mcp/server.js +91 -291
- package/cli/mcp/spec-harness.js +62 -0
- package/cli/mcp/stale-exec.js +48 -0
- package/cli/mcp/staleness.js +26 -0
- package/cli/mcp/stdio.js +141 -0
- package/cli/mcp/tool-call.js +73 -0
- package/cli/mcp/tools-audit-feed.js +33 -0
- package/cli/mcp/tools-audit.js +13 -7
- package/cli/mcp/tools-generate.js +3 -3
- package/cli/mcp/tools-lazy.js +39 -0
- package/cli/mcp/tools-patch.js +93 -21
- package/cli/mcp/tools-patterns.js +6 -3
- package/cli/mcp/tools-project.js +8 -4
- package/cli/mcp/tools-q-modes.js +15 -14
- package/cli/mcp/tools-q.js +94 -33
- package/cli/mcp/tools-read.js +30 -80
- package/cli/mcp/tools-team-feed.js +10 -8
- package/cli/mcp/tools-team-locks.js +22 -10
- package/cli/mcp/tools-team-mailbox.js +8 -7
- package/cli/mcp/tools-team-tasks.js +125 -38
- package/cli/mcp/tools-team.js +14 -7
- package/cli/mcp/tools-verify.js +44 -15
- package/cli/mcp/tools-write.js +11 -16
- package/cli/mcp/tools.js +202 -68
- package/cli/mcp/worker-run.js +24 -0
- package/cli/missing-imports.js +52 -0
- package/cli/mutation-args.js +96 -0
- package/cli/mutators.js +164 -61
- package/cli/navigator-actions.js +19 -13
- package/cli/navigator-banner-helpers.js +1 -26
- package/cli/navigator-banner.js +5 -3
- package/cli/navigator-conversion.js +23 -12
- package/cli/navigator-grades.js +70 -35
- package/cli/navigator-guide.js +13 -11
- package/cli/navigator-menu.js +80 -166
- package/cli/navigator-paged.js +15 -8
- package/cli/navigator-sections.js +32 -0
- package/cli/navigator-share.js +53 -39
- package/cli/navigator.d.ts +25 -5
- package/cli/navigator.js +14 -41
- package/cli/network-policy.js +72 -0
- package/cli/network-recorder.fixture.mjs +35 -0
- package/cli/outline/ast-outline.js +120 -0
- package/cli/outline/style-outline.js +42 -0
- package/cli/outline/vue-outline.js +88 -0
- package/cli/patcher-cli.js +255 -0
- package/cli/patcher.d.ts +55 -24
- package/cli/patcher.js +167 -358
- package/cli/path-scope.js +78 -22
- package/cli/patterns/fixtures/gt/A1.txt +109 -0
- package/cli/patterns/fixtures/gt/A10.txt +13 -0
- package/cli/patterns/fixtures/gt/A11.txt +10 -0
- package/cli/patterns/fixtures/gt/A12.txt +29 -0
- package/cli/patterns/fixtures/gt/A13.txt +39 -0
- package/cli/patterns/fixtures/gt/A14.txt +45 -0
- package/cli/patterns/fixtures/gt/A15.txt +70 -0
- package/cli/patterns/fixtures/gt/A16.txt +59 -0
- package/cli/patterns/fixtures/gt/A17.txt +29 -0
- package/cli/patterns/fixtures/gt/A18.txt +9 -0
- package/cli/patterns/fixtures/gt/A19.txt +29 -0
- package/cli/patterns/fixtures/gt/A2.txt +28 -0
- package/cli/patterns/fixtures/gt/A20.txt +83 -0
- package/cli/patterns/fixtures/gt/A21.txt +138 -0
- package/cli/patterns/fixtures/gt/A22.txt +32 -0
- package/cli/patterns/fixtures/gt/A23.txt +37 -0
- package/cli/patterns/fixtures/gt/A24.txt +67 -0
- package/cli/patterns/fixtures/gt/A25.txt +41 -0
- package/cli/patterns/fixtures/gt/A26.txt +29 -0
- package/cli/patterns/fixtures/gt/A3.txt +17 -0
- package/cli/patterns/fixtures/gt/A4.txt +44 -0
- package/cli/patterns/fixtures/gt/A5.txt +32 -0
- package/cli/patterns/fixtures/gt/A6.txt +15 -0
- package/cli/patterns/fixtures/gt/A7.txt +79 -0
- package/cli/patterns/fixtures/gt/A8.txt +41 -0
- package/cli/patterns/fixtures/gt/A9.txt +42 -0
- package/cli/patterns/fixtures/gt/B1.txt +11 -0
- package/cli/patterns/fixtures/gt/B10.txt +41 -0
- package/cli/patterns/fixtures/gt/B11.txt +7 -0
- package/cli/patterns/fixtures/gt/B2.txt +19 -0
- package/cli/patterns/fixtures/gt/B3.txt +70 -0
- package/cli/patterns/fixtures/gt/B4.txt +55 -0
- package/cli/patterns/fixtures/gt/B5.txt +21 -0
- package/cli/patterns/fixtures/gt/B6.txt +15 -0
- package/cli/patterns/fixtures/gt/B7.txt +24 -0
- package/cli/patterns/fixtures/gt/B8.txt +40 -0
- package/cli/patterns/fixtures/gt/B9.txt +18 -0
- package/cli/patterns/fixtures/gt/C1.txt +26 -0
- package/cli/patterns/fixtures/gt/C2.txt +33 -0
- package/cli/patterns/fixtures/gt/C3.txt +26 -0
- package/cli/patterns/fixtures/gt/C4.txt +7 -0
- package/cli/patterns/fixtures/gt/C5.txt +29 -0
- package/cli/patterns/fixtures/gt/C6.txt +7 -0
- package/cli/patterns/fixtures/gt/C7.txt +18 -0
- package/cli/patterns/fixtures/gt/labels.json +1837 -0
- package/cli/patterns/gt-build.js +55 -0
- package/cli/patterns/gt-locations.js +76 -0
- package/cli/patterns/gt-resolve.js +66 -0
- package/cli/patterns/gt-score-cli.js +80 -0
- package/cli/patterns/gt-score.js +188 -0
- package/cli/patterns/gt-text.js +79 -0
- package/cli/pillars-wizard.js +53 -24
- package/cli/pillars-write-guard.js +4 -1
- package/cli/postinstall.js +22 -19
- package/cli/project-detector.js +60 -35
- package/cli/project-markers.js +42 -0
- package/cli/project-scope.js +20 -0
- package/cli/read-revision.js +70 -0
- package/cli/reader-cards-gate.js +29 -0
- package/cli/reader-cards.js +153 -0
- package/cli/reader-cli.js +45 -18
- package/cli/reader-format.js +48 -0
- package/cli/reader-logic.js +128 -250
- package/cli/reader.js +210 -221
- package/cli/request-context.js +9 -0
- package/cli/result-status.js +23 -0
- package/cli/rules.js +81 -0
- package/cli/scaffold.js +80 -51
- package/cli/scan-ignore.js +12 -0
- package/cli/search-args.js +102 -0
- package/cli/search-ast-module.js +103 -0
- package/cli/search-ast.js +75 -112
- package/cli/search-commands-blast.js +70 -0
- package/cli/search-commands-graph.js +57 -105
- package/cli/search-commands-hazards.js +105 -0
- package/cli/search-commands-literal.js +102 -0
- package/cli/search-commands-semantic.js +39 -27
- package/cli/search-commands.js +93 -186
- package/cli/search-db.js +52 -252
- package/cli/search-debug.js +13 -0
- package/cli/search-graph-edges.js +112 -0
- package/cli/search-index-meta.js +66 -0
- package/cli/search-index-write.js +153 -0
- package/cli/search-literal-files.js +64 -0
- package/cli/search-literal.js +150 -0
- package/cli/search-output.js +88 -0
- package/cli/search-queries-graph.js +120 -193
- package/cli/search-queries-semantic.js +41 -14
- package/cli/search-queries-similar.js +2 -1
- package/cli/search-queries.js +46 -21
- package/cli/search-query-view.js +67 -0
- package/cli/search-rank.js +54 -0
- package/cli/search-replace-blocks.js +120 -0
- package/cli/search-resolve.js +52 -0
- package/cli/search-root.js +78 -0
- package/cli/search-scan.js +102 -0
- package/cli/search-schema-ddl.js +172 -0
- package/cli/search-schema.js +135 -220
- package/cli/search-session.js +11 -0
- package/cli/search-sync-paths.js +78 -0
- package/cli/search-sync-plan.js +63 -0
- package/cli/search-sync-rows.js +96 -0
- package/cli/search-sync.js +128 -0
- package/cli/search-tokenizer.js +8 -4
- package/cli/search.d.ts +26 -5
- package/cli/search.js +156 -410
- package/cli/sfc/component-resolver.js +96 -0
- package/cli/sfc/import-coverage.js +24 -0
- package/cli/sfc/module-aliases.js +102 -0
- package/cli/sfc/script-asts.js +51 -0
- package/cli/sfc/sfc-metadata.js +104 -0
- package/cli/sfc/sfc-parse.js +101 -0
- package/cli/sfc/svelte-parse.js +46 -0
- package/cli/sfc/template-walk.js +78 -0
- package/cli/sfc-scripts.js +60 -0
- package/cli/share-consent.js +49 -0
- package/cli/share-outcome.js +57 -0
- package/cli/silence-warnings.js +2 -1
- package/cli/source-parse.js +130 -0
- package/cli/spec-isolated-home.js +17 -0
- package/cli/spec-support/import-trace.mjs +22 -0
- package/cli/spec-support/run-cli.js +58 -0
- package/cli/sqlite-memory.js +47 -0
- package/cli/status-command.js +107 -0
- package/cli/symbol-locator.js +121 -0
- package/cli/team/agent-identity.js +58 -0
- package/cli/team/audit-run-adoption.js +117 -0
- package/cli/team/audit-run-bypass.js +177 -0
- package/cli/team/audit-run-calls.js +108 -0
- package/cli/team/audit-run-db.js +181 -0
- package/cli/team/audit-run-identity.js +80 -0
- package/cli/team/audit-run-invocations.js +130 -0
- package/cli/team/audit-run-protocol.js +258 -0
- package/cli/team/audit-run-render.js +107 -0
- package/cli/team/audit-run-shas.js +179 -0
- package/cli/team/audit-run.js +203 -0
- package/cli/team/claim-ignore-deps.js +16 -0
- package/cli/team/coordination-busy.js +164 -0
- package/cli/team/coordination-db.js +85 -0
- package/cli/team/coordination-fixture.js +53 -0
- package/cli/team/coordination-repos.js +72 -0
- package/cli/team/coordination-root.js +161 -0
- package/cli/team/coordination-target.js +114 -0
- package/cli/team/dispatch-templates/dispatch-v1.js +228 -0
- package/cli/team/edit-shas.js +45 -0
- package/cli/team/lease-activity.js +130 -0
- package/cli/team/lease-cap.js +67 -0
- package/cli/team/lease-contention.js +30 -0
- package/cli/team/lease-key.js +46 -0
- package/cli/team/lease-lapse.js +83 -0
- package/cli/team/lease-reacquire.js +99 -0
- package/cli/team/lease-renew.js +97 -0
- package/cli/team/lease-roots.js +30 -0
- package/cli/team/lease-waiter-notice.js +48 -0
- package/cli/team/staged-leases.js +64 -0
- package/cli/team/task-completion-output.js +78 -0
- package/cli/team/task-detail-sections.js +86 -0
- package/cli/team/task-list-view.js +10 -1
- package/cli/team/task-ref.js +73 -0
- package/cli/team/task-target.js +53 -0
- package/cli/team/task-tier.js +17 -0
- package/cli/team/team-brief.js +78 -0
- package/cli/team/team-commands-board.js +118 -0
- package/cli/team/team-commands-dispatch.js +85 -0
- package/cli/team/team-commands-lock-staged.js +87 -0
- package/cli/team/team-commands-lock-views.js +144 -0
- package/cli/team/team-commands-lock.js +115 -26
- package/cli/team/team-commands-migrate.js +171 -0
- package/cli/team/team-commands-profile.js +44 -0
- package/cli/team/team-commands-repo.js +114 -0
- package/cli/team/team-commands-task.js +312 -0
- package/cli/team/team-commands-tokens.js +57 -0
- package/cli/team/team-commands-triage.js +43 -0
- package/cli/team/team-commands-vds.js +2 -1
- package/cli/team/team-commands.js +108 -463
- package/cli/team/team-db-agents.js +12 -6
- package/cli/team/team-db-feed.js +25 -13
- package/cli/team/team-db-lock-promotion.js +95 -51
- package/cli/team/team-db-locks.js +167 -35
- package/cli/team/team-db-mailbox.js +15 -8
- package/cli/team/team-db-readonly.js +76 -0
- package/cli/team/team-db-task-helpers.js +68 -19
- package/cli/team/team-db-tasks.js +21 -9
- package/cli/team/team-db-transaction.js +20 -5
- package/cli/team/team-db.js +11 -4
- package/cli/team/team-dispatch-batches.js +271 -0
- package/cli/team/team-dispatch-prompts.js +152 -0
- package/cli/team/team-dispatch-render.js +154 -0
- package/cli/team/team-dispatch-run-cli.js +154 -0
- package/cli/team/team-dispatch-runs.js +155 -0
- package/cli/team/team-dispatch-script.js +67 -0
- package/cli/team/team-dispatch-select.js +220 -0
- package/cli/team/team-dispatch-v2-fixture.js +62 -0
- package/cli/team/team-dispatch-v2.js +207 -0
- package/cli/team/team-dispatch.js +229 -0
- package/cli/team/team-dispatcher-authority.js +43 -0
- package/cli/team/team-flags.js +222 -48
- package/cli/team/team-format.js +80 -26
- package/cli/team/team-handoff-hint.js +9 -0
- package/cli/team/team-migrate-agents.js +52 -0
- package/cli/team/team-migrate-apply.js +178 -0
- package/cli/team/team-migrate-junk.js +55 -0
- package/cli/team/team-migrate-metadata.js +80 -0
- package/cli/team/team-migrate-paths.js +50 -0
- package/cli/team/team-migrate-plan.js +85 -0
- package/cli/team/team-migrate-report.js +89 -0
- package/cli/team/team-migrate-tables.js +85 -0
- package/cli/team/team-migrate.js +193 -0
- package/cli/team/team-needs.js +99 -0
- package/cli/team/team-profile-format.js +126 -0
- package/cli/team/team-profile.js +144 -0
- package/cli/team/team-projects-coordinator.js +54 -33
- package/cli/team/team-projects-format.js +8 -4
- package/cli/team/team-projects-memory.js +6 -3
- package/cli/team/team-projects.js +2 -1
- package/cli/team/team-release-train.js +2 -1
- package/cli/team/team-route.js +132 -0
- package/cli/team/team-schema-repo.js +48 -0
- package/cli/team/team-schema-usage.js +25 -0
- package/cli/team/team-schema-vds.js +7 -3
- package/cli/team/team-schema.js +24 -4
- package/cli/team/team-task-close.js +132 -0
- package/cli/team/team-task-guard.js +24 -0
- package/cli/team/team-task-handoff.js +122 -0
- package/cli/team/team-task-ownership.js +74 -0
- package/cli/team/team-task-rules.js +21 -0
- package/cli/team/team-task-uncommitted.js +49 -0
- package/cli/team/team-telemetry.js +44 -32
- package/cli/team/team-tokens.js +4 -1
- package/cli/team/team-triage-generate.js +212 -0
- package/cli/team/team-triage-log.js +11 -0
- package/cli/team/team-triage-verify.js +153 -0
- package/cli/team/team-triage.js +92 -339
- package/cli/team/team-vds.js +2 -1
- package/cli/team/usage-compute.js +70 -0
- package/cli/team/usage-pricing.js +62 -0
- package/cli/team/usage-reader.js +106 -0
- package/cli/team/usage-render.js +72 -0
- package/cli/team/usage-store.js +56 -0
- package/cli/team/usage-transcript.js +127 -0
- package/cli/team/write-lock-guard.js +48 -0
- package/cli/telemetry/call-ledger.js +264 -0
- package/cli/telemetry/call-schema.js +53 -0
- package/cli/telemetry/savings-dbs.js +111 -0
- package/cli/telemetry/savings-render.js +68 -0
- package/cli/telemetry/savings-report.js +101 -0
- package/cli/telemetry/savings-routing.js +66 -0
- package/cli/telemetry/savings-tooling.js +140 -0
- package/cli/terminal.js +38 -40
- package/cli/tesseract-manifesto.js +2 -17
- package/cli/tesseract.js +8 -21
- package/cli/test-audit.js +218 -0
- package/cli/test-changes.js +60 -0
- package/cli/test-command.js +201 -0
- package/cli/test-depth.js +43 -0
- package/cli/test-failures.js +170 -0
- package/cli/test-graph-open.js +150 -0
- package/cli/test-graph.js +188 -0
- package/cli/test-lanes.js +117 -0
- package/cli/test-output.js +155 -0
- package/cli/test-paths.js +51 -0
- package/cli/test-profile.js +64 -0
- package/cli/test-report.js +112 -0
- package/cli/test-run.js +53 -0
- package/cli/test-scope.js +55 -0
- package/cli/test-select.js +107 -0
- package/cli/test-slots.js +276 -0
- package/cli/test-workers.js +45 -0
- package/cli/test-workspace.js +83 -0
- package/cli/theme.js +6 -3
- package/cli/timers.js +6 -0
- package/cli/trend.js +10 -5
- package/cli/tsconfig-shape.js +20 -0
- package/cli/tty-banner.js +11 -0
- package/cli/typecheck-audit.js +146 -0
- package/cli/typecheck-command.js +94 -0
- package/cli/typecheck-sandbox.js +93 -0
- package/cli/ui-actions-codebase.js +20 -7
- package/cli/ui-actions-helpers.js +9 -0
- package/cli/ui-actions-studio.js +11 -7
- package/cli/ui-actions-tasks.js +3 -2
- package/cli/ui-actions-vds.js +2 -1
- package/cli/ui-actions.js +4 -2
- package/cli/ui-attention.js +28 -12
- package/cli/ui-auth-hosts.js +46 -0
- package/cli/ui-auth.js +89 -0
- package/cli/ui-client-cert.js +2 -1
- package/cli/ui-client-filetree.js +2 -2
- package/cli/ui-db-studio.js +23 -33
- package/cli/ui-dev-watcher.js +2 -1
- package/cli/ui-forum-data.js +45 -46
- package/cli/ui-forum-topics.js +6 -3
- package/cli/ui-fresh-index.js +11 -0
- package/cli/ui-handlers.js +6 -6
- package/cli/ui-html.js +6 -12
- package/cli/ui-index.html +3 -3
- package/cli/ui-route-helpers.js +10 -0
- package/cli/ui-server-routes.js +15 -17
- package/cli/ui-server.js +49 -50
- package/cli/ui-sql-guard.js +76 -0
- package/cli/ui-sql-mask.js +61 -0
- package/cli/ui-sse.js +5 -4
- package/cli/ui-template-filetree.js +4 -4
- package/cli/ui-template-kanban.js +4 -7
- package/cli/verify-changed.js +43 -0
- package/cli/verify-helpers.js +21 -207
- package/cli/verify-lint.js +54 -20
- package/cli/verify-report.js +117 -0
- package/cli/verify-steps.js +71 -0
- package/cli/verify.js +111 -372
- package/cli/wait-command.js +147 -0
- package/cli/workspace-run.js +153 -0
- package/cli/workspace.js +147 -0
- package/cli/write-append.js +28 -0
- package/library/node-js/is-path-inside/entry.json +57 -0
- package/library/node-js/is-path-inside/negative/path-scope.js.txt +13 -0
- package/library/node-js/is-path-inside/piece.js +15 -0
- package/library/node-js/is-path-inside/piece.spec.js +38 -0
- package/library/node-js/read-json-or/entry.json +70 -0
- package/library/node-js/read-json-or/negative/ratchet.js.txt +14 -0
- package/library/node-js/read-json-or/negative/workspace.js.txt +8 -0
- package/library/node-js/read-json-or/piece.js +17 -0
- package/library/node-js/read-json-or/piece.spec.js +36 -0
- package/library/vue-ts/nullable-timer-handle/ambient.d.ts +5 -0
- package/library/vue-ts/nullable-timer-handle/entry.json +84 -0
- package/library/vue-ts/nullable-timer-handle/negative/const-alias.ts.txt +17 -0
- package/library/vue-ts/nullable-timer-handle/negative/inline-guard.ts.txt +15 -0
- package/library/vue-ts/nullable-timer-handle/piece.spec.js +48 -0
- package/library/vue-ts/nullable-timer-handle/piece.ts +41 -0
- package/package.json +9 -3
- package/scripts/check-framework-generation.mjs +32 -12
- package/scripts/direct-run.mjs +9 -0
- package/scripts/pre-commit.sh +48 -74
- package/scripts/publish-both.mjs +24 -16
- package/scripts/publish-summary.mjs +14 -0
- package/scripts/postinstall.mjs +0 -27
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Babel visitor passes for script code (a plain module or an SFC script overlay).
|
|
3
|
+
* Parsing, with the per-block fallback for SFCs whose combined overlay does not
|
|
4
|
+
* parse, lives in cli/sfc/script-asts.js so Forge's standalone path reads the same trees.
|
|
5
|
+
*/
|
|
6
|
+
import traverse from '@babel/traverse';
|
|
7
|
+
import { createAstVisitors } from './ast-visitors.js';
|
|
8
|
+
import { createAiSlopVisitors } from './ai-slop-detector.js';
|
|
9
|
+
import { createExtendedVisitors } from './extended-visitors.js';
|
|
10
|
+
import { createPatternVisitors } from './pattern-detector.js';
|
|
11
|
+
import { createHookShapeRegistry } from './hook-shape-validator.js';
|
|
12
|
+
import { createJsxRenderDepthVisitor } from './render-depth.js';
|
|
13
|
+
import { createFingerprintVisitors } from '../forge/fingerprint-visitors.js';
|
|
14
|
+
|
|
15
|
+
export { parseScriptAsts } from '../sfc/script-asts.js';
|
|
16
|
+
|
|
17
|
+
const traverseFn = traverse.default || traverse;
|
|
18
|
+
|
|
19
|
+
const mergeVisitorSets = (visitorSets) => {
|
|
20
|
+
const merged = {};
|
|
21
|
+
for (const visitorSet of visitorSets) {
|
|
22
|
+
for (const [key, fn] of Object.entries(visitorSet)) {
|
|
23
|
+
const previous = merged[key];
|
|
24
|
+
merged[key] = previous ? (p, s) => { previous(p, s); fn(p, s); } : fn;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return merged;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Runs every AST visitor family over the parsed script ASTs. options.fingerprint (a Forge collector)
|
|
32
|
+
* fills its binding index in the same traverse and fingerprints each AST right after it; the legacy
|
|
33
|
+
* pattern visitors still run alongside until Forge replaces them.
|
|
34
|
+
*/
|
|
35
|
+
export const runAstPasses = (asts, { relativePath, violations, ruleConfig, options, code = '' }) => {
|
|
36
|
+
const hookRegistry = options.hookRegistry || createHookShapeRegistry();
|
|
37
|
+
const fingerprint = options.fingerprint || null;
|
|
38
|
+
for (const ast of asts) {
|
|
39
|
+
const visitorSets = [
|
|
40
|
+
createAstVisitors({ relativePath, violations, hookRegistry, config: ruleConfig }),
|
|
41
|
+
createAiSlopVisitors({ relativePath, violations }),
|
|
42
|
+
createExtendedVisitors({ relativePath, violations }),
|
|
43
|
+
createJsxRenderDepthVisitor({ relativePath, violations, config: ruleConfig }),
|
|
44
|
+
options.patternRegistry ? createPatternVisitors(options.patternRegistry, relativePath) : {},
|
|
45
|
+
fingerprint ? createFingerprintVisitors(fingerprint) : {}
|
|
46
|
+
];
|
|
47
|
+
traverseFn(ast, mergeVisitorSets(visitorSets));
|
|
48
|
+
if (fingerprint) fingerprint.addScriptAst(ast, code);
|
|
49
|
+
}
|
|
50
|
+
const shouldRunLocalConsistency = !options.hookRegistry;
|
|
51
|
+
if (shouldRunLocalConsistency) violations.push(...hookRegistry.validateCrossHookConsistency());
|
|
52
|
+
};
|
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
import * as t from '@babel/types';
|
|
2
2
|
import { RULE_REGISTRY } from './rules-registry.js';
|
|
3
|
-
import { countLogicalOperators } from './rules-helpers.js';
|
|
4
3
|
import {
|
|
5
4
|
isCustomHookFunction,
|
|
6
5
|
resolveStartLine,
|
|
7
6
|
isZeroDelayTimeout,
|
|
8
7
|
isUnguardedConsoleCall,
|
|
9
8
|
isSilentGuardClause,
|
|
10
|
-
isSwallowedCatch,
|
|
11
9
|
countOptionalChainingDepth,
|
|
12
10
|
isCombinatorCall,
|
|
13
|
-
isRawBooleanArg
|
|
11
|
+
isRawBooleanArg,
|
|
12
|
+
isGuardClause
|
|
14
13
|
} from './rules-predicates.js';
|
|
14
|
+
import { isSwallowedCatch } from './catch-predicates.js';
|
|
15
|
+
import { resolveCatchEscalation, resolveCatchSpan } from './shallow-catch-escalation.js';
|
|
16
|
+
import { isNamedCondition, countJunctionOperators, resolveIfChainLength } from './lexicon-predicates.js';
|
|
17
|
+
import { narrowsMutableRef, MUTABLE_REF_REMEDY } from './mutable-ref-predicate.js';
|
|
18
|
+
import { collectTeardowns, classifyTimerDisposal, isListenerDisposed } from './lifecycle-predicates.js';
|
|
15
19
|
import { validateHookReturnShape } from './hook-shape-validator.js';
|
|
16
20
|
import { evaluateComponentStructuralWeight } from './structural-weight-evaluator.js';
|
|
17
21
|
|
|
22
|
+
const LOOKUP_CHAIN_MIN_BRANCHES = 3;
|
|
23
|
+
const MAX_TEMPLATE_JUNCTIONS = 2;
|
|
24
|
+
const TIMER_SEVERITY_BY_KIND = { setInterval: 'CRITICAL', setTimeout: 'LOW' };
|
|
25
|
+
|
|
18
26
|
export const createAstVisitors = ({ relativePath, violations, hookRegistry, config }) => {
|
|
27
|
+
let teardowns = { clearedHandles: new Set(), removedListeners: [] };
|
|
19
28
|
return {
|
|
29
|
+
Program(programPath) {
|
|
30
|
+
teardowns = collectTeardowns(programPath);
|
|
31
|
+
},
|
|
32
|
+
|
|
20
33
|
Function(astPath) {
|
|
21
34
|
evaluateComponentStructuralWeight({
|
|
22
35
|
funcPath: astPath,
|
|
@@ -37,16 +50,19 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
37
50
|
astPath.traverse({
|
|
38
51
|
CallExpression(callPath) {
|
|
39
52
|
const callee = callPath.node.callee;
|
|
40
|
-
|
|
53
|
+
const isHookCall = t.isIdentifier(callee) && /^use[A-Z0-9]/.test(callee.name);
|
|
54
|
+
if (isHookCall) {
|
|
41
55
|
const isExcluded = CONTROLLER_WRAPPER_EXCLUSIONS.has(callee.name);
|
|
42
|
-
|
|
56
|
+
const isOwnHookCall = !isExcluded && callPath.getFunctionParent() === astPath;
|
|
57
|
+
if (isOwnHookCall) {
|
|
43
58
|
hookCount += 1;
|
|
44
59
|
}
|
|
45
60
|
}
|
|
46
61
|
}
|
|
47
62
|
});
|
|
48
63
|
|
|
49
|
-
|
|
64
|
+
const isHookSaturated = hookCount > 5;
|
|
65
|
+
if (isHookSaturated) {
|
|
50
66
|
const line = astPath.node.loc?.start.line || 1;
|
|
51
67
|
const meta = RULE_REGISTRY.HOOK_SATURATION;
|
|
52
68
|
violations.push({
|
|
@@ -65,7 +81,8 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
65
81
|
if (isCustomHook) {
|
|
66
82
|
astPath.traverse({
|
|
67
83
|
ReturnStatement(retPath) {
|
|
68
|
-
|
|
84
|
+
const isOwnReturn = retPath.getFunctionParent() === astPath;
|
|
85
|
+
if (isOwnReturn) {
|
|
69
86
|
validateHookReturnShape({
|
|
70
87
|
retPath,
|
|
71
88
|
astPath,
|
|
@@ -82,9 +99,11 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
82
99
|
// Pillar 2: Control Flow Complexity
|
|
83
100
|
JSXExpressionContainer(astPath) {
|
|
84
101
|
const expr = astPath.node.expression;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
102
|
+
const isBooleanExpression = t.isLogicalExpression(expr) || t.isUnaryExpression(expr);
|
|
103
|
+
if (isBooleanExpression) {
|
|
104
|
+
const opCount = countJunctionOperators(expr);
|
|
105
|
+
const hasTooManyJunctions = opCount > MAX_TEMPLATE_JUNCTIONS;
|
|
106
|
+
if (hasTooManyJunctions) {
|
|
88
107
|
const line = resolveStartLine(expr, astPath.node, 1);
|
|
89
108
|
const meta = RULE_REGISTRY.CONTROL_FLOW_INLINE_BOOLEAN;
|
|
90
109
|
violations.push({
|
|
@@ -103,24 +122,24 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
103
122
|
|
|
104
123
|
IfStatement(astPath) {
|
|
105
124
|
const expr = astPath.node.test;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
125
|
+
const isLookupChain = resolveIfChainLength(astPath) >= LOOKUP_CHAIN_MIN_BRANCHES;
|
|
126
|
+
const isUnnamedTest = !isNamedCondition(expr);
|
|
127
|
+
const shouldFlagTest = isUnnamedTest && !isLookupChain;
|
|
128
|
+
if (shouldFlagTest) {
|
|
129
|
+
const line = resolveStartLine(expr, astPath.node, 1);
|
|
130
|
+
const meta = RULE_REGISTRY.CONTROL_FLOW_INLINE_BOOLEAN;
|
|
131
|
+
const isMutableNarrowing = narrowsMutableRef(astPath.get('test'), astPath.get('consequent'));
|
|
132
|
+
const remedy = isMutableNarrowing ? ` ${MUTABLE_REF_REMEDY}` : '';
|
|
133
|
+
violations.push({
|
|
134
|
+
filePath: relativePath,
|
|
135
|
+
line,
|
|
136
|
+
column: expr.loc?.start.column || 1,
|
|
137
|
+
hazard: `The if asks instead of reading a named condition. Name the question first (Directive 3.A).${remedy}`,
|
|
138
|
+
rule: 'CONTROL_FLOW_INLINE_BOOLEAN',
|
|
139
|
+
severity: countJunctionOperators(expr) > 0 ? meta.severity : 'LOW',
|
|
140
|
+
pillar: meta.pillar,
|
|
141
|
+
directive: meta.directive
|
|
142
|
+
});
|
|
124
143
|
}
|
|
125
144
|
|
|
126
145
|
const silentGuard = isSilentGuardClause(astPath, t);
|
|
@@ -141,7 +160,10 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
141
160
|
},
|
|
142
161
|
|
|
143
162
|
ConditionalExpression(astPath) {
|
|
144
|
-
|
|
163
|
+
const isOutermostOfChain = !astPath.parentPath?.isConditionalExpression();
|
|
164
|
+
const hasNestedBranch = t.isConditionalExpression(astPath.node.consequent) || t.isConditionalExpression(astPath.node.alternate);
|
|
165
|
+
const isNestedTernaryRoot = hasNestedBranch && isOutermostOfChain;
|
|
166
|
+
if (isNestedTernaryRoot) {
|
|
145
167
|
const line = astPath.node.loc?.start.line || 1;
|
|
146
168
|
const meta = RULE_REGISTRY.CONTROL_FLOW_NESTED_TERNARY;
|
|
147
169
|
violations.push({
|
|
@@ -159,18 +181,22 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
159
181
|
|
|
160
182
|
SwitchStatement(astPath) {
|
|
161
183
|
const cases = astPath.node.cases || [];
|
|
162
|
-
|
|
184
|
+
const hasTooFewCases = cases.length < 3;
|
|
185
|
+
if (hasTooFewCases) return;
|
|
163
186
|
|
|
164
187
|
const isDispatchConsequent = (statements) => {
|
|
165
|
-
|
|
166
|
-
if (
|
|
188
|
+
const isEmptyConsequent = !statements || statements.length === 0;
|
|
189
|
+
if (isEmptyConsequent) return false;
|
|
190
|
+
const isSingleStatement = statements.length === 1;
|
|
191
|
+
if (isSingleStatement) {
|
|
167
192
|
const s = statements[0];
|
|
168
193
|
if (t.isReturnStatement(s)) return true;
|
|
169
194
|
if (t.isBlockStatement(s)) {
|
|
170
195
|
return s.body.length === 1 && t.isReturnStatement(s.body[0]);
|
|
171
196
|
}
|
|
172
197
|
}
|
|
173
|
-
|
|
198
|
+
const isStatementPair = statements.length === 2;
|
|
199
|
+
if (isStatementPair) {
|
|
174
200
|
const [first, second] = statements;
|
|
175
201
|
if (t.isBreakStatement(second)) {
|
|
176
202
|
return t.isExpressionStatement(first) || t.isAssignmentExpression(first);
|
|
@@ -183,7 +209,8 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
183
209
|
let nonDefaultCount = 0;
|
|
184
210
|
|
|
185
211
|
for (const switchCase of cases) {
|
|
186
|
-
|
|
212
|
+
const isDefaultCase = !switchCase.test;
|
|
213
|
+
if (isDefaultCase) continue;
|
|
187
214
|
nonDefaultCount += 1;
|
|
188
215
|
if (isDispatchConsequent(switchCase.consequent)) {
|
|
189
216
|
dispatchCaseCount += 1;
|
|
@@ -207,14 +234,62 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
207
234
|
}
|
|
208
235
|
},
|
|
209
236
|
|
|
237
|
+
BlockStatement(astPath) {
|
|
238
|
+
const body = astPath.node.body;
|
|
239
|
+
const hasTooFewStatements = !body || body.length < 3;
|
|
240
|
+
if (hasTooFewStatements) return;
|
|
241
|
+
|
|
242
|
+
let currentGuards = [];
|
|
243
|
+
|
|
244
|
+
// A cascade is 3+ bail-out guards followed by the action they protect (Directive 3.H);
|
|
245
|
+
// a run of guards that ends the block protects nothing and is not reported.
|
|
246
|
+
const flushCluster = (isFollowedByAction) => {
|
|
247
|
+
const hasCascade = isFollowedByAction && currentGuards.length >= 3;
|
|
248
|
+
if (hasCascade) {
|
|
249
|
+
const firstGuard = currentGuards[0];
|
|
250
|
+
const guardCount = currentGuards.length;
|
|
251
|
+
const line = firstGuard.loc?.start.line || 1;
|
|
252
|
+
const column = firstGuard.loc?.start.column || 1;
|
|
253
|
+
const meta = RULE_REGISTRY.CONTROL_FLOW_CASCADE_GUARDS;
|
|
254
|
+
violations.push({
|
|
255
|
+
filePath: relativePath,
|
|
256
|
+
line,
|
|
257
|
+
column,
|
|
258
|
+
hazard: `Cascading guard clauses detected (${guardCount} guards >= 3 limit). Suggestion: Extract into a domain validator using ruleTree({ scope: { ... } }) with a 1-line callback return per Directive 3.H.`,
|
|
259
|
+
rule: 'CONTROL_FLOW_CASCADE_GUARDS',
|
|
260
|
+
severity: meta.severity,
|
|
261
|
+
pillar: meta.pillar,
|
|
262
|
+
directive: meta.directive
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
currentGuards = [];
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
for (const stmt of body) {
|
|
269
|
+
const isGuard = isGuardClause(stmt, t);
|
|
270
|
+
if (isGuard) {
|
|
271
|
+
currentGuards.push(stmt);
|
|
272
|
+
} else if (t.isVariableDeclaration(stmt)) {
|
|
273
|
+
continue;
|
|
274
|
+
} else {
|
|
275
|
+
flushCluster(true);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
flushCluster(false);
|
|
279
|
+
},
|
|
280
|
+
|
|
210
281
|
// Pillar 5: Design System & Inline Styles
|
|
211
282
|
JSXAttribute(astPath) {
|
|
212
283
|
const attrName = astPath.node.name?.name;
|
|
213
|
-
|
|
284
|
+
const isStyleAttr = attrName === 'style';
|
|
285
|
+
const isClassAttr = attrName === 'className' || attrName === 'class';
|
|
286
|
+
if (isStyleAttr) {
|
|
214
287
|
const value = astPath.node.value;
|
|
215
|
-
|
|
288
|
+
const isObjectStyle = t.isJSXExpressionContainer(value) && t.isObjectExpression(value.expression);
|
|
289
|
+
if (isObjectStyle) {
|
|
216
290
|
const preferTokens = config?.preferDesignTokens || 'warning';
|
|
217
|
-
|
|
291
|
+
const isTokenCheckEnabled = preferTokens !== 'off';
|
|
292
|
+
if (isTokenCheckEnabled) {
|
|
218
293
|
const line = astPath.node.loc?.start.line || 1;
|
|
219
294
|
const meta = RULE_REGISTRY.RAW_INLINE_STYLE;
|
|
220
295
|
const severity = preferTokens === 'error' ? 'HIGH' : meta.severity;
|
|
@@ -230,11 +305,13 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
230
305
|
});
|
|
231
306
|
}
|
|
232
307
|
}
|
|
233
|
-
} else if (
|
|
308
|
+
} else if (isClassAttr) {
|
|
234
309
|
const value = astPath.node.value;
|
|
235
310
|
const strVal = t.isStringLiteral(value) ? value.value : '';
|
|
236
|
-
|
|
237
|
-
|
|
311
|
+
const hasFontAwesomeClass = Boolean(strVal && (strVal.includes('fa-') || strVal.includes('fa ')));
|
|
312
|
+
if (hasFontAwesomeClass) {
|
|
313
|
+
const hasTextColorClass = /\btext-(primary|secondary|danger|warning|success|info|light|dark|\w+)\b/.test(strVal);
|
|
314
|
+
if (hasTextColorClass) {
|
|
238
315
|
const line = astPath.node.loc?.start.line || 1;
|
|
239
316
|
const meta = RULE_REGISTRY.ICON_SVG_STYLE_LEAK;
|
|
240
317
|
violations.push({
|
|
@@ -257,7 +334,8 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
257
334
|
const callee = astPath.node.callee;
|
|
258
335
|
|
|
259
336
|
// Timer Discipline
|
|
260
|
-
|
|
337
|
+
const isTimerCall = t.isIdentifier(callee) && (callee.name === 'setInterval' || callee.name === 'setTimeout');
|
|
338
|
+
if (isTimerCall) {
|
|
261
339
|
const args = astPath.node.arguments;
|
|
262
340
|
const delayArg = args[1];
|
|
263
341
|
|
|
@@ -277,28 +355,19 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
277
355
|
});
|
|
278
356
|
}
|
|
279
357
|
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
if (
|
|
283
|
-
fnParent.traverse({
|
|
284
|
-
ReturnStatement(retPath) {
|
|
285
|
-
if (retPath.node.argument) {
|
|
286
|
-
hasCleanup = true;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (!hasCleanup) {
|
|
358
|
+
const disposal = classifyTimerDisposal(astPath, teardowns);
|
|
359
|
+
const isUndisposed = disposal === 'held' || disposal === 'unheld';
|
|
360
|
+
if (isUndisposed) {
|
|
293
361
|
const line = astPath.node.loc?.start.line || 1;
|
|
294
362
|
const meta = RULE_REGISTRY.TIMER_DISCIPLINE;
|
|
363
|
+
const clearName = callee.name === 'setInterval' ? 'clearInterval' : 'clearTimeout';
|
|
295
364
|
violations.push({
|
|
296
365
|
filePath: relativePath,
|
|
297
366
|
line,
|
|
298
367
|
column: astPath.node.loc?.start.column || 1,
|
|
299
|
-
hazard: `Raw ${callee.name}
|
|
368
|
+
hazard: `Raw ${callee.name} with no ${clearName} for its handle anywhere in this module (Directive 6.C)`,
|
|
300
369
|
rule: 'TIMER_DISCIPLINE',
|
|
301
|
-
severity: meta.severity,
|
|
370
|
+
severity: TIMER_SEVERITY_BY_KIND[callee.name] || meta.severity,
|
|
302
371
|
pillar: meta.pillar,
|
|
303
372
|
directive: meta.directive
|
|
304
373
|
});
|
|
@@ -322,24 +391,9 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
322
391
|
}
|
|
323
392
|
|
|
324
393
|
// Pillar 6: Orphaned Event Listener
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (fnParent) {
|
|
329
|
-
const fnName = fnParent.node.id?.name || '';
|
|
330
|
-
if (fnName === 'listen') {
|
|
331
|
-
hasCleanup = true;
|
|
332
|
-
} else {
|
|
333
|
-
fnParent.traverse({
|
|
334
|
-
CallExpression(innerCall) {
|
|
335
|
-
const innerCallee = innerCall.node.callee;
|
|
336
|
-
if (t.isMemberExpression(innerCallee) && t.isIdentifier(innerCallee.property, { name: 'removeEventListener' })) {
|
|
337
|
-
hasCleanup = true;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
394
|
+
const isAddListenerCall = t.isMemberExpression(callee) && t.isIdentifier(callee.property, { name: 'addEventListener' });
|
|
395
|
+
if (isAddListenerCall) {
|
|
396
|
+
const hasCleanup = isListenerDisposed(astPath, teardowns);
|
|
343
397
|
if (!hasCleanup) {
|
|
344
398
|
const line = astPath.node.loc?.start.line || 1;
|
|
345
399
|
const meta = RULE_REGISTRY.LIFECYCLE_ORPHANED_LISTENER;
|
|
@@ -378,16 +432,18 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
378
432
|
|
|
379
433
|
// Pillar 2: Swallowed Exceptions
|
|
380
434
|
CatchClause(astPath) {
|
|
381
|
-
if (isSwallowedCatch(astPath
|
|
382
|
-
const line = astPath.node.loc?.start.line || 1;
|
|
435
|
+
if (isSwallowedCatch(astPath)) {
|
|
383
436
|
const meta = RULE_REGISTRY.ERROR_SWALLOWED_EXCEPTION;
|
|
437
|
+
const { severity, binding } = resolveCatchEscalation(astPath);
|
|
438
|
+
const finding = binding
|
|
439
|
+
? `Swallowed exception leaves "${binding}" unset; it is read after the try (silent undefined propagation)`
|
|
440
|
+
: 'Swallowed exception in catch block without active handling, logging, or ResultTuple';
|
|
384
441
|
violations.push({
|
|
385
442
|
filePath: relativePath,
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
hazard: 'Swallowed exception in catch block without active handling, logging, or ResultTuple',
|
|
443
|
+
...resolveCatchSpan(astPath),
|
|
444
|
+
hazard: `${finding}. Annotate intentional cases with // chemx-allow: best-effort <reason>`,
|
|
389
445
|
rule: 'ERROR_SWALLOWED_EXCEPTION',
|
|
390
|
-
severity
|
|
446
|
+
severity,
|
|
391
447
|
pillar: meta.pillar,
|
|
392
448
|
directive: meta.directive
|
|
393
449
|
});
|
|
@@ -399,7 +455,8 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
399
455
|
const isParentOptional = t.isOptionalMemberExpression(astPath.parent) || t.isOptionalCallExpression(astPath.parent);
|
|
400
456
|
if (!isParentOptional) {
|
|
401
457
|
const depth = countOptionalChainingDepth(astPath.node, t);
|
|
402
|
-
|
|
458
|
+
const isDeepChain = depth >= 3;
|
|
459
|
+
if (isDeepChain) {
|
|
403
460
|
const line = astPath.node.loc?.start.line || 1;
|
|
404
461
|
const meta = RULE_REGISTRY.DATA_FLOW_OPTIONAL_CHAINING_CHURN;
|
|
405
462
|
violations.push({
|
|
@@ -418,8 +475,10 @@ export const createAstVisitors = ({ relativePath, violations, hookRegistry, conf
|
|
|
418
475
|
|
|
419
476
|
// Pillar 4: Type Co-location
|
|
420
477
|
TSTypeLiteral(astPath) {
|
|
421
|
-
|
|
422
|
-
|
|
478
|
+
const isLargeLiteral = astPath.node.members.length > 3;
|
|
479
|
+
if (isLargeLiteral) {
|
|
480
|
+
const isInlinedType = !astPath.findParent((p) => p.isTSTypeAliasDeclaration() || p.isTSInterfaceDeclaration());
|
|
481
|
+
if (isInlinedType) {
|
|
423
482
|
const line = astPath.node.loc?.start.line || 1;
|
|
424
483
|
const meta = RULE_REGISTRY.TYPE_COLOCATION;
|
|
425
484
|
violations.push({
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Plain-text audit card for pipes, CI logs and agents: the facts of the dashboard banner
|
|
2
|
+
// without ASCII art, borders or color. Input is buildAuditSummary() output.
|
|
3
|
+
|
|
4
|
+
const formatGate = (gate) => {
|
|
5
|
+
const isUnknown = gate.passing === null;
|
|
6
|
+
if (isUnknown) return 'gate: not evaluated';
|
|
7
|
+
const verdict = gate.passing ? 'pass' : 'fail';
|
|
8
|
+
const basis = gate.basis ? ` (${gate.basis})` : '';
|
|
9
|
+
const note = gate.note ? `: ${gate.note}` : '';
|
|
10
|
+
return `gate: ${verdict}${basis}${note}`;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const formatPlainAuditSummary = (summary) => {
|
|
14
|
+
const { critical, highMedium, low } = summary.hazards;
|
|
15
|
+
const total = critical + highMedium + low;
|
|
16
|
+
const lines = [
|
|
17
|
+
`chemx audit ${summary.scope}: grade ${summary.health.grade} (${summary.health.score}/100), ${total} hazards: ${critical} critical, ${highMedium} high/medium, ${low} low`,
|
|
18
|
+
`${summary.files} files, ${summary.loc.toLocaleString('en-US')} LOC, ~${summary.tokens.estimate.toLocaleString('en-US')} tokens`,
|
|
19
|
+
formatGate(summary.gate)
|
|
20
|
+
];
|
|
21
|
+
for (const { rule, baseline, current } of summary.gate.regressions ?? []) {
|
|
22
|
+
lines.push(` regression: ${rule} ${baseline} -> ${current}`);
|
|
23
|
+
}
|
|
24
|
+
lines.push('detail: chemx audit --json | chemx audit --unroll | chemx q --hazards');
|
|
25
|
+
return `${lines.join('\n')}\n`;
|
|
26
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveProjectName, resolveCostFigures } from '
|
|
1
|
+
import { resolveProjectName, resolveCostFigures } from './project-figures.js';
|
|
2
2
|
|
|
3
3
|
const countHazards = (violations = []) => {
|
|
4
4
|
const counts = { critical: 0, highMedium: 0, low: 0 };
|
|
@@ -12,6 +12,12 @@ const countHazards = (violations = []) => {
|
|
|
12
12
|
return counts;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
const summarizeCoverageForCard = (coverage) => {
|
|
16
|
+
if (!coverage) return null;
|
|
17
|
+
const { files, astPct, parseErrors, textOnly, isPartial, sfc } = coverage;
|
|
18
|
+
return { files, astPct, parseErrors, textOnly, isPartial, sfcTemplates: sfc?.templatesParsed ?? 0 };
|
|
19
|
+
};
|
|
20
|
+
|
|
15
21
|
export const buildAuditSummary = (report, { projectRoot, scope }) => {
|
|
16
22
|
const gate = report.gate ?? {};
|
|
17
23
|
const summary = {
|
|
@@ -20,11 +26,18 @@ export const buildAuditSummary = (report, { projectRoot, scope }) => {
|
|
|
20
26
|
files: report.metrics?.scannedFiles ?? 0,
|
|
21
27
|
loc: report.metrics?.totalLoc ?? 0,
|
|
22
28
|
tokens: { estimate: report.contextAnalysis?.estimatedTokens ?? 0, savingsPct: report.contextAnalysis?.potentialSavingsPct ?? 0 },
|
|
23
|
-
health: { score: report.health.score, grade: report.health.grade, label: report.health.label ?? null },
|
|
29
|
+
health: { score: report.health.score, grade: report.health.grade, label: report.health.label ?? null, density: report.health.density ?? null, scoreModel: report.health.scoreModel ?? null },
|
|
24
30
|
aiSlop: { score: report.aiSlop?.score ?? 100, grade: report.aiSlop?.grade ?? 'A+' },
|
|
25
31
|
hazards: countHazards(report.violations),
|
|
26
32
|
cost: resolveCostFigures(report.contextAnalysis),
|
|
27
|
-
gate: {
|
|
33
|
+
gate: {
|
|
34
|
+
passing: gate.isPassing ?? null,
|
|
35
|
+
basis: gate.basis ?? null,
|
|
36
|
+
regressions: (gate.regressions ?? []).slice(0, 5),
|
|
37
|
+
adopted: (gate.adopted ?? []).map((a) => a.rule),
|
|
38
|
+
note: gate.note ?? null
|
|
39
|
+
},
|
|
40
|
+
coverage: summarizeCoverageForCard(report.coverage)
|
|
28
41
|
};
|
|
29
42
|
return report.rebaseline ? { ...summary, rebaseline: report.rebaseline } : summary;
|
|
30
43
|
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-aware mechanical fixes for one file's content.
|
|
3
|
+
*
|
|
4
|
+
* Only comments are edited, located by a real tokenizer (see comment-ranges.js): string
|
|
5
|
+
* literals, template literals, JSX text and Vue/Svelte templates are never touched. A comment
|
|
6
|
+
* flagged as AI residue is removed whole (never just its first line). Leaked Markdown fences
|
|
7
|
+
* are removed only as the first/last non-blank line of a JS/TS file, and only when the result
|
|
8
|
+
* parses (a fence pair can parse as tagged templates, so the original is not required to fail). setTimeout(fn, 0) is reported as a suggestion, never rewritten.
|
|
9
|
+
*/
|
|
10
|
+
import { findSourceRanges } from '../comment-ranges.js';
|
|
11
|
+
import { parseSource, langForPath } from '../source-parse.js';
|
|
12
|
+
import { lineOfIndex } from '../literal-replace.js';
|
|
13
|
+
|
|
14
|
+
const RESIDUE_PATTERNS = [
|
|
15
|
+
['hope this', 'helps'].join(' '),
|
|
16
|
+
['feel free', 'to tweak'].join(' '),
|
|
17
|
+
['let me know', 'if you need'].join(' '),
|
|
18
|
+
['as an ai', 'language model'].join(' ')
|
|
19
|
+
];
|
|
20
|
+
const RESIDUE_REGEX = new RegExp(`\\b(?:${RESIDUE_PATTERNS.join('|')})\\b`, 'i');
|
|
21
|
+
const PREAMBLE_REGEX = /\b(?:here(?:'s| is) the (?:complete|updated|refactored|full) (?:code|implementation|file|component|version))\b/i;
|
|
22
|
+
const TRUNCATION_REGEX = /^(?:\/\/|\/\*)\s*\.\.\.\s*(?:existing|rest of|remaining)\s+(?:code|implementation|logic|imports)/i;
|
|
23
|
+
const FENCE_LINE_REGEX = /^\s*```(?:typescript|javascript|tsx|jsx|vue|js|ts|html|css|scss)?\s*$/;
|
|
24
|
+
const TIMER_REGEX = /setTimeout\([^,]+,\s*0\)/g;
|
|
25
|
+
const EM_DASH = String.fromCharCode(0x2014);
|
|
26
|
+
|
|
27
|
+
const insideAny = (ranges, index) => ranges.some((r) => index >= r.start && index < r.end);
|
|
28
|
+
|
|
29
|
+
const stripEdgeFences = (content, filePath, fixes) => {
|
|
30
|
+
const isScript = Boolean(langForPath(filePath));
|
|
31
|
+
if (!isScript) return content;
|
|
32
|
+
const lines = content.split('\n');
|
|
33
|
+
const nonBlank = lines.map((l, i) => (l.trim() ? i : -1)).filter((i) => i >= 0);
|
|
34
|
+
const edges = [nonBlank[0], nonBlank[nonBlank.length - 1]].filter((i) => i !== undefined && FENCE_LINE_REGEX.test(lines[i]));
|
|
35
|
+
const fenceLines = [...new Set(edges)];
|
|
36
|
+
const candidate = lines.filter((_, i) => !fenceLines.includes(i)).join('\n');
|
|
37
|
+
const isRepaired = fenceLines.length > 0 && parseSource(candidate, filePath).ok;
|
|
38
|
+
if (!isRepaired) return content;
|
|
39
|
+
fenceLines.forEach((i) => fixes.push({ line: i + 1, rule: 'AI_SLOP_CONVERSATIONAL_ARTIFACT', action: 'Removed leaked markdown code fence' }));
|
|
40
|
+
return candidate;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const wholeCommentSpan = (content, comment) => {
|
|
44
|
+
const lineStart = content.lastIndexOf('\n', comment.start - 1) + 1;
|
|
45
|
+
const nextNewline = content.indexOf('\n', comment.end);
|
|
46
|
+
const lineEnd = nextNewline === -1 ? content.length : nextNewline;
|
|
47
|
+
const isAloneOnLines = content.slice(lineStart, comment.start).trim() === '' && content.slice(comment.end, lineEnd).trim() === '';
|
|
48
|
+
const isLastLine = nextNewline === -1;
|
|
49
|
+
const lineSpanStart = isLastLine && lineStart > 0 ? lineStart - 1 : lineStart;
|
|
50
|
+
if (isAloneOnLines) return { start: lineSpanStart, end: isLastLine ? lineEnd : lineEnd + 1 };
|
|
51
|
+
let start = comment.start;
|
|
52
|
+
while (start > lineStart && /[ \t]/.test(content[start - 1])) start--;
|
|
53
|
+
return { start, end: comment.end };
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const classifyComment = (text, shouldFix) => {
|
|
57
|
+
const isResidue = PREAMBLE_REGEX.test(text) || RESIDUE_REGEX.test(text);
|
|
58
|
+
const shouldRemoveResidue = isResidue && shouldFix('AI_SLOP_CONVERSATIONAL_ARTIFACT');
|
|
59
|
+
if (shouldRemoveResidue) return { rule: 'AI_SLOP_CONVERSATIONAL_ARTIFACT', action: 'Removed AI conversational residue comment' };
|
|
60
|
+
const isPlaceholder = TRUNCATION_REGEX.test(text.trim());
|
|
61
|
+
const shouldRemovePlaceholder = isPlaceholder && shouldFix('AI_SLOP_LAZY_PLACEHOLDER');
|
|
62
|
+
if (shouldRemovePlaceholder) return { rule: 'AI_SLOP_LAZY_PLACEHOLDER', action: 'Removed lazy AI truncation placeholder comment' };
|
|
63
|
+
return null;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const commentEdits = (content, ranges, shouldFix, fixes) => {
|
|
67
|
+
const edits = [];
|
|
68
|
+
for (const comment of [...ranges.comments].sort((a, b) => a.start - b.start)) {
|
|
69
|
+
const text = content.slice(comment.start, comment.end);
|
|
70
|
+
const removal = classifyComment(text, shouldFix);
|
|
71
|
+
const isRemoved = Boolean(removal);
|
|
72
|
+
if (isRemoved) {
|
|
73
|
+
edits.push({ ...wholeCommentSpan(content, comment), text: '' });
|
|
74
|
+
fixes.push({ line: lineOfIndex(content, comment.start), ...removal });
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const hasEmDash = text.includes(EM_DASH) && shouldFix('TYPOGRAPHY_EM_DASH');
|
|
78
|
+
if (!hasEmDash) continue;
|
|
79
|
+
edits.push({ start: comment.start, end: comment.end, text: text.split(EM_DASH).join('-') });
|
|
80
|
+
const dashLines = new Set([...text.matchAll(new RegExp(EM_DASH, 'g'))].map((m) => lineOfIndex(content, comment.start + m.index)));
|
|
81
|
+
dashLines.forEach((line) => fixes.push({ line, rule: 'TYPOGRAPHY_EM_DASH', action: 'Replaced em dash with standard hyphen in a comment' }));
|
|
82
|
+
}
|
|
83
|
+
return edits;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const timerSuggestions = (content, ranges, shouldFix) => {
|
|
87
|
+
const isTimerRuleOn = shouldFix('MACRO_TASK_OVER_MICRO_TASK');
|
|
88
|
+
if (!isTimerRuleOn) return [];
|
|
89
|
+
const skip = [...ranges.comments, ...ranges.literals];
|
|
90
|
+
return [...content.matchAll(TIMER_REGEX)]
|
|
91
|
+
.filter((m) => insideAny(ranges.codeRegions, m.index) && !insideAny(skip, m.index))
|
|
92
|
+
.map((m) => ({
|
|
93
|
+
line: lineOfIndex(content, m.index),
|
|
94
|
+
rule: 'MACRO_TASK_OVER_MICRO_TASK',
|
|
95
|
+
suggestion: 'Consider queueMicrotask(fn) if the timer id is never cleared (not applied: queueMicrotask returns undefined, so clearTimeout(id) would stop working).'
|
|
96
|
+
}));
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @param {string} content File content.
|
|
101
|
+
* @param {object} [options] { filePath = 'file.ts', rules }
|
|
102
|
+
* @returns {{ fixedContent: string, fixes: object[], suggestions: object[], skipped: string|null }}
|
|
103
|
+
*/
|
|
104
|
+
export const autofixContent = (content, options = {}) => {
|
|
105
|
+
const filePath = options.filePath || 'file.ts';
|
|
106
|
+
const allowedRules = options.rules ? new Set(options.rules) : null;
|
|
107
|
+
const shouldFix = (rule) => !allowedRules || allowedRules.has(rule);
|
|
108
|
+
const fixes = [];
|
|
109
|
+
|
|
110
|
+
const fenceShouldRun = shouldFix('AI_SLOP_CONVERSATIONAL_ARTIFACT');
|
|
111
|
+
const base = fenceShouldRun ? stripEdgeFences(content, filePath, fixes) : content;
|
|
112
|
+
const ranges = findSourceRanges(base, filePath);
|
|
113
|
+
const isTokenized = Boolean(ranges);
|
|
114
|
+
if (!isTokenized) return { fixedContent: base, fixes, suggestions: [], skipped: 'no tokenizer for this file type, or it does not parse' };
|
|
115
|
+
|
|
116
|
+
const edits = commentEdits(base, ranges, shouldFix, fixes);
|
|
117
|
+
let fixedContent = base;
|
|
118
|
+
for (const edit of edits.sort((a, b) => b.start - a.start)) {
|
|
119
|
+
fixedContent = fixedContent.slice(0, edit.start) + edit.text + fixedContent.slice(edit.end);
|
|
120
|
+
}
|
|
121
|
+
return { fixedContent, fixes, suggestions: timerSuggestions(base, ranges, shouldFix), skipped: null };
|
|
122
|
+
};
|