devrites 5.11.0 → 5.12.0
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/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/docs/agents/issue-driven-rites.md +1 -1
- package/docs/agents/issue-tracker.md +3 -0
- package/docs/cli.md +90 -0
- package/docs/command-map.md +4 -2
- package/docs/engine/commands.md +21 -0
- package/docs/engine/state-schema.md +1 -1
- package/docs/engine/workspace-schema.md +10 -2
- package/docs/usage.md +2 -0
- package/engine/commands.go +11 -5
- package/engine/help.go +80 -3
- package/engine/help_test.go +7 -1
- package/engine/internal/acceptance/acceptance_test.go +655 -0
- package/engine/internal/acceptance/approve.go +142 -0
- package/engine/internal/acceptance/cli.go +426 -0
- package/engine/internal/acceptance/evidence.go +139 -0
- package/engine/internal/acceptance/exec.go +131 -0
- package/engine/internal/acceptance/exec_unix.go +22 -0
- package/engine/internal/acceptance/exec_windows.go +16 -0
- package/engine/internal/acceptance/ledger.go +259 -0
- package/engine/internal/acceptance/lint.go +115 -0
- package/engine/internal/acceptance/run.go +207 -0
- package/engine/internal/acceptance/scaffold.go +55 -0
- package/engine/internal/gate/gate.go +12 -2
- package/engine/internal/gate/gate_test.go +17 -9
- package/engine/internal/gate/gates_ledger.go +76 -0
- package/engine/internal/gate/readiness_binding.go +39 -0
- package/engine/internal/gate/readiness_binding_test.go +4 -3
- package/engine/internal/install/install.go +7 -1
- package/engine/internal/install/install_test.go +17 -4
- package/engine/internal/install/merge.go +82 -22
- package/engine/internal/install/update.go +7 -1
- package/engine/internal/install/workspace_advisory.go +46 -0
- package/engine/internal/install/workspace_advisory_test.go +54 -0
- package/engine/internal/lib/candidate_test.go +1 -1
- package/engine/internal/lib/claims.go +411 -0
- package/engine/internal/lib/claims_test.go +182 -0
- package/engine/internal/lib/closeout_test.go +3 -3
- package/engine/internal/lib/context.go +445 -0
- package/engine/internal/lib/context_next_test.go +521 -0
- package/engine/internal/lib/detect.go +346 -0
- package/engine/internal/lib/detect_test.go +105 -0
- package/engine/internal/lib/diffscope.go +189 -0
- package/engine/internal/lib/dispatch.go +302 -0
- package/engine/internal/lib/drift.go +219 -0
- package/engine/internal/lib/drift_test.go +106 -0
- package/engine/internal/lib/dup.go +1243 -0
- package/engine/internal/lib/dup_test.go +488 -0
- package/engine/internal/lib/environment_report.go +1 -0
- package/engine/internal/lib/environment_report_test.go +2 -2
- package/engine/internal/lib/handoff.go +194 -0
- package/engine/internal/lib/handoff_test.go +83 -0
- package/engine/internal/lib/manifest_union_test.go +1 -1
- package/engine/internal/lib/metrics.go +256 -0
- package/engine/internal/lib/migrate_test.go +6 -6
- package/engine/internal/lib/next.go +155 -0
- package/engine/internal/lib/observe_budgets_test.go +3 -3
- package/engine/internal/lib/regression.go +378 -0
- package/engine/internal/lib/regression_test.go +179 -0
- package/engine/internal/lib/resolve_remediation_test.go +1 -1
- package/engine/internal/lib/secretscan_test.go +1 -1
- package/engine/internal/lib/slicecheck.go +179 -0
- package/engine/internal/lib/slicecheck_test.go +111 -0
- package/engine/internal/lib/taskgraph_test.go +2 -2
- package/engine/internal/lib/triggers.go +133 -0
- package/engine/internal/lib/windows.go +353 -0
- package/engine/internal/lib/windows_test.go +237 -0
- package/engine/internal/notes/cli.go +349 -0
- package/engine/internal/notes/notes.go +384 -0
- package/engine/internal/notes/notes_test.go +173 -0
- package/engine/internal/parallel/lease.go +3 -8
- package/engine/internal/parallel/parallel_test.go +34 -0
- package/engine/internal/state/budgets.go +13 -8
- package/engine/internal/state/observation_test.go +1 -0
- package/engine/internal/state/schema.go +4 -3
- package/engine/internal/state/state_test.go +3 -3
- package/engine/internal/state/workflow_manifest.json +13 -4
- package/engine/internal/state/workspaceschema_test.go +2 -2
- package/engine/internal/testutil/testutil.go +4 -0
- package/engine/main.go +59 -0
- package/engine/note_routing_test.go +95 -0
- package/engine/observation_contract_test.go +1 -0
- package/engine/root_routing_test.go +13 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/gates.md +4 -0
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/state.md +1 -1
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/state.md +1 -1
- package/engine/testdata/golden/TestParityResolve/answer/state.md.golden +1 -1
- package/engine/testdata/golden/TestParityResolve/drop/state.md.golden +1 -1
- package/engine/tests/adr_0027_readiness_binding_test.go +1 -0
- package/engine/tests/gate_test.go +3 -0
- package/engine/tests/parity_closeout_test.go +3 -3
- package/engine/tests/parity_resolve_test.go +1 -1
- package/engine/tests/workspace_observation_migration_test.go +8 -4
- package/pack/.claude/agents/_shared/composition-findings.md +1 -0
- package/pack/.claude/agents/_shared/composition-result.md +1 -0
- package/pack/.claude/agents/_shared/result-admission.md +3 -0
- package/pack/.claude/agents/_shared/untrusted-input-devex.md +1 -0
- package/pack/.claude/agents/_shared/untrusted-input-retrospector.md +1 -0
- package/pack/.claude/agents/_shared/untrusted-input.md +1 -0
- package/pack/.claude/agents/devrites-code-reviewer.md +19 -3
- package/pack/.claude/agents/devrites-devex-reviewer.md +3 -3
- package/pack/.claude/agents/devrites-doubt-reviewer.md +3 -3
- package/pack/.claude/agents/devrites-evidence-scout.md +3 -3
- package/pack/.claude/agents/devrites-frontend-reviewer.md +3 -3
- package/pack/.claude/agents/devrites-performance-reviewer.md +3 -3
- package/pack/.claude/agents/devrites-plan-drafter.md +3 -3
- package/pack/.claude/agents/devrites-plan-reviewer.md +3 -3
- package/pack/.claude/agents/devrites-proof-runner.md +3 -3
- package/pack/.claude/agents/devrites-retrospector.md +3 -3
- package/pack/.claude/agents/devrites-security-auditor.md +25 -3
- package/pack/.claude/agents/devrites-simplifier-reviewer.md +15 -5
- package/pack/.claude/agents/devrites-slice-wright.md +3 -3
- package/pack/.claude/agents/devrites-spec-reviewer.md +3 -3
- package/pack/.claude/agents/devrites-strategy-reviewer.md +3 -3
- package/pack/.claude/agents/devrites-test-analyst.md +3 -3
- package/pack/.claude/agents/devrites-upgrade-planner.md +3 -3
- package/pack/.claude/settings.json +39 -2
- package/pack/.claude/skills/devrites-api-interface/SKILL.md +2 -0
- package/pack/.claude/skills/devrites-audit/SKILL.md +9 -0
- package/pack/.claude/skills/devrites-browser-proof/SKILL.md +2 -0
- package/pack/.claude/skills/devrites-debug-recovery/SKILL.md +2 -0
- package/pack/.claude/skills/devrites-doubt/SKILL.md +2 -0
- package/pack/.claude/skills/devrites-frontend-craft/SKILL.md +2 -0
- package/pack/.claude/skills/devrites-frontend-craft/reference/design-references.md +4 -0
- package/pack/.claude/skills/devrites-frontend-craft/reference/shape.md +5 -0
- package/pack/.claude/skills/devrites-interview/SKILL.md +5 -0
- package/pack/.claude/skills/devrites-lib/SKILL.md +40 -5
- package/pack/.claude/skills/devrites-lib/reference/_shared/reslice-autocomplete.md +3 -0
- package/pack/.claude/skills/devrites-lib/reference/_shared/reslice-plan.md +3 -0
- package/pack/.claude/skills/devrites-lib/reference/_shared/reslice-vet.md +3 -0
- package/pack/.claude/skills/devrites-lib/reference/candidate-integrity.md +17 -0
- package/pack/.claude/skills/devrites-lib/reference/orchestration-profiles.md +20 -0
- package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +36 -4
- package/pack/.claude/skills/devrites-lib/reference/reply-contract.md +24 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/README.md +10 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/acceptance-preserving-reslice.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +21 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/anti-patterns.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/architecture-health.md +64 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/assumption-checkpoints.md +42 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/audit-coverage.md +103 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/browser-proof-checklist.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/ci-cd.md +11 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/code-navigation.md +71 -4
- package/pack/.claude/skills/devrites-lib/reference/standards/code-review.md +67 -7
- package/pack/.claude/skills/devrites-lib/reference/standards/coding-style.md +9 -4
- package/pack/.claude/skills/devrites-lib/reference/standards/context-hygiene.md +20 -3
- package/pack/.claude/skills/devrites-lib/reference/standards/core.md +10 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/data-integrity.md +24 -2
- package/pack/.claude/skills/devrites-lib/reference/standards/debug-recovery.md +14 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/definition-of-done.md +6 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/deprecation.md +18 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/developer-experience.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/development-workflow.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/documentation.md +12 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/duplicate-code.md +118 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/edge-case-trace.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/elicitation.md +29 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/error-handling.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/gates.md +117 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/git-workflow.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/glossary.md +40 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/hooks.md +16 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/integration-reliability.md +19 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/loop-operations.md +32 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/observability.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/one-shot-actions.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/patterns.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/performance.md +8 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/principles.md +14 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/prose-style.md +3 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/release/ship-checklist.md +4 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/repository-topology.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/review/README.md +23 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/review/ci-workflows.md +50 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/review/default.md +42 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/review/go.md +47 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/review/python.md +46 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/review/shell.md +40 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/review/ts-js.md +54 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/review-checklist.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/security-checklist.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/security.md +58 -6
- package/pack/.claude/skills/devrites-lib/reference/standards/skill-authoring.md +48 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/spec-grammar.md +18 -4
- package/pack/.claude/skills/devrites-lib/reference/standards/test-proof-checklist.md +5 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/testing.md +19 -2
- package/pack/.claude/skills/devrites-lib/reference/standards/tooling.md +12 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/verification-methods.md +110 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/windows.md +51 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +28 -3
- package/pack/.claude/skills/devrites-prose-craft/SKILL.md +3 -1
- package/pack/.claude/skills/devrites-source-driven/SKILL.md +2 -0
- package/pack/.claude/skills/devrites-ux-shape/SKILL.md +2 -0
- package/pack/.claude/skills/rite/SKILL.md +2 -0
- package/pack/.claude/skills/rite-adopt/SKILL.md +2 -0
- package/pack/.claude/skills/rite-autocomplete/SKILL.md +7 -4
- package/pack/.claude/skills/rite-autocomplete/reference/decision-policy.md +1 -3
- package/pack/.claude/skills/rite-autocomplete/reference/loop.md +8 -4
- package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +1 -3
- package/pack/.claude/skills/rite-build/SKILL.md +28 -14
- package/pack/.claude/skills/rite-build/reference/checkpoint.md +6 -0
- package/pack/.claude/skills/rite-build/reference/parallel-batch.md +11 -2
- package/pack/.claude/skills/rite-build/reference/phase-contract.md +8 -4
- package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +34 -8
- package/pack/.claude/skills/rite-clarify/SKILL.md +4 -0
- package/pack/.claude/skills/rite-converge/SKILL.md +14 -2
- package/pack/.claude/skills/rite-customize/SKILL.md +2 -0
- package/pack/.claude/skills/rite-define/SKILL.md +8 -2
- package/pack/.claude/skills/rite-doctor/SKILL.md +6 -1
- package/pack/.claude/skills/rite-dogfood/SKILL.md +2 -0
- package/pack/.claude/skills/rite-explain/SKILL.md +2 -0
- package/pack/.claude/skills/rite-frame/SKILL.md +4 -0
- package/pack/.claude/skills/rite-handoff/SKILL.md +8 -1
- package/pack/.claude/skills/rite-learn/SKILL.md +2 -0
- package/pack/.claude/skills/rite-plan/SKILL.md +7 -3
- package/pack/.claude/skills/rite-plan/reference/anti-patterns.md +1 -3
- package/pack/.claude/skills/rite-plan/reference/replan-and-repair.md +1 -3
- package/pack/.claude/skills/rite-plan/reference/task-breakdown.md +3 -1
- package/pack/.claude/skills/rite-polish/SKILL.md +13 -2
- package/pack/.claude/skills/rite-polish/reference/code.md +6 -1
- package/pack/.claude/skills/rite-polish/reference/ledger.md +3 -1
- package/pack/.claude/skills/rite-pov/SKILL.md +2 -0
- package/pack/.claude/skills/rite-pr-feedback/SKILL.md +2 -0
- package/pack/.claude/skills/rite-pressure-test/SKILL.md +2 -0
- package/pack/.claude/skills/rite-prototype/SKILL.md +2 -0
- package/pack/.claude/skills/rite-prove/SKILL.md +17 -3
- package/pack/.claude/skills/rite-prove/reference/test-command-discovery.md +6 -0
- package/pack/.claude/skills/rite-quick/SKILL.md +7 -1
- package/pack/.claude/skills/rite-resolve/SKILL.md +2 -0
- package/pack/.claude/skills/rite-review/SKILL.md +5 -1
- package/pack/.claude/skills/rite-review/reference/performance-checklist.md +14 -3
- package/pack/.claude/skills/rite-seal/SKILL.md +27 -3
- package/pack/.claude/skills/rite-seal/reference/go-no-go.md +1 -0
- package/pack/.claude/skills/rite-seal/reference/phase-contract.md +3 -1
- package/pack/.claude/skills/rite-ship/SKILL.md +5 -1
- package/pack/.claude/skills/rite-spec/SKILL.md +10 -3
- package/pack/.claude/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/.claude/skills/rite-status/SKILL.md +9 -0
- package/pack/.claude/skills/rite-temper/SKILL.md +5 -1
- package/pack/.claude/skills/rite-upgrade/SKILL.md +9 -1
- package/pack/.claude/skills/rite-vet/SKILL.md +29 -9
- package/pack/.claude/skills/rite-vet/reference/anti-patterns.md +1 -3
- package/pack/.claude/skills/rite-vet/reference/artifacts.md +20 -3
- package/pack/.claude/skills/rite-vet/reference/depth.md +1 -3
- package/pack/.claude/skills/rite-vet/reference/review-axes.md +6 -3
- package/pack/.claude/skills/rite-watch-pr/SKILL.md +2 -0
- package/pack/.claude/skills/rite-zoom-out/SKILL.md +2 -0
- package/pack/generated/claude/agents/devrites-code-reviewer.md +17 -1
- package/pack/generated/claude/agents/devrites-devex-reviewer.md +1 -1
- package/pack/generated/claude/agents/devrites-doubt-reviewer.md +1 -1
- package/pack/generated/claude/agents/devrites-evidence-scout.md +1 -1
- package/pack/generated/claude/agents/devrites-frontend-reviewer.md +1 -1
- package/pack/generated/claude/agents/devrites-performance-reviewer.md +1 -1
- package/pack/generated/claude/agents/devrites-plan-drafter.md +1 -1
- package/pack/generated/claude/agents/devrites-plan-reviewer.md +1 -1
- package/pack/generated/claude/agents/devrites-proof-runner.md +1 -1
- package/pack/generated/claude/agents/devrites-retrospector.md +1 -1
- package/pack/generated/claude/agents/devrites-security-auditor.md +23 -1
- package/pack/generated/claude/agents/devrites-simplifier-reviewer.md +13 -3
- package/pack/generated/claude/agents/devrites-slice-wright.md +1 -1
- package/pack/generated/claude/agents/devrites-spec-reviewer.md +1 -1
- package/pack/generated/claude/agents/devrites-strategy-reviewer.md +1 -1
- package/pack/generated/claude/agents/devrites-test-analyst.md +1 -1
- package/pack/generated/claude/agents/devrites-upgrade-planner.md +1 -1
- package/pack/generated/claude/settings.json +39 -2
- package/pack/generated/claude/skills/devrites-api-interface/SKILL.md +2 -0
- package/pack/generated/claude/skills/devrites-audit/SKILL.md +9 -0
- package/pack/generated/claude/skills/devrites-browser-proof/SKILL.md +2 -0
- package/pack/generated/claude/skills/devrites-debug-recovery/SKILL.md +2 -0
- package/pack/generated/claude/skills/devrites-doubt/SKILL.md +2 -0
- package/pack/generated/claude/skills/devrites-frontend-craft/SKILL.md +2 -0
- package/pack/generated/claude/skills/devrites-frontend-craft/reference/design-references.md +4 -0
- package/pack/generated/claude/skills/devrites-frontend-craft/reference/shape.md +5 -0
- package/pack/generated/claude/skills/devrites-interview/SKILL.md +5 -0
- package/pack/generated/claude/skills/devrites-lib/SKILL.md +40 -5
- package/pack/generated/claude/skills/devrites-lib/reference/candidate-integrity.md +17 -0
- package/pack/generated/claude/skills/devrites-lib/reference/orchestration-profiles.md +20 -0
- package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +36 -4
- package/pack/generated/claude/skills/devrites-lib/reference/reply-contract.md +24 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/README.md +10 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/acceptance-preserving-reslice.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +21 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/anti-patterns.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/architecture-health.md +64 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/assumption-checkpoints.md +42 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/audit-coverage.md +103 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/browser-proof-checklist.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/ci-cd.md +11 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/code-navigation.md +71 -4
- package/pack/generated/claude/skills/devrites-lib/reference/standards/code-review.md +67 -7
- package/pack/generated/claude/skills/devrites-lib/reference/standards/coding-style.md +9 -4
- package/pack/generated/claude/skills/devrites-lib/reference/standards/context-hygiene.md +20 -3
- package/pack/generated/claude/skills/devrites-lib/reference/standards/core.md +10 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/data-integrity.md +24 -2
- package/pack/generated/claude/skills/devrites-lib/reference/standards/debug-recovery.md +14 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/definition-of-done.md +6 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/deprecation.md +18 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/developer-experience.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/development-workflow.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/documentation.md +12 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/duplicate-code.md +118 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/edge-case-trace.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/elicitation.md +29 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/error-handling.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/gates.md +117 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/git-workflow.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/glossary.md +40 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/hooks.md +16 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/integration-reliability.md +19 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/loop-operations.md +32 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/observability.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/one-shot-actions.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/patterns.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/performance.md +8 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/principles.md +14 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/prose-style.md +3 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/release/ship-checklist.md +4 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/repository-topology.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/review/README.md +23 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/review/ci-workflows.md +50 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/review/default.md +42 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/review/go.md +47 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/review/python.md +46 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/review/shell.md +40 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/review/ts-js.md +54 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/review-checklist.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/security-checklist.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/security.md +58 -6
- package/pack/generated/claude/skills/devrites-lib/reference/standards/skill-authoring.md +48 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/spec-grammar.md +18 -4
- package/pack/generated/claude/skills/devrites-lib/reference/standards/test-proof-checklist.md +5 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/testing.md +19 -2
- package/pack/generated/claude/skills/devrites-lib/reference/standards/tooling.md +12 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/verification-methods.md +110 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/windows.md +51 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +28 -3
- package/pack/generated/claude/skills/devrites-prose-craft/SKILL.md +3 -1
- package/pack/generated/claude/skills/devrites-source-driven/SKILL.md +2 -0
- package/pack/generated/claude/skills/devrites-ux-shape/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-adopt/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +6 -1
- package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +7 -1
- package/pack/generated/claude/skills/rite-build/SKILL.md +28 -14
- package/pack/generated/claude/skills/rite-build/reference/checkpoint.md +6 -0
- package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +11 -2
- package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +8 -4
- package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +34 -8
- package/pack/generated/claude/skills/rite-clarify/SKILL.md +4 -0
- package/pack/generated/claude/skills/rite-converge/SKILL.md +14 -2
- package/pack/generated/claude/skills/rite-customize/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-define/SKILL.md +8 -2
- package/pack/generated/claude/skills/rite-doctor/SKILL.md +6 -1
- package/pack/generated/claude/skills/rite-dogfood/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-explain/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-frame/SKILL.md +4 -0
- package/pack/generated/claude/skills/rite-handoff/SKILL.md +8 -1
- package/pack/generated/claude/skills/rite-learn/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-plan/SKILL.md +6 -0
- package/pack/generated/claude/skills/rite-plan/reference/task-breakdown.md +3 -1
- package/pack/generated/claude/skills/rite-polish/SKILL.md +13 -2
- package/pack/generated/claude/skills/rite-polish/reference/code.md +6 -1
- package/pack/generated/claude/skills/rite-polish/reference/ledger.md +3 -1
- package/pack/generated/claude/skills/rite-pov/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-pr-feedback/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-pressure-test/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-prototype/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-prove/SKILL.md +17 -3
- package/pack/generated/claude/skills/rite-prove/reference/test-command-discovery.md +6 -0
- package/pack/generated/claude/skills/rite-quick/SKILL.md +7 -1
- package/pack/generated/claude/skills/rite-resolve/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-review/SKILL.md +5 -1
- package/pack/generated/claude/skills/rite-review/reference/performance-checklist.md +14 -3
- package/pack/generated/claude/skills/rite-seal/SKILL.md +27 -3
- package/pack/generated/claude/skills/rite-seal/reference/go-no-go.md +1 -0
- package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +3 -1
- package/pack/generated/claude/skills/rite-ship/SKILL.md +5 -1
- package/pack/generated/claude/skills/rite-spec/SKILL.md +10 -3
- package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/claude/skills/rite-status/SKILL.md +9 -0
- package/pack/generated/claude/skills/rite-temper/SKILL.md +5 -1
- package/pack/generated/claude/skills/rite-upgrade/SKILL.md +9 -1
- package/pack/generated/claude/skills/rite-vet/SKILL.md +28 -6
- package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +19 -0
- package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +5 -0
- package/pack/generated/claude/skills/rite-watch-pr/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-zoom-out/SKILL.md +2 -0
- package/pack/generated/codex/agents/devrites-code-reviewer.toml +16 -0
- package/pack/generated/codex/agents/devrites-security-auditor.toml +22 -0
- package/pack/generated/codex/agents/devrites-simplifier-reviewer.toml +12 -2
- package/pack/generated/codex/skills/devrites-api-interface/SKILL.md +2 -0
- package/pack/generated/codex/skills/devrites-audit/SKILL.md +9 -0
- package/pack/generated/codex/skills/devrites-browser-proof/SKILL.md +2 -0
- package/pack/generated/codex/skills/devrites-debug-recovery/SKILL.md +2 -0
- package/pack/generated/codex/skills/devrites-doubt/SKILL.md +2 -0
- package/pack/generated/codex/skills/devrites-frontend-craft/SKILL.md +2 -0
- package/pack/generated/codex/skills/devrites-frontend-craft/reference/design-references.md +4 -0
- package/pack/generated/codex/skills/devrites-frontend-craft/reference/shape.md +5 -0
- package/pack/generated/codex/skills/devrites-interview/SKILL.md +5 -0
- package/pack/generated/codex/skills/devrites-lib/SKILL.md +40 -5
- package/pack/generated/codex/skills/devrites-lib/reference/candidate-integrity.md +17 -0
- package/pack/generated/codex/skills/devrites-lib/reference/orchestration-profiles.md +20 -0
- package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +36 -4
- package/pack/generated/codex/skills/devrites-lib/reference/reply-contract.md +24 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/README.md +10 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/acceptance-preserving-reslice.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +21 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/anti-patterns.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/architecture-health.md +64 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/assumption-checkpoints.md +42 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/audit-coverage.md +103 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/browser-proof-checklist.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/ci-cd.md +11 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/code-navigation.md +71 -4
- package/pack/generated/codex/skills/devrites-lib/reference/standards/code-review.md +67 -7
- package/pack/generated/codex/skills/devrites-lib/reference/standards/coding-style.md +9 -4
- package/pack/generated/codex/skills/devrites-lib/reference/standards/context-hygiene.md +20 -3
- package/pack/generated/codex/skills/devrites-lib/reference/standards/core.md +10 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/data-integrity.md +24 -2
- package/pack/generated/codex/skills/devrites-lib/reference/standards/debug-recovery.md +14 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/definition-of-done.md +6 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/deprecation.md +18 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/developer-experience.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/development-workflow.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/documentation.md +12 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/duplicate-code.md +118 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/edge-case-trace.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/elicitation.md +29 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/error-handling.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/gates.md +117 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/git-workflow.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/glossary.md +40 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/hooks.md +16 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/integration-reliability.md +19 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/loop-operations.md +32 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/observability.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/one-shot-actions.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/patterns.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/performance.md +8 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/principles.md +14 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/prose-style.md +3 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/release/ship-checklist.md +4 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/repository-topology.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/review/README.md +23 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/review/ci-workflows.md +50 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/review/default.md +42 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/review/go.md +47 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/review/python.md +46 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/review/shell.md +40 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/review/ts-js.md +54 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/review-checklist.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/security-checklist.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/security.md +58 -6
- package/pack/generated/codex/skills/devrites-lib/reference/standards/skill-authoring.md +48 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/spec-grammar.md +18 -4
- package/pack/generated/codex/skills/devrites-lib/reference/standards/test-proof-checklist.md +5 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/testing.md +19 -2
- package/pack/generated/codex/skills/devrites-lib/reference/standards/tooling.md +12 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/verification-methods.md +110 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/windows.md +51 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +28 -3
- package/pack/generated/codex/skills/devrites-prose-craft/SKILL.md +3 -1
- package/pack/generated/codex/skills/devrites-source-driven/SKILL.md +2 -0
- package/pack/generated/codex/skills/devrites-ux-shape/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-adopt/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +6 -1
- package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +7 -1
- package/pack/generated/codex/skills/rite-build/SKILL.md +28 -14
- package/pack/generated/codex/skills/rite-build/reference/checkpoint.md +6 -0
- package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +11 -2
- package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +8 -4
- package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +34 -8
- package/pack/generated/codex/skills/rite-clarify/SKILL.md +4 -0
- package/pack/generated/codex/skills/rite-converge/SKILL.md +14 -2
- package/pack/generated/codex/skills/rite-customize/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-define/SKILL.md +8 -2
- package/pack/generated/codex/skills/rite-doctor/SKILL.md +6 -1
- package/pack/generated/codex/skills/rite-dogfood/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-explain/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-frame/SKILL.md +4 -0
- package/pack/generated/codex/skills/rite-handoff/SKILL.md +8 -1
- package/pack/generated/codex/skills/rite-learn/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-plan/SKILL.md +6 -0
- package/pack/generated/codex/skills/rite-plan/reference/task-breakdown.md +3 -1
- package/pack/generated/codex/skills/rite-polish/SKILL.md +13 -2
- package/pack/generated/codex/skills/rite-polish/reference/code.md +6 -1
- package/pack/generated/codex/skills/rite-polish/reference/ledger.md +3 -1
- package/pack/generated/codex/skills/rite-pov/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-pr-feedback/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-pressure-test/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-prototype/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-prove/SKILL.md +17 -3
- package/pack/generated/codex/skills/rite-prove/reference/test-command-discovery.md +6 -0
- package/pack/generated/codex/skills/rite-quick/SKILL.md +7 -1
- package/pack/generated/codex/skills/rite-resolve/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-review/SKILL.md +5 -1
- package/pack/generated/codex/skills/rite-review/reference/performance-checklist.md +14 -3
- package/pack/generated/codex/skills/rite-seal/SKILL.md +27 -3
- package/pack/generated/codex/skills/rite-seal/reference/go-no-go.md +1 -0
- package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +3 -1
- package/pack/generated/codex/skills/rite-ship/SKILL.md +5 -1
- package/pack/generated/codex/skills/rite-spec/SKILL.md +10 -3
- package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/codex/skills/rite-status/SKILL.md +9 -0
- package/pack/generated/codex/skills/rite-temper/SKILL.md +5 -1
- package/pack/generated/codex/skills/rite-upgrade/SKILL.md +9 -1
- package/pack/generated/codex/skills/rite-vet/SKILL.md +28 -6
- package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +19 -0
- package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +5 -0
- package/pack/generated/codex/skills/rite-watch-pr/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-zoom-out/SKILL.md +2 -0
- package/pack/generated/devin/agents/devrites-code-reviewer.md +16 -0
- package/pack/generated/devin/agents/devrites-security-auditor.md +22 -0
- package/pack/generated/devin/agents/devrites-simplifier-reviewer.md +12 -2
- package/pack/generated/devin/skills/devrites-api-interface/SKILL.md +2 -0
- package/pack/generated/devin/skills/devrites-audit/SKILL.md +9 -0
- package/pack/generated/devin/skills/devrites-browser-proof/SKILL.md +2 -0
- package/pack/generated/devin/skills/devrites-debug-recovery/SKILL.md +2 -0
- package/pack/generated/devin/skills/devrites-doubt/SKILL.md +2 -0
- package/pack/generated/devin/skills/devrites-frontend-craft/SKILL.md +2 -0
- package/pack/generated/devin/skills/devrites-frontend-craft/reference/design-references.md +4 -0
- package/pack/generated/devin/skills/devrites-frontend-craft/reference/shape.md +5 -0
- package/pack/generated/devin/skills/devrites-interview/SKILL.md +5 -0
- package/pack/generated/devin/skills/devrites-lib/SKILL.md +40 -5
- package/pack/generated/devin/skills/devrites-lib/reference/candidate-integrity.md +17 -0
- package/pack/generated/devin/skills/devrites-lib/reference/orchestration-profiles.md +20 -0
- package/pack/generated/devin/skills/devrites-lib/reference/parallel-dispatch.md +36 -4
- package/pack/generated/devin/skills/devrites-lib/reference/reply-contract.md +24 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/README.md +10 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/acceptance-preserving-reslice.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/afk-hitl.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/agents.md +21 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/anti-patterns.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/architecture-health.md +64 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/assumption-checkpoints.md +42 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/audit-coverage.md +103 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/browser-proof-checklist.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/ci-cd.md +11 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/code-navigation.md +71 -4
- package/pack/generated/devin/skills/devrites-lib/reference/standards/code-review.md +67 -7
- package/pack/generated/devin/skills/devrites-lib/reference/standards/coding-style.md +9 -4
- package/pack/generated/devin/skills/devrites-lib/reference/standards/context-hygiene.md +20 -3
- package/pack/generated/devin/skills/devrites-lib/reference/standards/core.md +10 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/data-integrity.md +24 -2
- package/pack/generated/devin/skills/devrites-lib/reference/standards/debug-recovery.md +14 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/definition-of-done.md +6 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/deprecation.md +18 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/developer-experience.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/development-workflow.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/documentation.md +12 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/duplicate-code.md +118 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/edge-case-trace.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/elicitation.md +29 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/error-handling.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/gates.md +117 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/git-workflow.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/glossary.md +40 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/hooks.md +16 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/integration-reliability.md +19 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/loop-operations.md +32 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/observability.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/one-shot-actions.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/patterns.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/performance.md +8 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/principles.md +14 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/prose-style.md +3 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/release/ship-checklist.md +4 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/repository-topology.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/review/README.md +23 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/review/ci-workflows.md +50 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/review/default.md +42 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/review/go.md +47 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/review/python.md +46 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/review/shell.md +40 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/review/ts-js.md +54 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/review-checklist.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/security-checklist.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/security.md +58 -6
- package/pack/generated/devin/skills/devrites-lib/reference/standards/skill-authoring.md +48 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/spec-grammar.md +18 -4
- package/pack/generated/devin/skills/devrites-lib/reference/standards/test-proof-checklist.md +5 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/testing.md +19 -2
- package/pack/generated/devin/skills/devrites-lib/reference/standards/tooling.md +12 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/verification-methods.md +110 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/windows.md +51 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/workspace-artifact-schema.md +28 -3
- package/pack/generated/devin/skills/devrites-prose-craft/SKILL.md +3 -1
- package/pack/generated/devin/skills/devrites-source-driven/SKILL.md +2 -0
- package/pack/generated/devin/skills/devrites-ux-shape/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-adopt/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-autocomplete/SKILL.md +6 -1
- package/pack/generated/devin/skills/rite-autocomplete/reference/loop.md +7 -1
- package/pack/generated/devin/skills/rite-build/SKILL.md +28 -14
- package/pack/generated/devin/skills/rite-build/reference/checkpoint.md +6 -0
- package/pack/generated/devin/skills/rite-build/reference/parallel-batch.md +11 -2
- package/pack/generated/devin/skills/rite-build/reference/phase-contract.md +8 -4
- package/pack/generated/devin/skills/rite-build/reference/wright-dispatch.md +34 -8
- package/pack/generated/devin/skills/rite-clarify/SKILL.md +4 -0
- package/pack/generated/devin/skills/rite-converge/SKILL.md +14 -2
- package/pack/generated/devin/skills/rite-customize/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-define/SKILL.md +8 -2
- package/pack/generated/devin/skills/rite-doctor/SKILL.md +6 -1
- package/pack/generated/devin/skills/rite-dogfood/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-explain/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-frame/SKILL.md +4 -0
- package/pack/generated/devin/skills/rite-handoff/SKILL.md +8 -1
- package/pack/generated/devin/skills/rite-learn/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-plan/SKILL.md +6 -0
- package/pack/generated/devin/skills/rite-plan/reference/task-breakdown.md +3 -1
- package/pack/generated/devin/skills/rite-polish/SKILL.md +13 -2
- package/pack/generated/devin/skills/rite-polish/reference/code.md +6 -1
- package/pack/generated/devin/skills/rite-polish/reference/ledger.md +3 -1
- package/pack/generated/devin/skills/rite-pov/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-pr-feedback/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-pressure-test/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-prototype/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-prove/SKILL.md +17 -3
- package/pack/generated/devin/skills/rite-prove/reference/test-command-discovery.md +6 -0
- package/pack/generated/devin/skills/rite-quick/SKILL.md +7 -1
- package/pack/generated/devin/skills/rite-resolve/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-review/SKILL.md +5 -1
- package/pack/generated/devin/skills/rite-review/reference/performance-checklist.md +14 -3
- package/pack/generated/devin/skills/rite-seal/SKILL.md +27 -3
- package/pack/generated/devin/skills/rite-seal/reference/go-no-go.md +1 -0
- package/pack/generated/devin/skills/rite-seal/reference/phase-contract.md +3 -1
- package/pack/generated/devin/skills/rite-ship/SKILL.md +5 -1
- package/pack/generated/devin/skills/rite-spec/SKILL.md +10 -3
- package/pack/generated/devin/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/devin/skills/rite-status/SKILL.md +9 -0
- package/pack/generated/devin/skills/rite-temper/SKILL.md +5 -1
- package/pack/generated/devin/skills/rite-upgrade/SKILL.md +9 -1
- package/pack/generated/devin/skills/rite-vet/SKILL.md +28 -6
- package/pack/generated/devin/skills/rite-vet/reference/artifacts.md +19 -0
- package/pack/generated/devin/skills/rite-vet/reference/review-axes.md +5 -0
- package/pack/generated/devin/skills/rite-watch-pr/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-zoom-out/SKILL.md +2 -0
- package/pack/generated/omp/agents/devrites-code-reviewer.md +16 -0
- package/pack/generated/omp/agents/devrites-security-auditor.md +22 -0
- package/pack/generated/omp/agents/devrites-simplifier-reviewer.md +12 -2
- package/pack/generated/omp/skills/devrites-api-interface/SKILL.md +2 -0
- package/pack/generated/omp/skills/devrites-audit/SKILL.md +9 -0
- package/pack/generated/omp/skills/devrites-browser-proof/SKILL.md +2 -0
- package/pack/generated/omp/skills/devrites-debug-recovery/SKILL.md +2 -0
- package/pack/generated/omp/skills/devrites-doubt/SKILL.md +2 -0
- package/pack/generated/omp/skills/devrites-frontend-craft/SKILL.md +2 -0
- package/pack/generated/omp/skills/devrites-frontend-craft/reference/design-references.md +4 -0
- package/pack/generated/omp/skills/devrites-frontend-craft/reference/shape.md +5 -0
- package/pack/generated/omp/skills/devrites-interview/SKILL.md +5 -0
- package/pack/generated/omp/skills/devrites-lib/SKILL.md +40 -5
- package/pack/generated/omp/skills/devrites-lib/reference/candidate-integrity.md +17 -0
- package/pack/generated/omp/skills/devrites-lib/reference/orchestration-profiles.md +20 -0
- package/pack/generated/omp/skills/devrites-lib/reference/parallel-dispatch.md +36 -4
- package/pack/generated/omp/skills/devrites-lib/reference/reply-contract.md +24 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/README.md +10 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/acceptance-preserving-reslice.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/agents.md +21 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/anti-patterns.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/architecture-health.md +64 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/assumption-checkpoints.md +42 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/audit-coverage.md +103 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/browser-proof-checklist.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/ci-cd.md +11 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/code-navigation.md +71 -4
- package/pack/generated/omp/skills/devrites-lib/reference/standards/code-review.md +67 -7
- package/pack/generated/omp/skills/devrites-lib/reference/standards/coding-style.md +9 -4
- package/pack/generated/omp/skills/devrites-lib/reference/standards/context-hygiene.md +20 -3
- package/pack/generated/omp/skills/devrites-lib/reference/standards/core.md +10 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/data-integrity.md +24 -2
- package/pack/generated/omp/skills/devrites-lib/reference/standards/debug-recovery.md +14 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/definition-of-done.md +6 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/deprecation.md +18 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/developer-experience.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/development-workflow.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/documentation.md +12 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/duplicate-code.md +118 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/edge-case-trace.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/elicitation.md +29 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/error-handling.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/gates.md +117 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/git-workflow.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/glossary.md +40 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/hooks.md +16 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/integration-reliability.md +19 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/loop-operations.md +32 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/observability.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/one-shot-actions.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/patterns.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/performance.md +8 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/principles.md +14 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/prose-style.md +3 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/release/ship-checklist.md +4 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/repository-topology.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/review/README.md +23 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/review/ci-workflows.md +50 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/review/default.md +42 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/review/go.md +47 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/review/python.md +46 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/review/shell.md +40 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/review/ts-js.md +54 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/review-checklist.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/security-checklist.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/security.md +58 -6
- package/pack/generated/omp/skills/devrites-lib/reference/standards/skill-authoring.md +48 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/spec-grammar.md +18 -4
- package/pack/generated/omp/skills/devrites-lib/reference/standards/test-proof-checklist.md +5 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/testing.md +19 -2
- package/pack/generated/omp/skills/devrites-lib/reference/standards/tooling.md +12 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/verification-methods.md +110 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/windows.md +51 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +28 -3
- package/pack/generated/omp/skills/devrites-prose-craft/SKILL.md +3 -1
- package/pack/generated/omp/skills/devrites-source-driven/SKILL.md +2 -0
- package/pack/generated/omp/skills/devrites-ux-shape/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-adopt/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +6 -1
- package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +7 -1
- package/pack/generated/omp/skills/rite-build/SKILL.md +28 -14
- package/pack/generated/omp/skills/rite-build/reference/checkpoint.md +6 -0
- package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +11 -2
- package/pack/generated/omp/skills/rite-build/reference/phase-contract.md +8 -4
- package/pack/generated/omp/skills/rite-build/reference/wright-dispatch.md +34 -8
- package/pack/generated/omp/skills/rite-clarify/SKILL.md +4 -0
- package/pack/generated/omp/skills/rite-converge/SKILL.md +14 -2
- package/pack/generated/omp/skills/rite-customize/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-define/SKILL.md +8 -2
- package/pack/generated/omp/skills/rite-doctor/SKILL.md +6 -1
- package/pack/generated/omp/skills/rite-dogfood/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-explain/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-frame/SKILL.md +4 -0
- package/pack/generated/omp/skills/rite-handoff/SKILL.md +8 -1
- package/pack/generated/omp/skills/rite-learn/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-plan/SKILL.md +6 -0
- package/pack/generated/omp/skills/rite-plan/reference/task-breakdown.md +3 -1
- package/pack/generated/omp/skills/rite-polish/SKILL.md +13 -2
- package/pack/generated/omp/skills/rite-polish/reference/code.md +6 -1
- package/pack/generated/omp/skills/rite-polish/reference/ledger.md +3 -1
- package/pack/generated/omp/skills/rite-pov/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-pr-feedback/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-pressure-test/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-prototype/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-prove/SKILL.md +17 -3
- package/pack/generated/omp/skills/rite-prove/reference/test-command-discovery.md +6 -0
- package/pack/generated/omp/skills/rite-quick/SKILL.md +7 -1
- package/pack/generated/omp/skills/rite-resolve/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-review/SKILL.md +5 -1
- package/pack/generated/omp/skills/rite-review/reference/performance-checklist.md +14 -3
- package/pack/generated/omp/skills/rite-seal/SKILL.md +27 -3
- package/pack/generated/omp/skills/rite-seal/reference/go-no-go.md +1 -0
- package/pack/generated/omp/skills/rite-seal/reference/phase-contract.md +3 -1
- package/pack/generated/omp/skills/rite-ship/SKILL.md +5 -1
- package/pack/generated/omp/skills/rite-spec/SKILL.md +10 -3
- package/pack/generated/omp/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/omp/skills/rite-status/SKILL.md +9 -0
- package/pack/generated/omp/skills/rite-temper/SKILL.md +5 -1
- package/pack/generated/omp/skills/rite-upgrade/SKILL.md +9 -1
- package/pack/generated/omp/skills/rite-vet/SKILL.md +28 -6
- package/pack/generated/omp/skills/rite-vet/reference/artifacts.md +19 -0
- package/pack/generated/omp/skills/rite-vet/reference/review-axes.md +5 -0
- package/pack/generated/omp/skills/rite-watch-pr/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-zoom-out/SKILL.md +2 -0
- package/pack/generated/pi/agents/devrites-code-reviewer.md +16 -0
- package/pack/generated/pi/agents/devrites-security-auditor.md +22 -0
- package/pack/generated/pi/agents/devrites-simplifier-reviewer.md +12 -2
- package/pack/generated/pi/skills/devrites-api-interface/SKILL.md +2 -0
- package/pack/generated/pi/skills/devrites-audit/SKILL.md +9 -0
- package/pack/generated/pi/skills/devrites-browser-proof/SKILL.md +2 -0
- package/pack/generated/pi/skills/devrites-debug-recovery/SKILL.md +2 -0
- package/pack/generated/pi/skills/devrites-doubt/SKILL.md +2 -0
- package/pack/generated/pi/skills/devrites-frontend-craft/SKILL.md +2 -0
- package/pack/generated/pi/skills/devrites-frontend-craft/reference/design-references.md +4 -0
- package/pack/generated/pi/skills/devrites-frontend-craft/reference/shape.md +5 -0
- package/pack/generated/pi/skills/devrites-interview/SKILL.md +5 -0
- package/pack/generated/pi/skills/devrites-lib/SKILL.md +40 -5
- package/pack/generated/pi/skills/devrites-lib/reference/candidate-integrity.md +17 -0
- package/pack/generated/pi/skills/devrites-lib/reference/orchestration-profiles.md +20 -0
- package/pack/generated/pi/skills/devrites-lib/reference/parallel-dispatch.md +36 -4
- package/pack/generated/pi/skills/devrites-lib/reference/reply-contract.md +24 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/README.md +10 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/acceptance-preserving-reslice.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/agents.md +21 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/anti-patterns.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/architecture-health.md +64 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/assumption-checkpoints.md +42 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/audit-coverage.md +103 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/browser-proof-checklist.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/ci-cd.md +11 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/code-navigation.md +71 -4
- package/pack/generated/pi/skills/devrites-lib/reference/standards/code-review.md +67 -7
- package/pack/generated/pi/skills/devrites-lib/reference/standards/coding-style.md +9 -4
- package/pack/generated/pi/skills/devrites-lib/reference/standards/context-hygiene.md +20 -3
- package/pack/generated/pi/skills/devrites-lib/reference/standards/core.md +10 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/data-integrity.md +24 -2
- package/pack/generated/pi/skills/devrites-lib/reference/standards/debug-recovery.md +14 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/definition-of-done.md +6 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/deprecation.md +18 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/developer-experience.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/development-workflow.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/documentation.md +12 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/duplicate-code.md +118 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/edge-case-trace.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/elicitation.md +29 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/error-handling.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/gates.md +117 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/git-workflow.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/glossary.md +40 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/hooks.md +16 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/integration-reliability.md +19 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/loop-operations.md +32 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/observability.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/one-shot-actions.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/patterns.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/performance.md +8 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/principles.md +14 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/prose-style.md +3 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/release/ship-checklist.md +4 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/repository-topology.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/review/README.md +23 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/review/ci-workflows.md +50 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/review/default.md +42 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/review/go.md +47 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/review/python.md +46 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/review/shell.md +40 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/review/ts-js.md +54 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/review-checklist.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/security-checklist.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/security.md +58 -6
- package/pack/generated/pi/skills/devrites-lib/reference/standards/skill-authoring.md +48 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/spec-grammar.md +18 -4
- package/pack/generated/pi/skills/devrites-lib/reference/standards/test-proof-checklist.md +5 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/testing.md +19 -2
- package/pack/generated/pi/skills/devrites-lib/reference/standards/tooling.md +12 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/verification-methods.md +110 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/windows.md +51 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/workspace-artifact-schema.md +28 -3
- package/pack/generated/pi/skills/devrites-prose-craft/SKILL.md +3 -1
- package/pack/generated/pi/skills/devrites-source-driven/SKILL.md +2 -0
- package/pack/generated/pi/skills/devrites-ux-shape/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-adopt/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +6 -1
- package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +7 -1
- package/pack/generated/pi/skills/rite-build/SKILL.md +28 -14
- package/pack/generated/pi/skills/rite-build/reference/checkpoint.md +6 -0
- package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +11 -2
- package/pack/generated/pi/skills/rite-build/reference/phase-contract.md +8 -4
- package/pack/generated/pi/skills/rite-build/reference/wright-dispatch.md +34 -8
- package/pack/generated/pi/skills/rite-clarify/SKILL.md +4 -0
- package/pack/generated/pi/skills/rite-converge/SKILL.md +14 -2
- package/pack/generated/pi/skills/rite-customize/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-define/SKILL.md +8 -2
- package/pack/generated/pi/skills/rite-doctor/SKILL.md +6 -1
- package/pack/generated/pi/skills/rite-dogfood/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-explain/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-frame/SKILL.md +4 -0
- package/pack/generated/pi/skills/rite-handoff/SKILL.md +8 -1
- package/pack/generated/pi/skills/rite-learn/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-plan/SKILL.md +6 -0
- package/pack/generated/pi/skills/rite-plan/reference/task-breakdown.md +3 -1
- package/pack/generated/pi/skills/rite-polish/SKILL.md +13 -2
- package/pack/generated/pi/skills/rite-polish/reference/code.md +6 -1
- package/pack/generated/pi/skills/rite-polish/reference/ledger.md +3 -1
- package/pack/generated/pi/skills/rite-pov/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-pr-feedback/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-pressure-test/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-prototype/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-prove/SKILL.md +17 -3
- package/pack/generated/pi/skills/rite-prove/reference/test-command-discovery.md +6 -0
- package/pack/generated/pi/skills/rite-quick/SKILL.md +7 -1
- package/pack/generated/pi/skills/rite-resolve/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-review/SKILL.md +5 -1
- package/pack/generated/pi/skills/rite-review/reference/performance-checklist.md +14 -3
- package/pack/generated/pi/skills/rite-seal/SKILL.md +27 -3
- package/pack/generated/pi/skills/rite-seal/reference/go-no-go.md +1 -0
- package/pack/generated/pi/skills/rite-seal/reference/phase-contract.md +3 -1
- package/pack/generated/pi/skills/rite-ship/SKILL.md +5 -1
- package/pack/generated/pi/skills/rite-spec/SKILL.md +10 -3
- package/pack/generated/pi/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/pi/skills/rite-status/SKILL.md +9 -0
- package/pack/generated/pi/skills/rite-temper/SKILL.md +5 -1
- package/pack/generated/pi/skills/rite-upgrade/SKILL.md +9 -1
- package/pack/generated/pi/skills/rite-vet/SKILL.md +28 -6
- package/pack/generated/pi/skills/rite-vet/reference/artifacts.md +19 -0
- package/pack/generated/pi/skills/rite-vet/reference/review-axes.md +5 -0
- package/pack/generated/pi/skills/rite-watch-pr/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-zoom-out/SKILL.md +2 -0
- package/package.json +1 -1
- package/scripts/build-host-artifacts.sh +48 -2
|
@@ -0,0 +1,1243 @@
|
|
|
1
|
+
package lib
|
|
2
|
+
|
|
3
|
+
// dup.go — deterministic near-duplicate detection.
|
|
4
|
+
//
|
|
5
|
+
// `devrites-engine check dup` finds structurally identical code regions —
|
|
6
|
+
// copies that survive renaming and reformatting — with no model and no
|
|
7
|
+
// network. Reviewers catch verbatim paste; this catches the same block
|
|
8
|
+
// re-typed with different identifiers, which is the class that review
|
|
9
|
+
// memory misses in large trees.
|
|
10
|
+
//
|
|
11
|
+
// Method: strip comments and strings, tokenize each line (keywords and
|
|
12
|
+
// punctuation kept, identifiers/numbers/string literals erased), then
|
|
13
|
+
// match k-line shingles across files and chain co-linear anchor hits into
|
|
14
|
+
// segment pairs. Pairs merge into transitive clusters ranked by similarity
|
|
15
|
+
// boosted by distance — a twin two modules away matters more than a twin
|
|
16
|
+
// in the same file. Each cluster gets a stable content hash so a dismissed
|
|
17
|
+
// cluster stays dismissed in .devrites/dup-ignore until the code changes.
|
|
18
|
+
//
|
|
19
|
+
// devrites-engine check dup [slug] [--all|--worktree|--staged|--base <ref>]
|
|
20
|
+
// [--min-lines n] [--threshold f] [--ignore-file <path>] [--limit n]
|
|
21
|
+
// [--exclude <csv>] [--cwd <dir>]
|
|
22
|
+
//
|
|
23
|
+
// Successful scans exit 0; usage or incomplete scans exit 2. Clusters are
|
|
24
|
+
// leads for reviewer adjudication, not a gate. A reported cluster is an unverified claim until a reader
|
|
25
|
+
// confirms the regions are genuinely interchangeable.
|
|
26
|
+
|
|
27
|
+
import (
|
|
28
|
+
"bytes"
|
|
29
|
+
"crypto/sha256"
|
|
30
|
+
"encoding/hex"
|
|
31
|
+
"fmt"
|
|
32
|
+
"hash/fnv"
|
|
33
|
+
"io"
|
|
34
|
+
"math"
|
|
35
|
+
"os"
|
|
36
|
+
"path"
|
|
37
|
+
"path/filepath"
|
|
38
|
+
"sort"
|
|
39
|
+
"strconv"
|
|
40
|
+
"strings"
|
|
41
|
+
|
|
42
|
+
"github.com/devrites/devrites/internal/devritespaths"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
const dupUsage = `usage: devrites-engine check dup [slug] [--all|--worktree|--staged|--base <ref>] [--min-lines n] [--threshold f] [--ignore-file <path>] [--limit n] [--exclude <csv>] [--phase p] [--cwd <dir>]
|
|
46
|
+
|
|
47
|
+
Finds near-duplicate code regions that survive renaming: comment/string-stripped
|
|
48
|
+
token shingles are matched across files, chained into segment pairs, clustered,
|
|
49
|
+
and ranked by similarity boosted by distance. In diff modes only clusters
|
|
50
|
+
touching changed lines print, with changed units marked '*'.
|
|
51
|
+
Ignore file: one cluster hash per line, '# comment' allowed; default
|
|
52
|
+
.devrites/dup-ignore. Advisory: exit 0 on success, 2 on usage or scan errors; clusters are leads for review.`
|
|
53
|
+
|
|
54
|
+
const (
|
|
55
|
+
dupMaxFiles = 8192
|
|
56
|
+
dupMaxBytes = 64 << 20
|
|
57
|
+
dupMaxFileBytes = 1 << 20
|
|
58
|
+
dupShingleLines = 3
|
|
59
|
+
dupMaxPostings = 32
|
|
60
|
+
dupMaxPairAnchors = 8192
|
|
61
|
+
dupMergeGap = 4
|
|
62
|
+
dupMaxClusters = 200
|
|
63
|
+
dupHashLength = 12
|
|
64
|
+
dupCrossDirMaxHops = 8
|
|
65
|
+
dupCrossDirBoost = 0.15
|
|
66
|
+
dupSameFileMaxStep = 8
|
|
67
|
+
dupSameFileBoost = 0.10
|
|
68
|
+
dupSameFileStepLn = 250
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
// dupCommentStyle names the comment syntax used to strip noise before
|
|
72
|
+
// tokenizing. Languages sharing a style share one table entry.
|
|
73
|
+
type dupCommentStyle struct {
|
|
74
|
+
line []string
|
|
75
|
+
blocks [][2]string
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
var (
|
|
79
|
+
dupCStyle = dupCommentStyle{line: []string{"//"}, blocks: [][2]string{{"/*", "*/"}}}
|
|
80
|
+
dupHashStyle = dupCommentStyle{line: []string{"#"}, blocks: [][2]string{{"<#", "#>"}}}
|
|
81
|
+
dupDashStyle = dupCommentStyle{line: []string{"--"}, blocks: [][2]string{{"{-", "-}"}}}
|
|
82
|
+
dupSemiStyle = dupCommentStyle{line: []string{";"}}
|
|
83
|
+
dupPctStyle = dupCommentStyle{line: []string{"%"}}
|
|
84
|
+
dupXMLStyle = dupCommentStyle{blocks: [][2]string{{"<!--", "-->"}}}
|
|
85
|
+
dupCSSStyle = dupCommentStyle{blocks: [][2]string{{"/*", "*/"}}}
|
|
86
|
+
dupMixedWeb = dupCommentStyle{line: []string{"//"}, blocks: [][2]string{{"/*", "*/"}, {"<!--", "-->"}}}
|
|
87
|
+
dupShellCfg = dupCommentStyle{line: []string{"#", "//"}, blocks: [][2]string{{"/*", "*/"}}}
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
// dupStyleByExt maps a lowercase file extension (with dot) to its comment
|
|
91
|
+
// style. Extensions absent here are not scanned: prose, data, and lockfile
|
|
92
|
+
// formats produce shingle noise, not reviewable duplication.
|
|
93
|
+
var dupStyleByExt = map[string]dupCommentStyle{
|
|
94
|
+
".go": dupCStyle, ".c": dupCStyle, ".h": dupCStyle,
|
|
95
|
+
".cpp": dupCStyle, ".cc": dupCStyle, ".cxx": dupCStyle,
|
|
96
|
+
".hpp": dupCStyle, ".hh": dupCStyle, ".m": dupCStyle, ".mm": dupCStyle,
|
|
97
|
+
".java": dupCStyle, ".kt": dupCStyle, ".kts": dupCStyle,
|
|
98
|
+
".scala": dupCStyle, ".groovy": dupCStyle, ".gradle": dupCStyle,
|
|
99
|
+
".js": dupCStyle, ".jsx": dupCStyle, ".mjs": dupCStyle, ".cjs": dupCStyle,
|
|
100
|
+
".ts": dupCStyle, ".tsx": dupCStyle, ".cts": dupCStyle, ".mts": dupCStyle,
|
|
101
|
+
".rs": dupCStyle, ".swift": dupCStyle, ".cs": dupCStyle,
|
|
102
|
+
".php": dupCStyle, ".phtml": dupCStyle, ".dart": dupCStyle,
|
|
103
|
+
".zig": dupCStyle, ".proto": dupCStyle, ".prisma": dupCStyle,
|
|
104
|
+
".gd": dupCStyle, ".nim": dupCStyle, ".vala": dupCStyle,
|
|
105
|
+
".py": dupHashStyle, ".pyi": dupHashStyle, ".rb": dupHashStyle,
|
|
106
|
+
".sh": dupHashStyle, ".bash": dupHashStyle, ".zsh": dupHashStyle,
|
|
107
|
+
".fish": dupHashStyle, ".pl": dupHashStyle, ".pm": dupHashStyle,
|
|
108
|
+
".r": dupHashStyle, ".jl": dupHashStyle, ".ex": dupHashStyle,
|
|
109
|
+
".exs": dupHashStyle, ".yaml": dupHashStyle, ".yml": dupHashStyle,
|
|
110
|
+
".toml": dupHashStyle, ".tf": dupShellCfg, ".hcl": dupShellCfg,
|
|
111
|
+
".graphql": dupHashStyle, ".gql": dupHashStyle, ".ps1": dupHashStyle,
|
|
112
|
+
".psm1": dupHashStyle, ".coffee": dupHashStyle, ".cr": dupHashStyle,
|
|
113
|
+
".sql": dupDashStyle, ".lua": dupDashStyle, ".hs": dupDashStyle,
|
|
114
|
+
".lhs": dupDashStyle, ".elm": dupDashStyle, ".ada": dupDashStyle,
|
|
115
|
+
".adb": dupDashStyle, ".ads": dupDashStyle,
|
|
116
|
+
".clj": dupSemiStyle, ".cljs": dupSemiStyle, ".lisp": dupSemiStyle,
|
|
117
|
+
".scm": dupSemiStyle, ".rkt": dupSemiStyle,
|
|
118
|
+
".erl": dupPctStyle, ".hrl": dupPctStyle, ".tex": dupPctStyle,
|
|
119
|
+
".html": dupXMLStyle, ".htm": dupXMLStyle, ".xml": dupXMLStyle,
|
|
120
|
+
".xhtml": dupXMLStyle, ".csproj": dupXMLStyle, ".fsproj": dupXMLStyle,
|
|
121
|
+
".css": dupCSSStyle,
|
|
122
|
+
".scss": dupCStyle, ".less": dupCStyle, ".sass": dupHashStyle,
|
|
123
|
+
".vue": dupMixedWeb, ".svelte": dupMixedWeb,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// dupStyleByName covers extensionless code files worth scanning.
|
|
127
|
+
var dupStyleByName = map[string]dupCommentStyle{
|
|
128
|
+
"dockerfile": dupHashStyle, "containerfile": dupHashStyle,
|
|
129
|
+
"makefile": dupHashStyle, "gnumakefile": dupHashStyle,
|
|
130
|
+
"rakefile": dupHashStyle, "gemfile": dupHashStyle,
|
|
131
|
+
"vagrantfile": dupHashStyle, "brewfile": dupHashStyle,
|
|
132
|
+
"cmakelists.txt": dupHashStyle, "justfile": dupHashStyle,
|
|
133
|
+
"jenkinsfile": dupCStyle, "podfile": dupHashStyle,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// dupSkipPrefixes are vendored or fixture trees where duplication is
|
|
137
|
+
// deliberate or out of the author's control.
|
|
138
|
+
var dupSkipPrefixes = []string{
|
|
139
|
+
"vendor/", "node_modules/", "third_party/", "external/", "extern/",
|
|
140
|
+
"testdata/", ".devrites/", ".git/",
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// dupKeywords is one union keyword set across the scanned language families.
|
|
144
|
+
// Keeping control/declaration words verbatim preserves the skeleton
|
|
145
|
+
// difference between `if` and `while`; every other word collapses to `id`,
|
|
146
|
+
// which is what lets renamed copies match.
|
|
147
|
+
var dupKeywords = map[string]bool{
|
|
148
|
+
"if": true, "else": true, "elif": true, "for": true, "while": true,
|
|
149
|
+
"do": true, "switch": true, "case": true, "default": true,
|
|
150
|
+
"break": true, "continue": true, "return": true, "goto": true,
|
|
151
|
+
"func": true, "function": true, "fn": true, "def": true,
|
|
152
|
+
"lambda": true, "class": true, "struct": true, "interface": true,
|
|
153
|
+
"impl": true, "enum": true, "trait": true, "type": true,
|
|
154
|
+
"package": true, "import": true, "from": true, "use": true,
|
|
155
|
+
"mod": true, "pub": true, "let": true, "const": true, "var": true,
|
|
156
|
+
"val": true, "mut": true, "ref": true, "static": true,
|
|
157
|
+
"try": true, "catch": true, "except": true, "finally": true,
|
|
158
|
+
"throw": true, "throws": true, "raise": true, "rescue": true,
|
|
159
|
+
"ensure": true, "async": true, "await": true, "yield": true,
|
|
160
|
+
"go": true, "defer": true, "select": true, "chan": true,
|
|
161
|
+
"public": true, "private": true, "protected": true, "final": true,
|
|
162
|
+
"abstract": true, "override": true, "virtual": true, "internal": true,
|
|
163
|
+
"sealed": true, "new": true, "delete": true, "this": true,
|
|
164
|
+
"self": true, "super": true, "extends": true, "implements": true,
|
|
165
|
+
"nil": true, "null": true, "none": true, "undefined": true,
|
|
166
|
+
"true": true, "false": true, "and": true, "or": true, "not": true,
|
|
167
|
+
"in": true, "is": true, "of": true, "as": true, "with": true,
|
|
168
|
+
"where": true, "when": true, "match": true, "then": true,
|
|
169
|
+
"begin": true, "end": true, "elsif": true, "until": true,
|
|
170
|
+
"unless": true, "repeat": true, "void": true, "int": true,
|
|
171
|
+
"long": true, "short": true, "float": true, "double": true,
|
|
172
|
+
"bool": true, "char": true, "string": true, "byte": true,
|
|
173
|
+
"rune": true, "uint": true, "export": true, "declare": true,
|
|
174
|
+
"namespace": true, "module": true, "fi": true, "esac": true,
|
|
175
|
+
"done": true, "local": true, "readonly": true, "eval": true,
|
|
176
|
+
"echo": true, "sizeof": true, "typeof": true, "instanceof": true,
|
|
177
|
+
"macro": true, "unsafe": true, "extern": true, "inline": true,
|
|
178
|
+
"typedef": true, "union": true, "volatile": true, "const_cast": true,
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
type dupFile struct {
|
|
182
|
+
path string
|
|
183
|
+
lines []dupLine
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
type dupLine struct {
|
|
187
|
+
tokens string // canonical token stream; "" when the line carried nothing
|
|
188
|
+
trivial bool // single punctuation/keyword line that still pads spans
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
type dupPos struct {
|
|
192
|
+
file int
|
|
193
|
+
line int // index into dupFile.lines (0-based)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
type dupAnchor struct {
|
|
197
|
+
aLine int
|
|
198
|
+
bLine int
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
type dupPairKey struct {
|
|
202
|
+
a int
|
|
203
|
+
b int
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
type dupSegment struct {
|
|
207
|
+
aFile, bFile int
|
|
208
|
+
aStart, aEnd int // 0-based inclusive line indexes into dupFile.lines
|
|
209
|
+
bStart, bEnd int
|
|
210
|
+
anchors int
|
|
211
|
+
score, boosted float64
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
type dupUnit struct {
|
|
215
|
+
file int
|
|
216
|
+
start, end int // 0-based inclusive
|
|
217
|
+
contentHash string
|
|
218
|
+
changed bool
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
type dupEdge struct {
|
|
222
|
+
a, b int // unit indexes
|
|
223
|
+
boosted float64
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
type dupCluster struct {
|
|
227
|
+
units []int
|
|
228
|
+
score float64 // max boosted edge inside the cluster
|
|
229
|
+
hash string
|
|
230
|
+
changed bool
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// normalizeDupSource strips comments and strings then canonicalizes each
|
|
234
|
+
// line into a token stream. The result keeps line indexes aligned with the
|
|
235
|
+
// source file so reported ranges stay true line numbers.
|
|
236
|
+
func normalizeDupSource(raw string, style dupCommentStyle) []dupLine {
|
|
237
|
+
srcLines := strings.Split(strings.ReplaceAll(raw, "\r\n", "\n"), "\n")
|
|
238
|
+
out := make([]dupLine, len(srcLines))
|
|
239
|
+
var blockEnd string
|
|
240
|
+
for i, src := range srcLines {
|
|
241
|
+
var b strings.Builder
|
|
242
|
+
for j := 0; j < len(src); {
|
|
243
|
+
if blockEnd != "" {
|
|
244
|
+
if k := strings.Index(src[j:], blockEnd); k >= 0 {
|
|
245
|
+
j += k + len(blockEnd)
|
|
246
|
+
blockEnd = ""
|
|
247
|
+
} else {
|
|
248
|
+
break
|
|
249
|
+
}
|
|
250
|
+
continue
|
|
251
|
+
}
|
|
252
|
+
matched := false
|
|
253
|
+
for _, marker := range style.line {
|
|
254
|
+
if strings.HasPrefix(src[j:], marker) {
|
|
255
|
+
j = len(src)
|
|
256
|
+
matched = true
|
|
257
|
+
break
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if matched || j >= len(src) {
|
|
261
|
+
break
|
|
262
|
+
}
|
|
263
|
+
for _, pair := range style.blocks {
|
|
264
|
+
if strings.HasPrefix(src[j:], pair[0]) {
|
|
265
|
+
blockEnd = pair[1]
|
|
266
|
+
j += len(pair[0])
|
|
267
|
+
matched = true
|
|
268
|
+
break
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if matched {
|
|
272
|
+
continue
|
|
273
|
+
}
|
|
274
|
+
c := src[j]
|
|
275
|
+
if c == '\'' || c == '"' || c == '`' {
|
|
276
|
+
b.WriteString(" \x01")
|
|
277
|
+
j++
|
|
278
|
+
for j < len(src) && src[j] != c {
|
|
279
|
+
if src[j] == '\\' && c != '`' {
|
|
280
|
+
j++
|
|
281
|
+
}
|
|
282
|
+
j++
|
|
283
|
+
}
|
|
284
|
+
if j < len(src) {
|
|
285
|
+
j++
|
|
286
|
+
}
|
|
287
|
+
continue
|
|
288
|
+
}
|
|
289
|
+
b.WriteByte(c)
|
|
290
|
+
j++
|
|
291
|
+
}
|
|
292
|
+
out[i] = canonicalizeDupLine(b.String())
|
|
293
|
+
}
|
|
294
|
+
return out
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// canonicalizeDupLine reduces one comment-free line to a space-joined token
|
|
298
|
+
// string: keywords and punctuation verbatim, identifiers → id, numbers → 0,
|
|
299
|
+
// strings already → s. Fewer than two tokens is a trivial line; it still
|
|
300
|
+
// participates as the wildcard `_` so a copied block stays contiguous.
|
|
301
|
+
func canonicalizeDupLine(text string) dupLine {
|
|
302
|
+
var tokens []string
|
|
303
|
+
for i := 0; i < len(text); {
|
|
304
|
+
c := text[i]
|
|
305
|
+
switch {
|
|
306
|
+
case c == ' ' || c == '\t':
|
|
307
|
+
i++
|
|
308
|
+
case c == '\x01':
|
|
309
|
+
tokens = append(tokens, "s")
|
|
310
|
+
i++
|
|
311
|
+
case isDupIdentStart(c):
|
|
312
|
+
j := i + 1
|
|
313
|
+
for j < len(text) && isDupIdentPart(text[j]) {
|
|
314
|
+
j++
|
|
315
|
+
}
|
|
316
|
+
word := strings.ToLower(text[i:j])
|
|
317
|
+
if dupKeywords[word] {
|
|
318
|
+
tokens = append(tokens, word)
|
|
319
|
+
} else {
|
|
320
|
+
tokens = append(tokens, "id")
|
|
321
|
+
}
|
|
322
|
+
i = j
|
|
323
|
+
case c >= '0' && c <= '9':
|
|
324
|
+
j := i + 1
|
|
325
|
+
for j < len(text) && (isDupIdentPart(text[j]) || text[j] == '.') {
|
|
326
|
+
j++
|
|
327
|
+
}
|
|
328
|
+
tokens = append(tokens, "0")
|
|
329
|
+
i = j
|
|
330
|
+
default:
|
|
331
|
+
tokens = append(tokens, string(c))
|
|
332
|
+
i++
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if len(tokens) < 2 {
|
|
336
|
+
return dupLine{tokens: "_", trivial: true}
|
|
337
|
+
}
|
|
338
|
+
return dupLine{tokens: strings.Join(tokens, " ")}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
func isDupIdentStart(c byte) bool {
|
|
342
|
+
return c == '_' || c == '$' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= 0x80
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
func isDupIdentPart(c byte) bool {
|
|
346
|
+
return isDupIdentStart(c) || c >= '0' && c <= '9'
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// dupShingle is the fnv64a fingerprint of dupShingleLines consecutive
|
|
350
|
+
// canonical lines.
|
|
351
|
+
func dupShingleHash(lines []dupLine, start int) uint64 {
|
|
352
|
+
h := fnv.New64a()
|
|
353
|
+
for i := start; i < start+dupShingleLines; i++ {
|
|
354
|
+
_, _ = h.Write([]byte(lines[i].tokens))
|
|
355
|
+
_, _ = h.Write([]byte{0})
|
|
356
|
+
}
|
|
357
|
+
return h.Sum64()
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// dupAnchorSegments chains shared-shingle hits between one file pair into
|
|
361
|
+
// maximal similar segments. Hits merge when both sides advance by at most
|
|
362
|
+
// dupMergeGap lines, so copies light edits stay one segment.
|
|
363
|
+
func dupAnchorSegments(key dupPairKey, anchors []dupAnchor, files []dupFile, minLines int, threshold float64) []dupSegment {
|
|
364
|
+
if len(anchors) == 0 {
|
|
365
|
+
return nil
|
|
366
|
+
}
|
|
367
|
+
sort.Slice(anchors, func(i, j int) bool {
|
|
368
|
+
if anchors[i].aLine != anchors[j].aLine {
|
|
369
|
+
return anchors[i].aLine < anchors[j].aLine
|
|
370
|
+
}
|
|
371
|
+
return anchors[i].bLine < anchors[j].bLine
|
|
372
|
+
})
|
|
373
|
+
var segs []dupSegment
|
|
374
|
+
start := 0
|
|
375
|
+
for i := 1; i <= len(anchors); i++ {
|
|
376
|
+
split := i == len(anchors) ||
|
|
377
|
+
anchors[i].aLine-anchors[i-1].aLine > dupMergeGap ||
|
|
378
|
+
abs(anchors[i].bLine-anchors[i-1].bLine) > dupMergeGap
|
|
379
|
+
if !split {
|
|
380
|
+
continue
|
|
381
|
+
}
|
|
382
|
+
run := anchors[start:i]
|
|
383
|
+
start = i
|
|
384
|
+
seg := dupSegment{
|
|
385
|
+
aFile: key.a, bFile: key.b,
|
|
386
|
+
aStart: run[0].aLine, aEnd: run[len(run)-1].aLine + dupShingleLines - 1,
|
|
387
|
+
bStart: run[0].bLine, bEnd: run[len(run)-1].bLine + dupShingleLines - 1,
|
|
388
|
+
anchors: len(run),
|
|
389
|
+
}
|
|
390
|
+
spanA := seg.aEnd - seg.aStart + 1
|
|
391
|
+
spanB := seg.bEnd - seg.bStart + 1
|
|
392
|
+
if spanA < minLines || spanB < minLines {
|
|
393
|
+
continue
|
|
394
|
+
}
|
|
395
|
+
if key.a == key.b && seg.aEnd >= seg.bStart {
|
|
396
|
+
continue // overlapping same-file windows are one region, not a pair
|
|
397
|
+
}
|
|
398
|
+
possible := max(spanA, spanB) - dupShingleLines + 1
|
|
399
|
+
seg.score = min(float64(seg.anchors)/float64(possible), 1.0)
|
|
400
|
+
if seg.score < threshold {
|
|
401
|
+
continue
|
|
402
|
+
}
|
|
403
|
+
seg.boosted = seg.score * (1 + dupDistanceBoost(files[key.a].path, files[key.b].path, seg))
|
|
404
|
+
segs = append(segs, seg)
|
|
405
|
+
}
|
|
406
|
+
return segs
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// dupDistanceBoost lifts pairs that sit far apart: a twin across modules
|
|
410
|
+
// hides from review where a twin one screen down does not. Same-file
|
|
411
|
+
// distance counts in 250-line steps; cross-file distance counts directory
|
|
412
|
+
// hops from the deepest common ancestor. Both boosts are log-scaled caps
|
|
413
|
+
// ported from the embedding-detector playbook.
|
|
414
|
+
func dupDistanceBoost(pathA, pathB string, seg dupSegment) float64 {
|
|
415
|
+
if pathA == pathB {
|
|
416
|
+
gap := seg.bStart - seg.aEnd
|
|
417
|
+
if gap < 0 {
|
|
418
|
+
gap = 0
|
|
419
|
+
}
|
|
420
|
+
steps := min(gap/dupSameFileStepLn, dupSameFileMaxStep)
|
|
421
|
+
if steps <= 0 {
|
|
422
|
+
return 0
|
|
423
|
+
}
|
|
424
|
+
return math.Log2(1+float64(steps)) / math.Log2(1+dupSameFileMaxStep) * dupSameFileBoost
|
|
425
|
+
}
|
|
426
|
+
da := strings.Split(path.Dir(pathA), "/")
|
|
427
|
+
db := strings.Split(path.Dir(pathB), "/")
|
|
428
|
+
common := 0
|
|
429
|
+
for common < len(da) && common < len(db) && da[common] == db[common] {
|
|
430
|
+
common++
|
|
431
|
+
}
|
|
432
|
+
hops := (len(da) - common) + (len(db) - common)
|
|
433
|
+
if hops <= 0 {
|
|
434
|
+
return 0
|
|
435
|
+
}
|
|
436
|
+
hops = min(hops, dupCrossDirMaxHops)
|
|
437
|
+
return math.Log2(1+float64(hops)) / math.Log2(1+dupCrossDirMaxHops) * dupCrossDirBoost
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// dupClusterUnits merges per-file ranges into units, unions segments into
|
|
441
|
+
// transitive clusters, and orders clusters by their strongest boosted pair.
|
|
442
|
+
func dupClusterUnits(segs []dupSegment, files []dupFile) ([]dupCluster, []dupUnit, []dupEdge) {
|
|
443
|
+
// Merge each file's overlapping/adjacent ranges into units.
|
|
444
|
+
perFile := map[int][]dupUnit{}
|
|
445
|
+
for _, s := range segs {
|
|
446
|
+
perFile[s.aFile] = append(perFile[s.aFile], dupUnit{file: s.aFile, start: s.aStart, end: s.aEnd})
|
|
447
|
+
perFile[s.bFile] = append(perFile[s.bFile], dupUnit{file: s.bFile, start: s.bStart, end: s.bEnd})
|
|
448
|
+
}
|
|
449
|
+
var units []dupUnit
|
|
450
|
+
for f, list := range perFile {
|
|
451
|
+
sort.Slice(list, func(i, j int) bool { return list[i].start < list[j].start })
|
|
452
|
+
var merged []dupUnit
|
|
453
|
+
for _, u := range list {
|
|
454
|
+
if n := len(merged); n > 0 && u.start <= merged[n-1].end+2 {
|
|
455
|
+
if u.end > merged[n-1].end {
|
|
456
|
+
merged[n-1].end = u.end
|
|
457
|
+
}
|
|
458
|
+
continue
|
|
459
|
+
}
|
|
460
|
+
merged = append(merged, u)
|
|
461
|
+
}
|
|
462
|
+
for _, u := range merged {
|
|
463
|
+
u.contentHash = dupUnitHash(files[f].lines[u.start : u.end+1])
|
|
464
|
+
units = append(units, u)
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
// Locate the unit covering a segment endpoint: same file, maximal overlap.
|
|
468
|
+
unitIndex := func(file, start, end int) int {
|
|
469
|
+
best, bestOverlap := -1, 0
|
|
470
|
+
for i, u := range units {
|
|
471
|
+
if u.file != file {
|
|
472
|
+
continue
|
|
473
|
+
}
|
|
474
|
+
ov := min(u.end, end) - max(u.start, start) + 1
|
|
475
|
+
if ov > bestOverlap {
|
|
476
|
+
best, bestOverlap = i, ov
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return best
|
|
480
|
+
}
|
|
481
|
+
var edges []dupEdge
|
|
482
|
+
parent := make([]int, len(units))
|
|
483
|
+
for i := range parent {
|
|
484
|
+
parent[i] = i
|
|
485
|
+
}
|
|
486
|
+
find := func(x int) int {
|
|
487
|
+
for parent[x] != x {
|
|
488
|
+
parent[x] = parent[parent[x]]
|
|
489
|
+
x = parent[x]
|
|
490
|
+
}
|
|
491
|
+
return x
|
|
492
|
+
}
|
|
493
|
+
for _, s := range segs {
|
|
494
|
+
ua := unitIndex(s.aFile, s.aStart, s.aEnd)
|
|
495
|
+
ub := unitIndex(s.bFile, s.bStart, s.bEnd)
|
|
496
|
+
if ua < 0 || ub < 0 || ua == ub {
|
|
497
|
+
continue
|
|
498
|
+
}
|
|
499
|
+
edges = append(edges, dupEdge{a: ua, b: ub, boosted: s.boosted})
|
|
500
|
+
ra, rb := find(ua), find(ub)
|
|
501
|
+
if ra != rb {
|
|
502
|
+
parent[rb] = ra
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
groups := map[int][]int{}
|
|
506
|
+
for _, e := range edges {
|
|
507
|
+
r := find(e.a)
|
|
508
|
+
if !containsInt(groups[r], e.a) {
|
|
509
|
+
groups[r] = append(groups[r], e.a)
|
|
510
|
+
}
|
|
511
|
+
if !containsInt(groups[r], e.b) {
|
|
512
|
+
groups[r] = append(groups[r], e.b)
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
var clusters []dupCluster
|
|
516
|
+
for _, members := range groups {
|
|
517
|
+
sort.Ints(members)
|
|
518
|
+
c := dupCluster{units: members}
|
|
519
|
+
var sb strings.Builder
|
|
520
|
+
var hashes []string
|
|
521
|
+
for _, u := range members {
|
|
522
|
+
hashes = append(hashes, files[units[u].file].path+"\x00"+units[u].contentHash)
|
|
523
|
+
}
|
|
524
|
+
sort.Strings(hashes)
|
|
525
|
+
for _, h := range hashes {
|
|
526
|
+
sb.WriteString(h)
|
|
527
|
+
sb.WriteByte('\n')
|
|
528
|
+
}
|
|
529
|
+
sum := sha256.Sum256([]byte(sb.String()))
|
|
530
|
+
c.hash = hex.EncodeToString(sum[:])[:dupHashLength]
|
|
531
|
+
clusters = append(clusters, c)
|
|
532
|
+
}
|
|
533
|
+
for i := range clusters {
|
|
534
|
+
best := 0.0
|
|
535
|
+
member := map[int]bool{}
|
|
536
|
+
for _, u := range clusters[i].units {
|
|
537
|
+
member[u] = true
|
|
538
|
+
}
|
|
539
|
+
for _, e := range edges {
|
|
540
|
+
if member[e.a] && member[e.b] && e.boosted > best {
|
|
541
|
+
best = e.boosted
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
clusters[i].score = best
|
|
545
|
+
}
|
|
546
|
+
sort.Slice(clusters, func(i, j int) bool {
|
|
547
|
+
if clusters[i].score != clusters[j].score {
|
|
548
|
+
return clusters[i].score > clusters[j].score
|
|
549
|
+
}
|
|
550
|
+
return clusters[i].hash < clusters[j].hash
|
|
551
|
+
})
|
|
552
|
+
return clusters, units, edges
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
func dupUnitHash(lines []dupLine) string {
|
|
556
|
+
// Trivial `_` lines (lone braces, blank padding) carry no identity: a block
|
|
557
|
+
// that moves past padding keeps its hash so the ignore ledger holds.
|
|
558
|
+
var sb strings.Builder
|
|
559
|
+
for _, l := range lines {
|
|
560
|
+
if l.trivial || dupHeaderLine(l.tokens) {
|
|
561
|
+
continue
|
|
562
|
+
}
|
|
563
|
+
sb.WriteString(l.tokens)
|
|
564
|
+
sb.WriteByte('\n')
|
|
565
|
+
}
|
|
566
|
+
sum := sha256.Sum256([]byte(sb.String()))
|
|
567
|
+
return hex.EncodeToString(sum[:])[:16]
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// dupHeaderLine reports whether a normalized line is a file-scope declaration
|
|
571
|
+
// (package/module/namespace). Header lines are file context, not copied code:
|
|
572
|
+
// including them would make unit hashes flip when a header enters or leaves a
|
|
573
|
+
// unit's matched range.
|
|
574
|
+
func dupHeaderLine(tokens string) bool {
|
|
575
|
+
fields := strings.Fields(tokens)
|
|
576
|
+
if len(fields) == 0 || len(fields) > 2 {
|
|
577
|
+
return false
|
|
578
|
+
}
|
|
579
|
+
switch fields[0] {
|
|
580
|
+
case "package", "module", "namespace":
|
|
581
|
+
return true
|
|
582
|
+
}
|
|
583
|
+
return false
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
func containsInt(xs []int, v int) bool {
|
|
587
|
+
for _, x := range xs {
|
|
588
|
+
if x == v {
|
|
589
|
+
return true
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return false
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// dupChangedRanges parses `git diff -U0` output into per-file added-line
|
|
596
|
+
// ranges on the new side. Deleted files contribute nothing.
|
|
597
|
+
func dupChangedRanges(diff string) map[string][][2]int {
|
|
598
|
+
ranges := map[string][][2]int{}
|
|
599
|
+
var cur string
|
|
600
|
+
for _, line := range strings.Split(diff, "\n") {
|
|
601
|
+
switch {
|
|
602
|
+
case strings.HasPrefix(line, "+++ "):
|
|
603
|
+
p := strings.TrimSpace(strings.TrimPrefix(line, "+++ "))
|
|
604
|
+
if strings.HasPrefix(p, `"`) {
|
|
605
|
+
decoded, err := strconv.Unquote(p)
|
|
606
|
+
if err != nil {
|
|
607
|
+
cur = ""
|
|
608
|
+
continue
|
|
609
|
+
}
|
|
610
|
+
p = decoded
|
|
611
|
+
}
|
|
612
|
+
if p == "/dev/null" {
|
|
613
|
+
cur = ""
|
|
614
|
+
continue
|
|
615
|
+
}
|
|
616
|
+
cur = strings.TrimPrefix(p, "b/")
|
|
617
|
+
case strings.HasPrefix(line, "@@") && cur != "":
|
|
618
|
+
i := strings.Index(line, "+")
|
|
619
|
+
if i < 0 {
|
|
620
|
+
continue
|
|
621
|
+
}
|
|
622
|
+
rest := line[i+1:]
|
|
623
|
+
end := strings.IndexAny(rest, " @")
|
|
624
|
+
if end < 0 {
|
|
625
|
+
end = len(rest)
|
|
626
|
+
}
|
|
627
|
+
spec := rest[:end] // "start,count" — the comma stays inside spec
|
|
628
|
+
parts := strings.SplitN(spec, ",", 2)
|
|
629
|
+
startN, err := strconv.Atoi(parts[0])
|
|
630
|
+
if err != nil {
|
|
631
|
+
continue
|
|
632
|
+
}
|
|
633
|
+
count := 1
|
|
634
|
+
if len(parts) == 2 {
|
|
635
|
+
if n, err := strconv.Atoi(parts[1]); err == nil {
|
|
636
|
+
count = n
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
if count == 0 {
|
|
640
|
+
ranges[cur] = append(ranges[cur], [2]int{startN, startN})
|
|
641
|
+
} else {
|
|
642
|
+
ranges[cur] = append(ranges[cur], [2]int{startN, startN + count - 1})
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return ranges
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
func dupLoadIgnore(path string) map[string]bool {
|
|
650
|
+
ignored := map[string]bool{}
|
|
651
|
+
// #nosec G304 -- path is the documented --ignore-file/default ledger under the project root
|
|
652
|
+
data, err := os.ReadFile(path)
|
|
653
|
+
if err != nil {
|
|
654
|
+
return ignored
|
|
655
|
+
}
|
|
656
|
+
for _, line := range strings.Split(string(data), "\n") {
|
|
657
|
+
if i := strings.Index(line, "#"); i >= 0 {
|
|
658
|
+
line = line[:i]
|
|
659
|
+
}
|
|
660
|
+
if h := strings.TrimSpace(line); h != "" {
|
|
661
|
+
ignored[h] = true
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
return ignored
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
type dupOptions struct {
|
|
668
|
+
slug string
|
|
669
|
+
phase string
|
|
670
|
+
mode string // all | worktree | staged | base
|
|
671
|
+
base string
|
|
672
|
+
minLines int
|
|
673
|
+
threshold float64
|
|
674
|
+
ignoreFile string
|
|
675
|
+
limit int
|
|
676
|
+
exclude []string
|
|
677
|
+
cwd string
|
|
678
|
+
root string
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
func parseDupArgs(root string, args []string, stderr io.Writer) (dupOptions, int) {
|
|
682
|
+
opts := dupOptions{mode: "worktree", phase: "review", minLines: 8, threshold: 0.6, limit: 50, root: root}
|
|
683
|
+
var positional []string
|
|
684
|
+
seen := map[string]bool{}
|
|
685
|
+
modeSeen := false
|
|
686
|
+
for i := 0; i < len(args); i++ {
|
|
687
|
+
flag := args[i]
|
|
688
|
+
if strings.HasPrefix(flag, "--") {
|
|
689
|
+
if seen[flag] {
|
|
690
|
+
fmt.Fprintf(stderr, "dup: repeated option %s\n", flag)
|
|
691
|
+
return opts, 2
|
|
692
|
+
}
|
|
693
|
+
seen[flag] = true
|
|
694
|
+
switch flag {
|
|
695
|
+
case "--all", "--worktree", "--staged", "--base":
|
|
696
|
+
if modeSeen {
|
|
697
|
+
fmt.Fprintln(stderr, "dup: conflicting scan modes")
|
|
698
|
+
return opts, 2
|
|
699
|
+
}
|
|
700
|
+
modeSeen = true
|
|
701
|
+
}
|
|
702
|
+
switch flag {
|
|
703
|
+
case "--base", "--phase", "--min-lines", "--threshold", "--ignore-file", "--limit", "--exclude", "--cwd":
|
|
704
|
+
value := argAt(args, i+1)
|
|
705
|
+
if strings.TrimSpace(value) == "" || strings.HasPrefix(value, "-") {
|
|
706
|
+
fmt.Fprintf(stderr, "dup: %s requires a value (not a flag)\n", flag)
|
|
707
|
+
return opts, 2
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
switch args[i] {
|
|
713
|
+
case "--phase":
|
|
714
|
+
opts.phase = argAt(args, i+1)
|
|
715
|
+
i++
|
|
716
|
+
case "--all":
|
|
717
|
+
opts.mode = "all"
|
|
718
|
+
case "--worktree":
|
|
719
|
+
opts.mode = "worktree"
|
|
720
|
+
case "--staged":
|
|
721
|
+
opts.mode = "staged"
|
|
722
|
+
case "--base":
|
|
723
|
+
opts.mode = "base"
|
|
724
|
+
opts.base = argAt(args, i+1)
|
|
725
|
+
i++
|
|
726
|
+
case "--min-lines":
|
|
727
|
+
n, err := strconv.Atoi(argAt(args, i+1))
|
|
728
|
+
if err != nil || n < dupShingleLines {
|
|
729
|
+
fmt.Fprintf(stderr, "dup: --min-lines must be an integer >= %d\n", dupShingleLines)
|
|
730
|
+
return opts, 2
|
|
731
|
+
}
|
|
732
|
+
opts.minLines = n
|
|
733
|
+
i++
|
|
734
|
+
case "--threshold":
|
|
735
|
+
f, err := strconv.ParseFloat(argAt(args, i+1), 64)
|
|
736
|
+
if err != nil || math.IsNaN(f) || math.IsInf(f, 0) || f <= 0 || f > 1 {
|
|
737
|
+
fmt.Fprintln(stderr, "dup: --threshold must be in (0, 1]")
|
|
738
|
+
return opts, 2
|
|
739
|
+
}
|
|
740
|
+
opts.threshold = f
|
|
741
|
+
i++
|
|
742
|
+
case "--ignore-file":
|
|
743
|
+
opts.ignoreFile = argAt(args, i+1)
|
|
744
|
+
i++
|
|
745
|
+
case "--limit":
|
|
746
|
+
n, err := strconv.Atoi(argAt(args, i+1))
|
|
747
|
+
if err != nil || n < 1 {
|
|
748
|
+
fmt.Fprintln(stderr, "dup: --limit must be a positive integer")
|
|
749
|
+
return opts, 2
|
|
750
|
+
}
|
|
751
|
+
opts.limit = n
|
|
752
|
+
i++
|
|
753
|
+
case "--exclude":
|
|
754
|
+
for _, entry := range strings.Split(argAt(args, i+1), ",") {
|
|
755
|
+
if entry = strings.TrimSpace(entry); entry != "" {
|
|
756
|
+
opts.exclude = append(opts.exclude, strings.TrimSuffix(entry, "/")+"/")
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
i++
|
|
760
|
+
case "--cwd":
|
|
761
|
+
opts.cwd = argAt(args, i+1)
|
|
762
|
+
i++
|
|
763
|
+
default:
|
|
764
|
+
if strings.HasPrefix(args[i], "-") {
|
|
765
|
+
fmt.Fprintf(stderr, "dup: unknown flag %q\n", args[i])
|
|
766
|
+
return opts, 2
|
|
767
|
+
}
|
|
768
|
+
positional = append(positional, args[i])
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
if len(positional) > 1 || opts.mode == "base" && opts.base == "" {
|
|
772
|
+
fmt.Fprint(stderr, dupUsage)
|
|
773
|
+
return opts, 2
|
|
774
|
+
}
|
|
775
|
+
if len(positional) == 1 {
|
|
776
|
+
opts.slug = positional[0]
|
|
777
|
+
}
|
|
778
|
+
return opts, 0
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// RunCheckDup scans tracked source for near-duplicate regions and prints
|
|
782
|
+
// ranked clusters. Advisory only: it never gates — a cluster is a lead that
|
|
783
|
+
// a reviewer confirms or dismisses into the ignore file.
|
|
784
|
+
func RunCheckDup(root string, args []string, stdout, stderr io.Writer) int {
|
|
785
|
+
opts, code := parseDupArgs(root, args, stderr)
|
|
786
|
+
if code != 0 {
|
|
787
|
+
return code
|
|
788
|
+
}
|
|
789
|
+
dir := opts.cwd
|
|
790
|
+
if dir == "" {
|
|
791
|
+
dir = projectDir(root)
|
|
792
|
+
}
|
|
793
|
+
repoOut, err := runGitCommand(dir, nil, "rev-parse", "--show-toplevel")
|
|
794
|
+
if err != nil {
|
|
795
|
+
fmt.Fprintf(stderr, "dup: %v\n", err)
|
|
796
|
+
return 2
|
|
797
|
+
}
|
|
798
|
+
repo := strings.TrimSpace(string(repoOut))
|
|
799
|
+
listed, err := dupGitOutput(repo, nil, gitOutputLimit, "ls-files", "-z")
|
|
800
|
+
if err != nil {
|
|
801
|
+
fmt.Fprintf(stderr, "dup: %v\n", err)
|
|
802
|
+
return 2
|
|
803
|
+
}
|
|
804
|
+
var paths []string
|
|
805
|
+
for _, p := range strings.Split(strings.TrimRight(string(listed), "\x00"), "\x00") {
|
|
806
|
+
if p != "" && dupScannable(p, opts.exclude) {
|
|
807
|
+
paths = append(paths, p)
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
var untracked []string
|
|
811
|
+
|
|
812
|
+
if opts.mode != "staged" {
|
|
813
|
+
out, uerr := dupGitOutput(repo, nil, gitOutputLimit, "ls-files", "--others", "--exclude-standard", "-z")
|
|
814
|
+
if uerr != nil {
|
|
815
|
+
fmt.Fprintf(stderr, "dup: %v\n", uerr)
|
|
816
|
+
return 2
|
|
817
|
+
}
|
|
818
|
+
for _, p := range strings.Split(string(out), "\x00") {
|
|
819
|
+
if p != "" && dupScannable(p, opts.exclude) {
|
|
820
|
+
untracked = append(untracked, p)
|
|
821
|
+
paths = append(paths, p)
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
if len(paths) > dupMaxFiles {
|
|
827
|
+
fmt.Fprintf(stderr, "dup: too many files (%d > %d)\n", len(paths), dupMaxFiles)
|
|
828
|
+
return 2
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
var files []dupFile
|
|
832
|
+
var skipped, failed int
|
|
833
|
+
if opts.mode == "staged" {
|
|
834
|
+
files, skipped, failed, err = dupReadIndex(repo, opts.exclude)
|
|
835
|
+
if err != nil {
|
|
836
|
+
fmt.Fprintf(stderr, "dup: incomplete scan: %v\n", err)
|
|
837
|
+
return 2
|
|
838
|
+
}
|
|
839
|
+
} else {
|
|
840
|
+
files, skipped, failed = dupReadFiles(repo, paths)
|
|
841
|
+
}
|
|
842
|
+
if failed > 0 {
|
|
843
|
+
fmt.Fprintf(stderr, "dup: incomplete scan: %d eligible file(s) unavailable or over resource limits; %d scanned\n", failed, len(files))
|
|
844
|
+
}
|
|
845
|
+
if len(files) == 0 {
|
|
846
|
+
if failed > 0 {
|
|
847
|
+
return 2
|
|
848
|
+
}
|
|
849
|
+
if skipped > 0 {
|
|
850
|
+
fmt.Fprintf(stdout, "dup: no source scanned (%d generated files excluded)\n", skipped)
|
|
851
|
+
} else {
|
|
852
|
+
fmt.Fprintln(stdout, "dup: no eligible source files")
|
|
853
|
+
}
|
|
854
|
+
return 0
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
clusters, units := dupDetect(files, opts)
|
|
858
|
+
|
|
859
|
+
// Changed-range marking and filtering.
|
|
860
|
+
allChanged := false
|
|
861
|
+
changedRanges := map[string][][2]int{}
|
|
862
|
+
switch opts.mode {
|
|
863
|
+
case "all":
|
|
864
|
+
// no changed marking
|
|
865
|
+
case "staged":
|
|
866
|
+
diff, derr := dupGitOutput(repo, nil, gitOutputLimit, "--no-replace-objects", "diff", "--no-ext-diff", "--no-textconv", "--no-color", "--src-prefix=a/", "--dst-prefix=b/", "--cached", "-U0", "--")
|
|
867
|
+
if derr != nil {
|
|
868
|
+
fmt.Fprintf(stderr, "dup: %v\n", derr)
|
|
869
|
+
return 2
|
|
870
|
+
}
|
|
871
|
+
changedRanges = dupChangedRanges(string(diff))
|
|
872
|
+
case "base":
|
|
873
|
+
diff, derr := dupGitOutput(repo, nil, gitOutputLimit, "--no-replace-objects", "diff", "--no-ext-diff", "--no-textconv", "--no-color", "--src-prefix=a/", "--dst-prefix=b/", opts.base, "-U0", "--")
|
|
874
|
+
if derr != nil {
|
|
875
|
+
fmt.Fprintf(stderr, "dup: %v\n", derr)
|
|
876
|
+
return 2
|
|
877
|
+
}
|
|
878
|
+
changedRanges = dupChangedRanges(string(diff))
|
|
879
|
+
default: // worktree
|
|
880
|
+
if isUnbornHEAD(repo) {
|
|
881
|
+
allChanged = true
|
|
882
|
+
} else {
|
|
883
|
+
diff, derr := dupGitOutput(repo, nil, gitOutputLimit, "--no-replace-objects", "diff", "--no-ext-diff", "--no-textconv", "--no-color", "--src-prefix=a/", "--dst-prefix=b/", "HEAD", "-U0", "--")
|
|
884
|
+
if derr != nil {
|
|
885
|
+
fmt.Fprintf(stderr, "dup: %v\n", derr)
|
|
886
|
+
return 2
|
|
887
|
+
}
|
|
888
|
+
changedRanges = dupChangedRanges(string(diff))
|
|
889
|
+
}
|
|
890
|
+
for _, p := range untracked {
|
|
891
|
+
changedRanges[p] = [][2]int{{1, 1 << 30}}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
if allChanged {
|
|
895
|
+
for i := range units {
|
|
896
|
+
units[i].changed = true
|
|
897
|
+
}
|
|
898
|
+
} else {
|
|
899
|
+
for i := range units {
|
|
900
|
+
for _, r := range changedRanges[files[units[i].file].path] {
|
|
901
|
+
// unit lines are 0-based inclusive; ranges are 1-based.
|
|
902
|
+
if units[i].start+1 <= r[1] && r[0] <= units[i].end+1 {
|
|
903
|
+
units[i].changed = true
|
|
904
|
+
break
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
for i := range clusters {
|
|
910
|
+
for _, u := range clusters[i].units {
|
|
911
|
+
if units[u].changed {
|
|
912
|
+
clusters[i].changed = true
|
|
913
|
+
break
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
totalClusters := len(clusters)
|
|
918
|
+
if opts.mode != "all" {
|
|
919
|
+
var kept []dupCluster
|
|
920
|
+
for _, c := range clusters {
|
|
921
|
+
if c.changed {
|
|
922
|
+
kept = append(kept, c)
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
clusters = kept
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
ignoreFile := opts.ignoreFile
|
|
929
|
+
if ignoreFile == "" {
|
|
930
|
+
ignoreFile = filepath.Join(projectDir(root), devritespaths.DevritesRootName, "dup-ignore")
|
|
931
|
+
}
|
|
932
|
+
if !filepath.IsAbs(ignoreFile) {
|
|
933
|
+
ignoreFile = filepath.Join(projectDir(root), ignoreFile)
|
|
934
|
+
}
|
|
935
|
+
ignored := dupLoadIgnore(ignoreFile)
|
|
936
|
+
var shown []dupCluster
|
|
937
|
+
ignoredCount := 0
|
|
938
|
+
for _, c := range clusters {
|
|
939
|
+
if ignored[c.hash] {
|
|
940
|
+
ignoredCount++
|
|
941
|
+
continue
|
|
942
|
+
}
|
|
943
|
+
shown = append(shown, c)
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
relIgnore, rerr := filepath.Rel(projectDir(root), ignoreFile)
|
|
947
|
+
if rerr != nil {
|
|
948
|
+
relIgnore = ignoreFile
|
|
949
|
+
}
|
|
950
|
+
fmt.Fprintf(stdout, "dup: scanned %d files (%d skipped), %d units; ignore-file %s\n",
|
|
951
|
+
len(files), skipped, len(units), filepath.ToSlash(relIgnore))
|
|
952
|
+
if len(shown) == 0 {
|
|
953
|
+
if failed > 0 {
|
|
954
|
+
return 2
|
|
955
|
+
}
|
|
956
|
+
if ignoredCount > 0 {
|
|
957
|
+
fmt.Fprintf(stdout, "dup: ok (all %d cluster(s) ignored via %s)\n", ignoredCount, filepath.ToSlash(relIgnore))
|
|
958
|
+
} else if opts.mode != "all" && totalClusters > 0 {
|
|
959
|
+
fmt.Fprintln(stdout, "dup: ok (no clusters touch the diff)")
|
|
960
|
+
} else {
|
|
961
|
+
fmt.Fprintln(stdout, "dup: ok (no similar regions)")
|
|
962
|
+
}
|
|
963
|
+
if opts.slug != "" {
|
|
964
|
+
recordMetric(root, opts.slug, opts.phase, "dup", "", int64(len(clusters)))
|
|
965
|
+
}
|
|
966
|
+
return 0
|
|
967
|
+
}
|
|
968
|
+
fmt.Fprintf(stdout, "dup: %d cluster(s)", len(shown))
|
|
969
|
+
if ignoredCount > 0 {
|
|
970
|
+
fmt.Fprintf(stdout, " (%d ignored)", ignoredCount)
|
|
971
|
+
}
|
|
972
|
+
fmt.Fprintln(stdout)
|
|
973
|
+
if len(shown) > opts.limit {
|
|
974
|
+
shown = shown[:opts.limit]
|
|
975
|
+
fmt.Fprintf(stdout, "dup: truncated to %d clusters (--limit)\n", opts.limit)
|
|
976
|
+
}
|
|
977
|
+
for i, c := range shown {
|
|
978
|
+
fmt.Fprintf(stdout, "cluster %d (%s) score %.2f:\n", i+1, c.hash, c.score)
|
|
979
|
+
members := append([]int(nil), c.units...)
|
|
980
|
+
sort.Slice(members, func(a, b int) bool {
|
|
981
|
+
ua, ub := units[members[a]], units[members[b]]
|
|
982
|
+
if ua.changed != ub.changed {
|
|
983
|
+
return ua.changed
|
|
984
|
+
}
|
|
985
|
+
if files[ua.file].path != files[ub.file].path {
|
|
986
|
+
return files[ua.file].path < files[ub.file].path
|
|
987
|
+
}
|
|
988
|
+
return ua.start < ub.start
|
|
989
|
+
})
|
|
990
|
+
for _, u := range members {
|
|
991
|
+
unit := units[u]
|
|
992
|
+
marker := " "
|
|
993
|
+
if unit.changed {
|
|
994
|
+
marker = "* "
|
|
995
|
+
}
|
|
996
|
+
fmt.Fprintf(stdout, " %s%s:%d-%d\n", marker, files[unit.file].path, unit.start+1, unit.end+1)
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
if failed > 0 {
|
|
1000
|
+
return 2
|
|
1001
|
+
}
|
|
1002
|
+
if opts.slug != "" {
|
|
1003
|
+
recordMetric(root, opts.slug, opts.phase, "dup", "", int64(len(shown)))
|
|
1004
|
+
}
|
|
1005
|
+
return 0
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
func abs(x int) int {
|
|
1009
|
+
if x < 0 {
|
|
1010
|
+
return -x
|
|
1011
|
+
}
|
|
1012
|
+
return x
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// dupDetect runs the shingle/segment/cluster pipeline over scanned files.
|
|
1016
|
+
func dupDetect(files []dupFile, opts dupOptions) ([]dupCluster, []dupUnit) {
|
|
1017
|
+
postings := map[uint64][]dupPos{}
|
|
1018
|
+
for fi := range files {
|
|
1019
|
+
lines := files[fi].lines
|
|
1020
|
+
for i := 0; i+dupShingleLines <= len(lines); i++ {
|
|
1021
|
+
allTrivial := true
|
|
1022
|
+
for j := i; j < i+dupShingleLines; j++ {
|
|
1023
|
+
if !lines[j].trivial {
|
|
1024
|
+
allTrivial = false
|
|
1025
|
+
break
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
if allTrivial {
|
|
1029
|
+
continue // padding runs anchor everywhere and add no signal
|
|
1030
|
+
}
|
|
1031
|
+
h := dupShingleHash(lines, i)
|
|
1032
|
+
postings[h] = append(postings[h], dupPos{file: fi, line: i})
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
anchorMap := map[dupPairKey][]dupAnchor{}
|
|
1036
|
+
for _, list := range postings {
|
|
1037
|
+
if len(list) > dupMaxPostings {
|
|
1038
|
+
continue // boilerplate shingle (e.g. brace runs) — no signal
|
|
1039
|
+
}
|
|
1040
|
+
for i := 0; i < len(list); i++ {
|
|
1041
|
+
for j := i + 1; j < len(list); j++ {
|
|
1042
|
+
a, b := list[i], list[j]
|
|
1043
|
+
if a.file > b.file || a.file == b.file && a.line > b.line {
|
|
1044
|
+
a, b = b, a
|
|
1045
|
+
}
|
|
1046
|
+
if a.file == b.file && b.line-a.line < dupShingleLines {
|
|
1047
|
+
continue // overlapping windows in one file match trivially
|
|
1048
|
+
}
|
|
1049
|
+
key := dupPairKey{a: a.file, b: b.file}
|
|
1050
|
+
anchors := anchorMap[key]
|
|
1051
|
+
if len(anchors) >= dupMaxPairAnchors {
|
|
1052
|
+
continue
|
|
1053
|
+
}
|
|
1054
|
+
anchorMap[key] = append(anchors, dupAnchor{aLine: a.line, bLine: b.line})
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
var segs []dupSegment
|
|
1059
|
+
for key, anchors := range anchorMap {
|
|
1060
|
+
segs = append(segs, dupAnchorSegments(key, anchors, files, opts.minLines, opts.threshold)...)
|
|
1061
|
+
}
|
|
1062
|
+
clusters, units, _ := dupClusterUnits(segs, files)
|
|
1063
|
+
return clusters, units
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// dupReadFiles loads and normalizes every scannable path under budgets.
|
|
1067
|
+
func dupReadFiles(repo string, paths []string) ([]dupFile, int, int) {
|
|
1068
|
+
var files []dupFile
|
|
1069
|
+
var skipped, failed int
|
|
1070
|
+
var remaining int64 = dupMaxBytes
|
|
1071
|
+
for _, p := range paths {
|
|
1072
|
+
full := filepath.Join(repo, filepath.FromSlash(p))
|
|
1073
|
+
info, err := os.Lstat(full)
|
|
1074
|
+
if err != nil || !info.Mode().IsRegular() || info.Size() > dupMaxFileBytes || info.Size() > remaining {
|
|
1075
|
+
failed++
|
|
1076
|
+
continue
|
|
1077
|
+
}
|
|
1078
|
+
// #nosec G304 -- repo-relative path from git ls-files, lstat'd regular file
|
|
1079
|
+
f, err := os.Open(full)
|
|
1080
|
+
if err != nil {
|
|
1081
|
+
failed++
|
|
1082
|
+
continue
|
|
1083
|
+
}
|
|
1084
|
+
raw, err := io.ReadAll(io.LimitReader(f, min(dupMaxFileBytes, remaining)+1))
|
|
1085
|
+
closeErr := f.Close()
|
|
1086
|
+
if err != nil || closeErr != nil || int64(len(raw)) > min(dupMaxFileBytes, remaining) {
|
|
1087
|
+
failed++
|
|
1088
|
+
continue
|
|
1089
|
+
}
|
|
1090
|
+
remaining -= int64(len(raw))
|
|
1091
|
+
if isDupGenerated(raw) {
|
|
1092
|
+
skipped++
|
|
1093
|
+
continue
|
|
1094
|
+
}
|
|
1095
|
+
style := dupStyleFor(p)
|
|
1096
|
+
files = append(files, dupFile{path: p, lines: normalizeDupSource(string(raw), style)})
|
|
1097
|
+
}
|
|
1098
|
+
return files, skipped, failed
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
func isDupGenerated(raw []byte) bool {
|
|
1102
|
+
head := string(raw[:min(len(raw), 2048)])
|
|
1103
|
+
return strings.Contains(head, "Code generated") ||
|
|
1104
|
+
strings.Contains(head, "DO NOT EDIT") ||
|
|
1105
|
+
strings.Contains(head, "auto-generated") ||
|
|
1106
|
+
strings.Contains(head, "Automatically generated")
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
// dupScannable reports whether a repo-relative slash path is in scope: a
|
|
1110
|
+
// known code extension or basename, outside vendored/generated trees, and
|
|
1111
|
+
// not excluded by --exclude prefixes.
|
|
1112
|
+
func dupScannable(p string, exclude []string) bool {
|
|
1113
|
+
for _, prefix := range dupSkipPrefixes {
|
|
1114
|
+
if dupPathPrefixMatch(p, prefix) {
|
|
1115
|
+
return false
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
for _, prefix := range exclude {
|
|
1119
|
+
if dupPathPrefixMatch(p, prefix) {
|
|
1120
|
+
return false
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
base := strings.ToLower(path.Base(p))
|
|
1124
|
+
if strings.Contains(base, ".min.") || strings.Contains(base, ".pb.") ||
|
|
1125
|
+
strings.Contains(base, ".gen.") || strings.HasSuffix(base, ".designer.cs") {
|
|
1126
|
+
return false
|
|
1127
|
+
}
|
|
1128
|
+
_, ok := dupStyleForOK(p)
|
|
1129
|
+
return ok
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// dupPathPrefixMatch reports whether path p sits under directory prefix —
|
|
1133
|
+
// gitignore-style: at the root or below any intermediate directory, so a
|
|
1134
|
+
// nested `services/x/vendor/` tree is skipped the same as a root `vendor/`.
|
|
1135
|
+
func dupPathPrefixMatch(p, prefix string) bool {
|
|
1136
|
+
return strings.HasPrefix(p, prefix) || strings.Contains(p, "/"+prefix)
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
func dupStyleFor(p string) dupCommentStyle {
|
|
1140
|
+
style, _ := dupStyleForOK(p)
|
|
1141
|
+
return style
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
func dupStyleForOK(p string) (dupCommentStyle, bool) {
|
|
1145
|
+
if style, ok := dupStyleByName[strings.ToLower(path.Base(p))]; ok {
|
|
1146
|
+
return style, true
|
|
1147
|
+
}
|
|
1148
|
+
style, ok := dupStyleByExt[strings.ToLower(path.Ext(p))]
|
|
1149
|
+
return style, ok
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
// Git listings and blob batches must fail on truncation, not scan a prefix.
|
|
1153
|
+
type dupOutput struct {
|
|
1154
|
+
buffer bytes.Buffer
|
|
1155
|
+
limit int
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
func (w *dupOutput) Write(p []byte) (int, error) {
|
|
1159
|
+
if len(p) > w.limit-w.buffer.Len() {
|
|
1160
|
+
return 0, fmt.Errorf("scan output exceeds resource limit")
|
|
1161
|
+
}
|
|
1162
|
+
return w.buffer.Write(p)
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
func dupGitOutput(repo string, input []byte, limit int, args ...string) ([]byte, error) {
|
|
1166
|
+
out := dupOutput{limit: limit}
|
|
1167
|
+
_, err := runGitCommandIO(repo, nil, input, &out, args...)
|
|
1168
|
+
return out.buffer.Bytes(), err
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
func dupReadIndex(repo string, exclude []string) ([]dupFile, int, int, error) {
|
|
1172
|
+
listing, err := dupGitOutput(repo, nil, gitOutputLimit, "ls-files", "--stage", "-z")
|
|
1173
|
+
if err != nil {
|
|
1174
|
+
return nil, 0, 0, err
|
|
1175
|
+
}
|
|
1176
|
+
var paths, oids []string
|
|
1177
|
+
var input strings.Builder
|
|
1178
|
+
for _, entry := range strings.Split(string(listing), "\x00") {
|
|
1179
|
+
if entry == "" {
|
|
1180
|
+
continue
|
|
1181
|
+
}
|
|
1182
|
+
header, p, ok := strings.Cut(entry, "\t")
|
|
1183
|
+
fields := strings.Fields(header)
|
|
1184
|
+
if !ok || len(fields) != 3 || fields[2] != "0" {
|
|
1185
|
+
return nil, 0, 0, fmt.Errorf("unresolved or malformed index")
|
|
1186
|
+
}
|
|
1187
|
+
if !dupScannable(p, exclude) {
|
|
1188
|
+
continue
|
|
1189
|
+
}
|
|
1190
|
+
if fields[0] != "100644" && fields[0] != "100755" {
|
|
1191
|
+
return nil, 0, 0, fmt.Errorf("non-regular indexed source %q", p)
|
|
1192
|
+
}
|
|
1193
|
+
if !isObjectID(fields[1]) || isZeroObjectID(fields[1]) {
|
|
1194
|
+
return nil, 0, 0, fmt.Errorf("invalid indexed blob")
|
|
1195
|
+
}
|
|
1196
|
+
paths = append(paths, p)
|
|
1197
|
+
oids = append(oids, fields[1])
|
|
1198
|
+
input.WriteString(fields[1] + "\n")
|
|
1199
|
+
if len(paths) > dupMaxFiles {
|
|
1200
|
+
return nil, 0, 0, fmt.Errorf("too many eligible files")
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
if len(paths) == 0 {
|
|
1204
|
+
return nil, 0, 0, nil
|
|
1205
|
+
}
|
|
1206
|
+
data, err := dupGitOutput(repo, []byte(input.String()), dupMaxBytes+dupMaxFiles*128, "--no-replace-objects", "cat-file", "--batch")
|
|
1207
|
+
if err != nil {
|
|
1208
|
+
return nil, 0, 0, err
|
|
1209
|
+
}
|
|
1210
|
+
var files []dupFile
|
|
1211
|
+
skipped, failed, total := 0, 0, 0
|
|
1212
|
+
for i, p := range paths {
|
|
1213
|
+
end := bytes.IndexByte(data, '\n')
|
|
1214
|
+
if end < 0 {
|
|
1215
|
+
return nil, 0, 0, fmt.Errorf("missing blob header")
|
|
1216
|
+
}
|
|
1217
|
+
fields := strings.Fields(string(data[:end]))
|
|
1218
|
+
data = data[end+1:]
|
|
1219
|
+
if len(fields) != 3 || fields[0] != oids[i] || fields[1] != "blob" {
|
|
1220
|
+
return nil, 0, 0, fmt.Errorf("unavailable indexed blob")
|
|
1221
|
+
}
|
|
1222
|
+
size, err := strconv.Atoi(fields[2])
|
|
1223
|
+
if err != nil || size < 0 || size >= len(data) || data[size] != '\n' {
|
|
1224
|
+
return nil, 0, 0, fmt.Errorf("invalid blob size")
|
|
1225
|
+
}
|
|
1226
|
+
raw := data[:size]
|
|
1227
|
+
data = data[size+1:]
|
|
1228
|
+
total += size
|
|
1229
|
+
if size > dupMaxFileBytes || total > dupMaxBytes {
|
|
1230
|
+
failed++
|
|
1231
|
+
continue
|
|
1232
|
+
}
|
|
1233
|
+
if isDupGenerated(raw) {
|
|
1234
|
+
skipped++
|
|
1235
|
+
continue
|
|
1236
|
+
}
|
|
1237
|
+
files = append(files, dupFile{path: p, lines: normalizeDupSource(string(raw), dupStyleFor(p))})
|
|
1238
|
+
}
|
|
1239
|
+
if len(data) != 0 {
|
|
1240
|
+
return nil, 0, 0, fmt.Errorf("unexpected blob output")
|
|
1241
|
+
}
|
|
1242
|
+
return files, skipped, failed, nil
|
|
1243
|
+
}
|