@sagentlab/navarch-runtime 0.1.53 → 0.1.55
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/adapters/opencode.cjs +45 -2
- package/dist/session.cjs +20 -11
- package/package.json +1 -1
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.openCodeAdapter = void 0;
|
|
4
7
|
exports.runOpenCodeAdapter = runOpenCodeAdapter;
|
|
5
8
|
const node_child_process_1 = require("node:child_process");
|
|
6
9
|
const node_fs_1 = require("node:fs");
|
|
10
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
7
12
|
const config_cjs_1 = require("../config.cjs");
|
|
8
13
|
const kill_agent_cjs_1 = require("../kill-agent.cjs");
|
|
9
14
|
/**
|
|
@@ -30,7 +35,7 @@ async function runOpenCodeAdapter(options) {
|
|
|
30
35
|
};
|
|
31
36
|
}
|
|
32
37
|
const env = { ...options.env };
|
|
33
|
-
await prepareOpenCodeConfig(options.mcpConfigPath, env);
|
|
38
|
+
await prepareOpenCodeConfig(options.mcpConfigPath, env, Boolean(options.dockerExec));
|
|
34
39
|
const args = ["run", options.prompt];
|
|
35
40
|
// Provider failures may only appear in logs, absent from assistant events.
|
|
36
41
|
if (!hasArg(options.extraArgs, "--print-logs"))
|
|
@@ -57,7 +62,7 @@ async function runOpenCodeAdapter(options) {
|
|
|
57
62
|
function hasArg(args, ...flags) {
|
|
58
63
|
return args.some((arg) => flags.some((flag) => arg === flag || arg.startsWith(`${flag}=`)));
|
|
59
64
|
}
|
|
60
|
-
async function prepareOpenCodeConfig(mcpConfigPath, env) {
|
|
65
|
+
async function prepareOpenCodeConfig(mcpConfigPath, env, inDocker) {
|
|
61
66
|
if (!mcpConfigPath) {
|
|
62
67
|
throw new Error("OpenCode requires a per-session MCP config path for isolated execution.");
|
|
63
68
|
}
|
|
@@ -101,6 +106,11 @@ async function prepareOpenCodeConfig(mcpConfigPath, env) {
|
|
|
101
106
|
permissions: [
|
|
102
107
|
{ action: "*", resource: "*", effect: "allow" },
|
|
103
108
|
{ action: "external_directory", resource: "*", effect: "deny" },
|
|
109
|
+
...(await openCodeManagedDirectories(env, inDocker)).map((resource) => ({
|
|
110
|
+
action: "external_directory",
|
|
111
|
+
resource,
|
|
112
|
+
effect: "allow",
|
|
113
|
+
})),
|
|
104
114
|
{ action: "question", resource: "*", effect: "deny" },
|
|
105
115
|
],
|
|
106
116
|
};
|
|
@@ -117,6 +127,39 @@ async function prepareOpenCodeConfig(mcpConfigPath, env) {
|
|
|
117
127
|
env.OPENCODE_DISABLE_PROJECT_CONFIG = "true";
|
|
118
128
|
env.XDG_CONFIG_HOME = xdgConfigHome;
|
|
119
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* OpenCode's own scratch locations: `os.tmpdir()/opencode` and the data dir's
|
|
132
|
+
* truncated tool-output and background-shell output files. OpenCode grants
|
|
133
|
+
* itself `external_directory` access to these, but config rules are appended
|
|
134
|
+
* after its grants and the last matching rule wins, so the blanket deny above
|
|
135
|
+
* would otherwise hide a background command's log from the agent. Inside the
|
|
136
|
+
* sandbox container the Linux defaults apply (`~` expands to the OpenCode
|
|
137
|
+
* process's home); on the host they follow the child environment, plus the
|
|
138
|
+
* canonical temp path since OpenCode canonicalizes before matching (macOS
|
|
139
|
+
* `/var` -> `/private/var`).
|
|
140
|
+
*/
|
|
141
|
+
async function openCodeManagedDirectories(env, inDocker) {
|
|
142
|
+
if (inDocker) {
|
|
143
|
+
return [
|
|
144
|
+
"/tmp/opencode/*",
|
|
145
|
+
"~/.local/share/opencode/tool-output/*",
|
|
146
|
+
"~/.local/share/opencode/shell/*/*",
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
const tmpRoot = env.TMPDIR || process.env.TMPDIR || node_os_1.default.tmpdir();
|
|
150
|
+
const tmpRoots = [tmpRoot, await node_fs_1.promises.realpath(tmpRoot).catch(() => tmpRoot)];
|
|
151
|
+
const dataHome = env.XDG_DATA_HOME ||
|
|
152
|
+
process.env.XDG_DATA_HOME ||
|
|
153
|
+
node_path_1.default.join(env.HOME || node_os_1.default.homedir(), ".local", "share");
|
|
154
|
+
const data = node_path_1.default.join(dataHome, "opencode");
|
|
155
|
+
return [
|
|
156
|
+
...new Set([
|
|
157
|
+
...tmpRoots.map((root) => node_path_1.default.join(root, "opencode", "*")),
|
|
158
|
+
node_path_1.default.join(data, "tool-output", "*"),
|
|
159
|
+
node_path_1.default.join(data, "shell", "*", "*"),
|
|
160
|
+
]),
|
|
161
|
+
];
|
|
162
|
+
}
|
|
120
163
|
function safeEnvSegment(value) {
|
|
121
164
|
return value.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
|
|
122
165
|
}
|
package/dist/session.cjs
CHANGED
|
@@ -94,7 +94,7 @@ async function runSession(deps, claimed, sessionId) {
|
|
|
94
94
|
await api
|
|
95
95
|
.completeLease(leaseId, {
|
|
96
96
|
status: "failed",
|
|
97
|
-
report: verificationFailureReport(task.task_type, failureSummary),
|
|
97
|
+
report: verificationFailureReport(task.task_type, failureSummary, "crashed"),
|
|
98
98
|
failure_summary: failureSummary,
|
|
99
99
|
failed_before_start: true,
|
|
100
100
|
evidence_urls: [],
|
|
@@ -174,7 +174,7 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
174
174
|
const failureSummary = `Project ${task.project_id} has no GitHub repository URL. Set it in Project settings before dispatching work.`;
|
|
175
175
|
await api.completeLease(leaseId, {
|
|
176
176
|
status: "failed",
|
|
177
|
-
report: verificationFailureReport(task.task_type, failureSummary),
|
|
177
|
+
report: verificationFailureReport(task.task_type, failureSummary, "crashed"),
|
|
178
178
|
failure_summary: failureSummary,
|
|
179
179
|
failed_before_start: true,
|
|
180
180
|
evidence_urls: [],
|
|
@@ -294,7 +294,7 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
294
294
|
await api
|
|
295
295
|
.completeLease(leaseId, {
|
|
296
296
|
status: "failed",
|
|
297
|
-
report: verificationFailureReport(task.task_type, "Docker sandbox unavailable on this machine."),
|
|
297
|
+
report: verificationFailureReport(task.task_type, "Docker sandbox unavailable on this machine.", "crashed"),
|
|
298
298
|
failure_summary: "Docker sandbox unavailable on this machine.",
|
|
299
299
|
failed_before_start: true,
|
|
300
300
|
evidence_urls: [],
|
|
@@ -616,7 +616,7 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
616
616
|
const completion = {
|
|
617
617
|
status: mapping.leaseOutcome,
|
|
618
618
|
report: mapping.leaseOutcome === "failed"
|
|
619
|
-
? verificationFailureReport(task.task_type, redactedReport)
|
|
619
|
+
? verificationFailureReport(task.task_type, redactedReport, mapping.exitStatus)
|
|
620
620
|
: redactedReport,
|
|
621
621
|
evidence_urls: mapping.evidenceUrls,
|
|
622
622
|
...(deliveryFailureSummary
|
|
@@ -674,7 +674,7 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
674
674
|
status: "failed",
|
|
675
675
|
report: verificationFailureReport(task.task_type, remediable
|
|
676
676
|
? redactedRejection
|
|
677
|
-
: `${redactedRejection}\n\n---\n\n${completion.report}
|
|
677
|
+
: `${redactedRejection}\n\n---\n\n${completion.report}`, "failed"),
|
|
678
678
|
failure_summary: redactedRejection,
|
|
679
679
|
exit_status: "failed",
|
|
680
680
|
});
|
|
@@ -708,7 +708,7 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
708
708
|
status: "failed",
|
|
709
709
|
report: verificationFailureReport(task.task_type, lastCompletion
|
|
710
710
|
? `${lastCompletion.report}\n\n---\n\n${failureSummary}`
|
|
711
|
-
: failureSummary),
|
|
711
|
+
: failureSummary, "crashed"),
|
|
712
712
|
failure_summary: failureSummary,
|
|
713
713
|
failed_before_start: !adapterStarted,
|
|
714
714
|
evidence_urls: lastCompletion?.evidence_urls ?? [],
|
|
@@ -794,14 +794,23 @@ function sumReportedUsage(attempts, key) {
|
|
|
794
794
|
* does not open with `Verification verdict: FAIL` or `BLOCKED`
|
|
795
795
|
* (verification_verdict_invalid), and that gate applies to runtime-authored
|
|
796
796
|
* failure reports too. When the report carries no usable verdict — the agent
|
|
797
|
-
*
|
|
798
|
-
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
797
|
+
* exited non-zero, or opened with PASS despite the failed outcome — label it
|
|
798
|
+
* BLOCKED: the failure prevented an acceptance decision. Without this, the
|
|
799
|
+
* failure completion is itself rejected, the session crashes, and the lease
|
|
800
|
+
* dangles until expiry.
|
|
801
|
+
*
|
|
802
|
+
* A `killed` or `crashed` exit is left unlabelled: the control plane accepts
|
|
803
|
+
* those verdict-less as the runtime's own failure and routes them through
|
|
804
|
+
* failure attribution (an infrastructure retry). A BLOCKED label there would
|
|
805
|
+
* misreport a transient timeout as a verifier verdict and escalate it to a
|
|
806
|
+
* human; the control plane discards such a label, so posting it only muddies
|
|
807
|
+
* the session report.
|
|
801
808
|
*/
|
|
802
|
-
function verificationFailureReport(taskType, report) {
|
|
809
|
+
function verificationFailureReport(taskType, report, exitStatus) {
|
|
803
810
|
if (taskType !== "verify")
|
|
804
811
|
return report;
|
|
812
|
+
if (exitStatus === "killed" || exitStatus === "crashed")
|
|
813
|
+
return report;
|
|
805
814
|
const verdict = (0, exit_conditions_cjs_1.leadingVerificationVerdict)(report);
|
|
806
815
|
if (verdict === "fail" || verdict === "blocked")
|
|
807
816
|
return report;
|
package/package.json
CHANGED