@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.
- package/dist/browser-probe.cjs +25 -2
- package/dist/git-worktree.cjs +12 -0
- package/dist/prompt.cjs +10 -2
- package/dist/session.cjs +1 -0
- package/dist/worktree-guard.cjs +13 -1
- package/package.json +1 -1
package/dist/browser-probe.cjs
CHANGED
|
@@ -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 [
|
|
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
|
-
:
|
|
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.";
|
package/dist/git-worktree.cjs
CHANGED
|
@@ -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",
|
package/dist/worktree-guard.cjs
CHANGED
|
@@ -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 = [
|
|
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