@loucompanion/forge-bridge 0.1.3-dev.b6be5e7f9668 → 0.1.3-dev.bca7d0ccee53
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 +6 -1
- package/dist/bridge/bridge.service.d.ts +60 -3
- package/dist/bridge/bridge.service.js +970 -24
- package/dist/bridge/bridge.types.d.ts +172 -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 +357 -206
- package/dist/cli/local-config.d.ts +6 -0
- package/dist/cli/local-config.js +47 -3
- package/dist/runtime/attempt-node-runtime-launcher.d.ts +17 -0
- package/dist/runtime/attempt-node-runtime-launcher.js +101 -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 +86 -0
- package/dist/runtime/attempt-process-supervisor.js +350 -0
- package/dist/runtime/generated-output-reset.d.ts +10 -0
- package/dist/runtime/generated-output-reset.js +103 -0
- package/dist/runtime/host-listener-inspector.d.ts +44 -0
- package/dist/runtime/host-listener-inspector.js +324 -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 +47 -0
- package/dist/runtime/host-runtime-contract.js +700 -0
- package/dist/runtime/host-runtime-lease.d.ts +133 -0
- package/dist/runtime/host-runtime-lease.js +1462 -0
- package/dist/runtime/host-runtime-promotion.d.ts +23 -0
- package/dist/runtime/host-runtime-promotion.js +159 -0
- package/dist/runtime/node-host-runtime-adapter.d.ts +51 -0
- package/dist/runtime/node-host-runtime-adapter.js +268 -0
- package/dist/runtime/playwright-host-runtime-adapter.d.ts +20 -0
- package/dist/runtime/playwright-host-runtime-adapter.js +220 -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 +54 -0
- package/dist/sandbox/preflight.js +335 -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 +72 -0
- package/dist/session/managed-attempt-tools.d.ts +17 -0
- package/dist/session/managed-attempt-tools.js +712 -0
- package/dist/session/phase-completion.artifacts.d.ts +10 -0
- package/dist/session/phase-completion.artifacts.js +627 -0
- package/dist/session/phase-completion.d.ts +43 -46
- package/dist/session/phase-completion.helpers.d.ts +117 -0
- package/dist/session/phase-completion.helpers.js +701 -0
- package/dist/session/phase-completion.js +40 -3488
- package/dist/session/phase-completion.prompts.d.ts +14 -0
- package/dist/session/phase-completion.prompts.js +235 -0
- package/dist/session/phase-completion.runtime.d.ts +48 -0
- package/dist/session/phase-completion.runtime.js +786 -0
- package/dist/session/phase-completion.schemas.d.ts +3 -0
- package/dist/session/phase-completion.schemas.js +812 -0
- package/dist/session/phase-completion.validation.d.ts +37 -0
- package/dist/session/phase-completion.validation.js +850 -0
- package/dist/session/provider-cli/ci-repair-readiness.d.ts +8 -0
- package/dist/session/provider-cli/ci-repair-readiness.js +95 -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 +375 -0
- package/dist/session/provider-cli/provider-cli.process.d.ts +48 -0
- package/dist/session/provider-cli/provider-cli.process.js +474 -0
- package/dist/session/provider-cli/provider-cli.prompts.d.ts +47 -0
- package/dist/session/provider-cli/provider-cli.prompts.js +595 -0
- package/dist/session/provider-cli/provider-cli.qa-sidecars.d.ts +11 -0
- package/dist/session/provider-cli/provider-cli.qa-sidecars.js +66 -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 +26 -53
- package/dist/session/provider-cli/provider-cli.service.js +524 -2571
- package/dist/session/provider-cli/provider-cli.types.d.ts +6 -0
- package/dist/session/provider-cli/provider-output-state.d.ts +22 -0
- package/dist/session/provider-cli/provider-output-state.js +473 -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 +6 -1
- package/dist/session/session.service.d.ts +8 -2
- package/dist/session/session.service.js +480 -58
- package/dist/session/session.types.d.ts +161 -1
- package/dist/session/session.types.js +318 -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 +57 -0
- package/dist/shared/process/host-process-supervisor.js +282 -0
- package/dist/shared/process/process.d.ts +1 -0
- package/dist/shared/process/process.js +1 -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.d.ts +3 -2
- package/dist/worktree/artifact-injector.js +82 -10
- package/dist/worktree/dependency-warmer.d.ts +21 -1
- package/dist/worktree/dependency-warmer.js +138 -5
- 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 +9 -3
- package/dist/worktree/worktree.service.js +100 -52
- package/dist/worktree/worktree.types.d.ts +3 -1
- package/package.json +6 -3
- package/runtime/windows-job-supervisor.ps1 +356 -0
- package/runtime/windows-listener-owner.ps1 +33 -0
|
@@ -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;
|
|
@@ -7,25 +7,82 @@ export interface RunOnceDispatchPacket {
|
|
|
7
7
|
readonly session: DispatchSession;
|
|
8
8
|
readonly lease: DispatchLease;
|
|
9
9
|
readonly execution: DispatchExecution;
|
|
10
|
+
readonly runtimeIntent: DispatchRuntimeIntent;
|
|
10
11
|
readonly serverLocal: DispatchServerLocalConfig;
|
|
12
|
+
readonly sandbox?: DispatchSandboxContext | null;
|
|
11
13
|
readonly pullRequest?: DispatchPullRequestContext | null;
|
|
12
14
|
readonly apiKeySecretGrant?: ApiKeySecretGrant | null;
|
|
15
|
+
readonly apiKeySecretGrantHandle?: ApiKeySecretGrantHandle | null;
|
|
13
16
|
readonly artifacts: readonly DispatchResolvedArtifact[];
|
|
17
|
+
readonly priorPhaseArtifacts?: readonly DispatchPriorPhaseArtifact[];
|
|
14
18
|
readonly warmPathOverrides?: readonly string[];
|
|
15
19
|
readonly qaBrowser?: DispatchQaBrowserContext | null;
|
|
16
20
|
readonly qaScope?: DispatchQaScope | null;
|
|
17
21
|
readonly qaRework?: DispatchQaReworkContext | null;
|
|
18
22
|
readonly architectRevision?: DispatchArchitectRevisionContext | null;
|
|
23
|
+
readonly architectDependencies?: DispatchArchitectDependencyContext | null;
|
|
19
24
|
readonly storyDevelop?: DispatchStoryDevelopContext | null;
|
|
20
25
|
readonly storyQa?: DispatchStoryQaContext | null;
|
|
26
|
+
readonly designerRefs?: DispatchDesignerRefHandoffContext | null;
|
|
21
27
|
readonly draft?: DispatchDraftPrompt | null;
|
|
22
28
|
}
|
|
29
|
+
export interface DispatchRuntimeIntent {
|
|
30
|
+
readonly executionClass: "analysis_only" | "managed_runtime";
|
|
31
|
+
readonly applicationRuntimeRequired: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface DispatchSandboxContext {
|
|
34
|
+
readonly dispatchAttemptId: string;
|
|
35
|
+
readonly executionLeaseId: string;
|
|
36
|
+
readonly runnerInstanceId: string;
|
|
37
|
+
readonly executionMode: "host" | "docker";
|
|
38
|
+
readonly executionPolicy: "host_allowed" | "sandbox_preferred" | "sandbox_required";
|
|
39
|
+
readonly networkPolicy: DispatchSandboxNetworkPolicy;
|
|
40
|
+
readonly requestedResources: DispatchSandboxResourceRequest;
|
|
41
|
+
readonly runtime?: string | null;
|
|
42
|
+
readonly sandboxConfigCommitSha?: string | null;
|
|
43
|
+
readonly inputCommitSha?: string | null;
|
|
44
|
+
readonly contractDigest?: string | null;
|
|
45
|
+
readonly imageDigest?: string | null;
|
|
46
|
+
readonly publicationMode: "bridge_push" | "shared_filesystem";
|
|
47
|
+
readonly publishGrantHandle?: DispatchPublishGrantHandle | null;
|
|
48
|
+
}
|
|
49
|
+
export interface DispatchPublishGrantHandle {
|
|
50
|
+
readonly grantId: string;
|
|
51
|
+
readonly branch: string;
|
|
52
|
+
readonly expiresAt: string;
|
|
53
|
+
}
|
|
54
|
+
export interface DispatchSandboxResourceRequest {
|
|
55
|
+
readonly sandboxSlots: number;
|
|
56
|
+
readonly cpuMillis: number;
|
|
57
|
+
readonly workerMemoryLimitBytes: number;
|
|
58
|
+
readonly serviceMemoryLimitBytes: number;
|
|
59
|
+
readonly runtimeOverheadBytes: number;
|
|
60
|
+
readonly memoryBytes: number;
|
|
61
|
+
readonly workspaceBytes: number;
|
|
62
|
+
readonly pids: number;
|
|
63
|
+
readonly buildSlots: number;
|
|
64
|
+
}
|
|
65
|
+
export interface DispatchSandboxNetworkPolicy {
|
|
66
|
+
readonly mode: "offline" | "public_allowlist" | "open_public";
|
|
67
|
+
readonly allowedHosts: readonly string[];
|
|
68
|
+
}
|
|
23
69
|
export interface DispatchDraftPrompt {
|
|
24
70
|
readonly kind: string;
|
|
25
71
|
readonly systemPrompt: string;
|
|
26
72
|
readonly userPrompt: string;
|
|
27
73
|
readonly projectName?: string | null;
|
|
28
74
|
readonly repoName?: string | null;
|
|
75
|
+
readonly attachments?: readonly DispatchDraftAttachment[];
|
|
76
|
+
}
|
|
77
|
+
export interface DispatchDraftAttachment {
|
|
78
|
+
readonly index: number;
|
|
79
|
+
readonly fileName: string;
|
|
80
|
+
readonly contentType: string;
|
|
81
|
+
readonly kind: string;
|
|
82
|
+
readonly byteCount: number;
|
|
83
|
+
readonly summary: string;
|
|
84
|
+
readonly textContent?: string | null;
|
|
85
|
+
readonly contentBase64?: string | null;
|
|
29
86
|
}
|
|
30
87
|
export interface DispatchQaBrowserContext {
|
|
31
88
|
readonly required: boolean;
|
|
@@ -53,6 +110,7 @@ export interface DispatchQaAppLaunchTarget {
|
|
|
53
110
|
readonly command?: string | null;
|
|
54
111
|
readonly working_directory?: string | null;
|
|
55
112
|
readonly ready_url?: string | null;
|
|
113
|
+
readonly managed_runtime_port?: string | null;
|
|
56
114
|
readonly routes: readonly string[];
|
|
57
115
|
readonly notes?: string | null;
|
|
58
116
|
}
|
|
@@ -69,6 +127,22 @@ export interface DispatchArchitectRevisionContext {
|
|
|
69
127
|
readonly priorContentHash: string;
|
|
70
128
|
readonly feedback: string;
|
|
71
129
|
}
|
|
130
|
+
export interface DispatchArchitectDependencyContext {
|
|
131
|
+
readonly baseBranch: string;
|
|
132
|
+
readonly prerequisites: readonly DispatchArchitectDependencyItemContext[];
|
|
133
|
+
}
|
|
134
|
+
export interface DispatchArchitectDependencyItemContext {
|
|
135
|
+
readonly storyId: string;
|
|
136
|
+
readonly title: string;
|
|
137
|
+
readonly scheduleIndex?: number | null;
|
|
138
|
+
readonly waveIndex?: number | null;
|
|
139
|
+
readonly featureScheduleIndex?: number | null;
|
|
140
|
+
readonly expectedOutput?: string | null;
|
|
141
|
+
readonly handoffSummary?: string | null;
|
|
142
|
+
readonly dependencyReason?: string | null;
|
|
143
|
+
readonly pullRequestNumber?: number | null;
|
|
144
|
+
readonly targetBranch: string;
|
|
145
|
+
}
|
|
72
146
|
export interface DispatchStoryDevelopContext {
|
|
73
147
|
readonly storyWorkItemId: string;
|
|
74
148
|
readonly planId: string;
|
|
@@ -125,6 +199,55 @@ export interface DispatchStoryQaDependencyContext {
|
|
|
125
199
|
readonly fromWorkItemId: string;
|
|
126
200
|
readonly toWorkItemId: string;
|
|
127
201
|
}
|
|
202
|
+
export interface DispatchPriorPhaseArtifact {
|
|
203
|
+
readonly workItemId: string;
|
|
204
|
+
readonly artifactId: string;
|
|
205
|
+
readonly cycleRunId: string;
|
|
206
|
+
readonly phase: "implementation" | "self_review" | "validation";
|
|
207
|
+
readonly status: string;
|
|
208
|
+
readonly producedAt: string;
|
|
209
|
+
readonly sourcePath: string;
|
|
210
|
+
readonly verdictJson: string;
|
|
211
|
+
readonly report: string;
|
|
212
|
+
readonly verdictContentHash: string;
|
|
213
|
+
readonly reportContentHash: string;
|
|
214
|
+
}
|
|
215
|
+
export interface DispatchDesignerRefHandoffContext {
|
|
216
|
+
readonly schemaVersion: number;
|
|
217
|
+
readonly kind: string;
|
|
218
|
+
readonly ownerType: string;
|
|
219
|
+
readonly ownerId: string;
|
|
220
|
+
readonly projectId: string;
|
|
221
|
+
readonly repoId: string;
|
|
222
|
+
readonly title: string;
|
|
223
|
+
readonly refs: readonly DispatchDesignerRefAttachment[];
|
|
224
|
+
}
|
|
225
|
+
export interface DispatchDesignerRefAttachment {
|
|
226
|
+
readonly ref: DispatchDesignerRef;
|
|
227
|
+
readonly reason: string;
|
|
228
|
+
readonly required: boolean;
|
|
229
|
+
readonly source: string;
|
|
230
|
+
readonly lineageKind: string;
|
|
231
|
+
readonly inheritedFromItemType?: string | null;
|
|
232
|
+
readonly inheritedFromItemId?: string | null;
|
|
233
|
+
readonly inheritedFromDesignerRefId?: string | null;
|
|
234
|
+
readonly addedByLane: string;
|
|
235
|
+
readonly sortOrder: number;
|
|
236
|
+
readonly createdAt: string;
|
|
237
|
+
}
|
|
238
|
+
export interface DispatchDesignerRef {
|
|
239
|
+
readonly id: string;
|
|
240
|
+
readonly projectId: string;
|
|
241
|
+
readonly repoId: string;
|
|
242
|
+
readonly refKey: string;
|
|
243
|
+
readonly kind: string;
|
|
244
|
+
readonly path: string;
|
|
245
|
+
readonly anchor?: string | null;
|
|
246
|
+
readonly title: string;
|
|
247
|
+
readonly contentHash: string;
|
|
248
|
+
readonly commitSha: string;
|
|
249
|
+
readonly createdAt: string;
|
|
250
|
+
}
|
|
128
251
|
export interface DispatchPullRequestContext {
|
|
129
252
|
readonly number: number;
|
|
130
253
|
readonly provider: string;
|
|
@@ -214,6 +337,11 @@ export interface ApiKeySecretGrant {
|
|
|
214
337
|
readonly secret: string;
|
|
215
338
|
readonly expiresAt: string;
|
|
216
339
|
}
|
|
340
|
+
export interface ApiKeySecretGrantHandle {
|
|
341
|
+
readonly grantId: string;
|
|
342
|
+
readonly provider: string;
|
|
343
|
+
readonly expiresAt: string;
|
|
344
|
+
}
|
|
217
345
|
export interface DispatchServerLocalConfig {
|
|
218
346
|
readonly repoRoot: string;
|
|
219
347
|
readonly cleanupWorktrees: boolean;
|
|
@@ -263,4 +391,36 @@ export interface RunnerEventLine {
|
|
|
263
391
|
readonly event: RunnerDispatchEvent;
|
|
264
392
|
}
|
|
265
393
|
export declare function parseRunOnceDispatchPacket(value: unknown): RunOnceDispatchPacket;
|
|
394
|
+
export interface HostRuntimeReadinessProbeRequest {
|
|
395
|
+
readonly requestId: string;
|
|
396
|
+
readonly fencingToken: string;
|
|
397
|
+
readonly userId: string;
|
|
398
|
+
readonly projectId: string;
|
|
399
|
+
readonly repoId: string;
|
|
400
|
+
readonly runnerId: string;
|
|
401
|
+
readonly runnerInstanceId: string;
|
|
402
|
+
readonly attempt: number;
|
|
403
|
+
readonly repoName: string;
|
|
404
|
+
readonly remoteUrl: string;
|
|
405
|
+
readonly defaultBranch: string;
|
|
406
|
+
readonly cloneOnDemand: boolean;
|
|
407
|
+
readonly runnerRepoLocalPath: string;
|
|
408
|
+
readonly revision: string;
|
|
409
|
+
readonly expiresAt: string;
|
|
410
|
+
readonly repoRoot: string;
|
|
411
|
+
readonly cleanupWorktrees: boolean;
|
|
412
|
+
}
|
|
413
|
+
export interface HostRuntimeReadinessProbeResult {
|
|
414
|
+
readonly status: "parallel_ready" | "serialized" | "failed";
|
|
415
|
+
readonly runtimeContractFingerprint?: string | null;
|
|
416
|
+
readonly runtimeContractSource?: string | null;
|
|
417
|
+
readonly reasonCode?: string | null;
|
|
418
|
+
readonly reasonMessage?: string | null;
|
|
419
|
+
readonly qaAppLaunchTarget?: HostRuntimeReadinessQaLaunchTarget | null;
|
|
420
|
+
readonly checkedAt: string;
|
|
421
|
+
}
|
|
422
|
+
export interface HostRuntimeReadinessQaLaunchTarget {
|
|
423
|
+
readonly managedRuntimePort: string;
|
|
424
|
+
readonly routes: readonly string[];
|
|
425
|
+
}
|
|
266
426
|
export declare function failureResult(summary: string, events?: readonly RunnerDispatchEvent[]): RunOnceResultPacket;
|
|
@@ -2,11 +2,11 @@ import path from "node:path";
|
|
|
2
2
|
export function parseRunOnceDispatchPacket(value) {
|
|
3
3
|
const packet = asObject(value, "dispatch packet");
|
|
4
4
|
const schemaVersion = requiredNumber(packet, "schemaVersion");
|
|
5
|
-
if (schemaVersion !== 1) {
|
|
5
|
+
if (schemaVersion !== 1 && schemaVersion !== 2) {
|
|
6
6
|
throw new Error(`Unsupported dispatch schemaVersion: ${schemaVersion}`);
|
|
7
7
|
}
|
|
8
8
|
return {
|
|
9
|
-
schemaVersion
|
|
9
|
+
schemaVersion,
|
|
10
10
|
userId: requiredString(packet, "userId"),
|
|
11
11
|
workItem: parseWorkItem(packet.workItem),
|
|
12
12
|
repo: parseRepo(packet.repo),
|
|
@@ -14,20 +14,163 @@ export function parseRunOnceDispatchPacket(value) {
|
|
|
14
14
|
session: parseSession(packet.session),
|
|
15
15
|
lease: parseLease(packet.lease),
|
|
16
16
|
execution: parseExecution(packet.execution),
|
|
17
|
+
runtimeIntent: parseRuntimeIntent(packet.runtimeIntent),
|
|
17
18
|
serverLocal: parseServerLocal(packet.serverLocal),
|
|
19
|
+
sandbox: parseSandbox(packet.sandbox, schemaVersion),
|
|
18
20
|
pullRequest: parsePullRequest(packet.pullRequest),
|
|
19
21
|
apiKeySecretGrant: parseApiKeySecretGrant(packet.apiKeySecretGrant),
|
|
22
|
+
apiKeySecretGrantHandle: parseApiKeySecretGrantHandle(packet.apiKeySecretGrantHandle),
|
|
20
23
|
artifacts: parseArtifacts(packet.artifacts),
|
|
24
|
+
priorPhaseArtifacts: parsePriorPhaseArtifacts(packet.priorPhaseArtifacts),
|
|
21
25
|
warmPathOverrides: parseWarmPathOverrides(packet.warmPathOverrides),
|
|
22
26
|
qaBrowser: parseQaBrowser(packet.qaBrowser),
|
|
23
27
|
qaScope: parseQaScope(packet.qaScope ?? packet.qa_scope),
|
|
24
28
|
qaRework: parseQaRework(packet.qaRework),
|
|
25
29
|
architectRevision: parseArchitectRevision(packet.architectRevision),
|
|
30
|
+
architectDependencies: parseArchitectDependencies(packet.architectDependencies),
|
|
26
31
|
storyDevelop: parseStoryDevelop(packet.storyDevelop),
|
|
27
32
|
storyQa: parseStoryQa(packet.storyQa),
|
|
33
|
+
designerRefs: parseDesignerRefs(packet.designerRefs ?? packet.designer_refs),
|
|
28
34
|
draft: parseDraftPrompt(packet.draft)
|
|
29
35
|
};
|
|
30
36
|
}
|
|
37
|
+
function parseRuntimeIntent(value) {
|
|
38
|
+
if (value === undefined || value === null) {
|
|
39
|
+
return { executionClass: "managed_runtime", applicationRuntimeRequired: true };
|
|
40
|
+
}
|
|
41
|
+
const intent = asObject(value, "runtimeIntent");
|
|
42
|
+
const executionClass = requiredString(intent, "executionClass").trim().toLowerCase();
|
|
43
|
+
if (executionClass !== "analysis_only" && executionClass !== "managed_runtime") {
|
|
44
|
+
throw new Error("runtimeIntent.executionClass must be analysis_only or managed_runtime.");
|
|
45
|
+
}
|
|
46
|
+
const applicationRuntimeRequired = requiredBoolean(intent, "applicationRuntimeRequired");
|
|
47
|
+
if ((executionClass === "analysis_only") === applicationRuntimeRequired) {
|
|
48
|
+
throw new Error("runtimeIntent execution class and application runtime requirement are inconsistent.");
|
|
49
|
+
}
|
|
50
|
+
return { executionClass, applicationRuntimeRequired };
|
|
51
|
+
}
|
|
52
|
+
function parseSandbox(value, schemaVersion) {
|
|
53
|
+
if (value === undefined || value === null) {
|
|
54
|
+
if (schemaVersion === 2) {
|
|
55
|
+
throw new Error("sandbox is required for dispatch schemaVersion 2.");
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const sandbox = asObject(value, "sandbox");
|
|
60
|
+
const executionMode = requiredString(sandbox, "executionMode");
|
|
61
|
+
if (executionMode !== "host" && executionMode !== "docker") {
|
|
62
|
+
throw new Error("sandbox.executionMode must be host or docker.");
|
|
63
|
+
}
|
|
64
|
+
const executionPolicy = requiredString(sandbox, "executionPolicy");
|
|
65
|
+
if (executionPolicy !== "host_allowed" && executionPolicy !== "sandbox_preferred" && executionPolicy !== "sandbox_required") {
|
|
66
|
+
throw new Error("sandbox.executionPolicy is invalid.");
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
dispatchAttemptId: requiredString(sandbox, "dispatchAttemptId"),
|
|
70
|
+
executionLeaseId: requiredString(sandbox, "executionLeaseId"),
|
|
71
|
+
runnerInstanceId: requiredString(sandbox, "runnerInstanceId"),
|
|
72
|
+
executionMode,
|
|
73
|
+
executionPolicy,
|
|
74
|
+
networkPolicy: parseSandboxNetworkPolicy(sandbox.networkPolicy),
|
|
75
|
+
requestedResources: parseSandboxResourceRequest(sandbox.requestedResources),
|
|
76
|
+
runtime: optionalString(sandbox, "runtime"),
|
|
77
|
+
sandboxConfigCommitSha: optionalString(sandbox, "sandboxConfigCommitSha"),
|
|
78
|
+
inputCommitSha: optionalString(sandbox, "inputCommitSha"),
|
|
79
|
+
contractDigest: optionalString(sandbox, "contractDigest"),
|
|
80
|
+
imageDigest: optionalString(sandbox, "imageDigest"),
|
|
81
|
+
publicationMode: parsePublicationMode(sandbox.publicationMode),
|
|
82
|
+
publishGrantHandle: parsePublishGrantHandle(sandbox.publishGrantHandle)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function parsePublicationMode(value) {
|
|
86
|
+
if (value === undefined || value === null)
|
|
87
|
+
return "shared_filesystem";
|
|
88
|
+
if (value !== "bridge_push" && value !== "shared_filesystem")
|
|
89
|
+
throw new Error("sandbox.publicationMode is invalid.");
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
function parsePublishGrantHandle(value) {
|
|
93
|
+
if (value === undefined || value === null)
|
|
94
|
+
return null;
|
|
95
|
+
const handle = asObject(value, "sandbox.publishGrantHandle");
|
|
96
|
+
const grantId = requiredString(handle, "grantId");
|
|
97
|
+
const branch = requiredString(handle, "branch");
|
|
98
|
+
const expiresAt = requiredString(handle, "expiresAt");
|
|
99
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(grantId)) {
|
|
100
|
+
throw new Error("sandbox.publishGrantHandle.grantId is invalid.");
|
|
101
|
+
}
|
|
102
|
+
if (branch.length > 240)
|
|
103
|
+
throw new Error("sandbox.publishGrantHandle.branch is too long.");
|
|
104
|
+
if (!Number.isFinite(Date.parse(expiresAt)))
|
|
105
|
+
throw new Error("sandbox.publishGrantHandle.expiresAt is invalid.");
|
|
106
|
+
return { grantId, branch, expiresAt };
|
|
107
|
+
}
|
|
108
|
+
function parseSandboxResourceRequest(value) {
|
|
109
|
+
if (value === undefined || value === null) {
|
|
110
|
+
return {
|
|
111
|
+
sandboxSlots: 1,
|
|
112
|
+
cpuMillis: 2000,
|
|
113
|
+
workerMemoryLimitBytes: 2 * 1024 ** 3,
|
|
114
|
+
serviceMemoryLimitBytes: 0,
|
|
115
|
+
runtimeOverheadBytes: 128 * 1024 ** 2,
|
|
116
|
+
memoryBytes: 2 * 1024 ** 3 + 128 * 1024 ** 2,
|
|
117
|
+
workspaceBytes: 10 * 1024 ** 3,
|
|
118
|
+
pids: 512,
|
|
119
|
+
buildSlots: 1
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const resources = asObject(value, "sandbox.requestedResources");
|
|
123
|
+
const memoryBytes = boundedInteger(resources, "memoryBytes", 128 * 1024 ** 2, 512 * 1024 ** 3);
|
|
124
|
+
const hasMemoryBreakdown = ["workerMemoryLimitBytes", "serviceMemoryLimitBytes", "runtimeOverheadBytes"]
|
|
125
|
+
.some(key => resources[key] !== undefined && resources[key] !== null);
|
|
126
|
+
const workerMemoryLimitBytes = hasMemoryBreakdown
|
|
127
|
+
? boundedInteger(resources, "workerMemoryLimitBytes", 128 * 1024 ** 2, 512 * 1024 ** 3)
|
|
128
|
+
: memoryBytes;
|
|
129
|
+
const serviceMemoryLimitBytes = hasMemoryBreakdown
|
|
130
|
+
? boundedInteger(resources, "serviceMemoryLimitBytes", 0, 512 * 1024 ** 3)
|
|
131
|
+
: 0;
|
|
132
|
+
const runtimeOverheadBytes = hasMemoryBreakdown
|
|
133
|
+
? boundedInteger(resources, "runtimeOverheadBytes", 0, 64 * 1024 ** 3)
|
|
134
|
+
: 0;
|
|
135
|
+
if (workerMemoryLimitBytes + serviceMemoryLimitBytes + runtimeOverheadBytes !== memoryBytes) {
|
|
136
|
+
throw new Error("sandbox.requestedResources memory breakdown must equal memoryBytes.");
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
sandboxSlots: boundedInteger(resources, "sandboxSlots", 1, 4),
|
|
140
|
+
cpuMillis: boundedInteger(resources, "cpuMillis", 100, 64_000),
|
|
141
|
+
workerMemoryLimitBytes,
|
|
142
|
+
serviceMemoryLimitBytes,
|
|
143
|
+
runtimeOverheadBytes,
|
|
144
|
+
memoryBytes,
|
|
145
|
+
workspaceBytes: boundedInteger(resources, "workspaceBytes", 1024 ** 3, 10 * 1024 ** 4),
|
|
146
|
+
pids: boundedInteger(resources, "pids", 32, 65_536),
|
|
147
|
+
buildSlots: boundedInteger(resources, "buildSlots", 0, 4)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function parseSandboxNetworkPolicy(value) {
|
|
151
|
+
if (value === undefined || value === null)
|
|
152
|
+
return { mode: "offline", allowedHosts: [] };
|
|
153
|
+
const policy = asObject(value, "sandbox.networkPolicy");
|
|
154
|
+
const mode = requiredString(policy, "mode");
|
|
155
|
+
if (mode !== "offline" && mode !== "public_allowlist" && mode !== "open_public") {
|
|
156
|
+
throw new Error("sandbox.networkPolicy.mode is invalid.");
|
|
157
|
+
}
|
|
158
|
+
const rawHosts = policy.allowedHosts ?? [];
|
|
159
|
+
if (!Array.isArray(rawHosts) || rawHosts.some((host) => typeof host !== "string")) {
|
|
160
|
+
throw new Error("sandbox.networkPolicy.allowedHosts must be a string array.");
|
|
161
|
+
}
|
|
162
|
+
const allowedHosts = [...new Set(rawHosts.map(host => host.trim().toLowerCase()).filter(Boolean))];
|
|
163
|
+
if (allowedHosts.length > 128 || allowedHosts.some(host => !/^(?:\*\.)?(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/u.test(host))) {
|
|
164
|
+
throw new Error("sandbox.networkPolicy.allowedHosts contains an invalid hostname.");
|
|
165
|
+
}
|
|
166
|
+
if (mode !== "public_allowlist" && allowedHosts.length > 0) {
|
|
167
|
+
throw new Error("sandbox.networkPolicy.allowedHosts requires public_allowlist mode.");
|
|
168
|
+
}
|
|
169
|
+
if (mode === "public_allowlist" && allowedHosts.length === 0) {
|
|
170
|
+
return { mode: "offline", allowedHosts: [] };
|
|
171
|
+
}
|
|
172
|
+
return { mode, allowedHosts };
|
|
173
|
+
}
|
|
31
174
|
export function failureResult(summary, events = []) {
|
|
32
175
|
return {
|
|
33
176
|
schemaVersion: 1,
|
|
@@ -119,9 +262,45 @@ function parseDraftPrompt(value) {
|
|
|
119
262
|
return {
|
|
120
263
|
kind: requiredString(draft, "kind"),
|
|
121
264
|
systemPrompt: requiredString(draft, "systemPrompt"),
|
|
122
|
-
userPrompt: requiredString(draft, "userPrompt")
|
|
265
|
+
userPrompt: requiredString(draft, "userPrompt"),
|
|
266
|
+
projectName: optionalString(draft, "projectName"),
|
|
267
|
+
repoName: optionalString(draft, "repoName"),
|
|
268
|
+
attachments: parseDraftAttachments(draft.attachments)
|
|
123
269
|
};
|
|
124
270
|
}
|
|
271
|
+
function parseDraftAttachments(value) {
|
|
272
|
+
if (value === undefined || value === null) {
|
|
273
|
+
return [];
|
|
274
|
+
}
|
|
275
|
+
if (!Array.isArray(value)) {
|
|
276
|
+
throw new Error("draft.attachments must be an array when provided.");
|
|
277
|
+
}
|
|
278
|
+
return value.map((entry, index) => {
|
|
279
|
+
const attachment = asObject(entry, `draft.attachments[${index}]`);
|
|
280
|
+
const kind = requiredString(attachment, "kind").trim().toLowerCase();
|
|
281
|
+
if (kind !== "text" && kind !== "image") {
|
|
282
|
+
throw new Error(`draft.attachments[${index}].kind must be text or image.`);
|
|
283
|
+
}
|
|
284
|
+
const textContent = optionalString(attachment, "textContent");
|
|
285
|
+
const contentBase64 = optionalString(attachment, "contentBase64");
|
|
286
|
+
if (kind === "text" && textContent === null) {
|
|
287
|
+
throw new Error(`draft.attachments[${index}].textContent is required for text attachments.`);
|
|
288
|
+
}
|
|
289
|
+
if (kind === "image" && contentBase64 === null) {
|
|
290
|
+
throw new Error(`draft.attachments[${index}].contentBase64 is required for image attachments.`);
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
index: optionalNonNegativeInteger(attachment, "index") ?? index,
|
|
294
|
+
fileName: requiredString(attachment, "fileName"),
|
|
295
|
+
contentType: optionalString(attachment, "contentType") ?? "",
|
|
296
|
+
kind,
|
|
297
|
+
byteCount: optionalNonNegativeInteger(attachment, "byteCount") ?? 0,
|
|
298
|
+
summary: optionalString(attachment, "summary") ?? "",
|
|
299
|
+
textContent,
|
|
300
|
+
contentBase64
|
|
301
|
+
};
|
|
302
|
+
});
|
|
303
|
+
}
|
|
125
304
|
function parseApiKeySecretGrant(value) {
|
|
126
305
|
if (value === undefined || value === null) {
|
|
127
306
|
return null;
|
|
@@ -134,6 +313,16 @@ function parseApiKeySecretGrant(value) {
|
|
|
134
313
|
expiresAt: requiredString(grant, "expiresAt")
|
|
135
314
|
};
|
|
136
315
|
}
|
|
316
|
+
function parseApiKeySecretGrantHandle(value) {
|
|
317
|
+
if (value === undefined || value === null)
|
|
318
|
+
return null;
|
|
319
|
+
const grant = asObject(value, "apiKeySecretGrantHandle");
|
|
320
|
+
return {
|
|
321
|
+
grantId: requiredString(grant, "grantId"),
|
|
322
|
+
provider: requiredString(grant, "provider"),
|
|
323
|
+
expiresAt: requiredString(grant, "expiresAt")
|
|
324
|
+
};
|
|
325
|
+
}
|
|
137
326
|
function parseServerLocal(value) {
|
|
138
327
|
const serverLocal = asObject(value, "serverLocal");
|
|
139
328
|
return {
|
|
@@ -233,6 +422,7 @@ function parseQaAppLaunchTarget(value) {
|
|
|
233
422
|
command: optionalString(launchTarget, "command"),
|
|
234
423
|
working_directory: optionalString(launchTarget, "working_directory"),
|
|
235
424
|
ready_url: optionalString(launchTarget, "ready_url"),
|
|
425
|
+
managed_runtime_port: optionalString(launchTarget, "managed_runtime_port"),
|
|
236
426
|
routes: Array.isArray(routes)
|
|
237
427
|
? routes.map((entry, index) => {
|
|
238
428
|
if (typeof entry !== "string") {
|
|
@@ -282,6 +472,34 @@ function parseArchitectRevision(value) {
|
|
|
282
472
|
feedback: requiredString(revision, "feedback")
|
|
283
473
|
};
|
|
284
474
|
}
|
|
475
|
+
function parseArchitectDependencies(value) {
|
|
476
|
+
if (value === undefined || value === null) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
const context = asObject(value, "architectDependencies");
|
|
480
|
+
const prerequisites = context.prerequisites;
|
|
481
|
+
if (!Array.isArray(prerequisites)) {
|
|
482
|
+
throw new Error("architectDependencies.prerequisites must be an array.");
|
|
483
|
+
}
|
|
484
|
+
return {
|
|
485
|
+
baseBranch: requiredString(context, "baseBranch").trim(),
|
|
486
|
+
prerequisites: prerequisites.map((entry, index) => {
|
|
487
|
+
const prerequisite = asObject(entry, `architectDependencies.prerequisites[${index}]`);
|
|
488
|
+
return {
|
|
489
|
+
storyId: requiredString(prerequisite, "storyId").trim(),
|
|
490
|
+
title: requiredString(prerequisite, "title").trim(),
|
|
491
|
+
scheduleIndex: optionalNonNegativeInteger(prerequisite, "scheduleIndex"),
|
|
492
|
+
waveIndex: optionalNonNegativeInteger(prerequisite, "waveIndex"),
|
|
493
|
+
featureScheduleIndex: optionalNonNegativeInteger(prerequisite, "featureScheduleIndex"),
|
|
494
|
+
expectedOutput: optionalString(prerequisite, "expectedOutput"),
|
|
495
|
+
handoffSummary: optionalString(prerequisite, "handoffSummary"),
|
|
496
|
+
dependencyReason: optionalString(prerequisite, "dependencyReason"),
|
|
497
|
+
pullRequestNumber: optionalPositiveInteger(prerequisite, "pullRequestNumber"),
|
|
498
|
+
targetBranch: requiredString(prerequisite, "targetBranch").trim()
|
|
499
|
+
};
|
|
500
|
+
})
|
|
501
|
+
};
|
|
502
|
+
}
|
|
285
503
|
function parseStoryDevelop(value) {
|
|
286
504
|
if (value === undefined || value === null) {
|
|
287
505
|
return null;
|
|
@@ -387,6 +605,58 @@ function parseStoryQaDependencies(value) {
|
|
|
387
605
|
};
|
|
388
606
|
});
|
|
389
607
|
}
|
|
608
|
+
function parseDesignerRefs(value) {
|
|
609
|
+
if (value === undefined || value === null) {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
const context = asObject(value, "designerRefs");
|
|
613
|
+
const refs = context.refs;
|
|
614
|
+
if (!Array.isArray(refs)) {
|
|
615
|
+
throw new Error("designerRefs.refs must be an array.");
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
schemaVersion: requiredNumber(context, "schemaVersion"),
|
|
619
|
+
kind: requiredString(context, "kind"),
|
|
620
|
+
ownerType: requiredString(context, "ownerType"),
|
|
621
|
+
ownerId: requiredString(context, "ownerId"),
|
|
622
|
+
projectId: requiredString(context, "projectId"),
|
|
623
|
+
repoId: requiredString(context, "repoId"),
|
|
624
|
+
title: requiredString(context, "title"),
|
|
625
|
+
refs: refs.map((entry, index) => parseDesignerRefAttachment(entry, index))
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
function parseDesignerRefAttachment(value, index) {
|
|
629
|
+
const attachment = asObject(value, `designerRefs.refs[${index}]`);
|
|
630
|
+
return {
|
|
631
|
+
ref: parseDesignerRef(attachment.ref, index),
|
|
632
|
+
reason: optionalString(attachment, "reason") ?? "",
|
|
633
|
+
required: requiredBoolean(attachment, "required"),
|
|
634
|
+
source: optionalString(attachment, "source") ?? "",
|
|
635
|
+
lineageKind: optionalString(attachment, "lineageKind") ?? optionalString(attachment, "lineage_kind") ?? "",
|
|
636
|
+
inheritedFromItemType: optionalString(attachment, "inheritedFromItemType") ?? optionalString(attachment, "inherited_from_item_type"),
|
|
637
|
+
inheritedFromItemId: optionalString(attachment, "inheritedFromItemId") ?? optionalString(attachment, "inherited_from_item_id"),
|
|
638
|
+
inheritedFromDesignerRefId: optionalString(attachment, "inheritedFromDesignerRefId") ?? optionalString(attachment, "inherited_from_designer_ref_id"),
|
|
639
|
+
addedByLane: optionalString(attachment, "addedByLane") ?? optionalString(attachment, "added_by_lane") ?? "",
|
|
640
|
+
sortOrder: requiredNumber(attachment, "sortOrder"),
|
|
641
|
+
createdAt: requiredString(attachment, "createdAt")
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
function parseDesignerRef(value, index) {
|
|
645
|
+
const designerRef = asObject(value, `designerRefs.refs[${index}].ref`);
|
|
646
|
+
return {
|
|
647
|
+
id: requiredString(designerRef, "id"),
|
|
648
|
+
projectId: requiredString(designerRef, "projectId"),
|
|
649
|
+
repoId: requiredString(designerRef, "repoId"),
|
|
650
|
+
refKey: requiredString(designerRef, "refKey"),
|
|
651
|
+
kind: requiredString(designerRef, "kind"),
|
|
652
|
+
path: requiredString(designerRef, "path"),
|
|
653
|
+
anchor: optionalString(designerRef, "anchor"),
|
|
654
|
+
title: optionalString(designerRef, "title") ?? "",
|
|
655
|
+
contentHash: requiredString(designerRef, "contentHash"),
|
|
656
|
+
commitSha: requiredString(designerRef, "commitSha"),
|
|
657
|
+
createdAt: requiredString(designerRef, "createdAt")
|
|
658
|
+
};
|
|
659
|
+
}
|
|
390
660
|
function parseStringArray(value, label) {
|
|
391
661
|
if (!Array.isArray(value)) {
|
|
392
662
|
throw new Error(`${label} must be an array.`);
|
|
@@ -431,6 +701,34 @@ function parseArtifacts(value) {
|
|
|
431
701
|
};
|
|
432
702
|
});
|
|
433
703
|
}
|
|
704
|
+
function parsePriorPhaseArtifacts(value) {
|
|
705
|
+
if (value === undefined || value === null) {
|
|
706
|
+
return [];
|
|
707
|
+
}
|
|
708
|
+
if (!Array.isArray(value)) {
|
|
709
|
+
throw new Error("priorPhaseArtifacts must be an array when provided.");
|
|
710
|
+
}
|
|
711
|
+
return value.map((entry, index) => {
|
|
712
|
+
const artifact = asObject(entry, `priorPhaseArtifacts[${index}]`);
|
|
713
|
+
const phase = requiredString(artifact, "phase").trim().toLowerCase().replace(/-/g, "_");
|
|
714
|
+
if (phase !== "implementation" && phase !== "self_review" && phase !== "validation") {
|
|
715
|
+
throw new Error(`priorPhaseArtifacts[${index}].phase must be implementation, self_review, or validation.`);
|
|
716
|
+
}
|
|
717
|
+
return {
|
|
718
|
+
workItemId: requiredString(artifact, "workItemId"),
|
|
719
|
+
artifactId: requiredString(artifact, "artifactId"),
|
|
720
|
+
cycleRunId: requiredString(artifact, "cycleRunId"),
|
|
721
|
+
phase,
|
|
722
|
+
status: requiredString(artifact, "status"),
|
|
723
|
+
producedAt: requiredString(artifact, "producedAt"),
|
|
724
|
+
sourcePath: requiredString(artifact, "sourcePath"),
|
|
725
|
+
verdictJson: requiredString(artifact, "verdictJson"),
|
|
726
|
+
report: optionalString(artifact, "report") ?? "",
|
|
727
|
+
verdictContentHash: requiredString(artifact, "verdictContentHash").toLowerCase(),
|
|
728
|
+
reportContentHash: requiredString(artifact, "reportContentHash").toLowerCase()
|
|
729
|
+
};
|
|
730
|
+
});
|
|
731
|
+
}
|
|
434
732
|
function asObject(value, label) {
|
|
435
733
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
436
734
|
throw new Error(`${label} must be an object.`);
|
|
@@ -481,6 +779,16 @@ function optionalPositiveInteger(source, key) {
|
|
|
481
779
|
}
|
|
482
780
|
return value;
|
|
483
781
|
}
|
|
782
|
+
function optionalNonNegativeInteger(source, key) {
|
|
783
|
+
const value = source[key];
|
|
784
|
+
if (value === undefined || value === null) {
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
788
|
+
throw new Error(`${key} must be a non-negative integer when provided.`);
|
|
789
|
+
}
|
|
790
|
+
return value;
|
|
791
|
+
}
|
|
484
792
|
function requiredNumber(source, key) {
|
|
485
793
|
const value = source[key];
|
|
486
794
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -488,3 +796,10 @@ function requiredNumber(source, key) {
|
|
|
488
796
|
}
|
|
489
797
|
return value;
|
|
490
798
|
}
|
|
799
|
+
function boundedInteger(source, key, minimum, maximum) {
|
|
800
|
+
const value = requiredNumber(source, key);
|
|
801
|
+
if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
|
|
802
|
+
throw new Error(`${key} must be an integer from ${minimum} through ${maximum}.`);
|
|
803
|
+
}
|
|
804
|
+
return value;
|
|
805
|
+
}
|
package/dist/shared/path/path.js
CHANGED
|
@@ -4,7 +4,9 @@ export function isSubPath(root, candidate) {
|
|
|
4
4
|
const normalizedRoot = path.resolve(root);
|
|
5
5
|
const normalizedCandidate = path.resolve(candidate);
|
|
6
6
|
const relative = path.relative(normalizedRoot, normalizedCandidate);
|
|
7
|
-
return relative === "" || (
|
|
7
|
+
return relative === "" || (relative !== ".."
|
|
8
|
+
&& !relative.startsWith(`..${path.sep}`)
|
|
9
|
+
&& !path.isAbsolute(relative));
|
|
8
10
|
}
|
|
9
11
|
export async function resolveExistingDirectoryPath(inputPath) {
|
|
10
12
|
const stat = await fs.stat(inputPath);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HostProcessSupervisorMetadata } from "./host-process-supervisor.js";
|
|
2
|
+
export type HostProcessRecoveryOutcome = "absent" | "terminated" | "pid_reused" | "unverifiable";
|
|
3
|
+
export interface HostProcessRecovery {
|
|
4
|
+
recover(metadata: HostProcessSupervisorMetadata): Promise<HostProcessRecoveryOutcome>;
|
|
5
|
+
}
|
|
6
|
+
/** Exact, birth-marker-fenced recovery for a process tree left by an old bridge. */
|
|
7
|
+
export declare class ExactHostProcessRecovery implements HostProcessRecovery {
|
|
8
|
+
private readonly platform;
|
|
9
|
+
private readonly graceMs;
|
|
10
|
+
constructor(platform?: NodeJS.Platform, graceMs?: number);
|
|
11
|
+
recover(metadata: HostProcessSupervisorMetadata): Promise<HostProcessRecoveryOutcome>;
|
|
12
|
+
}
|