@the-open-engine/zeroshot 6.33.0 → 6.34.0
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/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/codex.js +3 -1
- package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
- package/lib/hosted-target/adapter-request.cjs +55 -0
- package/lib/hosted-target/adapter-request.d.cts +9 -0
- package/lib/hosted-target/adapter-request.d.mts +9 -0
- package/lib/hosted-target/adapter-request.d.ts +9 -0
- package/lib/hosted-target/adapter-request.mjs +55 -1
- package/lib/hosted-target/adapter-types.d.cts +1 -0
- package/lib/hosted-target/adapter-types.d.mts +1 -0
- package/lib/hosted-target/adapter-types.d.ts +1 -0
- package/lib/hosted-target/response-status.cjs +18 -0
- package/lib/hosted-target/response-status.d.cts +2 -0
- package/lib/hosted-target/response-status.d.mts +2 -0
- package/lib/hosted-target/response-status.d.ts +2 -0
- package/lib/hosted-target/response-status.mjs +15 -0
- package/lib/hosted-target/retry-executor.d.cts +1 -1
- package/lib/hosted-target/retry-executor.d.mts +1 -1
- package/lib/hosted-target/retry-executor.d.ts +1 -1
- package/lib/hosted-target/runtime-install.cjs +45 -0
- package/lib/hosted-target/runtime-install.d.cts +14 -0
- package/lib/hosted-target/runtime-install.d.mts +14 -0
- package/lib/hosted-target/runtime-install.d.ts +14 -0
- package/lib/hosted-target/runtime-install.mjs +42 -0
- package/lib/hosted-target/zero-cloud-v1-adapter.cjs +35 -66
- package/lib/hosted-target/zero-cloud-v1-adapter.d.cts +1 -0
- package/lib/hosted-target/zero-cloud-v1-adapter.d.mts +1 -0
- package/lib/hosted-target/zero-cloud-v1-adapter.d.ts +1 -0
- package/lib/hosted-target/zero-cloud-v1-adapter.mjs +37 -68
- package/lib/target/discovery-validation.cjs +11 -18
- package/lib/target/discovery-validation.d.cts +1 -12
- package/lib/target/discovery-validation.d.mts +1 -12
- package/lib/target/discovery-validation.d.ts +1 -12
- package/lib/target/discovery-validation.js +11 -18
- package/lib/target/discovery-validation.mjs +11 -18
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -1
- package/src/agent/agent-config.js +3 -5
- package/src/agent-cli-provider/adapters/codex.ts +3 -1
- package/src/hosted-target/adapter-request.ts +75 -1
- package/src/hosted-target/adapter-types.ts +6 -0
- package/src/hosted-target/response-status.ts +21 -0
- package/src/hosted-target/retry-executor.ts +8 -1
- package/src/hosted-target/runtime-install.ts +83 -0
- package/src/hosted-target/zero-cloud-v1-adapter.ts +65 -100
- package/src/target/discovery-validation.ts +26 -28
- package/task-lib/runner.js +14 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { CredentialInstallDescriptor } from '../target/discovery.js';
|
|
2
|
+
import { readBoundedResponseJson } from '../target/bounded-response.js';
|
|
3
|
+
import { MAX_RESPONSE_BYTES } from './bounds.js';
|
|
4
|
+
import { TargetProtocolError } from './errors.js';
|
|
5
|
+
import { assertCapsuleResponseStatus } from './response-status.js';
|
|
6
|
+
import { withTargetRetry } from './retry-executor.js';
|
|
7
|
+
import type { Clock, RetryPolicy } from './types.js';
|
|
8
|
+
|
|
9
|
+
type RuntimeInstallOptions = {
|
|
10
|
+
readonly capsuleId: string;
|
|
11
|
+
readonly runtime: unknown;
|
|
12
|
+
readonly accessToken: string;
|
|
13
|
+
readonly descriptor: CredentialInstallDescriptor;
|
|
14
|
+
readonly signal?: AbortSignal;
|
|
15
|
+
readonly clock: Clock;
|
|
16
|
+
readonly retryPolicy: RetryPolicy;
|
|
17
|
+
readonly request: (
|
|
18
|
+
method: string,
|
|
19
|
+
path: string,
|
|
20
|
+
signal: AbortSignal | undefined,
|
|
21
|
+
body: string,
|
|
22
|
+
accessToken: string
|
|
23
|
+
) => Promise<Response>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function validOpaque(value: string, field: string): void {
|
|
27
|
+
if (value.length === 0 || value.length > 1024) {
|
|
28
|
+
throw new TargetProtocolError(`${field} is invalid`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function runtimeBody(runtime: unknown, maximum: number): string {
|
|
33
|
+
let body: string | undefined;
|
|
34
|
+
try {
|
|
35
|
+
body = JSON.stringify(runtime);
|
|
36
|
+
} catch {
|
|
37
|
+
throw new TargetProtocolError('Runtime bundle is not serializable');
|
|
38
|
+
}
|
|
39
|
+
if (body === undefined || Buffer.byteLength(body) > maximum) {
|
|
40
|
+
throw new TargetProtocolError('Runtime bundle exceeds the advertised size bound');
|
|
41
|
+
}
|
|
42
|
+
return body;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function installRuntime(options: RuntimeInstallOptions): Promise<void> {
|
|
46
|
+
validOpaque(options.capsuleId, 'capsule id');
|
|
47
|
+
validOpaque(options.accessToken, 'capsule access token');
|
|
48
|
+
let path: string;
|
|
49
|
+
try {
|
|
50
|
+
path = options.descriptor.install.routeTemplate.expand({
|
|
51
|
+
capsule_id: options.capsuleId,
|
|
52
|
+
});
|
|
53
|
+
} catch {
|
|
54
|
+
throw new TargetProtocolError('Runtime install route expansion is unsafe');
|
|
55
|
+
}
|
|
56
|
+
const body = runtimeBody(options.runtime, options.descriptor.maxBodyBytes);
|
|
57
|
+
await withTargetRetry(
|
|
58
|
+
'installRuntime',
|
|
59
|
+
async () => {
|
|
60
|
+
const response = await options.request(
|
|
61
|
+
options.descriptor.install.method,
|
|
62
|
+
path,
|
|
63
|
+
options.signal,
|
|
64
|
+
body,
|
|
65
|
+
options.accessToken
|
|
66
|
+
);
|
|
67
|
+
await assertCapsuleResponseStatus(
|
|
68
|
+
response,
|
|
69
|
+
204,
|
|
70
|
+
(errorResponse) =>
|
|
71
|
+
readBoundedResponseJson(
|
|
72
|
+
errorResponse,
|
|
73
|
+
MAX_RESPONSE_BYTES,
|
|
74
|
+
() => new TargetProtocolError('Capsule error response is malformed')
|
|
75
|
+
),
|
|
76
|
+
options.clock
|
|
77
|
+
);
|
|
78
|
+
await response.body?.cancel().catch(() => undefined);
|
|
79
|
+
},
|
|
80
|
+
options.signal,
|
|
81
|
+
{ clock: options.clock, policy: options.retryPolicy }
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { IDEMPOTENCY_KEY_PATTERN, MAX_RESPONSE_BYTES } from './bounds.js';
|
|
2
|
-
import {
|
|
3
|
-
TargetAdapterError,
|
|
4
|
-
TargetAuthError,
|
|
5
|
-
TargetProtocolError,
|
|
6
|
-
TargetTransportError,
|
|
7
|
-
} from './errors.js';
|
|
2
|
+
import { TargetProtocolError } from './errors.js';
|
|
8
3
|
import { DefaultRetryPolicy } from './retry.js';
|
|
9
4
|
import {
|
|
10
5
|
assertCapsule,
|
|
@@ -20,34 +15,23 @@ import type {
|
|
|
20
15
|
CapsuleLimits,
|
|
21
16
|
CapsuleListPage,
|
|
22
17
|
Clock,
|
|
23
|
-
HttpTransport,
|
|
24
18
|
ListRequest,
|
|
25
19
|
RetryPolicy,
|
|
26
|
-
TargetAccessTokenProvider,
|
|
27
20
|
} from './types.js';
|
|
28
21
|
import type { TargetDiscoveryDescriptor } from '../target/discovery.js';
|
|
29
22
|
import { readBoundedResponseJson } from '../target/bounded-response.js';
|
|
30
|
-
import { throwCapsuleServerError } from './capsule-error-response.js';
|
|
31
23
|
import { validateAccessUrl } from './access-url.js';
|
|
32
24
|
import { withTargetRetry } from './retry-executor.js';
|
|
25
|
+
import { installRuntime as installOpaqueRuntime } from './runtime-install.js';
|
|
26
|
+
import { assertCapsuleResponseStatus } from './response-status.js';
|
|
33
27
|
import {
|
|
34
|
-
|
|
35
|
-
type
|
|
28
|
+
createAdapterRequester,
|
|
29
|
+
type AdapterRequester,
|
|
36
30
|
type ExecuteArguments,
|
|
37
31
|
} from './adapter-request.js';
|
|
38
32
|
|
|
39
|
-
const DEFAULT_TRANSPORT: HttpTransport = {
|
|
40
|
-
fetch(url, init) {
|
|
41
|
-
return globalThis.fetch(url, init);
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
33
|
const DEFAULT_CLOCK: Clock = { now: () => Date.now() };
|
|
45
34
|
|
|
46
|
-
function throwIfAborted(signal?: AbortSignal): void {
|
|
47
|
-
if (signal?.aborted)
|
|
48
|
-
throw signal.reason ?? new globalThis.DOMException('The operation was aborted', 'AbortError');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
35
|
function validOpaque(value: string, field: string): void {
|
|
52
36
|
if (value.length === 0 || value.length > 1024)
|
|
53
37
|
throw new TargetProtocolError(`${field} is invalid`);
|
|
@@ -57,12 +41,10 @@ function jsonRequest(body: unknown): string {
|
|
|
57
41
|
return JSON.stringify(body);
|
|
58
42
|
}
|
|
59
43
|
|
|
60
|
-
|
|
61
44
|
export class ZeroCloudV1TargetAdapter implements TargetAdapter {
|
|
62
45
|
readonly #descriptor: TargetDiscoveryDescriptor;
|
|
63
46
|
readonly #organizationId: string;
|
|
64
|
-
readonly #
|
|
65
|
-
readonly #transport: HttpTransport;
|
|
47
|
+
readonly #request: AdapterRequester;
|
|
66
48
|
readonly #clock: Clock;
|
|
67
49
|
readonly #retryPolicy: RetryPolicy;
|
|
68
50
|
|
|
@@ -70,8 +52,11 @@ export class ZeroCloudV1TargetAdapter implements TargetAdapter {
|
|
|
70
52
|
this.#descriptor = options.descriptor;
|
|
71
53
|
this.#organizationId = options.organization.id;
|
|
72
54
|
validOpaque(this.#organizationId, 'organization id');
|
|
73
|
-
this.#
|
|
74
|
-
|
|
55
|
+
this.#request = createAdapterRequester(
|
|
56
|
+
options.descriptor,
|
|
57
|
+
options.tokenProvider,
|
|
58
|
+
options.transport
|
|
59
|
+
);
|
|
75
60
|
this.#clock = options.clock ?? DEFAULT_CLOCK;
|
|
76
61
|
this.#retryPolicy = options.retryPolicy ?? new DefaultRetryPolicy();
|
|
77
62
|
}
|
|
@@ -199,21 +184,42 @@ export class ZeroCloudV1TargetAdapter implements TargetAdapter {
|
|
|
199
184
|
return result;
|
|
200
185
|
}
|
|
201
186
|
|
|
187
|
+
async installRuntime(
|
|
188
|
+
capsuleId: string,
|
|
189
|
+
runtime: unknown,
|
|
190
|
+
accessToken: string,
|
|
191
|
+
signal?: AbortSignal
|
|
192
|
+
): Promise<void> {
|
|
193
|
+
const descriptor = this.#descriptor.credentialInstall;
|
|
194
|
+
if (descriptor === null) {
|
|
195
|
+
throw new TargetProtocolError('Target does not advertise runtime installation');
|
|
196
|
+
}
|
|
197
|
+
await installOpaqueRuntime({
|
|
198
|
+
capsuleId,
|
|
199
|
+
runtime,
|
|
200
|
+
accessToken,
|
|
201
|
+
descriptor,
|
|
202
|
+
...(signal === undefined ? {} : { signal }),
|
|
203
|
+
clock: this.#clock,
|
|
204
|
+
retryPolicy: this.#retryPolicy,
|
|
205
|
+
request: (method, path, requestSignal, body, token) =>
|
|
206
|
+
this.#request({
|
|
207
|
+
method,
|
|
208
|
+
path,
|
|
209
|
+
signal: requestSignal,
|
|
210
|
+
request: { body },
|
|
211
|
+
accessToken: token,
|
|
212
|
+
}),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
202
216
|
#execute<T>(...args: ExecuteArguments<T>): Promise<T> {
|
|
203
217
|
return Promise.resolve().then(() => this.#executeExpanded(args));
|
|
204
218
|
}
|
|
205
219
|
|
|
206
220
|
#executeExpanded<T>(args: ExecuteArguments<T>): Promise<T> {
|
|
207
|
-
const [
|
|
208
|
-
|
|
209
|
-
method,
|
|
210
|
-
template,
|
|
211
|
-
values,
|
|
212
|
-
expectedStatus,
|
|
213
|
-
validate,
|
|
214
|
-
signal,
|
|
215
|
-
request = {},
|
|
216
|
-
] = args;
|
|
221
|
+
const [operation, method, template, values, expectedStatus, validate, signal, request = {}] =
|
|
222
|
+
args;
|
|
217
223
|
let path: string;
|
|
218
224
|
try {
|
|
219
225
|
path = template.expand(values);
|
|
@@ -223,77 +229,36 @@ export class ZeroCloudV1TargetAdapter implements TargetAdapter {
|
|
|
223
229
|
return withTargetRetry(
|
|
224
230
|
operation,
|
|
225
231
|
async () => {
|
|
226
|
-
const response = await this.#request(
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
this.#clock,
|
|
240
|
-
);
|
|
241
|
-
}
|
|
232
|
+
const response = await this.#request({
|
|
233
|
+
method,
|
|
234
|
+
path,
|
|
235
|
+
signal,
|
|
236
|
+
request,
|
|
237
|
+
accessToken: undefined,
|
|
238
|
+
});
|
|
239
|
+
await assertCapsuleResponseStatus(
|
|
240
|
+
response,
|
|
241
|
+
expectedStatus,
|
|
242
|
+
(errorResponse) => this.#readJson(errorResponse),
|
|
243
|
+
this.#clock
|
|
244
|
+
);
|
|
242
245
|
return validate(await this.#readJson(response));
|
|
243
246
|
},
|
|
244
247
|
signal,
|
|
245
|
-
{ clock: this.#clock, policy: this.#retryPolicy }
|
|
248
|
+
{ clock: this.#clock, policy: this.#retryPolicy }
|
|
246
249
|
);
|
|
247
250
|
}
|
|
248
251
|
|
|
249
|
-
async #request(
|
|
250
|
-
method: string,
|
|
251
|
-
path: string,
|
|
252
|
-
signal: AbortSignal | undefined,
|
|
253
|
-
request: AdapterRequest,
|
|
254
|
-
): Promise<Response> {
|
|
255
|
-
throwIfAborted(signal);
|
|
256
|
-
const url = requestUrl(path, this.#descriptor);
|
|
257
|
-
let token: string;
|
|
258
|
-
try {
|
|
259
|
-
token = await this.#tokenProvider.getAccessToken(signal);
|
|
260
|
-
} catch {
|
|
261
|
-
throw new TargetAuthError('Target access authorization failed');
|
|
262
|
-
}
|
|
263
|
-
const init: RequestInit & { redirect: 'manual' } = {
|
|
264
|
-
method,
|
|
265
|
-
headers: {
|
|
266
|
-
Accept: 'application/json',
|
|
267
|
-
Authorization: `Bearer ${token}`,
|
|
268
|
-
...(request.body === undefined ? {} : { 'Content-Type': 'application/json' }),
|
|
269
|
-
...request.headers,
|
|
270
|
-
},
|
|
271
|
-
redirect: 'manual',
|
|
272
|
-
};
|
|
273
|
-
if (request.body !== undefined) init.body = request.body;
|
|
274
|
-
if (signal !== undefined) init.signal = signal;
|
|
275
|
-
try {
|
|
276
|
-
const response = await this.#transport.fetch(url.href, init);
|
|
277
|
-
if (response.url && new globalThis.URL(response.url).href !== url.href) {
|
|
278
|
-
await response.body?.cancel().catch(() => undefined);
|
|
279
|
-
throw new TargetProtocolError('Capsule response changed target route');
|
|
280
|
-
}
|
|
281
|
-
return response;
|
|
282
|
-
} catch (error) {
|
|
283
|
-
if (error instanceof TargetAdapterError) throw error;
|
|
284
|
-
throwIfAborted(signal);
|
|
285
|
-
throw new TargetTransportError('Capsule transport failed');
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
252
|
#readJson(response: Response): Promise<unknown> {
|
|
291
|
-
return readBoundedResponseJson(
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
253
|
+
return readBoundedResponseJson(
|
|
254
|
+
response,
|
|
255
|
+
MAX_RESPONSE_BYTES,
|
|
256
|
+
(kind) =>
|
|
257
|
+
new TargetProtocolError(
|
|
258
|
+
kind === 'size'
|
|
259
|
+
? 'Capsule response exceeds the size limit'
|
|
260
|
+
: 'Capsule response is not valid UTF-8 JSON'
|
|
261
|
+
)
|
|
297
262
|
);
|
|
298
263
|
}
|
|
299
264
|
}
|
|
@@ -3,16 +3,8 @@ import { routeTemplate, type RouteTemplate } from './route-template.js';
|
|
|
3
3
|
|
|
4
4
|
export interface CredentialInstallDescriptor {
|
|
5
5
|
readonly kind: 'openengine.capsule-credential-install/v1';
|
|
6
|
-
readonly grant: { readonly routeTemplate: RouteTemplate; readonly method: 'POST' };
|
|
7
6
|
readonly install: { readonly routeTemplate: RouteTemplate; readonly method: 'PUT' };
|
|
8
|
-
readonly
|
|
9
|
-
readonly sealedEnvelopeAlgorithms: readonly ['RSA-OAEP-3072-SHA256'];
|
|
10
|
-
readonly bounds: {
|
|
11
|
-
readonly maxEnvelopeBytes: number;
|
|
12
|
-
readonly maxBodyBytes: number;
|
|
13
|
-
readonly grantTtlSeconds: number;
|
|
14
|
-
readonly maxClockSkewSeconds: number;
|
|
15
|
-
};
|
|
7
|
+
readonly maxBodyBytes: number;
|
|
16
8
|
}
|
|
17
9
|
|
|
18
10
|
export function record(value: unknown, field: string): Record<string, unknown> {
|
|
@@ -116,29 +108,35 @@ export function sameOriginUrl(
|
|
|
116
108
|
export function parseCredentialInstall(value: unknown): CredentialInstallDescriptor | null {
|
|
117
109
|
if (value === undefined || value === null) return null;
|
|
118
110
|
const extension = closedRecord(value, 'extensions.credential_install', [
|
|
119
|
-
'kind',
|
|
111
|
+
'kind',
|
|
112
|
+
'install',
|
|
113
|
+
'max_body_bytes',
|
|
120
114
|
]);
|
|
121
|
-
exact(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
'max_envelope_bytes', 'max_body_bytes', 'grant_ttl_seconds', 'max_clock_skew_seconds',
|
|
115
|
+
exact(
|
|
116
|
+
extension.kind,
|
|
117
|
+
'openengine.capsule-credential-install/v1',
|
|
118
|
+
'extensions.credential_install.kind'
|
|
119
|
+
);
|
|
120
|
+
const install = closedRecord(extension.install, 'extensions.credential_install.install', [
|
|
121
|
+
'route_template',
|
|
122
|
+
'method',
|
|
130
123
|
]);
|
|
124
|
+
exact(install.method, 'PUT', 'extensions.credential_install.install.method');
|
|
131
125
|
return Object.freeze({
|
|
132
126
|
kind: 'openengine.capsule-credential-install/v1' as const,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
grantTtlSeconds: integer(bounds.grant_ttl_seconds, 'extensions.credential_install.bounds.grant_ttl_seconds', 1, 3_600),
|
|
141
|
-
maxClockSkewSeconds: integer(bounds.max_clock_skew_seconds, 'extensions.credential_install.bounds.max_clock_skew_seconds', 0, 300),
|
|
127
|
+
install: Object.freeze({
|
|
128
|
+
routeTemplate: routeTemplate(
|
|
129
|
+
install.route_template,
|
|
130
|
+
'extensions.credential_install.install.route_template',
|
|
131
|
+
['capsule_id']
|
|
132
|
+
),
|
|
133
|
+
method: 'PUT' as const,
|
|
142
134
|
}),
|
|
135
|
+
maxBodyBytes: integer(
|
|
136
|
+
extension.max_body_bytes,
|
|
137
|
+
'extensions.credential_install.max_body_bytes',
|
|
138
|
+
1,
|
|
139
|
+
4 * 1024 * 1024
|
|
140
|
+
),
|
|
143
141
|
});
|
|
144
142
|
}
|
package/task-lib/runner.js
CHANGED
|
@@ -43,6 +43,8 @@ const {
|
|
|
43
43
|
partitionPathFor,
|
|
44
44
|
createOmpSessionPartitionDirectory,
|
|
45
45
|
} = require('../src/omp-session-partition');
|
|
46
|
+
const TASK_EXECUTION_CONTEXT_ENV = 'ZEROSHOT_TASK_EXECUTION_CONTEXT';
|
|
47
|
+
const TASK_EXECUTION_CONTEXTS = new Set(['host', 'detached', 'docker', 'benchmark']);
|
|
46
48
|
export {
|
|
47
49
|
isOwnedProcessTreeRunning,
|
|
48
50
|
isProcessRunning,
|
|
@@ -413,7 +415,7 @@ function buildProviderOptions(options, runtime, modelSelection) {
|
|
|
413
415
|
outputFormat: runtime.outputFormat,
|
|
414
416
|
jsonSchema: runtime.jsonSchema,
|
|
415
417
|
cwd: runtime.cwd,
|
|
416
|
-
executionContext:
|
|
418
|
+
executionContext: resolveTaskExecutionContext(),
|
|
417
419
|
autoApprove: !structuredOutputRecovery,
|
|
418
420
|
...(modelSelection === undefined ? {} : { modelSpec: modelSelection.modelSpec }),
|
|
419
421
|
...(structuredOutputRecovery ? {} : mcpConfigOption(options)),
|
|
@@ -428,6 +430,17 @@ function buildProviderOptions(options, runtime, modelSelection) {
|
|
|
428
430
|
};
|
|
429
431
|
}
|
|
430
432
|
|
|
433
|
+
export function resolveTaskExecutionContext(environment = process.env) {
|
|
434
|
+
const context = environment[TASK_EXECUTION_CONTEXT_ENV];
|
|
435
|
+
if (context === undefined) return 'detached';
|
|
436
|
+
if (!TASK_EXECUTION_CONTEXTS.has(context)) {
|
|
437
|
+
throw new Error(
|
|
438
|
+
`${TASK_EXECUTION_CONTEXT_ENV} must be one of: ${[...TASK_EXECUTION_CONTEXTS].join(', ')}.`
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
return context;
|
|
442
|
+
}
|
|
443
|
+
|
|
431
444
|
function claudeSettingsFileOption() {
|
|
432
445
|
const settingsPath = process.env[CLAUDE_SETTINGS_ENV]?.trim();
|
|
433
446
|
return settingsPath ? { claudeSettingsFile: settingsPath } : {};
|