@loucompanion/forge-bridge 0.1.3-dev.b6be5e7f9668 → 0.1.3-dev.bf78fdcaa623
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 +44 -0
- package/dist/bridge/bridge.base.d.ts +5 -1
- package/dist/bridge/bridge.service.d.ts +36 -2
- package/dist/bridge/bridge.service.js +588 -18
- package/dist/bridge/bridge.types.d.ts +114 -1
- package/dist/cli/cli.help.d.ts +2 -0
- package/dist/cli/cli.help.js +183 -0
- package/dist/cli/cli.service.d.ts +12 -0
- package/dist/cli/cli.service.js +176 -184
- package/dist/cli/local-config.d.ts +2 -0
- package/dist/cli/local-config.js +6 -2
- 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 +33 -0
- package/dist/sandbox/image-policy.js +245 -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 +36 -0
- package/dist/sandbox/preflight.js +239 -0
- package/dist/sandbox/process.d.ts +20 -0
- package/dist/sandbox/process.js +124 -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 +83 -0
- package/dist/sandbox/runtime.d.ts +216 -0
- package/dist/sandbox/runtime.js +1658 -0
- package/dist/sandbox/sandbox.types.d.ts +83 -0
- package/dist/sandbox/sandbox.types.js +1 -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 +228 -0
- package/dist/sandbox/workspace.service.d.ts +12 -0
- package/dist/sandbox/workspace.service.js +49 -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 +660 -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 +609 -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 +754 -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 +32 -0
- package/dist/session/provider-cli/provider-cli.process.js +287 -0
- package/dist/session/provider-cli/provider-cli.prompts.d.ts +44 -0
- package/dist/session/provider-cli/provider-cli.prompts.js +528 -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 +40 -0
- package/dist/session/provider-cli/provider-cli.service.d.ts +9 -53
- package/dist/session/provider-cli/provider-cli.service.js +161 -2527
- package/dist/session/provider-cli/provider-cli.types.d.ts +1 -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.service.js +34 -24
- package/dist/session/session.types.d.ts +106 -1
- package/dist/session/session.types.js +248 -3
- 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 +4 -2
- 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/worktree.service.d.ts +2 -1
- package/dist/worktree/worktree.service.js +32 -12
- package/package.json +4 -2
|
@@ -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,72 @@ 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[];
|
|
14
16
|
readonly warmPathOverrides?: readonly string[];
|
|
15
17
|
readonly qaBrowser?: DispatchQaBrowserContext | null;
|
|
16
18
|
readonly qaScope?: DispatchQaScope | null;
|
|
17
19
|
readonly qaRework?: DispatchQaReworkContext | null;
|
|
18
20
|
readonly architectRevision?: DispatchArchitectRevisionContext | null;
|
|
21
|
+
readonly architectDependencies?: DispatchArchitectDependencyContext | null;
|
|
19
22
|
readonly storyDevelop?: DispatchStoryDevelopContext | null;
|
|
20
23
|
readonly storyQa?: DispatchStoryQaContext | null;
|
|
24
|
+
readonly designerRefs?: DispatchDesignerRefHandoffContext | null;
|
|
21
25
|
readonly draft?: DispatchDraftPrompt | null;
|
|
22
26
|
}
|
|
27
|
+
export interface DispatchSandboxContext {
|
|
28
|
+
readonly dispatchAttemptId: string;
|
|
29
|
+
readonly executionLeaseId: string;
|
|
30
|
+
readonly runnerInstanceId: string;
|
|
31
|
+
readonly executionMode: "host" | "docker";
|
|
32
|
+
readonly executionPolicy: "host_allowed" | "sandbox_preferred" | "sandbox_required";
|
|
33
|
+
readonly networkPolicy: DispatchSandboxNetworkPolicy;
|
|
34
|
+
readonly requestedResources: DispatchSandboxResourceRequest;
|
|
35
|
+
readonly runtime?: string | null;
|
|
36
|
+
readonly sandboxConfigCommitSha?: string | null;
|
|
37
|
+
readonly inputCommitSha?: string | null;
|
|
38
|
+
readonly contractDigest?: string | null;
|
|
39
|
+
readonly imageDigest?: string | null;
|
|
40
|
+
readonly publicationMode: "bridge_push" | "shared_filesystem";
|
|
41
|
+
readonly publishGrantHandle?: DispatchPublishGrantHandle | null;
|
|
42
|
+
}
|
|
43
|
+
export interface DispatchPublishGrantHandle {
|
|
44
|
+
readonly grantId: string;
|
|
45
|
+
readonly branch: string;
|
|
46
|
+
readonly expiresAt: string;
|
|
47
|
+
}
|
|
48
|
+
export interface DispatchSandboxResourceRequest {
|
|
49
|
+
readonly sandboxSlots: number;
|
|
50
|
+
readonly cpuMillis: number;
|
|
51
|
+
readonly memoryBytes: number;
|
|
52
|
+
readonly workspaceBytes: number;
|
|
53
|
+
readonly pids: number;
|
|
54
|
+
readonly buildSlots: number;
|
|
55
|
+
}
|
|
56
|
+
export interface DispatchSandboxNetworkPolicy {
|
|
57
|
+
readonly mode: "offline" | "public_allowlist" | "open_public";
|
|
58
|
+
readonly allowedHosts: readonly string[];
|
|
59
|
+
}
|
|
23
60
|
export interface DispatchDraftPrompt {
|
|
24
61
|
readonly kind: string;
|
|
25
62
|
readonly systemPrompt: string;
|
|
26
63
|
readonly userPrompt: string;
|
|
27
64
|
readonly projectName?: string | null;
|
|
28
65
|
readonly repoName?: string | null;
|
|
66
|
+
readonly attachments?: readonly DispatchDraftAttachment[];
|
|
67
|
+
}
|
|
68
|
+
export interface DispatchDraftAttachment {
|
|
69
|
+
readonly index: number;
|
|
70
|
+
readonly fileName: string;
|
|
71
|
+
readonly contentType: string;
|
|
72
|
+
readonly kind: string;
|
|
73
|
+
readonly byteCount: number;
|
|
74
|
+
readonly summary: string;
|
|
75
|
+
readonly textContent?: string | null;
|
|
76
|
+
readonly contentBase64?: string | null;
|
|
29
77
|
}
|
|
30
78
|
export interface DispatchQaBrowserContext {
|
|
31
79
|
readonly required: boolean;
|
|
@@ -69,6 +117,22 @@ export interface DispatchArchitectRevisionContext {
|
|
|
69
117
|
readonly priorContentHash: string;
|
|
70
118
|
readonly feedback: string;
|
|
71
119
|
}
|
|
120
|
+
export interface DispatchArchitectDependencyContext {
|
|
121
|
+
readonly baseBranch: string;
|
|
122
|
+
readonly prerequisites: readonly DispatchArchitectDependencyItemContext[];
|
|
123
|
+
}
|
|
124
|
+
export interface DispatchArchitectDependencyItemContext {
|
|
125
|
+
readonly storyId: string;
|
|
126
|
+
readonly title: string;
|
|
127
|
+
readonly scheduleIndex?: number | null;
|
|
128
|
+
readonly waveIndex?: number | null;
|
|
129
|
+
readonly featureScheduleIndex?: number | null;
|
|
130
|
+
readonly expectedOutput?: string | null;
|
|
131
|
+
readonly handoffSummary?: string | null;
|
|
132
|
+
readonly dependencyReason?: string | null;
|
|
133
|
+
readonly pullRequestNumber?: number | null;
|
|
134
|
+
readonly targetBranch: string;
|
|
135
|
+
}
|
|
72
136
|
export interface DispatchStoryDevelopContext {
|
|
73
137
|
readonly storyWorkItemId: string;
|
|
74
138
|
readonly planId: string;
|
|
@@ -125,6 +189,42 @@ export interface DispatchStoryQaDependencyContext {
|
|
|
125
189
|
readonly fromWorkItemId: string;
|
|
126
190
|
readonly toWorkItemId: string;
|
|
127
191
|
}
|
|
192
|
+
export interface DispatchDesignerRefHandoffContext {
|
|
193
|
+
readonly schemaVersion: number;
|
|
194
|
+
readonly kind: string;
|
|
195
|
+
readonly ownerType: string;
|
|
196
|
+
readonly ownerId: string;
|
|
197
|
+
readonly projectId: string;
|
|
198
|
+
readonly repoId: string;
|
|
199
|
+
readonly title: string;
|
|
200
|
+
readonly refs: readonly DispatchDesignerRefAttachment[];
|
|
201
|
+
}
|
|
202
|
+
export interface DispatchDesignerRefAttachment {
|
|
203
|
+
readonly ref: DispatchDesignerRef;
|
|
204
|
+
readonly reason: string;
|
|
205
|
+
readonly required: boolean;
|
|
206
|
+
readonly source: string;
|
|
207
|
+
readonly lineageKind: string;
|
|
208
|
+
readonly inheritedFromItemType?: string | null;
|
|
209
|
+
readonly inheritedFromItemId?: string | null;
|
|
210
|
+
readonly inheritedFromDesignerRefId?: string | null;
|
|
211
|
+
readonly addedByLane: string;
|
|
212
|
+
readonly sortOrder: number;
|
|
213
|
+
readonly createdAt: string;
|
|
214
|
+
}
|
|
215
|
+
export interface DispatchDesignerRef {
|
|
216
|
+
readonly id: string;
|
|
217
|
+
readonly projectId: string;
|
|
218
|
+
readonly repoId: string;
|
|
219
|
+
readonly refKey: string;
|
|
220
|
+
readonly kind: string;
|
|
221
|
+
readonly path: string;
|
|
222
|
+
readonly anchor?: string | null;
|
|
223
|
+
readonly title: string;
|
|
224
|
+
readonly contentHash: string;
|
|
225
|
+
readonly commitSha: string;
|
|
226
|
+
readonly createdAt: string;
|
|
227
|
+
}
|
|
128
228
|
export interface DispatchPullRequestContext {
|
|
129
229
|
readonly number: number;
|
|
130
230
|
readonly provider: string;
|
|
@@ -214,6 +314,11 @@ export interface ApiKeySecretGrant {
|
|
|
214
314
|
readonly secret: string;
|
|
215
315
|
readonly expiresAt: string;
|
|
216
316
|
}
|
|
317
|
+
export interface ApiKeySecretGrantHandle {
|
|
318
|
+
readonly grantId: string;
|
|
319
|
+
readonly provider: string;
|
|
320
|
+
readonly expiresAt: string;
|
|
321
|
+
}
|
|
217
322
|
export interface DispatchServerLocalConfig {
|
|
218
323
|
readonly repoRoot: string;
|
|
219
324
|
readonly cleanupWorktrees: boolean;
|
|
@@ -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),
|
|
@@ -15,19 +15,121 @@ export function parseRunOnceDispatchPacket(value) {
|
|
|
15
15
|
lease: parseLease(packet.lease),
|
|
16
16
|
execution: parseExecution(packet.execution),
|
|
17
17
|
serverLocal: parseServerLocal(packet.serverLocal),
|
|
18
|
+
sandbox: parseSandbox(packet.sandbox, schemaVersion),
|
|
18
19
|
pullRequest: parsePullRequest(packet.pullRequest),
|
|
19
20
|
apiKeySecretGrant: parseApiKeySecretGrant(packet.apiKeySecretGrant),
|
|
21
|
+
apiKeySecretGrantHandle: parseApiKeySecretGrantHandle(packet.apiKeySecretGrantHandle),
|
|
20
22
|
artifacts: parseArtifacts(packet.artifacts),
|
|
21
23
|
warmPathOverrides: parseWarmPathOverrides(packet.warmPathOverrides),
|
|
22
24
|
qaBrowser: parseQaBrowser(packet.qaBrowser),
|
|
23
25
|
qaScope: parseQaScope(packet.qaScope ?? packet.qa_scope),
|
|
24
26
|
qaRework: parseQaRework(packet.qaRework),
|
|
25
27
|
architectRevision: parseArchitectRevision(packet.architectRevision),
|
|
28
|
+
architectDependencies: parseArchitectDependencies(packet.architectDependencies),
|
|
26
29
|
storyDevelop: parseStoryDevelop(packet.storyDevelop),
|
|
27
30
|
storyQa: parseStoryQa(packet.storyQa),
|
|
31
|
+
designerRefs: parseDesignerRefs(packet.designerRefs ?? packet.designer_refs),
|
|
28
32
|
draft: parseDraftPrompt(packet.draft)
|
|
29
33
|
};
|
|
30
34
|
}
|
|
35
|
+
function parseSandbox(value, schemaVersion) {
|
|
36
|
+
if (value === undefined || value === null) {
|
|
37
|
+
if (schemaVersion === 2) {
|
|
38
|
+
throw new Error("sandbox is required for dispatch schemaVersion 2.");
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const sandbox = asObject(value, "sandbox");
|
|
43
|
+
const executionMode = requiredString(sandbox, "executionMode");
|
|
44
|
+
if (executionMode !== "host" && executionMode !== "docker") {
|
|
45
|
+
throw new Error("sandbox.executionMode must be host or docker.");
|
|
46
|
+
}
|
|
47
|
+
const executionPolicy = requiredString(sandbox, "executionPolicy");
|
|
48
|
+
if (executionPolicy !== "host_allowed" && executionPolicy !== "sandbox_preferred" && executionPolicy !== "sandbox_required") {
|
|
49
|
+
throw new Error("sandbox.executionPolicy is invalid.");
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
dispatchAttemptId: requiredString(sandbox, "dispatchAttemptId"),
|
|
53
|
+
executionLeaseId: requiredString(sandbox, "executionLeaseId"),
|
|
54
|
+
runnerInstanceId: requiredString(sandbox, "runnerInstanceId"),
|
|
55
|
+
executionMode,
|
|
56
|
+
executionPolicy,
|
|
57
|
+
networkPolicy: parseSandboxNetworkPolicy(sandbox.networkPolicy),
|
|
58
|
+
requestedResources: parseSandboxResourceRequest(sandbox.requestedResources),
|
|
59
|
+
runtime: optionalString(sandbox, "runtime"),
|
|
60
|
+
sandboxConfigCommitSha: optionalString(sandbox, "sandboxConfigCommitSha"),
|
|
61
|
+
inputCommitSha: optionalString(sandbox, "inputCommitSha"),
|
|
62
|
+
contractDigest: optionalString(sandbox, "contractDigest"),
|
|
63
|
+
imageDigest: optionalString(sandbox, "imageDigest"),
|
|
64
|
+
publicationMode: parsePublicationMode(sandbox.publicationMode),
|
|
65
|
+
publishGrantHandle: parsePublishGrantHandle(sandbox.publishGrantHandle)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function parsePublicationMode(value) {
|
|
69
|
+
if (value === undefined || value === null)
|
|
70
|
+
return "shared_filesystem";
|
|
71
|
+
if (value !== "bridge_push" && value !== "shared_filesystem")
|
|
72
|
+
throw new Error("sandbox.publicationMode is invalid.");
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
function parsePublishGrantHandle(value) {
|
|
76
|
+
if (value === undefined || value === null)
|
|
77
|
+
return null;
|
|
78
|
+
const handle = asObject(value, "sandbox.publishGrantHandle");
|
|
79
|
+
const grantId = requiredString(handle, "grantId");
|
|
80
|
+
const branch = requiredString(handle, "branch");
|
|
81
|
+
const expiresAt = requiredString(handle, "expiresAt");
|
|
82
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(grantId)) {
|
|
83
|
+
throw new Error("sandbox.publishGrantHandle.grantId is invalid.");
|
|
84
|
+
}
|
|
85
|
+
if (branch.length > 240)
|
|
86
|
+
throw new Error("sandbox.publishGrantHandle.branch is too long.");
|
|
87
|
+
if (!Number.isFinite(Date.parse(expiresAt)))
|
|
88
|
+
throw new Error("sandbox.publishGrantHandle.expiresAt is invalid.");
|
|
89
|
+
return { grantId, branch, expiresAt };
|
|
90
|
+
}
|
|
91
|
+
function parseSandboxResourceRequest(value) {
|
|
92
|
+
if (value === undefined || value === null) {
|
|
93
|
+
return {
|
|
94
|
+
sandboxSlots: 1,
|
|
95
|
+
cpuMillis: 2000,
|
|
96
|
+
memoryBytes: 4 * 1024 ** 3,
|
|
97
|
+
workspaceBytes: 10 * 1024 ** 3,
|
|
98
|
+
pids: 512,
|
|
99
|
+
buildSlots: 1
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const resources = asObject(value, "sandbox.requestedResources");
|
|
103
|
+
return {
|
|
104
|
+
sandboxSlots: boundedInteger(resources, "sandboxSlots", 1, 4),
|
|
105
|
+
cpuMillis: boundedInteger(resources, "cpuMillis", 100, 64_000),
|
|
106
|
+
memoryBytes: boundedInteger(resources, "memoryBytes", 128 * 1024 ** 2, 512 * 1024 ** 3),
|
|
107
|
+
workspaceBytes: boundedInteger(resources, "workspaceBytes", 1024 ** 3, 10 * 1024 ** 4),
|
|
108
|
+
pids: boundedInteger(resources, "pids", 32, 65_536),
|
|
109
|
+
buildSlots: boundedInteger(resources, "buildSlots", 0, 4)
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function parseSandboxNetworkPolicy(value) {
|
|
113
|
+
if (value === undefined || value === null)
|
|
114
|
+
return { mode: "public_allowlist", allowedHosts: [] };
|
|
115
|
+
const policy = asObject(value, "sandbox.networkPolicy");
|
|
116
|
+
const mode = requiredString(policy, "mode");
|
|
117
|
+
if (mode !== "offline" && mode !== "public_allowlist" && mode !== "open_public") {
|
|
118
|
+
throw new Error("sandbox.networkPolicy.mode is invalid.");
|
|
119
|
+
}
|
|
120
|
+
const rawHosts = policy.allowedHosts ?? [];
|
|
121
|
+
if (!Array.isArray(rawHosts) || rawHosts.some((host) => typeof host !== "string")) {
|
|
122
|
+
throw new Error("sandbox.networkPolicy.allowedHosts must be a string array.");
|
|
123
|
+
}
|
|
124
|
+
const allowedHosts = [...new Set(rawHosts.map(host => host.trim().toLowerCase()).filter(Boolean))];
|
|
125
|
+
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))) {
|
|
126
|
+
throw new Error("sandbox.networkPolicy.allowedHosts contains an invalid hostname.");
|
|
127
|
+
}
|
|
128
|
+
if (mode !== "public_allowlist" && allowedHosts.length > 0) {
|
|
129
|
+
throw new Error("sandbox.networkPolicy.allowedHosts requires public_allowlist mode.");
|
|
130
|
+
}
|
|
131
|
+
return { mode, allowedHosts };
|
|
132
|
+
}
|
|
31
133
|
export function failureResult(summary, events = []) {
|
|
32
134
|
return {
|
|
33
135
|
schemaVersion: 1,
|
|
@@ -119,9 +221,45 @@ function parseDraftPrompt(value) {
|
|
|
119
221
|
return {
|
|
120
222
|
kind: requiredString(draft, "kind"),
|
|
121
223
|
systemPrompt: requiredString(draft, "systemPrompt"),
|
|
122
|
-
userPrompt: requiredString(draft, "userPrompt")
|
|
224
|
+
userPrompt: requiredString(draft, "userPrompt"),
|
|
225
|
+
projectName: optionalString(draft, "projectName"),
|
|
226
|
+
repoName: optionalString(draft, "repoName"),
|
|
227
|
+
attachments: parseDraftAttachments(draft.attachments)
|
|
123
228
|
};
|
|
124
229
|
}
|
|
230
|
+
function parseDraftAttachments(value) {
|
|
231
|
+
if (value === undefined || value === null) {
|
|
232
|
+
return [];
|
|
233
|
+
}
|
|
234
|
+
if (!Array.isArray(value)) {
|
|
235
|
+
throw new Error("draft.attachments must be an array when provided.");
|
|
236
|
+
}
|
|
237
|
+
return value.map((entry, index) => {
|
|
238
|
+
const attachment = asObject(entry, `draft.attachments[${index}]`);
|
|
239
|
+
const kind = requiredString(attachment, "kind").trim().toLowerCase();
|
|
240
|
+
if (kind !== "text" && kind !== "image") {
|
|
241
|
+
throw new Error(`draft.attachments[${index}].kind must be text or image.`);
|
|
242
|
+
}
|
|
243
|
+
const textContent = optionalString(attachment, "textContent");
|
|
244
|
+
const contentBase64 = optionalString(attachment, "contentBase64");
|
|
245
|
+
if (kind === "text" && textContent === null) {
|
|
246
|
+
throw new Error(`draft.attachments[${index}].textContent is required for text attachments.`);
|
|
247
|
+
}
|
|
248
|
+
if (kind === "image" && contentBase64 === null) {
|
|
249
|
+
throw new Error(`draft.attachments[${index}].contentBase64 is required for image attachments.`);
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
index: optionalNonNegativeInteger(attachment, "index") ?? index,
|
|
253
|
+
fileName: requiredString(attachment, "fileName"),
|
|
254
|
+
contentType: optionalString(attachment, "contentType") ?? "",
|
|
255
|
+
kind,
|
|
256
|
+
byteCount: optionalNonNegativeInteger(attachment, "byteCount") ?? 0,
|
|
257
|
+
summary: optionalString(attachment, "summary") ?? "",
|
|
258
|
+
textContent,
|
|
259
|
+
contentBase64
|
|
260
|
+
};
|
|
261
|
+
});
|
|
262
|
+
}
|
|
125
263
|
function parseApiKeySecretGrant(value) {
|
|
126
264
|
if (value === undefined || value === null) {
|
|
127
265
|
return null;
|
|
@@ -134,6 +272,16 @@ function parseApiKeySecretGrant(value) {
|
|
|
134
272
|
expiresAt: requiredString(grant, "expiresAt")
|
|
135
273
|
};
|
|
136
274
|
}
|
|
275
|
+
function parseApiKeySecretGrantHandle(value) {
|
|
276
|
+
if (value === undefined || value === null)
|
|
277
|
+
return null;
|
|
278
|
+
const grant = asObject(value, "apiKeySecretGrantHandle");
|
|
279
|
+
return {
|
|
280
|
+
grantId: requiredString(grant, "grantId"),
|
|
281
|
+
provider: requiredString(grant, "provider"),
|
|
282
|
+
expiresAt: requiredString(grant, "expiresAt")
|
|
283
|
+
};
|
|
284
|
+
}
|
|
137
285
|
function parseServerLocal(value) {
|
|
138
286
|
const serverLocal = asObject(value, "serverLocal");
|
|
139
287
|
return {
|
|
@@ -282,6 +430,34 @@ function parseArchitectRevision(value) {
|
|
|
282
430
|
feedback: requiredString(revision, "feedback")
|
|
283
431
|
};
|
|
284
432
|
}
|
|
433
|
+
function parseArchitectDependencies(value) {
|
|
434
|
+
if (value === undefined || value === null) {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
const context = asObject(value, "architectDependencies");
|
|
438
|
+
const prerequisites = context.prerequisites;
|
|
439
|
+
if (!Array.isArray(prerequisites)) {
|
|
440
|
+
throw new Error("architectDependencies.prerequisites must be an array.");
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
baseBranch: requiredString(context, "baseBranch").trim(),
|
|
444
|
+
prerequisites: prerequisites.map((entry, index) => {
|
|
445
|
+
const prerequisite = asObject(entry, `architectDependencies.prerequisites[${index}]`);
|
|
446
|
+
return {
|
|
447
|
+
storyId: requiredString(prerequisite, "storyId").trim(),
|
|
448
|
+
title: requiredString(prerequisite, "title").trim(),
|
|
449
|
+
scheduleIndex: optionalNonNegativeInteger(prerequisite, "scheduleIndex"),
|
|
450
|
+
waveIndex: optionalNonNegativeInteger(prerequisite, "waveIndex"),
|
|
451
|
+
featureScheduleIndex: optionalNonNegativeInteger(prerequisite, "featureScheduleIndex"),
|
|
452
|
+
expectedOutput: optionalString(prerequisite, "expectedOutput"),
|
|
453
|
+
handoffSummary: optionalString(prerequisite, "handoffSummary"),
|
|
454
|
+
dependencyReason: optionalString(prerequisite, "dependencyReason"),
|
|
455
|
+
pullRequestNumber: optionalPositiveInteger(prerequisite, "pullRequestNumber"),
|
|
456
|
+
targetBranch: requiredString(prerequisite, "targetBranch").trim()
|
|
457
|
+
};
|
|
458
|
+
})
|
|
459
|
+
};
|
|
460
|
+
}
|
|
285
461
|
function parseStoryDevelop(value) {
|
|
286
462
|
if (value === undefined || value === null) {
|
|
287
463
|
return null;
|
|
@@ -387,6 +563,58 @@ function parseStoryQaDependencies(value) {
|
|
|
387
563
|
};
|
|
388
564
|
});
|
|
389
565
|
}
|
|
566
|
+
function parseDesignerRefs(value) {
|
|
567
|
+
if (value === undefined || value === null) {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
const context = asObject(value, "designerRefs");
|
|
571
|
+
const refs = context.refs;
|
|
572
|
+
if (!Array.isArray(refs)) {
|
|
573
|
+
throw new Error("designerRefs.refs must be an array.");
|
|
574
|
+
}
|
|
575
|
+
return {
|
|
576
|
+
schemaVersion: requiredNumber(context, "schemaVersion"),
|
|
577
|
+
kind: requiredString(context, "kind"),
|
|
578
|
+
ownerType: requiredString(context, "ownerType"),
|
|
579
|
+
ownerId: requiredString(context, "ownerId"),
|
|
580
|
+
projectId: requiredString(context, "projectId"),
|
|
581
|
+
repoId: requiredString(context, "repoId"),
|
|
582
|
+
title: requiredString(context, "title"),
|
|
583
|
+
refs: refs.map((entry, index) => parseDesignerRefAttachment(entry, index))
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
function parseDesignerRefAttachment(value, index) {
|
|
587
|
+
const attachment = asObject(value, `designerRefs.refs[${index}]`);
|
|
588
|
+
return {
|
|
589
|
+
ref: parseDesignerRef(attachment.ref, index),
|
|
590
|
+
reason: optionalString(attachment, "reason") ?? "",
|
|
591
|
+
required: requiredBoolean(attachment, "required"),
|
|
592
|
+
source: optionalString(attachment, "source") ?? "",
|
|
593
|
+
lineageKind: optionalString(attachment, "lineageKind") ?? optionalString(attachment, "lineage_kind") ?? "",
|
|
594
|
+
inheritedFromItemType: optionalString(attachment, "inheritedFromItemType") ?? optionalString(attachment, "inherited_from_item_type"),
|
|
595
|
+
inheritedFromItemId: optionalString(attachment, "inheritedFromItemId") ?? optionalString(attachment, "inherited_from_item_id"),
|
|
596
|
+
inheritedFromDesignerRefId: optionalString(attachment, "inheritedFromDesignerRefId") ?? optionalString(attachment, "inherited_from_designer_ref_id"),
|
|
597
|
+
addedByLane: optionalString(attachment, "addedByLane") ?? optionalString(attachment, "added_by_lane") ?? "",
|
|
598
|
+
sortOrder: requiredNumber(attachment, "sortOrder"),
|
|
599
|
+
createdAt: requiredString(attachment, "createdAt")
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
function parseDesignerRef(value, index) {
|
|
603
|
+
const designerRef = asObject(value, `designerRefs.refs[${index}].ref`);
|
|
604
|
+
return {
|
|
605
|
+
id: requiredString(designerRef, "id"),
|
|
606
|
+
projectId: requiredString(designerRef, "projectId"),
|
|
607
|
+
repoId: requiredString(designerRef, "repoId"),
|
|
608
|
+
refKey: requiredString(designerRef, "refKey"),
|
|
609
|
+
kind: requiredString(designerRef, "kind"),
|
|
610
|
+
path: requiredString(designerRef, "path"),
|
|
611
|
+
anchor: optionalString(designerRef, "anchor"),
|
|
612
|
+
title: optionalString(designerRef, "title") ?? "",
|
|
613
|
+
contentHash: requiredString(designerRef, "contentHash"),
|
|
614
|
+
commitSha: requiredString(designerRef, "commitSha"),
|
|
615
|
+
createdAt: requiredString(designerRef, "createdAt")
|
|
616
|
+
};
|
|
617
|
+
}
|
|
390
618
|
function parseStringArray(value, label) {
|
|
391
619
|
if (!Array.isArray(value)) {
|
|
392
620
|
throw new Error(`${label} must be an array.`);
|
|
@@ -481,6 +709,16 @@ function optionalPositiveInteger(source, key) {
|
|
|
481
709
|
}
|
|
482
710
|
return value;
|
|
483
711
|
}
|
|
712
|
+
function optionalNonNegativeInteger(source, key) {
|
|
713
|
+
const value = source[key];
|
|
714
|
+
if (value === undefined || value === null) {
|
|
715
|
+
return null;
|
|
716
|
+
}
|
|
717
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
718
|
+
throw new Error(`${key} must be a non-negative integer when provided.`);
|
|
719
|
+
}
|
|
720
|
+
return value;
|
|
721
|
+
}
|
|
484
722
|
function requiredNumber(source, key) {
|
|
485
723
|
const value = source[key];
|
|
486
724
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -488,3 +726,10 @@ function requiredNumber(source, key) {
|
|
|
488
726
|
}
|
|
489
727
|
return value;
|
|
490
728
|
}
|
|
729
|
+
function boundedInteger(source, key, minimum, maximum) {
|
|
730
|
+
const value = requiredNumber(source, key);
|
|
731
|
+
if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
|
|
732
|
+
throw new Error(`${key} must be an integer from ${minimum} through ${maximum}.`);
|
|
733
|
+
}
|
|
734
|
+
return value;
|
|
735
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface LaunchCommand {
|
|
2
|
+
readonly command: string;
|
|
3
|
+
readonly args: readonly string[];
|
|
4
|
+
}
|
|
5
|
+
export declare function buildWindowsCmdLaunch(command: string, args: readonly string[], comSpec?: string | undefined): LaunchCommand;
|
|
6
|
+
export declare function buildWindowsLaunchCommand(commandPath: string, args: readonly string[]): LaunchCommand;
|
|
7
|
+
export declare function windowsCommandLine(command: string, args: readonly string[]): string;
|
|
8
|
+
export declare function quoteWindowsCommandLineArg(value: string): string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export function buildWindowsCmdLaunch(command, args, comSpec = process.env.ComSpec) {
|
|
3
|
+
const resolvedComSpec = comSpec?.trim();
|
|
4
|
+
const commandLine = windowsCommandLine(command, args);
|
|
5
|
+
const cmdPayload = commandLine.startsWith('"') ? `"${commandLine}"` : commandLine;
|
|
6
|
+
return {
|
|
7
|
+
command: resolvedComSpec || "cmd.exe",
|
|
8
|
+
args: ["/d", "/s", "/v:off", "/c", cmdPayload]
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function buildWindowsLaunchCommand(commandPath, args) {
|
|
12
|
+
const extension = path.extname(commandPath).toLowerCase();
|
|
13
|
+
if (extension === ".ps1") {
|
|
14
|
+
return {
|
|
15
|
+
command: powershellExecutable(),
|
|
16
|
+
args: ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", commandPath, ...args]
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (extension === ".cmd" || extension === ".bat") {
|
|
20
|
+
return buildWindowsCmdLaunch(commandPath, args);
|
|
21
|
+
}
|
|
22
|
+
return { command: commandPath, args };
|
|
23
|
+
}
|
|
24
|
+
export function windowsCommandLine(command, args) {
|
|
25
|
+
return [command, ...args].map(quoteWindowsCommandLineArg).join(" ");
|
|
26
|
+
}
|
|
27
|
+
export function quoteWindowsCommandLineArg(value) {
|
|
28
|
+
const escaped = value
|
|
29
|
+
.replace(/\^/g, "^^")
|
|
30
|
+
.replace(/%/g, "^%");
|
|
31
|
+
if (escaped.length > 0 && !/[\s"&|<>()^%!]/.test(escaped)) {
|
|
32
|
+
return escaped;
|
|
33
|
+
}
|
|
34
|
+
return `"${escaped.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/g, "$1$1")}"`;
|
|
35
|
+
}
|
|
36
|
+
function powershellExecutable() {
|
|
37
|
+
const systemRoot = process.env.SystemRoot;
|
|
38
|
+
return systemRoot
|
|
39
|
+
? path.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
40
|
+
: "powershell.exe";
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function supportsDraftImageAttachmentsFor(cliProviders: readonly string[]): boolean;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
const secretKeyPattern = /(api[_-]?key|authorization|bearer|client[_-]?secret|password|secret|token)/i;
|
|
2
|
+
const attachmentContentKeyPattern = /^(textContent|contentBase64)$/i;
|
|
3
|
+
const serializedAttachmentContentPattern = /("(?:textContent|contentBase64)"\s*:\s*")(?:(?:\\.)|[^"\\])*(")/gi;
|
|
2
4
|
export function redactSecrets(value, exactSecrets = []) {
|
|
3
5
|
return redactValue(value, exactSecrets);
|
|
4
6
|
}
|
|
5
7
|
export function redactText(value, exactSecrets = []) {
|
|
6
|
-
let redacted = value;
|
|
8
|
+
let redacted = value.replace(serializedAttachmentContentPattern, "$1[REDACTED]$2");
|
|
7
9
|
for (const secret of exactSecrets) {
|
|
8
10
|
if (secret.length > 0) {
|
|
9
11
|
redacted = redacted.split(secret).join("[REDACTED]");
|
|
@@ -25,6 +27,6 @@ function redactValue(value, exactSecrets) {
|
|
|
25
27
|
}
|
|
26
28
|
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
27
29
|
key,
|
|
28
|
-
secretKeyPattern.test(key) ? "[REDACTED]" : redactValue(item, exactSecrets)
|
|
30
|
+
secretKeyPattern.test(key) || attachmentContentKeyPattern.test(key) ? "[REDACTED]" : redactValue(item, exactSecrets)
|
|
29
31
|
]));
|
|
30
32
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const forgeBridgeVersion = "0.1.3-dev.
|
|
1
|
+
export declare const forgeBridgeVersion = "0.1.3-dev.bf78fdcaa623";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const forgeBridgeVersion = "0.1.3-dev.
|
|
1
|
+
export const forgeBridgeVersion = "0.1.3-dev.bf78fdcaa623";
|
|
@@ -36,19 +36,29 @@ const DRAFT_OPERATIONAL_SKILLS = new Set([
|
|
|
36
36
|
"draft-repo-context",
|
|
37
37
|
"draft-graph-context",
|
|
38
38
|
"draft-product-scope",
|
|
39
|
-
"draft-work-order-plan",
|
|
40
39
|
"draft-critic",
|
|
41
40
|
"draft-proposal"
|
|
42
41
|
]);
|
|
42
|
+
const DRAFT_WORK_ITEM_OPERATIONAL_SKILLS = new Set([
|
|
43
|
+
"draft-work-item-plan"
|
|
44
|
+
]);
|
|
45
|
+
const DRAFT_WORK_ORDER_OPERATIONAL_SKILLS = new Set([
|
|
46
|
+
"draft-work-order-plan"
|
|
47
|
+
]);
|
|
43
48
|
const DRAFT_OPERATIONAL_HOOKS = new Set([
|
|
44
49
|
"draft-intent",
|
|
45
50
|
"draft-repo-context",
|
|
46
51
|
"draft-graph-context",
|
|
47
52
|
"draft-product-scope",
|
|
48
|
-
"draft-work-order-plan",
|
|
49
53
|
"draft-critic",
|
|
50
54
|
"draft-proposal"
|
|
51
55
|
]);
|
|
56
|
+
const DRAFT_WORK_ITEM_OPERATIONAL_HOOKS = new Set([
|
|
57
|
+
"draft-work-item-plan"
|
|
58
|
+
]);
|
|
59
|
+
const DRAFT_WORK_ORDER_OPERATIONAL_HOOKS = new Set([
|
|
60
|
+
"draft-work-order-plan"
|
|
61
|
+
]);
|
|
52
62
|
export async function injectWorktreeArtifacts(worktreePath, artifacts) {
|
|
53
63
|
for (const artifact of artifacts) {
|
|
54
64
|
await writeArtifact(worktreePath, artifact);
|
|
@@ -64,7 +74,7 @@ export function filterArtifactsForLane(artifacts, lane, phase) {
|
|
|
64
74
|
return artifacts.filter((artifact) => shouldInjectArchitectArtifact(artifact, commandSlug));
|
|
65
75
|
}
|
|
66
76
|
if (normalizedLane === "draft") {
|
|
67
|
-
return artifacts.filter((artifact) => shouldInjectDraftArtifact(artifact, commandSlug));
|
|
77
|
+
return artifacts.filter((artifact) => shouldInjectDraftArtifact(artifact, commandSlug, phase));
|
|
68
78
|
}
|
|
69
79
|
return artifacts;
|
|
70
80
|
}
|
|
@@ -142,7 +152,7 @@ function shouldInjectArchitectArtifact(artifact, commandSlug) {
|
|
|
142
152
|
return false;
|
|
143
153
|
}
|
|
144
154
|
}
|
|
145
|
-
function shouldInjectDraftArtifact(artifact, commandSlug) {
|
|
155
|
+
function shouldInjectDraftArtifact(artifact, commandSlug, phase) {
|
|
146
156
|
if (artifact.scope.trim().toLowerCase() !== "operational") {
|
|
147
157
|
return false;
|
|
148
158
|
}
|
|
@@ -151,13 +161,36 @@ function shouldInjectDraftArtifact(artifact, commandSlug) {
|
|
|
151
161
|
case "command":
|
|
152
162
|
return slug === commandSlug;
|
|
153
163
|
case "skill":
|
|
154
|
-
return DRAFT_OPERATIONAL_SKILLS.has(slug);
|
|
164
|
+
return DRAFT_OPERATIONAL_SKILLS.has(slug) || draftPhaseSkills(phase).has(slug);
|
|
155
165
|
case "hook":
|
|
156
|
-
return DRAFT_OPERATIONAL_HOOKS.has(slug);
|
|
166
|
+
return DRAFT_OPERATIONAL_HOOKS.has(slug) || draftPhaseHooks(phase).has(slug);
|
|
157
167
|
default:
|
|
158
168
|
return false;
|
|
159
169
|
}
|
|
160
170
|
}
|
|
171
|
+
function draftPhaseSkills(phase) {
|
|
172
|
+
switch (normalizeDraftPhase(phase)) {
|
|
173
|
+
case "work_order":
|
|
174
|
+
return DRAFT_WORK_ORDER_OPERATIONAL_SKILLS;
|
|
175
|
+
case "story":
|
|
176
|
+
return DRAFT_WORK_ITEM_OPERATIONAL_SKILLS;
|
|
177
|
+
default:
|
|
178
|
+
return DRAFT_WORK_ITEM_OPERATIONAL_SKILLS;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function draftPhaseHooks(phase) {
|
|
182
|
+
switch (normalizeDraftPhase(phase)) {
|
|
183
|
+
case "work_order":
|
|
184
|
+
return DRAFT_WORK_ORDER_OPERATIONAL_HOOKS;
|
|
185
|
+
case "story":
|
|
186
|
+
return DRAFT_WORK_ITEM_OPERATIONAL_HOOKS;
|
|
187
|
+
default:
|
|
188
|
+
return DRAFT_WORK_ITEM_OPERATIONAL_HOOKS;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function normalizeDraftPhase(phase) {
|
|
192
|
+
return phase.trim().toLowerCase().replaceAll("-", "_");
|
|
193
|
+
}
|
|
161
194
|
export function buildSpecBody(laneCommand, workItem, phase = "implementation") {
|
|
162
195
|
const prompt = laneCommand.body.replaceAll("{workItemId}", workItem.id);
|
|
163
196
|
return `---
|
|
@@ -30,3 +30,14 @@ export declare function createDirectoryLink(sourcePath: string, targetPath: stri
|
|
|
30
30
|
export declare function lockfilesDiffer(baseCheckoutPath: string, worktreePath: string, packageRootRelative: string): Promise<boolean>;
|
|
31
31
|
export declare function requiresInstallFallback(entry: WarmPathEntry, baseCheckoutPath: string, worktreePath: string, sourceExists: boolean): Promise<string | null>;
|
|
32
32
|
export declare function declaresNativeModules(packageRootPath: string): Promise<boolean>;
|
|
33
|
+
export interface NpmLaunchOptions {
|
|
34
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
35
|
+
readonly execPath?: string;
|
|
36
|
+
readonly platform?: NodeJS.Platform;
|
|
37
|
+
readonly homeDir?: string;
|
|
38
|
+
readonly candidates?: readonly string[];
|
|
39
|
+
}
|
|
40
|
+
export declare function resolveNpmLaunch(args: readonly string[], options?: NpmLaunchOptions): {
|
|
41
|
+
command: string;
|
|
42
|
+
args: readonly string[];
|
|
43
|
+
};
|