@danmoisan/drm-copilot-mcp 1.1.14 → 1.1.16

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.
Files changed (39) hide show
  1. package/package.json +1 -1
  2. package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +4 -5
  3. package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget-route.ps1 +137 -0
  4. package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +95 -66
  5. package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +330 -0
  6. package/resources/claude-customizations/.claude/rules/powershell.md +3 -3
  7. package/resources/claude-customizations/.claude/rules/shell.md +8 -7
  8. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +8 -8
  9. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +234 -0
  10. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_actions_lib.sh +451 -0
  11. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +301 -0
  12. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_dirt_lib.sh +495 -0
  13. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +252 -0
  14. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_lib.sh +496 -0
  15. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_eol_lib.sh +212 -0
  16. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +492 -0
  17. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_report_records_lib.sh +476 -0
  18. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +182 -0
  19. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +1 -1
  20. package/resources/claude-customizations/.claude/skills/invoke-powershell-engineer/SKILL.md +3 -4
  21. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +1 -1
  22. package/resources/claude-customizations/.claude/skills/powershell-change-budget-router/SKILL.md +6 -6
  23. package/resources/claude-customizations/pack-manifests/core.json +11 -0
  24. package/resources/claude-customizations/pack-manifests/powershell.json +1 -0
  25. package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +1 -1
  26. package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +1 -2
  27. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +2 -3
  28. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +2 -3
  29. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +2 -3
  30. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +2 -3
  31. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +2 -3
  32. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +2 -3
  33. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  34. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +285 -80
  35. package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +7 -7
  36. package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +8 -10
  37. package/resources/customizations/.github/prompts/orchestrate-powershell-work.prompt.md +2 -2
  38. package/resources/customizations/.github/skills/powershell-change-budget-router/SKILL.md +3 -3
  39. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +6 -0
@@ -0,0 +1,252 @@
1
+ #!/usr/bin/env bash
2
+ # cleanup_worktrees_enumerate_lib.sh: sourceable enumeration/protection function
3
+ # group for the cleanup-worktrees tool, split out of cleanup_worktrees_lib.sh to keep
4
+ # every file within the 500-line cap. Provides the git-binary test seam
5
+ # (cleanup_wt_git), branch/worktree enumeration (enumerate_branches,
6
+ # parse_worktree_list), path normalization (normalize_wt_path), the
7
+ # current-worktree/branch and base-branch protection set (compute_protected), and
8
+ # the main-freshness warning (check_main_freshness). The classification ladder,
9
+ # consolidation, deletion, and the CLI live in sibling files (cleanup_worktrees_lib.sh,
10
+ # cleanup_worktrees_actions_lib.sh, cleanup-worktrees.sh).
11
+ #
12
+ # Sourcing contract: defines functions and the single constant CLEANUP_WT_BASE_BRANCH
13
+ # and runs no other work at source time, so wrapper and bats suites source it safely.
14
+ # It MUST be sourced before cleanup_worktrees_lib.sh, whose classification functions
15
+ # call cleanup_wt_git, parse_worktree_list, compute_protected, and normalize_wt_path
16
+ # defined here.
17
+ #
18
+ # All git commands go through cleanup_wt_git so tests can stub the git binary via
19
+ # CLEANUP_WT_GIT_BIN. Git exit-code capture rule: the `git worktree list --porcelain`
20
+ # output consumed by parse_worktree_list is captured in the PARENT shell
21
+ # (`out=$(cmd) || rc=$?`, then iterated over `<<<"$out"`) so a non-zero exit is
22
+ # observed here rather than lost inside a process substitution. On a hard failure
23
+ # parse_worktree_list emits no records and returns git's non-zero exit code, and
24
+ # compute_protected propagates that failure rather than degrading to an empty
25
+ # (weakened) protected set. An empty porcelain output with exit 0 remains a valid
26
+ # empty list. enumerate_branches captures `git for-each-ref` in the parent shell
27
+ # (`out=$(...) || rc=$?`) BEFORE sorting, so a for-each-ref hard failure is observed
28
+ # even when the caller lacks pipefail; it returns git's exit code with no stdout rather
29
+ # than an empty branch list. compute_protected captures `git rev-parse --abbrev-ref
30
+ # HEAD` and `git rev-parse --show-toplevel`; a hard failure of either is fatal (git's
31
+ # exit code, no weakened fallback), and the base-branch record is emitted only after
32
+ # both guards pass. The detached-HEAD case (rev-parse prints HEAD) is unaffected.
33
+
34
+ cleanup_wt_git() {
35
+ # Resolve the git binary honoring the CLEANUP_WT_GIT_BIN override seam, then
36
+ # execute it with the caller's arguments.
37
+ #
38
+ # When CLEANUP_WT_GIT_BIN is set to a non-empty value it must point to an
39
+ # existing executable; an empty or nonexistent value is treated as missing and
40
+ # falls back to `command -v git`. This mirrors the SHELL_QC_<TOOL>_BIN seam in
41
+ # scripts/bash/shell_qc_lib.sh so the bats suites can stub git deterministically.
42
+ #
43
+ # Args: the git subcommand and its arguments.
44
+ # Returns git's exit code, or 127 when no git binary can be resolved.
45
+ local override=${CLEANUP_WT_GIT_BIN:-}
46
+ local git_bin=""
47
+ if [[ -n $override && -x $override ]]; then
48
+ git_bin=$override
49
+ else
50
+ git_bin=$(command -v git 2>/dev/null) || git_bin=""
51
+ fi
52
+ if [[ -z $git_bin ]]; then
53
+ printf 'cleanup-worktrees: no git binary resolved (CLEANUP_WT_GIT_BIN=%s)\n' "$override" >&2
54
+ return 127
55
+ fi
56
+ "$git_bin" "$@"
57
+ }
58
+
59
+ enumerate_branches() {
60
+ # Enumerate local branches via plumbing, one "name sha" pair per line.
61
+ #
62
+ # Uses `git for-each-ref` rather than `git branch` so loose refs and packed-refs
63
+ # are read uniformly and the output carries no decoration markers (`*`, `+`) or
64
+ # column padding. Output is LC_ALL=C sorted for deterministic ordering and
65
+ # deterministic cross-branch cherry-pick order.
66
+ #
67
+ # The for-each-ref result is captured in the parent shell (`out=$(...) || rc=$?`) so
68
+ # a non-zero for-each-ref exit is observed here even when the caller lacks pipefail
69
+ # (the bats harness); piping straight into sort would attribute only sort's exit to
70
+ # rc and lose the for-each-ref failure. On a hard failure it prints a diagnostic to
71
+ # stderr, emits no stdout, and returns git's non-zero exit code. Returns git's exit
72
+ # code from for-each-ref (0 on success).
73
+ local rc=0 out
74
+ out=$(cleanup_wt_git for-each-ref \
75
+ --format='%(refname:short) %(objectname)' refs/heads/) || rc=$?
76
+ if ((rc != 0)); then
77
+ printf 'cleanup-worktrees: git for-each-ref refs/heads/ failed (rc=%s)\n' "$rc" >&2
78
+ return "$rc"
79
+ fi
80
+ # printf-pipe (not a herestring) so an empty ref list emits nothing rather than one
81
+ # empty line.
82
+ printf '%s' "$out" | LC_ALL=C sort
83
+ }
84
+
85
+ parse_worktree_list() {
86
+ # Parse `git worktree list --porcelain` stanza-wise into pipe-delimited records.
87
+ #
88
+ # Emits one record per worktree: `path|head|branch-or-DETACHED|flags`. A new
89
+ # stanza begins at each `worktree ` line; a blank line closes the current stanza.
90
+ # The branch field carries the short branch name (refs/heads/ stripped) or the
91
+ # literal DETACHED when the stanza had a `detached` line. flags is a
92
+ # comma-separated set drawn from main,detached,bare,locked,prunable; the first
93
+ # stanza always carries the `main` flag (the main worktree is never a candidate).
94
+ #
95
+ # The porcelain listing is captured in the parent shell (`out=$(...) || rc=$?`) so
96
+ # a non-zero git exit is observed here rather than being lost inside a process
97
+ # substitution. Returns 0 on success (including an empty porcelain output with exit
98
+ # 0, which is a valid empty list); on a hard git failure it prints a diagnostic to
99
+ # stderr, emits no records, and returns git's non-zero exit code.
100
+ local rc=0 line out
101
+ local path="" head="" branch="" detached=0 bare=0 locked=0 prunable=0
102
+ local first=1 have=0
103
+ emit_record() {
104
+ # Flush the accumulated stanza as one record; no-op when none accumulated.
105
+ ((have == 0)) && return 0
106
+ local -a flag_parts=()
107
+ ((first == 1)) && flag_parts+=("main")
108
+ ((detached == 1)) && flag_parts+=("detached")
109
+ ((bare == 1)) && flag_parts+=("bare")
110
+ ((locked == 1)) && flag_parts+=("locked")
111
+ ((prunable == 1)) && flag_parts+=("prunable")
112
+ local flags=""
113
+ local IFS=,
114
+ flags="${flag_parts[*]}"
115
+ local branch_field="DETACHED"
116
+ [[ -n $branch ]] && branch_field=$branch
117
+ printf '%s|%s|%s|%s\n' "$path" "$head" "$branch_field" "$flags"
118
+ first=0
119
+ }
120
+ # Guarded parent-shell capture: a non-zero git exit is observed here (an unguarded
121
+ # `out=$(...)` would abort under the wrapper's set -euo pipefail). On a hard
122
+ # failure, return before emitting any record so the caller cannot mistake a git
123
+ # failure for an empty worktree list.
124
+ out=$(cleanup_wt_git worktree list --porcelain) || rc=$?
125
+ if ((rc != 0)); then
126
+ printf 'cleanup-worktrees: git worktree list --porcelain failed (rc=%s)\n' "$rc" >&2
127
+ return "$rc"
128
+ fi
129
+ while IFS= read -r line || [[ -n $line ]]; do
130
+ case "$line" in
131
+ "worktree "*)
132
+ emit_record
133
+ path=${line#worktree }
134
+ head="" branch="" detached=0 bare=0 locked=0 prunable=0
135
+ have=1
136
+ ;;
137
+ "HEAD "*) head=${line#HEAD } ;;
138
+ "branch "*) branch=${line#branch refs/heads/} ;;
139
+ detached) detached=1 ;;
140
+ bare) bare=1 ;;
141
+ "locked"*) locked=1 ;;
142
+ "prunable"*) prunable=1 ;;
143
+ "") ;; # stanza separator; the next `worktree ` flushes the record
144
+ esac
145
+ done <<<"$out"
146
+ emit_record
147
+ return "$rc"
148
+ }
149
+
150
+ normalize_wt_path() {
151
+ # Normalize a worktree path for comparison across Windows/WSL and git output.
152
+ #
153
+ # Converts backslashes to forward slashes, lowercases (case-insensitive match on
154
+ # Windows), and strips a single trailing slash. Echoes the normalized value;
155
+ # echoes nothing for an empty input.
156
+ #
157
+ # Args: $1 = path.
158
+ local p=${1:-}
159
+ [[ -z $p ]] && return 0
160
+ p=${p//\\//}
161
+ p=${p,,}
162
+ p=${p%/}
163
+ printf '%s\n' "$p"
164
+ }
165
+
166
+ # The ladder's fixed comparison base. compute_protected protects it by name in every
167
+ # checkout topology and delete_candidate refuses it. It is deliberately not read from
168
+ # the environment, so no override can unprotect the base branch (issue #594).
169
+ CLEANUP_WT_BASE_BRANCH="main"
170
+
171
+ compute_protected() {
172
+ # Compute the protected branch and protected worktree paths (PROTECTED_CURRENT).
173
+ #
174
+ # Dual exclusion, both checks required:
175
+ # 1. Current branch via `git rev-parse --abbrev-ref HEAD`. A `HEAD` result means
176
+ # detached: no branch name to protect (only the worktree path is protected).
177
+ # 2. Current worktree path via `git rev-parse --show-toplevel`, compared after
178
+ # slash/case normalization against each porcelain worktree path.
179
+ # The main worktree (first porcelain stanza) is always protected regardless of the
180
+ # above. Emits `protected-branch|<name>` (omitted when detached) and one
181
+ # `protected-path|<normalized-path>` line per protected worktree.
182
+ #
183
+ # The base branch CLEANUP_WT_BASE_BRANCH is always protected by name, whichever
184
+ # worktree (if any) has it checked out. Its `protected-branch|` record is emitted
185
+ # only after both rev-parse guards pass, so the fail-closed contract below is
186
+ # unchanged, and it is omitted when the current branch already equals the base, so
187
+ # no duplicate record is emitted.
188
+ #
189
+ # Returns 0 on success. A parse_worktree_list hard failure propagates as its
190
+ # non-zero return; the caller must treat that as fatal, not as an empty (weakened)
191
+ # protected set. A hard failure of `git rev-parse --abbrev-ref HEAD` or
192
+ # `git rev-parse --show-toplevel` is likewise fatal (return git's exit code), never a
193
+ # weakened protection fallback; the detached-HEAD case (rev-parse succeeds printing
194
+ # HEAD) is unaffected and keeps its branch-name omission.
195
+ local rc=0 current_branch current_top norm_cur cbrc=0 ctrc=0
196
+ current_branch=$(cleanup_wt_git rev-parse --abbrev-ref HEAD) || cbrc=$?
197
+ if ((cbrc != 0)); then
198
+ printf 'cleanup-worktrees: git rev-parse --abbrev-ref HEAD failed (rc=%s)\n' "$cbrc" >&2
199
+ return "$cbrc"
200
+ fi
201
+ current_top=$(cleanup_wt_git rev-parse --show-toplevel) || ctrc=$?
202
+ if ((ctrc != 0)); then
203
+ printf 'cleanup-worktrees: git rev-parse --show-toplevel failed (rc=%s)\n' "$ctrc" >&2
204
+ return "$ctrc"
205
+ fi
206
+ norm_cur=$(normalize_wt_path "$current_top")
207
+ if [[ -n $current_branch && $current_branch != HEAD ]]; then
208
+ printf 'protected-branch|%s\n' "$current_branch"
209
+ fi
210
+ # Base-branch protection is unconditional and emitted only after both rev-parse
211
+ # guards pass; it is skipped when the current branch already equals the base.
212
+ if [[ $current_branch != "$CLEANUP_WT_BASE_BRANCH" ]]; then
213
+ printf 'protected-branch|%s\n' "$CLEANUP_WT_BASE_BRANCH"
214
+ fi
215
+ local first=1 record path norm pout prc=0
216
+ # Guarded parent-shell capture: a parse_worktree_list hard failure must abort here,
217
+ # not degrade to an empty protected set. Compare the current toplevel against each
218
+ # porcelain worktree path; the first stanza (main worktree) is always protected.
219
+ pout=$(parse_worktree_list) || prc=$?
220
+ if ((prc != 0)); then
221
+ return "$prc"
222
+ fi
223
+ while IFS= read -r record; do
224
+ [[ -z $record ]] && continue
225
+ path=${record%%|*}
226
+ norm=$(normalize_wt_path "$path")
227
+ if ((first == 1)); then
228
+ printf 'protected-path|%s\n' "$norm"
229
+ elif [[ -n $norm_cur && $norm == "$norm_cur" ]]; then
230
+ printf 'protected-path|%s\n' "$norm"
231
+ fi
232
+ first=0
233
+ done <<<"$pout"
234
+ return "$rc"
235
+ }
236
+
237
+ check_main_freshness() {
238
+ # Warn when local `main` diverges from `origin/main`; never block classification.
239
+ #
240
+ # Compares `git rev-parse main` with `git rev-parse origin/main`. On mismatch it
241
+ # emits the report line `WARN|main-divergence|<local-sha>|<origin-sha>`. A stale
242
+ # local `main` can only produce a false "not merged" (the safe direction), so this
243
+ # is advisory only and always returns 0. If either rev-parse fails (e.g. no
244
+ # origin/main configured), the check is skipped without error.
245
+ local local_sha origin_sha
246
+ local_sha=$(cleanup_wt_git rev-parse main 2>/dev/null) || return 0
247
+ origin_sha=$(cleanup_wt_git rev-parse origin/main 2>/dev/null) || return 0
248
+ if [[ -n $local_sha && -n $origin_sha && $local_sha != "$origin_sha" ]]; then
249
+ printf 'WARN|main-divergence|%s|%s\n' "$local_sha" "$origin_sha"
250
+ fi
251
+ return 0
252
+ }