@loucompanion/forge-bridge 0.1.3-dev.f2b8822ce953 → 0.1.3-dev.fbe15023cdfe

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 (143) hide show
  1. package/README.md +78 -0
  2. package/dist/bridge/bridge.base.d.ts +6 -1
  3. package/dist/bridge/bridge.service.d.ts +60 -3
  4. package/dist/bridge/bridge.service.js +970 -24
  5. package/dist/bridge/bridge.types.d.ts +172 -1
  6. package/dist/cleanup/cleanup.service.d.ts +13 -2
  7. package/dist/cleanup/cleanup.service.js +435 -3
  8. package/dist/cleanup/cleanup.types.d.ts +10 -0
  9. package/dist/cleanup/index.d.ts +1 -1
  10. package/dist/cleanup/index.js +1 -1
  11. package/dist/cleanup/internals.d.ts +2 -2
  12. package/dist/cleanup/internals.js +1 -1
  13. package/dist/cli/cli.help.js +47 -1
  14. package/dist/cli/cli.service.d.ts +42 -2
  15. package/dist/cli/cli.service.js +351 -22
  16. package/dist/cli/local-config.d.ts +6 -0
  17. package/dist/cli/local-config.js +47 -3
  18. package/dist/runtime/attempt-node-runtime-launcher.d.ts +17 -0
  19. package/dist/runtime/attempt-node-runtime-launcher.js +101 -0
  20. package/dist/runtime/attempt-process-supervisor-registry.d.ts +20 -0
  21. package/dist/runtime/attempt-process-supervisor-registry.js +64 -0
  22. package/dist/runtime/attempt-process-supervisor.d.ts +86 -0
  23. package/dist/runtime/attempt-process-supervisor.js +350 -0
  24. package/dist/runtime/generated-output-reset.d.ts +10 -0
  25. package/dist/runtime/generated-output-reset.js +103 -0
  26. package/dist/runtime/host-listener-inspector.d.ts +44 -0
  27. package/dist/runtime/host-listener-inspector.js +324 -0
  28. package/dist/runtime/host-port-broker.d.ts +76 -0
  29. package/dist/runtime/host-port-broker.js +333 -0
  30. package/dist/runtime/host-runtime-contract.d.ts +47 -0
  31. package/dist/runtime/host-runtime-contract.js +700 -0
  32. package/dist/runtime/host-runtime-lease.d.ts +133 -0
  33. package/dist/runtime/host-runtime-lease.js +1460 -0
  34. package/dist/runtime/host-runtime-promotion.d.ts +23 -0
  35. package/dist/runtime/host-runtime-promotion.js +159 -0
  36. package/dist/runtime/node-host-runtime-adapter.d.ts +51 -0
  37. package/dist/runtime/node-host-runtime-adapter.js +268 -0
  38. package/dist/runtime/playwright-host-runtime-adapter.d.ts +20 -0
  39. package/dist/runtime/playwright-host-runtime-adapter.js +220 -0
  40. package/dist/runtime/runtime-isolation-lease.d.ts +67 -0
  41. package/dist/runtime/runtime-isolation-lease.js +158 -0
  42. package/dist/sandbox/command-runner.d.ts +4 -0
  43. package/dist/sandbox/command-runner.js +47 -0
  44. package/dist/sandbox/contract.d.ts +5 -0
  45. package/dist/sandbox/contract.js +276 -0
  46. package/dist/sandbox/event-budget.d.ts +11 -0
  47. package/dist/sandbox/event-budget.js +27 -0
  48. package/dist/sandbox/image-policy.d.ts +35 -0
  49. package/dist/sandbox/image-policy.js +247 -0
  50. package/dist/sandbox/index.d.ts +5 -0
  51. package/dist/sandbox/index.js +5 -0
  52. package/dist/sandbox/lease-watchdog.d.ts +18 -0
  53. package/dist/sandbox/lease-watchdog.js +67 -0
  54. package/dist/sandbox/preflight.d.ts +54 -0
  55. package/dist/sandbox/preflight.js +335 -0
  56. package/dist/sandbox/process.d.ts +20 -0
  57. package/dist/sandbox/process.js +209 -0
  58. package/dist/sandbox/provider-auth/codex.d.ts +26 -0
  59. package/dist/sandbox/provider-auth/codex.js +212 -0
  60. package/dist/sandbox/repository-lock.d.ts +5 -0
  61. package/dist/sandbox/repository-lock.js +119 -0
  62. package/dist/sandbox/runtime.d.ts +297 -0
  63. package/dist/sandbox/runtime.js +2338 -0
  64. package/dist/sandbox/sandbox.types.d.ts +86 -0
  65. package/dist/sandbox/sandbox.types.js +1 -0
  66. package/dist/sandbox/smoke.d.ts +76 -0
  67. package/dist/sandbox/smoke.js +380 -0
  68. package/dist/sandbox/worker-supervisor.d.ts +13 -0
  69. package/dist/sandbox/worker-supervisor.js +36 -0
  70. package/dist/sandbox/worker.d.ts +1 -0
  71. package/dist/sandbox/worker.js +225 -0
  72. package/dist/sandbox/workspace.service.d.ts +13 -0
  73. package/dist/sandbox/workspace.service.js +72 -0
  74. package/dist/session/managed-attempt-tools.d.ts +12 -0
  75. package/dist/session/managed-attempt-tools.js +561 -0
  76. package/dist/session/phase-completion.artifacts.js +32 -4
  77. package/dist/session/phase-completion.d.ts +4 -2
  78. package/dist/session/phase-completion.helpers.js +27 -3
  79. package/dist/session/phase-completion.js +12 -3
  80. package/dist/session/phase-completion.prompts.d.ts +3 -3
  81. package/dist/session/phase-completion.prompts.js +20 -6
  82. package/dist/session/phase-completion.runtime.d.ts +12 -1
  83. package/dist/session/phase-completion.runtime.js +129 -7
  84. package/dist/session/phase-completion.schemas.js +132 -5
  85. package/dist/session/phase-completion.validation.d.ts +4 -1
  86. package/dist/session/phase-completion.validation.js +106 -2
  87. package/dist/session/provider-cli/ci-repair-readiness.d.ts +8 -0
  88. package/dist/session/provider-cli/ci-repair-readiness.js +90 -0
  89. package/dist/session/provider-cli/provider-cli.artifacts.d.ts +1 -1
  90. package/dist/session/provider-cli/provider-cli.artifacts.js +28 -4
  91. package/dist/session/provider-cli/provider-cli.base.d.ts +1 -0
  92. package/dist/session/provider-cli/provider-cli.deterministic.d.ts +2 -0
  93. package/dist/session/provider-cli/provider-cli.deterministic.js +66 -9
  94. package/dist/session/provider-cli/provider-cli.process.d.ts +17 -0
  95. package/dist/session/provider-cli/provider-cli.process.js +223 -14
  96. package/dist/session/provider-cli/provider-cli.prompts.d.ts +17 -2
  97. package/dist/session/provider-cli/provider-cli.prompts.js +226 -18
  98. package/dist/session/provider-cli/provider-cli.qa-sidecars.js +1 -0
  99. package/dist/session/provider-cli/provider-cli.runtime.d.ts +1 -1
  100. package/dist/session/provider-cli/provider-cli.runtime.js +3 -2
  101. package/dist/session/provider-cli/provider-cli.service.d.ts +19 -3
  102. package/dist/session/provider-cli/provider-cli.service.js +503 -98
  103. package/dist/session/provider-cli/provider-cli.types.d.ts +6 -0
  104. package/dist/session/provider-cli/provider-output-state.d.ts +2 -0
  105. package/dist/session/provider-cli/provider-output-state.js +30 -2
  106. package/dist/session/session-redaction.d.ts +3 -0
  107. package/dist/session/session-redaction.js +23 -0
  108. package/dist/session/session.base.d.ts +6 -1
  109. package/dist/session/session.service.d.ts +8 -2
  110. package/dist/session/session.service.js +463 -58
  111. package/dist/session/session.types.d.ts +144 -1
  112. package/dist/session/session.types.js +279 -3
  113. package/dist/shared/path/path.js +3 -1
  114. package/dist/shared/process/host-process-recovery.d.ts +12 -0
  115. package/dist/shared/process/host-process-recovery.js +78 -0
  116. package/dist/shared/process/host-process-supervisor.d.ts +57 -0
  117. package/dist/shared/process/host-process-supervisor.js +282 -0
  118. package/dist/shared/process/process.d.ts +1 -0
  119. package/dist/shared/process/process.js +1 -0
  120. package/dist/shared/process/windows-launch.d.ts +1 -1
  121. package/dist/shared/process/windows-launch.js +6 -3
  122. package/dist/shared/provider-capabilities.d.ts +1 -0
  123. package/dist/shared/provider-capabilities.js +3 -0
  124. package/dist/shared/redaction/redaction.js +10 -3
  125. package/dist/version.d.ts +1 -1
  126. package/dist/version.js +1 -1
  127. package/dist/worktree/artifact-injector.d.ts +3 -2
  128. package/dist/worktree/artifact-injector.js +43 -4
  129. package/dist/worktree/dependency-warmer.d.ts +21 -1
  130. package/dist/worktree/dependency-warmer.js +138 -5
  131. package/dist/worktree/index.d.ts +1 -0
  132. package/dist/worktree/index.js +1 -0
  133. package/dist/worktree/prior-phase-artifact-hydrator.d.ts +2 -0
  134. package/dist/worktree/prior-phase-artifact-hydrator.js +136 -0
  135. package/dist/worktree/worktree-paths.d.ts +4 -0
  136. package/dist/worktree/worktree-paths.js +30 -0
  137. package/dist/worktree/worktree.base.d.ts +3 -0
  138. package/dist/worktree/worktree.service.d.ts +7 -2
  139. package/dist/worktree/worktree.service.js +72 -44
  140. package/dist/worktree/worktree.types.d.ts +3 -1
  141. package/package.json +6 -3
  142. package/runtime/windows-job-supervisor.ps1 +356 -0
  143. package/runtime/windows-listener-owner.ps1 +33 -0
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@loucompanion/forge-bridge",
3
- "version": "0.1.3-dev.f2b8822ce953",
3
+ "version": "0.1.3-dev.fbe15023cdfe",
4
4
  "description": "Forge runner bridge CLI for connecting local developer machines to Forge dispatch.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
7
7
  "bin": {
8
+ "forge": "dist/cli/bin.js",
8
9
  "forge-bridge": "dist/cli/bin.js"
9
10
  },
10
11
  "main": "./dist/index.js",
@@ -18,6 +19,7 @@
18
19
  },
19
20
  "files": [
20
21
  "dist",
22
+ "runtime",
21
23
  "README.md"
22
24
  ],
23
25
  "repository": {
@@ -40,10 +42,11 @@
40
42
  "test": "vitest run",
41
43
  "test:watch": "vitest",
42
44
  "smoke:package": "npm run build && node scripts/smoke-package.mjs",
43
- "lint": "eslint \"src/**/*.ts\" \"scripts/**/*.mjs\" \"vitest.config.ts\""
45
+ "lint": "eslint \"src/**/*.ts\" \"scripts/**/*.mjs\" \"vitest.config.ts\" \"vitest.setup.ts\""
44
46
  },
45
47
  "dependencies": {
46
- "@microsoft/signalr": "^8.0.17"
48
+ "@microsoft/signalr": "^8.0.17",
49
+ "yaml": "^2.9.0"
47
50
  },
48
51
  "devDependencies": {
49
52
  "@eslint/js": "^10.0.1",
@@ -0,0 +1,356 @@
1
+ param(
2
+ [Parameter(Mandatory = $true)]
3
+ [ValidateSet("Outer", "Inner")]
4
+ [string]$Mode,
5
+
6
+ [Parameter(Mandatory = $true)]
7
+ [string]$PayloadPath,
8
+
9
+ [string]$GateName
10
+ )
11
+
12
+ $ErrorActionPreference = "Stop"
13
+
14
+ Add-Type -TypeDefinition @"
15
+ using System;
16
+ using System.Runtime.InteropServices;
17
+ using System.Text;
18
+
19
+ public static class ForgeWindowsJob
20
+ {
21
+ [StructLayout(LayoutKind.Sequential)]
22
+ private struct JOBOBJECT_BASIC_LIMIT_INFORMATION
23
+ {
24
+ public long PerProcessUserTimeLimit;
25
+ public long PerJobUserTimeLimit;
26
+ public uint LimitFlags;
27
+ public UIntPtr MinimumWorkingSetSize;
28
+ public UIntPtr MaximumWorkingSetSize;
29
+ public uint ActiveProcessLimit;
30
+ public UIntPtr Affinity;
31
+ public uint PriorityClass;
32
+ public uint SchedulingClass;
33
+ }
34
+
35
+ [StructLayout(LayoutKind.Sequential)]
36
+ private struct IO_COUNTERS
37
+ {
38
+ public ulong ReadOperationCount;
39
+ public ulong WriteOperationCount;
40
+ public ulong OtherOperationCount;
41
+ public ulong ReadTransferCount;
42
+ public ulong WriteTransferCount;
43
+ public ulong OtherTransferCount;
44
+ }
45
+
46
+ [StructLayout(LayoutKind.Sequential)]
47
+ private struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
48
+ {
49
+ public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
50
+ public IO_COUNTERS IoInfo;
51
+ public UIntPtr ProcessMemoryLimit;
52
+ public UIntPtr JobMemoryLimit;
53
+ public UIntPtr PeakProcessMemoryUsed;
54
+ public UIntPtr PeakJobMemoryUsed;
55
+ }
56
+
57
+ private const uint JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000;
58
+ private const int JobObjectExtendedLimitInformation = 9;
59
+
60
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
61
+ private static extern IntPtr CreateJobObject(IntPtr securityAttributes, string name);
62
+
63
+ [DllImport("kernel32.dll", SetLastError = true)]
64
+ private static extern bool SetInformationJobObject(
65
+ IntPtr job,
66
+ int informationClass,
67
+ IntPtr information,
68
+ uint informationLength);
69
+
70
+ [DllImport("kernel32.dll", SetLastError = true)]
71
+ public static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
72
+
73
+ [DllImport("kernel32.dll", SetLastError = true)]
74
+ public static extern bool TerminateJobObject(IntPtr job, uint exitCode);
75
+
76
+ [DllImport("kernel32.dll", SetLastError = true)]
77
+ public static extern bool CloseHandle(IntPtr handle);
78
+
79
+ public static IntPtr CreateKillOnCloseJob(string name)
80
+ {
81
+ IntPtr job = CreateJobObject(IntPtr.Zero, name);
82
+ if (job == IntPtr.Zero)
83
+ {
84
+ throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error(), "CreateJobObject failed.");
85
+ }
86
+
87
+ var limits = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
88
+ limits.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
89
+ int size = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
90
+ IntPtr pointer = Marshal.AllocHGlobal(size);
91
+ try
92
+ {
93
+ Marshal.StructureToPtr(limits, pointer, false);
94
+ if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, pointer, (uint)size))
95
+ {
96
+ throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error(), "SetInformationJobObject failed.");
97
+ }
98
+ }
99
+ catch
100
+ {
101
+ CloseHandle(job);
102
+ throw;
103
+ }
104
+ finally
105
+ {
106
+ Marshal.FreeHGlobal(pointer);
107
+ }
108
+
109
+ return job;
110
+ }
111
+
112
+ public static string BuildArguments(object[] arguments)
113
+ {
114
+ var result = new StringBuilder();
115
+ for (int index = 0; index < arguments.Length; index++)
116
+ {
117
+ if (index > 0) result.Append(' ');
118
+ result.Append(QuoteArgument(Convert.ToString(arguments[index]) ?? String.Empty));
119
+ }
120
+ return result.ToString();
121
+ }
122
+
123
+ private static string QuoteArgument(string argument)
124
+ {
125
+ if (argument.Length > 0 && argument.IndexOfAny(new[] { ' ', '\t', '\n', '\v', '"' }) < 0)
126
+ {
127
+ return argument;
128
+ }
129
+
130
+ var result = new StringBuilder();
131
+ result.Append('"');
132
+ int backslashes = 0;
133
+ foreach (char character in argument)
134
+ {
135
+ if (character == '\\')
136
+ {
137
+ backslashes++;
138
+ continue;
139
+ }
140
+
141
+ if (character == '"')
142
+ {
143
+ result.Append('\\', backslashes * 2 + 1);
144
+ result.Append('"');
145
+ backslashes = 0;
146
+ continue;
147
+ }
148
+
149
+ result.Append('\\', backslashes);
150
+ backslashes = 0;
151
+ result.Append(character);
152
+ }
153
+
154
+ result.Append('\\', backslashes * 2);
155
+ result.Append('"');
156
+ return result.ToString();
157
+ }
158
+ }
159
+ "@
160
+
161
+ function Read-ForgeSupervisorPayload {
162
+ if (-not [IO.Path]::IsPathRooted($PayloadPath)) {
163
+ throw "The supervisor payload path must be absolute."
164
+ }
165
+ $json = [IO.File]::ReadAllText($PayloadPath, [Text.Encoding]::UTF8)
166
+ return $json | ConvertFrom-Json
167
+ }
168
+
169
+ function New-ForgeChildProcess(
170
+ [string]$command,
171
+ [object[]]$arguments,
172
+ [string]$workingDirectory,
173
+ [bool]$redirectStreams
174
+ ) {
175
+ $maximumAttempts = 3
176
+ for ($attempt = 1; $attempt -le $maximumAttempts; $attempt += 1) {
177
+ $startInfo = New-Object System.Diagnostics.ProcessStartInfo
178
+ $startInfo.FileName = $command
179
+ $startInfo.Arguments = [ForgeWindowsJob]::BuildArguments($arguments)
180
+ $startInfo.WorkingDirectory = $workingDirectory
181
+ $startInfo.UseShellExecute = $false
182
+ $startInfo.CreateNoWindow = $true
183
+ $startInfo.RedirectStandardInput = $redirectStreams
184
+ $startInfo.RedirectStandardOutput = $redirectStreams
185
+ $startInfo.RedirectStandardError = $redirectStreams
186
+
187
+ $child = New-Object System.Diagnostics.Process
188
+ $child.StartInfo = $startInfo
189
+ try {
190
+ if (-not $child.Start()) {
191
+ throw "Failed to start supervised process '$command'."
192
+ }
193
+ $child | Add-Member -NotePropertyName ForgeStartAttempt -NotePropertyValue $attempt
194
+ return $child
195
+ }
196
+ catch {
197
+ $nativeError = $_.Exception
198
+ while ($nativeError.InnerException) {
199
+ $nativeError = $nativeError.InnerException
200
+ }
201
+ $retryable = $nativeError -is [ComponentModel.Win32Exception] -and $nativeError.NativeErrorCode -in @(5, 32, 33)
202
+ $child.Dispose()
203
+ if (-not $retryable -or $attempt -eq $maximumAttempts) {
204
+ throw
205
+ }
206
+ Start-Sleep -Milliseconds (100 * $attempt)
207
+ }
208
+ }
209
+ }
210
+
211
+ function Write-ForgeProviderReady([object]$request, [Diagnostics.Process]$provider) {
212
+ $readyPath = [string]$request.readyPath
213
+ if ([string]::IsNullOrWhiteSpace($readyPath) -or -not [IO.Path]::IsPathRooted($readyPath)) {
214
+ throw "The provider-ready path must be absolute."
215
+ }
216
+ $payloadDirectory = [IO.Path]::GetDirectoryName([IO.Path]::GetFullPath($PayloadPath))
217
+ $readyDirectory = [IO.Path]::GetDirectoryName([IO.Path]::GetFullPath($readyPath))
218
+ if (-not [string]::Equals($payloadDirectory, $readyDirectory, [StringComparison]::OrdinalIgnoreCase)) {
219
+ throw "The provider-ready path must be beside the supervisor payload."
220
+ }
221
+
222
+ $ready = @{
223
+ schemaVersion = 1
224
+ supervisorId = [string]$request.supervisorId
225
+ rootPid = [int]$env:FORGE_SUPERVISOR_ROOT_PID
226
+ rootIdentity = [string]$env:FORGE_SUPERVISOR_ROOT_IDENTITY
227
+ providerPid = $provider.Id
228
+ providerCreatedAt = $provider.StartTime.ToUniversalTime().ToString("O")
229
+ providerIdentity = "win32:$($provider.StartTime.ToUniversalTime().Ticks)"
230
+ startAttempt = [int]$provider.ForgeStartAttempt
231
+ } | ConvertTo-Json -Compress
232
+ $temporaryPath = "$readyPath.$([Guid]::NewGuid().ToString('N')).tmp"
233
+ [IO.File]::WriteAllText($temporaryPath, "$ready`n", (New-Object Text.UTF8Encoding($false)))
234
+ [IO.File]::Move($temporaryPath, $readyPath)
235
+ }
236
+
237
+ function Wait-ForgeProviderStartGrant([object]$request) {
238
+ $grantPath = [string]$request.startGrantPath
239
+ if ([string]::IsNullOrWhiteSpace($grantPath) -or -not [IO.Path]::IsPathRooted($grantPath)) {
240
+ throw "The provider start-grant path must be absolute."
241
+ }
242
+ $payloadDirectory = [IO.Path]::GetDirectoryName([IO.Path]::GetFullPath($PayloadPath))
243
+ $grantDirectory = [IO.Path]::GetDirectoryName([IO.Path]::GetFullPath($grantPath))
244
+ if (-not [string]::Equals($payloadDirectory, $grantDirectory, [StringComparison]::OrdinalIgnoreCase)) {
245
+ throw "The provider start-grant path must be beside the supervisor payload."
246
+ }
247
+ for ($attempt = 0; $attempt -lt 1200; $attempt += 1) {
248
+ if ([IO.File]::Exists($grantPath)) {
249
+ return
250
+ }
251
+ Start-Sleep -Milliseconds 25
252
+ }
253
+ throw "Timed out waiting for the provider start grant."
254
+ }
255
+
256
+ function Start-ForgeOutputCopies([Diagnostics.Process]$child) {
257
+ return @(
258
+ $child.StandardOutput.BaseStream.CopyToAsync([Console]::OpenStandardOutput()),
259
+ $child.StandardError.BaseStream.CopyToAsync([Console]::OpenStandardError())
260
+ )
261
+ }
262
+
263
+ function Write-ForgeStandardInput([Diagnostics.Process]$child, [string]$inputText) {
264
+ if ($inputText.Length -gt 0) {
265
+ $child.StandardInput.Write($inputText)
266
+ }
267
+ $child.StandardInput.Close()
268
+ }
269
+
270
+ if ($Mode -eq "Inner") {
271
+ if ([string]::IsNullOrWhiteSpace($GateName)) {
272
+ throw "The inner supervisor requires a gate name."
273
+ }
274
+
275
+ $inputText = [Console]::In.ReadToEnd()
276
+ $request = Read-ForgeSupervisorPayload
277
+ $gate = [Threading.EventWaitHandle]::OpenExisting($GateName)
278
+ try {
279
+ if (-not $gate.WaitOne(30000)) {
280
+ throw "Timed out waiting for Windows Job Object assignment."
281
+ }
282
+ }
283
+ finally {
284
+ $gate.Dispose()
285
+ }
286
+
287
+ $provider = New-ForgeChildProcess ([string]$request.command) @($request.args) ([string]$request.cwd) $true
288
+ Write-ForgeProviderReady $request $provider
289
+ $copies = Start-ForgeOutputCopies $provider
290
+ Wait-ForgeProviderStartGrant $request
291
+ Write-ForgeStandardInput $provider $inputText
292
+ $provider.WaitForExit()
293
+ if (-not [Threading.Tasks.Task]::WaitAll([Threading.Tasks.Task[]]$copies, 1000)) {
294
+ $provider.StandardOutput.Dispose()
295
+ $provider.StandardError.Dispose()
296
+ }
297
+ exit $provider.ExitCode
298
+ }
299
+
300
+ $inputText = [Console]::In.ReadToEnd()
301
+ $request = Read-ForgeSupervisorPayload
302
+ $env:FORGE_SUPERVISOR_ROOT_PID = [string]$PID
303
+ $env:FORGE_SUPERVISOR_ROOT_IDENTITY = "win32:$([Diagnostics.Process]::GetCurrentProcess().StartTime.ToUniversalTime().Ticks)"
304
+ $parent = [Diagnostics.Process]::GetProcessById([int]$request.parentPid)
305
+ $jobName = "Local\Forge-$([string]$request.supervisorId)"
306
+ $job = [ForgeWindowsJob]::CreateKillOnCloseJob($jobName)
307
+ $gateNameValue = "Local\ForgeGate-$([Guid]::NewGuid().ToString('N'))"
308
+ $createdNew = $false
309
+ $gate = New-Object Threading.EventWaitHandle($false, [Threading.EventResetMode]::ManualReset, $gateNameValue, [ref]$createdNew)
310
+ $inner = $null
311
+
312
+ try {
313
+ $powerShell = Join-Path $PSHOME "powershell.exe"
314
+ $innerArguments = @(
315
+ "-NoLogo",
316
+ "-NoProfile",
317
+ "-NonInteractive",
318
+ "-ExecutionPolicy",
319
+ "Bypass",
320
+ "-File",
321
+ $PSCommandPath,
322
+ "-Mode",
323
+ "Inner",
324
+ "-PayloadPath",
325
+ $PayloadPath,
326
+ "-GateName",
327
+ $gateNameValue
328
+ )
329
+ $inner = New-ForgeChildProcess $powerShell $innerArguments ([string]$request.cwd) $true
330
+ if (-not [ForgeWindowsJob]::AssignProcessToJobObject($job, $inner.Handle)) {
331
+ throw (New-Object System.ComponentModel.Win32Exception([Runtime.InteropServices.Marshal]::GetLastWin32Error(), "AssignProcessToJobObject failed."))
332
+ }
333
+
334
+ $copies = Start-ForgeOutputCopies $inner
335
+ $gate.Set() | Out-Null
336
+ Write-ForgeStandardInput $inner $inputText
337
+ while (-not $inner.WaitForExit(250)) {
338
+ $parent.Refresh()
339
+ if ($parent.HasExited) {
340
+ [ForgeWindowsJob]::TerminateJobObject($job, 125) | Out-Null
341
+ exit 125
342
+ }
343
+ }
344
+
345
+ $exitCode = $inner.ExitCode
346
+ [ForgeWindowsJob]::TerminateJobObject($job, 1) | Out-Null
347
+ [Threading.Tasks.Task]::WaitAll([Threading.Tasks.Task[]]$copies, 2000) | Out-Null
348
+ exit $exitCode
349
+ }
350
+ finally {
351
+ if ($inner -and -not $inner.HasExited) {
352
+ [ForgeWindowsJob]::TerminateJobObject($job, 1) | Out-Null
353
+ }
354
+ $gate.Dispose()
355
+ [ForgeWindowsJob]::CloseHandle($job) | Out-Null
356
+ }
@@ -0,0 +1,33 @@
1
+ param(
2
+ [Parameter(Mandatory = $true)]
3
+ [int]$RootProcessId,
4
+ [Parameter(Mandatory = $true)]
5
+ [string]$ListenerProcessIds
6
+ )
7
+
8
+ $ErrorActionPreference = "Stop"
9
+ $parents = @{}
10
+ Get-CimInstance Win32_Process | ForEach-Object {
11
+ $parents[[int]$_.ProcessId] = [int]$_.ParentProcessId
12
+ }
13
+
14
+ $results = @()
15
+ foreach ($listenerText in $ListenerProcessIds.Split(',')) {
16
+ $current = [int]$listenerText
17
+ $visited = @{}
18
+ $owned = $false
19
+ while ($current -gt 0 -and -not $visited.ContainsKey($current)) {
20
+ if ($current -eq $RootProcessId) {
21
+ $owned = $true
22
+ break
23
+ }
24
+ $visited[$current] = $true
25
+ if (-not $parents.ContainsKey($current)) {
26
+ break
27
+ }
28
+ $current = [int]$parents[$current]
29
+ }
30
+ $results += $owned
31
+ }
32
+
33
+ ConvertTo-Json -Compress -InputObject @($results)