@loucompanion/forge-bridge 0.1.3-dev.b6be5e7f9668 → 0.1.3-dev.ba7d36726eda
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/README.md +78 -0
- package/dist/bridge/bridge.base.d.ts +5 -1
- package/dist/bridge/bridge.service.d.ts +52 -3
- package/dist/bridge/bridge.service.js +796 -22
- package/dist/bridge/bridge.types.d.ts +135 -1
- package/dist/cleanup/cleanup.service.d.ts +13 -2
- package/dist/cleanup/cleanup.service.js +435 -3
- package/dist/cleanup/cleanup.types.d.ts +10 -0
- package/dist/cleanup/index.d.ts +1 -1
- package/dist/cleanup/index.js +1 -1
- package/dist/cleanup/internals.d.ts +2 -2
- package/dist/cleanup/internals.js +1 -1
- package/dist/cli/cli.help.d.ts +2 -0
- package/dist/cli/cli.help.js +217 -0
- package/dist/cli/cli.service.d.ts +42 -2
- package/dist/cli/cli.service.js +356 -205
- package/dist/cli/local-config.d.ts +6 -0
- package/dist/cli/local-config.js +45 -2
- package/dist/runtime/attempt-node-runtime-launcher.d.ts +15 -0
- package/dist/runtime/attempt-node-runtime-launcher.js +50 -0
- package/dist/runtime/attempt-process-supervisor-registry.d.ts +20 -0
- package/dist/runtime/attempt-process-supervisor-registry.js +64 -0
- package/dist/runtime/attempt-process-supervisor.d.ts +74 -0
- package/dist/runtime/attempt-process-supervisor.js +290 -0
- package/dist/runtime/host-listener-inspector.d.ts +28 -0
- package/dist/runtime/host-listener-inspector.js +185 -0
- package/dist/runtime/host-port-broker.d.ts +76 -0
- package/dist/runtime/host-port-broker.js +333 -0
- package/dist/runtime/host-runtime-contract.d.ts +39 -0
- package/dist/runtime/host-runtime-contract.js +295 -0
- package/dist/runtime/host-runtime-lease.d.ts +122 -0
- package/dist/runtime/host-runtime-lease.js +1241 -0
- package/dist/runtime/host-runtime-promotion.d.ts +21 -0
- package/dist/runtime/host-runtime-promotion.js +128 -0
- package/dist/runtime/node-host-runtime-adapter.d.ts +44 -0
- package/dist/runtime/node-host-runtime-adapter.js +205 -0
- package/dist/runtime/playwright-host-runtime-adapter.d.ts +20 -0
- package/dist/runtime/playwright-host-runtime-adapter.js +136 -0
- package/dist/runtime/runtime-isolation-lease.d.ts +67 -0
- package/dist/runtime/runtime-isolation-lease.js +158 -0
- package/dist/sandbox/command-runner.d.ts +4 -0
- package/dist/sandbox/command-runner.js +47 -0
- package/dist/sandbox/contract.d.ts +5 -0
- package/dist/sandbox/contract.js +276 -0
- package/dist/sandbox/event-budget.d.ts +11 -0
- package/dist/sandbox/event-budget.js +27 -0
- package/dist/sandbox/image-policy.d.ts +35 -0
- package/dist/sandbox/image-policy.js +247 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +5 -0
- package/dist/sandbox/lease-watchdog.d.ts +18 -0
- package/dist/sandbox/lease-watchdog.js +67 -0
- package/dist/sandbox/preflight.d.ts +45 -0
- package/dist/sandbox/preflight.js +300 -0
- package/dist/sandbox/process.d.ts +20 -0
- package/dist/sandbox/process.js +209 -0
- package/dist/sandbox/provider-auth/codex.d.ts +26 -0
- package/dist/sandbox/provider-auth/codex.js +212 -0
- package/dist/sandbox/repository-lock.d.ts +5 -0
- package/dist/sandbox/repository-lock.js +119 -0
- package/dist/sandbox/runtime.d.ts +297 -0
- package/dist/sandbox/runtime.js +2338 -0
- package/dist/sandbox/sandbox.types.d.ts +86 -0
- package/dist/sandbox/sandbox.types.js +1 -0
- package/dist/sandbox/smoke.d.ts +76 -0
- package/dist/sandbox/smoke.js +380 -0
- package/dist/sandbox/worker-supervisor.d.ts +13 -0
- package/dist/sandbox/worker-supervisor.js +36 -0
- package/dist/sandbox/worker.d.ts +1 -0
- package/dist/sandbox/worker.js +225 -0
- package/dist/sandbox/workspace.service.d.ts +13 -0
- package/dist/sandbox/workspace.service.js +67 -0
- package/dist/session/phase-completion.artifacts.d.ts +10 -0
- package/dist/session/phase-completion.artifacts.js +620 -0
- package/dist/session/phase-completion.d.ts +32 -44
- package/dist/session/phase-completion.helpers.d.ts +112 -0
- package/dist/session/phase-completion.helpers.js +665 -0
- package/dist/session/phase-completion.js +28 -3485
- package/dist/session/phase-completion.prompts.d.ts +14 -0
- package/dist/session/phase-completion.prompts.js +220 -0
- package/dist/session/phase-completion.runtime.d.ts +36 -0
- package/dist/session/phase-completion.runtime.js +611 -0
- package/dist/session/phase-completion.schemas.d.ts +3 -0
- package/dist/session/phase-completion.schemas.js +707 -0
- package/dist/session/phase-completion.validation.d.ts +34 -0
- package/dist/session/phase-completion.validation.js +724 -0
- package/dist/session/provider-cli/provider-cli.artifacts.d.ts +93 -0
- package/dist/session/provider-cli/provider-cli.artifacts.js +778 -0
- package/dist/session/provider-cli/provider-cli.base.d.ts +1 -0
- package/dist/session/provider-cli/provider-cli.deterministic-payloads.d.ts +12 -0
- package/dist/session/provider-cli/provider-cli.deterministic-payloads.js +279 -0
- package/dist/session/provider-cli/provider-cli.deterministic.d.ts +14 -0
- package/dist/session/provider-cli/provider-cli.deterministic.js +329 -0
- package/dist/session/provider-cli/provider-cli.process.d.ts +34 -0
- package/dist/session/provider-cli/provider-cli.process.js +316 -0
- package/dist/session/provider-cli/provider-cli.prompts.d.ts +47 -0
- package/dist/session/provider-cli/provider-cli.prompts.js +573 -0
- package/dist/session/provider-cli/provider-cli.qa-sidecars.d.ts +11 -0
- package/dist/session/provider-cli/provider-cli.qa-sidecars.js +65 -0
- package/dist/session/provider-cli/provider-cli.runtime.d.ts +9 -0
- package/dist/session/provider-cli/provider-cli.runtime.js +41 -0
- package/dist/session/provider-cli/provider-cli.service.d.ts +9 -53
- package/dist/session/provider-cli/provider-cli.service.js +182 -2536
- package/dist/session/provider-cli/provider-cli.types.d.ts +3 -0
- package/dist/session/provider-cli/provider-output-state.d.ts +20 -0
- package/dist/session/provider-cli/provider-output-state.js +445 -0
- package/dist/session/session-redaction.d.ts +3 -0
- package/dist/session/session-redaction.js +23 -0
- package/dist/session/session.base.d.ts +4 -0
- package/dist/session/session.service.d.ts +6 -1
- package/dist/session/session.service.js +202 -53
- package/dist/session/session.types.d.ts +123 -1
- package/dist/session/session.types.js +301 -3
- package/dist/shared/path/path.js +3 -1
- package/dist/shared/process/host-process-recovery.d.ts +12 -0
- package/dist/shared/process/host-process-recovery.js +78 -0
- package/dist/shared/process/host-process-supervisor.d.ts +40 -0
- package/dist/shared/process/host-process-supervisor.js +195 -0
- package/dist/shared/process/windows-launch.d.ts +8 -0
- package/dist/shared/process/windows-launch.js +41 -0
- package/dist/shared/provider-capabilities.d.ts +1 -0
- package/dist/shared/provider-capabilities.js +3 -0
- package/dist/shared/redaction/redaction.js +10 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worktree/artifact-injector.js +39 -6
- package/dist/worktree/dependency-warmer.d.ts +11 -0
- package/dist/worktree/dependency-warmer.js +45 -1
- package/dist/worktree/index.d.ts +1 -0
- package/dist/worktree/index.js +1 -0
- package/dist/worktree/prior-phase-artifact-hydrator.d.ts +2 -0
- package/dist/worktree/prior-phase-artifact-hydrator.js +136 -0
- package/dist/worktree/worktree-paths.d.ts +4 -0
- package/dist/worktree/worktree-paths.js +30 -0
- package/dist/worktree/worktree.base.d.ts +3 -0
- package/dist/worktree/worktree.service.d.ts +8 -3
- package/dist/worktree/worktree.service.js +89 -52
- package/dist/worktree/worktree.types.d.ts +3 -1
- package/package.json +6 -3
- package/runtime/windows-job-supervisor.ps1 +287 -0
- package/runtime/windows-listener-owner.ps1 +33 -0
|
@@ -1,12 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { redactRunnerDispatchEvent, redactRunOnceResultPacket } from "./session-redaction.js";
|
|
2
2
|
import { RoutingProviderCliService } from "./provider-cli/provider-cli.service.js";
|
|
3
3
|
import { GitWorktreeService } from "../worktree/worktree.service.js";
|
|
4
|
+
import { SandboxWorkspaceService } from "../sandbox/workspace.service.js";
|
|
5
|
+
import { HostRuntimeAdmissionExpiredError, hostRuntimeEventResources, } from "../runtime/host-runtime-lease.js";
|
|
4
6
|
export class BridgeSessionService {
|
|
5
7
|
worktrees;
|
|
6
8
|
providerCli;
|
|
7
|
-
|
|
9
|
+
hostRuntime;
|
|
10
|
+
constructor(worktrees = process.env.FORGE_SANDBOX_ID
|
|
11
|
+
? new SandboxWorkspaceService()
|
|
12
|
+
: new GitWorktreeService(), providerCli = new RoutingProviderCliService(), hostRuntime) {
|
|
8
13
|
this.worktrees = worktrees;
|
|
9
14
|
this.providerCli = providerCli;
|
|
15
|
+
this.hostRuntime = hostRuntime;
|
|
16
|
+
}
|
|
17
|
+
async updateLease(dispatchAttemptId, fencingToken, expiresAt) {
|
|
18
|
+
await this.hostRuntime?.updateLease(dispatchAttemptId, fencingToken, expiresAt);
|
|
19
|
+
}
|
|
20
|
+
async reapHostRuntime(options) {
|
|
21
|
+
return await this.hostRuntime?.reap?.(options) ?? null;
|
|
22
|
+
}
|
|
23
|
+
runtimeCapacity() {
|
|
24
|
+
return this.hostRuntime?.snapshot?.() ?? null;
|
|
10
25
|
}
|
|
11
26
|
async runOnce(dispatch, sink, signal) {
|
|
12
27
|
validateApiKeySecretGrant(dispatch);
|
|
@@ -16,7 +31,12 @@ export class BridgeSessionService {
|
|
|
16
31
|
if (signal?.aborted) {
|
|
17
32
|
return;
|
|
18
33
|
}
|
|
19
|
-
const redacted =
|
|
34
|
+
const redacted = redactRunnerDispatchEvent(event, redactionSecrets);
|
|
35
|
+
events.push(redacted);
|
|
36
|
+
await sink.emit(redacted);
|
|
37
|
+
};
|
|
38
|
+
const emitLifecycle = async (event) => {
|
|
39
|
+
const redacted = redactRunnerDispatchEvent(event, redactionSecrets);
|
|
20
40
|
events.push(redacted);
|
|
21
41
|
await sink.emit(redacted);
|
|
22
42
|
};
|
|
@@ -27,59 +47,142 @@ export class BridgeSessionService {
|
|
|
27
47
|
content: "forge-bridge accepted run-once dispatch.",
|
|
28
48
|
eventType: "dispatch_accepted"
|
|
29
49
|
});
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
let worktree = null;
|
|
51
|
+
let hostSingletonKeys = null;
|
|
52
|
+
let hostLease = null;
|
|
53
|
+
try {
|
|
54
|
+
if (dispatch.sandbox?.executionMode === "host" && this.hostRuntime) {
|
|
55
|
+
await emitLifecycle({
|
|
56
|
+
role: "runner",
|
|
57
|
+
kind: "checkpoint",
|
|
58
|
+
content: "Evaluating runner-local managed host admission before preparing the worktree.",
|
|
59
|
+
eventType: "host_runtime_admission_waiting",
|
|
60
|
+
});
|
|
61
|
+
try {
|
|
62
|
+
hostSingletonKeys = await this.hostRuntime.acquire(dispatch, signal);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error instanceof HostRuntimeAdmissionExpiredError) {
|
|
66
|
+
await emitLifecycle({
|
|
67
|
+
role: "runner",
|
|
68
|
+
kind: "error",
|
|
69
|
+
content: "Managed host admission expired while the project singleton remained busy; no worktree or runtime resources were created.",
|
|
70
|
+
eventType: "host_runtime_admission_expired",
|
|
71
|
+
}).catch(() => undefined);
|
|
72
|
+
}
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
throwIfAborted(signal);
|
|
76
|
+
await emitLifecycle({
|
|
77
|
+
role: "runner",
|
|
78
|
+
kind: "checkpoint",
|
|
79
|
+
content: hostSingletonKeys.length > 0
|
|
80
|
+
? `Acquired managed host singleton ${hostSingletonKeys.join(", ")}.`
|
|
81
|
+
: "Observed assigned-port evidence permits provisional parallel host admission; the prepared runtime contract must still match before launch.",
|
|
82
|
+
eventType: "host_runtime_admission_acquired",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
worktree = await this.worktrees.prepare({
|
|
86
|
+
repo: dispatch.repo,
|
|
87
|
+
workItem: dispatch.workItem,
|
|
88
|
+
baseBranch: dispatch.cycleRun.baseBranch || dispatch.cycleRun.requestedBase,
|
|
89
|
+
worktreeKey: dispatch.lease.worktreeKey,
|
|
90
|
+
ownerType: dispatch.cycleRun.ownerType ?? dispatch.lease.ownerType ?? null,
|
|
91
|
+
ownerId: dispatch.cycleRun.ownerId ?? dispatch.lease.ownerId ?? null,
|
|
92
|
+
lane: dispatch.execution.lane,
|
|
93
|
+
phase: dispatch.cycleRun.phase,
|
|
94
|
+
allowedRepoRoot: dispatch.serverLocal.repoRoot,
|
|
95
|
+
cleanupWorktrees: dispatch.serverLocal.cleanupWorktrees,
|
|
96
|
+
artifacts: dispatch.artifacts,
|
|
97
|
+
priorPhaseArtifacts: dispatch.priorPhaseArtifacts,
|
|
98
|
+
qaRework: dispatch.qaRework,
|
|
99
|
+
warmPathOverrides: dispatch.warmPathOverrides
|
|
35
100
|
});
|
|
101
|
+
const providerDispatch = withPreparedQaReworkPacket(dispatch, worktree.qaReworkPacketPath);
|
|
36
102
|
throwIfAborted(signal);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
103
|
+
await emit({
|
|
104
|
+
role: "runner",
|
|
105
|
+
kind: "checkpoint",
|
|
106
|
+
content: `Prepared worktree ${worktree.branchName}.`,
|
|
107
|
+
eventType: "worktree_prepared"
|
|
108
|
+
});
|
|
109
|
+
if ((worktree.hydratedPriorPhaseArtifactCount ?? 0) > 0) {
|
|
110
|
+
await emit({
|
|
111
|
+
role: "runner",
|
|
112
|
+
kind: "checkpoint",
|
|
113
|
+
content: `Hydrated ${worktree.hydratedPriorPhaseArtifactCount} persisted prior-phase artifact(s) into the prepared worktree.`,
|
|
114
|
+
eventType: "prior_phase_artifacts_hydrated"
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (worktree.dependencyWarm) {
|
|
118
|
+
await emitDependencyWarmEvents(worktree.dependencyWarm, emit);
|
|
119
|
+
}
|
|
120
|
+
if (dispatch.sandbox?.executionMode === "host" && this.hostRuntime) {
|
|
121
|
+
hostLease = await this.hostRuntime.start(dispatch, worktree.worktreePath, signal);
|
|
122
|
+
await emitLifecycle({
|
|
123
|
+
role: "runner",
|
|
124
|
+
kind: "checkpoint",
|
|
125
|
+
content: `Host runtime lease ${hostLease.lease.leaseId} is active for this worktree.`,
|
|
126
|
+
eventType: "sandbox_started",
|
|
127
|
+
occurredAt: hostLease.lease.stateChangedAt,
|
|
128
|
+
data: JSON.stringify(hostRuntimeEventResources(hostLease.lease, hostLease.runtimeContract)),
|
|
129
|
+
});
|
|
130
|
+
await emitLifecycle({
|
|
131
|
+
role: "runner",
|
|
132
|
+
kind: "checkpoint",
|
|
133
|
+
content: "Managed host fallback isolates the worktree, attempt paths, assigned loopback ports, and supervised process trees, but not the host filesystem, network, credentials, or kernel. Serialized projects also hold a runner-local singleton. Enable Run in Docker in Project Settings when stronger isolation is required.",
|
|
134
|
+
eventType: "host_runtime_isolation_notice",
|
|
135
|
+
data: JSON.stringify({
|
|
136
|
+
isolationStrength: "managed_host_process",
|
|
137
|
+
remediation: "Enable Run in Docker in Project Settings.",
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
const unconfiguredPortCount = hostLease.lease.resources.ports.length;
|
|
141
|
+
hostLease = await this.hostRuntime.startConfiguredProject(dispatch.sandbox.dispatchAttemptId, dispatch.lease.fencingToken, signal);
|
|
142
|
+
if (hostLease.lease.resources.ports.length > unconfiguredPortCount) {
|
|
143
|
+
const assigned = hostLease.lease.resources.ports.at(-1);
|
|
144
|
+
await emitLifecycle({
|
|
145
|
+
role: "runner",
|
|
146
|
+
kind: "checkpoint",
|
|
147
|
+
content: `Verified supervised project runtime ${assigned.name} on ${assigned.hostIp}:${assigned.hostPort}.`,
|
|
148
|
+
eventType: "host_runtime_project_ready",
|
|
149
|
+
data: JSON.stringify(hostRuntimeEventResources(hostLease.lease, hostLease.runtimeContract)),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (dispatch.draft) {
|
|
154
|
+
throwIfAborted(signal);
|
|
155
|
+
const run = await this.providerCli.runDraft({
|
|
156
|
+
dispatch: providerDispatch,
|
|
157
|
+
worktree,
|
|
158
|
+
runtimeEnvironment: hostLease?.environment,
|
|
159
|
+
emit,
|
|
160
|
+
signal
|
|
161
|
+
});
|
|
162
|
+
throwIfAborted(signal);
|
|
163
|
+
const draftArtifacts = run.artifacts?.length ? run.artifacts : run.artifact ? [run.artifact] : [];
|
|
164
|
+
return redactRunOnceResultPacket({
|
|
165
|
+
schemaVersion: 1,
|
|
166
|
+
exitCode: 0,
|
|
167
|
+
summary: run.summary,
|
|
168
|
+
events,
|
|
169
|
+
spec: run.spec ?? null,
|
|
170
|
+
artifact: run.artifact ?? null,
|
|
171
|
+
artifacts: draftArtifacts
|
|
172
|
+
}, redactionSecrets);
|
|
173
|
+
}
|
|
74
174
|
throwIfAborted(signal);
|
|
75
|
-
const lane = dispatch.execution.lane.toLowerCase();
|
|
76
|
-
const role = dispatch.execution.role.toLowerCase();
|
|
175
|
+
const lane = dispatch.execution.lane.trim().toLowerCase();
|
|
176
|
+
const role = dispatch.execution.role.trim().toLowerCase();
|
|
177
|
+
const cycleKind = dispatch.cycleRun.kind.trim().toLowerCase();
|
|
77
178
|
const isQa = role === "qa" || lane === "qa";
|
|
78
|
-
const isArchitect = role === "architect" || lane === "architect" ||
|
|
179
|
+
const isArchitect = role === "architect" || lane === "architect" || cycleKind === "architect";
|
|
180
|
+
const isCiRepair = role === "ci_repair" || lane === "ci_repair" || cycleKind === "pr_checks";
|
|
79
181
|
const isConflictResolve = role === "conflict_resolve" || lane === "conflict_resolve";
|
|
80
182
|
const context = {
|
|
81
183
|
dispatch: providerDispatch,
|
|
82
184
|
worktree,
|
|
185
|
+
runtimeEnvironment: hostLease?.environment,
|
|
83
186
|
emit,
|
|
84
187
|
signal
|
|
85
188
|
};
|
|
@@ -87,12 +190,14 @@ export class BridgeSessionService {
|
|
|
87
190
|
? await this.providerCli.runQa(context)
|
|
88
191
|
: isArchitect
|
|
89
192
|
? await this.providerCli.runArchitect(context)
|
|
90
|
-
:
|
|
91
|
-
? await this.providerCli.
|
|
92
|
-
:
|
|
193
|
+
: isCiRepair
|
|
194
|
+
? await this.providerCli.runCiRepair(context)
|
|
195
|
+
: isConflictResolve
|
|
196
|
+
? await this.providerCli.runConflictResolve(context)
|
|
197
|
+
: await this.providerCli.runImplementation(context);
|
|
93
198
|
throwIfAborted(signal);
|
|
94
199
|
const phaseArtifacts = run.artifacts?.length ? run.artifacts : run.artifact ? [run.artifact] : [];
|
|
95
|
-
return
|
|
200
|
+
return redactRunOnceResultPacket({
|
|
96
201
|
schemaVersion: 1,
|
|
97
202
|
exitCode: 0,
|
|
98
203
|
summary: run.summary,
|
|
@@ -103,7 +208,51 @@ export class BridgeSessionService {
|
|
|
103
208
|
}, redactionSecrets);
|
|
104
209
|
}
|
|
105
210
|
finally {
|
|
106
|
-
|
|
211
|
+
if (hostLease && dispatch.sandbox) {
|
|
212
|
+
const teardownAt = new Date().toISOString();
|
|
213
|
+
await emitLifecycle({
|
|
214
|
+
role: "runner",
|
|
215
|
+
kind: "checkpoint",
|
|
216
|
+
content: `Releasing host runtime lease ${hostLease.lease.leaseId}.`,
|
|
217
|
+
eventType: "sandbox_teardown_started",
|
|
218
|
+
occurredAt: teardownAt,
|
|
219
|
+
}).catch(() => undefined);
|
|
220
|
+
try {
|
|
221
|
+
const released = await this.hostRuntime?.release(dispatch.sandbox.dispatchAttemptId, dispatch.lease.fencingToken);
|
|
222
|
+
if (!released) {
|
|
223
|
+
await emitLifecycle({
|
|
224
|
+
role: "runner",
|
|
225
|
+
kind: "error",
|
|
226
|
+
content: "Host runtime cleanup requires reconciliation: the runtime lease was not current during release.",
|
|
227
|
+
eventType: "teardown_failed",
|
|
228
|
+
occurredAt: new Date().toISOString(),
|
|
229
|
+
}).catch(() => undefined);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
await emitLifecycle({
|
|
233
|
+
role: "runner",
|
|
234
|
+
kind: "checkpoint",
|
|
235
|
+
content: `Released host runtime lease ${released.leaseId}.`,
|
|
236
|
+
eventType: "sandbox_teardown_completed",
|
|
237
|
+
occurredAt: released.releasedAt,
|
|
238
|
+
}).catch(() => undefined);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
await emitLifecycle({
|
|
243
|
+
role: "runner",
|
|
244
|
+
kind: "error",
|
|
245
|
+
content: `Host runtime cleanup requires reconciliation: ${error instanceof Error ? error.message : String(error)}`,
|
|
246
|
+
eventType: "teardown_failed",
|
|
247
|
+
occurredAt: new Date().toISOString(),
|
|
248
|
+
}).catch(() => undefined);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (!hostLease && hostSingletonKeys && dispatch.sandbox) {
|
|
252
|
+
await this.hostRuntime?.release(dispatch.sandbox.dispatchAttemptId, dispatch.lease.fencingToken).catch(() => undefined);
|
|
253
|
+
}
|
|
254
|
+
if (worktree)
|
|
255
|
+
await this.worktrees.release(worktree);
|
|
107
256
|
}
|
|
108
257
|
}
|
|
109
258
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface RunOnceDispatchPacket {
|
|
2
|
-
readonly schemaVersion: 1;
|
|
2
|
+
readonly schemaVersion: 1 | 2;
|
|
3
3
|
readonly userId: string;
|
|
4
4
|
readonly workItem: DispatchWorkItem;
|
|
5
5
|
readonly repo: DispatchRepo;
|
|
@@ -8,24 +8,76 @@ export interface RunOnceDispatchPacket {
|
|
|
8
8
|
readonly lease: DispatchLease;
|
|
9
9
|
readonly execution: DispatchExecution;
|
|
10
10
|
readonly serverLocal: DispatchServerLocalConfig;
|
|
11
|
+
readonly sandbox?: DispatchSandboxContext | null;
|
|
11
12
|
readonly pullRequest?: DispatchPullRequestContext | null;
|
|
12
13
|
readonly apiKeySecretGrant?: ApiKeySecretGrant | null;
|
|
14
|
+
readonly apiKeySecretGrantHandle?: ApiKeySecretGrantHandle | null;
|
|
13
15
|
readonly artifacts: readonly DispatchResolvedArtifact[];
|
|
16
|
+
readonly priorPhaseArtifacts?: readonly DispatchPriorPhaseArtifact[];
|
|
14
17
|
readonly warmPathOverrides?: readonly string[];
|
|
15
18
|
readonly qaBrowser?: DispatchQaBrowserContext | null;
|
|
16
19
|
readonly qaScope?: DispatchQaScope | null;
|
|
17
20
|
readonly qaRework?: DispatchQaReworkContext | null;
|
|
18
21
|
readonly architectRevision?: DispatchArchitectRevisionContext | null;
|
|
22
|
+
readonly architectDependencies?: DispatchArchitectDependencyContext | null;
|
|
19
23
|
readonly storyDevelop?: DispatchStoryDevelopContext | null;
|
|
20
24
|
readonly storyQa?: DispatchStoryQaContext | null;
|
|
25
|
+
readonly designerRefs?: DispatchDesignerRefHandoffContext | null;
|
|
21
26
|
readonly draft?: DispatchDraftPrompt | null;
|
|
22
27
|
}
|
|
28
|
+
export interface DispatchSandboxContext {
|
|
29
|
+
readonly dispatchAttemptId: string;
|
|
30
|
+
readonly executionLeaseId: string;
|
|
31
|
+
readonly runnerInstanceId: string;
|
|
32
|
+
readonly executionMode: "host" | "docker";
|
|
33
|
+
readonly executionPolicy: "host_allowed" | "sandbox_preferred" | "sandbox_required";
|
|
34
|
+
readonly networkPolicy: DispatchSandboxNetworkPolicy;
|
|
35
|
+
readonly requestedResources: DispatchSandboxResourceRequest;
|
|
36
|
+
readonly runtime?: string | null;
|
|
37
|
+
readonly sandboxConfigCommitSha?: string | null;
|
|
38
|
+
readonly inputCommitSha?: string | null;
|
|
39
|
+
readonly contractDigest?: string | null;
|
|
40
|
+
readonly imageDigest?: string | null;
|
|
41
|
+
readonly publicationMode: "bridge_push" | "shared_filesystem";
|
|
42
|
+
readonly publishGrantHandle?: DispatchPublishGrantHandle | null;
|
|
43
|
+
}
|
|
44
|
+
export interface DispatchPublishGrantHandle {
|
|
45
|
+
readonly grantId: string;
|
|
46
|
+
readonly branch: string;
|
|
47
|
+
readonly expiresAt: string;
|
|
48
|
+
}
|
|
49
|
+
export interface DispatchSandboxResourceRequest {
|
|
50
|
+
readonly sandboxSlots: number;
|
|
51
|
+
readonly cpuMillis: number;
|
|
52
|
+
readonly workerMemoryLimitBytes: number;
|
|
53
|
+
readonly serviceMemoryLimitBytes: number;
|
|
54
|
+
readonly runtimeOverheadBytes: number;
|
|
55
|
+
readonly memoryBytes: number;
|
|
56
|
+
readonly workspaceBytes: number;
|
|
57
|
+
readonly pids: number;
|
|
58
|
+
readonly buildSlots: number;
|
|
59
|
+
}
|
|
60
|
+
export interface DispatchSandboxNetworkPolicy {
|
|
61
|
+
readonly mode: "offline" | "public_allowlist" | "open_public";
|
|
62
|
+
readonly allowedHosts: readonly string[];
|
|
63
|
+
}
|
|
23
64
|
export interface DispatchDraftPrompt {
|
|
24
65
|
readonly kind: string;
|
|
25
66
|
readonly systemPrompt: string;
|
|
26
67
|
readonly userPrompt: string;
|
|
27
68
|
readonly projectName?: string | null;
|
|
28
69
|
readonly repoName?: string | null;
|
|
70
|
+
readonly attachments?: readonly DispatchDraftAttachment[];
|
|
71
|
+
}
|
|
72
|
+
export interface DispatchDraftAttachment {
|
|
73
|
+
readonly index: number;
|
|
74
|
+
readonly fileName: string;
|
|
75
|
+
readonly contentType: string;
|
|
76
|
+
readonly kind: string;
|
|
77
|
+
readonly byteCount: number;
|
|
78
|
+
readonly summary: string;
|
|
79
|
+
readonly textContent?: string | null;
|
|
80
|
+
readonly contentBase64?: string | null;
|
|
29
81
|
}
|
|
30
82
|
export interface DispatchQaBrowserContext {
|
|
31
83
|
readonly required: boolean;
|
|
@@ -69,6 +121,22 @@ export interface DispatchArchitectRevisionContext {
|
|
|
69
121
|
readonly priorContentHash: string;
|
|
70
122
|
readonly feedback: string;
|
|
71
123
|
}
|
|
124
|
+
export interface DispatchArchitectDependencyContext {
|
|
125
|
+
readonly baseBranch: string;
|
|
126
|
+
readonly prerequisites: readonly DispatchArchitectDependencyItemContext[];
|
|
127
|
+
}
|
|
128
|
+
export interface DispatchArchitectDependencyItemContext {
|
|
129
|
+
readonly storyId: string;
|
|
130
|
+
readonly title: string;
|
|
131
|
+
readonly scheduleIndex?: number | null;
|
|
132
|
+
readonly waveIndex?: number | null;
|
|
133
|
+
readonly featureScheduleIndex?: number | null;
|
|
134
|
+
readonly expectedOutput?: string | null;
|
|
135
|
+
readonly handoffSummary?: string | null;
|
|
136
|
+
readonly dependencyReason?: string | null;
|
|
137
|
+
readonly pullRequestNumber?: number | null;
|
|
138
|
+
readonly targetBranch: string;
|
|
139
|
+
}
|
|
72
140
|
export interface DispatchStoryDevelopContext {
|
|
73
141
|
readonly storyWorkItemId: string;
|
|
74
142
|
readonly planId: string;
|
|
@@ -125,6 +193,55 @@ export interface DispatchStoryQaDependencyContext {
|
|
|
125
193
|
readonly fromWorkItemId: string;
|
|
126
194
|
readonly toWorkItemId: string;
|
|
127
195
|
}
|
|
196
|
+
export interface DispatchPriorPhaseArtifact {
|
|
197
|
+
readonly workItemId: string;
|
|
198
|
+
readonly artifactId: string;
|
|
199
|
+
readonly cycleRunId: string;
|
|
200
|
+
readonly phase: "implementation" | "self_review" | "validation";
|
|
201
|
+
readonly status: string;
|
|
202
|
+
readonly producedAt: string;
|
|
203
|
+
readonly sourcePath: string;
|
|
204
|
+
readonly verdictJson: string;
|
|
205
|
+
readonly report: string;
|
|
206
|
+
readonly verdictContentHash: string;
|
|
207
|
+
readonly reportContentHash: string;
|
|
208
|
+
}
|
|
209
|
+
export interface DispatchDesignerRefHandoffContext {
|
|
210
|
+
readonly schemaVersion: number;
|
|
211
|
+
readonly kind: string;
|
|
212
|
+
readonly ownerType: string;
|
|
213
|
+
readonly ownerId: string;
|
|
214
|
+
readonly projectId: string;
|
|
215
|
+
readonly repoId: string;
|
|
216
|
+
readonly title: string;
|
|
217
|
+
readonly refs: readonly DispatchDesignerRefAttachment[];
|
|
218
|
+
}
|
|
219
|
+
export interface DispatchDesignerRefAttachment {
|
|
220
|
+
readonly ref: DispatchDesignerRef;
|
|
221
|
+
readonly reason: string;
|
|
222
|
+
readonly required: boolean;
|
|
223
|
+
readonly source: string;
|
|
224
|
+
readonly lineageKind: string;
|
|
225
|
+
readonly inheritedFromItemType?: string | null;
|
|
226
|
+
readonly inheritedFromItemId?: string | null;
|
|
227
|
+
readonly inheritedFromDesignerRefId?: string | null;
|
|
228
|
+
readonly addedByLane: string;
|
|
229
|
+
readonly sortOrder: number;
|
|
230
|
+
readonly createdAt: string;
|
|
231
|
+
}
|
|
232
|
+
export interface DispatchDesignerRef {
|
|
233
|
+
readonly id: string;
|
|
234
|
+
readonly projectId: string;
|
|
235
|
+
readonly repoId: string;
|
|
236
|
+
readonly refKey: string;
|
|
237
|
+
readonly kind: string;
|
|
238
|
+
readonly path: string;
|
|
239
|
+
readonly anchor?: string | null;
|
|
240
|
+
readonly title: string;
|
|
241
|
+
readonly contentHash: string;
|
|
242
|
+
readonly commitSha: string;
|
|
243
|
+
readonly createdAt: string;
|
|
244
|
+
}
|
|
128
245
|
export interface DispatchPullRequestContext {
|
|
129
246
|
readonly number: number;
|
|
130
247
|
readonly provider: string;
|
|
@@ -214,6 +331,11 @@ export interface ApiKeySecretGrant {
|
|
|
214
331
|
readonly secret: string;
|
|
215
332
|
readonly expiresAt: string;
|
|
216
333
|
}
|
|
334
|
+
export interface ApiKeySecretGrantHandle {
|
|
335
|
+
readonly grantId: string;
|
|
336
|
+
readonly provider: string;
|
|
337
|
+
readonly expiresAt: string;
|
|
338
|
+
}
|
|
217
339
|
export interface DispatchServerLocalConfig {
|
|
218
340
|
readonly repoRoot: string;
|
|
219
341
|
readonly cleanupWorktrees: boolean;
|