@danmoisan/drm-copilot-mcp 1.1.10 → 1.1.12
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 +3517 -1104
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +1 -1
- package/resources/claude-customizations/.claude/agents/epic-planner.md +4 -1
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +15 -2
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +3 -0
- package/resources/claude-customizations/.claude/agents/pr-author.md +15 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-authorization.ps1 +443 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +82 -51
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +52 -3
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +120 -5
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +127 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +163 -15
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +21 -28
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +103 -6
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +124 -8
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +171 -15
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1 +50 -10
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +3 -1
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1 +332 -0
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +211 -182
- package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +35 -7
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation.ps1 +483 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-scanner.ps1 +483 -0
- package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +218 -6
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +18 -75
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConflict.psm1 +290 -0
- package/resources/claude-customizations/.claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1 +415 -0
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +1 -0
- package/resources/claude-customizations/.claude/lib/project-file-merge/ProjectFileMerge.psm1 +355 -0
- package/resources/claude-customizations/.claude/lib/project-file-merge/ProjectFileMergeGrammar.psm1 +318 -0
- package/resources/claude-customizations/.claude/lib/project-file-merge/Resolve-MergeableConflict.ps1 +229 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/EpicScopeReadiness.psm1 +176 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/EpicScopeResolution.psm1 +369 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +392 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeResolution.psm1 +500 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeTargetResolution.psm1 +347 -0
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +27 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +66 -2
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +323 -16
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +14 -1
- package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +4 -0
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +46 -1
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +75 -8
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +6 -0
- package/resources/claude-customizations/.claude/skills/powershell-orchestration-state-machine/SKILL.md +29 -1
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +15 -0
- package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +221 -0
- package/resources/claude-customizations/config/blast-radius.json +7 -0
- package/resources/claude-customizations/pack-manifests/core.json +16 -0
- package/resources/codex-and-agents-customizations/.agents/skills/codex-model-routing/SKILL.md +13 -14
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +41 -0
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +41 -0
- package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +26 -0
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +242 -3
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +67 -12
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +34 -8
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +163 -15
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +6 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +34 -7
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +483 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +483 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +130 -2
- package/resources/codex-and-agents-customizations/.codex/scripts/Resolve-CodexDeployment.ps1 +87 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/Resolve-CodexTopology.ps1 +96 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/codex-routing-cli-common.ps1 +370 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/epic-child-launch-contract.ps1 +475 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/epic-child-launch-runtime.ps1 +445 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/epic-child-persistence-runtime.ps1 +118 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/epic-child-sandbox-preflight.ps1 +69 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/launch-epic-child-wave.ps1 +471 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/post-codex-worktree-session.ps1 +280 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/resume-epic-child.ps1 +263 -0
- package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +2 -1
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +23 -1
- package/resources/config/orchestration-handoff-registry.json +138 -0
- package/resources/config/orchestration-handoff.schema.json +472 -0
- package/resources/lib/codex-routing/CodexDeployment.psm1 +315 -0
- package/resources/lib/codex-routing/CodexTopology.psm1 +394 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +64 -0
package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Prompt-side feature-folder resolution for the prd-feature gate (issue #672).
|
|
4
|
+
.DESCRIPTION
|
|
5
|
+
This file is dot-sourced by its parent hook enforce-prd-feature-before-planner.ps1,
|
|
6
|
+
following the headroom-split precedent set by
|
|
7
|
+
enforce-orchestration-preimplementation-gate-helpers.ps1. The parent keeps the
|
|
8
|
+
decision entrypoint and the seams the existing suites mock; this file carries the
|
|
9
|
+
resolution and prerequisite-mapping logic, so neither file approaches the 500-line
|
|
10
|
+
cap as target resolution grows.
|
|
11
|
+
|
|
12
|
+
The file declares no file-scope parameter block, no requires directive, and no
|
|
13
|
+
entrypoint. Apart from its function declarations,
|
|
14
|
+
its only file-scope statement is the resolution-module import
|
|
15
|
+
that follows this block, which brings in issue #669's path normalisation and
|
|
16
|
+
ambiguity reason code. That import is deliberately unguarded, for the same
|
|
17
|
+
reason the parent hook's is: a resolution module that cannot be loaded is
|
|
18
|
+
itself the target-not-resolvable state, so letting the failure surface fails
|
|
19
|
+
the gate closed rather than degrading it to a permissive path.
|
|
20
|
+
.NOTES
|
|
21
|
+
Compatible with PowerShell 7+. Read-only resolution logic.
|
|
22
|
+
#>
|
|
23
|
+
|
|
24
|
+
# Issue #669 owns path normalisation and the ambiguity reason code. The import is
|
|
25
|
+
# unguarded for the same reason the parent's is: a resolution module that cannot be
|
|
26
|
+
# loaded is itself the target-not-resolvable state.
|
|
27
|
+
Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeResolution.psm1') -Force
|
|
28
|
+
|
|
29
|
+
function Resolve-PrdFeatureWorkMode {
|
|
30
|
+
<#
|
|
31
|
+
.SYNOPSIS
|
|
32
|
+
Parses the persisted `- Work Mode: ...` marker out of issue.md content
|
|
33
|
+
and returns the canonical mode, or $null when the marker is absent,
|
|
34
|
+
unreadable, or unrecognized.
|
|
35
|
+
.DESCRIPTION
|
|
36
|
+
Recognizes minor-audit, full-feature, full-bug, and the legacy full
|
|
37
|
+
marker (normalized to full-feature), mirroring the regex convention
|
|
38
|
+
used by scripts/dev_tools/prompt_mode_contract.py so both runtimes
|
|
39
|
+
agree on what counts as a valid marker line.
|
|
40
|
+
#>
|
|
41
|
+
[CmdletBinding()]
|
|
42
|
+
[OutputType([string])]
|
|
43
|
+
param(
|
|
44
|
+
[AllowNull()]
|
|
45
|
+
[string] $IssueContent
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if ([string]::IsNullOrWhiteSpace($IssueContent)) {
|
|
49
|
+
return $null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
$match = [regex]::Match($IssueContent, '(?im)^-\s*Work Mode:\s*(minor-audit|full-feature|full-bug|full)\s*$')
|
|
53
|
+
if (-not $match.Success) {
|
|
54
|
+
return $null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
$rawMode = $match.Groups[1].Value
|
|
58
|
+
if ($rawMode -eq 'full') {
|
|
59
|
+
return 'full-feature'
|
|
60
|
+
}
|
|
61
|
+
return $rawMode
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function Get-PrdFeatureRequiredFile {
|
|
65
|
+
<#
|
|
66
|
+
.SYNOPSIS
|
|
67
|
+
Maps a resolved work mode to the set of prd-feature output files the
|
|
68
|
+
target folder must contain before an atomic-planner delegation is
|
|
69
|
+
allowed.
|
|
70
|
+
.DESCRIPTION
|
|
71
|
+
full-feature requires spec.md and user-story.md; full-bug requires
|
|
72
|
+
spec.md only; minor-audit requires neither.
|
|
73
|
+
|
|
74
|
+
The default arm returns spec.md alone. It is not reached from the
|
|
75
|
+
decision path for an undeterminable mode, which denies on its own branch
|
|
76
|
+
without probing at all; the arm exists so a direct caller passing a $null
|
|
77
|
+
or unrecognized mode never receives a permissive empty set, and it must
|
|
78
|
+
not name user-story.md, because that document is required to be ABSENT
|
|
79
|
+
for full-bug and minor-audit work.
|
|
80
|
+
#>
|
|
81
|
+
[CmdletBinding()]
|
|
82
|
+
[OutputType([string[]])]
|
|
83
|
+
param(
|
|
84
|
+
[AllowNull()]
|
|
85
|
+
[string] $WorkMode
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Route on the canonical mode; anything outside the three known values
|
|
89
|
+
# (including $null) falls through to the fail-closed default case.
|
|
90
|
+
switch ($WorkMode) {
|
|
91
|
+
'full-feature' { return [string[]]@('spec.md', 'user-story.md') }
|
|
92
|
+
'full-bug' { return [string[]]@('spec.md') }
|
|
93
|
+
'minor-audit' { return [string[]]@() }
|
|
94
|
+
default { return [string[]]@('spec.md') }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function ConvertTo-PrdFeatureFolderToken {
|
|
99
|
+
<#
|
|
100
|
+
.SYNOPSIS
|
|
101
|
+
Reduces one cited path token to its four-segment repo-relative feature
|
|
102
|
+
folder, or $null when the token does not name one.
|
|
103
|
+
.DESCRIPTION
|
|
104
|
+
The prefix half is issue #669's path normalisation, not a local
|
|
105
|
+
re-implementation: ConvertTo-WorktreeResolutionRepoRelativePath places an
|
|
106
|
+
absolute token by locating its containing worktree and returns the full
|
|
107
|
+
remainder below that root, so no segment is dropped and no prefix is
|
|
108
|
+
discarded by pattern shape. A token that does not normalise is already
|
|
109
|
+
repo-relative (or names no worktree), and the repo-relative remainder is
|
|
110
|
+
then read from the token itself.
|
|
111
|
+
|
|
112
|
+
The depth-collapsing half below is carried byte-unmodified from the fix
|
|
113
|
+
for issue #518. It is depth normalisation, not the segment-count
|
|
114
|
+
truncation the epic prohibits: it maps a folder path, a spec.md path, a
|
|
115
|
+
research/ artifact path, and an evidence/ artifact path onto the same
|
|
116
|
+
folder.
|
|
117
|
+
#>
|
|
118
|
+
[CmdletBinding()]
|
|
119
|
+
[OutputType([string])]
|
|
120
|
+
param(
|
|
121
|
+
[Parameter(Mandatory)]
|
|
122
|
+
[AllowEmptyString()]
|
|
123
|
+
[string] $Path
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
if (-not $Path) {
|
|
127
|
+
return $null
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
$placed = ConvertTo-WorktreeResolutionRepoRelativePath -Path $Path
|
|
131
|
+
$normalized = if ($placed.IsNormalized) {
|
|
132
|
+
$placed.RepoRelativePath
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
($Path -replace '\\', '/')
|
|
136
|
+
}
|
|
137
|
+
$normalized = $normalized.TrimEnd('/')
|
|
138
|
+
|
|
139
|
+
# Read the feature-folder remainder from wherever it starts in the normalised
|
|
140
|
+
# token. A normalised token starts at it already; a token that named no
|
|
141
|
+
# worktree keeps whatever prefix it was cited with.
|
|
142
|
+
$start = $normalized.IndexOf('docs/features/active/')
|
|
143
|
+
if ($start -lt 0) {
|
|
144
|
+
return $null
|
|
145
|
+
}
|
|
146
|
+
$normalized = $normalized.Substring($start)
|
|
147
|
+
|
|
148
|
+
# Truncate to exactly two segments past the docs/features/active/ prefix,
|
|
149
|
+
# that is, to the four segments docs, features, active, and the feature
|
|
150
|
+
# folder name. Truncation is depth-insensitive, so a folder path, a
|
|
151
|
+
# spec.md path, a research/ artifact path, and an evidence/ artifact path
|
|
152
|
+
# all reduce to the same value. A '.' component is a path no-op and is
|
|
153
|
+
# discarded first, so a degenerate token such as docs/features/active/.
|
|
154
|
+
# yields three segments and is rejected rather than resolved.
|
|
155
|
+
$segments = @($normalized -split '/' | Where-Object { $_ -ne '' -and $_ -ne '.' })
|
|
156
|
+
if ($segments.Count -lt 4) {
|
|
157
|
+
return $null
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return ($segments[0..3] -join '/')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function Find-PrdFeatureFolderCandidate {
|
|
164
|
+
<#
|
|
165
|
+
.SYNOPSIS
|
|
166
|
+
Returns the distinct feature folders a prompt cites, in first-occurrence
|
|
167
|
+
order.
|
|
168
|
+
.DESCRIPTION
|
|
169
|
+
The scan pattern keeps any prefix the token was cited with, so an absolute
|
|
170
|
+
citation reaches the normalisation in ConvertTo-PrdFeatureFolderToken
|
|
171
|
+
rather than being discarded by the pattern itself.
|
|
172
|
+
#>
|
|
173
|
+
[CmdletBinding()]
|
|
174
|
+
[OutputType([string[]])]
|
|
175
|
+
param(
|
|
176
|
+
[Parameter(Mandatory)]
|
|
177
|
+
[AllowEmptyString()]
|
|
178
|
+
[string] $Prompt
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
if (-not $Prompt) {
|
|
182
|
+
return [string[]]@()
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
# Allow forward or backslash separators inside the matched path token, and
|
|
186
|
+
# keep any prefix the token carries.
|
|
187
|
+
$pattern = '(?:[^\s"''`]*[\\/])?docs[\\/]+features[\\/]+active[\\/]+[^\s"''`]+'
|
|
188
|
+
$matchList = [regex]::Matches($Prompt, $pattern)
|
|
189
|
+
if ($matchList.Count -eq 0) {
|
|
190
|
+
return [string[]]@()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# Deduplicate preserving FIRST-OCCURRENCE order. A [hashtable] must not be
|
|
194
|
+
# used here: PowerShell hashtable key enumeration order is unspecified, so a
|
|
195
|
+
# first-occurrence selection rule fed by a hashtable is not deterministic.
|
|
196
|
+
[System.Collections.Generic.List[string]] $candidates = [System.Collections.Generic.List[string]]::new()
|
|
197
|
+
foreach ($m in $matchList) {
|
|
198
|
+
$truncated = ConvertTo-PrdFeatureFolderToken -Path $m.Value
|
|
199
|
+
if (-not $truncated) {
|
|
200
|
+
continue
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (-not $candidates.Contains($truncated)) {
|
|
204
|
+
$candidates.Add($truncated)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return [string[]] $candidates.ToArray()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function Select-PrdFeatureFolderByCheckpoint {
|
|
212
|
+
<#
|
|
213
|
+
.SYNOPSIS
|
|
214
|
+
Returns the candidate the resolved worktree's checkpoint names, or $null when
|
|
215
|
+
the checkpoint names none of them.
|
|
216
|
+
.DESCRIPTION
|
|
217
|
+
The disambiguator is the orchestrator checkpoint of the worktree identity
|
|
218
|
+
resolution selected, which is the item's own. Neither prompt position nor a
|
|
219
|
+
foreign session's record takes that role: position would make selection an
|
|
220
|
+
accident of wording, and a checkpoint belonging to some other session would
|
|
221
|
+
choose between two cited folders on the strength of that session's record of
|
|
222
|
+
its own unrelated work.
|
|
223
|
+
|
|
224
|
+
Before issue #673 this function read a signal value off a call target the gate
|
|
225
|
+
had derived from a path token. That is gone: a path no longer selects a
|
|
226
|
+
worktree, so there is no derived signal to read.
|
|
227
|
+
.PARAMETER Candidate
|
|
228
|
+
The distinct feature folders cited in the prompt.
|
|
229
|
+
.PARAMETER CheckpointFolder
|
|
230
|
+
The feature-folder value read from the resolved worktree's checkpoint.
|
|
231
|
+
#>
|
|
232
|
+
[CmdletBinding()]
|
|
233
|
+
[OutputType([string])]
|
|
234
|
+
param(
|
|
235
|
+
[Parameter(Mandatory)]
|
|
236
|
+
[AllowEmptyCollection()]
|
|
237
|
+
[string[]] $Candidate,
|
|
238
|
+
|
|
239
|
+
[AllowNull()]
|
|
240
|
+
[string] $CheckpointFolder
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
$folder = ConvertTo-PrdFeatureFolderToken -Path $CheckpointFolder
|
|
244
|
+
if ($folder -and ($Candidate -contains $folder)) {
|
|
245
|
+
return $folder
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return $null
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function Find-PrdFeatureFolderFromPrompt {
|
|
252
|
+
<#
|
|
253
|
+
.SYNOPSIS
|
|
254
|
+
Scans a prompt string for docs/features/active/<...> path tokens,
|
|
255
|
+
truncates each to exactly four path segments, and returns the selected
|
|
256
|
+
feature folder. Returns $null when no token truncates to four segments
|
|
257
|
+
and when a multi-candidate tie cannot be resolved against the resolved
|
|
258
|
+
worktree's checkpoint.
|
|
259
|
+
.DESCRIPTION
|
|
260
|
+
Truncation to four segments -- docs, features, active, and the
|
|
261
|
+
feature-folder name -- is two segments past the docs/features/active/
|
|
262
|
+
prefix, so the depth at which an artifact is cited cannot change which
|
|
263
|
+
folder is resolved. Candidates are deduplicated preserving
|
|
264
|
+
first-occurrence order; selection among two or more distinct candidates
|
|
265
|
+
is made against the checkpoint of the worktree identity resolution
|
|
266
|
+
selected, which is the item's own, and an unresolved tie returns $null so
|
|
267
|
+
the caller can deny with the ambiguity code rather than guess.
|
|
268
|
+
|
|
269
|
+
The return value is a repo-relative path normalized to forward slashes,
|
|
270
|
+
or $null. The function reads no file except through issue #669's
|
|
271
|
+
normalisation, and it is deterministic for a given prompt and checkpoint
|
|
272
|
+
value.
|
|
273
|
+
.PARAMETER Prompt
|
|
274
|
+
The delegation prompt to scan.
|
|
275
|
+
.PARAMETER CheckpointFolder
|
|
276
|
+
Optional. The feature-folder value read from the resolved worktree's
|
|
277
|
+
checkpoint, used only to break a multi-candidate tie.
|
|
278
|
+
#>
|
|
279
|
+
[CmdletBinding()]
|
|
280
|
+
[OutputType([string])]
|
|
281
|
+
param(
|
|
282
|
+
[Parameter(Mandatory)]
|
|
283
|
+
[AllowEmptyString()]
|
|
284
|
+
[string] $Prompt,
|
|
285
|
+
|
|
286
|
+
[AllowNull()]
|
|
287
|
+
[string] $CheckpointFolder
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
$candidates = @(Find-PrdFeatureFolderCandidate -Prompt $Prompt)
|
|
291
|
+
if ($candidates.Count -eq 0) {
|
|
292
|
+
return $null
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
# One distinct candidate is used directly, so the common case never consults
|
|
296
|
+
# the checkpoint at all.
|
|
297
|
+
if ($candidates.Count -eq 1) {
|
|
298
|
+
return $candidates[0]
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
# More than one distinct feature folder was cited. The resolved worktree's own
|
|
302
|
+
# checkpoint is the only disambiguator; an unresolved tie is ambiguous and is
|
|
303
|
+
# reported as such by returning $null, rather than resolved positionally.
|
|
304
|
+
return (Select-PrdFeatureFolderByCheckpoint -Candidate $candidates -CheckpointFolder $CheckpointFolder)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function Get-PrdFeatureMissingFile {
|
|
308
|
+
<#
|
|
309
|
+
.SYNOPSIS
|
|
310
|
+
Returns the subset of $RequiredFile that is missing from the target
|
|
311
|
+
folder.
|
|
312
|
+
#>
|
|
313
|
+
[CmdletBinding()]
|
|
314
|
+
[OutputType([string[]])]
|
|
315
|
+
param(
|
|
316
|
+
[Parameter(Mandatory)]
|
|
317
|
+
[string] $FeatureFolder,
|
|
318
|
+
|
|
319
|
+
[Parameter(Mandatory)]
|
|
320
|
+
[AllowEmptyCollection()]
|
|
321
|
+
[string[]] $RequiredFile
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
[System.Collections.Generic.List[string]] $missing = [System.Collections.Generic.List[string]]::new()
|
|
325
|
+
foreach ($name in $RequiredFile) {
|
|
326
|
+
$candidate = "$FeatureFolder/$name"
|
|
327
|
+
if (-not (Get-PrdFeatureFileExistence -Path $candidate)) {
|
|
328
|
+
$missing.Add($name)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return [string[]] $missing.ToArray()
|
|
332
|
+
}
|