claude-dev-env 1.93.1 → 1.95.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/_shared/advisor/CLAUDE.md +2 -2
- package/_shared/advisor/advisor-protocol.md +35 -27
- package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +3 -2
- package/_shared/advisor/scripts/model_tier_run_validator.py +23 -15
- package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +81 -17
- package/_shared/pr-loop/CLAUDE.md +1 -0
- package/_shared/pr-loop/audit-contract.md +1 -1
- package/_shared/pr-loop/gh-payloads.md +3 -3
- package/_shared/pr-loop/post-audit-thread-contract.md +51 -0
- package/_shared/pr-loop/scripts/README.md +2 -2
- package/_shared/pr-loop/scripts/fix_hookspath.py +47 -12
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +0 -69
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -374
- package/_shared/pr-loop/state-schema.md +3 -22
- package/bin/CLAUDE.md +11 -2
- package/bin/ever-shipped-skills.mjs +70 -0
- package/bin/install.mjs +138 -13
- package/bin/install.prune.test.mjs +457 -0
- package/bin/install.test.mjs +10 -4
- package/docs/CODE_RULES.md +1 -1
- package/hooks/blocking/CLAUDE.md +2 -0
- package/hooks/blocking/code_rules_enforcer.py +4 -0
- package/hooks/blocking/code_rules_shared.py +82 -0
- package/hooks/blocking/code_rules_test_layout.py +9 -3
- package/hooks/blocking/pii_commit_command.py +398 -0
- package/hooks/blocking/pii_payload_scan.py +133 -0
- package/hooks/blocking/pii_prevention_blocker.py +151 -449
- package/hooks/blocking/plain_language_blocker.py +138 -4
- package/hooks/blocking/sensitive_file_protector.py +114 -48
- package/hooks/blocking/tdd_enforcer.py +9 -2
- package/hooks/blocking/test_code_rules_enforcer_scratchpad.py +105 -0
- package/hooks/blocking/test_code_rules_shared.py +181 -0
- package/hooks/blocking/test_pii_prevention_blocker.py +299 -0
- package/hooks/blocking/test_plain_language_blocker_allowlist.py +184 -0
- package/hooks/blocking/test_sensitive_file_protector.py +185 -0
- package/hooks/blocking/test_tdd_enforcer_scratchpad.py +105 -0
- package/hooks/blocking/test_verdict_directory_write_blocker.py +42 -7
- package/hooks/hooks_constants/CLAUDE.md +4 -2
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +0 -2
- package/hooks/hooks_constants/harness_scratchpad_constants.py +17 -0
- package/hooks/hooks_constants/local_identity.py +65 -15
- package/hooks/hooks_constants/pii_prevention_constants.py +16 -0
- package/hooks/hooks_constants/plain_language_blocker_constants.py +5 -0
- package/hooks/hooks_constants/pr_description_enforcer_constants.py +1 -1
- package/hooks/hooks_constants/sensitive_file_protector_constants.py +42 -0
- package/hooks/hooks_constants/test_local_identity.py +68 -0
- package/hooks/pyproject.toml +75 -4
- package/hooks/validators/CLAUDE.md +1 -1
- package/hooks/validators/README.md +2 -0
- package/hooks/validators/python_style_checks.py +114 -136
- package/hooks/validators/python_style_helpers.py +95 -0
- package/hooks/validators/test_python_style_checks.py +0 -164
- package/hooks/validators/test_python_style_checks_decorator_gap.py +119 -0
- package/hooks/validators/test_python_style_fixes.py +251 -0
- package/hooks/validators/test_python_style_helpers.py +125 -0
- package/package.json +1 -1
- package/rules/CLAUDE.md +1 -0
- package/rules/anti-corollary-tests.md +69 -0
- package/rules/bdd.md +1 -3
- package/rules/code-reviews.md +1 -1
- package/rules/gh-paginate.md +1 -1
- package/rules/plain-language.md +2 -0
- package/scripts/CLAUDE.md +10 -1
- package/scripts/Get-SessionAccount.ps1 +210 -0
- package/scripts/tests/CLAUDE.md +15 -1
- package/scripts/tests/Get-SessionAccount.Tests.ps1 +350 -0
- package/skills/CLAUDE.md +6 -27
- package/skills/anthropic-plan/SKILL.md +1 -13
- package/skills/autoconverge/CLAUDE.md +5 -2
- package/skills/autoconverge/SKILL.md +112 -387
- package/skills/autoconverge/reference/CLAUDE.md +4 -1
- package/skills/autoconverge/reference/closing-report.md +9 -2
- package/skills/autoconverge/reference/convergence.md +26 -22
- package/skills/autoconverge/reference/headless-safety.md +44 -0
- package/skills/autoconverge/reference/multi-pr.md +88 -0
- package/skills/autoconverge/reference/self-closing-loop.md +84 -0
- package/skills/autoconverge/reference/stop-conditions.md +21 -13
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +87 -27
- package/skills/autoconverge/workflow/converge.contract.test.mjs +40 -10
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +179 -47
- package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
- package/skills/autoconverge/workflow/converge.mjs +286 -96
- package/skills/bugteam/CLAUDE.md +1 -1
- package/skills/bugteam/CONSTRAINTS.md +3 -3
- package/skills/bugteam/PROMPTS.md +8 -19
- package/skills/bugteam/SKILL.md +13 -14
- package/skills/bugteam/reference/CLAUDE.md +1 -1
- package/skills/bugteam/reference/README.md +2 -3
- package/skills/bugteam/reference/audit-and-teammates.md +2 -2
- package/skills/bugteam/reference/copilot-gap-analysis.md +2 -0
- package/skills/bugteam/reference/github-pr-reviews.md +56 -38
- package/skills/bugteam/reference/team-setup.md +11 -11
- package/skills/bugteam/scripts/CLAUDE.md +6 -6
- package/skills/bugteam/scripts/README.md +20 -8
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +13 -1463
- package/skills/bugteam/scripts/bugteam_fix_hookspath.py +23 -358
- package/skills/bugteam/scripts/bugteam_preflight.py +13 -315
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +2 -3
- package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +34 -1053
- package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +30 -347
- package/skills/bugteam/scripts/test_bugteam_preflight.py +30 -305
- package/skills/closeout/SKILL.md +153 -0
- package/skills/closeout/reference/handoff-prompt-template.md +72 -0
- package/skills/closeout/reference/issue-body-templates.md +108 -0
- package/skills/closeout/reference/pii-redaction-checklist.md +36 -0
- package/skills/copilot-finding-triage/SKILL.md +80 -28
- package/skills/copilot-finding-triage/reference/tier-rubric.md +70 -11
- package/skills/copilot-finding-triage/templates/notification.md +8 -3
- package/skills/everything-search/SKILL.md +1 -2
- package/skills/grokify/SKILL.md +58 -0
- package/skills/grokify/templates/handoff-template.md +92 -0
- package/skills/orchestrator/SKILL.md +35 -25
- package/skills/orchestrator-refresh/SKILL.md +15 -11
- package/skills/pr-converge/CLAUDE.md +1 -1
- package/skills/pr-converge/SKILL.md +132 -233
- package/skills/pr-converge/reference/convergence-gates.md +102 -66
- package/skills/pr-converge/reference/examples.md +37 -25
- package/skills/pr-converge/reference/fix-protocol.md +7 -7
- package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -4
- package/skills/pr-converge/reference/per-tick.md +64 -41
- package/skills/pr-converge/reference/state-schema.md +27 -2
- package/skills/pr-converge/scripts/CLAUDE.md +8 -0
- package/skills/pr-converge/scripts/README.md +4 -3
- package/skills/pr-converge/scripts/_pr_converge_path_setup.py +23 -0
- package/skills/pr-converge/scripts/check_convergence.py +189 -645
- package/skills/pr-converge/scripts/check_convergence_gates.py +235 -0
- package/skills/pr-converge/scripts/check_convergence_thread_gates.py +219 -0
- package/skills/pr-converge/scripts/conftest.py +8 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -0
- package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +26 -0
- package/skills/pr-converge/scripts/test_check_convergence.py +73 -228
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +321 -0
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +68 -0
- package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +75 -0
- package/skills/pr-fix-protocol/SKILL.md +20 -20
- package/skills/privacy-hygiene/SKILL.md +4 -3
- package/skills/reviewer-gates/SKILL.md +26 -8
- package/skills/session-log/SKILL.md +11 -12
- package/skills/session-tidy/SKILL.md +40 -30
- package/skills/skill-builder/CLAUDE.md +13 -10
- package/skills/skill-builder/SKILL.md +31 -31
- package/skills/skill-builder/references/CLAUDE.md +10 -6
- package/skills/skill-builder/references/delegation-map.md +13 -4
- package/skills/skill-builder/references/description-field.md +113 -0
- package/skills/skill-builder/references/self-audit-checklist.md +21 -4
- package/skills/skill-builder/references/skill-modularity.md +113 -0
- package/skills/skill-builder/references/skill-types.md +4 -0
- package/skills/skill-builder/templates/CLAUDE.md +4 -4
- package/skills/skill-builder/templates/gap-analysis.md +25 -1
- package/skills/skill-builder/workflows/CLAUDE.md +6 -4
- package/skills/skill-builder/workflows/improve-skill.md +17 -16
- package/skills/skill-builder/workflows/new-skill.md +34 -10
- package/skills/skill-builder/workflows/polish-skill.md +59 -43
- package/skills/team-advisor/SKILL.md +15 -11
- package/skills/usage-pause/SKILL.md +10 -14
- package/system-prompts/software-engineer.xml +7 -6
- package/hooks/validators/test_verify_paths.py +0 -32
- package/hooks/validators/verify_paths.py +0 -57
- package/skills/bdd-protocol/CLAUDE.md +0 -26
- package/skills/bdd-protocol/SKILL.md +0 -30
- package/skills/bdd-protocol/references/CLAUDE.md +0 -10
- package/skills/bdd-protocol/references/anti-patterns.md +0 -26
- package/skills/bdd-protocol/references/example-mapping.md +0 -23
- package/skills/bg-agent/CLAUDE.md +0 -17
- package/skills/bg-agent/SKILL.md +0 -69
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_code_rules_gate_constants.py +0 -55
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_fix_hookspath_constants.py +0 -26
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_preflight_constants.py +0 -35
- package/skills/caveman/CLAUDE.md +0 -15
- package/skills/caveman/SKILL.md +0 -38
- package/skills/code/CLAUDE.md +0 -17
- package/skills/code/SKILL.md +0 -178
- package/skills/deep-research/CLAUDE.md +0 -17
- package/skills/deep-research/SKILL.md +0 -80
- package/skills/findbugs/CLAUDE.md +0 -20
- package/skills/findbugs/SKILL.md +0 -241
- package/skills/fixbugs/CLAUDE.md +0 -19
- package/skills/fixbugs/SKILL.md +0 -142
- package/skills/gh-paginate/CLAUDE.md +0 -18
- package/skills/gh-paginate/SKILL.md +0 -84
- package/skills/gotcha/CLAUDE.md +0 -33
- package/skills/gotcha/SKILL.md +0 -73
- package/skills/implement/CLAUDE.md +0 -27
- package/skills/implement/SKILL.md +0 -66
- package/skills/implement/scripts/CLAUDE.md +0 -22
- package/skills/implement/scripts/append_note.py +0 -133
- package/skills/implement/scripts/implement_scripts_constants/CLAUDE.md +0 -22
- package/skills/implement/scripts/implement_scripts_constants/__init__.py +0 -0
- package/skills/implement/scripts/implement_scripts_constants/notes_constants.py +0 -12
- package/skills/implement/scripts/test_append_note.py +0 -191
- package/skills/log-audit/CLAUDE.md +0 -20
- package/skills/log-audit/SKILL.md +0 -66
- package/skills/log-audit/reference/CLAUDE.md +0 -9
- package/skills/log-audit/reference/charter.md +0 -52
- package/skills/log-audit/scripts/CLAUDE.md +0 -27
- package/skills/log-audit/scripts/cluster_recurrences.py +0 -261
- package/skills/log-audit/scripts/collect_log_window.py +0 -199
- package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +0 -12
- package/skills/log-audit/scripts/log_audit_constants/__init__.py +0 -0
- package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +0 -23
- package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +0 -24
- package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +0 -49
- package/skills/log-audit/scripts/mine_copilot_findings.py +0 -302
- package/skills/log-audit/scripts/test_cluster_recurrences.py +0 -160
- package/skills/log-audit/scripts/test_collect_log_window.py +0 -111
- package/skills/log-audit/scripts/test_mine_copilot_findings.py +0 -126
- package/skills/logifix/CLAUDE.md +0 -36
- package/skills/logifix/SKILL.md +0 -69
- package/skills/logifix/scripts/CLAUDE.md +0 -16
- package/skills/logifix/scripts/logifix.ps1 +0 -205
- package/skills/monitor-open-prs/CLAUDE.md +0 -34
- package/skills/monitor-open-prs/SKILL.md +0 -88
- package/skills/monitor-open-prs/scripts/CLAUDE.md +0 -17
- package/skills/monitor-open-prs/scripts/discover_open_prs.py +0 -69
- package/skills/monitor-open-prs/scripts/test_discover_open_prs.py +0 -149
- package/skills/monitor-open-prs/test_skill_contract.py +0 -27
- package/skills/post-audit-findings/SKILL.md +0 -80
- package/skills/pr-consistency-audit/CLAUDE.md +0 -34
- package/skills/pr-consistency-audit/SKILL.md +0 -116
- package/skills/pr-consistency-audit/reference/CLAUDE.md +0 -16
- package/skills/pr-consistency-audit/reference/detection-rules.md +0 -96
- package/skills/pr-consistency-audit/reference/illustrations.md +0 -78
- package/skills/pr-review-responder/CLAUDE.md +0 -35
- package/skills/pr-review-responder/EXAMPLES.md +0 -590
- package/skills/pr-review-responder/PRINCIPLES.md +0 -533
- package/skills/pr-review-responder/README.md +0 -168
- package/skills/pr-review-responder/SKILL.md +0 -203
- package/skills/pr-review-responder/TESTING.md +0 -350
- package/skills/pr-scope-resolve/SKILL.md +0 -45
- package/skills/pre-compact/CLAUDE.md +0 -24
- package/skills/pre-compact/SKILL.md +0 -134
- package/skills/qbug/CLAUDE.md +0 -40
- package/skills/qbug/SKILL.md +0 -387
- package/skills/qbug/test_qbug_skill_audit_schema.py +0 -152
- package/skills/qbug/test_qbug_skill_post_fix_audit.py +0 -103
- package/skills/refine/CLAUDE.md +0 -44
- package/skills/refine/SKILL.md +0 -262
- package/skills/refine/templates/CLAUDE.md +0 -17
- package/skills/refine/templates/implementation-notes-template.html +0 -56
- package/skills/refine/templates/plan-template.md +0 -60
- package/skills/research-mode/CLAUDE.md +0 -35
- package/skills/research-mode/SKILL.md +0 -53
- package/skills/structure-prompt/CLAUDE.md +0 -42
- package/skills/structure-prompt/SKILL.md +0 -44
- package/skills/structure-prompt/reference/CLAUDE.md +0 -28
- package/skills/structure-prompt/reference/adversarial-tuning.md +0 -62
- package/skills/structure-prompt/reference/block-classification.md +0 -27
- package/skills/structure-prompt/reference/canonical-case.md +0 -48
- package/skills/structure-prompt/reference/citation-depth.md +0 -70
- package/skills/structure-prompt/reference/cleanup.md +0 -33
- package/skills/structure-prompt/reference/constraints.md +0 -33
- package/skills/structure-prompt/reference/directives.md +0 -37
- package/skills/structure-prompt/reference/examples.md +0 -72
- package/skills/structure-prompt/reference/instantiation.md +0 -51
- package/skills/structure-prompt/reference/output-contract.md +0 -72
- package/skills/structure-prompt/reference/per-category.md +0 -23
- package/skills/structure-prompt/reference/persona.md +0 -38
- package/skills/structure-prompt/reference/research.md +0 -33
- package/skills/structure-prompt/reference/structure.md +0 -28
- package/skills/verified-build/CLAUDE.md +0 -33
- package/skills/verified-build/SKILL.md +0 -33
package/rules/CLAUDE.md
CHANGED
|
@@ -12,6 +12,7 @@ Rule files installed into `~/.claude/rules/` by `bin/install.mjs`. Claude Code l
|
|
|
12
12
|
| File | Rule |
|
|
13
13
|
|---|---|
|
|
14
14
|
| `agent-spawn-protocol.md` | Protocol for spawning subagents: context sufficiency check, prompt generation via `/prompt-generator`, then spawn |
|
|
15
|
+
| `anti-corollary-tests.md` | Tests must carry information: no corollary matrices over canonical reductions, no suite that only matches a dead-implementation default, stated mutation in the audit lane |
|
|
15
16
|
| `ask-user-question-required.md` | Every user-directed question goes through the `AskUserQuestion` tool — no plain-text questions |
|
|
16
17
|
| `bdd.md` | BDD discovery-driven development workflow and Example Mapping reference |
|
|
17
18
|
| `claude-md-orphan-file.md` | Every backticked bare filename in a per-directory `CLAUDE.md` table's first column names a file in that directory's subtree |
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/test_*.py"
|
|
4
|
+
- "**/*_test.py"
|
|
5
|
+
- "**/*.test.*"
|
|
6
|
+
- "**/*.spec.*"
|
|
7
|
+
- "**/conftest.py"
|
|
8
|
+
- "**/tests/**"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Anti-Corollary Tests
|
|
12
|
+
|
|
13
|
+
**When this applies:** Any Write or Edit that adds or changes tests.
|
|
14
|
+
|
|
15
|
+
## Rule
|
|
16
|
+
|
|
17
|
+
A large green suite can prove almost nothing. Before you keep a case, answer three questions. If any answer fails, cut the case or replace it with one that carries information.
|
|
18
|
+
|
|
19
|
+
## The three questions
|
|
20
|
+
|
|
21
|
+
### 1. Is this a corollary?
|
|
22
|
+
|
|
23
|
+
When the code reduces each input to a canonical form and then compares the forms, every pairwise combination of input spellings follows once the reduction is proven canonical. Walking the full N×N matrix restates that fact. It adds cases and runtime, and it buries the few cases that carry information.
|
|
24
|
+
|
|
25
|
+
**Do this:** test the reduction once. Test the comparison with a few discriminating cases. Do not walk the cross product of spellings.
|
|
26
|
+
|
|
27
|
+
### 2. Could this test pass if the mechanism were dead?
|
|
28
|
+
|
|
29
|
+
Name the degenerate value a dead implementation would return — empty string, `None`, `False`, a blanket refusal, an empty collection. When the test's expected value equals that default, the test passes whether the mechanism works or not. On its own it proves nothing.
|
|
30
|
+
|
|
31
|
+
**Do this:** keep at least one case that expects the **non-default** answer, and drive the real code path — not a mock that only records that a call happened.
|
|
32
|
+
|
|
33
|
+
### 3. What single change to the code would make this test fail?
|
|
34
|
+
|
|
35
|
+
When the honest answer is "none," or "only a change that also breaks everything else," the test is decoration. Drop it or rewrite it so one named mutation kills it.
|
|
36
|
+
|
|
37
|
+
## What a mechanism with a degenerate failure mode needs
|
|
38
|
+
|
|
39
|
+
1. **At least one non-default case** that exercises the live path and expects the non-default answer.
|
|
40
|
+
2. **A stated mutation (audit lane):** name one specific change to the code and record how many tests it kills. A mutation that kills zero tests means the suite proves nothing. A reviewer or an audit skill checks this; a hook does not compute it.
|
|
41
|
+
3. **A few discriminating cases** in place of a large matrix.
|
|
42
|
+
|
|
43
|
+
## Worked shape (sanitized)
|
|
44
|
+
|
|
45
|
+
A write guard decides whether a write is about to hit a production database. It reduces each database URL to a canonical endpoint identity, then compares identities.
|
|
46
|
+
|
|
47
|
+
Two independent mutations show the two halves of a useful suite:
|
|
48
|
+
|
|
49
|
+
- Gut the reduction so it always returns the empty string: the guard fails **closed** and refuses everything. Only the *allow*-expecting cases die.
|
|
50
|
+
- Abandon the reduction and compare raw hostnames: the guard fails **open** and allows a production write. Only the *refuse*-expecting cases die.
|
|
51
|
+
|
|
52
|
+
Opposite breaks kill opposite halves. A suite with only one half cannot see one of those breaks. Build both halves; skip the spelling matrix once the reduction is covered.
|
|
53
|
+
|
|
54
|
+
## What this is not
|
|
55
|
+
|
|
56
|
+
A structural hook is the wrong tool here. "Is this a corollary?" and "would this pass against a dead implementation?" need the intent of the code under test. A hook that pattern-matches `parametrize` breadth or counts assertions fires on correct suites and trains people to ignore it. A false-positive gate on a judgment call is worse than no gate. This rule stays judgment-only, with the stated-mutation check in the audit lane — the same pattern as other judgment rules in this package that have no Write/Edit blocker.
|
|
57
|
+
|
|
58
|
+
## Sibling rules
|
|
59
|
+
|
|
60
|
+
| Rule | Role |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `tdd.md` | Write a failing test before production code |
|
|
63
|
+
| `testing.md` | Mocks and test infrastructure standards |
|
|
64
|
+
| `paired-test-coverage.md` | Every public function in an established suite gets a behavioral test |
|
|
65
|
+
| `anti-corollary-tests.md` | Each test carries information; no corollary matrices; no suite that only matches the dead default |
|
|
66
|
+
|
|
67
|
+
## Enforcement
|
|
68
|
+
|
|
69
|
+
The AI review lane and audit skills carry this rule: an agent applies it to the test lines a PR changes. No blocking hook backs it, because corollary and dead-default judgments need meaning a regex cannot read.
|
package/rules/bdd.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
**Canonical detail:** `~/.claude/system-prompts/software-engineer.xml` → `<behavior_protocol>`.
|
|
4
4
|
|
|
5
|
-
**On-demand depth:** `@~/.claude/skills/bdd-protocol/SKILL.md` (Example Mapping §6.4, §7.6 catalog, solo patterns). Tracking design: [jl-cmd/claude-dev-env#82](https://github.com/jl-cmd/claude-dev-env/issues/82).
|
|
6
|
-
|
|
7
5
|
**Optional long-form references (load when needed):**
|
|
8
6
|
|
|
9
7
|
- `@~/.claude/docs/BDD_SCENARIO_QUALITY.md` — seven scenario quality patterns (§7.6-style)
|
|
@@ -21,7 +19,7 @@ Conversation is the essential practice: if discovery is skipped, structured form
|
|
|
21
19
|
|
|
22
20
|
## Solo developer
|
|
23
21
|
|
|
24
|
-
You are often the stakeholder. Use **Example Mapping** in chat ("the one where …", probes, parking lot).
|
|
22
|
+
You are often the stakeholder. Use **Example Mapping** in chat ("the one where …", probes, parking lot). See the optional long-form references above for the full algorithm and anti-pattern list.
|
|
25
23
|
|
|
26
24
|
## Naming
|
|
27
25
|
|
package/rules/code-reviews.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**When this applies:** GitHub PR review feedback on a branch you are fixing.
|
|
4
4
|
|
|
5
|
-
**MANDATORY PROTOCOL
|
|
5
|
+
**MANDATORY PROTOCOL:**
|
|
6
6
|
|
|
7
7
|
1. Fetch ALL reviewer comments BEFORE any fixes
|
|
8
8
|
2. Create TodoWrite checklist - One item per comment
|
package/rules/gh-paginate.md
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# gh API Pagination
|
|
2
2
|
|
|
3
|
-
Every `gh api` read of a paginated GitHub list endpoint (PR `reviews`/`comments`/`files`, issue `comments`, `pulls`, `issues`) uses `--paginate --slurp` piped to **external** `jq` — `gh`'s built-in `--jq` runs per page, so cross-page operations like `sort_by | last` give wrong-but-confident results. Single-object endpoints (`pulls/<n>`, `issues/<n>`) skip pagination and may use `--jq` directly.
|
|
3
|
+
Every `gh api` read of a paginated GitHub list endpoint (PR `reviews`/`comments`/`files`, issue `comments`, `pulls`, `issues`) uses `--paginate --slurp` piped to **external** `jq` — `gh`'s built-in `--jq` runs per page, so cross-page operations like `sort_by | last` give wrong-but-confident results. Single-object endpoints (`pulls/<n>`, `issues/<n>`) skip pagination and may use `--jq` directly. For a newest-first walk, sort the slurped array and take the last element; for single-page bounds, cap with a `per_page` query parameter.
|
package/rules/plain-language.md
CHANGED
|
@@ -3,3 +3,5 @@
|
|
|
3
3
|
All prose a person reads (chat, `AskUserQuestion`, docs, PR/issue bodies, commits): everyday words, short active sentences, lead with the answer, define jargon on first use, and give only the detail the reader needs to act (progressive disclosure). Aim for first-pass readability by a non-specialist. Exact identifiers, file paths, and API names stay exact; code is out of scope.
|
|
4
4
|
|
|
5
5
|
The `plain_language_blocker` PreToolUse hook (AskUserQuestion + `.md` Write/Edit/MultiEdit) blocks a heavy word and names the everyday swap; code fences, inline code, blockquotes, URLs, and file paths are skipped.
|
|
6
|
+
|
|
7
|
+
A project can keep its own domain words out of the check with a `.claude/plain-language-allow.json` file: a JSON array of terms. An exact, case-insensitive, whole-word match on any term passes. The hook reads this file only from inside the project tree, up to the repository root, so each project's allowlist stays with its own code.
|
package/scripts/CLAUDE.md
CHANGED
|
@@ -21,6 +21,7 @@ Utility scripts installed into `~/.claude/scripts/` by `bin/install.mjs`. Each s
|
|
|
21
21
|
| `Install-SweepEmptyDirs.ps1` | Registers `sweep_empty_dirs.py` as a scheduled task on Windows |
|
|
22
22
|
| `check.ps1` | Runs the full code-quality check suite |
|
|
23
23
|
| `Show-Asset.ps1` | Opens files on screen, sizing each image window to the image's pixel dimensions (scaled to fit the screen); non-image files open in their default application |
|
|
24
|
+
| `Get-SessionAccount.ps1` | Reports which Claude account the current session is actually logged into by comparing `~/.claude.json`'s CLI login against a `CLAUDE_USER_DATA_DIR` desktop profile's `lastKnownAccountUuid`, recovering the desktop account's email from profile storage when the two accounts differ |
|
|
24
25
|
|
|
25
26
|
## Subdirectories
|
|
26
27
|
|
|
@@ -28,10 +29,18 @@ Utility scripts installed into `~/.claude/scripts/` by `bin/install.mjs`. Each s
|
|
|
28
29
|
|---|---|
|
|
29
30
|
| `dev_env_scripts_constants/` | Named constants (`timing.py`) for scripts in this directory |
|
|
30
31
|
| `sync_to_cursor/` | Package that builds Cursor `.mdc` files from Claude rules and docs |
|
|
31
|
-
| `tests/` | pytest suite for the Python scripts in this directory |
|
|
32
|
+
| `tests/` | pytest suite for the Python scripts and Pester (`*.Tests.ps1`) suite for the PowerShell scripts in this directory |
|
|
32
33
|
|
|
33
34
|
## Running tests
|
|
34
35
|
|
|
36
|
+
Python scripts (pytest):
|
|
37
|
+
|
|
35
38
|
```bash
|
|
36
39
|
python -m pytest packages/claude-dev-env/scripts/tests/
|
|
37
40
|
```
|
|
41
|
+
|
|
42
|
+
PowerShell scripts (Pester 5+, `*.Tests.ps1`):
|
|
43
|
+
|
|
44
|
+
```powershell
|
|
45
|
+
Invoke-Pester -Path packages/claude-dev-env/scripts/tests/
|
|
46
|
+
```
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env pwsh
|
|
2
|
+
[CmdletBinding()]
|
|
3
|
+
param(
|
|
4
|
+
[switch]$AsJson
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
$noiseEmailPatterns = @(
|
|
8
|
+
'@example\.(com|org|net)$',
|
|
9
|
+
'(@|\.)sentry\.io$',
|
|
10
|
+
'@anthropic\.',
|
|
11
|
+
'^Claude@\d'
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
$isoLatin1CodePage = 28591
|
|
15
|
+
|
|
16
|
+
$profileStorageDirectoryNames = @('sentry', 'IndexedDB', 'Session Storage', 'WebStorage')
|
|
17
|
+
|
|
18
|
+
$emailAddressPattern = '(?<![a-zA-Z0-9._%+-])[a-zA-Z0-9][a-zA-Z0-9._%+-]*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+(?![a-zA-Z0-9-])'
|
|
19
|
+
|
|
20
|
+
$maximumStorageFileBytes = 50MB
|
|
21
|
+
|
|
22
|
+
function Test-NoiseEmail {
|
|
23
|
+
param([string]$Email)
|
|
24
|
+
foreach ($pattern in $noiseEmailPatterns) {
|
|
25
|
+
if ($Email -imatch $pattern) { return $true }
|
|
26
|
+
}
|
|
27
|
+
return $false
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function Get-EncodingAgnosticTextView {
|
|
31
|
+
param([string]$FilePath)
|
|
32
|
+
try {
|
|
33
|
+
$fileBytes = [System.IO.File]::ReadAllBytes($FilePath)
|
|
34
|
+
if ($fileBytes.Length -eq 0) { return @() }
|
|
35
|
+
$isoLatin1Encoding = [System.Text.Encoding]::GetEncoding($isoLatin1CodePage)
|
|
36
|
+
return @(
|
|
37
|
+
$isoLatin1Encoding.GetString($fileBytes),
|
|
38
|
+
[System.Text.Encoding]::Unicode.GetString($fileBytes)
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return @()
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function Get-EmailCandidatesFromProfile {
|
|
47
|
+
param(
|
|
48
|
+
[string]$ProfileDirectory,
|
|
49
|
+
[string]$ExcludeEmail
|
|
50
|
+
)
|
|
51
|
+
$scanDirectories = $profileStorageDirectoryNames |
|
|
52
|
+
ForEach-Object { Join-Path $ProfileDirectory $_ } |
|
|
53
|
+
Where-Object { Test-Path -LiteralPath $_ }
|
|
54
|
+
$foundEmails = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
|
|
55
|
+
|
|
56
|
+
foreach ($scanDirectory in $scanDirectories) {
|
|
57
|
+
$candidateFiles = Get-ChildItem -LiteralPath $scanDirectory -Recurse -File -ErrorAction SilentlyContinue |
|
|
58
|
+
Where-Object { $_.Length -lt $maximumStorageFileBytes }
|
|
59
|
+
foreach ($candidateFile in $candidateFiles) {
|
|
60
|
+
$decodedTextViews = Get-EncodingAgnosticTextView -FilePath $candidateFile.FullName
|
|
61
|
+
foreach ($decodedText in $decodedTextViews) {
|
|
62
|
+
foreach ($match in [regex]::Matches($decodedText, $emailAddressPattern)) {
|
|
63
|
+
$candidateEmail = $match.Value
|
|
64
|
+
$isKnownCliEmail = $ExcludeEmail -and ($candidateEmail -ieq $ExcludeEmail)
|
|
65
|
+
if (-not (Test-NoiseEmail -Email $candidateEmail) -and -not $isKnownCliEmail) {
|
|
66
|
+
[void]$foundEmails.Add($candidateEmail)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return $foundEmails
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function Write-AccountResult {
|
|
76
|
+
param(
|
|
77
|
+
[string]$Email,
|
|
78
|
+
[string]$AccountUuid,
|
|
79
|
+
[string]$Source,
|
|
80
|
+
[string]$CliEmail,
|
|
81
|
+
[string]$CliAccountUuid,
|
|
82
|
+
[switch]$AsJson
|
|
83
|
+
)
|
|
84
|
+
if ($AsJson) {
|
|
85
|
+
[pscustomobject]@{
|
|
86
|
+
account = $Email
|
|
87
|
+
accountUuid = $AccountUuid
|
|
88
|
+
source = $Source
|
|
89
|
+
cliAccount = $CliEmail
|
|
90
|
+
cliAccountUuid = $CliAccountUuid
|
|
91
|
+
} | ConvertTo-Json
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
Write-Output "Account: $Email"
|
|
95
|
+
Write-Output "AccountUuid: $AccountUuid"
|
|
96
|
+
Write-Output "Source: $Source"
|
|
97
|
+
if ($CliEmail) {
|
|
98
|
+
Write-Output "CliAccount: $CliEmail"
|
|
99
|
+
Write-Output "CliAccountUuid: $CliAccountUuid"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function Get-SessionAccountResult {
|
|
104
|
+
param(
|
|
105
|
+
[int]$ExitCode,
|
|
106
|
+
[string]$Email = $null,
|
|
107
|
+
[string]$AccountUuid = $null,
|
|
108
|
+
[string]$Source = $null,
|
|
109
|
+
[string]$CliEmail = $null,
|
|
110
|
+
[string]$CliAccountUuid = $null,
|
|
111
|
+
[string]$ErrorMessage = $null
|
|
112
|
+
)
|
|
113
|
+
[pscustomobject]@{
|
|
114
|
+
ExitCode = $ExitCode
|
|
115
|
+
Email = $Email
|
|
116
|
+
AccountUuid = $AccountUuid
|
|
117
|
+
Source = $Source
|
|
118
|
+
CliEmail = $CliEmail
|
|
119
|
+
CliAccountUuid = $CliAccountUuid
|
|
120
|
+
ErrorMessage = $ErrorMessage
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function Resolve-SessionAccount {
|
|
125
|
+
param(
|
|
126
|
+
[string]$CliConfigPath,
|
|
127
|
+
[string]$ProfileDirectory
|
|
128
|
+
)
|
|
129
|
+
if (-not (Test-Path -LiteralPath $CliConfigPath)) {
|
|
130
|
+
return Get-SessionAccountResult -ExitCode 2 -ErrorMessage "CLI config not found: $CliConfigPath"
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
$cliConfig = Get-Content -LiteralPath $CliConfigPath -Raw -ErrorAction Stop | ConvertFrom-Json -AsHashtable -ErrorAction Stop
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return Get-SessionAccountResult -ExitCode 2 -ErrorMessage "Failed to parse CLI config as JSON: $CliConfigPath"
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if ($cliConfig -isnot [System.Collections.IDictionary]) {
|
|
141
|
+
return Get-SessionAccountResult -ExitCode 2 -ErrorMessage "CLI config top level is not a JSON object: $CliConfigPath"
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
$oauthAccount = $cliConfig['oauthAccount']
|
|
145
|
+
$cliEmail = if ($oauthAccount) { $oauthAccount['emailAddress'] } else { $null }
|
|
146
|
+
$cliAccountUuid = if ($oauthAccount) { $oauthAccount['accountUuid'] } else { $null }
|
|
147
|
+
if (-not $cliEmail -or -not $cliAccountUuid) {
|
|
148
|
+
return Get-SessionAccountResult -ExitCode 2 -ErrorMessage "CLI config is missing oauthAccount.emailAddress or oauthAccount.accountUuid: $CliConfigPath"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (-not $ProfileDirectory -or -not (Test-Path -LiteralPath $ProfileDirectory)) {
|
|
152
|
+
return Get-SessionAccountResult -ExitCode 0 -Email $cliEmail -AccountUuid $cliAccountUuid -Source 'cli-config'
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
$profileConfigPath = Join-Path $ProfileDirectory 'config.json'
|
|
156
|
+
if (-not (Test-Path -LiteralPath $profileConfigPath)) {
|
|
157
|
+
return Get-SessionAccountResult -ExitCode 2 -ErrorMessage "Desktop profile config not found: $profileConfigPath"
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
$profileConfig = Get-Content -LiteralPath $profileConfigPath -Raw -ErrorAction Stop | ConvertFrom-Json -AsHashtable -ErrorAction Stop
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return Get-SessionAccountResult -ExitCode 2 -ErrorMessage "Failed to parse desktop profile config as JSON: $profileConfigPath"
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if ($profileConfig -isnot [System.Collections.IDictionary]) {
|
|
168
|
+
return Get-SessionAccountResult -ExitCode 2 -ErrorMessage "Desktop profile config top level is not a JSON object: $profileConfigPath"
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
$profileAccountUuid = $profileConfig['lastKnownAccountUuid']
|
|
172
|
+
if (-not $profileAccountUuid) {
|
|
173
|
+
return Get-SessionAccountResult -ExitCode 2 -ErrorMessage "Desktop profile config is missing lastKnownAccountUuid: $profileConfigPath"
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if ($profileAccountUuid -eq $cliAccountUuid) {
|
|
177
|
+
return Get-SessionAccountResult -ExitCode 0 -Email $cliEmail -AccountUuid $cliAccountUuid -Source 'desktop-profile (matches cli-config)'
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
$candidateEmails = @(Get-EmailCandidatesFromProfile -ProfileDirectory $ProfileDirectory -ExcludeEmail $cliEmail)
|
|
181
|
+
if ($candidateEmails.Count -eq 1) {
|
|
182
|
+
return Get-SessionAccountResult -ExitCode 0 -Email $candidateEmails[0] -AccountUuid $profileAccountUuid -Source 'desktop-profile (differs from cli-config)' -CliEmail $cliEmail -CliAccountUuid $cliAccountUuid
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if ($candidateEmails.Count -eq 0) {
|
|
186
|
+
return Get-SessionAccountResult -ExitCode 1 -ErrorMessage "Desktop profile account ($profileAccountUuid) differs from CLI config, but no candidate email was recovered from profile storage: $ProfileDirectory"
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return Get-SessionAccountResult -ExitCode 1 -ErrorMessage "Desktop profile account ($profileAccountUuid) differs from CLI config, and multiple candidate emails were found in profile storage: $($candidateEmails -join ', ')"
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function Invoke-GetSessionAccount {
|
|
193
|
+
param(
|
|
194
|
+
[switch]$AsJson
|
|
195
|
+
)
|
|
196
|
+
$cliConfigPath = Join-Path $HOME '.claude.json'
|
|
197
|
+
$sessionAccount = Resolve-SessionAccount -CliConfigPath $cliConfigPath -ProfileDirectory $env:CLAUDE_USER_DATA_DIR
|
|
198
|
+
if ($sessionAccount.ErrorMessage) {
|
|
199
|
+
Write-Error $sessionAccount.ErrorMessage -ErrorAction Continue
|
|
200
|
+
exit $sessionAccount.ExitCode
|
|
201
|
+
}
|
|
202
|
+
Write-AccountResult -Email $sessionAccount.Email -AccountUuid $sessionAccount.AccountUuid -Source $sessionAccount.Source -CliEmail $sessionAccount.CliEmail -CliAccountUuid $sessionAccount.CliAccountUuid -AsJson:$AsJson
|
|
203
|
+
exit $sessionAccount.ExitCode
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if ($MyInvocation.InvocationName -ne '.') {
|
|
207
|
+
Set-StrictMode -Version Latest
|
|
208
|
+
$ErrorActionPreference = 'Stop'
|
|
209
|
+
Invoke-GetSessionAccount -AsJson:$AsJson
|
|
210
|
+
}
|
package/scripts/tests/CLAUDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# scripts/tests
|
|
2
2
|
|
|
3
|
-
pytest suite for the Python scripts in `scripts/`.
|
|
3
|
+
pytest suite for the Python scripts and Pester suite for the PowerShell scripts in `scripts/`.
|
|
4
4
|
|
|
5
5
|
## Test files
|
|
6
6
|
|
|
@@ -11,8 +11,22 @@ pytest suite for the Python scripts in `scripts/`.
|
|
|
11
11
|
| `test_sweep_empty_dirs.py` | `sweep_empty_dirs.py` — age check, one-shot mode, and continuous-watch behavior |
|
|
12
12
|
| `test_sync_to_cursor.py` | `sync_to_cursor/` package — mapping, hashing, manifest, and path resolution |
|
|
13
13
|
|
|
14
|
+
## PowerShell test files
|
|
15
|
+
|
|
16
|
+
| File | Covers |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `Get-SessionAccount.Tests.ps1` | `Get-SessionAccount.ps1` — noise filtering, profile-storage email recovery, CLI-vs-desktop account resolution, and output formatting |
|
|
19
|
+
|
|
14
20
|
## Running
|
|
15
21
|
|
|
22
|
+
Python scripts (pytest):
|
|
23
|
+
|
|
16
24
|
```bash
|
|
17
25
|
python -m pytest packages/claude-dev-env/scripts/tests/
|
|
18
26
|
```
|
|
27
|
+
|
|
28
|
+
PowerShell scripts (Pester 5+, `*.Tests.ps1`):
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
Invoke-Pester -Path packages/claude-dev-env/scripts/tests/
|
|
32
|
+
```
|