@getollie/cli 0.2.2 → 0.2.3
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/cli.js +78 -273
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -19
- package/dist/index.js +15 -106
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7,12 +7,8 @@ import { CommanderError } from "commander";
|
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
|
|
9
9
|
// src/config.ts
|
|
10
|
-
import { access,
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
// src/sandbox/mounts.ts
|
|
14
|
-
import { realpathSync, statSync } from "fs";
|
|
15
|
-
import { posix, resolve } from "path";
|
|
10
|
+
import { access, stat } from "fs/promises";
|
|
11
|
+
import { resolve } from "path";
|
|
16
12
|
|
|
17
13
|
// src/utils/errors.ts
|
|
18
14
|
var CliError = class extends Error {
|
|
@@ -30,68 +26,6 @@ function getErrorMessage(error) {
|
|
|
30
26
|
return String(error);
|
|
31
27
|
}
|
|
32
28
|
|
|
33
|
-
// src/sandbox/mounts.ts
|
|
34
|
-
var SANDBOX_WORKSPACE_PATH = "/workspace";
|
|
35
|
-
function sandboxPathsOverlap(left, right) {
|
|
36
|
-
return left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`);
|
|
37
|
-
}
|
|
38
|
-
function sandboxPathContains(parent, child) {
|
|
39
|
-
return parent === child || child.startsWith(`${parent}/`);
|
|
40
|
-
}
|
|
41
|
-
function validateSandboxPath(path, label = "Sandbox path") {
|
|
42
|
-
if (!posix.isAbsolute(path) || path.includes("\\") || path.includes("\0") || path.split("/").includes("..") || posix.normalize(path) !== path) {
|
|
43
|
-
throw new CliError(`${label} must be a normalized absolute sandbox path: ${path}`);
|
|
44
|
-
}
|
|
45
|
-
return path;
|
|
46
|
-
}
|
|
47
|
-
function validateMountPoint(mountPoint) {
|
|
48
|
-
validateSandboxPath(mountPoint, "Mount point");
|
|
49
|
-
if (mountPoint === "/") {
|
|
50
|
-
throw new CliError(`Mount point must be a normalized absolute sandbox path other than /: ${mountPoint}`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function validateSandboxMounts(mounts, options = {}) {
|
|
54
|
-
const reservedMountPoint = options.reservedMountPoint === void 0 ? SANDBOX_WORKSPACE_PATH : options.reservedMountPoint;
|
|
55
|
-
const validated = [];
|
|
56
|
-
for (const mount of mounts) {
|
|
57
|
-
validateMountPoint(mount.mountPoint);
|
|
58
|
-
if (reservedMountPoint && sandboxPathsOverlap(mount.mountPoint, reservedMountPoint)) {
|
|
59
|
-
throw new CliError(`Mount point must be outside ${reservedMountPoint}: ${mount.mountPoint}`);
|
|
60
|
-
}
|
|
61
|
-
let hostPath;
|
|
62
|
-
try {
|
|
63
|
-
hostPath = realpathSync(resolve(mount.hostPath));
|
|
64
|
-
if (!statSync(hostPath).isDirectory()) throw new Error("not a directory");
|
|
65
|
-
} catch {
|
|
66
|
-
throw new CliError(
|
|
67
|
-
`Mount source host path does not exist or is not a directory: ${resolve(mount.hostPath)}`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
const conflict = validated.find(
|
|
71
|
-
(candidate) => sandboxPathsOverlap(candidate.mountPoint, mount.mountPoint)
|
|
72
|
-
);
|
|
73
|
-
if (conflict) {
|
|
74
|
-
throw new CliError(
|
|
75
|
-
`Mount points must not overlap: ${conflict.mountPoint} and ${mount.mountPoint}`
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
validated.push({ hostPath, mountPoint: mount.mountPoint });
|
|
79
|
-
}
|
|
80
|
-
return validated;
|
|
81
|
-
}
|
|
82
|
-
function parseSandboxMounts(specs = [], options) {
|
|
83
|
-
const mounts = specs.map((spec) => {
|
|
84
|
-
const separator = spec.lastIndexOf(":");
|
|
85
|
-
if (separator <= 0 || separator === spec.length - 1) {
|
|
86
|
-
throw new CliError(
|
|
87
|
-
`Invalid mount ${JSON.stringify(spec)}. Expected <host-path>:<sandbox-path>`
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
return { hostPath: spec.slice(0, separator), mountPoint: spec.slice(separator + 1) };
|
|
91
|
-
});
|
|
92
|
-
return validateSandboxMounts(mounts, options);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
29
|
// src/config.ts
|
|
96
30
|
var DEFAULT_PROVIDER = "openai";
|
|
97
31
|
var DEFAULT_MODEL = "gpt-5.6";
|
|
@@ -100,7 +34,9 @@ var DEFAULT_COMMAND_TIMEOUT_MS = 3e4;
|
|
|
100
34
|
var DEFAULT_MAX_OUTPUT_BYTES = 65536;
|
|
101
35
|
var DEFAULT_EXECUTOR = "none";
|
|
102
36
|
function parseNumber(name, value, fallback) {
|
|
103
|
-
if (value === void 0 || value === "")
|
|
37
|
+
if (value === void 0 || value === "") {
|
|
38
|
+
return fallback;
|
|
39
|
+
}
|
|
104
40
|
const parsed = typeof value === "number" ? value : Number.parseInt(value, 10);
|
|
105
41
|
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
106
42
|
throw new CliError(`${name} must be a non-negative integer`);
|
|
@@ -117,82 +53,39 @@ function parseExecutor(value) {
|
|
|
117
53
|
}
|
|
118
54
|
return executor;
|
|
119
55
|
}
|
|
120
|
-
async function resolveHostDirectory(value, label) {
|
|
121
|
-
const absolute = resolve2(value);
|
|
122
|
-
const stats = await stat(absolute).catch(() => null);
|
|
123
|
-
if (!stats?.isDirectory()) {
|
|
124
|
-
throw new CliError(`${label} host path does not exist or is not a directory: ${absolute}`);
|
|
125
|
-
}
|
|
126
|
-
await access(absolute);
|
|
127
|
-
return realpath(absolute);
|
|
128
|
-
}
|
|
129
56
|
async function resolveRunConfig(input = {}, env = process.env) {
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const explicitMounts = parseSandboxMounts(input.mount, {
|
|
135
|
-
reservedMountPoint: hostCwdValue ? "/workspace" : null
|
|
136
|
-
});
|
|
137
|
-
let workspace;
|
|
138
|
-
let mounts;
|
|
139
|
-
let sandboxCwd;
|
|
140
|
-
if (hostCwdValue) {
|
|
141
|
-
workspace = {
|
|
142
|
-
hostPath: await resolveHostDirectory(hostCwdValue, "Working directory"),
|
|
143
|
-
mountPoint: "/workspace"
|
|
144
|
-
};
|
|
145
|
-
mounts = explicitMounts;
|
|
146
|
-
sandboxCwd = configuredSandboxCwd ?? "/workspace";
|
|
147
|
-
} else {
|
|
148
|
-
if (!configuredSandboxCwd) {
|
|
149
|
-
throw new CliError("Either --cwd or --sandbox-cwd must be specified.");
|
|
150
|
-
}
|
|
151
|
-
sandboxCwd = configuredSandboxCwd;
|
|
152
|
-
validateSandboxPath(sandboxCwd, "Sandbox cwd");
|
|
153
|
-
const containing2 = explicitMounts.find(
|
|
154
|
-
(mount) => sandboxPathContains(mount.mountPoint, sandboxCwd)
|
|
155
|
-
);
|
|
156
|
-
if (!containing2) {
|
|
157
|
-
const destinations = explicitMounts.map((mount) => mount.mountPoint).join(", ") || "(none)";
|
|
158
|
-
throw new CliError(
|
|
159
|
-
`Sandbox cwd ${sandboxCwd} is not contained by the primary workspace or any configured mount. Configured mount destinations: ${destinations}`
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
workspace = containing2;
|
|
163
|
-
mounts = explicitMounts.filter((mount) => mount !== containing2);
|
|
164
|
-
}
|
|
165
|
-
validateSandboxPath(sandboxCwd, "Sandbox cwd");
|
|
166
|
-
const allMounts = [workspace, ...mounts];
|
|
167
|
-
const containing = allMounts.find((mount) => sandboxPathContains(mount.mountPoint, sandboxCwd));
|
|
168
|
-
if (!containing) {
|
|
169
|
-
const destinations = allMounts.map((mount) => mount.mountPoint).join(", ");
|
|
170
|
-
throw new CliError(
|
|
171
|
-
`Sandbox cwd ${sandboxCwd} is not contained by the primary workspace or any configured mount. Configured mount destinations: ${destinations}`
|
|
172
|
-
);
|
|
57
|
+
const cwd = resolve(input.cwd ?? env.OLLIE_CWD ?? process.cwd());
|
|
58
|
+
const stats = await stat(cwd).catch(() => null);
|
|
59
|
+
if (!stats?.isDirectory()) {
|
|
60
|
+
throw new CliError(`Working directory does not exist or is not a directory: ${cwd}`);
|
|
173
61
|
}
|
|
174
|
-
|
|
175
|
-
await resolveHostDirectory(resolve2(containing.hostPath, mappedRelative), "Sandbox cwd mapped");
|
|
176
|
-
const workspaceRelativeCwd = sandboxPathContains(workspace.mountPoint, sandboxCwd) ? posix2.relative(workspace.mountPoint, sandboxCwd) || "." : null;
|
|
62
|
+
await access(cwd);
|
|
177
63
|
const executor = parseExecutor(input.executor ?? env.OLLIE_EXECUTOR);
|
|
178
64
|
return {
|
|
179
|
-
cwd
|
|
180
|
-
workspaceMountPoint: workspace.mountPoint,
|
|
181
|
-
sandboxCwd,
|
|
182
|
-
workspaceRelativeCwd,
|
|
183
|
-
mounts,
|
|
184
|
-
usedImplicitCwd,
|
|
65
|
+
cwd,
|
|
185
66
|
provider: input.provider ?? env.OLLIE_PROVIDER ?? DEFAULT_PROVIDER,
|
|
186
67
|
model: input.model ?? env.OLLIE_MODEL ?? DEFAULT_MODEL,
|
|
187
68
|
executor,
|
|
188
|
-
maxSteps: clamp(
|
|
69
|
+
maxSteps: clamp(
|
|
70
|
+
parseNumber("max steps", input.maxSteps ?? env.OLLIE_MAX_STEPS, DEFAULT_MAX_STEPS),
|
|
71
|
+
1,
|
|
72
|
+
100
|
|
73
|
+
),
|
|
189
74
|
commandTimeoutMs: clamp(
|
|
190
|
-
parseNumber(
|
|
75
|
+
parseNumber(
|
|
76
|
+
"command timeout",
|
|
77
|
+
input.timeout ?? env.OLLIE_COMMAND_TIMEOUT_MS,
|
|
78
|
+
DEFAULT_COMMAND_TIMEOUT_MS
|
|
79
|
+
),
|
|
191
80
|
1,
|
|
192
81
|
3e5
|
|
193
82
|
),
|
|
194
83
|
maxOutputBytes: clamp(
|
|
195
|
-
parseNumber(
|
|
84
|
+
parseNumber(
|
|
85
|
+
"max output",
|
|
86
|
+
input.maxOutput ?? env.OLLIE_MAX_OUTPUT_BYTES,
|
|
87
|
+
DEFAULT_MAX_OUTPUT_BYTES
|
|
88
|
+
),
|
|
196
89
|
1,
|
|
197
90
|
2e6
|
|
198
91
|
),
|
|
@@ -206,23 +99,23 @@ async function resolveRunConfig(input = {}, env = process.env) {
|
|
|
206
99
|
import { access as access2, stat as stat2 } from "fs/promises";
|
|
207
100
|
|
|
208
101
|
// src/sandbox/just-bash.ts
|
|
209
|
-
import { realpathSync
|
|
102
|
+
import { realpathSync, statSync } from "fs";
|
|
210
103
|
import { Bash, InMemoryFs, MountableFs, ReadWriteFs } from "just-bash";
|
|
211
104
|
|
|
212
105
|
// src/sandbox/git/index.ts
|
|
213
|
-
import { posix as
|
|
106
|
+
import { posix as posix2 } from "path";
|
|
214
107
|
import { createTwoFilesPatch } from "diff";
|
|
215
108
|
import * as git from "isomorphic-git";
|
|
216
109
|
import { defineCommand } from "just-bash";
|
|
217
110
|
|
|
218
111
|
// src/sandbox/git/fs-adapter.ts
|
|
219
|
-
import { posix
|
|
112
|
+
import { posix } from "path";
|
|
220
113
|
var ROOT = "/workspace";
|
|
221
114
|
function safePath(path) {
|
|
222
115
|
if (path.includes("\0") || path.includes("\\")) {
|
|
223
116
|
throw Object.assign(new Error("Invalid virtual Git path"), { code: "EINVAL" });
|
|
224
117
|
}
|
|
225
|
-
const normalized =
|
|
118
|
+
const normalized = posix.resolve(path);
|
|
226
119
|
if (normalized !== ROOT && !normalized.startsWith(`${ROOT}/`)) {
|
|
227
120
|
throw Object.assign(new Error("Git path is outside /workspace"), { code: "EACCES" });
|
|
228
121
|
}
|
|
@@ -242,7 +135,7 @@ function normalizeError(error) {
|
|
|
242
135
|
throw Object.assign(new Error("Virtual filesystem operation failed"), { code: "EIO" });
|
|
243
136
|
}
|
|
244
137
|
async function ensureParent(fs, path) {
|
|
245
|
-
const parent =
|
|
138
|
+
const parent = posix.dirname(path);
|
|
246
139
|
if (!await fs.exists(parent)) await fs.mkdir(parent, { recursive: true });
|
|
247
140
|
}
|
|
248
141
|
function statShape(stat4) {
|
|
@@ -477,9 +370,9 @@ function virtualPath(ctx, input = ".") {
|
|
|
477
370
|
async function repositoryDir(ctx) {
|
|
478
371
|
let current = virtualPath(ctx);
|
|
479
372
|
while (current === WORKSPACE || current.startsWith(`${WORKSPACE}/`)) {
|
|
480
|
-
if (await ctx.fs.exists(
|
|
373
|
+
if (await ctx.fs.exists(posix2.join(current, ".git"))) return current;
|
|
481
374
|
if (current === WORKSPACE) break;
|
|
482
|
-
current =
|
|
375
|
+
current = posix2.dirname(current);
|
|
483
376
|
}
|
|
484
377
|
throw new Error("not a git repository (or any parent up to /workspace)");
|
|
485
378
|
}
|
|
@@ -562,7 +455,7 @@ async function writeGlobalConfig(ctx, values) {
|
|
|
562
455
|
([section, entries]) => `[${section}]
|
|
563
456
|
${entries.map(([key, value]) => ` ${key} = ${value}`).join("\n")}`
|
|
564
457
|
).join("\n");
|
|
565
|
-
await ctx.fs.mkdir(
|
|
458
|
+
await ctx.fs.mkdir(posix2.dirname(GLOBAL_CONFIG_PATH), { recursive: true });
|
|
566
459
|
await ctx.fs.writeFile(GLOBAL_CONFIG_PATH, content ? `${content}
|
|
567
460
|
` : "");
|
|
568
461
|
}
|
|
@@ -576,7 +469,7 @@ async function handleInit(context, args) {
|
|
|
576
469
|
throw new Error("cannot create repository directory");
|
|
577
470
|
});
|
|
578
471
|
await git.init({ fs: context.fs, dir, defaultBranch: branchOpt.value ?? "main" });
|
|
579
|
-
return ok(`Initialized empty Git repository in ${
|
|
472
|
+
return ok(`Initialized empty Git repository in ${posix2.join(dir, ".git")}/
|
|
580
473
|
`);
|
|
581
474
|
}
|
|
582
475
|
async function handleStatus(context, args) {
|
|
@@ -729,7 +622,7 @@ async function handleDiff(context, args) {
|
|
|
729
622
|
const changed = cachedFlag.enabled ? headStatus !== stageStatus : workdirStatus !== stageStatus;
|
|
730
623
|
if (!changed) continue;
|
|
731
624
|
const oldBytes = cachedFlag.enabled ? head && headStatus !== 0 ? (await git.readBlob({ fs: context.fs, dir, oid: head, filepath })).blob : empty : await readStage(filepath);
|
|
732
|
-
const newBytes = cachedFlag.enabled ? await readStage(filepath) : workdirStatus === 0 ? empty : await context.command.fs.readFileBuffer(
|
|
625
|
+
const newBytes = cachedFlag.enabled ? await readStage(filepath) : workdirStatus === 0 ? empty : await context.command.fs.readFileBuffer(posix2.join(dir, filepath));
|
|
733
626
|
patches.push(patch(filepath, oldBytes, newBytes));
|
|
734
627
|
}
|
|
735
628
|
return ok(patches.join(""));
|
|
@@ -796,7 +689,7 @@ async function handleCheckout(context, args) {
|
|
|
796
689
|
const oid = await git.resolveRef({ fs: context.fs, dir, ref });
|
|
797
690
|
for (const filepath of filepaths) {
|
|
798
691
|
const blob = await readCheckoutBlob(context, dir, oid, filepath);
|
|
799
|
-
await context.command.fs.writeFile(
|
|
692
|
+
await context.command.fs.writeFile(posix2.join(dir, filepath), blob);
|
|
800
693
|
}
|
|
801
694
|
return ok();
|
|
802
695
|
}
|
|
@@ -923,7 +816,7 @@ async function handleClone(context, args) {
|
|
|
923
816
|
const [rawUrl, destination, ...rest] = noCheckoutFlag.rest;
|
|
924
817
|
if (!rawUrl || rest.length) usage("clone requires a URL and optional directory");
|
|
925
818
|
const url = validateRemoteUrl(rawUrl);
|
|
926
|
-
const inferred =
|
|
819
|
+
const inferred = posix2.basename(new URL(url).pathname).replace(/\.git$/, "") || "repository";
|
|
927
820
|
const dir = virtualPath(context.command, destination ?? inferred);
|
|
928
821
|
const depth = positiveInteger(depthOpt.value, "--depth");
|
|
929
822
|
await git.clone({
|
|
@@ -1087,49 +980,34 @@ Supported commands: ${COMMANDS.join(", ")}
|
|
|
1087
980
|
}
|
|
1088
981
|
|
|
1089
982
|
// src/sandbox/just-bash.ts
|
|
1090
|
-
var
|
|
983
|
+
var SANDBOX_WORKSPACE_PATH = "/workspace";
|
|
1091
984
|
function canonicalizeWorkspaceRoot(workspaceRoot) {
|
|
1092
|
-
const canonicalRoot =
|
|
1093
|
-
if (!
|
|
985
|
+
const canonicalRoot = realpathSync(workspaceRoot);
|
|
986
|
+
if (!statSync(canonicalRoot).isDirectory()) {
|
|
1094
987
|
throw new Error("The sandbox workspace root must be a directory");
|
|
1095
988
|
}
|
|
1096
989
|
return canonicalRoot;
|
|
1097
990
|
}
|
|
1098
|
-
function createWorkspaceFs(workspaceRoot
|
|
991
|
+
function createWorkspaceFs(workspaceRoot) {
|
|
1099
992
|
const root = canonicalizeWorkspaceRoot(workspaceRoot);
|
|
1100
|
-
const workspaceMountPoint = options.workspaceMountPoint ?? SANDBOX_WORKSPACE_PATH2;
|
|
1101
|
-
validateSandboxPath(workspaceMountPoint, "Workspace mount point");
|
|
1102
|
-
const additionalMounts = validateSandboxMounts(options.mounts ?? [], {
|
|
1103
|
-
reservedMountPoint: workspaceMountPoint
|
|
1104
|
-
}).map((mount) => ({
|
|
1105
|
-
mountPoint: mount.mountPoint,
|
|
1106
|
-
filesystem: new ReadWriteFs({ root: mount.hostPath, allowSymlinks: false })
|
|
1107
|
-
}));
|
|
1108
993
|
return new MountableFs({
|
|
1109
994
|
base: new InMemoryFs(),
|
|
1110
995
|
mounts: [
|
|
1111
996
|
{
|
|
1112
|
-
mountPoint:
|
|
997
|
+
mountPoint: SANDBOX_WORKSPACE_PATH,
|
|
1113
998
|
filesystem: new ReadWriteFs({ root, allowSymlinks: false })
|
|
1114
|
-
}
|
|
1115
|
-
...additionalMounts
|
|
999
|
+
}
|
|
1116
1000
|
]
|
|
1117
1001
|
});
|
|
1118
1002
|
}
|
|
1119
1003
|
function createJustBash(workspaceRoot, options = {}) {
|
|
1120
|
-
const workspaceMountPoint = options.workspaceMountPoint ?? SANDBOX_WORKSPACE_PATH2;
|
|
1121
|
-
const sandboxCwd = options.sandboxCwd ?? workspaceMountPoint;
|
|
1122
|
-
validateSandboxPath(sandboxCwd, "Sandbox cwd");
|
|
1123
|
-
const configuredMountPoints = [workspaceMountPoint, ...(options.mounts ?? []).map((m) => m.mountPoint)];
|
|
1124
|
-
if (!configuredMountPoints.some((mountPoint) => sandboxPathContains(mountPoint, sandboxCwd))) {
|
|
1125
|
-
throw new CliError(
|
|
1126
|
-
`Sandbox cwd ${sandboxCwd} is not contained by the primary workspace or any configured mount.`
|
|
1127
|
-
);
|
|
1128
|
-
}
|
|
1129
1004
|
return new Bash({
|
|
1130
|
-
fs: createWorkspaceFs(workspaceRoot
|
|
1131
|
-
cwd:
|
|
1132
|
-
env: {
|
|
1005
|
+
fs: createWorkspaceFs(workspaceRoot),
|
|
1006
|
+
cwd: SANDBOX_WORKSPACE_PATH,
|
|
1007
|
+
env: {
|
|
1008
|
+
HOME: "/home/user",
|
|
1009
|
+
TERM: "xterm-256color"
|
|
1010
|
+
},
|
|
1133
1011
|
python: true,
|
|
1134
1012
|
javascript: true,
|
|
1135
1013
|
customCommands: options.git === false ? [] : [createGitCommand(options.git)],
|
|
@@ -1226,11 +1104,7 @@ async function runExecCommand(cwd, command, options, signal) {
|
|
|
1226
1104
|
const combinedSignal = combineSignals([signal, timeout.signal]);
|
|
1227
1105
|
const timedOut = () => timeout.signal.aborted && !signal?.aborted;
|
|
1228
1106
|
try {
|
|
1229
|
-
const bash = createJustBash(cwd
|
|
1230
|
-
workspaceMountPoint: options.workspaceMountPoint,
|
|
1231
|
-
sandboxCwd: options.sandboxCwd,
|
|
1232
|
-
mounts: options.mounts
|
|
1233
|
-
});
|
|
1107
|
+
const bash = createJustBash(cwd);
|
|
1234
1108
|
const result = await bash.exec(command, { env: options.env, signal: combinedSignal });
|
|
1235
1109
|
return {
|
|
1236
1110
|
...result,
|
|
@@ -1479,7 +1353,7 @@ var ExecutorController = class {
|
|
|
1479
1353
|
// src/executor/daytona.ts
|
|
1480
1354
|
import { randomUUID } from "crypto";
|
|
1481
1355
|
import { mkdir, readdir, readFile, rm, stat as stat3, writeFile } from "fs/promises";
|
|
1482
|
-
import { dirname, isAbsolute, relative, resolve as
|
|
1356
|
+
import { dirname, isAbsolute, relative, resolve as resolve2, sep } from "path";
|
|
1483
1357
|
import {
|
|
1484
1358
|
Daytona,
|
|
1485
1359
|
DaytonaProcessExecutionTimeoutError
|
|
@@ -1514,7 +1388,7 @@ async function listLocalFiles(root) {
|
|
|
1514
1388
|
const files = /* @__PURE__ */ new Map();
|
|
1515
1389
|
async function visit(directory) {
|
|
1516
1390
|
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
1517
|
-
const absolutePath =
|
|
1391
|
+
const absolutePath = resolve2(directory, entry.name);
|
|
1518
1392
|
if (entry.isDirectory()) {
|
|
1519
1393
|
await visit(absolutePath);
|
|
1520
1394
|
} else if (entry.isFile()) {
|
|
@@ -1529,14 +1403,12 @@ async function listLocalFiles(root) {
|
|
|
1529
1403
|
var DaytonaSandbox = class {
|
|
1530
1404
|
#sandbox;
|
|
1531
1405
|
#workspacePath;
|
|
1532
|
-
#workingDirectory;
|
|
1533
1406
|
#commandTimeoutMs;
|
|
1534
1407
|
#signal;
|
|
1535
1408
|
#disposed = false;
|
|
1536
1409
|
constructor(sandbox, options) {
|
|
1537
1410
|
this.#sandbox = sandbox;
|
|
1538
1411
|
this.#workspacePath = options.workspacePath;
|
|
1539
|
-
this.#workingDirectory = options.workingDirectory ?? options.workspacePath;
|
|
1540
1412
|
this.#commandTimeoutMs = options.commandTimeoutMs;
|
|
1541
1413
|
this.#signal = options.signal;
|
|
1542
1414
|
}
|
|
@@ -1553,7 +1425,7 @@ ${marker}
|
|
|
1553
1425
|
const response = await abortable(
|
|
1554
1426
|
this.#sandbox.process.executeCommand(
|
|
1555
1427
|
wrapped,
|
|
1556
|
-
this.#
|
|
1428
|
+
this.#workspacePath,
|
|
1557
1429
|
void 0,
|
|
1558
1430
|
timeoutSeconds(this.#commandTimeoutMs)
|
|
1559
1431
|
),
|
|
@@ -1600,7 +1472,7 @@ ${marker}
|
|
|
1600
1472
|
this.#disposed = true;
|
|
1601
1473
|
}
|
|
1602
1474
|
#resolvePath(path) {
|
|
1603
|
-
const target = isAbsolute(path) ?
|
|
1475
|
+
const target = isAbsolute(path) ? resolve2(path) : resolve2(this.#workspacePath, path);
|
|
1604
1476
|
if (target !== this.#workspacePath && !target.startsWith(`${this.#workspacePath}/`)) {
|
|
1605
1477
|
throw new Error(`Path is outside the Daytona workspace: ${path}`);
|
|
1606
1478
|
}
|
|
@@ -1616,7 +1488,7 @@ var DaytonaWorkspaceSynchronizer = class {
|
|
|
1616
1488
|
#sandbox;
|
|
1617
1489
|
#knownFiles = /* @__PURE__ */ new Set();
|
|
1618
1490
|
constructor(cwd, remoteWorkspacePath, sandbox) {
|
|
1619
|
-
this.#cwd =
|
|
1491
|
+
this.#cwd = resolve2(cwd);
|
|
1620
1492
|
this.#remoteWorkspacePath = remoteWorkspacePath;
|
|
1621
1493
|
this.#sandbox = sandbox;
|
|
1622
1494
|
}
|
|
@@ -1647,7 +1519,7 @@ var DaytonaWorkspaceSynchronizer = class {
|
|
|
1647
1519
|
for (const [path, size] of localFiles) {
|
|
1648
1520
|
signal?.throwIfAborted();
|
|
1649
1521
|
await abortable(
|
|
1650
|
-
this.#sandbox.fs.uploadFile(
|
|
1522
|
+
this.#sandbox.fs.uploadFile(resolve2(this.#cwd, path), this.#remotePath(path)),
|
|
1651
1523
|
signal
|
|
1652
1524
|
);
|
|
1653
1525
|
if (this.#knownFiles.has(path)) filesUpdated++;
|
|
@@ -1679,7 +1551,7 @@ var DaytonaWorkspaceSynchronizer = class {
|
|
|
1679
1551
|
let bytesTransferred = 0;
|
|
1680
1552
|
for (const path of this.#knownFiles) {
|
|
1681
1553
|
if (remoteFiles.has(path)) continue;
|
|
1682
|
-
await rm(
|
|
1554
|
+
await rm(resolve2(this.#cwd, path), { force: true });
|
|
1683
1555
|
filesDeleted++;
|
|
1684
1556
|
}
|
|
1685
1557
|
for (const path of remoteFiles) {
|
|
@@ -1709,7 +1581,7 @@ var DaytonaWorkspaceSynchronizer = class {
|
|
|
1709
1581
|
return `${this.#remoteWorkspacePath}/${path}`;
|
|
1710
1582
|
}
|
|
1711
1583
|
#localPath(path) {
|
|
1712
|
-
const target =
|
|
1584
|
+
const target = resolve2(this.#cwd, path);
|
|
1713
1585
|
if (target !== this.#cwd && !target.startsWith(`${this.#cwd}${sep}`)) {
|
|
1714
1586
|
throw new Error(`Daytona returned a path outside the workspace: ${path}`);
|
|
1715
1587
|
}
|
|
@@ -1734,24 +1606,16 @@ var DaytonaExecutorSession = class {
|
|
|
1734
1606
|
#disposed = false;
|
|
1735
1607
|
constructor(remote, options, signal) {
|
|
1736
1608
|
const workspacePath = options.remoteWorkspacePath ?? DEFAULT_REMOTE_WORKSPACE;
|
|
1737
|
-
const relativeCwd = options.relativeCwd ?? ".";
|
|
1738
|
-
const workingDirectory = resolve3(workspacePath, relativeCwd);
|
|
1739
1609
|
this.#remote = remote;
|
|
1740
1610
|
this.#synchronizer = new DaytonaWorkspaceSynchronizer(options.cwd, workspacePath, remote);
|
|
1741
1611
|
this.sandbox = new DaytonaSandbox(remote, {
|
|
1742
1612
|
workspacePath,
|
|
1743
|
-
workingDirectory,
|
|
1744
1613
|
commandTimeoutMs: options.commandTimeoutMs,
|
|
1745
1614
|
signal
|
|
1746
1615
|
});
|
|
1747
1616
|
this.context = {
|
|
1748
1617
|
kind: "daytona",
|
|
1749
1618
|
workspacePath,
|
|
1750
|
-
...options.relativeCwd !== void 0 ? {
|
|
1751
|
-
workingDirectory,
|
|
1752
|
-
cwdPreserved: options.relativeCwd !== null,
|
|
1753
|
-
...options.relativeCwd === null ? { cwdLimitation: "The selected sandbox cwd is on an additional mount; starting at the effective workspace root." } : {}
|
|
1754
|
-
} : {},
|
|
1755
1619
|
isolated: true,
|
|
1756
1620
|
networkAccess: "full"
|
|
1757
1621
|
};
|
|
@@ -1851,7 +1715,7 @@ Terminus-2 spirit:
|
|
|
1851
1715
|
- Summarize final findings and important command results clearly.
|
|
1852
1716
|
|
|
1853
1717
|
Runtime context:
|
|
1854
|
-
- Working directory: ${
|
|
1718
|
+
- Working directory: ${SANDBOX_WORKSPACE_PATH}
|
|
1855
1719
|
- Current time: ${options.now.toISOString()}
|
|
1856
1720
|
- Maximum model/tool steps: ${options.maxSteps}
|
|
1857
1721
|
- Per-command timeout: ${options.commandTimeoutMs} ms
|
|
@@ -1874,20 +1738,17 @@ Tool policy:
|
|
|
1874
1738
|
}
|
|
1875
1739
|
function buildDelegatedSystemPrompt(options) {
|
|
1876
1740
|
const executionBoundary = options.context.isolated ? "Commands run natively inside an isolated remote environment." : "Commands run natively with the current user's permissions and are not isolated.";
|
|
1877
|
-
const cwdNote = options.context.cwdLimitation ? `
|
|
1878
|
-
- Working-directory limitation: ${options.context.cwdLimitation}` : "";
|
|
1879
1741
|
return `You are Ollie's delegated execution agent. Complete one bounded task using native workspace tools.
|
|
1880
1742
|
|
|
1881
1743
|
Runtime context:
|
|
1882
1744
|
- Workspace root: ${options.context.workspacePath}
|
|
1883
|
-
- Working directory: ${options.context.workingDirectory ?? options.context.workspacePath}${cwdNote}
|
|
1884
1745
|
- Current time: ${options.now.toISOString()}
|
|
1885
1746
|
- Maximum model/tool steps: ${options.maxSteps}
|
|
1886
1747
|
- Per-command timeout: ${options.commandTimeoutMs} ms
|
|
1887
1748
|
- ${executionBoundary}
|
|
1888
1749
|
|
|
1889
1750
|
Operating rules:
|
|
1890
|
-
- Start at the
|
|
1751
|
+
- Start at the workspace root and use relative paths for workspace files.
|
|
1891
1752
|
- Inspect the relevant state before making changes.
|
|
1892
1753
|
- Keep changes minimal and directly related to the delegated task.
|
|
1893
1754
|
- Run appropriate native checks or tests and report their actual results.
|
|
@@ -1909,12 +1770,8 @@ async function createWorkspaceTools(options) {
|
|
|
1909
1770
|
}
|
|
1910
1771
|
async function createTools(options) {
|
|
1911
1772
|
return createWorkspaceTools({
|
|
1912
|
-
sandbox: createJustBash(options.cwd,
|
|
1913
|
-
|
|
1914
|
-
workspaceMountPoint: options.workspaceMountPoint,
|
|
1915
|
-
sandboxCwd: options.sandboxCwd
|
|
1916
|
-
}),
|
|
1917
|
-
destination: options.sandboxCwd ?? options.workspaceMountPoint ?? SANDBOX_WORKSPACE_PATH2,
|
|
1773
|
+
sandbox: createJustBash(options.cwd),
|
|
1774
|
+
destination: SANDBOX_WORKSPACE_PATH,
|
|
1918
1775
|
maxOutputBytes: options.maxOutputBytes,
|
|
1919
1776
|
extraInstructions: "Use bash commands to inspect files, search, run tests, and gather terminal state. Sandbox-native git is available; local Git changes persist in the workspace, and git push has permanent remote effects, so destructive actions and pushes must only be used when explicitly requested. Keep commands bounded."
|
|
1920
1777
|
});
|
|
@@ -1939,9 +1796,9 @@ var ModelTaskDelegator = class {
|
|
|
1939
1796
|
});
|
|
1940
1797
|
const tools = await createWorkspaceTools({
|
|
1941
1798
|
sandbox: session.sandbox,
|
|
1942
|
-
destination: session.context.
|
|
1799
|
+
destination: session.context.workspacePath,
|
|
1943
1800
|
maxOutputBytes: this.options.maxOutputBytes,
|
|
1944
|
-
extraInstructions: "Use the native workspace tools to complete the delegated task.
|
|
1801
|
+
extraInstructions: "Use the native workspace tools to complete the delegated task. Start at the workspace root, use relative paths, keep changes focused, and verify the result before reporting it."
|
|
1945
1802
|
});
|
|
1946
1803
|
const result = await generateText({
|
|
1947
1804
|
model: this.options.model,
|
|
@@ -1989,7 +1846,7 @@ var ModelTaskDelegator = class {
|
|
|
1989
1846
|
// src/executor/local.ts
|
|
1990
1847
|
import { spawn } from "child_process";
|
|
1991
1848
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
1992
|
-
import { dirname as dirname2, isAbsolute as isAbsolute2, resolve as
|
|
1849
|
+
import { dirname as dirname2, isAbsolute as isAbsolute2, resolve as resolve3 } from "path";
|
|
1993
1850
|
var LocalSandbox = class {
|
|
1994
1851
|
#cwd;
|
|
1995
1852
|
#commandTimeoutMs;
|
|
@@ -1998,7 +1855,7 @@ var LocalSandbox = class {
|
|
|
1998
1855
|
#processes = /* @__PURE__ */ new Set();
|
|
1999
1856
|
#disposed = false;
|
|
2000
1857
|
constructor(options, signal) {
|
|
2001
|
-
this.#cwd =
|
|
1858
|
+
this.#cwd = resolve3(options.cwd);
|
|
2002
1859
|
this.#commandTimeoutMs = options.commandTimeoutMs;
|
|
2003
1860
|
this.#env = options.env ?? process.env;
|
|
2004
1861
|
this.#signal = signal;
|
|
@@ -2111,7 +1968,7 @@ var LocalSandbox = class {
|
|
|
2111
1968
|
this.#processes.clear();
|
|
2112
1969
|
}
|
|
2113
1970
|
#resolvePath(path) {
|
|
2114
|
-
return isAbsolute2(path) ? path :
|
|
1971
|
+
return isAbsolute2(path) ? path : resolve3(this.#cwd, path);
|
|
2115
1972
|
}
|
|
2116
1973
|
#assertActive() {
|
|
2117
1974
|
if (this.#disposed) throw new Error("Local executor session has been disposed");
|
|
@@ -2122,17 +1979,11 @@ var LocalExecutorSession = class {
|
|
|
2122
1979
|
context;
|
|
2123
1980
|
#disposed = false;
|
|
2124
1981
|
constructor(options, signal) {
|
|
2125
|
-
const workspacePath =
|
|
2126
|
-
const workingDirectory = resolve4(workspacePath, options.relativeCwd ?? ".");
|
|
1982
|
+
const workspacePath = resolve3(options.cwd);
|
|
2127
1983
|
this.sandbox = new LocalSandbox(options, signal);
|
|
2128
1984
|
this.context = {
|
|
2129
1985
|
kind: "local",
|
|
2130
1986
|
workspacePath,
|
|
2131
|
-
...options.relativeCwd !== void 0 ? {
|
|
2132
|
-
workingDirectory,
|
|
2133
|
-
cwdPreserved: options.relativeCwd !== null,
|
|
2134
|
-
...options.relativeCwd === null ? { cwdLimitation: "The selected sandbox cwd is on an additional mount; starting at the effective workspace root." } : {}
|
|
2135
|
-
} : {},
|
|
2136
1987
|
isolated: false,
|
|
2137
1988
|
networkAccess: "full"
|
|
2138
1989
|
};
|
|
@@ -2215,7 +2066,7 @@ function createLanguageModel({
|
|
|
2215
2066
|
throw new CliError("OPENAI_API_KEY is required when using the openai provider.");
|
|
2216
2067
|
}
|
|
2217
2068
|
const openai = createOpenAI({ apiKey: env.OPENAI_API_KEY });
|
|
2218
|
-
return openai(model);
|
|
2069
|
+
return openai.chat(model);
|
|
2219
2070
|
}
|
|
2220
2071
|
|
|
2221
2072
|
// src/runner.ts
|
|
@@ -2226,13 +2077,11 @@ function createExecutorProvider(options) {
|
|
|
2226
2077
|
case "local":
|
|
2227
2078
|
return new LocalExecutorProvider({
|
|
2228
2079
|
cwd: options.cwd,
|
|
2229
|
-
relativeCwd: options.workspaceRelativeCwd,
|
|
2230
2080
|
commandTimeoutMs: options.commandTimeoutMs
|
|
2231
2081
|
});
|
|
2232
2082
|
case "daytona":
|
|
2233
2083
|
return new DaytonaExecutorProvider({
|
|
2234
2084
|
cwd: options.cwd,
|
|
2235
|
-
relativeCwd: options.workspaceRelativeCwd,
|
|
2236
2085
|
commandTimeoutMs: options.commandTimeoutMs,
|
|
2237
2086
|
snapshot: process.env.OLLIE_DAYTONA_SNAPSHOT
|
|
2238
2087
|
});
|
|
@@ -2247,9 +2096,6 @@ async function runOneShot(options) {
|
|
|
2247
2096
|
});
|
|
2248
2097
|
const workspaceTools = await createTools({
|
|
2249
2098
|
cwd: options.cwd,
|
|
2250
|
-
workspaceMountPoint: options.workspaceMountPoint,
|
|
2251
|
-
sandboxCwd: options.sandboxCwd,
|
|
2252
|
-
mounts: options.mounts,
|
|
2253
2099
|
maxOutputBytes: options.maxOutputBytes
|
|
2254
2100
|
});
|
|
2255
2101
|
const executorProvider = createExecutorProvider(options);
|
|
@@ -2276,7 +2122,6 @@ async function runOneShot(options) {
|
|
|
2276
2122
|
now: /* @__PURE__ */ new Date(),
|
|
2277
2123
|
maxSteps: options.maxSteps,
|
|
2278
2124
|
commandTimeoutMs: options.commandTimeoutMs,
|
|
2279
|
-
sandboxCwd: options.sandboxCwd,
|
|
2280
2125
|
executorInstructions: executorProvider?.systemPrompt
|
|
2281
2126
|
}),
|
|
2282
2127
|
prompt: options.prompt,
|
|
@@ -2328,7 +2173,7 @@ async function runOneShot(options) {
|
|
|
2328
2173
|
|
|
2329
2174
|
// src/sandbox/runtime.ts
|
|
2330
2175
|
import { once } from "events";
|
|
2331
|
-
import { posix as
|
|
2176
|
+
import { posix as posix3 } from "path";
|
|
2332
2177
|
import { createInterface } from "readline";
|
|
2333
2178
|
function isRecord(value) {
|
|
2334
2179
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -2366,7 +2211,7 @@ function requireString(params, name) {
|
|
|
2366
2211
|
return value;
|
|
2367
2212
|
}
|
|
2368
2213
|
function validateVirtualPath(path) {
|
|
2369
|
-
if (!
|
|
2214
|
+
if (!posix3.isAbsolute(path) || path.includes("\\") || path.includes("\0") || posix3.normalize(path) !== path || path.split("/").some((component) => component === "." || component === "..")) {
|
|
2370
2215
|
throw new Error("Path must be a normalized absolute virtual path");
|
|
2371
2216
|
}
|
|
2372
2217
|
return path;
|
|
@@ -2427,11 +2272,7 @@ async function runWorker(options = {}) {
|
|
|
2427
2272
|
const workspaceRoot = options.cwd ?? process.cwd();
|
|
2428
2273
|
const input = options.input ?? process.stdin;
|
|
2429
2274
|
const output = options.output ?? process.stdout;
|
|
2430
|
-
const bash = createJustBash(workspaceRoot
|
|
2431
|
-
mounts: options.mounts,
|
|
2432
|
-
workspaceMountPoint: options.workspaceMountPoint,
|
|
2433
|
-
sandboxCwd: options.sandboxCwd
|
|
2434
|
-
});
|
|
2275
|
+
const bash = createJustBash(workspaceRoot);
|
|
2435
2276
|
const lines = createInterface({ input, crlfDelay: Number.POSITIVE_INFINITY });
|
|
2436
2277
|
const close = () => lines.close();
|
|
2437
2278
|
if (options.signal?.aborted) {
|
|
@@ -2480,17 +2321,7 @@ function truncateText(input, maxBytes) {
|
|
|
2480
2321
|
|
|
2481
2322
|
// src/cli-program.ts
|
|
2482
2323
|
function addExecOptions(command, ndjsonDescription = "emit one JSON result record") {
|
|
2483
|
-
return
|
|
2484
|
-
}
|
|
2485
|
-
function collectOption(value, previous) {
|
|
2486
|
-
return [...previous ?? [], value];
|
|
2487
|
-
}
|
|
2488
|
-
function addMountOption(command) {
|
|
2489
|
-
return command.option(
|
|
2490
|
-
"--mount <host-path:sandbox-path>",
|
|
2491
|
-
"mount a host directory read-write (repeatable)",
|
|
2492
|
-
collectOption
|
|
2493
|
-
);
|
|
2324
|
+
return command.option("--cwd <path>", "working directory").option("--timeout <ms>", "command timeout in milliseconds").option("--max-output <bytes>", "maximum retained output").option("--ndjson", ndjsonDescription);
|
|
2494
2325
|
}
|
|
2495
2326
|
function addAgentOptions(command) {
|
|
2496
2327
|
return addExecOptions(command, "emit newline-delimited JSON event records").option("--provider <provider>", "model provider", "openai").option("--model <model>", "model id").option(
|
|
@@ -2499,20 +2330,12 @@ function addAgentOptions(command) {
|
|
|
2499
2330
|
"none"
|
|
2500
2331
|
).option("--max-steps <number>", "maximum model/tool steps").option("--no-color", "disable color output");
|
|
2501
2332
|
}
|
|
2502
|
-
function warnImplicitCwd(usedImplicitCwd) {
|
|
2503
|
-
if (usedImplicitCwd) {
|
|
2504
|
-
process.stderr.write(
|
|
2505
|
-
"Warning: omitting --cwd and --sandbox-cwd is deprecated; currently using --cwd .\n"
|
|
2506
|
-
);
|
|
2507
|
-
}
|
|
2508
|
-
}
|
|
2509
2333
|
async function runAgent(promptParts, options) {
|
|
2510
2334
|
const prompt = promptParts.join(" ").trim();
|
|
2511
2335
|
if (!prompt) {
|
|
2512
2336
|
throw new CliError('A prompt is required. Example: ollie agent "summarize this repository"');
|
|
2513
2337
|
}
|
|
2514
2338
|
const config = await resolveRunConfig(options);
|
|
2515
|
-
warnImplicitCwd(config.usedImplicitCwd);
|
|
2516
2339
|
const renderer = createRenderer({ ndjson: config.ndjson, color: config.color });
|
|
2517
2340
|
const controller = new AbortController();
|
|
2518
2341
|
const onSigint = () => controller.abort();
|
|
@@ -2535,7 +2358,6 @@ async function runExec(commandParts, options) {
|
|
|
2535
2358
|
throw new CliError('A command is required. Example: ollie "pwd && ls -la"');
|
|
2536
2359
|
}
|
|
2537
2360
|
const config = await resolveRunConfig(options);
|
|
2538
|
-
warnImplicitCwd(config.usedImplicitCwd);
|
|
2539
2361
|
const controller = new AbortController();
|
|
2540
2362
|
let signalExitCode;
|
|
2541
2363
|
const onSigint = () => {
|
|
@@ -2554,10 +2376,7 @@ async function runExec(commandParts, options) {
|
|
|
2554
2376
|
shellCommand,
|
|
2555
2377
|
{
|
|
2556
2378
|
timeoutMs: config.commandTimeoutMs,
|
|
2557
|
-
env: process.env
|
|
2558
|
-
workspaceMountPoint: config.workspaceMountPoint,
|
|
2559
|
-
sandboxCwd: config.sandboxCwd,
|
|
2560
|
-
mounts: config.mounts
|
|
2379
|
+
env: process.env
|
|
2561
2380
|
},
|
|
2562
2381
|
controller.signal
|
|
2563
2382
|
);
|
|
@@ -2596,8 +2415,6 @@ async function runExec(commandParts, options) {
|
|
|
2596
2415
|
}
|
|
2597
2416
|
}
|
|
2598
2417
|
async function runSandbox(options) {
|
|
2599
|
-
const config = await resolveRunConfig(options);
|
|
2600
|
-
warnImplicitCwd(config.usedImplicitCwd);
|
|
2601
2418
|
const controller = new AbortController();
|
|
2602
2419
|
let signalExitCode;
|
|
2603
2420
|
const onSigint = () => {
|
|
@@ -2612,10 +2429,7 @@ async function runSandbox(options) {
|
|
|
2612
2429
|
process.once("SIGTERM", onSigterm);
|
|
2613
2430
|
try {
|
|
2614
2431
|
await runWorker({
|
|
2615
|
-
cwd:
|
|
2616
|
-
workspaceMountPoint: config.workspaceMountPoint,
|
|
2617
|
-
sandboxCwd: config.sandboxCwd,
|
|
2618
|
-
mounts: config.mounts,
|
|
2432
|
+
cwd: options.cwd,
|
|
2619
2433
|
signal: controller.signal
|
|
2620
2434
|
});
|
|
2621
2435
|
if (signalExitCode !== void 0) {
|
|
@@ -2644,10 +2458,7 @@ function createProgram() {
|
|
|
2644
2458
|
agent.action(async (prompt, options) => {
|
|
2645
2459
|
await runAgent(prompt, options);
|
|
2646
2460
|
});
|
|
2647
|
-
|
|
2648
|
-
program.command("sandbox").description("run the persistent sandbox NDJSON command interface").option("--cwd <host-path>", "host workspace mounted at /workspace").option("--sandbox-cwd <sandbox-path>", "initial working directory inside the sandbox")
|
|
2649
|
-
);
|
|
2650
|
-
sandbox.action(async (options) => {
|
|
2461
|
+
program.command("sandbox").description("run the persistent sandbox NDJSON command interface").option("--cwd <path>", "working directory").action(async (options) => {
|
|
2651
2462
|
await runSandbox(options);
|
|
2652
2463
|
});
|
|
2653
2464
|
program.command("doctor").description("validate the local Ollie setup without making model calls").option("--cwd <path>", "working directory").option("--provider <provider>", "model provider", "openai").option("--model <model>", "model id").option("--json", "emit JSON report").action(async (options) => {
|
|
@@ -2657,13 +2468,7 @@ function createProgram() {
|
|
|
2657
2468
|
return program;
|
|
2658
2469
|
}
|
|
2659
2470
|
var RESERVED_SUBCOMMANDS = /* @__PURE__ */ new Set(["agent", "sandbox", "doctor"]);
|
|
2660
|
-
var ROOT_OPTIONS_WITH_VALUES = /* @__PURE__ */ new Set([
|
|
2661
|
-
"--cwd",
|
|
2662
|
-
"--sandbox-cwd",
|
|
2663
|
-
"--mount",
|
|
2664
|
-
"--timeout",
|
|
2665
|
-
"--max-output"
|
|
2666
|
-
]);
|
|
2471
|
+
var ROOT_OPTIONS_WITH_VALUES = /* @__PURE__ */ new Set(["--cwd", "--timeout", "--max-output"]);
|
|
2667
2472
|
function rootBoundaryPrecedesCommand(args) {
|
|
2668
2473
|
for (let index = 0; index < args.length; index += 1) {
|
|
2669
2474
|
const token = args[index] ?? "";
|