@danmoisan/drm-copilot-mcp 1.0.21 → 1.0.22
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/out/mcp-server.js +1624 -190
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/MEMORY.md +5 -1
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_commit_push_memory_before_pr.md +48 -2
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_no_sendmessage_tool.md +35 -0
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_worktree_isolation_branches_from_main.md +45 -0
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +238 -0
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +149 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +23 -11
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +259 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +499 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate-helpers.ps1 +302 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +359 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +244 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +379 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +491 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +490 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusGlob.psm1 +429 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +366 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +184 -0
- package/resources/claude-customizations/.claude/settings.json +25 -0
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +148 -0
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +93 -0
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +960 -0
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +420 -0
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +176 -0
- package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +56 -0
- package/resources/claude-customizations/pack-manifests/core.json +19 -1
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/config/orchestration-routing.json +22 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +29 -0
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Blast-radius input guards and truth-table resolution.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Destination-runtime PowerShell port of the guard and truth-table half of
|
|
7
|
+
scripts/dev_tools/_blast_radius_validation.py (require_text,
|
|
8
|
+
require_str_tuple, require_mapping, config_string_list, config_modules,
|
|
9
|
+
config_over_breadth_fraction, resolve_modules, resolve_shared_surfaces). The
|
|
10
|
+
construction-time invariants of the BlastRadius dataclass are ported in the
|
|
11
|
+
sibling module BlastRadiusValidation.psm1, which keeps every file inside the
|
|
12
|
+
500-line limit.
|
|
13
|
+
|
|
14
|
+
The Python modules remain the authoritative reference implementation. This
|
|
15
|
+
module is one half of a two-language mirror; it never imports validator
|
|
16
|
+
logic. Every function is pure: no filesystem, subprocess, network, or
|
|
17
|
+
wall-clock access, and no input is mutated.
|
|
18
|
+
|
|
19
|
+
Parity notes for maintainers:
|
|
20
|
+
- The Python guards raise TypeError or ValueError; this port throws, which
|
|
21
|
+
is the PowerShell analog of a fail-fast contract violation.
|
|
22
|
+
- require_str_tuple rejects a bare string so Python cannot silently split
|
|
23
|
+
it into characters. The port keeps that rejection even though PowerShell
|
|
24
|
+
would not split, because the contract is "throw on malformed input" and
|
|
25
|
+
the two languages must agree on which inputs are malformed.
|
|
26
|
+
- A parsed truth table must be a dictionary. ConvertFrom-Json produces a
|
|
27
|
+
PSCustomObject by default, so callers should either pass -AsHashtable or
|
|
28
|
+
rely on the PSCustomObject conversion this module performs; no other
|
|
29
|
+
shape is accepted.
|
|
30
|
+
- Every returned collection is deduplicated and ordinally sorted.
|
|
31
|
+
#>
|
|
32
|
+
|
|
33
|
+
Set-StrictMode -Version Latest
|
|
34
|
+
|
|
35
|
+
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'BlastRadiusExtraction.psm1') -Force
|
|
36
|
+
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'BlastRadiusGlob.psm1') -Force
|
|
37
|
+
|
|
38
|
+
# Keys read from the parsed config/blast-radius.json truth table.
|
|
39
|
+
$script:ConfigSharedSurfaceKey = 'shared_surfaces'
|
|
40
|
+
$script:ConfigSharedSurfaceGlobKey = 'shared_surface_globs'
|
|
41
|
+
$script:ConfigModuleKey = 'modules'
|
|
42
|
+
$script:ConfigOverBreadthKey = 'over_breadth_fraction'
|
|
43
|
+
|
|
44
|
+
# Numeric types a JSON or literal truth table may carry for the V3 threshold.
|
|
45
|
+
# Booleans are excluded explicitly because Python treats them as integers and the
|
|
46
|
+
# reference guard rejects them.
|
|
47
|
+
$script:NumericTypeName = @('System.Int32', 'System.Int64', 'System.Double',
|
|
48
|
+
'System.Single', 'System.Decimal', 'System.Int16', 'System.Byte')
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
function Get-RequiredText {
|
|
52
|
+
<#
|
|
53
|
+
.SYNOPSIS
|
|
54
|
+
Guard a caller-supplied value that must be a string.
|
|
55
|
+
|
|
56
|
+
.DESCRIPTION
|
|
57
|
+
Port of require_text. Returns the validated value unchanged so call sites
|
|
58
|
+
can guard and assign in one expression.
|
|
59
|
+
|
|
60
|
+
.PARAMETER Value
|
|
61
|
+
Value of unknown runtime type.
|
|
62
|
+
|
|
63
|
+
.PARAMETER FieldName
|
|
64
|
+
Name used in the error message.
|
|
65
|
+
|
|
66
|
+
.PARAMETER AllowEmpty
|
|
67
|
+
When set, a blank string is accepted.
|
|
68
|
+
|
|
69
|
+
.OUTPUTS
|
|
70
|
+
System.String. The validated value, unchanged.
|
|
71
|
+
#>
|
|
72
|
+
[CmdletBinding()]
|
|
73
|
+
[OutputType([string])]
|
|
74
|
+
param(
|
|
75
|
+
[Parameter(Mandatory = $true)]
|
|
76
|
+
[AllowNull()]
|
|
77
|
+
[AllowEmptyString()]
|
|
78
|
+
[object] $Value,
|
|
79
|
+
[Parameter(Mandatory = $true)]
|
|
80
|
+
[string] $FieldName,
|
|
81
|
+
[switch] $AllowEmpty
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if ($Value -isnot [string]) {
|
|
85
|
+
$actual = if ($null -eq $Value) { 'null' } else { $Value.GetType().Name }
|
|
86
|
+
throw "$FieldName must be a string, got $actual."
|
|
87
|
+
}
|
|
88
|
+
if (-not $AllowEmpty -and [string]::IsNullOrWhiteSpace($Value)) {
|
|
89
|
+
throw "$FieldName must not be empty."
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return [string]$Value
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function Get-RequiredStringList {
|
|
96
|
+
<#
|
|
97
|
+
.SYNOPSIS
|
|
98
|
+
Guard a caller-supplied string collection and normalize its order.
|
|
99
|
+
|
|
100
|
+
.DESCRIPTION
|
|
101
|
+
Port of require_str_tuple. A bare string is rejected because the Python
|
|
102
|
+
reference rejects it; accepting it here would make the two languages
|
|
103
|
+
disagree about which inputs are malformed. Every entry is validated
|
|
104
|
+
before sorting so an error names the offending value rather than a
|
|
105
|
+
position in an already-reordered collection.
|
|
106
|
+
|
|
107
|
+
.PARAMETER Value
|
|
108
|
+
A collection of non-blank strings.
|
|
109
|
+
|
|
110
|
+
.PARAMETER FieldName
|
|
111
|
+
Name used in the error message.
|
|
112
|
+
|
|
113
|
+
.OUTPUTS
|
|
114
|
+
System.Object[]. Entries deduplicated and ordinally sorted for parity.
|
|
115
|
+
#>
|
|
116
|
+
[CmdletBinding()]
|
|
117
|
+
[OutputType([System.Object[]])]
|
|
118
|
+
param(
|
|
119
|
+
[Parameter(Mandatory = $true)]
|
|
120
|
+
[AllowNull()]
|
|
121
|
+
[object] $Value,
|
|
122
|
+
[Parameter(Mandatory = $true)]
|
|
123
|
+
[string] $FieldName
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
if ($Value -is [string] -or $Value -isnot [System.Collections.IEnumerable]) {
|
|
127
|
+
$actual = if ($null -eq $Value) { 'null' } else { $Value.GetType().Name }
|
|
128
|
+
throw "$FieldName must be a list or tuple, got $actual."
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
$entry = [System.Collections.Generic.List[string]]::new()
|
|
132
|
+
foreach ($item in $Value) {
|
|
133
|
+
$entry.Add((Get-RequiredText -Value $item -FieldName "$FieldName entry"))
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return @(Get-OrdinalSortedEntry -Entry $entry.ToArray())
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function Get-RequiredMapping {
|
|
140
|
+
<#
|
|
141
|
+
.SYNOPSIS
|
|
142
|
+
Guard a caller-supplied mapping such as the parsed truth table.
|
|
143
|
+
|
|
144
|
+
.DESCRIPTION
|
|
145
|
+
Port of require_mapping. A dictionary is returned as a hashtable view; a
|
|
146
|
+
PSCustomObject, which is what ConvertFrom-Json yields without
|
|
147
|
+
-AsHashtable, is converted from its properties. The input is read only
|
|
148
|
+
and never mutated.
|
|
149
|
+
|
|
150
|
+
.PARAMETER Value
|
|
151
|
+
Value of unknown runtime type.
|
|
152
|
+
|
|
153
|
+
.PARAMETER FieldName
|
|
154
|
+
Name used in the error message.
|
|
155
|
+
|
|
156
|
+
.OUTPUTS
|
|
157
|
+
System.Collections.Hashtable. The validated mapping.
|
|
158
|
+
#>
|
|
159
|
+
[CmdletBinding()]
|
|
160
|
+
[OutputType([hashtable])]
|
|
161
|
+
param(
|
|
162
|
+
[Parameter(Mandatory = $true)]
|
|
163
|
+
[AllowNull()]
|
|
164
|
+
[object] $Value,
|
|
165
|
+
[Parameter(Mandatory = $true)]
|
|
166
|
+
[string] $FieldName
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
if ($Value -is [hashtable]) {
|
|
170
|
+
return $Value
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# The two remaining accepted shapes are any other IDictionary (for example an
|
|
174
|
+
# ordered dictionary) and the PSCustomObject ConvertFrom-Json produces; both
|
|
175
|
+
# are copied key by key so the caller's object is never mutated.
|
|
176
|
+
$copy = @{}
|
|
177
|
+
if ($Value -is [System.Collections.IDictionary]) {
|
|
178
|
+
foreach ($key in $Value.Keys) {
|
|
179
|
+
$copy[$key] = $Value[$key]
|
|
180
|
+
}
|
|
181
|
+
return $copy
|
|
182
|
+
}
|
|
183
|
+
if ($Value -is [System.Management.Automation.PSCustomObject]) {
|
|
184
|
+
foreach ($property in $Value.PSObject.Properties) {
|
|
185
|
+
$copy[$property.Name] = $property.Value
|
|
186
|
+
}
|
|
187
|
+
return $copy
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
$actual = if ($null -eq $Value) { 'null' } else { $Value.GetType().Name }
|
|
191
|
+
throw "$FieldName must be a mapping, got $actual."
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function Get-ConfigStringList {
|
|
195
|
+
<#
|
|
196
|
+
.SYNOPSIS
|
|
197
|
+
Read an optional list-of-strings entry from the truth table.
|
|
198
|
+
|
|
199
|
+
.DESCRIPTION
|
|
200
|
+
Port of config_string_list. An absent or null key yields an empty list so
|
|
201
|
+
a minimal truth table stays usable.
|
|
202
|
+
|
|
203
|
+
.PARAMETER Config
|
|
204
|
+
Parsed config/blast-radius.json.
|
|
205
|
+
|
|
206
|
+
.PARAMETER Key
|
|
207
|
+
Truth-table key to read.
|
|
208
|
+
|
|
209
|
+
.OUTPUTS
|
|
210
|
+
System.Object[]. Entries sorted and deduplicated.
|
|
211
|
+
#>
|
|
212
|
+
[CmdletBinding()]
|
|
213
|
+
[OutputType([System.Object[]])]
|
|
214
|
+
param(
|
|
215
|
+
[Parameter(Mandatory = $true)]
|
|
216
|
+
[AllowNull()]
|
|
217
|
+
[object] $Config,
|
|
218
|
+
[Parameter(Mandatory = $true)]
|
|
219
|
+
[string] $Key
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
$mapping = Get-RequiredMapping -Value $Config -FieldName 'config'
|
|
223
|
+
if (-not $mapping.ContainsKey($Key) -or $null -eq $mapping[$Key]) {
|
|
224
|
+
return @()
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return @(Get-RequiredStringList -Value $mapping[$Key] -FieldName "config[""$Key""]")
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function Get-ConfigRootSurface {
|
|
231
|
+
<#
|
|
232
|
+
.SYNOPSIS
|
|
233
|
+
Read the separator-free subset of the configured shared surfaces.
|
|
234
|
+
|
|
235
|
+
.DESCRIPTION
|
|
236
|
+
Port of config_root_surfaces. This is the sole source of separator-free
|
|
237
|
+
path acceptance (issue #452). The extraction module has no access to the
|
|
238
|
+
truth table, so both entry points that must agree, Get-BlastRadius and
|
|
239
|
+
Test-BlastRadius, call this reader on the same -Config value and forward
|
|
240
|
+
the result as -RootSurface. Deriving the set from the shared_surfaces
|
|
241
|
+
list rather than a second hardcoded list is what keeps extraction and
|
|
242
|
+
surface resolution from desynchronizing.
|
|
243
|
+
|
|
244
|
+
shared_surface_globs is deliberately not a source: a glob can never be an
|
|
245
|
+
exact token match, and admitting one would classify as a glob rather than
|
|
246
|
+
a concrete path.
|
|
247
|
+
|
|
248
|
+
.PARAMETER Config
|
|
249
|
+
Parsed config/blast-radius.json. Only the shared_surfaces key is read.
|
|
250
|
+
|
|
251
|
+
.OUTPUTS
|
|
252
|
+
System.Object[]. The shared_surfaces entries carrying no '/', ordinally
|
|
253
|
+
sorted and deduplicated by the underlying reader. A config with no
|
|
254
|
+
shared_surfaces key yields an empty array, which reproduces pre-change
|
|
255
|
+
behavior.
|
|
256
|
+
#>
|
|
257
|
+
[CmdletBinding()]
|
|
258
|
+
[OutputType([System.Object[]])]
|
|
259
|
+
param(
|
|
260
|
+
[Parameter(Mandatory = $true)]
|
|
261
|
+
[AllowNull()]
|
|
262
|
+
[object] $Config
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
$listed = @(Get-ConfigStringList -Config $Config -Key $script:ConfigSharedSurfaceKey)
|
|
266
|
+
|
|
267
|
+
# Keep only the entries a bare inline-code token could match exactly. A
|
|
268
|
+
# surface carrying a separator is already reachable through the ordinary
|
|
269
|
+
# path-shape rules, so admitting it here would widen nothing; a
|
|
270
|
+
# separator-free surface is the only kind the classifier's separator test
|
|
271
|
+
# made unreachable.
|
|
272
|
+
$rootSurface = [System.Collections.Generic.List[string]]::new()
|
|
273
|
+
foreach ($surface in $listed) {
|
|
274
|
+
if (-not $surface.Contains('/')) {
|
|
275
|
+
$rootSurface.Add($surface)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return @($rootSurface.ToArray())
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function Get-ConfigModuleEntry {
|
|
283
|
+
<#
|
|
284
|
+
.SYNOPSIS
|
|
285
|
+
Read the module map from the truth table as ordered name/glob pairs.
|
|
286
|
+
|
|
287
|
+
.DESCRIPTION
|
|
288
|
+
Port of config_modules. Each module is validated as it is read so a
|
|
289
|
+
malformed truth table fails at the first offending module rather than
|
|
290
|
+
producing a partial resolution. Pairs are returned ordered by module name
|
|
291
|
+
so resolution is deterministic in both languages.
|
|
292
|
+
|
|
293
|
+
.PARAMETER Config
|
|
294
|
+
Parsed config/blast-radius.json.
|
|
295
|
+
|
|
296
|
+
.OUTPUTS
|
|
297
|
+
System.Object[]. Hashtables with keys name and globs, ordered by name.
|
|
298
|
+
#>
|
|
299
|
+
[CmdletBinding()]
|
|
300
|
+
[OutputType([System.Object[]])]
|
|
301
|
+
param(
|
|
302
|
+
[Parameter(Mandatory = $true)]
|
|
303
|
+
[AllowNull()]
|
|
304
|
+
[object] $Config
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
$mapping = Get-RequiredMapping -Value $Config -FieldName 'config'
|
|
308
|
+
if (-not $mapping.ContainsKey($script:ConfigModuleKey) -or
|
|
309
|
+
$null -eq $mapping[$script:ConfigModuleKey]) {
|
|
310
|
+
return @()
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
$moduleMap = Get-RequiredMapping -Value $mapping[$script:ConfigModuleKey] `
|
|
314
|
+
-FieldName "config[""$script:ConfigModuleKey""]"
|
|
315
|
+
|
|
316
|
+
# Validate every key before ordering so the error names the offending module
|
|
317
|
+
# rather than a position in an already-sorted collection.
|
|
318
|
+
$name = [System.Collections.Generic.List[string]]::new()
|
|
319
|
+
foreach ($key in $moduleMap.Keys) {
|
|
320
|
+
$name.Add((Get-RequiredText -Value $key -FieldName "config[""$script:ConfigModuleKey""] key"))
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
$pair = [System.Collections.Generic.List[hashtable]]::new()
|
|
324
|
+
foreach ($module in @(Get-OrdinalSortedEntry -Entry $name.ToArray())) {
|
|
325
|
+
$globs = @(Get-RequiredStringList -Value $moduleMap[$module] `
|
|
326
|
+
-FieldName "config[""$script:ConfigModuleKey""][$module]")
|
|
327
|
+
$pair.Add(@{ name = $module; globs = $globs })
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return @($pair.ToArray())
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function Get-ConfigOverBreadthFraction {
|
|
334
|
+
<#
|
|
335
|
+
.SYNOPSIS
|
|
336
|
+
Read the V3 over-breadth threshold from the truth table.
|
|
337
|
+
|
|
338
|
+
.DESCRIPTION
|
|
339
|
+
Port of config_over_breadth_fraction. Booleans are rejected explicitly
|
|
340
|
+
because Python treats them as integers, and the value must lie within
|
|
341
|
+
(0, 1].
|
|
342
|
+
|
|
343
|
+
.PARAMETER Config
|
|
344
|
+
Parsed config/blast-radius.json.
|
|
345
|
+
|
|
346
|
+
.OUTPUTS
|
|
347
|
+
System.Double. The fraction of tracked files above which a radius is
|
|
348
|
+
over-broad.
|
|
349
|
+
#>
|
|
350
|
+
[CmdletBinding()]
|
|
351
|
+
[OutputType([double])]
|
|
352
|
+
param(
|
|
353
|
+
[Parameter(Mandatory = $true)]
|
|
354
|
+
[AllowNull()]
|
|
355
|
+
[object] $Config
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
$mapping = Get-RequiredMapping -Value $Config -FieldName 'config'
|
|
359
|
+
$value = $null
|
|
360
|
+
if ($mapping.ContainsKey($script:ConfigOverBreadthKey)) {
|
|
361
|
+
$value = $mapping[$script:ConfigOverBreadthKey]
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if ($value -is [bool] -or $null -eq $value -or
|
|
365
|
+
$script:NumericTypeName -notcontains $value.GetType().FullName) {
|
|
366
|
+
throw "config[""$script:ConfigOverBreadthKey""] must be a number in (0, 1]."
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
$fraction = [double]$value
|
|
370
|
+
if (-not ($fraction -gt 0 -and $fraction -le 1)) {
|
|
371
|
+
throw "config[""$script:ConfigOverBreadthKey""] must be within (0, 1]."
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return $fraction
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function Resolve-BlastRadiusModule {
|
|
378
|
+
<#
|
|
379
|
+
.SYNOPSIS
|
|
380
|
+
Resolve path entries to the module names of the truth-table map.
|
|
381
|
+
|
|
382
|
+
.DESCRIPTION
|
|
383
|
+
Port of resolve_modules. A module joins the radius as soon as one of its
|
|
384
|
+
globs covers one entry, so the search stops at the first hit per module.
|
|
385
|
+
A path matching no glob resolves to no module.
|
|
386
|
+
|
|
387
|
+
.PARAMETER PathEntry
|
|
388
|
+
Concrete paths and globs of a radius. An empty collection is accepted.
|
|
389
|
+
|
|
390
|
+
.PARAMETER Config
|
|
391
|
+
Parsed config/blast-radius.json.
|
|
392
|
+
|
|
393
|
+
.OUTPUTS
|
|
394
|
+
System.Object[]. Matched module names, deduplicated and ordinally sorted.
|
|
395
|
+
#>
|
|
396
|
+
[CmdletBinding()]
|
|
397
|
+
[OutputType([System.Object[]])]
|
|
398
|
+
param(
|
|
399
|
+
[Parameter(Mandatory = $true)]
|
|
400
|
+
[AllowEmptyCollection()]
|
|
401
|
+
[AllowEmptyString()]
|
|
402
|
+
[string[]] $PathEntry,
|
|
403
|
+
[Parameter(Mandatory = $true)]
|
|
404
|
+
[AllowNull()]
|
|
405
|
+
[object] $Config
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
$matched = [System.Collections.Generic.List[string]]::new()
|
|
409
|
+
foreach ($pair in @(Get-ConfigModuleEntry -Config $Config)) {
|
|
410
|
+
foreach ($pattern in $pair['globs']) {
|
|
411
|
+
$hit = $false
|
|
412
|
+
foreach ($entry in $PathEntry) {
|
|
413
|
+
if (Test-GlobMatch -Pattern $pattern -Candidate $entry) {
|
|
414
|
+
$matched.Add([string]$pair['name'])
|
|
415
|
+
$hit = $true
|
|
416
|
+
break
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if ($hit) {
|
|
420
|
+
break
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return @(Get-OrdinalSortedEntry -Entry $matched.ToArray())
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function Resolve-BlastRadiusSharedSurface {
|
|
429
|
+
<#
|
|
430
|
+
.SYNOPSIS
|
|
431
|
+
Select the concrete paths that are shared surfaces.
|
|
432
|
+
|
|
433
|
+
.DESCRIPTION
|
|
434
|
+
Port of resolve_shared_surfaces. Membership has two independent sources,
|
|
435
|
+
the literal truth-table list and the membership globs. A glob hit counts
|
|
436
|
+
even when the path is absent from the literal list, which is the
|
|
437
|
+
fail-closed direction.
|
|
438
|
+
|
|
439
|
+
.PARAMETER ConcretePath
|
|
440
|
+
Wildcard-free paths of a radius or plan. An empty collection is accepted.
|
|
441
|
+
|
|
442
|
+
.PARAMETER Config
|
|
443
|
+
Parsed config/blast-radius.json.
|
|
444
|
+
|
|
445
|
+
.OUTPUTS
|
|
446
|
+
System.Object[]. Touched surfaces, deduplicated and ordinally sorted.
|
|
447
|
+
#>
|
|
448
|
+
[CmdletBinding()]
|
|
449
|
+
[OutputType([System.Object[]])]
|
|
450
|
+
param(
|
|
451
|
+
[Parameter(Mandatory = $true)]
|
|
452
|
+
[AllowEmptyCollection()]
|
|
453
|
+
[AllowEmptyString()]
|
|
454
|
+
[string[]] $ConcretePath,
|
|
455
|
+
[Parameter(Mandatory = $true)]
|
|
456
|
+
[AllowNull()]
|
|
457
|
+
[object] $Config
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
$listed = [System.Collections.Generic.HashSet[string]]::new(
|
|
461
|
+
[string[]]@(Get-ConfigStringList -Config $Config -Key $script:ConfigSharedSurfaceKey),
|
|
462
|
+
[StringComparer]::Ordinal)
|
|
463
|
+
$surfaceGlob = [string[]]@(Get-ConfigStringList -Config $Config -Key $script:ConfigSharedSurfaceGlobKey)
|
|
464
|
+
|
|
465
|
+
$touched = [System.Collections.Generic.List[string]]::new()
|
|
466
|
+
foreach ($path in $ConcretePath) {
|
|
467
|
+
if ($listed.Contains($path)) {
|
|
468
|
+
$touched.Add($path)
|
|
469
|
+
continue
|
|
470
|
+
}
|
|
471
|
+
foreach ($pattern in $surfaceGlob) {
|
|
472
|
+
if (Test-GlobMatch -Pattern $pattern -Candidate $path) {
|
|
473
|
+
$touched.Add($path)
|
|
474
|
+
break
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return @(Get-OrdinalSortedEntry -Entry $touched.ToArray())
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
Export-ModuleMember -Function `
|
|
483
|
+
Get-RequiredText, `
|
|
484
|
+
Get-RequiredStringList, `
|
|
485
|
+
Get-RequiredMapping, `
|
|
486
|
+
Get-ConfigStringList, `
|
|
487
|
+
Get-ConfigRootSurface, `
|
|
488
|
+
Get-ConfigModuleEntry, `
|
|
489
|
+
Get-ConfigOverBreadthFraction, `
|
|
490
|
+
Resolve-BlastRadiusModule, `
|
|
491
|
+
Resolve-BlastRadiusSharedSurface
|