@the-open-engine/zeroshot 6.39.1 → 6.40.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.
Files changed (121) hide show
  1. package/README.md +45 -1
  2. package/cli/agent-provider-boundary.js +19 -0
  3. package/cli/agent-provider-boundary.ts +79 -0
  4. package/cli/export-stream.js +94 -0
  5. package/cli/export-stream.ts +118 -0
  6. package/cli/index.js +132 -61
  7. package/cli/json-export.js +2 -38
  8. package/cli/json-export.ts +2 -56
  9. package/cli/semantic-canonical.js +60 -0
  10. package/cli/semantic-canonical.ts +59 -0
  11. package/cli/semantic-contract.js +97 -0
  12. package/cli/semantic-contract.ts +153 -0
  13. package/cli/semantic-events.js +53 -0
  14. package/cli/semantic-events.ts +65 -0
  15. package/cli/semantic-evidence.js +63 -0
  16. package/cli/semantic-evidence.ts +65 -0
  17. package/cli/semantic-export.js +186 -0
  18. package/cli/semantic-export.ts +245 -0
  19. package/cli/semantic-json.js +69 -0
  20. package/cli/semantic-json.ts +69 -0
  21. package/cli/semantic-line-scanner.js +56 -0
  22. package/cli/semantic-line-scanner.ts +54 -0
  23. package/cli/semantic-parser.js +78 -0
  24. package/cli/semantic-parser.ts +95 -0
  25. package/cli/semantic-provider-line.js +91 -0
  26. package/cli/semantic-provider-line.ts +106 -0
  27. package/cli/trace-evidence.js +86 -0
  28. package/cli/trace-evidence.ts +115 -0
  29. package/cli/trace-export.js +120 -0
  30. package/cli/trace-export.ts +164 -0
  31. package/cli/trace-output-record.js +15 -0
  32. package/cli/trace-output-record.ts +18 -0
  33. package/cli/trace-output.js +98 -0
  34. package/cli/trace-output.ts +119 -0
  35. package/cluster-templates/conductor-bootstrap.json +1 -1
  36. package/lib/agent-cli-provider/adapters/claude.js +1 -1
  37. package/lib/agent-cli-provider/adapters/claude.js.map +1 -1
  38. package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
  39. package/lib/agent-cli-provider/adapters/codex.js +26 -1
  40. package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
  41. package/lib/agent-cli-provider/adapters/omp.d.ts.map +1 -1
  42. package/lib/agent-cli-provider/adapters/omp.js +1 -1
  43. package/lib/agent-cli-provider/adapters/omp.js.map +1 -1
  44. package/lib/agent-cli-provider/log-prefix.d.ts.map +1 -1
  45. package/lib/agent-cli-provider/log-prefix.js +8 -6
  46. package/lib/agent-cli-provider/log-prefix.js.map +1 -1
  47. package/lib/agent-cli-provider/omp/sdk-environment-policy.d.ts +4 -0
  48. package/lib/agent-cli-provider/omp/sdk-environment-policy.d.ts.map +1 -0
  49. package/lib/agent-cli-provider/omp/sdk-environment-policy.js +37 -0
  50. package/lib/agent-cli-provider/omp/sdk-environment-policy.js.map +1 -0
  51. package/lib/agent-cli-provider/omp/sdk-process-private-runtime.d.ts.map +1 -1
  52. package/lib/agent-cli-provider/omp/sdk-process-private-runtime.js +4 -15
  53. package/lib/agent-cli-provider/omp/sdk-process-private-runtime.js.map +1 -1
  54. package/lib/agent-cli-provider/omp/sdk-process-result.d.ts +2 -0
  55. package/lib/agent-cli-provider/omp/sdk-process-result.d.ts.map +1 -1
  56. package/lib/agent-cli-provider/omp/sdk-process-result.js +2 -2
  57. package/lib/agent-cli-provider/omp/sdk-process-result.js.map +1 -1
  58. package/lib/agent-cli-provider/omp/sdk-process-runner.d.ts.map +1 -1
  59. package/lib/agent-cli-provider/omp/sdk-process-runner.js +6 -1
  60. package/lib/agent-cli-provider/omp/sdk-process-runner.js.map +1 -1
  61. package/lib/agent-cli-provider/provider-registry.d.ts +3 -1
  62. package/lib/agent-cli-provider/provider-registry.d.ts.map +1 -1
  63. package/lib/agent-cli-provider/provider-registry.js +9 -2
  64. package/lib/agent-cli-provider/provider-registry.js.map +1 -1
  65. package/lib/agent-cli-provider/single-agent-runtime.d.ts +4 -1
  66. package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -1
  67. package/lib/agent-cli-provider/single-agent-runtime.js +18 -15
  68. package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -1
  69. package/lib/agent-cli-provider/types.d.ts +3 -0
  70. package/lib/agent-cli-provider/types.d.ts.map +1 -1
  71. package/lib/agent-cli-provider/types.js.map +1 -1
  72. package/lib/cluster-worker/engine-adapter-common.js +18 -0
  73. package/lib/cluster-worker/engine-adapter.js +2 -1
  74. package/lib/git-remote-utils.js +22 -5
  75. package/lib/stream-json-parser.js +6 -5
  76. package/npm-shrinkwrap.json +2 -2
  77. package/package.json +7 -4
  78. package/scripts/omp/runtime-identities.js +31 -18
  79. package/scripts/omp/runtime.js +2 -0
  80. package/src/agent/agent-lifecycle.js +17 -1
  81. package/src/agent/agent-task-executor.js +36 -40
  82. package/src/agent/output-extraction-failures.js +73 -0
  83. package/src/agent/output-extraction-failures.ts +100 -0
  84. package/src/agent/output-extraction-json.js +5 -6
  85. package/src/agent/output-extraction-json.ts +4 -7
  86. package/src/agent/output-extraction-types.ts +5 -0
  87. package/src/agent/provider-terminal-failure.js +2 -2
  88. package/src/agent/provider-terminal-failure.ts +4 -2
  89. package/src/agent-cli-provider/adapters/claude.ts +1 -1
  90. package/src/agent-cli-provider/adapters/codex.ts +36 -1
  91. package/src/agent-cli-provider/adapters/omp.ts +2 -1
  92. package/src/agent-cli-provider/log-prefix.ts +12 -7
  93. package/src/agent-cli-provider/omp/sdk-environment-policy.ts +38 -0
  94. package/src/agent-cli-provider/omp/sdk-process-private-runtime.ts +4 -16
  95. package/src/agent-cli-provider/omp/sdk-process-result.ts +4 -2
  96. package/src/agent-cli-provider/omp/sdk-process-runner.ts +7 -1
  97. package/src/agent-cli-provider/provider-registry.ts +10 -2
  98. package/src/agent-cli-provider/single-agent-runtime.ts +24 -15
  99. package/src/agent-cli-provider/types.ts +3 -0
  100. package/src/agents/git-pusher-template.js +61 -71
  101. package/src/attach/socket-paths.js +1 -1
  102. package/src/attach/socket-paths.ts +1 -1
  103. package/src/claude-task-runner.js +9 -9
  104. package/src/foreground-benchmark-run.js +24 -12
  105. package/src/legacy-lib/git-remote-utils.ts +23 -5
  106. package/src/legacy-lib/stream-json-parser.ts +10 -5
  107. package/src/omp-session-verifier.js +8 -5
  108. package/src/orchestrator.js +42 -0
  109. package/src/preflight.js +31 -6
  110. package/src/providers/index.js +4 -22
  111. package/src/task-execution-context.js +22 -0
  112. package/src/task-log-line.d.ts +20 -0
  113. package/src/task-log-line.js +80 -0
  114. package/src/watcher-prompt-channel.js +1 -1
  115. package/src/worktree-claude-config.js +25 -0
  116. package/src/worktree-claude-config.ts +28 -0
  117. package/task-lib/commands/logs.js +5 -8
  118. package/task-lib/runner.js +57 -22
  119. package/task-lib/sdk-watcher-output.js +31 -0
  120. package/task-lib/sdk-watcher.js +4 -11
  121. package/task-lib/watcher-output-runtime.js +30 -16
@@ -73,6 +73,7 @@ function detectCliFeatures(
73
73
  supportsIgnoreUserConfig: !unknown && /--ignore-user-config\b/.test(help),
74
74
  supportsIgnoreRules: !unknown && /--ignore-rules\b/.test(help),
75
75
  supportsStrictConfig: !unknown && /--strict-config\b/.test(help),
76
+ supportsAddDir: !unknown && /--add-dir\b/.test(help),
76
77
  unknown,
77
78
  };
78
79
  }
@@ -119,6 +120,14 @@ function addAutoApproveArgs(args: string[], options: BuildProviderCommandOptions
119
120
  ? 'danger-full-access'
120
121
  : 'workspace-write';
121
122
  args.push('--sandbox', sandboxMode, '--config', 'approval_policy="never"');
123
+ if (sandboxMode === 'workspace-write') {
124
+ args.push('--config', 'sandbox_workspace_write.network_access=true');
125
+ }
126
+ if (features.supportsAddDir) {
127
+ for (const directory of new Set(options.additionalWritableDirectories ?? [])) {
128
+ args.push('--add-dir', directory);
129
+ }
130
+ }
122
131
  }
123
132
  }
124
133
 
@@ -129,6 +138,18 @@ function addSkipGitArgs(args: string[], options: BuildProviderCommandOptions): v
129
138
  }
130
139
  }
131
140
 
141
+ function codexExecAuthEnv(
142
+ authEnv: Readonly<Record<string, string>>
143
+ ): Readonly<Record<string, string>> {
144
+ const openAiApiKey = authEnv.OPENAI_API_KEY;
145
+ if (openAiApiKey === undefined) return authEnv;
146
+ const { OPENAI_API_KEY: _openAiApiKey, ...rest } = authEnv;
147
+ return {
148
+ ...rest,
149
+ CODEX_API_KEY: rest.CODEX_API_KEY ?? openAiApiKey,
150
+ };
151
+ }
152
+
132
153
  function applySchemaArgs(
133
154
  args: string[],
134
155
  cleanup: string[],
@@ -175,6 +196,19 @@ function collectWarnings(options: BuildProviderCommandOptions): WarningMetadata[
175
196
  )
176
197
  );
177
198
  }
199
+ if (
200
+ options.autoApprove &&
201
+ (options.additionalWritableDirectories?.length ?? 0) > 0 &&
202
+ features.supportsAddDir === false
203
+ ) {
204
+ warnings.push(
205
+ warning(
206
+ 'codex',
207
+ 'codex-add-dir',
208
+ 'Codex CLI does not support --add-dir; Git worktree metadata outside cwd may be read-only.'
209
+ )
210
+ );
211
+ }
178
212
  if (options.jsonSchema && features.supportsOutputSchema === false) {
179
213
  warnings.push(
180
214
  warning(
@@ -216,6 +250,7 @@ function buildCommand(context: string, options: BuildProviderCommandOptions = {}
216
250
  }
217
251
  const args: string[] = ['exec'];
218
252
  const cleanup: string[] = [];
253
+ const authEnv = options.authEnv ?? {};
219
254
  const resumeSessionId =
220
255
  options.resumeSessionId && optionFeatures(options).supportsResume !== false
221
256
  ? options.resumeSessionId
@@ -244,7 +279,7 @@ function buildCommand(context: string, options: BuildProviderCommandOptions = {}
244
279
  return commandSpec({
245
280
  binary: 'codex',
246
281
  args,
247
- env: {},
282
+ env: codexExecAuthEnv(authEnv),
248
283
  ...(options.cwd === undefined ? {} : { cwd: options.cwd }),
249
284
  cleanup,
250
285
  cleanupMetadata: cleanup.map((schemaFile) => ({
@@ -73,7 +73,8 @@ const LEVEL_MAPPING: Readonly<Record<ModelLevel, LevelModelSpec>> = {
73
73
  const CREDENTIAL_ENV_KEYS = OMP_CREDENTIAL_ENV_KEYS;
74
74
 
75
75
  const VERSION_TOKEN_PATTERN = /(?<![\w.])17\.2\.1(?![\w.])/;
76
- const MODEL_ID_PATTERN = /^@?[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/u;
76
+ const MODEL_ID_PATTERN =
77
+ /^(?=.{1,128}$)(?:@?[A-Za-z0-9][A-Za-z0-9._:/-]*|[a-z0-9][a-z0-9._-]*\/~[A-Za-z0-9][A-Za-z0-9._:/-]*)$/u;
77
78
 
78
79
  function detectCliFeatures(helpText?: string | null, versionText?: string | null): OmpCliFeatures {
79
80
  const help = helpText ?? '';
@@ -1,13 +1,18 @@
1
+ interface TaskLogDecoder {
2
+ decodeTaskLogLine(line: string): { readonly content: string; readonly providerOutput: boolean };
3
+ }
4
+
5
+ // The canonical decoder is maintained JavaScript and remains at the same source path after build.
6
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
7
+ const taskLogDecoder: TaskLogDecoder = require('../../src/task-log-line');
8
+ const { decodeTaskLogLine } = taskLogDecoder;
9
+
1
10
  export function stripTimestampPrefix(line: string): string {
2
- let trimmed = line.trim().replace(/\r$/, '');
11
+ const decoded = decodeTaskLogLine(line.trim());
12
+ if (!decoded.providerOutput) return '';
13
+ let trimmed = decoded.content;
3
14
  if (!trimmed) return '';
4
15
 
5
- const timestampMatch = /^\[(\d{13})\](.*)$/.exec(trimmed);
6
- const timestampRemainder = timestampMatch?.[2];
7
- if (typeof timestampRemainder === 'string') {
8
- trimmed = timestampRemainder.trimStart();
9
- }
10
-
11
16
  if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
12
17
  const pipeMatch = /^[^|]{1,40}\|\s*(.*)$/.exec(trimmed);
13
18
  const afterPipe = pipeMatch?.[1]?.trimStart();
@@ -0,0 +1,38 @@
1
+ import { getProviderRegistryEntry } from '../provider-registry';
2
+ import type { PreparedEnvironmentPolicy } from '../types';
3
+
4
+ const MINIMAL_ENV_NAMES = [
5
+ 'ALL_PROXY',
6
+ 'HTTP_PROXY',
7
+ 'HTTPS_PROXY',
8
+ 'LANG',
9
+ 'LC_ALL',
10
+ 'NO_PROXY',
11
+ 'PATH',
12
+ 'SSL_CERT_DIR',
13
+ 'SSL_CERT_FILE',
14
+ 'TZ',
15
+ ] as const;
16
+
17
+ const ALLOWED_ENV_NAMES = new Set([
18
+ ...MINIMAL_ENV_NAMES,
19
+ ...(getProviderRegistryEntry('omp').configurationEnvKeys ?? []),
20
+ ]);
21
+
22
+ export function isOmpSdkEnvironmentName(name: string): boolean {
23
+ return ALLOWED_ENV_NAMES.has(name.toUpperCase());
24
+ }
25
+
26
+ export function ompSdkEnvironmentPolicy(
27
+ environment: NodeJS.ProcessEnv = process.env
28
+ ): PreparedEnvironmentPolicy {
29
+ const values: Record<string, string> = {};
30
+ for (const name of ALLOWED_ENV_NAMES) {
31
+ const value = environment[name];
32
+ if (value !== undefined) values[name] = value;
33
+ }
34
+ return {
35
+ inherit: 'minimal',
36
+ values: Object.freeze(values),
37
+ };
38
+ }
@@ -19,6 +19,7 @@ import type {
19
19
  PreparedProviderInvoke,
20
20
  } from '../types';
21
21
  import type { ProcessResult, ProcessRunnerOptions } from '../process-runner';
22
+ import { isOmpSdkEnvironmentName } from './sdk-environment-policy';
22
23
  import { OmpSdkProcessRunnerError } from './sdk-process-error';
23
24
 
24
25
  export { credentialPayload, redactDiagnostic } from './sdk-process-credentials';
@@ -33,19 +34,6 @@ const PRIVATE_ENV_NAMES = new Set([
33
34
  'XDG_STATE_HOME',
34
35
  'PI_CODING_AGENT_DIR',
35
36
  ]);
36
- const MINIMAL_ENV_NAMES = new Set([
37
- 'ALL_PROXY',
38
- 'HTTP_PROXY',
39
- 'HTTPS_PROXY',
40
- 'LANG',
41
- 'LC_ALL',
42
- 'NO_PROXY',
43
- 'PATH',
44
- 'SSL_CERT_DIR',
45
- 'SSL_CERT_FILE',
46
- 'TZ',
47
- ]);
48
-
49
37
  export interface OmpSdkPreparedInvocation extends PreparedSingleAgentProviderCommand {
50
38
  readonly invoke: PreparedProviderInvoke & {
51
39
  readonly lane: 'spawn';
@@ -119,13 +107,13 @@ export function assertPrepared(
119
107
  }
120
108
  export function assertHostContainment(requirement: OmpSdkContainmentRequirement): void {
121
109
  if (
122
- requirement.mode !== 'host-process-tree' ||
110
+ (requirement.mode !== 'host-process-tree' && requirement.mode !== 'container') ||
123
111
  process.platform !== 'linux' ||
124
112
  (process.arch !== 'x64' && process.arch !== 'arm64')
125
113
  ) {
126
114
  throw new OmpSdkProcessRunnerError(
127
115
  'containment-error',
128
- 'OMP SDK host spawn requires the packaged Linux subreaper/pidfd supervisor; container invocations require the container spawn owner.'
116
+ 'OMP SDK spawn requires the packaged Linux subreaper/pidfd supervisor.'
129
117
  );
130
118
  }
131
119
  }
@@ -228,7 +216,7 @@ export function childEnvironment(
228
216
  for (const [name, value] of Object.entries(policy.values)) {
229
217
  const normalized = name.toUpperCase();
230
218
  if (
231
- !MINIMAL_ENV_NAMES.has(normalized) ||
219
+ !isOmpSdkEnvironmentName(normalized) ||
232
220
  PRIVATE_ENV_NAMES.has(normalized) ||
233
221
  /(?:^|_)(?:AUTH|CREDENTIAL|KEY|PASSWORD|SECRET|TOKEN)(?:_|$)/i.test(name)
234
222
  ) {
@@ -4,7 +4,7 @@ import type {
4
4
  OmpSdkProtocolCollector,
5
5
  OmpSdkSidecarRequest,
6
6
  } from './sdk-protocol';
7
- import type { OmpSdkCleanupAttestation } from '../types';
7
+ import type { OmpSdkCleanupAttestation, OmpSdkContainmentRequirement } from '../types';
8
8
  import { cancelledTerminal, type ChildOutcome } from './sdk-process-io';
9
9
  import {
10
10
  OmpSdkProcessRunnerError,
@@ -35,6 +35,7 @@ interface OmpSdkResultContext {
35
35
  readonly secretValues: readonly string[];
36
36
  readonly startedAt: number;
37
37
  readonly externalAbort: () => void;
38
+ readonly containmentMode: OmpSdkContainmentRequirement['mode'];
38
39
  }
39
40
 
40
41
  export async function collectOmpSdkProcessResult(
@@ -52,6 +53,7 @@ export async function collectOmpSdkProcessResult(
52
53
  secretValues,
53
54
  startedAt,
54
55
  externalAbort,
56
+ containmentMode,
55
57
  } = context;
56
58
  let rootRemoved = false;
57
59
  try {
@@ -113,7 +115,7 @@ export async function collectOmpSdkProcessResult(
113
115
  await removePrivateRoot(privateRuntime);
114
116
  rootRemoved = true;
115
117
  const cleanupAttestation: OmpSdkCleanupAttestation = {
116
- mode: 'host-process-tree',
118
+ mode: containmentMode,
117
119
  terminalBuffered: true,
118
120
  descendantsReaped: true,
119
121
  clean: true,
@@ -60,6 +60,10 @@ export async function spawnOmpSdkProcess(
60
60
  const environment = childEnvironment(prepared.environmentPolicy, privateRuntime);
61
61
  const { payload, secretValues } = credentialPayload(prepared.credentialNames, process.env);
62
62
  const requestProvider = request.modelSelector.slice(0, request.modelSelector.indexOf('/'));
63
+ const requestContainmentMode =
64
+ request.executionContext === 'docker' || request.executionContext === 'benchmark'
65
+ ? 'container'
66
+ : 'host-process-tree';
63
67
  const sidecarPath = prepared.commandSpec.args[0] ?? '';
64
68
  if (
65
69
  !isAbsolute(prepared.commandSpec.binary) ||
@@ -70,7 +74,8 @@ export async function spawnOmpSdkProcess(
70
74
  Object.keys(prepared.commandSpec.env).length !== 0 ||
71
75
  prepared.semanticIdentity.requestedModelSelector !== request.modelSelector ||
72
76
  prepared.semanticIdentity.reasoningEffort !== request.reasoningEffort ||
73
- prepared.semanticIdentity.provider !== requestProvider
77
+ prepared.semanticIdentity.provider !== requestProvider ||
78
+ prepared.containmentRequirement.mode !== requestContainmentMode
74
79
  ) {
75
80
  payload.fill(0);
76
81
  throw new OmpSdkProcessRunnerError(
@@ -258,6 +263,7 @@ export async function spawnOmpSdkProcess(
258
263
  secretValues,
259
264
  startedAt,
260
265
  externalAbort,
266
+ containmentMode: prepared.containmentRequirement.mode,
261
267
  });
262
268
 
263
269
  return {
@@ -128,6 +128,7 @@ interface ProviderRegistryEntryBase {
128
128
  readonly authInstructions: string;
129
129
  readonly credentialPaths: readonly string[];
130
130
  readonly credentialEnvKeys: readonly string[];
131
+ readonly configurationEnvKeys?: readonly string[];
131
132
  readonly settingsFields: readonly string[];
132
133
  readonly settingsDefaults?: Readonly<Record<string, unknown>>;
133
134
  readonly settingsValidator?: (
@@ -185,6 +186,12 @@ const STANDARD_CAPABILITIES: Readonly<
185
186
 
186
187
  const CLAUDE_DOCKER_ENV_PASSTHROUGH = [
187
188
  'ANTHROPIC_API_KEY',
189
+ 'ANTHROPIC_AUTH_TOKEN',
190
+ 'ANTHROPIC_BASE_URL',
191
+ 'ANTHROPIC_DEFAULT_OPUS_MODEL',
192
+ 'ANTHROPIC_DEFAULT_SONNET_MODEL',
193
+ 'ANTHROPIC_DEFAULT_HAIKU_MODEL',
194
+ 'CLAUDE_CODE_SUBAGENT_MODEL',
188
195
  'AWS_BEARER_TOKEN_BEDROCK',
189
196
  'AWS_REGION',
190
197
  'CLAUDE_CODE_USE_BEDROCK',
@@ -198,7 +205,7 @@ const PI_EXPLICIT_DOCKER_CREDENTIALS = new Set([
198
205
  'GOOGLE_APPLICATION_CREDENTIALS',
199
206
  ]);
200
207
 
201
- const PI_DOCKER_CONFIGURATION_ENV = [
208
+ const PI_AGENT_CONFIGURATION_ENV = [
202
209
  'AWS_BEDROCK_FORCE_CACHE',
203
210
  'AWS_BEDROCK_FORCE_HTTP1',
204
211
  'AWS_BEDROCK_SKIP_AUTH',
@@ -504,7 +511,7 @@ export const providerRegistry = [
504
511
  configRoots: ['$HOME/.pi/agent'],
505
512
  envPassthrough: [
506
513
  ...piAdapter.credentialEnvKeys.filter((name) => !PI_EXPLICIT_DOCKER_CREDENTIALS.has(name)),
507
- ...PI_DOCKER_CONFIGURATION_ENV,
514
+ ...PI_AGENT_CONFIGURATION_ENV,
508
515
  ],
509
516
  },
510
517
  defaultLevels: {
@@ -527,6 +534,7 @@ export const providerRegistry = [
527
534
  'Manually edit providerSettings.omp in ZEROSHOT_SETTINGS_FILE or $HOME/.zeroshot/settings.json (file 0600, parent directory 0700). Use declared environment or broker variables, an explicit host-only OMP agent directory containing agent.db, or keyless mode; Zeroshot never logs in or stores credential values.',
528
535
  credentialPaths: ['~/.omp'],
529
536
  credentialEnvKeys: ompAdapter.credentialEnvKeys,
537
+ configurationEnvKeys: PI_AGENT_CONFIGURATION_ENV,
530
538
  settingsFields: [
531
539
  'transport',
532
540
  'minLevel',
@@ -4,6 +4,7 @@ import * as os from 'node:os';
4
4
  import * as path from 'node:path';
5
5
 
6
6
  import { getProviderAdapter } from './adapters';
7
+ import { providerCredentialEnv } from './contract-env';
7
8
  import { UnsupportedProviderCapabilityError } from './errors';
8
9
  import { normalizeGatewayBuildOptions, resolveGatewayConfiguration } from './gateway-tools';
9
10
  import { isRecord } from './json';
@@ -21,6 +22,7 @@ import {
21
22
  parseExactOmpModelSelector,
22
23
  resolveOmpSdkSettings,
23
24
  } from './omp/sdk-settings';
25
+ import { ompSdkEnvironmentPolicy } from './omp/sdk-environment-policy';
24
26
  import type { ConfiguredOmpSdkSettings } from './omp/sdk-settings';
25
27
  import {
26
28
  getDefaultProviderId,
@@ -124,6 +126,10 @@ const commandExistsFn = moduleFunction(providerDetectionModule, 'commandExists')
124
126
  const getHelpOutputFn = moduleFunction(providerDetectionModule, 'getHelpOutput');
125
127
  const getVersionOutputFn = moduleFunction(providerDetectionModule, 'getVersionOutput');
126
128
  const resolveOmpSdkRuntimeFn = moduleFunction(ompSdkRuntimeModule, 'resolveOmpSdkRuntime');
129
+ const resolveOmpSdkContainerRuntimeFn = moduleFunction(
130
+ ompSdkRuntimeModule,
131
+ 'resolveOmpSdkContainerRuntime'
132
+ );
127
133
 
128
134
  export const resolveOmpTransport = (runtimeSettings?: Record<string, unknown>): 'sdk' | 'rpc' => {
129
135
  const settings = runtimeSettings ?? loadRuntimeSettings();
@@ -325,14 +331,7 @@ function prepareOmpProviderCommand(
325
331
  }
326
332
 
327
333
  const usesContainerRuntime = executionContext === 'docker' || executionContext === 'benchmark';
328
- const runtime = usesContainerRuntime
329
- ? {
330
- bunExecutable: '/opt/zeroshot/node_modules/bun/bin/bun.exe',
331
- bunVersion: OMP_SDK_BUN_VERSION,
332
- ompVersion: OMP_SDK_BACKEND_VERSION,
333
- sidecarPath: '/opt/zeroshot/scripts/omp/sidecar.ts',
334
- }
335
- : ompSdkRuntimeAssets();
334
+ const runtime = usesContainerRuntime ? ompSdkContainerRuntimeAssets() : ompSdkRuntimeAssets();
336
335
  let privateRoot: string | undefined;
337
336
  try {
338
337
  privateRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'zeroshot-omp-sdk-request-'));
@@ -356,10 +355,7 @@ function prepareOmpProviderCommand(
356
355
  webSearch: { requested: false, effective: false },
357
356
  },
358
357
  invoke,
359
- environmentPolicy: {
360
- inherit: 'minimal',
361
- values: Object.freeze({}),
362
- },
358
+ environmentPolicy: ompSdkEnvironmentPolicy(),
363
359
  credentialNames,
364
360
  privateArtifacts: {
365
361
  root: privateRoot,
@@ -483,7 +479,14 @@ function requiredStringValue(value: unknown, field: string): string {
483
479
  }
484
480
 
485
481
  function ompSdkRuntimeAssets(): OmpSdkRuntimeAssets {
486
- const value = resolveOmpSdkRuntimeFn();
482
+ return validatedOmpSdkRuntime(resolveOmpSdkRuntimeFn());
483
+ }
484
+
485
+ function ompSdkContainerRuntimeAssets(): OmpSdkRuntimeAssets {
486
+ return validatedOmpSdkRuntime(resolveOmpSdkContainerRuntimeFn());
487
+ }
488
+
489
+ function validatedOmpSdkRuntime(value: unknown): OmpSdkRuntimeAssets {
487
490
  if (!isRecord(value))
488
491
  throw new Error('Pinned OMP SDK runtime resolver returned invalid evidence.');
489
492
  const runtime = {
@@ -640,7 +643,8 @@ function mergeAcpFailClosedCliFeatures(
640
643
  export function probeRuntimeProviderCli(
641
644
  provider: string,
642
645
  evidence?: RuntimeProbeEvidence,
643
- runtimeSettings?: Record<string, unknown>
646
+ runtimeSettings?: Record<string, unknown>,
647
+ context: { readonly executionContext?: OmpSdkExecutionContext } = {}
644
648
  ): RuntimeProviderProbe {
645
649
  const adapter = getProviderAdapter(provider);
646
650
  if (adapter.id === 'gateway') {
@@ -651,7 +655,11 @@ export function probeRuntimeProviderCli(
651
655
  if (adapter.id === 'omp' && resolveOmpTransport(settings) === 'sdk') {
652
656
  const capabilities = adapter.detectCliFeatures('', '');
653
657
  try {
654
- const runtime = ompSdkRuntimeAssets();
658
+ const executionContext = ompExecutionContext(context.executionContext);
659
+ const runtime =
660
+ executionContext === 'docker' || executionContext === 'benchmark'
661
+ ? ompSdkContainerRuntimeAssets()
662
+ : ompSdkRuntimeAssets();
655
663
  return {
656
664
  available: true,
657
665
  helpText: 'Pinned bundled OMP SDK sidecar',
@@ -881,6 +889,7 @@ function resolveRuntimeAuthEnv(
881
889
  provider: ProviderId,
882
890
  settings: Record<string, unknown>
883
891
  ): Readonly<Record<string, string>> {
892
+ if (provider === 'codex') return providerCredentialEnv(provider);
884
893
  if (provider !== 'claude') return {};
885
894
  const claudeAuthModule: unknown = require('../../lib/settings/claude-auth');
886
895
  const resolveClaudeAuth = moduleFunction(claudeAuthModule, 'resolveClaudeAuth');
@@ -131,6 +131,7 @@ export interface CodexCliFeatures extends BaseCliFeatures {
131
131
  readonly supportsIgnoreUserConfig: boolean;
132
132
  readonly supportsIgnoreRules: boolean;
133
133
  readonly supportsStrictConfig: boolean;
134
+ readonly supportsAddDir: boolean;
134
135
  }
135
136
 
136
137
  export interface GeminiCliFeatures extends BaseCliFeatures {
@@ -447,6 +448,8 @@ export interface BuildProviderCommandOptions {
447
448
  readonly outputFormat?: OutputFormat;
448
449
  readonly jsonSchema?: unknown;
449
450
  readonly cwd?: string;
451
+ /** Host paths Codex must be able to write in addition to cwd during normal unattended runs. */
452
+ readonly additionalWritableDirectories?: readonly string[];
450
453
  readonly agentName?: string;
451
454
  readonly autoApprove?: boolean;
452
455
  readonly resumeSessionId?: string;
@@ -457,18 +457,27 @@ for i in $(seq 1 90); do if timeout 30 gh pr view --json mergedAt --jq .mergedAt
457
457
  */
458
458
  const SUPPORTED_PLATFORMS = ['github', 'gitlab', 'azure-devops'];
459
459
 
460
- /**
461
- * Generate the review-mode prompt (--pr without --ship): create the PR/MR and STOP.
462
- * No merge step, no issue-closing - the PR is left open for human review.
463
- * @param {Object} config - Platform configuration from PLATFORM_CONFIGS
464
- * @returns {string} The complete review-mode prompt
465
- */
466
- function generateReviewModePrompt(config) {
460
+ function buildPushCommand(config, gitRemoteArgument) {
461
+ if (config.prName !== 'PR' || !config.createCmd.startsWith('gh pr create')) {
462
+ return `git push -u -- ${gitRemoteArgument} HEAD`;
463
+ }
464
+
465
+ const gitConfig = [
466
+ 'url.https://github.com/.insteadOf=git@github.com:',
467
+ 'url.https://github.com/.insteadOf=ssh://git@github.com/',
468
+ 'credential.helper=',
469
+ 'credential.helper=!gh auth git-credential',
470
+ ]
471
+ .map((value) => `-c ${quoteShellArgument(value)}`)
472
+ .join(' ');
473
+ return `git ${gitConfig} push -u -- ${gitRemoteArgument} HEAD`;
474
+ }
475
+
476
+ function generateDeliverySteps(config, createNote = '') {
467
477
  const {
468
478
  prName,
469
479
  prNameLower,
470
480
  createCmd,
471
- prUrlExample,
472
481
  outputFields,
473
482
  requiresPrIdExtraction,
474
483
  gitRemote,
@@ -478,28 +487,13 @@ function generateReviewModePrompt(config) {
478
487
  const commitMessageArgument = quoteShellArgument(
479
488
  `feat: implement #${issueContext.issueNumber} - ${issueContext.issueTitle}`
480
489
  );
490
+ const pushCommand = buildPushCommand(config, gitRemoteArgument);
491
+ const createCommandName = createCmd.split(' ').slice(0, 3).join(' ');
492
+ const prUrlInstruction = requiresPrIdExtraction
493
+ ? ''
494
+ : ` Save the actual ${prName} URL from the output.`;
481
495
 
482
- return `CRITICAL: ALL VALIDATORS APPROVED. YOU ARE A TRANSPORT-ONLY GIT PUSHER.
483
-
484
- Your job is to preserve validator ownership: stage, commit, push, and create the ${prName} for HUMAN REVIEW.
485
-
486
- Do NOT edit source files, tests, configs, generated artifacts, or lockfiles.
487
- Do NOT inspect CI logs to debug product code.
488
- Do NOT resolve merge conflicts or rebase conflicts.
489
- Do NOT run implementation/debugging workflows after validators hand off.
490
- Do NOT merge the ${prName} - it is left OPEN for human review.
491
- Do NOT close the linked issue - it stays open until a human merges the ${prName}.
492
-
493
- Allowed after validation:
494
- - git add/status/commit/push
495
- - ${createCmd.split(' ').slice(0, 3).join(' ')}
496
- - status-only commands such as ${prName === 'PR' ? 'gh pr view/gh pr checks' : 'the platform PR/MR status command'}
497
-
498
- If commit hooks, push, ${prName} creation, or conflict handling requires code changes, STOP and report the blocked state in JSON. The implementation and validator agents must fix code and rerun quality gates.
499
-
500
- ## MANDATORY STEPS - EXECUTE EACH ONE IN ORDER - DO NOT SKIP ANY STEP
501
-
502
- ### STEP 1: Stage ALL changes (MANDATORY)
496
+ return `### STEP 1: Stage ALL changes (MANDATORY)
503
497
  \`\`\`bash
504
498
  git add -A
505
499
  \`\`\`
@@ -519,7 +513,7 @@ Run this command. Do not skip it.
519
513
 
520
514
  ### STEP 4: Push to ${gitRemote} (MANDATORY)
521
515
  \`\`\`bash
522
- git push -u -- ${gitRemoteArgument} HEAD
516
+ ${pushCommand}
523
517
  \`\`\`
524
518
  Run this. If it fails, do not edit files, rebase, or resolve conflicts. Output blocked JSON with the failure summary.
525
519
 
@@ -529,9 +523,42 @@ Run this. If it fails, do not edit files, rebase, or resolve conflicts. Output b
529
523
  \`\`\`bash
530
524
  ${createCmd}
531
525
  \`\`\`
532
- 🚨 YOU MUST RUN \`${createCmd.split(' ').slice(0, 3).join(' ')}\`! Outputting a link is NOT creating a ${prName}! 🚨
526
+ 🚨 YOU MUST RUN \`${createCommandName}\`! Outputting a link is NOT creating a ${prName}! 🚨
533
527
  The push output shows a "Create a ${prNameLower}" link - IGNORE IT.
534
- You MUST run the \`${createCmd.split(' ').slice(0, 3).join(' ')}\` command above.${requiresPrIdExtraction ? '' : ` Save the actual ${prName} URL from the output.`}
528
+ You MUST run the \`${createCommandName}\` command above.${prUrlInstruction}${createNote}`;
529
+ }
530
+
531
+ /**
532
+ * Generate the review-mode prompt (--pr without --ship): create the PR/MR and STOP.
533
+ * No merge step, no issue-closing - the PR is left open for human review.
534
+ * @param {Object} config - Platform configuration from PLATFORM_CONFIGS
535
+ * @returns {string} The complete review-mode prompt
536
+ */
537
+ function generateReviewModePrompt(config) {
538
+ const { prName, createCmd, prUrlExample, outputFields } = config;
539
+ const deliverySteps = generateDeliverySteps(config);
540
+
541
+ return `CRITICAL: ALL VALIDATORS APPROVED. YOU ARE A TRANSPORT-ONLY GIT PUSHER.
542
+
543
+ Your job is to preserve validator ownership: stage, commit, push, and create the ${prName} for HUMAN REVIEW.
544
+
545
+ Do NOT edit source files, tests, configs, generated artifacts, or lockfiles.
546
+ Do NOT inspect CI logs to debug product code.
547
+ Do NOT resolve merge conflicts or rebase conflicts.
548
+ Do NOT run implementation/debugging workflows after validators hand off.
549
+ Do NOT merge the ${prName} - it is left OPEN for human review.
550
+ Do NOT close the linked issue - it stays open until a human merges the ${prName}.
551
+
552
+ Allowed after validation:
553
+ - git add/status/commit/push
554
+ - ${createCmd.split(' ').slice(0, 3).join(' ')}
555
+ - status-only commands such as ${prName === 'PR' ? 'gh pr view/gh pr checks' : 'the platform PR/MR status command'}
556
+
557
+ If commit hooks, push, ${prName} creation, or conflict handling requires code changes, STOP and report the blocked state in JSON. The implementation and validator agents must fix code and rerun quality gates.
558
+
559
+ ## MANDATORY STEPS - EXECUTE EACH ONE IN ORDER - DO NOT SKIP ANY STEP
560
+
561
+ ${deliverySteps}
535
562
 
536
563
  ⚠️ AFTER THE ${prName} IS CREATED, YOU ARE DONE. DO NOT MERGE. DO NOT CLOSE THE ISSUE. ⚠️
537
564
 
@@ -578,7 +605,6 @@ If blocked before creating a ${prName}, output:
578
605
  function generatePrompt(config) {
579
606
  const {
580
607
  prName,
581
- prNameLower,
582
608
  createCmd,
583
609
  mergeCmd,
584
610
  mergeFallbackCmd,
@@ -589,14 +615,9 @@ function generatePrompt(config) {
589
615
  usesMergeQueue,
590
616
  closeIssueMode,
591
617
  autoMerge,
592
- gitRemote,
593
618
  issueContext,
594
619
  } = config;
595
- const gitRemoteArgument = quoteShellArgument(gitRemote);
596
620
  const issueNumberArgument = quoteShellArgument(issueContext.issueNumber);
597
- const commitMessageArgument = quoteShellArgument(
598
- `feat: implement #${issueContext.issueNumber} - ${issueContext.issueTitle}`
599
- );
600
621
 
601
622
  if (!autoMerge) {
602
623
  return generateReviewModePrompt(config);
@@ -608,6 +629,7 @@ function generatePrompt(config) {
608
629
  Look for output like: "Created PR 123" or parse the URL for the PR number.
609
630
  Save the PR ID to a variable for step 6.`
610
631
  : '';
632
+ const deliverySteps = generateDeliverySteps(config, azurePrIdNote);
611
633
 
612
634
  // Azure uses different merge terminology
613
635
  const mergeDescription = requiresPrIdExtraction
@@ -666,39 +688,7 @@ If commit hooks, push, ${prName} creation, merge, CI, or conflict handling requi
666
688
 
667
689
  ## MANDATORY STEPS - EXECUTE EACH ONE IN ORDER - DO NOT SKIP ANY STEP
668
690
 
669
- ### STEP 1: Stage ALL changes (MANDATORY)
670
- \`\`\`bash
671
- git add -A
672
- \`\`\`
673
- Run this command. Do not skip it. If commit fails because hooks/checks fail, do not edit files. Output blocked JSON with the failure summary.
674
-
675
- ### STEP 2: Check what's staged
676
- \`\`\`bash
677
- git status
678
- \`\`\`
679
- Run this. If nothing to commit, output JSON with ${outputFields.urlField}: null and stop.
680
-
681
- ### STEP 3: Commit the changes (MANDATORY if there are changes)
682
- \`\`\`bash
683
- git commit -m ${commitMessageArgument}
684
- \`\`\`
685
- Run this command. Do not skip it.
686
-
687
- ### STEP 4: Push to ${gitRemote} (MANDATORY)
688
- \`\`\`bash
689
- git push -u -- ${gitRemoteArgument} HEAD
690
- \`\`\`
691
- Run this. If it fails, do not edit files, rebase, or resolve conflicts. Output blocked JSON with the failure summary.
692
-
693
- ⚠️ AFTER PUSH YOU ARE NOT DONE! CONTINUE TO STEP 5! ⚠️
694
-
695
- ### STEP 5: CREATE THE ${prName.toUpperCase()} (MANDATORY - YOU MUST RUN THIS COMMAND)
696
- \`\`\`bash
697
- ${createCmd}
698
- \`\`\`
699
- 🚨 YOU MUST RUN \`${createCmd.split(' ').slice(0, 3).join(' ')}\`! Outputting a link is NOT creating a ${prName}! 🚨
700
- The push output shows a "Create a ${prNameLower}" link - IGNORE IT.
701
- You MUST run the \`${createCmd.split(' ').slice(0, 3).join(' ')}\` command above.${requiresPrIdExtraction ? '' : ` Save the actual ${prName} URL from the output.`}${azurePrIdNote}
691
+ ${deliverySteps}
702
692
 
703
693
  ⚠️ AFTER ${prName} CREATION YOU ARE NOT DONE! CONTINUE TO STEP 6! ⚠️
704
694
 
@@ -3,7 +3,7 @@ const crypto = require("crypto");
3
3
  const fs = require("fs");
4
4
  const os = require("os");
5
5
  const path = require("path");
6
- const SOCKET_ROOT = process.platform === 'win32' ? null : '/tmp';
6
+ const SOCKET_ROOT = process.platform === 'win32' ? null : path.resolve(os.tmpdir());
7
7
  const SOCKET_DIR_MODE = 0o700;
8
8
  function shortHash(value) {
9
9
  return crypto.createHash('sha256').update(value).digest('hex').slice(0, 16);
@@ -3,7 +3,7 @@ import fs = require('fs');
3
3
  import os = require('os');
4
4
  import path = require('path');
5
5
 
6
- const SOCKET_ROOT = process.platform === 'win32' ? null : '/tmp';
6
+ const SOCKET_ROOT = process.platform === 'win32' ? null : path.resolve(os.tmpdir());
7
7
  const SOCKET_DIR_MODE = 0o700;
8
8
 
9
9
  function shortHash(value: string): string {