devrites 5.14.4 → 6.0.1
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 +23 -0
- package/NOTICE.md +6 -4
- package/README.md +77 -16
- package/SECURITY.md +25 -11
- package/bin/devrites.mjs +49 -15
- package/docs/adr/0001-go-engine-as-control-plane.md +6 -3
- package/docs/adr/0029-v5-workspace-schema-and-native-migration.md +9 -0
- package/docs/adr/README.md +3 -2
- package/docs/agents/issue-tracker.md +1 -1
- package/docs/architecture.md +6 -3
- package/docs/cli.md +32 -9
- package/docs/command-map.md +5 -3
- package/docs/engine/state-schema.md +1 -1
- package/docs/flow.md +1 -1
- package/docs/harness-compliance.md +2 -2
- package/docs/release.md +15 -11
- package/docs/usage.md +1 -1
- package/engine/commands.go +1 -1
- package/engine/go.mod +1 -1
- package/engine/help.go +41 -15
- package/engine/help_test.go +134 -0
- package/engine/internal/acceptance/acceptance_test.go +298 -7
- package/engine/internal/acceptance/approve.go +7 -2
- package/engine/internal/acceptance/cli.go +3 -0
- package/engine/internal/acceptance/evidence.go +69 -5
- package/engine/internal/acceptance/lint.go +1 -1
- package/engine/internal/acceptance/run.go +5 -3
- package/engine/internal/acceptance/scaffold.go +5 -16
- package/engine/internal/devritespaths/paths.go +7 -6
- package/engine/internal/devritespaths/paths_test.go +18 -0
- package/engine/internal/fsutil/copy.go +83 -49
- package/engine/internal/fsutil/copy_test.go +70 -109
- package/engine/internal/gate/gate.go +89 -16
- package/engine/internal/gate/gate_test.go +101 -0
- package/engine/internal/hostpack/hostpack.go +52 -2
- package/engine/internal/hostpack/hostpack_test.go +83 -2
- package/engine/internal/install/apply.go +59 -16
- package/engine/internal/install/binary.go +10 -1
- package/engine/internal/install/install_test.go +428 -0
- package/engine/internal/install/merge.go +69 -38
- package/engine/internal/install/preflight.go +7 -0
- package/engine/internal/install/uninstall.go +43 -4
- package/engine/internal/lib/claims.go +25 -4
- package/engine/internal/lib/claims_test.go +57 -0
- package/engine/internal/lib/closeout.go +41 -3
- package/engine/internal/lib/closeout_test.go +144 -0
- package/engine/internal/lib/context.go +8 -4
- package/engine/internal/lib/context_next_test.go +100 -0
- package/engine/internal/lib/detect.go +1 -1
- package/engine/internal/lib/detect_test.go +13 -0
- package/engine/internal/lib/diffscope.go +19 -9
- package/engine/internal/lib/dispatch.go +7 -0
- package/engine/internal/lib/dup.go +40 -37
- package/engine/internal/lib/dup_test.go +178 -0
- package/engine/internal/lib/manifest_union.go +4 -1
- package/engine/internal/lib/manifest_union_test.go +37 -0
- package/engine/internal/lib/metrics.go +4 -0
- package/engine/internal/lib/metrics_test.go +28 -0
- package/engine/internal/lib/migrate_test.go +59 -0
- package/engine/internal/lib/observe_budgets.go +25 -9
- package/engine/internal/lib/observe_budgets_test.go +254 -0
- package/engine/internal/lib/observe_summary.go +23 -2
- package/engine/internal/lib/open_visual.go +4 -2
- package/engine/internal/lib/open_visual_test.go +11 -0
- package/engine/internal/lib/regression.go +62 -23
- package/engine/internal/lib/regression_test.go +103 -0
- package/engine/internal/lib/resolve.go +36 -17
- package/engine/internal/lib/resolve_remediation_test.go +132 -0
- package/engine/internal/lib/skilltrust.go +0 -11
- package/engine/internal/lib/slicecheck.go +7 -5
- package/engine/internal/lib/slicecheck_test.go +18 -0
- package/engine/internal/lib/triggers.go +9 -3
- package/engine/internal/lib/triggers_test.go +23 -0
- package/engine/internal/lib/util.go +17 -3
- package/engine/internal/lib/util_test.go +104 -0
- package/engine/internal/lib/visual_outline.go +7 -3
- package/engine/internal/lib/visual_outline_test.go +28 -0
- package/engine/internal/lib/windows.go +13 -9
- package/engine/internal/lib/windows_test.go +98 -0
- package/engine/internal/lib/workspace_read.go +2 -11
- package/engine/internal/lib/workspace_read_test.go +102 -0
- package/engine/internal/markdowntext/markdowntext.go +194 -11
- package/engine/internal/markdowntext/testdata/structural.json +250 -0
- package/engine/internal/notes/cli.go +30 -12
- package/engine/internal/notes/notes.go +242 -39
- package/engine/internal/notes/notes_test.go +372 -0
- package/engine/internal/overhaul/admit/packet.go +89 -0
- package/engine/internal/overhaul/admit/packet_test.go +223 -0
- package/engine/internal/overhaul/admit/run.go +4 -0
- package/engine/internal/overhaul/bench/run.go +6 -0
- package/engine/internal/overhaul/bench/run_test.go +46 -0
- package/engine/internal/overhaul/overhaul.go +6 -1
- package/engine/internal/overhaul/ovio/ovio.go +10 -3
- package/engine/internal/overhaul/ovio/ovio_test.go +75 -0
- package/engine/internal/overhaul/packet/packet.go +208 -0
- package/engine/internal/overhaul/packet/packet_test.go +263 -0
- package/engine/internal/overhaul/records/check.go +6 -0
- package/engine/internal/overhaul/records/init.go +16 -5
- package/engine/internal/overhaul/records/records_test.go +4 -0
- package/engine/internal/overhaul/records/run.go +66 -0
- package/engine/internal/overhaul/records/run_test.go +77 -0
- package/engine/internal/overhaul/render/run.go +15 -11
- package/engine/internal/overhaul/render/run_test.go +463 -1
- package/engine/internal/overhaul/render/visual.go +95 -33
- package/engine/internal/overhaul/score/run.go +20 -0
- package/engine/internal/overhaul/score/run_test.go +156 -1
- package/engine/internal/overhaul/snapshot/run.go +78 -21
- package/engine/internal/overhaul/snapshot/run_test.go +344 -8
- package/engine/internal/parallel/cli.go +33 -20
- package/engine/internal/parallel/cli_test.go +59 -0
- package/engine/internal/parallel/git.go +39 -1
- package/engine/internal/parallel/ops.go +101 -11
- package/engine/internal/parallel/ops_test.go +552 -69
- package/engine/internal/parallel/parallel_test.go +31 -1
- package/engine/internal/parallel/pathdisjoint.go +19 -1
- package/engine/internal/parallel/pathdisjoint_test.go +72 -0
- package/engine/internal/parallel/select.go +6 -2
- package/engine/internal/release/release.go +13 -3
- package/engine/internal/release/release_test.go +208 -3
- package/engine/internal/rootfacts/facts.go +9 -0
- package/engine/internal/rootfacts/facts_test.go +38 -0
- package/engine/internal/state/acceptance.go +7 -1
- package/engine/internal/state/budgets.go +11 -10
- package/engine/internal/state/budgets_test.go +93 -0
- package/engine/internal/state/cursor.go +19 -8
- package/engine/internal/state/cursor_test.go +120 -0
- package/engine/internal/state/lock_unix.go +7 -1
- package/engine/internal/state/lock_windows.go +7 -1
- package/engine/internal/state/state_test.go +49 -18
- package/engine/internal/state/taskgraph.go +18 -4
- package/engine/internal/state/taskgraph_test.go +43 -0
- package/engine/internal/state/workspaceschema.go +16 -2
- package/engine/internal/state/workspaceschema_test.go +34 -0
- package/engine/internal/state/write.go +67 -6
- package/engine/internal/state/write_test.go +136 -0
- package/engine/internal/version/version_test.go +2 -0
- package/engine/main.go +8 -1
- package/engine/observation_contract_test.go +1 -1
- package/engine/root_routing_test.go +23 -1
- package/install.sh +132 -12
- package/pack/.claude/agents/devrites-spec-reviewer.md +2 -2
- package/pack/.claude/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/.claude/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/.claude/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/.claude/skills/devrites-interview/SKILL.md +4 -4
- package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +5 -2
- package/pack/.claude/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/.claude/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/.claude/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/.claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/.claude/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/.claude/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/.claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/.claude/skills/overhaul/SKILL.md +1 -1
- package/pack/.claude/skills/overhaul/references/orchestration.md +5 -3
- package/pack/.claude/skills/overhaul/references/records.md +39 -0
- package/pack/.claude/skills/overhaul/references/scoring.md +14 -4
- package/pack/.claude/skills/rite/reference/menu.md +1 -1
- package/pack/.claude/skills/rite-adopt/SKILL.md +8 -2
- package/pack/.claude/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/.claude/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/.claude/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/.claude/skills/rite-build/SKILL.md +2 -1
- package/pack/.claude/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/.claude/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/.claude/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/.claude/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +6 -3
- package/pack/.claude/skills/rite-clarify/SKILL.md +5 -4
- package/pack/.claude/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/.claude/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/.claude/skills/rite-converge/SKILL.md +2 -0
- package/pack/.claude/skills/rite-customize/SKILL.md +6 -4
- package/pack/.claude/skills/rite-define/SKILL.md +2 -0
- package/pack/.claude/skills/rite-define/reference/gates.md +8 -7
- package/pack/.claude/skills/rite-explain/SKILL.md +1 -1
- package/pack/.claude/skills/rite-explain/reference/intake.md +1 -1
- package/pack/.claude/skills/rite-fast/SKILL.md +1 -1
- package/pack/.claude/skills/rite-plan/SKILL.md +4 -3
- package/pack/.claude/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/.claude/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/.claude/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/.claude/skills/rite-resolve/SKILL.md +3 -3
- package/pack/.claude/skills/rite-seal/SKILL.md +4 -3
- package/pack/.claude/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/.claude/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/.claude/skills/rite-ship/SKILL.md +4 -2
- package/pack/.claude/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/.claude/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/.claude/skills/rite-spec/SKILL.md +2 -2
- package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/.claude/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/.claude/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/.claude/skills/rite-temper/SKILL.md +12 -9
- package/pack/.claude/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/.claude/skills/rite-temper/reference/significance.md +10 -3
- package/pack/.claude/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/.claude/skills/rite-vet/SKILL.md +4 -3
- package/pack/.claude/skills/rite-vet/reference/artifacts.md +1 -1
- package/pack/.claude/workflows/devrites-readonly-review.js +5 -4
- package/pack/generated/claude/agents/devrites-spec-reviewer.md +2 -2
- package/pack/generated/claude/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/generated/claude/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/generated/claude/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/generated/claude/skills/devrites-interview/SKILL.md +4 -4
- package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +5 -2
- package/pack/generated/claude/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/generated/claude/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/generated/claude/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/generated/claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/generated/claude/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/generated/claude/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/generated/claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/generated/claude/skills/overhaul/SKILL.md +1 -1
- package/pack/generated/claude/skills/overhaul/references/orchestration.md +5 -3
- package/pack/generated/claude/skills/overhaul/references/records.md +39 -0
- package/pack/generated/claude/skills/overhaul/references/scoring.md +14 -4
- package/pack/generated/claude/skills/rite/reference/menu.md +1 -1
- package/pack/generated/claude/skills/rite-adopt/SKILL.md +8 -2
- package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/generated/claude/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/generated/claude/skills/rite-build/SKILL.md +2 -1
- package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/claude/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/generated/claude/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +6 -3
- package/pack/generated/claude/skills/rite-clarify/SKILL.md +5 -4
- package/pack/generated/claude/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/generated/claude/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/generated/claude/skills/rite-converge/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-customize/SKILL.md +6 -4
- package/pack/generated/claude/skills/rite-define/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-define/reference/gates.md +8 -7
- package/pack/generated/claude/skills/rite-explain/SKILL.md +1 -1
- package/pack/generated/claude/skills/rite-explain/reference/intake.md +1 -1
- package/pack/generated/claude/skills/rite-fast/SKILL.md +1 -1
- package/pack/generated/claude/skills/rite-plan/SKILL.md +4 -3
- package/pack/generated/claude/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/generated/claude/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/generated/claude/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/generated/claude/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/claude/skills/rite-seal/SKILL.md +4 -3
- package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/generated/claude/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/generated/claude/skills/rite-ship/SKILL.md +4 -2
- package/pack/generated/claude/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/generated/claude/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/generated/claude/skills/rite-spec/SKILL.md +2 -2
- package/pack/generated/claude/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/generated/claude/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/generated/claude/skills/rite-temper/SKILL.md +12 -9
- package/pack/generated/claude/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/generated/claude/skills/rite-temper/reference/significance.md +10 -3
- package/pack/generated/claude/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/generated/claude/skills/rite-vet/SKILL.md +4 -3
- package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +1 -1
- package/pack/generated/claude/workflows/devrites-readonly-review.js +5 -4
- package/pack/generated/codex/AGENTS.md +1 -1
- package/pack/generated/codex/agents/devrites-spec-reviewer.toml +2 -2
- package/pack/generated/codex/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/generated/codex/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/generated/codex/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/generated/codex/skills/devrites-interview/SKILL.md +4 -4
- package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +5 -2
- package/pack/generated/codex/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/generated/codex/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/generated/codex/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/generated/codex/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/generated/codex/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/generated/codex/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/generated/codex/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/generated/codex/skills/overhaul/SKILL.md +1 -1
- package/pack/generated/codex/skills/overhaul/references/orchestration.md +5 -3
- package/pack/generated/codex/skills/overhaul/references/records.md +39 -0
- package/pack/generated/codex/skills/overhaul/references/scoring.md +14 -4
- package/pack/generated/codex/skills/rite/reference/menu.md +1 -1
- package/pack/generated/codex/skills/rite-adopt/SKILL.md +8 -2
- package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/generated/codex/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/generated/codex/skills/rite-build/SKILL.md +2 -1
- package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/codex/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/generated/codex/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +6 -3
- package/pack/generated/codex/skills/rite-clarify/SKILL.md +5 -4
- package/pack/generated/codex/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/generated/codex/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/generated/codex/skills/rite-converge/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-customize/SKILL.md +6 -4
- package/pack/generated/codex/skills/rite-define/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-define/reference/gates.md +8 -7
- package/pack/generated/codex/skills/rite-explain/SKILL.md +1 -1
- package/pack/generated/codex/skills/rite-explain/reference/intake.md +1 -1
- package/pack/generated/codex/skills/rite-fast/SKILL.md +1 -1
- package/pack/generated/codex/skills/rite-plan/SKILL.md +4 -3
- package/pack/generated/codex/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/generated/codex/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/generated/codex/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/generated/codex/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/codex/skills/rite-seal/SKILL.md +4 -3
- package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/generated/codex/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/generated/codex/skills/rite-ship/SKILL.md +4 -2
- package/pack/generated/codex/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/generated/codex/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/generated/codex/skills/rite-spec/SKILL.md +2 -2
- package/pack/generated/codex/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/generated/codex/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/generated/codex/skills/rite-temper/SKILL.md +12 -9
- package/pack/generated/codex/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/generated/codex/skills/rite-temper/reference/significance.md +10 -3
- package/pack/generated/codex/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/generated/codex/skills/rite-vet/SKILL.md +4 -3
- package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +1 -1
- package/pack/generated/devin/AGENTS.md +1 -1
- package/pack/generated/devin/agents/devrites-spec-reviewer.md +2 -2
- package/pack/generated/devin/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/generated/devin/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/generated/devin/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/generated/devin/skills/devrites-interview/SKILL.md +4 -4
- package/pack/generated/devin/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/agents.md +5 -2
- package/pack/generated/devin/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/generated/devin/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/generated/devin/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/generated/devin/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/generated/devin/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/generated/devin/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/generated/devin/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/generated/devin/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/generated/devin/skills/overhaul/SKILL.md +1 -1
- package/pack/generated/devin/skills/overhaul/references/orchestration.md +5 -3
- package/pack/generated/devin/skills/overhaul/references/records.md +39 -0
- package/pack/generated/devin/skills/overhaul/references/scoring.md +14 -4
- package/pack/generated/devin/skills/rite/reference/menu.md +1 -1
- package/pack/generated/devin/skills/rite-adopt/SKILL.md +8 -2
- package/pack/generated/devin/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/generated/devin/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/generated/devin/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/generated/devin/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/generated/devin/skills/rite-build/SKILL.md +2 -1
- package/pack/generated/devin/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/devin/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/generated/devin/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/generated/devin/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/generated/devin/skills/rite-build/reference/wright-dispatch.md +6 -3
- package/pack/generated/devin/skills/rite-clarify/SKILL.md +5 -4
- package/pack/generated/devin/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/generated/devin/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/generated/devin/skills/rite-converge/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-customize/SKILL.md +6 -4
- package/pack/generated/devin/skills/rite-define/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-define/reference/gates.md +8 -7
- package/pack/generated/devin/skills/rite-explain/SKILL.md +1 -1
- package/pack/generated/devin/skills/rite-explain/reference/intake.md +1 -1
- package/pack/generated/devin/skills/rite-fast/SKILL.md +1 -1
- package/pack/generated/devin/skills/rite-plan/SKILL.md +4 -3
- package/pack/generated/devin/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/generated/devin/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/generated/devin/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/generated/devin/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/devin/skills/rite-seal/SKILL.md +4 -3
- package/pack/generated/devin/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/generated/devin/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/generated/devin/skills/rite-ship/SKILL.md +4 -2
- package/pack/generated/devin/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/generated/devin/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/generated/devin/skills/rite-spec/SKILL.md +2 -2
- package/pack/generated/devin/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/generated/devin/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/generated/devin/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/generated/devin/skills/rite-temper/SKILL.md +12 -9
- package/pack/generated/devin/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/generated/devin/skills/rite-temper/reference/significance.md +10 -3
- package/pack/generated/devin/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/generated/devin/skills/rite-vet/SKILL.md +4 -3
- package/pack/generated/devin/skills/rite-vet/reference/artifacts.md +1 -1
- package/pack/generated/omp/agents/devrites-spec-reviewer.md +2 -2
- package/pack/generated/omp/commands/rite-define.md +1 -1
- package/pack/generated/omp/commands/rite-handoff.md +1 -1
- package/pack/generated/omp/commands/rite-plan.md +1 -1
- package/pack/generated/omp/commands/rite-pressure-test.md +1 -1
- package/pack/generated/omp/commands/rite-quick.md +1 -1
- package/pack/generated/omp/commands/rite-status.md +1 -1
- package/pack/generated/omp/commands/rite-temper.md +1 -1
- package/pack/generated/omp/commands/rite-zoom-out.md +1 -1
- package/pack/generated/omp/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/generated/omp/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/generated/omp/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/generated/omp/skills/devrites-interview/SKILL.md +4 -4
- package/pack/generated/omp/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/agents.md +5 -2
- package/pack/generated/omp/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/generated/omp/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/generated/omp/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/generated/omp/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/generated/omp/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/generated/omp/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/generated/omp/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/generated/omp/skills/overhaul/SKILL.md +1 -1
- package/pack/generated/omp/skills/overhaul/references/orchestration.md +5 -3
- package/pack/generated/omp/skills/overhaul/references/records.md +39 -0
- package/pack/generated/omp/skills/overhaul/references/scoring.md +14 -4
- package/pack/generated/omp/skills/rite/reference/menu.md +1 -1
- package/pack/generated/omp/skills/rite-adopt/SKILL.md +8 -2
- package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/generated/omp/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/generated/omp/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/generated/omp/skills/rite-build/SKILL.md +2 -1
- package/pack/generated/omp/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/omp/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/generated/omp/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/generated/omp/skills/rite-build/reference/wright-dispatch.md +6 -3
- package/pack/generated/omp/skills/rite-clarify/SKILL.md +5 -4
- package/pack/generated/omp/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/generated/omp/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/generated/omp/skills/rite-converge/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-customize/SKILL.md +6 -4
- package/pack/generated/omp/skills/rite-define/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-define/reference/gates.md +8 -7
- package/pack/generated/omp/skills/rite-explain/SKILL.md +1 -1
- package/pack/generated/omp/skills/rite-explain/reference/intake.md +1 -1
- package/pack/generated/omp/skills/rite-fast/SKILL.md +1 -1
- package/pack/generated/omp/skills/rite-plan/SKILL.md +4 -3
- package/pack/generated/omp/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/generated/omp/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/generated/omp/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/generated/omp/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/omp/skills/rite-seal/SKILL.md +4 -3
- package/pack/generated/omp/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/generated/omp/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/generated/omp/skills/rite-ship/SKILL.md +4 -2
- package/pack/generated/omp/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/generated/omp/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/generated/omp/skills/rite-spec/SKILL.md +2 -2
- package/pack/generated/omp/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/generated/omp/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/generated/omp/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/generated/omp/skills/rite-temper/SKILL.md +12 -9
- package/pack/generated/omp/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/generated/omp/skills/rite-temper/reference/significance.md +10 -3
- package/pack/generated/omp/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/generated/omp/skills/rite-vet/SKILL.md +4 -3
- package/pack/generated/omp/skills/rite-vet/reference/artifacts.md +1 -1
- package/pack/generated/pi/AGENTS.md +1 -1
- package/pack/generated/pi/agents/devrites-spec-reviewer.md +2 -2
- package/pack/generated/pi/prompts/rite-define.md +1 -1
- package/pack/generated/pi/prompts/rite-handoff.md +1 -1
- package/pack/generated/pi/prompts/rite-plan.md +1 -1
- package/pack/generated/pi/prompts/rite-pressure-test.md +1 -1
- package/pack/generated/pi/prompts/rite-quick.md +1 -1
- package/pack/generated/pi/prompts/rite-status.md +1 -1
- package/pack/generated/pi/prompts/rite-temper.md +1 -1
- package/pack/generated/pi/prompts/rite-zoom-out.md +1 -1
- package/pack/generated/pi/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/generated/pi/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/generated/pi/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/generated/pi/skills/devrites-interview/SKILL.md +4 -4
- package/pack/generated/pi/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/agents.md +5 -2
- package/pack/generated/pi/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/generated/pi/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/generated/pi/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/generated/pi/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/generated/pi/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/generated/pi/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/generated/pi/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/generated/pi/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/generated/pi/skills/overhaul/SKILL.md +1 -1
- package/pack/generated/pi/skills/overhaul/references/orchestration.md +5 -3
- package/pack/generated/pi/skills/overhaul/references/records.md +39 -0
- package/pack/generated/pi/skills/overhaul/references/scoring.md +14 -4
- package/pack/generated/pi/skills/rite/reference/menu.md +1 -1
- package/pack/generated/pi/skills/rite-adopt/SKILL.md +8 -2
- package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/generated/pi/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/generated/pi/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/generated/pi/skills/rite-build/SKILL.md +2 -1
- package/pack/generated/pi/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/pi/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/generated/pi/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/generated/pi/skills/rite-build/reference/wright-dispatch.md +6 -3
- package/pack/generated/pi/skills/rite-clarify/SKILL.md +5 -4
- package/pack/generated/pi/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/generated/pi/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/generated/pi/skills/rite-converge/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-customize/SKILL.md +6 -4
- package/pack/generated/pi/skills/rite-define/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-define/reference/gates.md +8 -7
- package/pack/generated/pi/skills/rite-explain/SKILL.md +1 -1
- package/pack/generated/pi/skills/rite-explain/reference/intake.md +1 -1
- package/pack/generated/pi/skills/rite-fast/SKILL.md +1 -1
- package/pack/generated/pi/skills/rite-plan/SKILL.md +4 -3
- package/pack/generated/pi/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/generated/pi/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/generated/pi/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/generated/pi/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/pi/skills/rite-seal/SKILL.md +4 -3
- package/pack/generated/pi/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/generated/pi/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/generated/pi/skills/rite-ship/SKILL.md +4 -2
- package/pack/generated/pi/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/generated/pi/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/generated/pi/skills/rite-spec/SKILL.md +2 -2
- package/pack/generated/pi/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/generated/pi/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/generated/pi/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/generated/pi/skills/rite-temper/SKILL.md +12 -9
- package/pack/generated/pi/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/generated/pi/skills/rite-temper/reference/significance.md +10 -3
- package/pack/generated/pi/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/generated/pi/skills/rite-vet/SKILL.md +4 -3
- package/pack/generated/pi/skills/rite-vet/reference/artifacts.md +1 -1
- package/package.json +5 -4
- package/scripts/build-host-artifacts.sh +15 -0
- package/scripts/codex-generate.sh +1 -1
- package/scripts/devin-generate.sh +1 -1
- package/scripts/expand-includes.py +46 -0
- package/scripts/install-lib.sh +42 -7
- package/scripts/omp-generate.sh +11 -0
- package/scripts/pi-generate.sh +12 -1
- package/update.sh +1 -2
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/README.md +0 -7
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/architecture.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/assumptions.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/brief.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/decision-coverage.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/decisions.md +0 -4
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/eng-review.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/gates.md +0 -4
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/plan.md +0 -5
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/questions.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/spec.md +0 -6
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/state.md +0 -8
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/tasks.md +0 -1
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/test-plan.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/traceability.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/README.md +0 -7
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/assumptions.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/brief.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/decisions.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/questions.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/spec.md +0 -6
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/state.md +0 -3
- package/engine/testdata/golden/TestParityCloseOut/active_pointed_elsewhere.golden +0 -2
- package/engine/testdata/golden/TestParityCloseOut/active_slug_cleared.golden +0 -2
- package/engine/testdata/golden/TestParityCloseOut/archive_clobber.golden +0 -1
- package/engine/testdata/golden/TestParityCloseOut/missing_slug.golden +0 -1
- package/engine/testdata/golden/TestParityCloseOut/missing_workspace.golden +0 -1
- package/engine/testdata/golden/TestParityLearnings/add.golden +0 -2
- package/engine/testdata/golden/TestParityLearnings/list.golden +0 -5
- package/engine/testdata/golden/TestParityLearnings/mine-no-archive.golden +0 -2
- package/engine/testdata/golden/TestParityLearnings/mine.golden +0 -5
- package/engine/testdata/golden/TestParityLearnings/nudge.golden +0 -2
- package/engine/testdata/golden/TestParityLearnings/unknown.golden +0 -1
- package/engine/testdata/golden/TestParityPackageExistence/ghost-workspace.golden +0 -1
- package/engine/testdata/golden/TestParityPackageExistence/no-manifest.golden +0 -1
- package/engine/testdata/golden/TestParityPackageExistence/not-git.golden +0 -1
- package/engine/testdata/golden/TestParityPackageExistence/undeclared.golden +0 -1
- package/engine/testdata/golden/TestParityPreamble/afk/a.golden +0 -14
- package/engine/testdata/golden/TestParityPreamble/hitl/active.golden +0 -18
- package/engine/testdata/golden/TestParityPreamble/hitl/bare.golden +0 -10
- package/engine/testdata/golden/TestParityPreamble/hitl/full.golden +0 -18
- package/engine/testdata/golden/TestParityPreamble/hitl/ghost.golden +0 -2
- package/engine/testdata/golden/TestParityPreamble/hitl/nonl.golden +0 -11
- package/engine/testdata/golden/TestParityPreamble/hitl/openend.golden +0 -13
- package/engine/testdata/golden/TestParityProgress/arg=allbuilt.golden +0 -4
- package/engine/testdata/golden/TestParityProgress/arg=done.golden +0 -3
- package/engine/testdata/golden/TestParityProgress/arg=ghost.golden +0 -1
- package/engine/testdata/golden/TestParityProgress/arg=mid.golden +0 -4
- package/engine/testdata/golden/TestParityProgress/arg=nophase.golden +0 -3
- package/engine/testdata/golden/TestParityProgress/arg=noslice.golden +0 -3
- package/engine/testdata/golden/TestParityProgress/arg=plan.golden +0 -4
- package/engine/testdata/golden/TestParityProgress/arg=seal.golden +0 -3
- package/engine/testdata/golden/TestParityResolve/answer/questions.md.golden +0 -9
- package/engine/testdata/golden/TestParityResolve/answer/state.md.golden +0 -7
- package/engine/testdata/golden/TestParityResolve/answer.golden +0 -4
- package/engine/testdata/golden/TestParityResolve/batch/questions.md.golden +0 -9
- package/engine/testdata/golden/TestParityResolve/batch-unterminated/questions.md.golden +0 -9
- package/engine/testdata/golden/TestParityResolve/batch-unterminated.golden +0 -2
- package/engine/testdata/golden/TestParityResolve/batch.golden +0 -3
- package/engine/testdata/golden/TestParityResolve/drop/questions.md.golden +0 -9
- package/engine/testdata/golden/TestParityResolve/drop/state.md.golden +0 -9
- package/engine/testdata/golden/TestParityResolve/drop.golden +0 -4
- package/engine/testdata/golden/TestParityResolve/missing-answer.golden +0 -1
- package/engine/testdata/golden/TestParityResolve/no-workspace.golden +0 -1
- package/engine/testdata/golden/TestParityResolve/not-found.golden +0 -1
- package/engine/testdata/golden/TestParityResolve/not-open.golden +0 -1
- package/engine/testdata/golden/TestStatusLiveWorkspace.golden +0 -10
- package/engine/testdata/golden/status/auth-tokens.txt +0 -9
- package/engine/testdata/golden/status/search-ranking.txt +0 -9
- package/engine/testdata/visual/open-visual-smoke.html +0 -675
- package/engine/testdata/visual/open-visual-smoke.outline.md +0 -54
- package/engine/tests/adr_0003_gate_exit_code_test.go +0 -32
- package/engine/tests/adr_0004_required_by_phase_test.go +0 -54
- package/engine/tests/adr_0011_define_plan_test.go +0 -32
- package/engine/tests/adr_0027_readiness_binding_test.go +0 -107
- package/engine/tests/cli_test.go +0 -126
- package/engine/tests/gate_test.go +0 -669
- package/engine/tests/meta_test.go +0 -37
- package/engine/tests/parity_closeout_test.go +0 -105
- package/engine/tests/parity_githelpers_test.go +0 -41
- package/engine/tests/parity_resolve_test.go +0 -136
- package/engine/tests/parity_test.go +0 -86
- package/engine/tests/workspace_observation_migration_test.go +0 -1069
|
@@ -39,6 +39,10 @@ func Resolve(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
39
39
|
return fail(stderr, err.Error(), 3)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
human := argAt(args, 0) == "--human"
|
|
43
|
+
if human {
|
|
44
|
+
args = args[1:]
|
|
45
|
+
}
|
|
42
46
|
var mode, qid, payload string
|
|
43
47
|
switch first := argAt(args, 0); first {
|
|
44
48
|
case "--drop":
|
|
@@ -55,7 +59,7 @@ func Resolve(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
55
59
|
return fail(stderr, "Batch file not found: "+payload, 5)
|
|
56
60
|
}
|
|
57
61
|
case "":
|
|
58
|
-
return fail(stderr, `Usage: devrites-engine state resolve <qid> "<answer>" | state resolve --drop <qid> ["<reason>"] | state resolve --batch <file>`, 5)
|
|
62
|
+
return fail(stderr, `Usage: devrites-engine state resolve [--human] <qid> "<answer>" | state resolve [--human] --drop <qid> ["<reason>"] | state resolve [--human] --batch <file>`, 5)
|
|
59
63
|
default:
|
|
60
64
|
mode = "answer"
|
|
61
65
|
qid = first
|
|
@@ -67,7 +71,7 @@ func Resolve(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
67
71
|
|
|
68
72
|
code := 0
|
|
69
73
|
if err := state.WithFeatureLock(root, slug, func() error {
|
|
70
|
-
code = resolveMutation(mode, qid, payload, qfile, sfile, stdout, stderr)
|
|
74
|
+
code = resolveMutation(mode, qid, payload, qfile, sfile, human, stdout, stderr)
|
|
71
75
|
return nil
|
|
72
76
|
}); err != nil {
|
|
73
77
|
return fail(stderr, err.Error(), 1)
|
|
@@ -75,10 +79,10 @@ func Resolve(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
75
79
|
return code
|
|
76
80
|
}
|
|
77
81
|
|
|
78
|
-
func resolveMutation(mode, qid, payload, qfile, sfile string, stdout, stderr io.Writer) int {
|
|
82
|
+
func resolveMutation(mode, qid, payload, qfile, sfile string, human bool, stdout, stderr io.Writer) int {
|
|
79
83
|
switch mode {
|
|
80
84
|
case "answer":
|
|
81
|
-
if code := resolveQuestion(qfile, qid, "answered", payload, stderr); code != 0 {
|
|
85
|
+
if code := resolveQuestion(qfile, qid, "answered", payload, human, stderr); code != 0 {
|
|
82
86
|
return code
|
|
83
87
|
}
|
|
84
88
|
if err := clearAwaiting(sfile, qid); err != nil {
|
|
@@ -88,7 +92,7 @@ func resolveMutation(mode, qid, payload, qfile, sfile string, stdout, stderr io.
|
|
|
88
92
|
fmt.Fprintf(stdout, "Status: answered\n")
|
|
89
93
|
fmt.Fprintf(stdout, "Workspace: questions.md + state.md updated.\n")
|
|
90
94
|
case "drop":
|
|
91
|
-
if code := resolveQuestion(qfile, qid, "dropped", payload, stderr); code != 0 {
|
|
95
|
+
if code := resolveQuestion(qfile, qid, "dropped", payload, human, stderr); code != 0 {
|
|
92
96
|
return code
|
|
93
97
|
}
|
|
94
98
|
if err := clearAwaiting(sfile, qid); err != nil {
|
|
@@ -111,7 +115,7 @@ func resolveMutation(mode, qid, payload, qfile, sfile string, stdout, stderr io.
|
|
|
111
115
|
rest := strings.TrimPrefix(line, "--drop ")
|
|
112
116
|
bid, reason := splitColon(rest)
|
|
113
117
|
reason = strings.TrimPrefix(reason, " ")
|
|
114
|
-
if code := resolveQuestion(qfile, bid, "dropped", reason, stderr); code != 0 {
|
|
118
|
+
if code := resolveQuestion(qfile, bid, "dropped", reason, human, stderr); code != 0 {
|
|
115
119
|
return code
|
|
116
120
|
}
|
|
117
121
|
if err := clearAwaiting(sfile, bid); err != nil {
|
|
@@ -121,7 +125,7 @@ func resolveMutation(mode, qid, payload, qfile, sfile string, stdout, stderr io.
|
|
|
121
125
|
} else {
|
|
122
126
|
bid, ans := splitColon(line)
|
|
123
127
|
ans = strings.TrimPrefix(ans, " ")
|
|
124
|
-
if code := resolveQuestion(qfile, bid, "answered", ans, stderr); code != 0 {
|
|
128
|
+
if code := resolveQuestion(qfile, bid, "answered", ans, human, stderr); code != 0 {
|
|
125
129
|
return code
|
|
126
130
|
}
|
|
127
131
|
if err := clearAwaiting(sfile, bid); err != nil {
|
|
@@ -156,12 +160,15 @@ func isFile(path string) bool {
|
|
|
156
160
|
return err == nil && info.Mode().IsRegular()
|
|
157
161
|
}
|
|
158
162
|
|
|
159
|
-
// batchLines returns the
|
|
160
|
-
//
|
|
161
|
-
// is
|
|
163
|
+
// batchLines returns the lines of a batch file. A final line without a
|
|
164
|
+
// terminating newline is kept; only the empty element after a trailing newline
|
|
165
|
+
// is dropped.
|
|
162
166
|
func batchLines(data []byte) []string {
|
|
163
167
|
lines := strings.Split(string(data), "\n")
|
|
164
|
-
|
|
168
|
+
if lines[len(lines)-1] == "" {
|
|
169
|
+
lines = lines[:len(lines)-1]
|
|
170
|
+
}
|
|
171
|
+
return lines
|
|
165
172
|
}
|
|
166
173
|
|
|
167
174
|
// splitColon splits s at the first ':', returning the parts before and after it
|
|
@@ -192,9 +199,12 @@ func clockNow() time.Time {
|
|
|
192
199
|
func nowUTC() string { return clockNow().UTC().Format("2006-01-02T15:04:05Z") }
|
|
193
200
|
|
|
194
201
|
// resolveQuestion rewrites the <qid> block in questions.md so it records the new
|
|
195
|
-
// status, answer, and answered-at time in one pass.
|
|
202
|
+
// status, answer, and answered-at time in one pass. With human set it also records
|
|
203
|
+
// answered_by: human; without it any answered_by line in the block, whatever its
|
|
204
|
+
// indentation or case, is removed, so
|
|
205
|
+
// an identity written before the resolve cannot survive it. Returns 0, or 3 (qid
|
|
196
206
|
// not found) / 4 (qid not open), writing the message on failure.
|
|
197
|
-
func resolveQuestion(qfile, qid, status, answer string, stderr io.Writer) int {
|
|
207
|
+
func resolveQuestion(qfile, qid, status, answer string, human bool, stderr io.Writer) int {
|
|
198
208
|
// #nosec G304 -- questions.md path inside the feature workspace
|
|
199
209
|
data, err := os.ReadFile(qfile)
|
|
200
210
|
if err != nil {
|
|
@@ -204,7 +214,7 @@ func resolveQuestion(qfile, qid, status, answer string, stderr io.Writer) int {
|
|
|
204
214
|
answer = oneLine(answer)
|
|
205
215
|
target := regexp.MustCompile(`^## ` + regexp.QuoteMeta(qid) + `([[:space:]]|$)`)
|
|
206
216
|
|
|
207
|
-
updated, found, notOpen := rewriteQuestionFields(splitLinesNoTrailing(data), target, status, answer, ts)
|
|
217
|
+
updated, found, notOpen := rewriteQuestionFields(splitLinesNoTrailing(data), target, status, answer, ts, human)
|
|
208
218
|
if !found {
|
|
209
219
|
return fail(stderr, "qid not found: "+qid, 3)
|
|
210
220
|
}
|
|
@@ -224,6 +234,7 @@ var (
|
|
|
224
234
|
statusStrip = regexp.MustCompile(`^status:[[:space:]]*`)
|
|
225
235
|
answeredAtRe = regexp.MustCompile(`^answered_at:`)
|
|
226
236
|
answerRe = regexp.MustCompile(`^answer:`)
|
|
237
|
+
answeredByRe = regexp.MustCompile(`(?i)^[[:space:]]*answered_by:`)
|
|
227
238
|
)
|
|
228
239
|
|
|
229
240
|
// rewriteQuestionFields walks questions.md and, inside the target question's
|
|
@@ -231,9 +242,9 @@ var (
|
|
|
231
242
|
// reports whether the block was found and whether it was already not open (an
|
|
232
243
|
// attempt to re-answer). A target block with no status line at all gets a full set
|
|
233
244
|
// of closing fields appended.
|
|
234
|
-
func rewriteQuestionFields(lines []string, target *regexp.Regexp, status, answer, ts string) (out []string, found, notOpen bool) {
|
|
245
|
+
func rewriteQuestionFields(lines []string, target *regexp.Regexp, status, answer, ts string, human bool) (out []string, found, notOpen bool) {
|
|
235
246
|
inQ := false
|
|
236
|
-
statusSeen, answeredAtSeen, answerSeen := false, false, false
|
|
247
|
+
statusSeen, answeredAtSeen, answerSeen, answeredBySeen := false, false, false, false
|
|
237
248
|
closeBlock := func() {
|
|
238
249
|
if !inQ {
|
|
239
250
|
return
|
|
@@ -247,13 +258,16 @@ func rewriteQuestionFields(lines []string, target *regexp.Regexp, status, answer
|
|
|
247
258
|
if !answerSeen {
|
|
248
259
|
out = append(out, "answer: "+answer)
|
|
249
260
|
}
|
|
261
|
+
if human && !answeredBySeen {
|
|
262
|
+
out = append(out, "answered_by: human")
|
|
263
|
+
}
|
|
250
264
|
}
|
|
251
265
|
for _, line := range lines {
|
|
252
266
|
switch {
|
|
253
267
|
case qHeaderRe.MatchString(line):
|
|
254
268
|
closeBlock()
|
|
255
269
|
inQ = target.MatchString(line)
|
|
256
|
-
statusSeen, answeredAtSeen, answerSeen = false, false, false
|
|
270
|
+
statusSeen, answeredAtSeen, answerSeen, answeredBySeen = false, false, false, false
|
|
257
271
|
if inQ {
|
|
258
272
|
found = true
|
|
259
273
|
}
|
|
@@ -274,6 +288,11 @@ func rewriteQuestionFields(lines []string, target *regexp.Regexp, status, answer
|
|
|
274
288
|
case inQ && answerRe.MatchString(line):
|
|
275
289
|
answerSeen = true
|
|
276
290
|
out = append(out, "answer: "+answer)
|
|
291
|
+
case inQ && answeredByRe.MatchString(line):
|
|
292
|
+
if human && !answeredBySeen {
|
|
293
|
+
answeredBySeen = true
|
|
294
|
+
out = append(out, "answered_by: human")
|
|
295
|
+
}
|
|
277
296
|
default:
|
|
278
297
|
out = append(out, line)
|
|
279
298
|
}
|
|
@@ -58,3 +58,135 @@ func resolveWorkspace(t *testing.T, questions string) string {
|
|
|
58
58
|
testutil.WriteFile(t, filepath.Join(root, "work", "feat", "state.md"), "- Status: running\n- Next step: continue\n- Schema: 4\n")
|
|
59
59
|
return root
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
func TestResolveHumanFlagRecordsResolverIdentity(t *testing.T) {
|
|
63
|
+
root := resolveWorkspace(t, "## q-1 blocking\nstatus: open\n")
|
|
64
|
+
var stdout, stderr bytes.Buffer
|
|
65
|
+
|
|
66
|
+
if code := Resolve(root, []string{"--human", "q-1", "yes"}, &stdout, &stderr); code != 0 {
|
|
67
|
+
t.Fatalf("code = %d, want 0; stderr=%q", code, stderr.String())
|
|
68
|
+
}
|
|
69
|
+
data, err := os.ReadFile(filepath.Join(root, "work", "feat", "questions.md"))
|
|
70
|
+
if err != nil {
|
|
71
|
+
t.Fatal(err)
|
|
72
|
+
}
|
|
73
|
+
if !strings.Contains(string(data), "answered_by: human\n") {
|
|
74
|
+
t.Fatalf("questions.md missing answered_by: human:\n%s", data)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
func TestResolveWithoutHumanFlagDropsPreSeededIdentity(t *testing.T) {
|
|
79
|
+
root := resolveWorkspace(t, "## q-1 blocking\nstatus: open\nanswered_by: human\n")
|
|
80
|
+
var stdout, stderr bytes.Buffer
|
|
81
|
+
|
|
82
|
+
if code := Resolve(root, []string{"q-1", "yes"}, &stdout, &stderr); code != 0 {
|
|
83
|
+
t.Fatalf("code = %d, want 0; stderr=%q", code, stderr.String())
|
|
84
|
+
}
|
|
85
|
+
data, err := os.ReadFile(filepath.Join(root, "work", "feat", "questions.md"))
|
|
86
|
+
if err != nil {
|
|
87
|
+
t.Fatal(err)
|
|
88
|
+
}
|
|
89
|
+
if strings.Contains(string(data), "answered_by") {
|
|
90
|
+
t.Fatalf("forged answered_by survived an unflagged resolve:\n%s", data)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
func TestResolveWithoutHumanFlagDropsVariantPreSeededIdentity(t *testing.T) {
|
|
95
|
+
for _, seed := range []string{" answered_by: human", "Answered_By: human", "\tANSWERED_BY: human"} {
|
|
96
|
+
root := resolveWorkspace(t, "## q-1 blocking\nstatus: open\n"+seed+"\n")
|
|
97
|
+
var stdout, stderr bytes.Buffer
|
|
98
|
+
|
|
99
|
+
if code := Resolve(root, []string{"q-1", "yes"}, &stdout, &stderr); code != 0 {
|
|
100
|
+
t.Fatalf("%q: code = %d, want 0; stderr=%q", seed, code, stderr.String())
|
|
101
|
+
}
|
|
102
|
+
if text := readQuestions(t, root); strings.Contains(strings.ToLower(text), "answered_by") {
|
|
103
|
+
t.Fatalf("%q: forged answered_by survived an unflagged resolve:\n%s", seed, text)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
func TestResolveHumanFlagKeepsSingleCanonicalIdentity(t *testing.T) {
|
|
109
|
+
root := resolveWorkspace(t, "## q-1 blocking\nstatus: open\n answered_by: agent\nAnswered_By: agent\n")
|
|
110
|
+
var stdout, stderr bytes.Buffer
|
|
111
|
+
|
|
112
|
+
if code := Resolve(root, []string{"--human", "q-1", "yes"}, &stdout, &stderr); code != 0 {
|
|
113
|
+
t.Fatalf("code = %d, want 0; stderr=%q", code, stderr.String())
|
|
114
|
+
}
|
|
115
|
+
text := readQuestions(t, root)
|
|
116
|
+
if strings.Count(strings.ToLower(text), "answered_by") != 1 || !strings.Contains(text, "\nanswered_by: human\n") {
|
|
117
|
+
t.Fatalf("want exactly one canonical answered_by: human:\n%s", text)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func TestResolveDropHonorsHumanFlag(t *testing.T) {
|
|
122
|
+
seeded := "## q-1 blocking\nstatus: open\n answered_by: human\n"
|
|
123
|
+
for _, tc := range []struct {
|
|
124
|
+
args []string
|
|
125
|
+
want bool
|
|
126
|
+
}{
|
|
127
|
+
{[]string{"--human", "--drop", "q-1", "obsolete"}, true},
|
|
128
|
+
{[]string{"--drop", "q-1", "obsolete"}, false},
|
|
129
|
+
} {
|
|
130
|
+
root := resolveWorkspace(t, seeded)
|
|
131
|
+
var stdout, stderr bytes.Buffer
|
|
132
|
+
|
|
133
|
+
if code := Resolve(root, tc.args, &stdout, &stderr); code != 0 {
|
|
134
|
+
t.Fatalf("%v: code = %d, want 0; stderr=%q", tc.args, code, stderr.String())
|
|
135
|
+
}
|
|
136
|
+
text := readQuestions(t, root)
|
|
137
|
+
if got := strings.Contains(text, "\nanswered_by: human\n"); got != tc.want || !strings.Contains(text, "status: dropped") {
|
|
138
|
+
t.Fatalf("%v: canonical answered_by = %v, want %v:\n%s", tc.args, got, tc.want, text)
|
|
139
|
+
}
|
|
140
|
+
if !tc.want && strings.Contains(text, "answered_by") {
|
|
141
|
+
t.Fatalf("%v: answered_by survived:\n%s", tc.args, text)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
func TestResolveBatchHonorsHumanFlag(t *testing.T) {
|
|
147
|
+
questions := "## q-1 blocking\nstatus: open\n answered_by: human\n## q-2 blocking\nstatus: open\n"
|
|
148
|
+
batch := "q-1: yes\n--drop q-2: obsolete\n"
|
|
149
|
+
for _, tc := range []struct {
|
|
150
|
+
args []string
|
|
151
|
+
want int
|
|
152
|
+
}{
|
|
153
|
+
{[]string{"--human"}, 2},
|
|
154
|
+
{nil, 0},
|
|
155
|
+
} {
|
|
156
|
+
root := resolveWorkspace(t, questions)
|
|
157
|
+
file := filepath.Join(t.TempDir(), "batch.txt")
|
|
158
|
+
testutil.WriteFile(t, file, batch)
|
|
159
|
+
var stdout, stderr bytes.Buffer
|
|
160
|
+
|
|
161
|
+
if code := Resolve(root, append(tc.args, "--batch", file), &stdout, &stderr); code != 0 {
|
|
162
|
+
t.Fatalf("%v: code = %d, want 0; stderr=%q", tc.args, code, stderr.String())
|
|
163
|
+
}
|
|
164
|
+
text := readQuestions(t, root)
|
|
165
|
+
if got := strings.Count(text, "\nanswered_by: human\n"); got != tc.want || (tc.want == 0 && strings.Contains(text, "answered_by")) {
|
|
166
|
+
t.Fatalf("%v: answered_by count = %d, want %d:\n%s", tc.args, got, tc.want, text)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
func readQuestions(t *testing.T, root string) string {
|
|
172
|
+
t.Helper()
|
|
173
|
+
data, err := os.ReadFile(filepath.Join(root, "work", "feat", "questions.md"))
|
|
174
|
+
if err != nil {
|
|
175
|
+
t.Fatal(err)
|
|
176
|
+
}
|
|
177
|
+
return string(data)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
func TestResolveBatchAppliesUnterminatedFinalLine(t *testing.T) {
|
|
181
|
+
root := resolveWorkspace(t, "## q-1 blocking\nstatus: open\n## q-2 blocking\nstatus: open\n")
|
|
182
|
+
file := filepath.Join(t.TempDir(), "batch.txt")
|
|
183
|
+
testutil.WriteFile(t, file, "q-1: yes\n--drop q-2: obsolete")
|
|
184
|
+
var stdout, stderr bytes.Buffer
|
|
185
|
+
|
|
186
|
+
if code := Resolve(root, []string{"--batch", file}, &stdout, &stderr); code != 0 {
|
|
187
|
+
t.Fatalf("code = %d, want 0; stderr=%q", code, stderr.String())
|
|
188
|
+
}
|
|
189
|
+
if text := readQuestions(t, root); strings.Contains(text, "status: open") {
|
|
190
|
+
t.Fatalf("a question stayed open:\n%s", text)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -7,7 +7,6 @@ import (
|
|
|
7
7
|
"path/filepath"
|
|
8
8
|
"regexp"
|
|
9
9
|
"strings"
|
|
10
|
-
"unicode"
|
|
11
10
|
)
|
|
12
11
|
|
|
13
12
|
// SkillTrustFinding is one deterministic trust scan result.
|
|
@@ -185,13 +184,3 @@ func FormatSkillTrust(result SkillTrustResult) string {
|
|
|
185
184
|
}
|
|
186
185
|
return b.String()
|
|
187
186
|
}
|
|
188
|
-
|
|
189
|
-
// ContainsOnlyASCII returns false when non-ASCII control or bidi characters appear.
|
|
190
|
-
func ContainsOnlyASCII(text string) bool {
|
|
191
|
-
for _, r := range text {
|
|
192
|
-
if r > unicode.MaxASCII && isSuspiciousUnicode(r) {
|
|
193
|
-
return false
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return true
|
|
197
|
-
}
|
|
@@ -3,6 +3,7 @@ package lib
|
|
|
3
3
|
import (
|
|
4
4
|
"fmt"
|
|
5
5
|
"io"
|
|
6
|
+
"path"
|
|
6
7
|
"regexp"
|
|
7
8
|
"strings"
|
|
8
9
|
|
|
@@ -68,6 +69,7 @@ func checkAllowlistPaths(paths []string) []string {
|
|
|
68
69
|
var problems []string
|
|
69
70
|
seen := map[string]bool{}
|
|
70
71
|
for _, p := range paths {
|
|
72
|
+
c := path.Clean(p)
|
|
71
73
|
switch {
|
|
72
74
|
case strings.HasPrefix(p, "/") || windowsDrivePath.MatchString(p):
|
|
73
75
|
problems = append(problems, fmt.Sprintf("allowlist path %q is not project-relative", p))
|
|
@@ -77,12 +79,12 @@ func checkAllowlistPaths(paths []string) []string {
|
|
|
77
79
|
problems = append(problems, fmt.Sprintf("allowlist path %q uses a glob — exact paths only", p))
|
|
78
80
|
case strings.HasSuffix(p, "/"):
|
|
79
81
|
problems = append(problems, fmt.Sprintf("allowlist path %q is a directory — exact files only", p))
|
|
80
|
-
case devritesPathRe.MatchString(
|
|
82
|
+
case devritesPathRe.MatchString(c):
|
|
81
83
|
problems = append(problems, fmt.Sprintf("allowlist path %q targets .devrites — wrights never write workflow state", p))
|
|
82
|
-
case seen[
|
|
84
|
+
case seen[c]:
|
|
83
85
|
problems = append(problems, fmt.Sprintf("allowlist path %q is duplicated", p))
|
|
84
86
|
}
|
|
85
|
-
seen[
|
|
87
|
+
seen[c] = true
|
|
86
88
|
}
|
|
87
89
|
return problems
|
|
88
90
|
}
|
|
@@ -128,10 +130,10 @@ func RunCheckSlice(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
128
130
|
if touchedRaw, ok := fieldValue(fields, "files likely touched"); ok {
|
|
129
131
|
allowed := map[string]bool{}
|
|
130
132
|
for _, p := range allowlist {
|
|
131
|
-
allowed[p] = true
|
|
133
|
+
allowed[path.Clean(p)] = true
|
|
132
134
|
}
|
|
133
135
|
for _, p := range parsePathList(touchedRaw) {
|
|
134
|
-
if hasAllow && !allowed[p] {
|
|
136
|
+
if hasAllow && !allowed[path.Clean(p)] {
|
|
135
137
|
problems = append(problems, fmt.Sprintf("Files likely touched %q is outside the Writer allowlist", p))
|
|
136
138
|
}
|
|
137
139
|
}
|
|
@@ -109,3 +109,21 @@ Tests/proof: none needed
|
|
|
109
109
|
t.Fatalf("code=%d out:\n%s%s", code, stdout, stderr)
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
+
|
|
113
|
+
func TestCheckAllowlistPathsNormalizesBeforeRules(t *testing.T) {
|
|
114
|
+
if got := checkAllowlistPaths([]string{"./.devrites/state.md"}); len(got) != 1 || !strings.Contains(got[0], ".devrites") {
|
|
115
|
+
t.Fatalf("./.devrites path not rejected as workflow state: %v", got)
|
|
116
|
+
}
|
|
117
|
+
if got := checkAllowlistPaths([]string{"src/a.go", "./src/a.go"}); len(got) != 1 || !strings.Contains(got[0], "duplicated") {
|
|
118
|
+
t.Fatalf("./src/a.go not detected as duplicate of src/a.go: %v", got)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
func TestCheckSliceTouchedComparesNormalizedPaths(t *testing.T) {
|
|
123
|
+
tasks := strings.Replace(goodSliceTasks, "Files likely touched: src/a.go; src/a_test.go", "Files likely touched: ./src/a.go; src/a_test.go", 1)
|
|
124
|
+
root := sliceWorkspace(t, tasks, sliceSpec)
|
|
125
|
+
stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
|
|
126
|
+
if code := RunCheckSlice(root, []string{"feat", "SLICE-001"}, stdout, stderr); code != 0 {
|
|
127
|
+
t.Fatalf("code=%d want 0\n%s%s", code, stdout, stderr)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package lib
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"io"
|
|
4
5
|
"os"
|
|
5
6
|
"path/filepath"
|
|
6
7
|
"regexp"
|
|
@@ -103,11 +104,16 @@ func gatherTriggerFacts(root, featureDir, role string) triggerFacts {
|
|
|
103
104
|
for _, name := range triggerEvidenceFiles {
|
|
104
105
|
path := filepath.Join(featureDir, name)
|
|
105
106
|
info, err := os.Stat(path)
|
|
106
|
-
if err != nil || !info.Mode().IsRegular()
|
|
107
|
+
if err != nil || !info.Mode().IsRegular() {
|
|
107
108
|
continue
|
|
108
109
|
}
|
|
109
|
-
// #nosec G304 -- workspace artifact;
|
|
110
|
-
if
|
|
110
|
+
f, err := os.Open(path) // #nosec G304 -- workspace artifact; read is capped below
|
|
111
|
+
if err != nil {
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
data, err := io.ReadAll(io.LimitReader(f, triggerEvidenceFileCap))
|
|
115
|
+
_ = f.Close()
|
|
116
|
+
if err == nil {
|
|
111
117
|
corpus.Write(data)
|
|
112
118
|
corpus.WriteByte('\n')
|
|
113
119
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
package lib
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"strings"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func TestGatherTriggerFactsReadsCappedPrefixOfOversizedArtifact(t *testing.T) {
|
|
11
|
+
dir := t.TempDir()
|
|
12
|
+
body := "this feature adds a frontend component\n" + strings.Repeat(" ", triggerEvidenceFileCap)
|
|
13
|
+
if err := os.WriteFile(filepath.Join(dir, "spec.md"), []byte(body), 0o600); err != nil {
|
|
14
|
+
t.Fatal(err)
|
|
15
|
+
}
|
|
16
|
+
facts := gatherTriggerFacts("", dir, "")
|
|
17
|
+
if !uiSignalRe.MatchString(facts.corpus) {
|
|
18
|
+
t.Fatalf("oversized artifact contributed no corpus (len=%d)", len(facts.corpus))
|
|
19
|
+
}
|
|
20
|
+
if len(facts.corpus) > triggerEvidenceFileCap+1 {
|
|
21
|
+
t.Fatalf("corpus exceeds cap: %d", len(facts.corpus))
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -9,6 +9,7 @@ import (
|
|
|
9
9
|
"os"
|
|
10
10
|
"os/exec"
|
|
11
11
|
"strings"
|
|
12
|
+
"sync"
|
|
12
13
|
"time"
|
|
13
14
|
|
|
14
15
|
"github.com/devrites/devrites/internal/devritespaths"
|
|
@@ -21,18 +22,27 @@ const (
|
|
|
21
22
|
)
|
|
22
23
|
|
|
23
24
|
type cappedGitOutput struct {
|
|
24
|
-
|
|
25
|
+
mu sync.Mutex
|
|
26
|
+
buffer bytes.Buffer
|
|
25
27
|
truncated bool
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
func (w *cappedGitOutput) Len() int { return w.buffer.Len() }
|
|
31
|
+
|
|
32
|
+
func (w *cappedGitOutput) Bytes() []byte { return w.buffer.Bytes() }
|
|
33
|
+
|
|
34
|
+
func (w *cappedGitOutput) String() string { return w.buffer.String() }
|
|
35
|
+
|
|
28
36
|
func (w *cappedGitOutput) Write(p []byte) (int, error) {
|
|
37
|
+
w.mu.Lock()
|
|
38
|
+
defer w.mu.Unlock()
|
|
29
39
|
remaining := gitOutputLimit - w.Len()
|
|
30
40
|
if remaining > 0 {
|
|
31
41
|
if len(p) > remaining {
|
|
32
|
-
_, _ = w.
|
|
42
|
+
_, _ = w.buffer.Write(p[:remaining])
|
|
33
43
|
w.truncated = true
|
|
34
44
|
} else {
|
|
35
|
-
_, _ = w.
|
|
45
|
+
_, _ = w.buffer.Write(p)
|
|
36
46
|
}
|
|
37
47
|
} else {
|
|
38
48
|
w.truncated = true
|
|
@@ -77,6 +87,7 @@ func runGitCommandIO(dir string, env []string, input []byte, stdout io.Writer, a
|
|
|
77
87
|
env = gitenv.Sanitize(env)
|
|
78
88
|
cmd.Env = append(
|
|
79
89
|
env,
|
|
90
|
+
"GIT_OPTIONAL_LOCKS=0",
|
|
80
91
|
"GIT_TERMINAL_PROMPT=0",
|
|
81
92
|
"GCM_INTERACTIVE=never",
|
|
82
93
|
"GIT_PAGER=cat",
|
|
@@ -92,6 +103,9 @@ func runGitCommandIO(dir string, env []string, input []byte, stdout io.Writer, a
|
|
|
92
103
|
cmd.Stderr = &output
|
|
93
104
|
err := cmd.Run()
|
|
94
105
|
if err == nil {
|
|
106
|
+
if output.truncated {
|
|
107
|
+
return nil, &gitCommandError{args: args, exitCode: 0, err: errors.New("git output exceeds limit")}
|
|
108
|
+
}
|
|
95
109
|
return output.Bytes(), nil
|
|
96
110
|
}
|
|
97
111
|
code := -1
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
package lib
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"io"
|
|
4
6
|
"os"
|
|
5
7
|
"os/exec"
|
|
6
8
|
"path/filepath"
|
|
7
9
|
"strings"
|
|
10
|
+
"sync"
|
|
8
11
|
"testing"
|
|
12
|
+
"time"
|
|
9
13
|
)
|
|
10
14
|
|
|
11
15
|
func TestRunGitCommandIgnoresInheritedRepositoryTargets(t *testing.T) {
|
|
@@ -30,6 +34,41 @@ func TestRunGitCommandIgnoresInheritedRepositoryTargets(t *testing.T) {
|
|
|
30
34
|
}
|
|
31
35
|
}
|
|
32
36
|
|
|
37
|
+
func TestGitStatusPathsLeavesStaleIndexUntouched(t *testing.T) {
|
|
38
|
+
t.Setenv("GIT_OPTIONAL_LOCKS", "")
|
|
39
|
+
if err := os.Unsetenv("GIT_OPTIONAL_LOCKS"); err != nil {
|
|
40
|
+
t.Fatal(err)
|
|
41
|
+
}
|
|
42
|
+
repo := initGitRepository(t, filepath.Join(t.TempDir(), "repo"))
|
|
43
|
+
file := filepath.Join(repo, "a.txt")
|
|
44
|
+
if err := os.WriteFile(file, []byte("one\n"), 0o644); err != nil {
|
|
45
|
+
t.Fatal(err)
|
|
46
|
+
}
|
|
47
|
+
add := exec.Command("git", "-C", repo, "add", "a.txt")
|
|
48
|
+
if out, err := add.CombinedOutput(); err != nil {
|
|
49
|
+
t.Fatalf("git add: %v\n%s", err, out)
|
|
50
|
+
}
|
|
51
|
+
stale := time.Now().Add(-time.Hour)
|
|
52
|
+
if err := os.Chtimes(file, stale, stale); err != nil {
|
|
53
|
+
t.Fatal(err)
|
|
54
|
+
}
|
|
55
|
+
indexPath := filepath.Join(repo, ".git", "index")
|
|
56
|
+
before, err := os.ReadFile(indexPath)
|
|
57
|
+
if err != nil {
|
|
58
|
+
t.Fatal(err)
|
|
59
|
+
}
|
|
60
|
+
if _, err := gitStatusPaths(repo); err != nil {
|
|
61
|
+
t.Fatal(err)
|
|
62
|
+
}
|
|
63
|
+
after, err := os.ReadFile(indexPath)
|
|
64
|
+
if err != nil {
|
|
65
|
+
t.Fatal(err)
|
|
66
|
+
}
|
|
67
|
+
if !bytes.Equal(before, after) {
|
|
68
|
+
t.Fatal("git status rewrote .git/index")
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
33
72
|
func initGitRepository(t *testing.T, path string) string {
|
|
34
73
|
t.Helper()
|
|
35
74
|
if err := os.MkdirAll(path, 0o755); err != nil {
|
|
@@ -42,3 +81,68 @@ func initGitRepository(t *testing.T, path string) string {
|
|
|
42
81
|
}
|
|
43
82
|
return path
|
|
44
83
|
}
|
|
84
|
+
|
|
85
|
+
// cappedGitOutput is installed as both cmd.Stdout and cmd.Stderr; this drives
|
|
86
|
+
// two concurrent writers at it so -race flags any unsynchronized access.
|
|
87
|
+
func TestCappedGitOutputConcurrentWriters(t *testing.T) {
|
|
88
|
+
const writes, size = 2000, 64
|
|
89
|
+
chunk := []byte(strings.Repeat("x", size))
|
|
90
|
+
|
|
91
|
+
var seq cappedGitOutput
|
|
92
|
+
for i := 0; i < 2*writes; i++ {
|
|
93
|
+
_, _ = seq.Write(chunk)
|
|
94
|
+
}
|
|
95
|
+
if seq.Len() != 2*writes*size || seq.truncated {
|
|
96
|
+
t.Fatalf("sequential: got %d bytes truncated=%v, want %d", seq.Len(), seq.truncated, 2*writes*size)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
var out cappedGitOutput
|
|
100
|
+
var wg sync.WaitGroup
|
|
101
|
+
for w := 0; w < 2; w++ {
|
|
102
|
+
wg.Add(1)
|
|
103
|
+
go func() {
|
|
104
|
+
defer wg.Done()
|
|
105
|
+
for i := 0; i < writes; i++ {
|
|
106
|
+
_, _ = out.Write(chunk)
|
|
107
|
+
}
|
|
108
|
+
}()
|
|
109
|
+
}
|
|
110
|
+
wg.Wait()
|
|
111
|
+
t.Logf("concurrent bytes %d of %d", out.Len(), 2*writes*size)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
func TestCappedGitOutputBoundsIOCopy(t *testing.T) {
|
|
115
|
+
src := func() io.Reader { return io.LimitReader(zeroReader{}, 25<<20) }
|
|
116
|
+
|
|
117
|
+
var control boundedSecretScanBuffer
|
|
118
|
+
control.limit = gitOutputLimit
|
|
119
|
+
_, _ = io.Copy(&control, src())
|
|
120
|
+
if control.Len() != gitOutputLimit || !control.overflow {
|
|
121
|
+
t.Fatalf("control: got %d bytes overflow=%v, want %d and overflow", control.Len(), control.overflow, gitOutputLimit)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
var out cappedGitOutput
|
|
125
|
+
_, _ = io.Copy(&out, src())
|
|
126
|
+
if out.Len() > gitOutputLimit || !out.truncated {
|
|
127
|
+
t.Fatalf("got %d bytes truncated=%v, want at most %d and truncated", out.Len(), out.truncated, gitOutputLimit)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
func TestRunGitCommandRejectsTruncatedOutput(t *testing.T) {
|
|
132
|
+
repo := initGitRepository(t, t.TempDir())
|
|
133
|
+
blob := filepath.Join(t.TempDir(), "big")
|
|
134
|
+
if err := os.WriteFile(blob, bytes.Repeat([]byte("x"), gitOutputLimit+1), 0o600); err != nil {
|
|
135
|
+
t.Fatal(err)
|
|
136
|
+
}
|
|
137
|
+
oid, err := runGitCommand(repo, nil, "hash-object", "-w", blob)
|
|
138
|
+
if err != nil {
|
|
139
|
+
t.Fatal(err)
|
|
140
|
+
}
|
|
141
|
+
if _, err := runGitCommand(repo, nil, "cat-file", "blob", strings.TrimSpace(string(oid))); err == nil {
|
|
142
|
+
t.Fatal("truncated git output returned without error")
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
type zeroReader struct{}
|
|
147
|
+
|
|
148
|
+
func (zeroReader) Read(p []byte) (int, error) { return len(p), nil }
|
|
@@ -5,8 +5,9 @@ import (
|
|
|
5
5
|
"strings"
|
|
6
6
|
)
|
|
7
7
|
|
|
8
|
-
// htmlIDAttrRE matches
|
|
9
|
-
|
|
8
|
+
// htmlIDAttrRE matches quoted and unquoted id attributes without a full HTML
|
|
9
|
+
// parser. The attribute name is anchored so data-id and similar do not match.
|
|
10
|
+
var htmlIDAttrRE = regexp.MustCompile(`(?i)(?:^|[\s"'/])id\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>` + "`" + `]+))`)
|
|
10
11
|
|
|
11
12
|
// VisualIDConsistency summarizes outline ## ID inventory vs HTML id attributes.
|
|
12
13
|
//
|
|
@@ -29,7 +30,7 @@ func ParseOutlineInventoryIDs(outline string) []string {
|
|
|
29
30
|
return parseMarkdownFirstColumnIDs(section)
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
// ScanHTMLIDs returns unique id="..." / id='...' attribute values in document order.
|
|
33
|
+
// ScanHTMLIDs returns unique id="..." / id='...' / id=value attribute values in document order.
|
|
33
34
|
func ScanHTMLIDs(html string) []string {
|
|
34
35
|
matches := htmlIDAttrRE.FindAllStringSubmatch(html, -1)
|
|
35
36
|
if len(matches) == 0 {
|
|
@@ -42,6 +43,9 @@ func ScanHTMLIDs(html string) []string {
|
|
|
42
43
|
if id == "" {
|
|
43
44
|
id = m[2]
|
|
44
45
|
}
|
|
46
|
+
if id == "" {
|
|
47
|
+
id = m[3]
|
|
48
|
+
}
|
|
45
49
|
id = strings.TrimSpace(id)
|
|
46
50
|
if id == "" {
|
|
47
51
|
continue
|
|
@@ -159,3 +159,31 @@ func TestOpenVisualIDsOkTip(t *testing.T) {
|
|
|
159
159
|
t.Fatalf("stdout = %q, want ids=ok tip", stdout.String())
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
+
|
|
163
|
+
func TestCheckVisualIDConsistencyAttributeForms(t *testing.T) {
|
|
164
|
+
outline := `## ID inventory
|
|
165
|
+
| HTML id | Meaning |
|
|
166
|
+
| --- | --- |
|
|
167
|
+
| viz-title | Header |
|
|
168
|
+
`
|
|
169
|
+
cases := []struct {
|
|
170
|
+
name string
|
|
171
|
+
html string
|
|
172
|
+
wantMissing []string
|
|
173
|
+
}{
|
|
174
|
+
{"unquoted", `<section id=viz-title></section>`, nil},
|
|
175
|
+
{"unquoted before close", `<section id=viz-title>x</section>`, nil},
|
|
176
|
+
{"single quoted", `<section id='viz-title'></section>`, nil},
|
|
177
|
+
{"data-id is not id", `<section data-id="viz-title"></section>`, []string{"viz-title"}},
|
|
178
|
+
{"hyphenated name ending in id", `<section grid-id=viz-title></section>`, []string{"viz-title"}},
|
|
179
|
+
{"newline before attribute", "<section\nid=viz-title></section>", nil},
|
|
180
|
+
}
|
|
181
|
+
for _, tc := range cases {
|
|
182
|
+
t.Run(tc.name, func(t *testing.T) {
|
|
183
|
+
got := CheckVisualIDConsistency(tc.html, outline).MissingInHTML
|
|
184
|
+
if len(got) != len(tc.wantMissing) || (len(got) == 1 && got[0] != tc.wantMissing[0]) {
|
|
185
|
+
t.Fatalf("MissingInHTML = %#v, want %#v", got, tc.wantMissing)
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
}
|