@sagentlab/navarch-runtime 0.1.54 → 0.1.56
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/exit-conditions.cjs +22 -1
- 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/exit-conditions.cjs
CHANGED
|
@@ -6,6 +6,7 @@ exports.parseCodexJsonEvents = parseCodexJsonEvents;
|
|
|
6
6
|
exports.extractUsageFromCodexEvents = extractUsageFromCodexEvents;
|
|
7
7
|
exports.extractFinalMessageFromCodexEvents = extractFinalMessageFromCodexEvents;
|
|
8
8
|
exports.leadingVerificationVerdict = leadingVerificationVerdict;
|
|
9
|
+
exports.leadWithReviewFixMarker = leadWithReviewFixMarker;
|
|
9
10
|
exports.mapExitCondition = mapExitCondition;
|
|
10
11
|
/**
|
|
11
12
|
* Best-effort parse of `claude -p --output-format json` stdout into the
|
|
@@ -201,6 +202,26 @@ function leadingVerificationVerdict(report) {
|
|
|
201
202
|
const match = /^Verification verdict:\s*(PASS|FAIL|BLOCKED)\b/i.exec(firstLine ?? "");
|
|
202
203
|
return match?.[1] ? match[1].toLowerCase() : null;
|
|
203
204
|
}
|
|
205
|
+
const REVIEW_FIX_MARKER_LINE = /^[ \t]*Review fix delivered: [a-f0-9]{40}(?=\s|$)/im;
|
|
206
|
+
/**
|
|
207
|
+
* Moves a `Review fix delivered: <sha>` line to the top of the report. The
|
|
208
|
+
* control plane (lib/navarch/review-fix-marker.ts) accepts the marker at the
|
|
209
|
+
* start of any line, but summarize() collapses whitespace and truncates, so a
|
|
210
|
+
* marker below a sentence of preamble ends up mid-sentence or cut off and the
|
|
211
|
+
* review fix is rejected. Kept in step with leadWithReviewFixMarker there;
|
|
212
|
+
* this package cannot import it. A report without a marker is unchanged.
|
|
213
|
+
*/
|
|
214
|
+
function leadWithReviewFixMarker(report) {
|
|
215
|
+
const marker = REVIEW_FIX_MARKER_LINE.exec(report);
|
|
216
|
+
if (!marker || !report.slice(0, marker.index).trim())
|
|
217
|
+
return report;
|
|
218
|
+
const lineEnd = report.indexOf("\n", marker.index);
|
|
219
|
+
const line = report.slice(marker.index, lineEnd === -1 ? undefined : lineEnd).trim();
|
|
220
|
+
const rest = (report.slice(0, marker.index) + (lineEnd === -1 ? "" : report.slice(lineEnd + 1)))
|
|
221
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
222
|
+
.trim();
|
|
223
|
+
return rest ? `${line}\n\n${rest}` : line;
|
|
224
|
+
}
|
|
204
225
|
function summarize(text, maxLen = 500) {
|
|
205
226
|
const trimmed = text.trim();
|
|
206
227
|
if (!trimmed)
|
|
@@ -292,7 +313,7 @@ function mapExitCondition(result) {
|
|
|
292
313
|
// falls back to raw stdout when neither is available (see
|
|
293
314
|
// parseClaudeJsonResult's doc comment).
|
|
294
315
|
const reportText = result.reportText ?? parsedJson?.result ?? result.stdout;
|
|
295
|
-
const reportSummary = summarize(reportText) || "Adapter completed with no report text.";
|
|
316
|
+
const reportSummary = summarize(leadWithReviewFixMarker(reportText)) || "Adapter completed with no report text.";
|
|
296
317
|
// A verify agent's FAIL/BLOCKED verdict is a successful agent run whose
|
|
297
318
|
// conclusion is that the delivery did not pass. The completion API only
|
|
298
319
|
// accepts those verdicts with a failed outcome, so map them to a failed
|
package/package.json
CHANGED