@sagentlab/navarch-runtime 0.1.89 → 0.1.91

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.
@@ -192,7 +192,17 @@ async function probeCodexSandbox(config, deps) {
192
192
  readRoots: [node_path_1.default.dirname(await node_fs_1.promises.realpath(process.execPath)), node_path_1.default.dirname(playwrightDir)],
193
193
  });
194
194
  const env = { NAVARCH_PROBE_PLAYWRIGHT: playwrightDir };
195
- for (const key of ["HOME", "PATH", "TMPDIR", "CODEX_HOME", "PLAYWRIGHT_BROWSERS_PATH", "XDG_CACHE_HOME"]) {
195
+ for (const key of [
196
+ "HOME",
197
+ "PATH",
198
+ "TMPDIR",
199
+ "CODEX_HOME",
200
+ "PLAYWRIGHT_BROWSERS_PATH",
201
+ "XDG_CACHE_HOME",
202
+ // Agent sessions inherit it; without it Node falls back to the default
203
+ // config path, which can disagree with what sessions actually load.
204
+ "OPENSSL_CONF",
205
+ ]) {
196
206
  if (process.env[key])
197
207
  env[key] = process.env[key];
198
208
  }
@@ -204,12 +214,16 @@ async function probeCodexSandbox(config, deps) {
204
214
  // bwrap could not find the program it was asked to start inside the
205
215
  // sandbox view: a path outside the granted read roots, not an old CLI.
206
216
  const hidden = /bwrap: execvp .*No such file or directory/.test(output);
217
+ const opensslConfig = /OpenSSL configuration error/.test(output);
207
218
  return ("Could not verify a browser inside the Codex sandbox: `codex sandbox` did not run the probe " +
208
219
  `(${result.timedOut ? "timed out" : output.trim() ? summarizeLaunchFailure(output) : `exit ${result.code}`}). ` +
209
220
  (hidden
210
221
  ? "The sandbox cannot see that executable; add its install directory to NAVARCH_GUARD_EXTRA_ROOTS, " +
211
222
  "or run browser tasks with another agent."
212
- : "Update the Codex CLI, or run browser tasks with another agent."));
223
+ : opensslConfig
224
+ ? "Node cannot read its OpenSSL config inside the sandbox, so Codex sessions cannot run node either; " +
225
+ "update the Navarch runtime, or add that file's directory to NAVARCH_GUARD_EXTRA_ROOTS."
226
+ : "Update the Codex CLI, or run browser tasks with another agent."));
213
227
  }
214
228
  const detail = result.timedOut ? "the launch timed out." : summarizeLaunchFailure(output);
215
229
  const machPort = /bootstrap_check_in|MachPortRendezvous|mach_port_rendezvous/i.test(output);
@@ -236,6 +250,15 @@ function summarizeLaunchFailure(output) {
236
250
  // "[pid=1][err] [1001/210406.593317:FATAL:base/apple/mach_port_rendezvous_mac.cc:159] Check failed: ..."
237
251
  return fatal.replace(/^.*FATAL:[^\]]*\]\s*/, "");
238
252
  }
253
+ const opensslIndex = lines.findIndex((line) => /OpenSSL configuration error/.test(line));
254
+ if (opensslIndex >= 0) {
255
+ // "<node>: OpenSSL configuration error:" with the reason on the next line:
256
+ // "...:error:80000001:system library:BIO_new_file:Operation not permitted:...:calling fopen(<path>, rb)"
257
+ const reason = lines[opensslIndex + 1] ?? "";
258
+ const cause = /:system library:[^:]*:([^:]+):/.exec(reason)?.[1];
259
+ const file = /fopen\(([^,]+),/.exec(reason)?.[1];
260
+ return `OpenSSL configuration error${cause ? `: ${cause}` : ""}${file ? ` reading ${node_path_1.default.normalize(file)}` : ""}`;
261
+ }
239
262
  const missing = lines.find((line) => /Executable doesn't exist/.test(line));
240
263
  if (missing)
241
264
  return "Chromium is not installed for the runtime's Playwright.";
@@ -40,6 +40,7 @@ class GitWorktree {
40
40
  checkpointRoot;
41
41
  cloneUrl;
42
42
  githubToken;
43
+ workingBranch;
43
44
  repoLocalGithubToken;
44
45
  prContinuation;
45
46
  taskBranchSuffix;
@@ -78,6 +79,7 @@ class GitWorktree {
78
79
  this.sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
79
80
  this.cloneUrl = options.cloneUrl;
80
81
  this.githubToken = options.githubToken;
82
+ this.workingBranch = options.workingBranch?.trim() || null;
81
83
  this.repoLocalGithubToken = options.repoLocalGithubToken;
82
84
  this.prContinuation = options.prContinuation ?? false;
83
85
  this.hostedCheckpointRef = options.restoreHostedCheckpoint ? hostedCheckpointRef(options.taskId) : null;
@@ -517,6 +519,16 @@ class GitWorktree {
517
519
  * when the remote has no branches at all (a freshly provisioned empty repo).
518
520
  */
519
521
  async resolveStartRef() {
522
+ // The claim already merged the integration branch into the working branch,
523
+ // so it is the start (and delivery) base. A missing ref falls through to
524
+ // the default branch rather than starting the task on nothing.
525
+ if (this.workingBranch) {
526
+ const ref = `refs/remotes/origin/${this.workingBranch}`;
527
+ const found = await this.runGit(["--git-dir", this.repositoryPath, "rev-parse", "--verify", "--quiet", ref], false)
528
+ .then(() => true, () => false);
529
+ if (found)
530
+ return ref;
531
+ }
520
532
  const remoteHead = await this.runGit(["--git-dir", this.repositoryPath, "ls-remote", "--symref", "origin", "HEAD"], true);
521
533
  const defaultBranch = parseRemoteHead(remoteHead.stdout);
522
534
  if (defaultBranch)
package/dist/prompt.cjs CHANGED
@@ -5,6 +5,12 @@ exports.renderGuidanceCorrectionPrompt = renderGuidanceCorrectionPrompt;
5
5
  exports.renderHostedCheckpointNote = renderHostedCheckpointNote;
6
6
  const CODE_GRAPH_GUIDANCE = "For JS/TS dependency inspection, the runtime provides `navarch-runtime code-graph --query <symbol-or-file> --mode search|callers|callees|impact --commit HEAD`. If the runtime is not on PATH, use its installed entry point; do not install another copy mid-task. Results describe committed source and include commit/freshness warnings; inspect current files for uncommitted changes and unresolved dependencies.";
7
7
  const PROCESS_GUIDANCE = "Process management: this host may run other agent sessions. Keep the PID or tool handle of each preview server you start and stop only that owned process. Never use broad process-name or command-line matching (pkill, killall) to clean up servers: the agent launcher carries the task prompt in its arguments and can match those patterns, terminating your own session. Use a different port when a port is occupied by a process you do not own. Keep scratch files in the current worktree; paths in previous transcripts belong to earlier sessions.";
8
+ /** Overrides the playbooks' "default branch" PR base when the project sets a working branch. */
9
+ function workingBranchNote(workingBranch) {
10
+ if (!workingBranch)
11
+ return "";
12
+ return `\nWorking branch: \`${workingBranch}\`. Your branch already starts from it. Open the pull request with \`--base ${workingBranch}\` instead of the default branch, and rebase onto \`origin/${workingBranch}\` when you need the latest base.`;
13
+ }
8
14
  /**
9
15
  * Renders the four-layer context bundle (project-plan.md §3.8: steering docs,
10
16
  * task itself, task-type playbook, depends_on reports) into the single prompt
@@ -15,7 +21,8 @@ const PROCESS_GUIDANCE = "Process management: this host may run other agent sess
15
21
  function renderPrompt(task, bundle) {
16
22
  if (bundle.task_context) {
17
23
  const repositoryContext = bundle.repository
18
- ? `Repository: ${bundle.repository.full_name} (${bundle.repository.url})\nLocal checkout: this session's isolated git worktree (current working directory).`
24
+ ? `Repository: ${bundle.repository.full_name} (${bundle.repository.url})\nLocal checkout: this session's isolated git worktree (current working directory).` +
25
+ workingBranchNote(bundle.repository.working_branch)
19
26
  : null;
20
27
  return [repositoryContext, PROCESS_GUIDANCE, bundle.task_context.trim(), CODE_GRAPH_GUIDANCE, bundle.retry_context?.trim()]
21
28
  .filter((section) => Boolean(section))
@@ -26,7 +33,8 @@ function renderPrompt(task, bundle) {
26
33
  sections.push(`Type: ${task.task_type} | Repo: ${task.repo} | Environment: ${task.environment_scope}`);
27
34
  sections.push(PROCESS_GUIDANCE);
28
35
  if (bundle.repository) {
29
- sections.push(`Repository URL: ${bundle.repository.url}\nLocal checkout: this session's isolated git worktree (current working directory).`);
36
+ sections.push(`Repository URL: ${bundle.repository.url}\nLocal checkout: this session's isolated git worktree (current working directory).` +
37
+ workingBranchNote(bundle.repository.working_branch));
30
38
  }
31
39
  if (task.github_issue_url) {
32
40
  sections.push(`GitHub issue: ${task.github_issue_url}`);
package/dist/session.cjs CHANGED
@@ -208,6 +208,7 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
208
208
  sessionId,
209
209
  cloneUrl,
210
210
  githubToken,
211
+ workingBranch: bundle.repository?.working_branch,
211
212
  repoLocalGithubToken: secrets["github-pat"],
212
213
  // Hosted runs skip checkpoints for verify tasks, which deliver a verdict.
213
214
  restoreHostedCheckpoint: !allowBranchRename && task.task_type !== "verify",
@@ -138,6 +138,9 @@ function codexToolReadRoots(env = process.env, platform = process.platform) {
138
138
  node_path_1.default.join(miseDataDir(env, homeDir), "installs"),
139
139
  node_path_1.default.join(env.NVM_DIR?.trim() || node_path_1.default.join(homeDir, ".nvm"), "versions"),
140
140
  ...(platform === "darwin" ? MACOS_TOOLCHAIN_READ_ROOTS : []),
141
+ // An operator-chosen OpenSSL config is read by every Node (and OpenSSL
142
+ // CLI) start; the agent inherits OPENSSL_CONF, so the file must be too.
143
+ ...(env.OPENSSL_CONF?.trim() ? [env.OPENSSL_CONF.trim()] : []),
141
144
  ];
142
145
  }
143
146
  function miseDataDir(env, homeDir) {
@@ -209,7 +212,16 @@ function resolveExecutable(bin, env) {
209
212
  * system prefixes for the Claude hook (bin/worktree-guard-hook.cjs), so this
210
213
  * only brings the Codex profile level with it.
211
214
  */
212
- const MACOS_TOOLCHAIN_READ_ROOTS = ["/Library/Developer", "/Applications"];
215
+ const MACOS_TOOLCHAIN_READ_ROOTS = [
216
+ "/Library/Developer",
217
+ "/Applications",
218
+ // Official nodejs.org macOS builds (nvm, fnm, volta, the .pkg installer)
219
+ // load OPENSSLDIR/openssl.cnf on every start and exit with "OpenSSL
220
+ // configuration error: ... Operation not permitted" when seatbelt denies
221
+ // the read, so no `node` or `npm` runs. Grant only the file: the directory
222
+ // also holds private/.
223
+ "/System/Library/OpenSSL/openssl.cnf",
224
+ ];
213
225
  /**
214
226
  * Per-user macOS build state that Xcode and SwiftPM write during a build or
215
227
  * test run: simulator devices and DerivedData under `~/Library/Developer`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sagentlab/navarch-runtime",
3
- "version": "0.1.89",
3
+ "version": "0.1.91",
4
4
  "description": "Navarch machine-side session manager: claims delivery tasks and runs them through local coding agents.",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",