@danmoisan/drm-copilot-mcp 1.1.0 → 1.1.2
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 +10 -2
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +349 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +118 -6
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +34 -60
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +187 -0
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +16 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +62 -4
- package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +27 -0
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +28 -0
- package/resources/claude-customizations/config/orchestration-routing.json +1 -1
- package/resources/claude-customizations/pack-manifests/core.json +2 -0
- package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +0 -3
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +0 -3
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +2 -1
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +3 -2
- package/resources/codex-and-agents-customizations/.agents/skills/policy-audit-template-usage/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +0 -4
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/python/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/python-qa-gate/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/python-suppressions/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +4 -3
- package/resources/codex-and-agents-customizations/.agents/skills/self-explanatory-code-commenting/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/tonality/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +3 -3
- package/resources/codex-and-agents-customizations/.agents/skills/translate-copilot-to-claude/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/typescript/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/typescript-suppressions/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +349 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +123 -6
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +1 -0
- package/resources/config/orchestration-routing.json +1 -1
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +17 -1
|
@@ -284,7 +284,7 @@ After reading `artifacts/orchestration/orchestrator-state.json`, the main sessio
|
|
|
284
284
|
- `atomic-executor` — executes approved plans task-by-task
|
|
285
285
|
- `feature-reviewer` — produces policy, code, and feature audit artifacts by
|
|
286
286
|
applying the `feature-review` workflow skill
|
|
287
|
-
- `task-researcher` — performs deep research and writes findings to `
|
|
287
|
+
- `task-researcher` — performs deep research and writes findings to the applicable feature-associated `docs/features/<feature>/research/` or one-off `docs/research/` root
|
|
288
288
|
- `prd-feature` — produces issue, specification, and user-story artifacts when required by the selected workflow
|
|
289
289
|
- `staged-review` — reviews staged changes when a pre-commit review is required
|
|
290
290
|
- `epic-review` — reviews epic-level artifacts when the work item is an epic
|
|
@@ -326,7 +326,6 @@ All evidence artifacts produced during orchestration MUST comply with the canoni
|
|
|
326
326
|
|
|
327
327
|
Permitted `artifacts/`-rooted sub-paths (non-evidence orchestration use only):
|
|
328
328
|
- `artifacts/orchestration/` — orchestrator state and checkpoints
|
|
329
|
-
- `artifacts/research/` — research outputs from task-researcher
|
|
330
329
|
- `artifacts/pr_context` — PR context artifacts
|
|
331
330
|
- `artifacts/reviews/` — review staging artifacts
|
|
332
331
|
- `artifacts/status/` — status update artifacts
|
|
@@ -334,6 +333,8 @@ Permitted `artifacts/`-rooted sub-paths (non-evidence orchestration use only):
|
|
|
334
333
|
- `artifacts/pester/` — Pester coverage outputs
|
|
335
334
|
- `artifacts/csharp/` — C# coverage outputs
|
|
336
335
|
|
|
336
|
+
Research outputs from `task-researcher` are written to `docs/features/<feature>/research/` for feature-associated work or `docs/research/` for one-off work.
|
|
337
|
+
|
|
337
338
|
All other `artifacts/` sub-paths (e.g., `artifacts/baselines/`, `artifacts/qa/`, `artifacts/coverage/`, `artifacts/evidence/`) are FORBIDDEN for evidence output and will be blocked by the `enforce-evidence-locations.ps1` PreToolUse hook.
|
|
338
339
|
|
|
339
340
|
## Completion Requirements
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: policy-audit-template-usage
|
|
3
|
-
description:
|
|
3
|
+
description: Policy audit template usage and output requirements. Use when creating timestamped policy-audit artifacts from the repository templates.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Policy Audit Template Usage
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: powershell-change-budget-router
|
|
3
|
-
description: Budget-first routing contract for PowerShell work: estimate production-file scope, choose small vs large path, enforce direct-mode escalation to orchestrator, and use the VS Code extension command surface for promotion lifecycle steps when available.
|
|
3
|
+
description: 'Budget-first routing contract for PowerShell work: estimate production-file scope, choose small vs large path, enforce direct-mode escalation to orchestrator, and use the VS Code extension command surface for promotion lifecycle steps when available.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# PowerShell Change Budget Router
|
package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: powershell-qa-gate
|
|
3
|
-
description: Final QA gate for PowerShell changes.
|
|
3
|
+
description: Final QA gate for PowerShell changes. Runs PoshQC formatting, analysis, and testing with coverage where enforced; compares a captured baseline, enforces zero-regression deltas, and produces the required reporting block before completion.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# PowerShell QA Gate
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: python-qa-gate
|
|
3
|
-
description: Final QA gate for Python changes.
|
|
3
|
+
description: Final QA gate for Python changes. Runs Black, Ruff, Pyright, and Pytest; compares a captured baseline, enforces zero-regression deltas, and produces the required reporting block before completion.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Python QA Gate
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: research-issue
|
|
3
|
-
description: Investigate the best implementation approach for a feature or bug by analyzing the codebase and external references, then writing structured findings to
|
|
3
|
+
description: Investigate the best implementation approach for a feature or bug by analyzing the codebase and external references, then writing structured findings to the applicable tracked research folder.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Research Issue Skill
|
|
@@ -17,9 +17,10 @@ Accept one or more feature documents as context:
|
|
|
17
17
|
|
|
18
18
|
## Output
|
|
19
19
|
|
|
20
|
-
Create or update a single research file:
|
|
20
|
+
Create or update a single research file in the applicable tracked research root:
|
|
21
21
|
|
|
22
|
-
-
|
|
22
|
+
- Feature-associated path: `docs/features/<feature>/research/<timestamp>-<short-name>-research.md`
|
|
23
|
+
- One-off path: `docs/research/<timestamp>-<short-name>-research.md`
|
|
23
24
|
- Use the Task Researcher template from the repository exactly.
|
|
24
25
|
- Place rejected-alternatives summaries inside `## Recommended Approach`, not as a separate top-level header.
|
|
25
26
|
|
package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: translate-claude-to-codex
|
|
3
|
-
description: Translate the native Claude Code runtime
|
|
3
|
+
description: Translate the native Claude Code runtime, including Claude rules, skills, agents, hooks, and settings, into the native Codex ecosystem. Preserve mechanical enforceability, diff against existing Codex state, produce an approval plan with an enforceability ledger, then apply it.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Translate Claude to Codex
|
|
@@ -21,7 +21,7 @@ Use this skill when:
|
|
|
21
21
|
|
|
22
22
|
## Authoritative Inputs
|
|
23
23
|
|
|
24
|
-
This skill consumes the Codex ecosystem mapping recorded in `
|
|
24
|
+
This skill consumes the Codex ecosystem mapping recorded in `docs/research/20260616-codex-native-ecosystem.2026-06-16T13-32.md`. That artifact is the source of truth for Codex primitive behavior, discovery order, and enforceability. Do not restate Codex documentation from memory; cite the research artifact.
|
|
25
25
|
|
|
26
26
|
Required source paths under `.claude/` (one or more). Accepted types:
|
|
27
27
|
|
|
@@ -172,7 +172,7 @@ Plan structure:
|
|
|
172
172
|
|
|
173
173
|
Generated: <timestamp>
|
|
174
174
|
Mode: <plan-only | apply>
|
|
175
|
-
Research basis:
|
|
175
|
+
Research basis: docs/research/20260616-codex-native-ecosystem.2026-06-16T13-32.md
|
|
176
176
|
|
|
177
177
|
## Inputs
|
|
178
178
|
- <source path 1>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: translate-copilot-to-claude
|
|
3
|
-
description: Translate
|
|
3
|
+
description: Translate GitHub Copilot native files, including instructions, agents, prompts, and skills, into the native Claude runtime. Classify each section, diff against existing Claude state, produce a translation plan for approval, then apply it.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Translate Copilot to Claude
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Pathspec classifier for the orchestration-bookkeeping staging exemption (issue #539).
|
|
4
|
+
.DESCRIPTION
|
|
5
|
+
Pure string logic only: no disk, process, network, or environment access. The single
|
|
6
|
+
entry predicate `Test-ExemptOrchestrationStagingCommand` answers one question - does
|
|
7
|
+
this command text parse, in its entirety, as recognized staging or integration
|
|
8
|
+
invocations whose every pathspec operand resolves inside an orchestration-bookkeeping
|
|
9
|
+
tree? Every parse ambiguity answers false, so the caller's pre-change deny is the
|
|
10
|
+
fallback for every unmodeled form.
|
|
11
|
+
|
|
12
|
+
The normative contract is the D4 fail-closed rule table in
|
|
13
|
+
docs/features/active/2026-08-24-preimplementation-gate-blocks-planner-integration-commits-539/spec.md.
|
|
14
|
+
Rule-table row numbers are cited inline against the code that realizes them.
|
|
15
|
+
|
|
16
|
+
This file is dot-sourced by the sibling gate hook, following the headroom-split
|
|
17
|
+
precedent set by enforce-pr-author-skill.ps1.
|
|
18
|
+
#>
|
|
19
|
+
|
|
20
|
+
# The five exempt orchestration-bookkeeping trees (D2). Directory prefixes, repo-relative,
|
|
21
|
+
# forward-slash spelled. No glob, no absolute entry, no literal-file entry.
|
|
22
|
+
$script:OrchestrationBookkeepingTrees = @(
|
|
23
|
+
'docs/features/epics/'
|
|
24
|
+
'docs/features/parallel/'
|
|
25
|
+
'docs/features/active/'
|
|
26
|
+
'docs/features/potential/'
|
|
27
|
+
'artifacts/orchestration/'
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Characters that make a command line statically unresolvable: shell interpolation and
|
|
31
|
+
# redirection (D4 row 12). Tested across the whole line rather than per operand, because a
|
|
32
|
+
# redirection anywhere in the line moves content the operand list cannot describe.
|
|
33
|
+
$script:UnresolvableCommandCharacters = [char[]]@('$', '`', '>', '<')
|
|
34
|
+
|
|
35
|
+
# Wildcards that make an operand a glob (D4 row 15). Only the literal prefix before the
|
|
36
|
+
# first of these is prefix-tested.
|
|
37
|
+
$script:PathspecWildcardCharacters = [char[]]@('*', '?', '[')
|
|
38
|
+
|
|
39
|
+
function Split-OrchestrationCommandLine {
|
|
40
|
+
<#
|
|
41
|
+
.SYNOPSIS
|
|
42
|
+
Splits a command line into segments on chain operators outside quotes.
|
|
43
|
+
.DESCRIPTION
|
|
44
|
+
Realizes D4 row 13. Quote state is tracked while scanning so a chain operator
|
|
45
|
+
inside a quoted span does not split. The returned `Balanced` flag reports whether
|
|
46
|
+
the scan ended outside every quote; unbalanced text is not splittable and the
|
|
47
|
+
caller denies (D4 rows 11 and 13). Empty and whitespace-only segments are dropped.
|
|
48
|
+
.OUTPUTS
|
|
49
|
+
System.Collections.Hashtable with keys `Balanced` (bool) and `Segments` (string[]).
|
|
50
|
+
#>
|
|
51
|
+
[CmdletBinding()]
|
|
52
|
+
[OutputType([hashtable])]
|
|
53
|
+
param([Parameter(Mandatory)][AllowEmptyString()][string] $CommandText)
|
|
54
|
+
|
|
55
|
+
$segments = [System.Collections.Generic.List[string]]::new()
|
|
56
|
+
$current = [System.Text.StringBuilder]::new()
|
|
57
|
+
$openQuote = [char]0
|
|
58
|
+
|
|
59
|
+
foreach ($character in $CommandText.ToCharArray()) {
|
|
60
|
+
if ($openQuote -ne [char]0) {
|
|
61
|
+
if ($character -eq $openQuote) {
|
|
62
|
+
$openQuote = [char]0
|
|
63
|
+
}
|
|
64
|
+
[void]$current.Append($character)
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if ($character -eq '"' -or $character -eq "'") {
|
|
69
|
+
$openQuote = $character
|
|
70
|
+
[void]$current.Append($character)
|
|
71
|
+
continue
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if ($character -eq ';' -or $character -eq '&' -or $character -eq '|' -or
|
|
75
|
+
$character -eq "`n" -or $character -eq "`r") {
|
|
76
|
+
$segments.Add($current.ToString())
|
|
77
|
+
[void]$current.Clear()
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
[void]$current.Append($character)
|
|
82
|
+
}
|
|
83
|
+
$segments.Add($current.ToString())
|
|
84
|
+
|
|
85
|
+
return @{
|
|
86
|
+
Balanced = ($openQuote -eq [char]0)
|
|
87
|
+
Segments = @($segments | Where-Object { $_.Trim() })
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function ConvertTo-OrchestrationCommandToken {
|
|
92
|
+
<#
|
|
93
|
+
.SYNOPSIS
|
|
94
|
+
Splits one segment into whitespace-delimited tokens with balanced quotes stripped.
|
|
95
|
+
.DESCRIPTION
|
|
96
|
+
Realizes the quote handling of D4 row 11. A quoted span contributes to the token it
|
|
97
|
+
sits in, so `-m "epic scaffold"` yields the two tokens `-m` and `epic scaffold`, and
|
|
98
|
+
a quoted operand arrives at the prefix test unquoted. The caller has already
|
|
99
|
+
rejected unbalanced text, so an unterminated quote simply ends the final token.
|
|
100
|
+
.OUTPUTS
|
|
101
|
+
System.String[]
|
|
102
|
+
#>
|
|
103
|
+
[CmdletBinding()]
|
|
104
|
+
[OutputType([string[]])]
|
|
105
|
+
param([Parameter(Mandatory)][AllowEmptyString()][string] $Segment)
|
|
106
|
+
|
|
107
|
+
$tokens = [System.Collections.Generic.List[string]]::new()
|
|
108
|
+
$current = [System.Text.StringBuilder]::new()
|
|
109
|
+
$hasToken = $false
|
|
110
|
+
$openQuote = [char]0
|
|
111
|
+
|
|
112
|
+
foreach ($character in $Segment.ToCharArray()) {
|
|
113
|
+
if ($openQuote -ne [char]0) {
|
|
114
|
+
if ($character -eq $openQuote) {
|
|
115
|
+
$openQuote = [char]0
|
|
116
|
+
} else {
|
|
117
|
+
[void]$current.Append($character)
|
|
118
|
+
}
|
|
119
|
+
continue
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if ($character -eq '"' -or $character -eq "'") {
|
|
123
|
+
$openQuote = $character
|
|
124
|
+
$hasToken = $true
|
|
125
|
+
continue
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if ([char]::IsWhiteSpace($character)) {
|
|
129
|
+
if ($hasToken) {
|
|
130
|
+
$tokens.Add($current.ToString())
|
|
131
|
+
[void]$current.Clear()
|
|
132
|
+
$hasToken = $false
|
|
133
|
+
}
|
|
134
|
+
continue
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
$hasToken = $true
|
|
138
|
+
[void]$current.Append($character)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if ($hasToken) {
|
|
142
|
+
$tokens.Add($current.ToString())
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return $tokens.ToArray()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function Test-ExemptOrchestrationOperand {
|
|
149
|
+
<#
|
|
150
|
+
.SYNOPSIS
|
|
151
|
+
Tests one pathspec operand against the five exempt orchestration trees.
|
|
152
|
+
.DESCRIPTION
|
|
153
|
+
Realizes D4 rows 3, 9, 15, 16, 17, and 18. Backslashes normalize to forward slashes
|
|
154
|
+
before the prefix test (row 18); pathspec magic, absolute spellings, parent-directory
|
|
155
|
+
segments, and globs whose literal prefix escapes the exempt set all deny.
|
|
156
|
+
.OUTPUTS
|
|
157
|
+
System.Boolean
|
|
158
|
+
#>
|
|
159
|
+
[CmdletBinding()]
|
|
160
|
+
[OutputType([bool])]
|
|
161
|
+
param([Parameter(Mandatory)][AllowEmptyString()][string] $Operand)
|
|
162
|
+
|
|
163
|
+
if (-not $Operand) {
|
|
164
|
+
return $false
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
# Row 3b and row 9: any leading colon is pathspec magic, which can escape or invert the
|
|
168
|
+
# tree scope, so no colon-led operand is ever resolvable by a prefix test.
|
|
169
|
+
if ($Operand.StartsWith(':')) {
|
|
170
|
+
return $false
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# Row 18: separator normalization precedes every prefix comparison below.
|
|
174
|
+
$normalized = $Operand -replace '\\', '/'
|
|
175
|
+
|
|
176
|
+
# Row 16: rooted, drive-lettered, and UNC spellings all deny; the exempt prefixes stay
|
|
177
|
+
# repo-relative (this is the posture issue #516 later composes with).
|
|
178
|
+
if ($normalized.StartsWith('/')) {
|
|
179
|
+
return $false
|
|
180
|
+
}
|
|
181
|
+
if ($normalized -match '^[A-Za-z]:') {
|
|
182
|
+
return $false
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
# Rows 15c and 17: any parent-directory component escapes the prefix.
|
|
186
|
+
if (($normalized -split '/') -contains '..') {
|
|
187
|
+
return $false
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# Row 15: only the literal prefix before the first wildcard is prefix-tested, so a glob
|
|
191
|
+
# whose wildcard occupies or truncates an ancestor segment cannot pass.
|
|
192
|
+
$literalPrefix = $normalized
|
|
193
|
+
$wildcardIndex = $normalized.IndexOfAny($script:PathspecWildcardCharacters)
|
|
194
|
+
if ($wildcardIndex -ge 0) {
|
|
195
|
+
$literalPrefix = $normalized.Substring(0, $wildcardIndex)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
foreach ($tree in $script:OrchestrationBookkeepingTrees) {
|
|
199
|
+
if ($literalPrefix.StartsWith($tree)) {
|
|
200
|
+
return $true
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return $false
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function Test-ExemptOrchestrationSegmentToken {
|
|
207
|
+
<#
|
|
208
|
+
.SYNOPSIS
|
|
209
|
+
Tests one already-tokenized segment as a recognized all-exempt invocation.
|
|
210
|
+
.DESCRIPTION
|
|
211
|
+
Realizes D4 rows 1, 2, 4, 5, 6, 7, 8, 10, 14, and 19. The command name must lead the
|
|
212
|
+
segment and the subcommand must follow it immediately (row 14), the option table is
|
|
213
|
+
modelled positively so any unmodelled dash-leading token denies (rows 2, 5, 6, 8, 10),
|
|
214
|
+
tokens after the double-dash separator are pathspecs (row 7), at least one operand is
|
|
215
|
+
required (rows 1, 4, 7), and every operand must pass (row 19).
|
|
216
|
+
.OUTPUTS
|
|
217
|
+
System.Boolean
|
|
218
|
+
#>
|
|
219
|
+
[CmdletBinding()]
|
|
220
|
+
[OutputType([bool])]
|
|
221
|
+
param([Parameter(Mandatory)][AllowEmptyCollection()][string[]] $Token)
|
|
222
|
+
|
|
223
|
+
if ($Token.Count -lt 2) {
|
|
224
|
+
return $false
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
# Row 14: the command name leads and the subcommand follows immediately. Anything in
|
|
228
|
+
# between - a relocating option or an env-style prefix - moves the pathspec base and is
|
|
229
|
+
# rejected here rather than modelled.
|
|
230
|
+
if ($Token[0] -cne 'git') {
|
|
231
|
+
return $false
|
|
232
|
+
}
|
|
233
|
+
$subcommand = $Token[1]
|
|
234
|
+
if ($subcommand -cne 'add' -and $subcommand -cne 'commit') {
|
|
235
|
+
return $false
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
$operands = [System.Collections.Generic.List[string]]::new()
|
|
239
|
+
$afterSeparator = $false
|
|
240
|
+
$index = 2
|
|
241
|
+
|
|
242
|
+
while ($index -lt $Token.Count) {
|
|
243
|
+
$candidate = $Token[$index]
|
|
244
|
+
|
|
245
|
+
if (-not $afterSeparator) {
|
|
246
|
+
if ($candidate -ceq '--') {
|
|
247
|
+
# Row 7: every remaining token is a pathspec, dash-leading or not.
|
|
248
|
+
$afterSeparator = $true
|
|
249
|
+
$index++
|
|
250
|
+
continue
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if ($candidate.StartsWith('-')) {
|
|
254
|
+
# The message option is the only modelled option on either subcommand. Rows
|
|
255
|
+
# 2, 5, 6, 8, and 10 all land here and deny, including a dash-leading
|
|
256
|
+
# operand supplied without a preceding separator.
|
|
257
|
+
if ($subcommand -cne 'commit') {
|
|
258
|
+
return $false
|
|
259
|
+
}
|
|
260
|
+
if ($candidate -ceq '-m' -or $candidate -ceq '--message') {
|
|
261
|
+
# The message value is the following token and is not a pathspec.
|
|
262
|
+
$index += 2
|
|
263
|
+
if ($index -gt $Token.Count) {
|
|
264
|
+
return $false
|
|
265
|
+
}
|
|
266
|
+
continue
|
|
267
|
+
}
|
|
268
|
+
if ($candidate.StartsWith('--message=') -or
|
|
269
|
+
($candidate.Length -gt 2 -and $candidate.StartsWith('-m'))) {
|
|
270
|
+
$index++
|
|
271
|
+
continue
|
|
272
|
+
}
|
|
273
|
+
return $false
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
$operands.Add($candidate)
|
|
278
|
+
$index++
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
# Rows 1, 4, and 7: an invocation with no pathspec operand claims no path, so there is
|
|
282
|
+
# nothing for the prefix test to scope and the exemption is not available.
|
|
283
|
+
if ($operands.Count -eq 0) {
|
|
284
|
+
return $false
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
# Row 19: all-operands-exempt is the invariant; one non-exempt operand denies the set.
|
|
288
|
+
foreach ($operand in $operands) {
|
|
289
|
+
if (-not (Test-ExemptOrchestrationOperand -Operand $operand)) {
|
|
290
|
+
return $false
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return $true
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function Test-ExemptOrchestrationStagingCommand {
|
|
297
|
+
<#
|
|
298
|
+
.SYNOPSIS
|
|
299
|
+
Reports whether a command line is an orchestration-bookkeeping staging invocation.
|
|
300
|
+
.DESCRIPTION
|
|
301
|
+
The entry predicate of the issue #539 exemption. Returns true only when the whole
|
|
302
|
+
command line splits cleanly into segments and EVERY segment parses as a complete,
|
|
303
|
+
recognized staging or integration invocation carrying at least one pathspec operand,
|
|
304
|
+
with every operand resolving inside one of the five exempt orchestration-bookkeeping
|
|
305
|
+
trees after balanced-quote stripping and separator normalization.
|
|
306
|
+
|
|
307
|
+
The all-segments reading is deliberate and fail-closed: a chained line denies unless
|
|
308
|
+
each of its segments is independently a recognized all-exempt invocation, so a
|
|
309
|
+
relocating spelling or a prose fragment anywhere in the line withholds the exemption
|
|
310
|
+
even when another segment on the same line would have qualified on its own.
|
|
311
|
+
|
|
312
|
+
Consumed allow-side only. A false result restores the caller's unchanged
|
|
313
|
+
classification; it never suppresses the trigger.
|
|
314
|
+
.OUTPUTS
|
|
315
|
+
System.Boolean
|
|
316
|
+
#>
|
|
317
|
+
[CmdletBinding()]
|
|
318
|
+
[OutputType([bool])]
|
|
319
|
+
param([Parameter(Mandatory)][AllowEmptyString()][string] $CommandText)
|
|
320
|
+
|
|
321
|
+
if (-not $CommandText) {
|
|
322
|
+
return $false
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
# Row 12: interpolation and redirection are not statically resolvable, so the operand
|
|
326
|
+
# list cannot be trusted to describe what the line actually touches.
|
|
327
|
+
if ($CommandText.IndexOfAny($script:UnresolvableCommandCharacters) -ge 0) {
|
|
328
|
+
return $false
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
$split = Split-OrchestrationCommandLine -CommandText $CommandText
|
|
332
|
+
if (-not $split.Balanced) {
|
|
333
|
+
# Rows 11 and 13: unbalanced quoting makes the segment boundaries ambiguous.
|
|
334
|
+
return $false
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
$segments = @($split.Segments)
|
|
338
|
+
if ($segments.Count -eq 0) {
|
|
339
|
+
return $false
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
foreach ($segment in $segments) {
|
|
343
|
+
$tokens = @(ConvertTo-OrchestrationCommandToken -Segment $segment)
|
|
344
|
+
if (-not (Test-ExemptOrchestrationSegmentToken -Token $tokens)) {
|
|
345
|
+
return $false
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return $true
|
|
349
|
+
}
|