@danmoisan/drm-copilot-mcp 1.1.11 → 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.
Files changed (52) hide show
  1. package/out/mcp-server.js +366 -159
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +1 -1
  4. package/resources/claude-customizations/.claude/agents/epic-planner.md +4 -1
  5. package/resources/claude-customizations/.claude/agents/pr-author.md +15 -0
  6. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-authorization.ps1 +443 -0
  7. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +33 -37
  8. package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +120 -5
  9. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +127 -0
  10. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +163 -15
  11. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +14 -27
  12. package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +66 -5
  13. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +134 -10
  14. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1 +37 -8
  15. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +3 -1
  16. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1 +332 -0
  17. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +211 -182
  18. package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +1 -0
  19. package/resources/claude-customizations/.claude/lib/worktree-resolution/EpicScopeReadiness.psm1 +176 -0
  20. package/resources/claude-customizations/.claude/lib/worktree-resolution/EpicScopeResolution.psm1 +369 -0
  21. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +392 -0
  22. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeResolution.psm1 +500 -0
  23. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeTargetResolution.psm1 +347 -0
  24. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +27 -0
  25. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +12 -0
  26. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +14 -1
  27. package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +4 -0
  28. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +4 -1
  29. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +39 -6
  30. package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +15 -0
  31. package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +221 -0
  32. package/resources/claude-customizations/pack-manifests/core.json +9 -0
  33. package/resources/codex-and-agents-customizations/.agents/skills/codex-model-routing/SKILL.md +13 -14
  34. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  35. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +193 -0
  36. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +15 -5
  37. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +163 -15
  38. package/resources/codex-and-agents-customizations/.codex/scripts/Resolve-CodexDeployment.ps1 +87 -0
  39. package/resources/codex-and-agents-customizations/.codex/scripts/Resolve-CodexTopology.ps1 +96 -0
  40. package/resources/codex-and-agents-customizations/.codex/scripts/codex-routing-cli-common.ps1 +370 -0
  41. package/resources/codex-and-agents-customizations/.codex/scripts/epic-child-launch-contract.ps1 +475 -0
  42. package/resources/codex-and-agents-customizations/.codex/scripts/epic-child-launch-runtime.ps1 +445 -0
  43. package/resources/codex-and-agents-customizations/.codex/scripts/epic-child-persistence-runtime.ps1 +118 -0
  44. package/resources/codex-and-agents-customizations/.codex/scripts/epic-child-sandbox-preflight.ps1 +69 -0
  45. package/resources/codex-and-agents-customizations/.codex/scripts/launch-epic-child-wave.ps1 +471 -0
  46. package/resources/codex-and-agents-customizations/.codex/scripts/post-codex-worktree-session.ps1 +280 -0
  47. package/resources/codex-and-agents-customizations/.codex/scripts/resume-epic-child.ps1 +263 -0
  48. package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +2 -1
  49. package/resources/codex-and-agents-customizations/pack-manifests/core.json +18 -1
  50. package/resources/lib/codex-routing/CodexDeployment.psm1 +315 -0
  51. package/resources/lib/codex-routing/CodexTopology.psm1 +394 -0
  52. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +26 -0
@@ -0,0 +1,280 @@
1
+ [CmdletBinding()]
2
+ param(
3
+ [string]$SourceRoot = "",
4
+ [string]$WorktreeRoot = ""
5
+ )
6
+
7
+ Set-StrictMode -Version Latest
8
+ $ErrorActionPreference = 'Stop'
9
+
10
+ function ConvertTo-NormalizedRootPath {
11
+ [CmdletBinding()]
12
+ param(
13
+ [Parameter(Mandatory = $true)]
14
+ [string]$Path
15
+ )
16
+
17
+ return $Path.Replace('\', '/').TrimEnd('/')
18
+ }
19
+
20
+ function Join-NormalizedPath {
21
+ [CmdletBinding()]
22
+ [OutputType([string])]
23
+ param(
24
+ [Parameter(Mandatory = $true)]
25
+ [string]$Root,
26
+
27
+ [Parameter(Mandatory = $true)]
28
+ [string]$ChildPath
29
+ )
30
+
31
+ $normalizedRoot = ConvertTo-NormalizedRootPath -Path $Root
32
+ $normalizedChildPath = $ChildPath.Replace('\', '/').TrimStart('/')
33
+ return "$normalizedRoot/$normalizedChildPath"
34
+ }
35
+
36
+ function Get-NormalizedParentPath {
37
+ [CmdletBinding()]
38
+ param(
39
+ [Parameter(Mandatory = $true)]
40
+ [string]$Path
41
+ )
42
+
43
+ return (Split-Path -Parent $Path).Replace('\', '/').TrimEnd('/')
44
+ }
45
+
46
+ function Get-RelativeCustomizationPath {
47
+ [CmdletBinding()]
48
+ param(
49
+ [Parameter(Mandatory = $true)]
50
+ [string]$SourceFolder,
51
+
52
+ [Parameter(Mandatory = $true)]
53
+ [string]$SourcePath
54
+ )
55
+
56
+ $normalizedSourceFolder = ConvertTo-NormalizedRootPath -Path $SourceFolder
57
+ $normalizedSourcePath = $SourcePath.Replace('\', '/')
58
+ return $normalizedSourcePath.Substring($normalizedSourceFolder.Length).TrimStart('/')
59
+ }
60
+
61
+ function Test-TransientCustomizationPath {
62
+ [CmdletBinding()]
63
+ [OutputType([bool])]
64
+ param(
65
+ [Parameter(Mandatory = $true)]
66
+ [string]$RelativePath
67
+ )
68
+
69
+ $normalizedRelativePath = $RelativePath.Replace('\', '/').TrimStart('/')
70
+ $firstSegment = ($normalizedRelativePath -split '/')[0]
71
+ $blockedSegments = @(
72
+ '.cache',
73
+ '.venv',
74
+ 'cache',
75
+ 'caches',
76
+ 'credentials',
77
+ 'dist',
78
+ 'logs',
79
+ 'node_modules',
80
+ 'out',
81
+ 'sessions',
82
+ 'tmp',
83
+ 'venv'
84
+ )
85
+
86
+ if ($blockedSegments -contains $firstSegment) {
87
+ return $true
88
+ }
89
+
90
+ return $normalizedRelativePath -match '(^|/)(.*\.log|.*\.tmp|.*\.cache|credentials(\..*)?)$'
91
+ }
92
+
93
+ function Resolve-CodexCustomizationSourceRoot {
94
+ [CmdletBinding()]
95
+ param(
96
+ [string]$SourceRoot = "",
97
+
98
+ [Parameter(Mandatory = $true)]
99
+ [string]$WorktreeRoot,
100
+
101
+ [string]$ScriptRoot = $PSScriptRoot,
102
+
103
+ [scriptblock]$InvokeGit = {
104
+ param([string[]]$GitArgs)
105
+ git @GitArgs 2>$null
106
+ }
107
+ )
108
+
109
+ if (-not [string]::IsNullOrWhiteSpace($SourceRoot)) {
110
+ return ConvertTo-NormalizedRootPath -Path $SourceRoot
111
+ }
112
+
113
+ $normalizedWorktreeRoot = ConvertTo-NormalizedRootPath -Path $WorktreeRoot
114
+ $commonDir = [string]::Join("`n", @(& $InvokeGit -GitArgs @('-C', $normalizedWorktreeRoot, 'rev-parse', '--git-common-dir'))).Trim()
115
+ if (-not [string]::IsNullOrWhiteSpace($commonDir)) {
116
+ $normalizedCommonDir = ConvertTo-NormalizedRootPath -Path $commonDir
117
+ if ($normalizedCommonDir.EndsWith('/.git', [System.StringComparison]::OrdinalIgnoreCase)) {
118
+ return Get-NormalizedParentPath -Path $normalizedCommonDir
119
+ }
120
+ }
121
+
122
+ $worktreeList = @(& $InvokeGit -GitArgs @('-C', $normalizedWorktreeRoot, 'worktree', 'list', '--porcelain'))
123
+ foreach ($line in $worktreeList) {
124
+ if ($line -match '^worktree\s+(.+)$') {
125
+ return ConvertTo-NormalizedRootPath -Path $Matches[1]
126
+ }
127
+ }
128
+
129
+ $fallbackPath = [System.IO.Path]::GetFullPath((Join-Path -Path $ScriptRoot -ChildPath '../..'))
130
+ return ConvertTo-NormalizedRootPath -Path $fallbackPath
131
+ }
132
+
133
+ function Get-CodexCustomizationCopyPlan {
134
+ [CmdletBinding()]
135
+ [OutputType([pscustomobject])]
136
+ param(
137
+ [Parameter(Mandatory = $true)]
138
+ [string]$SourceRoot,
139
+
140
+ [Parameter(Mandatory = $true)]
141
+ [string]$WorktreeRoot,
142
+
143
+ [scriptblock]$TestPath = {
144
+ param([string]$LiteralPath)
145
+ Test-Path -LiteralPath $LiteralPath -PathType Container
146
+ },
147
+
148
+ [scriptblock]$GetChildItem = {
149
+ param([string]$LiteralPath)
150
+ Get-ChildItem -LiteralPath $LiteralPath -File -Recurse
151
+ }
152
+ )
153
+
154
+ $normalizedSourceRoot = ConvertTo-NormalizedRootPath -Path $SourceRoot
155
+ $normalizedWorktreeRoot = ConvertTo-NormalizedRootPath -Path $WorktreeRoot
156
+ if ($normalizedSourceRoot.Equals($normalizedWorktreeRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
157
+ return
158
+ }
159
+
160
+ foreach ($customizationFolder in @('.codex', '.agents')) {
161
+ $sourceFolder = Join-NormalizedPath -Root $normalizedSourceRoot -ChildPath $customizationFolder
162
+ if (-not (& $TestPath -LiteralPath $sourceFolder)) {
163
+ continue
164
+ }
165
+
166
+ foreach ($file in @(& $GetChildItem -LiteralPath $sourceFolder | Sort-Object -Property FullName)) {
167
+ $fullNameProperty = $file.PSObject.Properties['FullName']
168
+ if ($null -eq $fullNameProperty) {
169
+ throw "Customization file object is missing FullName."
170
+ }
171
+
172
+ $sourcePath = [string]$fullNameProperty.Value
173
+ $relativePath = Get-RelativeCustomizationPath -SourceFolder $sourceFolder -SourcePath $sourcePath
174
+ if (Test-TransientCustomizationPath -RelativePath $relativePath) {
175
+ [pscustomobject]@{
176
+ Action = 'Skip'
177
+ CustomizationFolder = $customizationFolder
178
+ SourcePath = $sourcePath.Replace('\', '/')
179
+ DestinationPath = ''
180
+ Reason = 'transient or machine-local path'
181
+ }
182
+ continue
183
+ }
184
+
185
+ [pscustomobject]@{
186
+ Action = 'Copy'
187
+ CustomizationFolder = $customizationFolder
188
+ SourcePath = $sourcePath.Replace('\', '/')
189
+ DestinationPath = Join-NormalizedPath -Root $normalizedWorktreeRoot -ChildPath "$customizationFolder/$relativePath"
190
+ Reason = ''
191
+ }
192
+ }
193
+ }
194
+ }
195
+
196
+ function Invoke-CodexCustomizationCopyPlan {
197
+ [CmdletBinding()]
198
+ param(
199
+ [Parameter(Mandatory = $true)]
200
+ [AllowEmptyCollection()]
201
+ [object[]]$CopyOperation,
202
+
203
+ [scriptblock]$NewDirectory = {
204
+ param([string]$LiteralPath)
205
+ New-Item -ItemType Directory -Force -Path $LiteralPath | Out-Null
206
+ },
207
+
208
+ [scriptblock]$CopyFile = {
209
+ param(
210
+ [string]$SourcePath,
211
+ [string]$DestinationPath
212
+ )
213
+ Copy-Item -LiteralPath $SourcePath -Destination $DestinationPath -Force
214
+ }
215
+ )
216
+
217
+ foreach ($operation in @($CopyOperation | Where-Object { $_.Action -ne 'Skip' })) {
218
+ $destinationDirectory = Get-NormalizedParentPath -Path $operation.DestinationPath
219
+ & $NewDirectory -LiteralPath $destinationDirectory
220
+ & $CopyFile -SourcePath $operation.SourcePath -DestinationPath $operation.DestinationPath
221
+ }
222
+ }
223
+
224
+ function Write-CodexCustomizationCopySummary {
225
+ [CmdletBinding()]
226
+ param(
227
+ [Parameter(Mandatory = $true)]
228
+ [string]$SourceRoot,
229
+
230
+ [Parameter(Mandatory = $true)]
231
+ [string]$WorktreeRoot,
232
+
233
+ [Parameter(Mandatory = $true)]
234
+ [AllowEmptyCollection()]
235
+ [object[]]$CopyOperation,
236
+
237
+ [Parameter(Mandatory = $true)]
238
+ [AllowEmptyCollection()]
239
+ [object[]]$SkippedOperation,
240
+
241
+ [scriptblock]$WriteLog = {
242
+ param([string]$Message)
243
+ Write-Information -MessageData $Message -InformationAction Continue
244
+ }
245
+ )
246
+
247
+ & $WriteLog -Message "SourceRoot: $(ConvertTo-NormalizedRootPath -Path $SourceRoot)"
248
+ & $WriteLog -Message "WorktreeRoot: $(ConvertTo-NormalizedRootPath -Path $WorktreeRoot)"
249
+ & $WriteLog -Message "Copied: $(@($CopyOperation).Count)"
250
+ foreach ($operation in @($CopyOperation | Select-Object -First 5)) {
251
+ & $WriteLog -Message " copied $($operation.CustomizationFolder): $($operation.DestinationPath)"
252
+ }
253
+
254
+ & $WriteLog -Message "Skipped: $(@($SkippedOperation).Count)"
255
+ foreach ($operation in @($SkippedOperation | Select-Object -First 5)) {
256
+ & $WriteLog -Message " skipped $($operation.CustomizationFolder): $($operation.Reason)"
257
+ }
258
+ }
259
+
260
+ if ($MyInvocation.InvocationName -ne '.') {
261
+ $effectiveWorktreeRoot = if ([string]::IsNullOrWhiteSpace($WorktreeRoot)) {
262
+ (Get-Location).Path
263
+ }
264
+ else {
265
+ $WorktreeRoot
266
+ }
267
+
268
+ $effectiveSourceRoot = Resolve-CodexCustomizationSourceRoot -SourceRoot $SourceRoot -WorktreeRoot $effectiveWorktreeRoot
269
+ $plan = @(
270
+ Get-CodexCustomizationCopyPlan -SourceRoot $effectiveSourceRoot -WorktreeRoot $effectiveWorktreeRoot
271
+ )
272
+ $copyOperations = @($plan | Where-Object { $_.Action -ne 'Skip' })
273
+ $skippedOperations = @($plan | Where-Object { $_.Action -eq 'Skip' })
274
+ Invoke-CodexCustomizationCopyPlan -CopyOperation $copyOperations
275
+ Write-CodexCustomizationCopySummary `
276
+ -SourceRoot $effectiveSourceRoot `
277
+ -WorktreeRoot $effectiveWorktreeRoot `
278
+ -CopyOperation $copyOperations `
279
+ -SkippedOperation $skippedOperations
280
+ }
@@ -0,0 +1,263 @@
1
+ # Resume one launcher-authorized Codex epic child with its sealed runtime controls.
2
+ [CmdletBinding(SupportsShouldProcess)]
3
+ param(
4
+ [Parameter(Mandatory)][string] $ReceiptPath,
5
+ [AllowEmptyString()][string] $Prompt = '',
6
+ [AllowEmptyString()][string] $LastMessagePath = ''
7
+ )
8
+
9
+ $ErrorActionPreference = 'Stop'
10
+ . (Join-Path $PSScriptRoot 'epic-child-launch-contract.ps1')
11
+ . (Join-Path $PSScriptRoot 'epic-child-launch-runtime.ps1')
12
+
13
+ function Test-CodexChildResumeSpecEntry {
14
+ [OutputType([string[]])]
15
+ param([Parameter(Mandatory)] $Receipt, [Parameter(Mandatory)] $Spec)
16
+ $errors = [System.Collections.Generic.List[string]]::new()
17
+ $entry = @($Spec.launches | Where-Object { [string]$_.launch_id -eq [string]$Receipt.launch_id })
18
+ if ($entry.Count -ne 1) {
19
+ return @('sealed launch specification must contain the receipt launch_id exactly once.')
20
+ }
21
+ $entry = $entry[0]
22
+ $pairs = @(
23
+ @('delegation_id', 'delegation_id'), @('feature_folder', 'feature_folder'),
24
+ @('deployment_agent', 'deployment_agent'), @('model', 'model'),
25
+ @('model_reasoning_effort', 'model_reasoning_effort'), @('permissions', 'permissions'),
26
+ @('execution_context', 'execution_context'), @('worktree_path', 'worktree_path'),
27
+ @('branch_name', 'branch_name')
28
+ )
29
+ foreach ($pair in $pairs) {
30
+ if ([string]$entry.($pair[0]) -cne [string]$Receipt.($pair[1])) {
31
+ $errors.Add("sealed launch specification $($pair[0]) differs from the receipt.")
32
+ }
33
+ }
34
+ if (-not (Test-CodexChildIssueEqual -Left $entry.issue_num -Right $Receipt.issue_num)) {
35
+ $errors.Add('sealed launch specification issue_num differs from the receipt.')
36
+ }
37
+ if ((Get-CodexChildSha256 -Value ([string]$entry.prompt)) -ne [string]$Receipt.prompt_sha256) {
38
+ $errors.Add('sealed launch specification prompt hash differs from the receipt.')
39
+ }
40
+ return $errors.ToArray()
41
+ }
42
+
43
+ function Get-CodexChildResumeContext {
44
+ [CmdletBinding()]
45
+ param([Parameter(Mandatory)][string] $Path)
46
+ if (-not [System.IO.Path]::IsPathFullyQualified($Path)) {
47
+ throw 'EPIC_CHILD_RESUME_BLOCKED: ReceiptPath must be an absolute path.'
48
+ }
49
+ $canonicalReceipt = Get-CodexChildCanonicalPath -Path $Path -BasePath (Get-Location).Path
50
+ $receipt = ConvertFrom-CodexChildLaunchJson -Raw (Get-Content -Raw -LiteralPath $canonicalReceipt) -Name 'launch receipt'
51
+ $errors = [System.Collections.Generic.List[string]]::new()
52
+ $lifecycleErrors = if ([string]$receipt.state -eq 'active') {
53
+ @(Get-CodexChildActiveReceiptErrorList -Receipt $receipt)
54
+ } else {
55
+ @(Get-CodexChildTerminalReceiptErrorList -Receipt $receipt)
56
+ }
57
+ foreach ($receiptError in $lifecycleErrors) {
58
+ $errors.Add($receiptError)
59
+ }
60
+ if ((Get-CodexChildCanonicalPath -Path ([string]$receipt.receipt_path) -BasePath (Get-Location).Path) -ne $canonicalReceipt) {
61
+ $errors.Add('receipt_path does not identify the loaded sealed receipt.')
62
+ }
63
+ $worktree = Get-CodexChildCanonicalPath -Path ([string]$receipt.worktree_path) `
64
+ -BasePath ([string]$receipt.trusted_repository_root)
65
+ $top = Get-CodexChildGitScalar -GitArgs @('-C', $worktree, 'rev-parse', '--show-toplevel')
66
+ if ((Get-CodexChildCanonicalPath -Path $top -BasePath $worktree) -ne $worktree) {
67
+ $errors.Add('worktree_path is not the exact Git worktree root.')
68
+ }
69
+ if ((Get-CodexChildCommonDirectory -WorktreePath $worktree) -ne [string]$receipt.git_common_directory) {
70
+ $errors.Add('worktree no longer shares the sealed Git common directory.')
71
+ }
72
+ $branch = Get-CodexChildGitScalar -GitArgs @('-C', $worktree, 'branch', '--show-current')
73
+ if ($branch -cne [string]$receipt.branch_name) { $errors.Add('live branch differs from the sealed receipt.') }
74
+ $head = Get-CodexChildGitScalar -GitArgs @('-C', $worktree, 'rev-parse', 'HEAD')
75
+ foreach ($ancestor in @([string]$receipt.integration_head, [string]$receipt.child_head)) {
76
+ if (-not (Test-CodexChildGit -GitArgs @('-C', $worktree, 'merge-base', '--is-ancestor', $ancestor, $head))) {
77
+ $errors.Add('worktree HEAD no longer descends from the sealed launch ancestry.')
78
+ }
79
+ }
80
+ $trustedObjects = Get-CodexChildSurfaceObjectMap -RepositoryPath ([string]$receipt.trusted_repository_root) `
81
+ -Commit ([string]$receipt.trusted_repository_head)
82
+ $currentObjects = Get-CodexChildSurfaceObjectMap -RepositoryPath $worktree -Commit $head
83
+ if (-not (Test-CodexChildSurfaceObjectsEqual -Expected $receipt.trusted_surface_objects -Actual $trustedObjects) -or
84
+ -not (Test-CodexChildSurfaceObjectsEqual -Expected $receipt.trusted_surface_objects -Actual $currentObjects) -or
85
+ (Get-CodexChildSurfaceFingerprint -SurfaceObjects $currentObjects) -ne [string]$receipt.trusted_surface_sha256) {
86
+ $errors.Add('trusted Codex instructions, skills, configuration, or routing surfaces have changed.')
87
+ }
88
+ $surfaceStatus = @(Invoke-CodexChildGit -GitArgs @(
89
+ '-C', $worktree, 'status', '--porcelain=v1', '--untracked-files=all', '--',
90
+ '.codex', '.agents', 'AGENTS.md', 'config/orchestration-routing.json'
91
+ ))
92
+ if (-not (Test-CodexChildCustomizationClean -StatusLines $surfaceStatus)) {
93
+ $errors.Add('trusted customization surfaces are not clean against worktree HEAD.')
94
+ }
95
+ $profilePath = Get-CodexChildCanonicalPath -Path ([string]$receipt.profile_path) -BasePath $worktree
96
+ $expectedProfile = Get-CodexChildCanonicalPath -Path ".codex/agents/$($receipt.deployment_agent).toml" -BasePath $worktree
97
+ $profileRaw = Get-Content -Raw -LiteralPath $profilePath
98
+ $agentProfile = ConvertFrom-CodexAgentProfile -ProfileRaw $profileRaw
99
+ if ($profilePath -ne $expectedProfile -or
100
+ (Get-FileHash -LiteralPath $profilePath -Algorithm SHA256).Hash.ToLowerInvariant() -cne [string]$receipt.profile_sha256 -or
101
+ [string]$agentProfile.name -cne [string]$receipt.deployment_agent -or [string]$agentProfile.model -cne [string]$receipt.model -or
102
+ [string]$agentProfile.model_reasoning_effort -cne [string]$receipt.model_reasoning_effort -or
103
+ [string]$agentProfile.default_permissions -cne [string]$receipt.permissions -or
104
+ (Get-CodexChildSha256 -Value ([string]$agentProfile.developer_instructions) -ne [string]$receipt.developer_instructions_sha256) -or
105
+ (Get-CodexChildSha256 -Value ([string]$agentProfile.skills_config) -ne [string]$receipt.skills_config_sha256)) {
106
+ $errors.Add('checked-in generated deployment profile differs from the sealed receipt.')
107
+ }
108
+ $specPath = Get-CodexChildCanonicalPath -Path ([string]$receipt.spec_path) -BasePath ([string]$receipt.trusted_repository_root)
109
+ if ((Get-FileHash -LiteralPath $specPath -Algorithm SHA256).Hash.ToLowerInvariant() -ne [string]$receipt.spec_sha256) {
110
+ $errors.Add('sealed launch specification hash has changed.')
111
+ }
112
+ $spec = ConvertFrom-CodexChildLaunchJson -Raw (Get-Content -Raw -LiteralPath $specPath) -Name 'launch spec'
113
+ if ([string]$receipt.checkpoint_kind -cne [string]$spec.checkpoint_kind) {
114
+ $errors.Add('checkpoint_kind differs from the sealed launch specification.')
115
+ }
116
+ $expectedLockPath = Get-CodexChildSemanticWaveLockPath -Spec $spec -ArtifactRoot (Split-Path $specPath -Parent)
117
+ $receiptLockPath = Get-CodexChildCanonicalPath -Path ([string]$receipt.wave_lock_path) `
118
+ -BasePath ([string]$receipt.trusted_repository_root)
119
+ if ($receiptLockPath -cne $expectedLockPath) {
120
+ $errors.Add('wave_lock_path does not match the sealed semantic wave identity.')
121
+ }
122
+ foreach ($specError in @(Test-CodexChildResumeSpecEntry -Receipt $receipt -Spec $spec)) {
123
+ $errors.Add($specError)
124
+ }
125
+ $codexRuntime = Get-CodexChildCommandContext
126
+ $codexHome = Get-CodexChildCanonicalPath -Path ([string]$receipt.codex_home_path) `
127
+ -BasePath (Get-CodexChildAuthorityRoot)
128
+ if (-not $codexHome.StartsWith((Get-CodexChildAuthorityRoot) + [System.IO.Path]::DirectorySeparatorChar,
129
+ [System.StringComparison]::OrdinalIgnoreCase) -or -not (Test-Path -LiteralPath $codexHome -PathType Container)) {
130
+ $errors.Add('isolated CODEX_HOME is missing or outside launcher authority.')
131
+ }
132
+ $expectedDeniedPaths = [string[]]@($codexRuntime.DeniedPaths) + @($codexHome)
133
+ if ([string]$codexRuntime.CommandPath -ne [string]$receipt.codex_command_path -or
134
+ (@($expectedDeniedPaths) | ConvertTo-Json -Compress) -ne (@($receipt.codex_denied_paths) | ConvertTo-Json -Compress)) {
135
+ $errors.Add('Codex executable or package paths differ from the sealed runtime deny set.')
136
+ }
137
+ if ($errors.Count -gt 0) { throw "EPIC_CHILD_RESUME_BLOCKED: $($errors -join ' ')" }
138
+ return [pscustomobject]@{ Receipt = $receipt; Profile = $agentProfile; CodexRuntime = $codexRuntime }
139
+ }
140
+
141
+ function Get-CodexChildResumeStartInfo {
142
+ [CmdletBinding()]
143
+ param(
144
+ [Parameter(Mandatory)] $Context,
145
+ [AllowEmptyString()][string] $ResumePrompt = '',
146
+ [AllowEmptyString()][string] $OutputPath = ''
147
+ )
148
+ $receipt = $Context.Receipt; $agentProfile = $Context.Profile
149
+ $commandPath = [string]$Context.CodexRuntime.CommandPath
150
+ $isPowerShellShim = $commandPath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)
151
+ $info = [System.Diagnostics.ProcessStartInfo]::new($(if ($isPowerShellShim) { 'pwsh' } else { $commandPath }))
152
+ $info.UseShellExecute = $false; $info.WorkingDirectory = [string]$receipt.worktree_path
153
+ if ($isPowerShellShim) { foreach ($item in @('-NoProfile', '-File', $commandPath)) { $info.ArgumentList.Add($item) } }
154
+ $permissionOverride = Get-CodexChildPermissionOverride -DeniedPaths ([string[]]$receipt.codex_denied_paths)
155
+ $projectsOverride = Get-CodexChildProjectsOverride -WorktreePath ([string]$receipt.worktree_path)
156
+ $shellOverrides = Get-CodexChildShellEnvironmentOverrideList -WorktreePath ([string]$receipt.worktree_path)
157
+ foreach ($item in @(
158
+ 'exec', 'resume', '--ignore-user-config', '-c', $projectsOverride, '-c', $permissionOverride,
159
+ '-c', $shellOverrides[0], '-c', $shellOverrides[1],
160
+ '-m', [string]$receipt.model, '-c', "model_reasoning_effort=$($receipt.model_reasoning_effort)",
161
+ '-c', 'default_permissions="epic-child-workspace"', '-c', 'approval_policy="never"',
162
+ '-c', ('developer_instructions=' + ([string]$agentProfile.developer_instructions | ConvertTo-Json -Compress)),
163
+ '-c', "skills.config=$($agentProfile.skills_config)", '--strict-config',
164
+ '--dangerously-bypass-hook-trust', '--json'
165
+ )) { $info.ArgumentList.Add($item) }
166
+ if ($IsWindows) { $info.ArgumentList.Insert(2, 'windows.sandbox="elevated"'); $info.ArgumentList.Insert(2, '-c') }
167
+ if (-not [string]::IsNullOrWhiteSpace($OutputPath)) { $info.ArgumentList.Add('-o'); $info.ArgumentList.Add($OutputPath) }
168
+ $info.ArgumentList.Add([string]$receipt.codex_session_id)
169
+ if (-not [string]::IsNullOrWhiteSpace($ResumePrompt)) { $info.ArgumentList.Add($ResumePrompt) }
170
+ $environment = @{
171
+ CODEX_EPIC_CHILD_LAUNCH_ID = [string]$receipt.launch_id
172
+ CODEX_EPIC_CHILD_LAUNCH_RECEIPT = [string]$receipt.receipt_path
173
+ CODEX_EPIC_CHILD_LAUNCH_SPEC = [string]$receipt.spec_path
174
+ CODEX_EPIC_CHILD_EXPECTED_WORKTREE = [string]$receipt.worktree_path
175
+ CODEX_EPIC_CHILD_DELEGATION_ID = [string]$receipt.delegation_id
176
+ CODEX_EPIC_CHILD_EXECUTION_CONTEXT = [string]$receipt.execution_context
177
+ CODEX_EPIC_CHILD_AGENT = [string]$receipt.deployment_agent
178
+ CODEX_EPIC_CHILD_MODEL = [string]$receipt.model
179
+ CODEX_EPIC_CHILD_REASONING_EFFORT = [string]$receipt.model_reasoning_effort
180
+ CODEX_EPIC_CHILD_PROFILE_SHA256 = [string]$receipt.profile_sha256
181
+ CODEX_EPIC_CHILD_SESSION_ID = [string]$receipt.codex_session_id
182
+ }
183
+ foreach ($item in $environment.GetEnumerator()) { $info.Environment[$item.Key] = $item.Value }
184
+ $info.Environment['CODEX_HOME'] = [string]$receipt.codex_home_path
185
+ return $info
186
+ }
187
+
188
+ function Set-CodexChildResumeWaveStatus {
189
+ [CmdletBinding(SupportsShouldProcess)]
190
+ param([Parameter(Mandatory)] $Receipt)
191
+ if (-not $PSCmdlet.ShouldProcess([string]$Receipt.status_path, 'Update epic-child wave status from resume receipt')) {
192
+ return
193
+ }
194
+ $status = ConvertFrom-CodexChildLaunchJson -Raw `
195
+ (Get-Content -Raw -LiteralPath ([string]$Receipt.status_path)) -Name 'wave status'
196
+ $property = $status.launches.PSObject.Properties[[string]$Receipt.launch_id]
197
+ if ($null -eq $property) { throw 'EPIC_CHILD_RESUME_BLOCKED: wave status lacks the receipt launch_id.' }
198
+ $entry = $property.Value
199
+ $entry.state = [string]$Receipt.state; $entry.codex_session_id = [string]$Receipt.codex_session_id
200
+ $entry.receipt_path = [string]$Receipt.receipt_path
201
+ if ([string]$Receipt.state -eq 'completed') {
202
+ $entry.exit_code = 0; $entry.completed_at = [string]$Receipt.completed_at
203
+ } elseif ([string]$Receipt.state -eq 'failed') {
204
+ $entry.exit_code = [int]$Receipt.exit_code; $entry.failed_at = [string]$Receipt.failed_at
205
+ }
206
+ $status.updated_at = [datetimeoffset]::UtcNow.ToString('o')
207
+ Write-CodexChildJsonAtomic -Path ([string]$Receipt.status_path) -Value $status
208
+ }
209
+
210
+ if ($MyInvocation.InvocationName -eq '.') { return }
211
+ $context = Get-CodexChildResumeContext -Path $ReceiptPath
212
+ $outputPath = if ([string]::IsNullOrWhiteSpace($LastMessagePath)) {
213
+ Join-Path (Split-Path ([string]$context.Receipt.receipt_path) -Parent) "$($context.Receipt.launch_id).resume.last-message.txt"
214
+ } else { Get-CodexChildCanonicalPath -Path $LastMessagePath -BasePath ([string]$context.Receipt.worktree_path) }
215
+ if (-not $PSCmdlet.ShouldProcess([string]$context.Receipt.worktree_path, "Resume Codex epic child $($context.Receipt.launch_id)")) { return }
216
+ $receipt = $context.Receipt
217
+ $waveLock = Enter-CodexChildWaveLock -Path ([string]$receipt.wave_lock_path)
218
+ $authOwned = $false
219
+ $process = $null; $processStarted = $false
220
+ try {
221
+ Restore-CodexChildIsolatedAuth -HomePath ([string]$receipt.codex_home_path) `
222
+ -OriginalAuthPath ([string]$context.CodexRuntime.OriginalAuthPath) -Confirm:$false
223
+ $authOwned = $true
224
+ $probeInfo = Get-CodexChildSandboxProbeStartInfo -WorktreePath ([string]$receipt.worktree_path) `
225
+ -CodexHomePath ([string]$receipt.codex_home_path) -CommandPath ([string]$context.CodexRuntime.CommandPath) `
226
+ -DeniedPaths ([string[]]$receipt.codex_denied_paths) `
227
+ -DeniedProbePath ([string]$context.CodexRuntime.OriginalAuthPath)
228
+ Assert-CodexChildSandboxPreflight -StartInfo $probeInfo
229
+ Set-CodexChildReceiptState -Receipt $receipt -State launching
230
+ $process = [System.Diagnostics.Process]::new()
231
+ $process.StartInfo = Get-CodexChildResumeStartInfo -Context $context -ResumePrompt $Prompt -OutputPath $outputPath
232
+ if (-not $process.Start()) { throw 'failed to start Codex resume process.' }
233
+ $processStarted = $true
234
+ Set-CodexChildReceiptState -Receipt $receipt -State active -SessionId ([string]$receipt.codex_session_id)
235
+ $process.WaitForExit()
236
+ if ($process.ExitCode -eq 0) {
237
+ Set-CodexChildReceiptState -Receipt $receipt -State completed -ExitCode 0
238
+ } else {
239
+ Set-CodexChildReceiptState -Receipt $receipt -State failed -ExitCode $process.ExitCode `
240
+ -FailureReason 'Codex resume process returned a nonzero exit code.'
241
+ }
242
+ Set-CodexChildResumeWaveStatus -Receipt $receipt
243
+ $exitCode = $process.ExitCode
244
+ } catch {
245
+ if ($processStarted -and -not $process.HasExited) {
246
+ $process.Kill($true); $process.WaitForExit()
247
+ }
248
+ if ([string]$receipt.state -in @('launching', 'active')) {
249
+ $failureExitCode = if ($processStarted -and $process.HasExited) { [int]$process.ExitCode } else { -1 }
250
+ Set-CodexChildReceiptState -Receipt $receipt -State failed -ExitCode $failureExitCode -FailureReason ([string]$_)
251
+ Set-CodexChildResumeWaveStatus -Receipt $receipt
252
+ }
253
+ throw "EPIC_CHILD_RESUME_BLOCKED: $_"
254
+ } finally {
255
+ try {
256
+ if ($authOwned) {
257
+ Remove-CodexChildIsolatedAuth -HomePath ([string]$receipt.codex_home_path) -Confirm:$false
258
+ }
259
+ } finally {
260
+ $waveLock.Dispose()
261
+ }
262
+ }
263
+ exit $exitCode
@@ -1,6 +1,7 @@
1
1
  name = "csharp-typed-engineer"
2
2
  description = "Converted subagent"
3
- variant = "legacy"
3
+ model = "gpt-5.6-terra"
4
+ model_reasoning_effort = "high"
4
5
  developer_instructions = '''
5
6
  Canonical migration source: .github/agents/csharp-typed-engineer.agent.md
6
7
  Read the canonical source agent file first and follow it exactly.
@@ -44,12 +44,27 @@
44
44
  ".codex/hooks/hook-command-scanner.ps1",
45
45
  ".codex/hooks/record-subagent-routing-attestation.ps1",
46
46
  ".codex/hooks/validate-codex-subagent-routing.ps1",
47
+ ".codex/hooks/check-powershell-test-purity.ps1",
48
+ ".codex/hooks/check-python-test-purity.ps1",
49
+ ".codex/hooks/enforce-checkpoint-monotonic.ps1",
50
+ ".codex/hooks/enforce-completion-consistency.ps1",
51
+ ".codex/hooks/enforce-completion-helpers.ps1",
52
+ ".codex/hooks/enforce-evidence-locations.ps1",
53
+ ".codex/hooks/enforce-orchestration-preimplementation-gate.ps1",
54
+ ".codex/hooks/enforce-powershell-batch-budget.ps1",
55
+ ".codex/hooks/enforce-promotion-mcp-only.ps1",
56
+ ".codex/hooks/enforce-python-batch-budget.ps1",
57
+ ".codex/hooks/validate-bash.ps1",
58
+ ".codex/hooks/validate-feature-review-coverage.ps1",
47
59
  ".codex/scripts/epic-child-launch-contract.ps1",
48
60
  ".codex/scripts/epic-child-launch-runtime.ps1",
49
61
  ".codex/scripts/epic-child-persistence-runtime.ps1",
50
62
  ".codex/scripts/epic-child-sandbox-preflight.ps1",
51
63
  ".codex/scripts/launch-epic-child-wave.ps1",
52
64
  ".codex/scripts/resume-epic-child.ps1",
65
+ ".codex/scripts/codex-routing-cli-common.ps1",
66
+ ".codex/scripts/Resolve-CodexDeployment.ps1",
67
+ ".codex/scripts/Resolve-CodexTopology.ps1",
53
68
  ".codex/prompts/generate-pr.md",
54
69
  ".codex/prompts/orchestrate-work.md",
55
70
  ".codex/agents/feature-reviewer.toml",
@@ -98,6 +113,8 @@
98
113
  ".codex/agents/commit-steward-c3-elevated.toml",
99
114
  ".codex/agents/commit-steward-c4.toml",
100
115
  "config/orchestration-handoff-registry.json",
101
- "config/orchestration-handoff.schema.json"
116
+ "config/orchestration-handoff.schema.json",
117
+ ".codex/lib/codex-routing/CodexDeployment.psm1",
118
+ ".codex/lib/codex-routing/CodexTopology.psm1"
102
119
  ]
103
120
  }