@danmoisan/drm-copilot-mcp 1.1.12 → 1.1.15

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 (38) hide show
  1. package/out/mcp-server.js +30 -78
  2. package/package.json +2 -2
  3. package/resources/claude-customizations/.claude/agents/parallel-planner.md +18 -1
  4. package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +16 -8
  5. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +27 -27
  6. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +43 -6
  7. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusScheduling.psm1 +486 -0
  8. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +5 -2
  9. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusWriteIntent.psm1 +446 -0
  10. package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +330 -0
  11. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +150 -2
  12. package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +5 -5
  13. package/resources/claude-customizations/.claude/rules/shell.md +8 -7
  14. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +8 -8
  15. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +234 -0
  16. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_actions_lib.sh +451 -0
  17. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +301 -0
  18. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_dirt_lib.sh +495 -0
  19. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +252 -0
  20. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_lib.sh +496 -0
  21. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_eol_lib.sh +212 -0
  22. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +492 -0
  23. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_report_records_lib.sh +476 -0
  24. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +182 -0
  25. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +1 -1
  26. package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +11 -0
  27. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +1 -1
  28. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +32 -17
  29. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +39 -10
  30. package/resources/claude-customizations/config/blast-radius.json +14 -1
  31. package/resources/claude-customizations/pack-manifests/core.json +13 -0
  32. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  33. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-resolution.ps1 +493 -0
  34. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +189 -0
  35. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +27 -27
  36. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +14 -27
  37. package/resources/codex-and-agents-customizations/pack-manifests/core.json +2 -0
  38. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +16 -0
@@ -0,0 +1,446 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Write-intent extraction for the blast-radius library (issue #722).
4
+
5
+ .DESCRIPTION
6
+ Destination-runtime PowerShell mirror of
7
+ scripts/dev_tools/_blast_radius_write_intent.py. The rules narrow the text
8
+ harvest of derivation and validation so that only write-intent tokens become
9
+ radius entries, and they are active only when the truth table carries
10
+ write_intent_extraction set to true:
11
+
12
+ - W1 glob mention: a token containing * or ? is dropped.
13
+ - W2 command span: every token of an inline span that splits into more
14
+ than one word is dropped.
15
+ - W3 read task: the tokens of a task attribution window (a task line plus
16
+ the following non-task lines up to the next ATX heading) are dropped
17
+ when the title starts with a read verb, after an optional bold label,
18
+ and carries no write verb anywhere.
19
+ - W4 root anchoring: a concrete token whose first segment, after a
20
+ leading ./ is stripped, is not in path_roots and which is not a
21
+ configured root surface is dropped; an empty path_roots disables W4.
22
+ - W5 spec contracts only: the spec contributes contracts and no paths,
23
+ and contract harvesting applies W1 and W2.
24
+ - W6 placeholder stem: a concrete token whose final-component stem is in
25
+ the placeholder-stem set is dropped.
26
+
27
+ Each exported function names its Python counterpart:
28
+
29
+ - Test-WriteIntentExtractionEnabled config_write_intent_extraction
30
+ - Get-ConfigPathRoot config_path_roots
31
+ - Get-WriteIntentPlanPath extract_write_intent_plan_paths
32
+ - Get-WriteIntentSpecContract extract_write_intent_contracts
33
+ - Select-WriteIntentPathEntry select_write_intent_path_entries
34
+ - Get-PlanPathForConfig select_plan_paths
35
+
36
+ Parity notes for maintainers:
37
+ - The three vocabularies below are pinned equal, member for member and in
38
+ order, to the Python constants READ_VERBS, WRITE_VERBS, and
39
+ PLACEHOLDER_STEMS by a Pester parity test that reads the Python source.
40
+ - With the flag absent or false, Get-PlanPathForConfig returns exactly
41
+ Get-PlanPaths, so every caller behaves as before (fail closed).
42
+ - The rules only drop tokens the current classifier accepts; they never
43
+ add one. Every function is pure: no filesystem, subprocess, network, or
44
+ clock access, and no input is mutated.
45
+ - This module imports the extraction, glob, and config leaves only, never
46
+ the validation module or the facade, so no import cycle can form.
47
+ CONVENTION: this module fails fast at module scope and imports its siblings with -ErrorAction Stop.
48
+ #>
49
+
50
+ Set-StrictMode -Version Latest
51
+ $ErrorActionPreference = 'Stop'
52
+
53
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'BlastRadiusExtraction.psm1') -Force -ErrorAction Stop
54
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'BlastRadiusGlob.psm1') -Force -ErrorAction Stop
55
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'BlastRadiusConfig.psm1') -Force -ErrorAction Stop
56
+
57
+ # Truth-table keys read by this module.
58
+ $script:WriteIntentKey = 'write_intent_extraction'
59
+ $script:PathRootKey = 'path_roots'
60
+
61
+ # The three rule vocabularies, in the same order as the Python constants.
62
+ $script:WriteIntentReadVerb = @('Read', 'Verify', 'Confirm', 'Inspect', 'Review', 'Baseline')
63
+ $script:WriteIntentWriteVerb = @(
64
+ 'Fix', 'Write', 'Update', 'Edit', 'Add', 'Create', 'Delete', 'Remove',
65
+ 'Rename', 'Author', 'Append', 'Replace'
66
+ )
67
+ $script:WriteIntentPlaceholderStem = @(
68
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
69
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
70
+ 'foo', 'bar', 'baz', 'example', 'sample', 'placeholder'
71
+ )
72
+
73
+ # Plan and spec structure patterns, mirroring the extraction module's regexes.
74
+ $script:TaskPattern = [regex]::new('^- \[(?<state>[ xX])\] \[P(?<phase>\d+)-T(?<task>\d+)\] (?<title>.+)$')
75
+ $script:HeadingPattern = [regex]::new('^(?<hashes>#{1,6}) (?<title>.+)$')
76
+ $script:InlineCodeSpanPattern = [regex]::new('`([^`]+)`')
77
+ $script:LineSuffixPattern = [regex]::new(':\d+$')
78
+ $script:ContractLetterPattern = [regex]::new('[A-Za-z]')
79
+ $script:ContractHeadingKeyword = @('API', 'Interface', 'Contract', 'Surface')
80
+
81
+ # W3 title parsing: an optional leading bold label is skipped before the first
82
+ # word is read; write verbs match as whole words anywhere, case-insensitively.
83
+ $script:BoldLabelPattern = [regex]::new('^\*\*[^*]+\*\*\s*')
84
+ $script:FirstWordPattern = [regex]::new('^[A-Za-z]+')
85
+ $script:WriteVerbPattern = [regex]::new(
86
+ '\b(?:' + ($script:WriteIntentWriteVerb -join '|') + ')\b',
87
+ [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
88
+ $script:ReadVerbSet = [System.Collections.Generic.HashSet[string]]::new(
89
+ [string[]]@($script:WriteIntentReadVerb | ForEach-Object { $_.ToLowerInvariant() }),
90
+ [StringComparer]::Ordinal)
91
+ $script:PlaceholderStemSet = [System.Collections.Generic.HashSet[string]]::new(
92
+ [string[]]$script:WriteIntentPlaceholderStem, [StringComparer]::Ordinal)
93
+
94
+
95
+ function Test-WriteIntentExtractionEnabled {
96
+ <#
97
+ .SYNOPSIS
98
+ Read the write_intent_extraction flag strictly.
99
+
100
+ .DESCRIPTION
101
+ Port of config_write_intent_extraction. An absent or null key reads as
102
+ false, which keeps current extraction.
103
+
104
+ .PARAMETER Config
105
+ Parsed config/blast-radius.json.
106
+
107
+ .OUTPUTS
108
+ System.Boolean. The flag value. Throws, naming the key, when the value is
109
+ present and is not a boolean.
110
+ #>
111
+ [CmdletBinding()]
112
+ [OutputType([bool])]
113
+ param(
114
+ [Parameter(Mandatory = $true)]
115
+ [AllowNull()]
116
+ [object] $Config
117
+ )
118
+
119
+ $mapping = Get-RequiredMapping -Value $Config -FieldName 'config'
120
+ if (-not $mapping.ContainsKey($script:WriteIntentKey) -or $null -eq $mapping[$script:WriteIntentKey]) {
121
+ return $false
122
+ }
123
+ $value = $mapping[$script:WriteIntentKey]
124
+ if ($value -isnot [bool]) {
125
+ throw "config[""$($script:WriteIntentKey)""] must be a boolean, got $($value.GetType().Name)."
126
+ }
127
+ return $value
128
+ }
129
+
130
+ function Get-ConfigPathRoot {
131
+ <#
132
+ .SYNOPSIS
133
+ Read the path_roots list strictly.
134
+
135
+ .DESCRIPTION
136
+ Port of config_path_roots. An absent or null key yields an empty list,
137
+ which disables rule W4.
138
+
139
+ .PARAMETER Config
140
+ Parsed config/blast-radius.json.
141
+
142
+ .OUTPUTS
143
+ System.Object[]. First path segments, deduplicated and ordinally sorted.
144
+ Throws, naming the key, when the value is not a list of non-blank
145
+ strings.
146
+ #>
147
+ [CmdletBinding()]
148
+ [OutputType([System.Object[]])]
149
+ param(
150
+ [Parameter(Mandatory = $true)]
151
+ [AllowNull()]
152
+ [object] $Config
153
+ )
154
+
155
+ $mapping = Get-RequiredMapping -Value $Config -FieldName 'config'
156
+ if (-not $mapping.ContainsKey($script:PathRootKey) -or $null -eq $mapping[$script:PathRootKey]) {
157
+ return @()
158
+ }
159
+ return @(Get-RequiredStringList -Value $mapping[$script:PathRootKey] -FieldName "config[""$($script:PathRootKey)""]")
160
+ }
161
+
162
+ # Report whether a task title makes its attribution window a read task (W3).
163
+ function Test-ReadTaskTitle {
164
+ [CmdletBinding()]
165
+ [OutputType([bool])]
166
+ param([Parameter(Mandatory = $true)] [AllowEmptyString()] [string] $Title)
167
+
168
+ $unlabeled = $script:BoldLabelPattern.Replace($Title.Trim(), '', 1)
169
+ $firstWord = $script:FirstWordPattern.Match($unlabeled)
170
+ if (-not $firstWord.Success -or -not $script:ReadVerbSet.Contains($firstWord.Value.ToLowerInvariant())) {
171
+ return $false
172
+ }
173
+ return -not $script:WriteVerbPattern.IsMatch($Title)
174
+ }
175
+
176
+ # Report whether an entry is a feature-folder glob, which is never dropped.
177
+ function Test-FeatureFolderGlob {
178
+ [CmdletBinding()]
179
+ [OutputType([bool])]
180
+ param([Parameter(Mandatory = $true)] [string] $Entry)
181
+
182
+ if (-not ($Entry.StartsWith('docs/features/', [System.StringComparison]::Ordinal) -and
183
+ $Entry.EndsWith('/**', [System.StringComparison]::Ordinal))) {
184
+ return $false
185
+ }
186
+ $body = $Entry.Substring(0, $Entry.Length - 3)
187
+ return ($body.IndexOf('*') -lt 0 -and $body.IndexOf('?') -lt 0)
188
+ }
189
+
190
+ # Apply the token-level rules W1, W4, and W6 to one token; true means it survives.
191
+ function Test-WriteIntentToken {
192
+ [CmdletBinding()]
193
+ [OutputType([bool])]
194
+ param(
195
+ [Parameter(Mandatory = $true)] [string] $Token,
196
+ [AllowEmptyCollection()] [string[]] $RootSurface = @(),
197
+ [AllowEmptyCollection()] [string[]] $PathRoot = @()
198
+ )
199
+
200
+ # W1: a wildcard marks a glob mention rather than a write claim.
201
+ if ($Token.IndexOf('*') -ge 0 -or $Token.IndexOf('?') -ge 0) {
202
+ return $false
203
+ }
204
+
205
+ # W4: enabled only by a non-empty root list; a configured root surface is a
206
+ # repository-root file with no first directory segment to test.
207
+ if ($PathRoot.Count -gt 0 -and $RootSurface -cnotcontains $Token) {
208
+ $stripped = if ($Token.StartsWith('./', [System.StringComparison]::Ordinal)) { $Token.Substring(2) } else { $Token }
209
+ if ($PathRoot -cnotcontains $stripped.Split('/', 2)[0]) {
210
+ return $false
211
+ }
212
+ }
213
+
214
+ # W6: the final component's stem, compared case-insensitively.
215
+ $finalComponent = $script:LineSuffixPattern.Replace($Token.Substring($Token.LastIndexOf('/') + 1), '')
216
+ $stem = if ($finalComponent.Contains('.')) { $finalComponent.Substring(0, $finalComponent.LastIndexOf('.')) } else { $finalComponent }
217
+ return -not $script:PlaceholderStemSet.Contains($stem.ToLowerInvariant())
218
+ }
219
+
220
+ # Yield the token of every inline span that holds exactly one word (W2).
221
+ function Get-SingleWordToken {
222
+ [CmdletBinding()]
223
+ [OutputType([System.Object[]])]
224
+ param([Parameter(Mandatory = $true)] [AllowEmptyString()] [string] $Line)
225
+
226
+ $token = [System.Collections.Generic.List[string]]::new()
227
+ foreach ($match in $script:InlineCodeSpanPattern.Matches($Line)) {
228
+ $word = @($match.Groups[1].Value -split '\s+' | Where-Object { $_.Length -gt 0 })
229
+ if ($word.Count -eq 1) {
230
+ $token.Add($word[0])
231
+ }
232
+ }
233
+ return @($token.ToArray())
234
+ }
235
+
236
+ function Get-WriteIntentPlanPath {
237
+ <#
238
+ .SYNOPSIS
239
+ Extract plan paths under rules W1 through W4 and W6.
240
+
241
+ .DESCRIPTION
242
+ Port of extract_write_intent_plan_paths. A task line opens a window
243
+ whose read status comes from its title; an ATX heading closes any
244
+ window; every other line belongs to the open window. Tokens of a read
245
+ window are dropped (W3); every other line is harvested under W1, W2, W4,
246
+ and W6 after the current classifier accepts the token.
247
+
248
+ .PARAMETER PlanText
249
+ Full atomic-plan document text; may be empty.
250
+
251
+ .PARAMETER RootSurface
252
+ Configured separator-free root surfaces, forwarded to the classifier and
253
+ exempt from W4.
254
+
255
+ .PARAMETER PathRoot
256
+ Configured first segments for W4; empty disables W4.
257
+
258
+ .OUTPUTS
259
+ System.Object[]. Surviving tokens, deduplicated and ordinally sorted.
260
+ #>
261
+ [CmdletBinding()]
262
+ [OutputType([System.Object[]])]
263
+ param(
264
+ [Parameter(Mandatory = $true)]
265
+ [AllowEmptyString()]
266
+ [string] $PlanText,
267
+ [AllowEmptyCollection()] [string[]] $RootSurface = @(),
268
+ [AllowEmptyCollection()] [string[]] $PathRoot = @()
269
+ )
270
+
271
+ $accepted = [System.Collections.Generic.List[string]]::new()
272
+ $inReadWindow = $false
273
+ foreach ($line in @(ConvertTo-NormalizedLine -Text $PlanText)) {
274
+ $taskMatch = $script:TaskPattern.Match($line)
275
+ if ($taskMatch.Success) {
276
+ $inReadWindow = Test-ReadTaskTitle -Title $taskMatch.Groups['title'].Value
277
+ } elseif ($script:HeadingPattern.IsMatch($line)) {
278
+ $inReadWindow = $false
279
+ }
280
+ if ($inReadWindow) {
281
+ continue
282
+ }
283
+
284
+ foreach ($token in @(Get-SingleWordToken -Line $line)) {
285
+ if ($null -ne (Get-PathTokenKind -Token $token -RootSurface $RootSurface) -and
286
+ (Test-WriteIntentToken -Token $token -RootSurface $RootSurface -PathRoot $PathRoot)) {
287
+ $accepted.Add($token)
288
+ }
289
+ }
290
+ }
291
+ return @(Get-OrdinalSortedEntry -Entry $accepted.ToArray())
292
+ }
293
+
294
+ function Get-WriteIntentSpecContract {
295
+ <#
296
+ .SYNOPSIS
297
+ Extract spec contract identifiers with W1 and W2 applied (W5).
298
+
299
+ .DESCRIPTION
300
+ Port of extract_write_intent_contracts. Identifiers are harvested only
301
+ inside a section whose heading, or an ancestor heading, names an API,
302
+ interface, contract, or surface; a multi-word span and a wildcard token
303
+ contribute nothing.
304
+
305
+ .PARAMETER SpecText
306
+ Full feature spec.md document text; may be empty.
307
+
308
+ .OUTPUTS
309
+ System.Object[]. Identifiers carrying an ASCII letter and no separator,
310
+ deduplicated and ordinally sorted.
311
+ #>
312
+ [CmdletBinding()]
313
+ [OutputType([System.Object[]])]
314
+ param(
315
+ [Parameter(Mandatory = $true)]
316
+ [AllowEmptyString()]
317
+ [string] $SpecText
318
+ )
319
+
320
+ $identifier = [System.Collections.Generic.List[string]]::new()
321
+ $qualifyingDepth = 0
322
+ foreach ($line in @(ConvertTo-NormalizedLine -Text $SpecText)) {
323
+ $headingMatch = $script:HeadingPattern.Match($line)
324
+
325
+ # A deeper heading stays inside the qualifying section; a heading at or
326
+ # above that level ends it and is judged on its own title.
327
+ if ($headingMatch.Success) {
328
+ $level = $headingMatch.Groups['hashes'].Value.Length
329
+ if ($qualifyingDepth -ne 0 -and $level -gt $qualifyingDepth) {
330
+ continue
331
+ }
332
+ $title = $headingMatch.Groups['title'].Value
333
+ $qualifyingDepth = 0
334
+ foreach ($keyword in $script:ContractHeadingKeyword) {
335
+ if ($title.IndexOf($keyword, [System.StringComparison]::Ordinal) -ge 0) {
336
+ $qualifyingDepth = $level
337
+ break
338
+ }
339
+ }
340
+ continue
341
+ }
342
+ if ($qualifyingDepth -eq 0) {
343
+ continue
344
+ }
345
+
346
+ foreach ($token in @(Get-SingleWordToken -Line $line)) {
347
+ if ($token.IndexOf('/') -lt 0 -and $token.IndexOf('*') -lt 0 -and
348
+ $token.IndexOf('?') -lt 0 -and $script:ContractLetterPattern.IsMatch($token)) {
349
+ $identifier.Add($token)
350
+ }
351
+ }
352
+ }
353
+ return @(Get-OrdinalSortedEntry -Entry $identifier.ToArray())
354
+ }
355
+
356
+ function Select-WriteIntentPathEntry {
357
+ <#
358
+ .SYNOPSIS
359
+ Apply the token-level rules W1, W4, and W6 to recorded radius entries.
360
+
361
+ .DESCRIPTION
362
+ Port of select_write_intent_path_entries. Normalization calls this
363
+ before the mandate-read filter when the flag is true. The feature-folder
364
+ glob is always kept.
365
+
366
+ .PARAMETER Entry
367
+ Recorded entries already accepted by the current classifier.
368
+
369
+ .PARAMETER RootSurface
370
+ Configured separator-free root surfaces.
371
+
372
+ .PARAMETER PathRoot
373
+ Configured first segments for W4.
374
+
375
+ .OUTPUTS
376
+ System.Object[]. Surviving entries, deduplicated and ordinally sorted.
377
+ #>
378
+ [CmdletBinding()]
379
+ [OutputType([System.Object[]])]
380
+ param(
381
+ [Parameter(Mandatory = $true)]
382
+ [AllowEmptyCollection()]
383
+ [string[]] $Entry,
384
+ [AllowEmptyCollection()] [string[]] $RootSurface = @(),
385
+ [AllowEmptyCollection()] [string[]] $PathRoot = @()
386
+ )
387
+
388
+ $kept = [System.Collections.Generic.List[string]]::new()
389
+ foreach ($item in $Entry) {
390
+ if ((Test-FeatureFolderGlob -Entry $item) -or
391
+ (Test-WriteIntentToken -Token $item -RootSurface $RootSurface -PathRoot $PathRoot)) {
392
+ $kept.Add($item)
393
+ }
394
+ }
395
+ return @(Get-OrdinalSortedEntry -Entry $kept.ToArray())
396
+ }
397
+
398
+ function Get-PlanPathForConfig {
399
+ <#
400
+ .SYNOPSIS
401
+ Select the plan-side extractor from the truth table's flag.
402
+
403
+ .DESCRIPTION
404
+ Port of select_plan_paths, the single selector shared by derivation and
405
+ by validation rules V1 and V2, which keeps a derived radius passing V1
406
+ and V2 against its own plan in both modes.
407
+
408
+ .PARAMETER PlanText
409
+ Full atomic-plan document text; may be empty.
410
+
411
+ .PARAMETER Config
412
+ Parsed config/blast-radius.json.
413
+
414
+ .PARAMETER RootSurface
415
+ Configured separator-free root surfaces.
416
+
417
+ .OUTPUTS
418
+ System.Object[]. The write-intent plan paths when the flag is true, and
419
+ exactly Get-PlanPaths otherwise.
420
+ #>
421
+ [CmdletBinding()]
422
+ [OutputType([System.Object[]])]
423
+ param(
424
+ [Parameter(Mandatory = $true)]
425
+ [AllowEmptyString()]
426
+ [string] $PlanText,
427
+ [Parameter(Mandatory = $true)]
428
+ [AllowNull()]
429
+ [object] $Config,
430
+ [AllowEmptyCollection()] [string[]] $RootSurface = @()
431
+ )
432
+
433
+ if (Test-WriteIntentExtractionEnabled -Config $Config) {
434
+ return @(Get-WriteIntentPlanPath -PlanText $PlanText -RootSurface $RootSurface `
435
+ -PathRoot ([string[]]@(Get-ConfigPathRoot -Config $Config)))
436
+ }
437
+ return @(Get-PlanPaths -PlanText $PlanText -RootSurface $RootSurface)
438
+ }
439
+
440
+ Export-ModuleMember -Function `
441
+ Test-WriteIntentExtractionEnabled, `
442
+ Get-ConfigPathRoot, `
443
+ Get-WriteIntentPlanPath, `
444
+ Get-WriteIntentSpecContract, `
445
+ Select-WriteIntentPathEntry, `
446
+ Get-PlanPathForConfig