@parall/codex-agent 1.42.0 → 1.43.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.
@@ -7,6 +7,14 @@ type CodexAppServerAdapterOptions = Pick<CodexAgentConfig, 'approvalPolicy' | 'c
7
7
  contextFilePath?: string;
8
8
  contextDirPath?: string;
9
9
  useParallProvider?: boolean;
10
+ /**
11
+ * Channel-capability shim directory (agent-core's capabilityBinDir),
12
+ * prepended to the subprocess PATH unconditionally. The DIRECTORY is
13
+ * constant for the bridge's lifetime; its CONTENT tracks capability
14
+ * grants, so a grant or revocation reaches even a long-lived app-server
15
+ * on its next shell command — no respawn needed.
16
+ */
17
+ capabilityBinDir?: string;
10
18
  };
11
19
  export declare class CodexAppServerAdapter implements DispatchAdapter {
12
20
  private readonly opts;
@@ -41,6 +49,16 @@ export declare class CodexAppServerAdapter implements DispatchAdapter {
41
49
  forkSession({ sessionKey: parentSessionKey }: ForkOpts): Promise<ForkSessionHandle | null>;
42
50
  cleanupFork({ fork }: CleanupForkOpts): void;
43
51
  private logForkFailure;
52
+ /**
53
+ * Lazily restart the app-server before the NEXT turn: the workspace
54
+ * config.toml (developer_instructions, carrying capability fragments) is
55
+ * loaded at process start, so a changed fragment set needs a respawn to
56
+ * reach the prompt. Deferred to the next dispatch with no active turns —
57
+ * never kills an in-flight turn; thread state survives via thread/resume.
58
+ */
59
+ requestProcessRestart(): void;
60
+ private restartRequested;
61
+ private applyPendingRestart;
44
62
  stop(): Promise<void>;
45
63
  private ensureStarted;
46
64
  private doStart;
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,KAAK,4BAA4B,GAAG,IAAI,CACtC,gBAAgB,EACd,gBAAgB,GAChB,UAAU,GACV,WAAW,GACX,OAAO,GACP,iBAAiB,GACjB,SAAS,GACT,cAAc,CACjB,GAAG;IACF,cAAc,EAAE,mBAAmB,CAAC;IACpC,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAqCF,qBAAa,qBAAsB,YAAW,eAAe;IA+B/C,OAAO,CAAC,QAAQ,CAAC,IAAI;IA9BjC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,IAAI,CAA+C;IAC3D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+B;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IAC/D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;gBAYQ,IAAI,EAAE,4BAA4B;IAE/D,YAAY,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IAMhF,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqB/E,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAUvC,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAI1C,QAAQ,CAAC,EACd,KAAK,EACL,YAAY,EACZ,UAAU,EACV,OAAO,GACR,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC;IA6P7C,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMjD,WAAW,CAAC,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAgChG,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,eAAe;IAIrC,OAAO,CAAC,cAAc;IAKhB,IAAI;YAiBI,aAAa;YA2Bb,OAAO;IAuFrB,OAAO,CAAC,qBAAqB;YAmCf,UAAU;IA6CxB,OAAO,CAAC,iBAAiB;CA2B1B"}
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,KAAK,4BAA4B,GAAG,IAAI,CACtC,gBAAgB,EACd,gBAAgB,GAChB,UAAU,GACV,WAAW,GACX,OAAO,GACP,iBAAiB,GACjB,SAAS,GACT,cAAc,CACjB,GAAG;IACF,cAAc,EAAE,mBAAmB,CAAC;IACpC,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAqCF,qBAAa,qBAAsB,YAAW,eAAe;IA+B/C,OAAO,CAAC,QAAQ,CAAC,IAAI;IA9BjC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,IAAI,CAA+C;IAC3D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+B;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IAC/D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;gBAYQ,IAAI,EAAE,4BAA4B;IAE/D,YAAY,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IAMhF,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqB/E,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAUvC,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAI1C,QAAQ,CAAC,EACd,KAAK,EACL,YAAY,EACZ,UAAU,EACV,OAAO,GACR,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC;IA8P7C,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMjD,WAAW,CAAC,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAgChG,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,eAAe;IAIrC,OAAO,CAAC,cAAc;IAKtB;;;;;;OAMG;IACH,qBAAqB,IAAI,IAAI;IAI7B,OAAO,CAAC,gBAAgB,CAAS;YAEnB,mBAAmB;IAS3B,IAAI;YAuBI,aAAa;YA2Bb,OAAO;IAuGrB,OAAO,CAAC,qBAAqB;YAmCf,UAAU;IA6CxB,OAAO,CAAC,iBAAiB;CA2B1B"}
package/dist/dispatch.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { execSync, spawn } from 'node:child_process';
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import * as fs from 'node:fs';
4
+ import * as path from 'node:path';
4
5
  import { appendPreparedLocalAttachmentRefs, ensureLocalAttachmentGitExclude, pinLocalAttachmentPaths, } from '@parall/agent-core/internal/attachment-input';
5
6
  import { normalizeApprovalPolicy, normalizeSandbox } from './config.js';
6
7
  import { EventMapper } from './event-mapping.js';
@@ -125,6 +126,7 @@ export class CodexAppServerAdapter {
125
126
  }
126
127
  (this.opts.log ?? context.log)?.warn?.(`pending steer invalidated (subprocess died); falling through to normal dispatch`);
127
128
  }
129
+ await this.applyPendingRestart(context.log);
128
130
  await this.ensureStarted(context.log);
129
131
  // After ensureStarted resolves the subprocess could still die before we
130
132
  // capture the client (handleSubprocessClose nulls this.client). Yield a
@@ -405,6 +407,24 @@ export class CodexAppServerAdapter {
405
407
  this.opts.log?.warn?.(`thread/fork failed: ${errToString(err)}`);
406
408
  return null;
407
409
  }
410
+ /**
411
+ * Lazily restart the app-server before the NEXT turn: the workspace
412
+ * config.toml (developer_instructions, carrying capability fragments) is
413
+ * loaded at process start, so a changed fragment set needs a respawn to
414
+ * reach the prompt. Deferred to the next dispatch with no active turns —
415
+ * never kills an in-flight turn; thread state survives via thread/resume.
416
+ */
417
+ requestProcessRestart() {
418
+ this.restartRequested = true;
419
+ }
420
+ restartRequested = false;
421
+ async applyPendingRestart(log) {
422
+ if (!this.restartRequested || this.activeTurns.size > 0)
423
+ return;
424
+ this.restartRequested = false;
425
+ (log ?? this.opts.log)?.info?.('restarting codex app-server to pick up updated developer_instructions');
426
+ await this.stop();
427
+ }
408
428
  async stop() {
409
429
  this.stopping = true;
410
430
  const proc = this.proc;
@@ -414,6 +434,12 @@ export class CodexAppServerAdapter {
414
434
  this.initialized = false;
415
435
  this.activeTurnIds.clear();
416
436
  this.pendingInjections.clear();
437
+ // Resume markers are process-local facts. Clear them HERE, synchronously:
438
+ // the old child's close callback sees the replaced refs and skips its
439
+ // cleanup as stale, so a marker surviving stop() would make the next
440
+ // dispatch treat the persisted thread as already resumed in the NEW
441
+ // process and lose conversation continuity when turn/start rejects.
442
+ this.resumedThreadIds.clear();
417
443
  if (client)
418
444
  client.dispose(new Error('adapter stopped'));
419
445
  if (proc && proc.exitCode === null && proc.signalCode === null) {
@@ -468,6 +494,22 @@ export class CodexAppServerAdapter {
468
494
  FORCE_COLOR: '0',
469
495
  NO_COLOR: '1',
470
496
  };
497
+ // Channel-capability shims resolve ahead of any globally-installed CLI of
498
+ // the same name (the shim owns auth; the real binary is found further
499
+ // down the PATH by the shim itself). On Windows env keys are
500
+ // case-insensitive and the host key is usually `Path`; after the
501
+ // plain-object spread a literal `PATH` write would SPLIT the key
502
+ // (undefined which wins in the child), so reuse the parent's casing. On
503
+ // POSIX keys are case-SENSITIVE — match `PATH` exactly.
504
+ if (this.opts.capabilityBinDir) {
505
+ const pathKey = IS_WIN32
506
+ ? (Object.keys(env).find((k) => k.toUpperCase() === 'PATH') ?? 'PATH')
507
+ : 'PATH';
508
+ const existing = env[pathKey];
509
+ env[pathKey] = existing
510
+ ? `${this.opts.capabilityBinDir}${path.delimiter}${existing}`
511
+ : this.opts.capabilityBinDir;
512
+ }
471
513
  if (this.opts.contextFilePath) {
472
514
  env.PRLL_CONTEXT_FILE = this.opts.contextFilePath;
473
515
  }
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import * as os from 'node:os';
3
- import { ParallAgentGateway, createPlatformConfigManager, createLogger, createOtelLogger, childLogger, deriveModelIsPin, resolveRuntimeModel, parseShutdownDeadlineMs, parseForkDeadlineMs, parseDispatchDeadlineMs, parseProviderConfig, clearAllProviderCreds, llmSource, initAgentTelemetry, } from '@parall/agent-core';
3
+ import { ParallAgentGateway, capabilityBinDir, createPlatformConfigManager, createLogger, createOtelLogger, childLogger, deriveModelIsPin, materializeChannelCapabilities, resolveRuntimeModel, parseShutdownDeadlineMs, parseForkDeadlineMs, parseDispatchDeadlineMs, parseProviderConfig, clearAllProviderCreds, llmSource, initAgentTelemetry, } from '@parall/agent-core';
4
4
  import { ApiError, ParallClient, ParallWs } from '@parall/sdk';
5
5
  import { buildCodexRuntimeKey, contextFilePathForSession, dispatchContextDirPath, resolveCodexAgentConfig, resolveWsUrl, sessionStateFilePathForRuntime, stepIdFilePathForSession, } from './config.js';
6
6
  import { CodexAppServerAdapter } from './dispatch.js';
7
7
  import { CodexSessionManager } from './session-manager.js';
8
- import { ensureCodexWorkspace, ensureParallProvider, ensureWorkspaceTrusted, isParallProxyMode, } from './workspace.js';
8
+ import { ensureCodexWorkspace, ensureParallProvider, ensureWorkspaceTrusted, isParallProxyMode, writeCodexSystemPrompt, } from './workspace.js';
9
9
  const log = createLogger('codex-agent');
10
10
  let activeLog = log;
11
11
  async function getAgentMeWithLegacyFallback(client, orgId) {
@@ -58,11 +58,11 @@ async function main() {
58
58
  ensureParallProvider(config.codexHome, config.apiUrl, agentLog);
59
59
  agentLog.info('parall custom provider configured (Responses API HTTP/SSE mode)');
60
60
  }
61
- ensureCodexWorkspace(config.workspaceDir, agentLog, {
61
+ const agentIdentity = {
62
62
  userId: agentUserId,
63
63
  displayName: me.display_name,
64
64
  description: me.agent_profile?.description ?? undefined,
65
- });
65
+ };
66
66
  const runtimeKey = config.runtimeKey || buildCodexRuntimeKey(agentUserId);
67
67
  const mainContextFilePath = contextFilePathForSession(config.stateDir, runtimeKey);
68
68
  const sessionStateFilePath = sessionStateFilePathForRuntime(config.stateDir, runtimeKey);
@@ -79,6 +79,21 @@ async function main() {
79
79
  log: agentLog,
80
80
  });
81
81
  const platformDefaults = await configMgr.fetch();
82
+ // Channel capabilities: ONE call materializes the local artifacts (the
83
+ // lark-cli auth shim under capabilityBinDir) and yields the system-prompt
84
+ // fragments, so declaration and shim can never diverge within a refresh.
85
+ // No freshness gate — a stale (LKG-cached) declaration fail-closes at the
86
+ // mint endpoint, which re-evaluates the grant on every token request.
87
+ const applyChannelCapabilities = () => {
88
+ const caps = configMgr.capabilities();
89
+ materializeChannelCapabilities(config.stateDir, caps, agentLog);
90
+ return caps.map((c) => c.fragment);
91
+ };
92
+ // Assemble the workspace AFTER the first config fetch so
93
+ // developer_instructions carries the capability declarations from boot.
94
+ const bootCapabilityFragments = applyChannelCapabilities();
95
+ let lastCapabilityFragments = bootCapabilityFragments.join('\n\n');
96
+ ensureCodexWorkspace(config.workspaceDir, agentLog, agentIdentity, bootCapabilityFragments);
82
97
  // Model precedence: operator PIN (override) > env > server FLOOR. The server
83
98
  // now says which it is via model_is_pin (deriveModelIsPin presence-gates the
84
99
  // dual-read: old servers omit it → fall back to model_management). A PIN beats
@@ -104,6 +119,7 @@ async function main() {
104
119
  contextFilePath: mainContextFilePath,
105
120
  contextDirPath: dispatchContextDirPath(config.stateDir),
106
121
  useParallProvider,
122
+ capabilityBinDir: capabilityBinDir(config.stateDir),
107
123
  });
108
124
  // Shared by onConfigUpdate + onSessionReady. /agents/me is only consumed as
109
125
  // deriveModelIsPin's legacy fallback when the server omits model_is_pin
@@ -129,6 +145,24 @@ async function main() {
129
145
  model: resolveRuntimeModel(isPin, updated.model, config.model) ?? null,
130
146
  reasoningEffort: updated.thinkingEffort ?? config.reasoningEffort ?? null,
131
147
  });
148
+ // Capability heat-update: re-materialize shims + rewrite the prompt
149
+ // surfaces. The write is refresh-tolerant (warn + retry next refresh);
150
+ // only a SUCCESSFUL write with a changed fragment set schedules the
151
+ // lazy app-server restart (developer_instructions loads at spawn).
152
+ const fragments = applyChannelCapabilities();
153
+ const joinedFragments = fragments.join('\n\n');
154
+ let promptWritten = true;
155
+ try {
156
+ writeCodexSystemPrompt(config.workspaceDir, agentIdentity, fragments);
157
+ }
158
+ catch (err) {
159
+ promptWritten = false;
160
+ agentLog.warn(`system prompt refresh write failed (retrying next refresh): ${String(err)}`);
161
+ }
162
+ if (promptWritten && joinedFragments !== lastCapabilityFragments) {
163
+ lastCapabilityFragments = joinedFragments;
164
+ adapter.requestProcessRestart();
165
+ }
132
166
  };
133
167
  const gateway = new ParallAgentGateway({
134
168
  accountId: agentUserId,
@@ -152,6 +186,9 @@ async function main() {
152
186
  },
153
187
  dispatchAdapter: adapter,
154
188
  log: agentLog,
189
+ // Live capability view for hint routing: the channel reply hint points
190
+ // at the vendor CLI only while the grant is active.
191
+ getCapabilityKeys: () => configMgr.capabilities().map((c) => c.key),
155
192
  shutdownDeadlineMs: parseShutdownDeadlineMs(process.env.PRLL_SHUTDOWN_DEADLINE_MS),
156
193
  forkDeadlineMs: parseForkDeadlineMs(process.env.PRLL_FORK_DEADLINE_MS),
157
194
  dispatchDeadlineMs: parseDispatchDeadlineMs(process.env.PRLL_DISPATCH_DEADLINE_MS),
@@ -1,4 +1,89 @@
1
1
  import type { AgentIdentity } from '@parall/agent-core';
2
+ /**
3
+ * Config-lock timings, exported for tests.
4
+ *
5
+ * `staleMs` — a queue ticket untouched this long is treated as a crashed
6
+ * owner (live contenders refresh their ticket's mtime every `retryMs`, so
7
+ * the margin is ~400×). `waitMs` deliberately exceeds `staleMs`: a waiter
8
+ * facing a crashed head-of-queue outlasts the staleness threshold and skips
9
+ * it instead of falling through to a lockless write — the lockless fallback
10
+ * is a last resort, not a normal path.
11
+ */
12
+ export declare const CONFIG_LOCK_TIMINGS: {
13
+ staleMs: number;
14
+ waitMs: number;
15
+ retryMs: number;
16
+ };
17
+ /**
18
+ * Advisory cross-process lock serializing `<codexHome>/config.toml`
19
+ * read-modify-write. On a local daemon machine every runtime_auth codex
20
+ * bridge child shares the operator's CODEX_HOME, and the daemon starts them
21
+ * together — without a lock, a whole-file rewrite working from a stale read
22
+ * can erase a trust entry another agent appended in between.
23
+ *
24
+ * Queue design (why not wx-create + steal): any scheme that renames or
25
+ * unlinks the SHARED lock path can, between its staleness check and the
26
+ * destructive op, hit a fresh lock that replaced the stale one — deleting a
27
+ * live holder's lock and overlapping critical sections (reproduced under
28
+ * 12-process contention). Here contenders queue in `config.toml.lock.d/`
29
+ * using Lamport's bakery protocol, and the smallest live ticket holds the
30
+ * lock. Two phases per enqueue: (1) create a `choosing-<token>` marker,
31
+ * (2) take seq = max(existing ticket seqs) + 1 and publish by atomically
32
+ * RENAMING the marker into `t-<seq>-<token>`. Evaluators wait while any
33
+ * live choosing marker exists, so a contender that read the queue but
34
+ * hasn't published yet can never be missed — the classic bakery guarantee.
35
+ * (A naive self-chosen timestamp order would race: a process descheduled
36
+ * between choosing its stamp and writing its ticket could insert itself
37
+ * before an already-running holder.) The rename-publish closes the
38
+ * stale-mid-choosing hole: once a frozen chooser's marker has been GC'd,
39
+ * its publish fails and it must re-enqueue fresh — it can never surface an
40
+ * old low seq under a holder elected in its absence. ENTRY is the same
41
+ * pattern: the elected head atomically renames its ticket into a
42
+ * `held-<entry-ts>-…` entry, racing any staleness eviction of that ticket
43
+ * on the same path — a contender revived at the staleness boundary loses
44
+ * the rename and re-enqueues rather than entering behind an eviction. The
45
+ * holder's freshness is embedded in the held name (atomic with entry), so
46
+ * evicting a holder needs no stat. Evaluators mirror the atomicity: after
47
+ * any GC attempt, or on a marker that vanished mid-scan, they take a fresh
48
+ * snapshot instead of electing from the old one. Ticket order is
49
+ * (seq, token), identical for every observer.
50
+ *
51
+ * No process ever mutates a shared path: release unlinks only the caller's
52
+ * own ticket, and the only cross-process destructive op is GC of entries
53
+ * untouched for `staleMs` — safe because live contenders refresh their
54
+ * ticket's mtime every `retryMs`, and names embed a per-acquisition random
55
+ * token so they are never reused (no identity switch on unlink).
56
+ *
57
+ * Residual (documented, not fixable without OS-level flock, which Node core
58
+ * does not expose): a HOLDER frozen inside `fn` for longer than `staleMs`
59
+ * looks crashed, gets evicted, and the next head may overlap it — `fn` is a
60
+ * millisecond-scale sync config write, 400× within margin. Freezes anywhere
61
+ * else (mid-choosing, at entry) are safe: the atomic renames fail after an
62
+ * eviction and the process re-enqueues. On `waitMs` timeout
63
+ * the mutation proceeds without the lock (warn) — blocking would wedge
64
+ * bridge startup. The lock coordinates bridge processes only; codex itself
65
+ * does not observe it, which is why bridge writes to a shared config are
66
+ * additionally kept rare (the trust write is a no-op after the first boot
67
+ * per workspace, and runtime_auth agents never write the provider block)
68
+ * and whole-file writes are atomic (temp + rename) so codex never reads a
69
+ * truncated file.
70
+ *
71
+ * Exported for tests.
72
+ */
73
+ export declare function withConfigLock(codexHome: string, log: {
74
+ warn: (msg: string) => void;
75
+ } | undefined, fn: () => void): void;
76
+ /**
77
+ * Test-only scheduling hooks for deterministic race tests. Production code
78
+ * never sets these; tests use them to pause a contender at the two points
79
+ * where another process can act in between (barrier files stand in for the
80
+ * OS scheduler).
81
+ */
82
+ export declare const CONFIG_LOCK_TEST_HOOKS: {
83
+ beforeChoosingMarker?: () => void;
84
+ beforeTicketPublish?: () => void;
85
+ beforeTicketEntry?: () => void;
86
+ };
2
87
  /**
3
88
  * Ensure the workspace directory is marked as trusted in the global Codex
4
89
  * config so that project-level `developer_instructions` are loaded at
@@ -35,7 +120,8 @@ export declare function isParallProxyMode(env?: NodeJS.ProcessEnv): boolean;
35
120
  export declare function ensureParallProvider(codexHome: string, apiUrl: string, log?: {
36
121
  warn: (msg: string) => void;
37
122
  }): void;
123
+ export declare function writeCodexSystemPrompt(workspaceDir: string, agentIdentity?: AgentIdentity, capabilityFragments?: string[]): void;
38
124
  export declare function ensureCodexWorkspace(workspaceDir: string, log?: {
39
125
  warn: (msg: string) => void;
40
- }, agentIdentity?: AgentIdentity): void;
126
+ }, agentIdentity?: AgentIdentity, capabilityFragments?: string[]): void;
41
127
  //# sourceMappingURL=workspace.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpC,IAAI,CAgFN;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAK/E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpC,IAAI,CA6CN;AASD,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,EACrC,aAAa,CAAC,EAAE,aAAa,GAC5B,IAAI,CAqBN"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB;;;;CAI/B,CAAC;AAUF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GAAG,SAAS,EAChD,EAAE,EAAE,MAAM,IAAI,GACb,IAAI,CAkJN;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,EAAE;IACnC,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAuJP;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpC,IAAI,CAEN;AAqGD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAK/E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpC,IAAI,CAEN;AAoED,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,aAAa,CAAC,EAAE,aAAa,EAC7B,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAC7B,IAAI,CAqBN;AAED,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,EACrC,aAAa,CAAC,EAAE,aAAa,EAC7B,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAC7B,IAAI,CAQN"}