@danmoisan/drm-copilot-mcp 1.1.24 → 1.1.26
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/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +7 -3
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +6 -2
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +41 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-cleanup.ps1 +481 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +3 -1
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier-helpers.ps1 +69 -3
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +2 -2
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.cleanup.ps1 +246 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.docs-only.ps1 +1 -0
- package/resources/claude-customizations/.claude/hooks/hook-cleanup-context.ps1 +343 -0
- package/resources/claude-customizations/.claude/lib/parallel-admission/Invoke-ParallelAdmission.ps1 +626 -0
- package/resources/claude-customizations/.claude/lib/parallel-admission/ParallelAdmission.psm1 +508 -0
- package/resources/claude-customizations/.claude/lib/parallel-admission/ParallelAdmissionJson.psm1 +141 -0
- package/resources/claude-customizations/.claude/lib/parallel-admission/ParallelAdmissionPrecedence.psm1 +508 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +17 -1
- package/resources/claude-customizations/.claude/settings.json +1 -0
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +93 -14
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +23 -10
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +54 -46
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_merge_lib.sh +234 -0
- package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +15 -5
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +71 -7
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +26 -2
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +82 -12
- package/resources/claude-customizations/pack-manifests/core.json +8 -0
- package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +15 -5
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-cleanup.ps1 +481 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +4 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-cleanup-context.ps1 +343 -0
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +2 -0
- package/resources/customizations/.github/skills/execution-environment/SKILL.md +15 -5
- package/resources/powershell/PoshQC/PoshQC.ScanConfig.psm1 +3 -1
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +12 -10
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Pure cleanup-context predicates shared by the cleanup legs of the enforcement gates (issue #1026).
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
The cleanup-merged-worktrees skill writes no per-feature, epic, or parallel checkpoint, so
|
|
7
|
+
the checkpoint-based gates cannot recognize its writes, commits, delegation, and pull
|
|
8
|
+
request. Its integrity record is the sanctioned-removal manifest. This file holds the pure
|
|
9
|
+
decisions the gates' cleanup legs share:
|
|
10
|
+
|
|
11
|
+
Test-CleanupManifestText - the manifest header (tool, schema_version) and,
|
|
12
|
+
with -UtcNow, its freshness and run_id.
|
|
13
|
+
Test-CleanupConsolidationRelativePath - the allowlist: the repository-relative prefixes
|
|
14
|
+
docs/ and .claude/agent-memory/ (ordinal,
|
|
15
|
+
case-sensitive), plus the pr-author receipt
|
|
16
|
+
artifacts/pr_body_<digits>.receipt.json with
|
|
17
|
+
-AllowReceipt.
|
|
18
|
+
Find-CleanupConsolidationRecord - the consolidation worktree, identified by its
|
|
19
|
+
porcelain branch, never by its path.
|
|
20
|
+
Test-CleanupScratchPath - the scratch rule: an absolute path outside every
|
|
21
|
+
registered worktree and the session root, under a
|
|
22
|
+
temporary root.
|
|
23
|
+
Test-CleanupConsolidationBranchLabel - the delegation label rule of the model-routing leg.
|
|
24
|
+
|
|
25
|
+
Every function fails closed: a malformed or ambiguous input answers $false or $null.
|
|
26
|
+
|
|
27
|
+
The literals below restate values owned elsewhere: the branch equals
|
|
28
|
+
CLEANUP_WT_CONSOLIDATION_BRANCH in
|
|
29
|
+
.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_actions_lib.sh, and the
|
|
30
|
+
manifest tool, schema version, and freshness bound equal $script:ExpectedManifestTool,
|
|
31
|
+
$script:ExpectedManifestSchemaVersion, and $script:ManifestFreshnessBound in
|
|
32
|
+
.claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1. The Codex hooks cannot import
|
|
33
|
+
.claude/lib, so the values are restated here and pinned equal by
|
|
34
|
+
tests/scripts/claude-hooks/hook-cleanup-context.Parity.Tests.ps1. The names avoid the
|
|
35
|
+
removal gates' $script:CleanupWorktreeManifestPath.
|
|
36
|
+
|
|
37
|
+
.NOTES
|
|
38
|
+
PowerShell 7+. Functions and literals only: no file, process, network, clock, or
|
|
39
|
+
environment access, no dot-source, and no import. Byte-identical at .claude/hooks,
|
|
40
|
+
.codex/hooks, and both bundle mirrors under extensions/drm-copilot/resources/.
|
|
41
|
+
#>
|
|
42
|
+
|
|
43
|
+
$script:CleanupContextBranch = 'documentationandmemories'
|
|
44
|
+
$script:CleanupContextManifestRelativePath = 'artifacts/orchestration/cleanup-worktrees-manifest.json'
|
|
45
|
+
$script:CleanupContextManifestTool = 'cleanup-merged-worktrees'
|
|
46
|
+
$script:CleanupContextManifestSchemaVersion = 1
|
|
47
|
+
$script:CleanupContextFreshnessHours = 24
|
|
48
|
+
|
|
49
|
+
function Test-CleanupManifestText {
|
|
50
|
+
<#
|
|
51
|
+
.SYNOPSIS
|
|
52
|
+
Return $true when the text is a cleanup manifest with the expected header.
|
|
53
|
+
.DESCRIPTION
|
|
54
|
+
The text must parse as a JSON object whose tool is the string cleanup-merged-worktrees
|
|
55
|
+
(ordinal) and whose schema_version is the integer 1. When -UtcNow is supplied, the
|
|
56
|
+
manifest must also carry a generated_at that parses, is not after UtcNow, and lies
|
|
57
|
+
within the freshness bound, and a run_id that is a non-blank string. The generated_at
|
|
58
|
+
value is read exactly as CleanupWorktreeManifest.psm1 reads it, so the PR and
|
|
59
|
+
delegation legs agree with the removal gates on freshness.
|
|
60
|
+
.PARAMETER Raw
|
|
61
|
+
The manifest text, or $null when no manifest exists.
|
|
62
|
+
.PARAMETER UtcNow
|
|
63
|
+
The current UTC time from the caller's clock seam.
|
|
64
|
+
.OUTPUTS
|
|
65
|
+
System.Boolean
|
|
66
|
+
#>
|
|
67
|
+
[CmdletBinding()]
|
|
68
|
+
[OutputType([bool])]
|
|
69
|
+
param(
|
|
70
|
+
[AllowNull()][AllowEmptyString()][string] $Raw,
|
|
71
|
+
[datetime] $UtcNow
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
if ([string]::IsNullOrWhiteSpace($Raw)) {
|
|
75
|
+
return $false
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
$manifest = $Raw | ConvertFrom-Json -ErrorAction Stop
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return $false
|
|
82
|
+
}
|
|
83
|
+
if ($manifest -isnot [System.Management.Automation.PSCustomObject]) {
|
|
84
|
+
return $false
|
|
85
|
+
}
|
|
86
|
+
$names = @($manifest.PSObject.Properties.Name)
|
|
87
|
+
if ($names -notcontains 'tool' -or $names -notcontains 'schema_version') {
|
|
88
|
+
return $false
|
|
89
|
+
}
|
|
90
|
+
if ($manifest.tool -isnot [string] -or $manifest.tool -cne $script:CleanupContextManifestTool) {
|
|
91
|
+
return $false
|
|
92
|
+
}
|
|
93
|
+
$schemaVersion = $manifest.schema_version
|
|
94
|
+
if (($schemaVersion -isnot [int] -and $schemaVersion -isnot [long]) -or [long]$schemaVersion -ne $script:CleanupContextManifestSchemaVersion) {
|
|
95
|
+
return $false
|
|
96
|
+
}
|
|
97
|
+
if (-not $PSBoundParameters.ContainsKey('UtcNow')) {
|
|
98
|
+
return $true
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if ($names -notcontains 'generated_at' -or $names -notcontains 'run_id') {
|
|
102
|
+
return $false
|
|
103
|
+
}
|
|
104
|
+
$generatedAt = [datetime]::MinValue
|
|
105
|
+
$styles = [System.Globalization.DateTimeStyles]::AdjustToUniversal -bor [System.Globalization.DateTimeStyles]::AssumeUniversal
|
|
106
|
+
if (-not [datetime]::TryParse([string]$manifest.generated_at, [cultureinfo]::InvariantCulture, $styles, [ref] $generatedAt)) {
|
|
107
|
+
return $false
|
|
108
|
+
}
|
|
109
|
+
if ($generatedAt -gt $UtcNow -or ($UtcNow - $generatedAt) -gt [timespan]::FromHours($script:CleanupContextFreshnessHours)) {
|
|
110
|
+
return $false
|
|
111
|
+
}
|
|
112
|
+
return ($manifest.run_id -is [string] -and -not [string]::IsNullOrWhiteSpace($manifest.run_id))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function Test-CleanupConsolidationRelativePath {
|
|
116
|
+
<#
|
|
117
|
+
.SYNOPSIS
|
|
118
|
+
Return $true when a repository-relative path is on the consolidation allowlist.
|
|
119
|
+
.DESCRIPTION
|
|
120
|
+
The path must use only the plain characters A-Z a-z 0-9 . _ / -, must not be rooted,
|
|
121
|
+
must carry no '..' segment, and must start with docs/ or .claude/agent-memory/ under
|
|
122
|
+
ordinal, case-sensitive comparison with at least one character after the prefix. Any
|
|
123
|
+
other Markdown path, such as CLAUDE.md or .claude/rules/x.md, is not admitted. With
|
|
124
|
+
-AllowReceipt the pr-author receipt artifacts/pr_body_<digits>.receipt.json is also
|
|
125
|
+
admitted; it never enters the staging allowlist.
|
|
126
|
+
.PARAMETER RelativePath
|
|
127
|
+
The repository-relative path or operand.
|
|
128
|
+
.PARAMETER AllowReceipt
|
|
129
|
+
Admit the pr-author receipt path (Write and Edit leg only).
|
|
130
|
+
.OUTPUTS
|
|
131
|
+
System.Boolean
|
|
132
|
+
#>
|
|
133
|
+
[CmdletBinding()]
|
|
134
|
+
[OutputType([bool])]
|
|
135
|
+
param(
|
|
136
|
+
[AllowNull()][AllowEmptyString()][string] $RelativePath,
|
|
137
|
+
[switch] $AllowReceipt
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
$path = [string]$RelativePath
|
|
141
|
+
if ($path -cnotmatch '^[A-Za-z0-9._/-]+$' -or $path.StartsWith('/')) {
|
|
142
|
+
return $false
|
|
143
|
+
}
|
|
144
|
+
if (@($path -split '/') -contains '..') {
|
|
145
|
+
return $false
|
|
146
|
+
}
|
|
147
|
+
if ($AllowReceipt -and $path -cmatch '^artifacts/pr_body_[0-9]+\.receipt\.json$') {
|
|
148
|
+
return $true
|
|
149
|
+
}
|
|
150
|
+
foreach ($prefix in @('docs/', '.claude/agent-memory/')) {
|
|
151
|
+
if ($path.Length -gt $prefix.Length -and $path.StartsWith($prefix, [System.StringComparison]::Ordinal)) {
|
|
152
|
+
return $true
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return $false
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function Find-CleanupConsolidationRecord {
|
|
159
|
+
<#
|
|
160
|
+
.SYNOPSIS
|
|
161
|
+
Return the registered consolidation worktree record, or $null.
|
|
162
|
+
.DESCRIPTION
|
|
163
|
+
Takes the records ConvertFrom-HookTargetWorktreePorcelain emits. The first record (the
|
|
164
|
+
main worktree stanza), prunable records, and detached records are skipped. The single
|
|
165
|
+
remaining record whose Branch is ordinal-equal to documentationandmemories is returned;
|
|
166
|
+
none, or more than one, returns $null. The path is never consulted, because the
|
|
167
|
+
consolidation path can be overridden by CLEANUP_WT_CONSOLIDATION_PATH.
|
|
168
|
+
.PARAMETER Record
|
|
169
|
+
The porcelain records, in listing order.
|
|
170
|
+
.OUTPUTS
|
|
171
|
+
System.Management.Automation.PSCustomObject or $null
|
|
172
|
+
#>
|
|
173
|
+
[CmdletBinding()]
|
|
174
|
+
[OutputType([pscustomobject])]
|
|
175
|
+
param(
|
|
176
|
+
[AllowNull()][AllowEmptyCollection()][object[]] $Record
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
$records = @($Record | Where-Object { $null -ne $_ })
|
|
180
|
+
$found = [System.Collections.Generic.List[object]]::new()
|
|
181
|
+
for ($index = 1; $index -lt $records.Count; $index++) {
|
|
182
|
+
$candidate = $records[$index]
|
|
183
|
+
if ([bool]$candidate.Prunable -or $null -eq $candidate.Branch) {
|
|
184
|
+
continue
|
|
185
|
+
}
|
|
186
|
+
if ([string]$candidate.Branch -ceq $script:CleanupContextBranch) {
|
|
187
|
+
$found.Add($candidate)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if ($found.Count -ne 1) {
|
|
191
|
+
return $null
|
|
192
|
+
}
|
|
193
|
+
return $found[0]
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function ConvertTo-CleanupContextPath {
|
|
197
|
+
<#
|
|
198
|
+
.SYNOPSIS
|
|
199
|
+
Normalize a path to forward slashes with one trailing slash removed (bare roots kept).
|
|
200
|
+
.OUTPUTS
|
|
201
|
+
System.String
|
|
202
|
+
#>
|
|
203
|
+
[CmdletBinding()]
|
|
204
|
+
[OutputType([string])]
|
|
205
|
+
param(
|
|
206
|
+
[AllowNull()][AllowEmptyString()][string] $Path
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
$normalized = ([string]$Path).Replace('\', '/')
|
|
210
|
+
if ($normalized.Length -gt 1 -and $normalized.EndsWith('/') -and $normalized -notmatch '^[A-Za-z]:/$') {
|
|
211
|
+
$normalized = $normalized.Substring(0, $normalized.Length - 1)
|
|
212
|
+
}
|
|
213
|
+
return $normalized
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function Test-CleanupContextPathUnder {
|
|
217
|
+
<#
|
|
218
|
+
.SYNOPSIS
|
|
219
|
+
Return $true when a normalized path equals a root or lies beneath it (OrdinalIgnoreCase).
|
|
220
|
+
.OUTPUTS
|
|
221
|
+
System.Boolean
|
|
222
|
+
#>
|
|
223
|
+
[CmdletBinding()]
|
|
224
|
+
[OutputType([bool])]
|
|
225
|
+
param(
|
|
226
|
+
[Parameter(Mandatory)][AllowEmptyString()][string] $Path,
|
|
227
|
+
[AllowNull()][AllowEmptyString()][string] $Root
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
$normalizedRoot = ConvertTo-CleanupContextPath -Path $Root
|
|
231
|
+
if ([string]::IsNullOrEmpty($normalizedRoot)) {
|
|
232
|
+
return $false
|
|
233
|
+
}
|
|
234
|
+
if ([string]::Equals($Path, $normalizedRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
235
|
+
return $true
|
|
236
|
+
}
|
|
237
|
+
$prefix = if ($normalizedRoot.EndsWith('/')) { $normalizedRoot } else { $normalizedRoot + '/' }
|
|
238
|
+
return $Path.StartsWith($prefix, [System.StringComparison]::OrdinalIgnoreCase)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function Test-CleanupScratchPath {
|
|
242
|
+
<#
|
|
243
|
+
.SYNOPSIS
|
|
244
|
+
Return $true when a path is a scratch path under a temporary root and outside every worktree.
|
|
245
|
+
.DESCRIPTION
|
|
246
|
+
The path must be absolute (drive-rooted or slash-rooted, not UNC), carry no '.' or '..'
|
|
247
|
+
segment and no surrounding whitespace, lie outside every registered worktree root and
|
|
248
|
+
outside the session root, and lie under at least one accepted temporary-root spelling.
|
|
249
|
+
Comparisons use forward-slash normalization and OrdinalIgnoreCase. The rule fails
|
|
250
|
+
closed when no registered root or no temporary root is supplied, and when any
|
|
251
|
+
registered worktree root lies under an accepted temporary root, because a path under
|
|
252
|
+
such a worktree could then be spelled so that it matches no registered root.
|
|
253
|
+
.PARAMETER Path
|
|
254
|
+
The Write or Edit file path.
|
|
255
|
+
.PARAMETER RegisteredRoot
|
|
256
|
+
Every registered worktree root from the listing, prunable ones included.
|
|
257
|
+
.PARAMETER SessionRoot
|
|
258
|
+
The session root.
|
|
259
|
+
.PARAMETER TemporaryRoot
|
|
260
|
+
Every accepted spelling of the operating-system temporary root.
|
|
261
|
+
.OUTPUTS
|
|
262
|
+
System.Boolean
|
|
263
|
+
#>
|
|
264
|
+
[CmdletBinding()]
|
|
265
|
+
[OutputType([bool])]
|
|
266
|
+
param(
|
|
267
|
+
[AllowNull()][AllowEmptyString()][string] $Path,
|
|
268
|
+
[AllowNull()][AllowEmptyCollection()][string[]] $RegisteredRoot,
|
|
269
|
+
[AllowNull()][AllowEmptyString()][string] $SessionRoot,
|
|
270
|
+
[AllowNull()][AllowEmptyCollection()][string[]] $TemporaryRoot
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
$raw = [string]$Path
|
|
274
|
+
if ([string]::IsNullOrEmpty($raw) -or $raw.Trim() -cne $raw) {
|
|
275
|
+
return $false
|
|
276
|
+
}
|
|
277
|
+
$normalized = ConvertTo-CleanupContextPath -Path $raw
|
|
278
|
+
if ($normalized -notmatch '^([A-Za-z]:/|/(?!/))') {
|
|
279
|
+
return $false
|
|
280
|
+
}
|
|
281
|
+
$segments = @($normalized -split '/')
|
|
282
|
+
if ($segments -contains '.' -or $segments -contains '..') {
|
|
283
|
+
return $false
|
|
284
|
+
}
|
|
285
|
+
$roots = @($RegisteredRoot | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
|
|
286
|
+
$temporary = @($TemporaryRoot | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
|
|
287
|
+
if ($roots.Count -eq 0 -or $temporary.Count -eq 0 -or [string]::IsNullOrWhiteSpace($SessionRoot)) {
|
|
288
|
+
return $false
|
|
289
|
+
}
|
|
290
|
+
foreach ($registeredCandidate in $roots) {
|
|
291
|
+
$normalizedRoot = ConvertTo-CleanupContextPath -Path $registeredCandidate
|
|
292
|
+
foreach ($temporaryCandidate in $temporary) {
|
|
293
|
+
if (Test-CleanupContextPathUnder -Path $normalizedRoot -Root $temporaryCandidate) {
|
|
294
|
+
return $false
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (Test-CleanupContextPathUnder -Path $normalized -Root $registeredCandidate) {
|
|
298
|
+
return $false
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (Test-CleanupContextPathUnder -Path $normalized -Root $SessionRoot) {
|
|
302
|
+
return $false
|
|
303
|
+
}
|
|
304
|
+
foreach ($temporaryCandidate in $temporary) {
|
|
305
|
+
$normalizedTemporary = ConvertTo-CleanupContextPath -Path $temporaryCandidate
|
|
306
|
+
if (-not [string]::Equals($normalized, $normalizedTemporary, [System.StringComparison]::OrdinalIgnoreCase) -and
|
|
307
|
+
(Test-CleanupContextPathUnder -Path $normalized -Root $normalizedTemporary)) {
|
|
308
|
+
return $true
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return $false
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function Test-CleanupConsolidationBranchLabel {
|
|
315
|
+
<#
|
|
316
|
+
.SYNOPSIS
|
|
317
|
+
Return $true when a delegation prompt names the consolidation branch by exactly one label.
|
|
318
|
+
.DESCRIPTION
|
|
319
|
+
The prompt must contain exactly one 'branch:' label (case-insensitive count), on its own
|
|
320
|
+
line in the lowercase form 'branch: <value>', with the value ordinal-equal to
|
|
321
|
+
documentationandmemories, and no --head or --branch token anywhere, so the worktree
|
|
322
|
+
resolvers that read the first branch signal cannot select a different branch.
|
|
323
|
+
.PARAMETER PromptText
|
|
324
|
+
The delegation prompt.
|
|
325
|
+
.OUTPUTS
|
|
326
|
+
System.Boolean
|
|
327
|
+
#>
|
|
328
|
+
[CmdletBinding()]
|
|
329
|
+
[OutputType([bool])]
|
|
330
|
+
param(
|
|
331
|
+
[AllowNull()][AllowEmptyString()][string] $PromptText
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
$text = [string]$PromptText
|
|
335
|
+
if ([regex]::Matches($text, '(?i)\bbranch:').Count -ne 1) {
|
|
336
|
+
return $false
|
|
337
|
+
}
|
|
338
|
+
if ([regex]::IsMatch($text, '(?i)(?<![\w-])--(?:head|branch)(?![\w-])')) {
|
|
339
|
+
return $false
|
|
340
|
+
}
|
|
341
|
+
$label = [regex]::Match($text, '(?m)^[ \t]*branch:[ \t]*(?<value>[^\r\n]*?)[ \t]*\r?$')
|
|
342
|
+
return ($label.Success -and $label.Groups['value'].Value -ceq $script:CleanupContextBranch)
|
|
343
|
+
}
|