@mifune/agro 0.15.0 → 0.16.0
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/README.md +14 -2
- package/dist/agro.js +652 -345
- package/package.json +1 -1
package/dist/agro.js
CHANGED
|
@@ -7,8 +7,8 @@ var __export = (target, all) => {
|
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
-
import { dirname as dirname10, join as
|
|
11
|
-
import { existsSync as
|
|
10
|
+
import { dirname as dirname10, join as join19, resolve as resolve11 } from "node:path";
|
|
11
|
+
import { existsSync as existsSync23, mkdtempSync as mkdtempSync5, readFileSync as readFileSync13, rmSync as rmSync6 } from "node:fs";
|
|
12
12
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
13
13
|
|
|
14
14
|
// src/commands/update.ts
|
|
@@ -2222,7 +2222,7 @@ function resolveExecutionTarget(opts) {
|
|
|
2222
2222
|
}
|
|
2223
2223
|
|
|
2224
2224
|
// src/lib/version.ts
|
|
2225
|
-
var AGRO_VERSION = true ? "0.
|
|
2225
|
+
var AGRO_VERSION = true ? "0.16.0" : "0.0.0-dev";
|
|
2226
2226
|
var OFFICIAL_IMAGE = "ghcr.io/mifunedev/agro";
|
|
2227
2227
|
var RELEASE_VERSION = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[a-z][a-z0-9]*\.[0-9]+)?$/;
|
|
2228
2228
|
function parseReleaseVersion(value) {
|
|
@@ -3129,7 +3129,7 @@ var HARNESS_CATALOG = [
|
|
|
3129
3129
|
installArgv: [
|
|
3130
3130
|
"bash",
|
|
3131
3131
|
"-lc",
|
|
3132
|
-
`curl -fsSL https://hermes-agent.nousresearch.com/install.sh | HERMES_INSTALL_DIR="${HARNESS_PREFIX_TOKEN}/lib/hermes-agent" bash -s -- --skip-setup --skip-browser &&
|
|
3132
|
+
`curl -fsSL https://hermes-agent.nousresearch.com/install.sh | HERMES_INSTALL_DIR="${HARNESS_PREFIX_TOKEN}/lib/hermes-agent" bash -s -- --skip-setup --skip-browser && "${HARNESS_PREFIX_TOKEN}/bin/hermes" pm install --extra slack --extra teams`
|
|
3133
3133
|
],
|
|
3134
3134
|
installUser: "sandbox",
|
|
3135
3135
|
verifyArgv: ["hermes", "--version"],
|
|
@@ -3732,9 +3732,9 @@ async function runLangfuseSetup(opts, io) {
|
|
|
3732
3732
|
}
|
|
3733
3733
|
|
|
3734
3734
|
// src/commands/sandbox.ts
|
|
3735
|
-
import { existsSync as
|
|
3735
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync3, statSync as statSync4 } from "node:fs";
|
|
3736
3736
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
3737
|
-
import { join as
|
|
3737
|
+
import { join as join12, resolve as resolve7 } from "node:path";
|
|
3738
3738
|
|
|
3739
3739
|
// src/lib/runtimes/catalog.ts
|
|
3740
3740
|
var RUNTIME_CATALOG = Object.freeze([
|
|
@@ -3763,6 +3763,76 @@ function runtimeIds() {
|
|
|
3763
3763
|
return RUNTIME_CATALOG.map((r) => r.id);
|
|
3764
3764
|
}
|
|
3765
3765
|
|
|
3766
|
+
// src/lib/star-prompt.ts
|
|
3767
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "node:fs";
|
|
3768
|
+
import { join as join11 } from "node:path";
|
|
3769
|
+
var STAR_PROMPT_LINE = "\u2B50 If AGRO helps, star https://github.com/mifunedev/agro";
|
|
3770
|
+
var MARKER = "star-prompt-shown";
|
|
3771
|
+
function maybePrintStarPrompt(io, env = process.env, isTTY = process.stdout.isTTY === true, stateHome = resolveUserStateHome(env)) {
|
|
3772
|
+
if (env.AGRO_NO_STAR_PROMPT === "1") return;
|
|
3773
|
+
if (env.CI !== void 0 && env.CI !== "") return;
|
|
3774
|
+
if (!isTTY) return;
|
|
3775
|
+
const marker = join11(stateHome, MARKER);
|
|
3776
|
+
if (existsSync15(marker)) return;
|
|
3777
|
+
io.stdout(`${STAR_PROMPT_LINE}
|
|
3778
|
+
`);
|
|
3779
|
+
try {
|
|
3780
|
+
mkdirSync7(stateHome, { recursive: true });
|
|
3781
|
+
writeFileSync8(marker, "");
|
|
3782
|
+
} catch {
|
|
3783
|
+
return;
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
|
|
3787
|
+
// src/commands/sandbox-list.ts
|
|
3788
|
+
async function entryStatus(root, name, run) {
|
|
3789
|
+
try {
|
|
3790
|
+
const target = resolveExecutionTarget({ projectRoot: root, container: name, run });
|
|
3791
|
+
return await target.status();
|
|
3792
|
+
} catch {
|
|
3793
|
+
return "unknown";
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
async function runSandboxList(opts, io) {
|
|
3797
|
+
const run = opts.run ?? spawnRunner;
|
|
3798
|
+
const rows = [];
|
|
3799
|
+
for (const name of listEntries()) {
|
|
3800
|
+
const root = entryRoot(name);
|
|
3801
|
+
const config = readAgroConfig(agroConfigPath(root));
|
|
3802
|
+
const checkout = configCheckout(config) ?? "-";
|
|
3803
|
+
rows.push({
|
|
3804
|
+
name,
|
|
3805
|
+
runtime: config.runtime ?? "docker",
|
|
3806
|
+
checkout,
|
|
3807
|
+
repo: checkout,
|
|
3808
|
+
status: await entryStatus(root, name, run)
|
|
3809
|
+
});
|
|
3810
|
+
}
|
|
3811
|
+
if (opts.json === true) {
|
|
3812
|
+
io.stdout(`${JSON.stringify(rows, null, 2)}
|
|
3813
|
+
`);
|
|
3814
|
+
return 0;
|
|
3815
|
+
}
|
|
3816
|
+
if (rows.length === 0) {
|
|
3817
|
+
io.stdout(
|
|
3818
|
+
`no sandbox is registered in ${registryRoot()} \u2014 create one with \`${opts.bin} sandbox install docker\`
|
|
3819
|
+
`
|
|
3820
|
+
);
|
|
3821
|
+
return 0;
|
|
3822
|
+
}
|
|
3823
|
+
const width = (pick) => Math.max(...rows.map((row) => pick(row).length));
|
|
3824
|
+
const nameWidth = width((row) => row.name);
|
|
3825
|
+
const runtimeWidth = width((row) => row.runtime);
|
|
3826
|
+
const statusWidth = width((row) => row.status);
|
|
3827
|
+
for (const row of rows) {
|
|
3828
|
+
io.stdout(
|
|
3829
|
+
`${row.name.padEnd(nameWidth)} ${row.runtime.padEnd(runtimeWidth)} ${row.status.padEnd(statusWidth)} ${row.checkout}
|
|
3830
|
+
`
|
|
3831
|
+
);
|
|
3832
|
+
}
|
|
3833
|
+
return 0;
|
|
3834
|
+
}
|
|
3835
|
+
|
|
3766
3836
|
// src/commands/sandbox.ts
|
|
3767
3837
|
function hostTimezone() {
|
|
3768
3838
|
const tz = process.env.TZ;
|
|
@@ -3779,27 +3849,27 @@ function gitIdentity(run, key) {
|
|
|
3779
3849
|
return (result.stdout ?? "").trim();
|
|
3780
3850
|
}
|
|
3781
3851
|
function isBuildCapable(repo) {
|
|
3782
|
-
return repo !== void 0 &&
|
|
3852
|
+
return repo !== void 0 && existsSync16(join12(repo, ".devcontainer", "Dockerfile"));
|
|
3783
3853
|
}
|
|
3784
3854
|
function prepareHomeMount(value) {
|
|
3785
3855
|
const path4 = resolve7(value);
|
|
3786
|
-
if (
|
|
3856
|
+
if (existsSync16(path4)) {
|
|
3787
3857
|
if (!statSync4(path4).isDirectory()) {
|
|
3788
3858
|
throw new Error(`--home-mount path exists and is not a directory: ${path4}`);
|
|
3789
3859
|
}
|
|
3790
3860
|
return path4;
|
|
3791
3861
|
}
|
|
3792
|
-
|
|
3862
|
+
mkdirSync8(path4, { recursive: true });
|
|
3793
3863
|
return path4;
|
|
3794
3864
|
}
|
|
3795
3865
|
function readSeedConfig(repo) {
|
|
3796
3866
|
if (repo === void 0) return void 0;
|
|
3797
3867
|
const file = agroConfigPath(repo);
|
|
3798
|
-
return
|
|
3868
|
+
return existsSync16(file) ? readAgroConfig(file) : void 0;
|
|
3799
3869
|
}
|
|
3800
3870
|
function readEntryConfig(name) {
|
|
3801
3871
|
const file = agroConfigPath(entryRoot(name));
|
|
3802
|
-
return
|
|
3872
|
+
return existsSync16(file) ? readAgroConfig(file) : void 0;
|
|
3803
3873
|
}
|
|
3804
3874
|
function assignSetting(target, path4, value) {
|
|
3805
3875
|
const segments = path4.split(".");
|
|
@@ -3896,7 +3966,7 @@ async function runSandboxInstall(opts, io) {
|
|
|
3896
3966
|
return 1;
|
|
3897
3967
|
}
|
|
3898
3968
|
const checkout = opts.checkout === void 0 ? void 0 : resolve7(opts.checkout);
|
|
3899
|
-
if (checkout !== void 0 && !
|
|
3969
|
+
if (checkout !== void 0 && !existsSync16(checkout)) {
|
|
3900
3970
|
io.stderr(`${opts.bin} sandbox install: --checkout directory does not exist: ${checkout}
|
|
3901
3971
|
`);
|
|
3902
3972
|
return 1;
|
|
@@ -3915,7 +3985,7 @@ async function runSandboxInstall(opts, io) {
|
|
|
3915
3985
|
if (buildRequested && !isBuildCapable(configCheckout(config))) {
|
|
3916
3986
|
const target = configCheckout(config) ?? resolve7(opts.checkout ?? ".");
|
|
3917
3987
|
io.stderr(
|
|
3918
|
-
`${opts.bin} sandbox install: image.mode is "build" but ${
|
|
3988
|
+
`${opts.bin} sandbox install: image.mode is "build" but ${join12(target, ".devcontainer", "Dockerfile")} does not exist \u2014 point --checkout <dir> at a harness checkout that has .devcontainer/Dockerfile, or set image.mode to "image" to run the prebuilt image
|
|
3919
3989
|
`
|
|
3920
3990
|
);
|
|
3921
3991
|
return 1;
|
|
@@ -3959,7 +4029,7 @@ async function runSandboxInstall(opts, io) {
|
|
|
3959
4029
|
...useNoBuild ? { noBuild: true } : {}
|
|
3960
4030
|
};
|
|
3961
4031
|
if (opts.printArgv === true) {
|
|
3962
|
-
const preview = mkdtempSync3(
|
|
4032
|
+
const preview = mkdtempSync3(join12(tmpdir3(), "oh-sandbox-preview-"));
|
|
3963
4033
|
try {
|
|
3964
4034
|
writeAgroConfig(preview, config);
|
|
3965
4035
|
materialize(preview, { ...configCheckout(config) !== void 0 ? { checkout: configCheckout(config) } : {} });
|
|
@@ -3969,66 +4039,395 @@ async function runSandboxInstall(opts, io) {
|
|
|
3969
4039
|
}
|
|
3970
4040
|
}
|
|
3971
4041
|
const root = entryRoot(config.name);
|
|
3972
|
-
|
|
4042
|
+
mkdirSync8(root, { recursive: true });
|
|
3973
4043
|
writeAgroConfig(root, config);
|
|
3974
4044
|
materialize(root, { ...configCheckout(config) !== void 0 ? { checkout: configCheckout(config) } : {} });
|
|
3975
4045
|
const code = await runSandbox({ ...sandboxOpts, cwd: root }, io);
|
|
3976
|
-
if (code === 0)
|
|
4046
|
+
if (code === 0) {
|
|
4047
|
+
io.stdout(`next: ${opts.bin} shell ${config.name}
|
|
3977
4048
|
`);
|
|
4049
|
+
maybePrintStarPrompt(io);
|
|
4050
|
+
}
|
|
3978
4051
|
return code;
|
|
3979
4052
|
}
|
|
3980
|
-
|
|
4053
|
+
|
|
4054
|
+
// src/services/sandbox-upgrade.ts
|
|
4055
|
+
import { closeSync as closeSync2, existsSync as existsSync17, openSync as openSync2, readFileSync as readFileSync11, unlinkSync as unlinkSync5, writeSync } from "node:fs";
|
|
4056
|
+
import { join as join13 } from "node:path";
|
|
4057
|
+
function errorMessage(error) {
|
|
4058
|
+
return error instanceof Error ? error.message : String(error);
|
|
4059
|
+
}
|
|
4060
|
+
function conflictingDotenvImage(root, imageRef) {
|
|
4061
|
+
const rootEnv = join13(root, ".env");
|
|
4062
|
+
const fallbackEnv = join13(root, ".devcontainer", ".env");
|
|
4063
|
+
const file = existsSync17(rootEnv) ? rootEnv : fallbackEnv;
|
|
4064
|
+
if (!existsSync17(file)) return void 0;
|
|
4065
|
+
for (const line of readFileSync11(file, "utf8").split(/\r?\n/)) {
|
|
4066
|
+
const match = /^AGRO_SANDBOX_IMAGE=(.*)$/.exec(line);
|
|
4067
|
+
if (!match) continue;
|
|
4068
|
+
const value = match[1].trim().replace(/^(?:"(.*)"|'(.*)')$/, (_whole, double, single) => double ?? single ?? "");
|
|
4069
|
+
if (value !== imageRef) return file;
|
|
4070
|
+
}
|
|
4071
|
+
return void 0;
|
|
4072
|
+
}
|
|
4073
|
+
async function runSandboxUpgrade(opts, io) {
|
|
4074
|
+
const prefix = `${opts.bin} sandbox upgrade:`;
|
|
4075
|
+
const version = parseReleaseVersion(opts.version);
|
|
4076
|
+
if (version === void 0) {
|
|
4077
|
+
io.stderr(`${prefix} invalid release version "${opts.version}"
|
|
4078
|
+
`);
|
|
4079
|
+
return 1;
|
|
4080
|
+
}
|
|
4081
|
+
if (runningInsideSandbox()) {
|
|
4082
|
+
io.stderr(`${prefix} host-only \u2014 run this command on the host
|
|
4083
|
+
`);
|
|
4084
|
+
return 1;
|
|
4085
|
+
}
|
|
4086
|
+
let root;
|
|
3981
4087
|
try {
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
4088
|
+
root = entryRoot(opts.name);
|
|
4089
|
+
} catch (error) {
|
|
4090
|
+
io.stderr(`${prefix} ${errorMessage(error)}
|
|
4091
|
+
`);
|
|
4092
|
+
return 1;
|
|
4093
|
+
}
|
|
4094
|
+
const configFile = agroConfigPath(root);
|
|
4095
|
+
if (!existsSync17(configFile)) {
|
|
4096
|
+
io.stderr(`${prefix} no sandbox entry named "${opts.name}"
|
|
4097
|
+
`);
|
|
4098
|
+
return 1;
|
|
4099
|
+
}
|
|
4100
|
+
const lock = join13(root, ".sandbox-upgrade.lock");
|
|
4101
|
+
let fd;
|
|
4102
|
+
try {
|
|
4103
|
+
fd = openSync2(lock, "wx", 384);
|
|
4104
|
+
} catch (error) {
|
|
4105
|
+
const message = error instanceof Error && "code" in error && error.code === "EEXIST" ? `upgrade already in progress for ${opts.name}; lock: ${lock}. Confirm no upgrade process owns this entry before removing that lock and retrying` : errorMessage(error);
|
|
4106
|
+
io.stderr(`${prefix} ${message}
|
|
4107
|
+
`);
|
|
4108
|
+
return 1;
|
|
4109
|
+
}
|
|
4110
|
+
try {
|
|
4111
|
+
writeSync(fd, `${process.pid}
|
|
4112
|
+
`);
|
|
4113
|
+
const config = readAgroConfig(configFile);
|
|
4114
|
+
if (config.image?.mode !== "image") {
|
|
4115
|
+
io.stderr(`${prefix} ${opts.name} requires image.mode "image"
|
|
4116
|
+
`);
|
|
4117
|
+
return 1;
|
|
4118
|
+
}
|
|
4119
|
+
const imageRef = officialImageRef(version);
|
|
4120
|
+
if (process.env.AGRO_SANDBOX_IMAGE !== void 0 && process.env.AGRO_SANDBOX_IMAGE !== "" && process.env.AGRO_SANDBOX_IMAGE !== imageRef) {
|
|
4121
|
+
io.stderr(`${prefix} conflicting AGRO_SANDBOX_IMAGE in the host environment
|
|
4122
|
+
`);
|
|
4123
|
+
return 1;
|
|
4124
|
+
}
|
|
4125
|
+
const dotenv = conflictingDotenvImage(root, imageRef);
|
|
4126
|
+
if (dotenv !== void 0) {
|
|
4127
|
+
io.stderr(`${prefix} conflicting AGRO_SANDBOX_IMAGE in ${dotenv}
|
|
4128
|
+
`);
|
|
4129
|
+
return 1;
|
|
4130
|
+
}
|
|
4131
|
+
const run = opts.run ?? spawnRunner;
|
|
4132
|
+
let priorRef = config.image.ref;
|
|
4133
|
+
if (!priorRef) {
|
|
4134
|
+
const name = configuredContainerName(root) ?? DEFAULT_CONTAINER_NAME;
|
|
4135
|
+
const inspected = run("docker", ["inspect", "-f", "{{.Config.Image}}", name], { stdio: "capture" });
|
|
4136
|
+
priorRef = inspected.status === 0 && !inspected.error ? inspected.stdout?.trim() : void 0;
|
|
4137
|
+
if (!priorRef) {
|
|
4138
|
+
io.stderr(`${prefix} cannot determine previous image for ${name}; no changes made
|
|
4139
|
+
`);
|
|
4140
|
+
return 1;
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
const apply = (ref) => runSandbox({ bin: opts.bin, cwd: root, imageRef: ref, run }, io);
|
|
4144
|
+
let failure;
|
|
4145
|
+
try {
|
|
4146
|
+
const code = await apply(imageRef);
|
|
4147
|
+
if (code !== 0) failure = `exit ${code}`;
|
|
4148
|
+
} catch (error) {
|
|
4149
|
+
failure = errorMessage(error);
|
|
4150
|
+
}
|
|
4151
|
+
if (failure === void 0) {
|
|
4152
|
+
try {
|
|
4153
|
+
(opts.writeConfig ?? writeAgroConfig)(root, { ...config, image: { ...config.image, ref: imageRef } });
|
|
4154
|
+
return 0;
|
|
4155
|
+
} catch (error) {
|
|
4156
|
+
failure = `config persistence failed (${errorMessage(error)})`;
|
|
4157
|
+
}
|
|
4158
|
+
} else {
|
|
4159
|
+
failure = `provisioning failed (${failure})`;
|
|
4160
|
+
}
|
|
4161
|
+
io.stderr(`${prefix} ${failure}; restoring previous image
|
|
4162
|
+
`);
|
|
4163
|
+
try {
|
|
4164
|
+
const code = await apply(priorRef);
|
|
4165
|
+
if (code !== 0) io.stderr(`${prefix} restoration failed (exit ${code})
|
|
4166
|
+
`);
|
|
4167
|
+
} catch (error) {
|
|
4168
|
+
io.stderr(`${prefix} restoration failed (${errorMessage(error)})
|
|
4169
|
+
`);
|
|
4170
|
+
}
|
|
4171
|
+
return 1;
|
|
4172
|
+
} catch (error) {
|
|
4173
|
+
io.stderr(`${prefix} ${errorMessage(error)}
|
|
4174
|
+
`);
|
|
4175
|
+
return 1;
|
|
4176
|
+
} finally {
|
|
4177
|
+
closeSync2(fd);
|
|
4178
|
+
unlinkSync5(lock);
|
|
3986
4179
|
}
|
|
3987
4180
|
}
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4181
|
+
|
|
4182
|
+
// src/controllers/sandbox.ts
|
|
4183
|
+
function isHelpFlag(arg) {
|
|
4184
|
+
return arg === "--help" || arg === "-h" || arg === "help";
|
|
4185
|
+
}
|
|
4186
|
+
function runtimeLines() {
|
|
4187
|
+
const width = Math.max(...RUNTIME_CATALOG.map((r) => r.id.length));
|
|
4188
|
+
return RUNTIME_CATALOG.map(
|
|
4189
|
+
(r) => ` ${r.id.padEnd(width)} ${r.provisionable ? "provisionable" : "planned"}`
|
|
4190
|
+
).join("\n");
|
|
4191
|
+
}
|
|
4192
|
+
function printSandboxHelp(bin = AGRO_PRODUCT.bin) {
|
|
4193
|
+
process.stdout.write(`${bin} sandbox \u2014 Create and list sandboxes
|
|
4194
|
+
|
|
4195
|
+
Usage:
|
|
4196
|
+
${bin} sandbox install <runtime> [--name <name>] [--checkout <dir>]
|
|
4197
|
+
[--home-mount <dir>] [--yes]
|
|
4198
|
+
[--version <X.Y.Z> | --image[=<ref>]]
|
|
4199
|
+
[--no-build] [--print-argv]
|
|
4200
|
+
${bin} sandbox list [--json]
|
|
4201
|
+
${bin} sandbox upgrade <name> --version <X.Y.Z>
|
|
4202
|
+
|
|
4203
|
+
\`install\` writes a sandbox entry under \${${stateNames(bin).envPrefix}HOME:-~/${stateNames(bin).userStateDir}}/sandboxes/<name>/,
|
|
4204
|
+
materialises the compose files and the compose wrapper into it, then starts the
|
|
4205
|
+
container. It needs no project checkout and runs from any directory. Without
|
|
4206
|
+
--checkout the sandbox runs the prebuilt image; with --checkout <dir> that
|
|
4207
|
+
checkout is bound at /home/sandbox/harness; the sandbox builds locally only
|
|
4208
|
+
when that directory holds .devcontainer/Dockerfile.
|
|
4209
|
+
|
|
4210
|
+
On a terminal without --yes it asks for the sandbox name, the timezone, the git
|
|
4211
|
+
identity, SSH (with its host port), the host Docker socket, and the host path
|
|
4212
|
+
for /home/sandbox. With --checkout it seeds those answers from that
|
|
4213
|
+
checkout's ${stateNames(bin).configFile}.
|
|
4214
|
+
|
|
4215
|
+
Flags:
|
|
4216
|
+
--name <name> Registry entry name (default: the lowest free ${DEFAULT_NAME_PREFIX}<n>)
|
|
4217
|
+
--checkout <dir> Bind this checkout into the sandbox and seed the defaults
|
|
4218
|
+
from its ${stateNames(bin).configFile}. The sandbox builds
|
|
4219
|
+
locally only when that directory holds
|
|
4220
|
+
.devcontainer/Dockerfile
|
|
4221
|
+
--repo <dir> Deprecated alias for --checkout
|
|
4222
|
+
--home-mount <dir>
|
|
4223
|
+
Bind this host directory at /home/sandbox instead of the
|
|
4224
|
+
Docker-managed volume. Relative paths resolve against the
|
|
4225
|
+
working directory. The directory is created when absent
|
|
4226
|
+
--yes Non-interactive: keep every default and ask nothing
|
|
4227
|
+
--version <X.Y.Z>
|
|
4228
|
+
Run the official release image ghcr.io/mifunedev/agro:<X.Y.Z>
|
|
4229
|
+
(implies --image). A leading v and a -<channel>.<n>
|
|
4230
|
+
pre-release suffix are accepted
|
|
4231
|
+
--image Run the prebuilt image instead of building (implies
|
|
4232
|
+
--no-build). The ref resolves first-match: --version or
|
|
4233
|
+
--image=<ref> > ${stateNames(bin).envPrefix}SANDBOX_IMAGE >
|
|
4234
|
+
${stateNames(bin).configFile} image.ref > ${officialImageRef(AGRO_VERSION)}
|
|
4235
|
+
--image=<ref> Run a custom image (implies --image); conflicts with --version
|
|
4236
|
+
--no-build Suppress the local build and reuse an existing image
|
|
4237
|
+
--print-argv Print the docker compose argv that would run, then exit
|
|
4238
|
+
without writing an entry
|
|
4239
|
+
--json Machine-readable output (list)
|
|
4240
|
+
|
|
4241
|
+
Runtimes:
|
|
4242
|
+
${runtimeLines()}
|
|
4243
|
+
|
|
4244
|
+
Next: ${bin} shell <name>
|
|
4245
|
+
`);
|
|
4246
|
+
}
|
|
4247
|
+
var SANDBOX_VALUE_FLAGS = {
|
|
4248
|
+
"--name": "name",
|
|
4249
|
+
"--checkout": "checkout",
|
|
4250
|
+
"--repo": "checkout",
|
|
4251
|
+
"--home-mount": "homeMount"
|
|
4252
|
+
};
|
|
4253
|
+
function parseSandboxArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
4254
|
+
const args = {
|
|
4255
|
+
help: false,
|
|
4256
|
+
yes: false,
|
|
4257
|
+
image: false,
|
|
4258
|
+
noBuild: false,
|
|
4259
|
+
printArgv: false,
|
|
4260
|
+
json: false
|
|
4261
|
+
};
|
|
4262
|
+
if (rest.length === 0 || isHelpFlag(rest[0])) {
|
|
4263
|
+
return { ok: true, args: { ...args, help: true } };
|
|
4002
4264
|
}
|
|
4003
|
-
|
|
4004
|
-
|
|
4265
|
+
const [head, ...tail] = rest;
|
|
4266
|
+
if (head === "upgrade") {
|
|
4267
|
+
if (tail.length === 1 && isHelpFlag(tail[0])) {
|
|
4268
|
+
return { ok: true, args: { ...args, subcommand: "upgrade", help: true } };
|
|
4269
|
+
}
|
|
4270
|
+
const [name, flag, value, ...extra] = tail;
|
|
4271
|
+
if (name === void 0 || name === "" || name.startsWith("-")) {
|
|
4272
|
+
return { ok: false, error: `${bin} sandbox upgrade: a name is required` };
|
|
4273
|
+
}
|
|
4274
|
+
if (flag === void 0) {
|
|
4275
|
+
return { ok: false, error: `${bin} sandbox upgrade: --version is required` };
|
|
4276
|
+
}
|
|
4277
|
+
if (flag !== "--version") {
|
|
4278
|
+
return { ok: false, error: `${bin} sandbox upgrade: ${flag.startsWith("-") ? "unknown flag" : "unexpected argument"} "${flag}"` };
|
|
4279
|
+
}
|
|
4280
|
+
if (value === void 0 || value === "") {
|
|
4281
|
+
return { ok: false, error: `${bin} sandbox upgrade: --version requires a value` };
|
|
4282
|
+
}
|
|
4283
|
+
if (value.startsWith("-")) {
|
|
4284
|
+
return { ok: false, error: `${bin} sandbox upgrade: unknown flag "${value}"` };
|
|
4285
|
+
}
|
|
4286
|
+
const version2 = parseReleaseVersion(value);
|
|
4287
|
+
if (version2 === void 0) {
|
|
4288
|
+
return { ok: false, error: `${bin} sandbox upgrade: --version "${value}" is not a release version \u2014 expected X.Y.Z` };
|
|
4289
|
+
}
|
|
4290
|
+
if (extra.length > 0) {
|
|
4291
|
+
const token = extra[0];
|
|
4292
|
+
return { ok: false, error: `${bin} sandbox upgrade: ${token.startsWith("-") && token !== "--version" ? "unknown flag" : "unexpected argument"} "${token}"` };
|
|
4293
|
+
}
|
|
4294
|
+
return { ok: true, args: { ...args, subcommand: "upgrade", name, version: version2 } };
|
|
4295
|
+
}
|
|
4296
|
+
if (head !== "install" && head !== "list") {
|
|
4297
|
+
return {
|
|
4298
|
+
ok: false,
|
|
4299
|
+
error: `${bin} sandbox: unknown subcommand "${head}" \u2014 expected install or list`,
|
|
4300
|
+
showHelp: true
|
|
4301
|
+
};
|
|
4302
|
+
}
|
|
4303
|
+
args.subcommand = head;
|
|
4304
|
+
if (isHelpFlag(tail[0])) return { ok: true, args: { ...args, help: true } };
|
|
4305
|
+
const positionals = [];
|
|
4306
|
+
const checkoutSpellings = /* @__PURE__ */ new Set();
|
|
4307
|
+
let version;
|
|
4308
|
+
for (let i = 0; i < tail.length; i++) {
|
|
4309
|
+
const token = tail[i];
|
|
4310
|
+
const valueFlag = SANDBOX_VALUE_FLAGS[token];
|
|
4311
|
+
if (valueFlag !== void 0) {
|
|
4312
|
+
const value = tail[i + 1];
|
|
4313
|
+
if (value === void 0) {
|
|
4314
|
+
return { ok: false, error: `${bin} sandbox ${head}: ${token} requires a value` };
|
|
4315
|
+
}
|
|
4316
|
+
if (valueFlag === "checkout") checkoutSpellings.add(token);
|
|
4317
|
+
args[valueFlag] = value;
|
|
4318
|
+
i++;
|
|
4319
|
+
} else if (token === "--yes") {
|
|
4320
|
+
args.yes = true;
|
|
4321
|
+
} else if (token === "--no-build") {
|
|
4322
|
+
args.noBuild = true;
|
|
4323
|
+
} else if (token === "--print-argv") {
|
|
4324
|
+
args.printArgv = true;
|
|
4325
|
+
} else if (token === "--image") {
|
|
4326
|
+
args.image = true;
|
|
4327
|
+
} else if (token.startsWith("--image=")) {
|
|
4328
|
+
const ref = token.slice("--image=".length);
|
|
4329
|
+
if (ref === "") {
|
|
4330
|
+
return { ok: false, error: `${bin} sandbox: --image=<ref> requires a non-empty image ref` };
|
|
4331
|
+
}
|
|
4332
|
+
args.image = true;
|
|
4333
|
+
args.imageRef = ref;
|
|
4334
|
+
} else if (token === "--version" || token.startsWith("--version=")) {
|
|
4335
|
+
const value = token === "--version" ? tail[++i] : token.slice("--version=".length);
|
|
4336
|
+
if (value === void 0 || value === "") {
|
|
4337
|
+
return { ok: false, error: `${bin} sandbox ${head}: --version requires a value` };
|
|
4338
|
+
}
|
|
4339
|
+
version = parseReleaseVersion(value);
|
|
4340
|
+
if (version === void 0) {
|
|
4341
|
+
return {
|
|
4342
|
+
ok: false,
|
|
4343
|
+
error: `${bin} sandbox ${head}: --version "${value}" is not a release version \u2014 expected X.Y.Z`
|
|
4344
|
+
};
|
|
4345
|
+
}
|
|
4346
|
+
} else if (token === "--json") {
|
|
4347
|
+
args.json = true;
|
|
4348
|
+
} else if (token.startsWith("-")) {
|
|
4349
|
+
return { ok: false, error: `${bin} sandbox ${head}: unknown flag "${token}"` };
|
|
4350
|
+
} else {
|
|
4351
|
+
positionals.push(token);
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4354
|
+
if (checkoutSpellings.has("--checkout") && checkoutSpellings.has("--repo")) {
|
|
4355
|
+
return {
|
|
4356
|
+
ok: false,
|
|
4357
|
+
error: `${bin} sandbox ${head}: --checkout conflicts with --repo \u2014 pass exactly one, and prefer --checkout`
|
|
4358
|
+
};
|
|
4359
|
+
}
|
|
4360
|
+
if (version !== void 0) {
|
|
4361
|
+
if (args.imageRef !== void 0) {
|
|
4362
|
+
return {
|
|
4363
|
+
ok: false,
|
|
4364
|
+
error: `${bin} sandbox ${head}: --version conflicts with --image=<ref> \u2014 pass --version for an official release or --image=<ref> for a custom image`
|
|
4365
|
+
};
|
|
4366
|
+
}
|
|
4367
|
+
args.image = true;
|
|
4368
|
+
args.imageRef = officialImageRef(version);
|
|
4369
|
+
}
|
|
4370
|
+
if (head === "list") {
|
|
4371
|
+
if (positionals.length > 0) {
|
|
4372
|
+
return { ok: false, error: `${bin} sandbox list: unexpected argument "${positionals[0]}"` };
|
|
4373
|
+
}
|
|
4374
|
+
return { ok: true, args };
|
|
4375
|
+
}
|
|
4376
|
+
if (positionals.length === 0) {
|
|
4377
|
+
return {
|
|
4378
|
+
ok: false,
|
|
4379
|
+
error: `${bin} sandbox install: a runtime is required, e.g. \`${bin} sandbox install docker\``,
|
|
4380
|
+
showHelp: true
|
|
4381
|
+
};
|
|
4382
|
+
}
|
|
4383
|
+
if (positionals.length > 1) {
|
|
4384
|
+
return { ok: false, error: `${bin} sandbox install: unexpected argument "${positionals[1]}"` };
|
|
4385
|
+
}
|
|
4386
|
+
args.runtime = positionals[0];
|
|
4387
|
+
return { ok: true, args };
|
|
4388
|
+
}
|
|
4389
|
+
async function runSandboxCommand(rest, bin) {
|
|
4390
|
+
const parsed = parseSandboxArgs(rest, bin);
|
|
4391
|
+
if (!parsed.ok) {
|
|
4392
|
+
process.stderr.write(`${parsed.error}
|
|
4005
4393
|
`);
|
|
4006
|
-
|
|
4394
|
+
if (parsed.showHelp) printSandboxHelp(bin);
|
|
4395
|
+
return 1;
|
|
4007
4396
|
}
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
);
|
|
4013
|
-
return 0;
|
|
4397
|
+
const a = parsed.args;
|
|
4398
|
+
if (a.help) {
|
|
4399
|
+
printSandboxHelp(bin);
|
|
4400
|
+
return a.subcommand === void 0 ? 1 : 0;
|
|
4014
4401
|
}
|
|
4015
|
-
const
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
`
|
|
4023
|
-
);
|
|
4402
|
+
const io = {
|
|
4403
|
+
stdout: (s) => process.stdout.write(s),
|
|
4404
|
+
stderr: (s) => process.stderr.write(s)
|
|
4405
|
+
};
|
|
4406
|
+
if (a.subcommand === "list") return await runSandboxList({ bin, json: a.json }, io);
|
|
4407
|
+
if (a.subcommand === "upgrade") {
|
|
4408
|
+
return await runSandboxUpgrade({ bin, name: a.name, version: a.version }, io);
|
|
4024
4409
|
}
|
|
4025
|
-
return
|
|
4410
|
+
return await runSandboxInstall(
|
|
4411
|
+
{
|
|
4412
|
+
bin,
|
|
4413
|
+
runtime: a.runtime,
|
|
4414
|
+
...a.name !== void 0 ? { name: a.name } : {},
|
|
4415
|
+
...a.checkout !== void 0 ? { checkout: a.checkout } : {},
|
|
4416
|
+
...a.homeMount !== void 0 ? { homeMount: a.homeMount } : {},
|
|
4417
|
+
yes: a.yes,
|
|
4418
|
+
image: a.image,
|
|
4419
|
+
...a.imageRef !== void 0 ? { imageRef: a.imageRef } : {},
|
|
4420
|
+
noBuild: a.noBuild,
|
|
4421
|
+
printArgv: a.printArgv
|
|
4422
|
+
},
|
|
4423
|
+
io
|
|
4424
|
+
);
|
|
4026
4425
|
}
|
|
4027
4426
|
|
|
4028
4427
|
// src/commands/harness.ts
|
|
4029
|
-
import { existsSync as
|
|
4428
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
4030
4429
|
import { homedir as homedir3 } from "node:os";
|
|
4031
|
-
import { delimiter as delimiter2, join as
|
|
4430
|
+
import { delimiter as delimiter2, join as join16 } from "node:path";
|
|
4032
4431
|
|
|
4033
4432
|
// src/lib/docs.ts
|
|
4034
4433
|
var SOURCE_DOCS_BASE = "https://github.com/mifunedev/agro/blob/main/";
|
|
@@ -4041,17 +4440,20 @@ function sourceDocsUrl(docsPath) {
|
|
|
4041
4440
|
}
|
|
4042
4441
|
|
|
4043
4442
|
// src/lib/host-config.ts
|
|
4044
|
-
import { existsSync as
|
|
4045
|
-
import { basename as basename5, dirname as dirname8, isAbsolute, join as
|
|
4443
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync12, renameSync as renameSync4, unlinkSync as unlinkSync6, writeFileSync as writeFileSync9 } from "node:fs";
|
|
4444
|
+
import { basename as basename5, dirname as dirname8, isAbsolute, join as join14, resolve as resolve8 } from "node:path";
|
|
4046
4445
|
var HOST_CONFIG_MODE = 420;
|
|
4047
4446
|
var HOST_CONFIG_FILE = "config.json";
|
|
4048
4447
|
var WORKSPACES_SUBDIR = "workspaces";
|
|
4049
|
-
var DEFAULT_WORKSPACE_NAME = "
|
|
4448
|
+
var DEFAULT_WORKSPACE_NAME = "harness";
|
|
4449
|
+
function isRootToolReceipt(receipt) {
|
|
4450
|
+
return receipt.scope === "root";
|
|
4451
|
+
}
|
|
4050
4452
|
function hostStateHome(env, home) {
|
|
4051
4453
|
return resolveUserStateHome(env, home);
|
|
4052
4454
|
}
|
|
4053
4455
|
function hostConfigPath(env, home) {
|
|
4054
|
-
return
|
|
4456
|
+
return join14(hostStateHome(env, home), HOST_CONFIG_FILE);
|
|
4055
4457
|
}
|
|
4056
4458
|
function assertWorkspaceName(name) {
|
|
4057
4459
|
if (!SANDBOX_NAME_PATTERN.test(name)) {
|
|
@@ -4061,14 +4463,14 @@ function assertWorkspaceName(name) {
|
|
|
4061
4463
|
}
|
|
4062
4464
|
}
|
|
4063
4465
|
function workspacesRoot(env, home) {
|
|
4064
|
-
return
|
|
4466
|
+
return join14(hostStateHome(env, home), WORKSPACES_SUBDIR);
|
|
4065
4467
|
}
|
|
4066
4468
|
function workspaceRoot(name, env, home) {
|
|
4067
4469
|
assertWorkspaceName(name);
|
|
4068
|
-
return
|
|
4470
|
+
return join14(workspacesRoot(env, home), name);
|
|
4069
4471
|
}
|
|
4070
4472
|
function defaultHarnessRoot(env, home) {
|
|
4071
|
-
return
|
|
4473
|
+
return join14(workspacesRoot(env, home), DEFAULT_WORKSPACE_NAME);
|
|
4072
4474
|
}
|
|
4073
4475
|
function validateHostConfig(value) {
|
|
4074
4476
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -4090,7 +4492,7 @@ function validateHostConfig(value) {
|
|
|
4090
4492
|
const hostHarnesses = record.hostHarnesses;
|
|
4091
4493
|
if (hostHarnesses !== void 0) validateReceipts(hostHarnesses, "hostHarnesses", "harness");
|
|
4092
4494
|
const hostTools = record.hostTools;
|
|
4093
|
-
if (hostTools !== void 0) validateReceipts(hostTools, "hostTools", "tool");
|
|
4495
|
+
if (hostTools !== void 0) validateReceipts(hostTools, "hostTools", "tool", true);
|
|
4094
4496
|
return { ...record, version: 1 };
|
|
4095
4497
|
}
|
|
4096
4498
|
function absoluteField(value, path4) {
|
|
@@ -4100,7 +4502,7 @@ function absoluteField(value, path4) {
|
|
|
4100
4502
|
if (!isAbsolute(value)) throw fieldError2(path4, "must be an absolute path");
|
|
4101
4503
|
return value;
|
|
4102
4504
|
}
|
|
4103
|
-
function validateReceipts(value, field, noun) {
|
|
4505
|
+
function validateReceipts(value, field, noun, allowRootScope = false) {
|
|
4104
4506
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
4105
4507
|
throw fieldError2(field, `must be a JSON object keyed by ${noun} id`);
|
|
4106
4508
|
}
|
|
@@ -4111,8 +4513,15 @@ function validateReceipts(value, field, noun) {
|
|
|
4111
4513
|
throw fieldError2(at, "must be a JSON object");
|
|
4112
4514
|
}
|
|
4113
4515
|
const entry = receipt;
|
|
4114
|
-
|
|
4115
|
-
|
|
4516
|
+
if (allowRootScope && entry.scope !== void 0) {
|
|
4517
|
+
if (entry.scope !== "root") throw fieldError2(`${at}.scope`, 'must be "root" when present');
|
|
4518
|
+
for (const key of ["prefix", "binPath"]) {
|
|
4519
|
+
if (entry[key] !== void 0) throw fieldError2(`${at}.${key}`, 'must be absent when scope is "root"');
|
|
4520
|
+
}
|
|
4521
|
+
} else {
|
|
4522
|
+
absoluteField(entry.prefix, `${at}.prefix`);
|
|
4523
|
+
absoluteField(entry.binPath, `${at}.binPath`);
|
|
4524
|
+
}
|
|
4116
4525
|
if (typeof entry.binary !== "string" || entry.binary === "") {
|
|
4117
4526
|
throw fieldError2(`${at}.binary`, "must be a non-empty string");
|
|
4118
4527
|
}
|
|
@@ -4126,10 +4535,10 @@ function validateReceipts(value, field, noun) {
|
|
|
4126
4535
|
}
|
|
4127
4536
|
function readHostConfig(env, home) {
|
|
4128
4537
|
const path4 = hostConfigPath(env, home);
|
|
4129
|
-
if (!
|
|
4538
|
+
if (!existsSync18(path4)) return { version: 1 };
|
|
4130
4539
|
let raw;
|
|
4131
4540
|
try {
|
|
4132
|
-
raw =
|
|
4541
|
+
raw = readFileSync12(path4, "utf8");
|
|
4133
4542
|
} catch (error) {
|
|
4134
4543
|
const detail = error instanceof Error ? error.message : String(error);
|
|
4135
4544
|
throw new Error(`could not read ${path4}: ${detail}`);
|
|
@@ -4148,13 +4557,13 @@ function writeHostConfig(config, env, home) {
|
|
|
4148
4557
|
const body = `${JSON.stringify(validated, null, 2)}
|
|
4149
4558
|
`;
|
|
4150
4559
|
const tmp = `${path4}.tmp.${process.pid}`;
|
|
4151
|
-
|
|
4560
|
+
mkdirSync9(dirname8(path4), { recursive: true });
|
|
4152
4561
|
try {
|
|
4153
|
-
|
|
4562
|
+
writeFileSync9(tmp, body, { mode: HOST_CONFIG_MODE, encoding: "utf8" });
|
|
4154
4563
|
renameSync4(tmp, path4);
|
|
4155
4564
|
} catch (error) {
|
|
4156
4565
|
try {
|
|
4157
|
-
|
|
4566
|
+
unlinkSync6(tmp);
|
|
4158
4567
|
} catch {
|
|
4159
4568
|
}
|
|
4160
4569
|
throw error;
|
|
@@ -4177,8 +4586,8 @@ function fieldError2(path4, requirement) {
|
|
|
4177
4586
|
}
|
|
4178
4587
|
|
|
4179
4588
|
// src/lib/host-workspace.ts
|
|
4180
|
-
import { existsSync as
|
|
4181
|
-
import { dirname as dirname9, join as
|
|
4589
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, readdirSync as readdirSync3, renameSync as renameSync5, rmSync as rmSync4, statSync as statSync5 } from "node:fs";
|
|
4590
|
+
import { dirname as dirname9, join as join15, resolve as resolve9 } from "node:path";
|
|
4182
4591
|
var AGRO_REPO_URL = "https://github.com/mifunedev/agro.git";
|
|
4183
4592
|
var IGNORABLE_ENTRIES = [
|
|
4184
4593
|
REGISTRY_SUBDIR,
|
|
@@ -4190,7 +4599,7 @@ function isDirectory3(path4) {
|
|
|
4190
4599
|
return statSync5(path4, { throwIfNoEntry: false })?.isDirectory() === true;
|
|
4191
4600
|
}
|
|
4192
4601
|
function stateHomes(home) {
|
|
4193
|
-
return STATE_HOME_DIRS.map((name) =>
|
|
4602
|
+
return STATE_HOME_DIRS.map((name) => join15(home, name));
|
|
4194
4603
|
}
|
|
4195
4604
|
function stateHomeRootRefusal(bin, root, home, verb = "harness") {
|
|
4196
4605
|
const target = resolve9(root);
|
|
@@ -4198,7 +4607,7 @@ function stateHomeRootRefusal(bin, root, home, verb = "harness") {
|
|
|
4198
4607
|
if (enclosing === void 0) return void 0;
|
|
4199
4608
|
return `${bin} ${verb}: the ${verb} root ${target} is the state home ${enclosing} itself.
|
|
4200
4609
|
A workspace there collides with AGRO state and blocks every command run from ${home}.
|
|
4201
|
-
Move it out \u2014 for example \`mv ${enclosing} ${
|
|
4610
|
+
Move it out \u2014 for example \`mv ${enclosing} ${join15(home, "agro")}\` \u2014 then re-run this command.
|
|
4202
4611
|
`;
|
|
4203
4612
|
}
|
|
4204
4613
|
function isIgnorableEntry(name) {
|
|
@@ -4215,16 +4624,16 @@ function cloneInto(target, run, root, ref) {
|
|
|
4215
4624
|
assertCloned(run("git", ["clone", ...branch, AGRO_REPO_URL, target], { stdio: "inherit" }), root);
|
|
4216
4625
|
}
|
|
4217
4626
|
function cloneThroughStaging(root, run, ref) {
|
|
4218
|
-
const staging = mkdtempSync4(
|
|
4627
|
+
const staging = mkdtempSync4(join15(dirname9(root), "agro-clone-"));
|
|
4219
4628
|
try {
|
|
4220
|
-
const checkout =
|
|
4629
|
+
const checkout = join15(staging, "agro");
|
|
4221
4630
|
cloneInto(checkout, run, root, ref);
|
|
4222
4631
|
for (const name of readdirSync3(checkout)) {
|
|
4223
|
-
const destination =
|
|
4224
|
-
if (
|
|
4632
|
+
const destination = join15(root, name);
|
|
4633
|
+
if (existsSync19(destination)) {
|
|
4225
4634
|
throw new Error(`could not move ${name} into ${root} \u2014 the path already exists`);
|
|
4226
4635
|
}
|
|
4227
|
-
renameSync5(
|
|
4636
|
+
renameSync5(join15(checkout, name), destination);
|
|
4228
4637
|
}
|
|
4229
4638
|
} finally {
|
|
4230
4639
|
rmSync4(staging, { recursive: true, force: true });
|
|
@@ -4232,10 +4641,10 @@ function cloneThroughStaging(root, run, ref) {
|
|
|
4232
4641
|
}
|
|
4233
4642
|
function ensureHostWorkspace(path4, run = spawnRunner, ref) {
|
|
4234
4643
|
const root = resolve9(path4);
|
|
4235
|
-
if (
|
|
4644
|
+
if (existsSync19(join15(root, ".git"))) return { root, action: "reused" };
|
|
4236
4645
|
const stats = statSync5(root, { throwIfNoEntry: false });
|
|
4237
4646
|
if (stats === void 0) {
|
|
4238
|
-
|
|
4647
|
+
mkdirSync10(dirname9(root), { recursive: true });
|
|
4239
4648
|
cloneInto(root, run, root, ref);
|
|
4240
4649
|
return { root, action: "cloned" };
|
|
4241
4650
|
}
|
|
@@ -4254,11 +4663,11 @@ function ensureHostWorkspace(path4, run = spawnRunner, ref) {
|
|
|
4254
4663
|
function listHostWorkspaces(env, home) {
|
|
4255
4664
|
const root = workspacesRoot(env, home);
|
|
4256
4665
|
if (!isDirectory3(root)) return [];
|
|
4257
|
-
return readdirSync3(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => SANDBOX_NAME_PATTERN.test(name)).filter((name) =>
|
|
4666
|
+
return readdirSync3(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => SANDBOX_NAME_PATTERN.test(name)).filter((name) => existsSync19(join15(root, name, ".git"))).sort();
|
|
4258
4667
|
}
|
|
4259
4668
|
function resolveExistingWorkspace(bin, verb, path4, env, home) {
|
|
4260
4669
|
const root = resolve9(path4);
|
|
4261
|
-
if (
|
|
4670
|
+
if (existsSync19(join15(root, ".git"))) return { ok: true, root };
|
|
4262
4671
|
const existing = listHostWorkspaces(env, home);
|
|
4263
4672
|
const inventory = existing.length === 0 ? "No host workspace exists yet.\n" : `Workspaces that exist: ${existing.join(", ")}
|
|
4264
4673
|
`;
|
|
@@ -4288,7 +4697,7 @@ function targetFor(root, run, env) {
|
|
|
4288
4697
|
});
|
|
4289
4698
|
}
|
|
4290
4699
|
function hostPrefix(home) {
|
|
4291
|
-
return
|
|
4700
|
+
return join16(home, ".local");
|
|
4292
4701
|
}
|
|
4293
4702
|
function pathEntries(env) {
|
|
4294
4703
|
return (env.PATH ?? "").split(delimiter2).filter((part) => part !== "");
|
|
@@ -4322,6 +4731,21 @@ async function probeInstalled(target, entry, prefix, user, env) {
|
|
|
4322
4731
|
throw err;
|
|
4323
4732
|
}
|
|
4324
4733
|
}
|
|
4734
|
+
function sandboxMarkerPath(entry) {
|
|
4735
|
+
return `${SANDBOX_HARNESS_PREFIX}/share/agro/harnesses/${entry.id}.installed`;
|
|
4736
|
+
}
|
|
4737
|
+
async function sandboxMarkerExists(target, entry) {
|
|
4738
|
+
const r = await target.exec({
|
|
4739
|
+
argv: ["test", "-f", sandboxMarkerPath(entry)],
|
|
4740
|
+
user: "sandbox",
|
|
4741
|
+
stdio: "capture",
|
|
4742
|
+
timeoutMs: PROBE_TIMEOUT_MS
|
|
4743
|
+
});
|
|
4744
|
+
return r.exitCode === 0;
|
|
4745
|
+
}
|
|
4746
|
+
function hostBinaryUnderPrefix(entry, prefix) {
|
|
4747
|
+
return existsSync20(join16(harnessBinPath(prefix), entry.binary));
|
|
4748
|
+
}
|
|
4325
4749
|
function stateOf(entry, installed, location) {
|
|
4326
4750
|
return {
|
|
4327
4751
|
id: entry.id,
|
|
@@ -4341,7 +4765,7 @@ function probeableHost(env, home) {
|
|
|
4341
4765
|
return void 0;
|
|
4342
4766
|
}
|
|
4343
4767
|
const prefix = hostPrefix(home);
|
|
4344
|
-
if (!
|
|
4768
|
+
if (!existsSync20(join16(root, ".git")) && !existsSync20(prefix)) return void 0;
|
|
4345
4769
|
return { root, prefix };
|
|
4346
4770
|
}
|
|
4347
4771
|
async function collectStates(root, run, home, env, only) {
|
|
@@ -4547,7 +4971,15 @@ Run: bash ${root}/.agro/scripts/link-providers.sh --init
|
|
|
4547
4971
|
const code = await reconcileHermes(target, io, bin, void 0, root);
|
|
4548
4972
|
if (code !== 0) return code;
|
|
4549
4973
|
}
|
|
4550
|
-
|
|
4974
|
+
let hasReceipt;
|
|
4975
|
+
try {
|
|
4976
|
+
hasReceipt = readHostConfig(env, home).hostHarnesses?.[entry.id] !== void 0;
|
|
4977
|
+
} catch (err) {
|
|
4978
|
+
io.stderr(`${bin} harness: ${messageOf(err)}
|
|
4979
|
+
`);
|
|
4980
|
+
return 1;
|
|
4981
|
+
}
|
|
4982
|
+
if (await probeInstalled(target, entry, prefix, void 0, installEnv) === true && (hasReceipt || !hostBinaryUnderPrefix(entry, prefix))) {
|
|
4551
4983
|
io.stdout(`${entry.id}: already installed (${entry.binary})
|
|
4552
4984
|
`);
|
|
4553
4985
|
try {
|
|
@@ -4711,7 +5143,20 @@ async function runHarnessUninstall(name, opts, io) {
|
|
|
4711
5143
|
if (!isReachable(await resolveTargetStatus(target))) {
|
|
4712
5144
|
return await uninstallOnHost(entry, opts, io, run);
|
|
4713
5145
|
}
|
|
4714
|
-
|
|
5146
|
+
const outcome = await removeHarness(entry, target, SANDBOX_HARNESS_PREFIX, "sandbox", opts, io);
|
|
5147
|
+
if (outcome.dropReceipt) {
|
|
5148
|
+
const cleared = await target.exec({
|
|
5149
|
+
argv: ["rm", "-f", sandboxMarkerPath(entry)],
|
|
5150
|
+
user: "sandbox",
|
|
5151
|
+
stdio: "capture"
|
|
5152
|
+
});
|
|
5153
|
+
if (cleared.exitCode !== 0) {
|
|
5154
|
+
io.stderr(`${opts.bin} harness: could not clear the install record (exit ${cleared.exitCode}).
|
|
5155
|
+
`);
|
|
5156
|
+
return 1;
|
|
5157
|
+
}
|
|
5158
|
+
}
|
|
5159
|
+
return outcome.code;
|
|
4715
5160
|
}
|
|
4716
5161
|
async function runHarnessInstall(name, opts, io) {
|
|
4717
5162
|
const run = opts.run ?? spawnRunner;
|
|
@@ -4737,7 +5182,7 @@ async function runHarnessInstall(name, opts, io) {
|
|
|
4737
5182
|
if (code !== 0) return code;
|
|
4738
5183
|
}
|
|
4739
5184
|
const already = await probeInstalled(target, entry, SANDBOX_HARNESS_PREFIX, "sandbox", installEnv);
|
|
4740
|
-
if (already === true) {
|
|
5185
|
+
if (already === true && await sandboxMarkerExists(target, entry)) {
|
|
4741
5186
|
io.stdout(`${entry.id}: already installed (${entry.binary})
|
|
4742
5187
|
`);
|
|
4743
5188
|
return 0;
|
|
@@ -4768,15 +5213,26 @@ async function runHarnessInstall(name, opts, io) {
|
|
|
4768
5213
|
const code = await reconcileHermes(target, io, opts.bin, "sandbox");
|
|
4769
5214
|
if (code !== 0) return code;
|
|
4770
5215
|
}
|
|
5216
|
+
const marker = sandboxMarkerPath(entry);
|
|
5217
|
+
const marked = await target.exec({
|
|
5218
|
+
argv: ["sh", "-c", `mkdir -p "$(dirname "$1")" && : > "$1"`, "sh", marker],
|
|
5219
|
+
user: "sandbox",
|
|
5220
|
+
stdio: "capture"
|
|
5221
|
+
});
|
|
5222
|
+
if (marked.exitCode !== 0) {
|
|
5223
|
+
io.stderr(`${opts.bin} harness: could not record the install at ${marker} (exit ${marked.exitCode}).
|
|
5224
|
+
`);
|
|
5225
|
+
return 1;
|
|
5226
|
+
}
|
|
4771
5227
|
io.stdout(`${entry.id}: installed \u2014 see ${sourceDocsUrl(entry.docsPath)} for authentication
|
|
4772
5228
|
`);
|
|
4773
5229
|
return 0;
|
|
4774
5230
|
}
|
|
4775
5231
|
|
|
4776
5232
|
// src/commands/workspace.ts
|
|
4777
|
-
import { existsSync as
|
|
5233
|
+
import { existsSync as existsSync21, rmSync as rmSync5 } from "node:fs";
|
|
4778
5234
|
import { homedir as homedir4 } from "node:os";
|
|
4779
|
-
import { join as
|
|
5235
|
+
import { join as join17, resolve as resolve10 } from "node:path";
|
|
4780
5236
|
function homeOf2(opts) {
|
|
4781
5237
|
return (opts.homedir ?? homedir4)();
|
|
4782
5238
|
}
|
|
@@ -4822,9 +5278,9 @@ async function runWorkspaceCreate(name, opts, io) {
|
|
|
4822
5278
|
return 1;
|
|
4823
5279
|
}
|
|
4824
5280
|
let action;
|
|
4825
|
-
const preexisting =
|
|
5281
|
+
const preexisting = existsSync21(root);
|
|
4826
5282
|
try {
|
|
4827
|
-
if (!opts.json && !
|
|
5283
|
+
if (!opts.json && !existsSync21(join17(root, ".git"))) {
|
|
4828
5284
|
const at = opts.ref !== void 0 ? ` at ${opts.ref}` : "";
|
|
4829
5285
|
io.stdout(`cloning ${AGRO_REPO_URL}${at} into ${root}\u2026
|
|
4830
5286
|
`);
|
|
@@ -4869,7 +5325,7 @@ async function runWorkspaceList(opts, io) {
|
|
|
4869
5325
|
const recorded = recordedRoot(env, home);
|
|
4870
5326
|
const registry = workspacesRoot(env, home);
|
|
4871
5327
|
rows = listHostWorkspaces(env, home).map((name) => {
|
|
4872
|
-
const root =
|
|
5328
|
+
const root = join17(registry, name);
|
|
4873
5329
|
return { name, root, default: recorded === root };
|
|
4874
5330
|
});
|
|
4875
5331
|
} catch (err) {
|
|
@@ -4894,9 +5350,9 @@ async function runWorkspaceList(opts, io) {
|
|
|
4894
5350
|
}
|
|
4895
5351
|
|
|
4896
5352
|
// src/commands/tool.ts
|
|
4897
|
-
import { existsSync as
|
|
5353
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
4898
5354
|
import { homedir as homedir5, userInfo as userInfo2 } from "node:os";
|
|
4899
|
-
import { delimiter as delimiter3, join as
|
|
5355
|
+
import { delimiter as delimiter3, join as join18 } from "node:path";
|
|
4900
5356
|
|
|
4901
5357
|
// src/lib/tools/catalog.ts
|
|
4902
5358
|
var TOOLS_DOC = "docs/installation.md";
|
|
@@ -5313,6 +5769,7 @@ function resolveToolInstallArgv(entry, host) {
|
|
|
5313
5769
|
}
|
|
5314
5770
|
|
|
5315
5771
|
// src/commands/tool.ts
|
|
5772
|
+
var ROOT_TOOL_REMOVAL_DOCS = `${sourceDocsUrl("docs/installation.md")}#remove-a-root-level-tool`;
|
|
5316
5773
|
function isReachable2(status) {
|
|
5317
5774
|
return status === "ready" || status === "starting";
|
|
5318
5775
|
}
|
|
@@ -5326,7 +5783,21 @@ function targetFor2(root, run, env) {
|
|
|
5326
5783
|
});
|
|
5327
5784
|
}
|
|
5328
5785
|
function hostPrefix2(home) {
|
|
5329
|
-
return
|
|
5786
|
+
return join18(home, ".local");
|
|
5787
|
+
}
|
|
5788
|
+
function sandboxMarkerPath2(entry) {
|
|
5789
|
+
return `${SANDBOX_HARNESS_PREFIX}/share/agro/tools/${entry.id}.installed`;
|
|
5790
|
+
}
|
|
5791
|
+
async function sandboxMarkerExists2(target, entry) {
|
|
5792
|
+
const r = await target.exec({
|
|
5793
|
+
argv: ["test", "-f", sandboxMarkerPath2(entry)],
|
|
5794
|
+
user: "sandbox",
|
|
5795
|
+
stdio: "capture"
|
|
5796
|
+
});
|
|
5797
|
+
return r.exitCode === 0;
|
|
5798
|
+
}
|
|
5799
|
+
function hostBinaryUnderPrefix2(entry, prefix) {
|
|
5800
|
+
return existsSync22(join18(harnessBinPath(prefix), entry.binary));
|
|
5330
5801
|
}
|
|
5331
5802
|
function pathEntries2(env) {
|
|
5332
5803
|
return (env.PATH ?? "").split(delimiter3).filter((part) => part !== "");
|
|
@@ -5406,7 +5877,7 @@ function probeableHost2(env, home) {
|
|
|
5406
5877
|
return void 0;
|
|
5407
5878
|
}
|
|
5408
5879
|
const prefix = hostPrefix2(home);
|
|
5409
|
-
if (!
|
|
5880
|
+
if (!existsSync22(join18(root, ".git")) && !existsSync22(prefix)) return void 0;
|
|
5410
5881
|
return { root, prefix };
|
|
5411
5882
|
}
|
|
5412
5883
|
async function collectRows(root, run, home, env, only) {
|
|
@@ -5622,7 +6093,15 @@ Every tool installer in the catalog is Debian-specific. Install ${entry.id} with
|
|
|
5622
6093
|
const prefix = hostPrefix2(home);
|
|
5623
6094
|
const installEnv = { NPM_USER_PREFIX: prefix };
|
|
5624
6095
|
const target = hostTargetFor2(root, prefix, run, env);
|
|
5625
|
-
|
|
6096
|
+
let hasReceipt;
|
|
6097
|
+
try {
|
|
6098
|
+
hasReceipt = readHostConfig(env, home).hostTools?.[entry.id] !== void 0;
|
|
6099
|
+
} catch (err) {
|
|
6100
|
+
io.stderr(`${bin} tool: ${messageOf3(err)}
|
|
6101
|
+
`);
|
|
6102
|
+
return 1;
|
|
6103
|
+
}
|
|
6104
|
+
if (await probeInstalled2(target, entry, void 0, installEnv) === true && (hasReceipt || entry.hostInstallUser === "root" || !hostBinaryUnderPrefix2(entry, prefix))) {
|
|
5626
6105
|
io.stdout(`${entry.id}: already installed (${entry.binary})
|
|
5627
6106
|
`);
|
|
5628
6107
|
try {
|
|
@@ -5657,13 +6136,8 @@ Every tool installer in the catalog is Debian-specific. Install ${entry.id} with
|
|
|
5657
6136
|
`);
|
|
5658
6137
|
return r.exitCode;
|
|
5659
6138
|
}
|
|
5660
|
-
const
|
|
5661
|
-
|
|
5662
|
-
binary: entry.binary,
|
|
5663
|
-
binPath: harnessBinPath(prefix),
|
|
5664
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5665
|
-
workspaceRoot: root
|
|
5666
|
-
};
|
|
6139
|
+
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6140
|
+
const receipt = entry.hostInstallUser === "root" ? { scope: "root", binary: entry.binary, installedAt, workspaceRoot: root } : { prefix, binary: entry.binary, binPath: harnessBinPath(prefix), installedAt, workspaceRoot: root };
|
|
5667
6141
|
try {
|
|
5668
6142
|
const config = readHostConfig(env, home);
|
|
5669
6143
|
writeHostConfig(
|
|
@@ -5723,7 +6197,7 @@ ${installableToolIds().map((t) => ` ${t}`).join("\n")}
|
|
|
5723
6197
|
}
|
|
5724
6198
|
if (entry.installArgv === void 0) return refuseContainer();
|
|
5725
6199
|
const already = await probeInstalled2(target, entry, "sandbox");
|
|
5726
|
-
if (already === true) {
|
|
6200
|
+
if (already === true && await sandboxMarkerExists2(target, entry)) {
|
|
5727
6201
|
io.stdout(`${entry.id}: already installed (${entry.binary})
|
|
5728
6202
|
`);
|
|
5729
6203
|
return 0;
|
|
@@ -5745,6 +6219,17 @@ ${installableToolIds().map((t) => ` ${t}`).join("\n")}
|
|
|
5745
6219
|
`);
|
|
5746
6220
|
return r.exitCode;
|
|
5747
6221
|
}
|
|
6222
|
+
const marker = sandboxMarkerPath2(entry);
|
|
6223
|
+
const marked = await target.exec({
|
|
6224
|
+
argv: ["sh", "-c", `mkdir -p "$(dirname "$1")" && : > "$1"`, "sh", marker],
|
|
6225
|
+
user: "sandbox",
|
|
6226
|
+
stdio: "capture"
|
|
6227
|
+
});
|
|
6228
|
+
if (marked.exitCode !== 0) {
|
|
6229
|
+
io.stderr(`${opts.bin} tool: could not record the install at ${marker} (exit ${marked.exitCode}).
|
|
6230
|
+
`);
|
|
6231
|
+
return 1;
|
|
6232
|
+
}
|
|
5748
6233
|
io.stdout(`${entry.id}: installed \u2014 see ${sourceDocsUrl(entry.docsPath)}
|
|
5749
6234
|
`);
|
|
5750
6235
|
return 0;
|
|
@@ -5805,7 +6290,7 @@ Removing it could delete a tool you installed yourself. Re-run with \`--force\`
|
|
|
5805
6290
|
);
|
|
5806
6291
|
return 1;
|
|
5807
6292
|
}
|
|
5808
|
-
const prefix = receipt
|
|
6293
|
+
const prefix = receipt === void 0 || isRootToolReceipt(receipt) ? computed : receipt.prefix;
|
|
5809
6294
|
const target = hostTargetFor2(receipt?.workspaceRoot ?? workspace, prefix, run, env);
|
|
5810
6295
|
const outcome = await removeTool(entry, target, prefix, void 0, opts, io, true);
|
|
5811
6296
|
if (outcome.dropReceipt && receipt !== void 0) {
|
|
@@ -5828,6 +6313,15 @@ async function runToolUninstall(name, opts, io) {
|
|
|
5828
6313
|
const root = resolveProjectRoot(opts.cwd);
|
|
5829
6314
|
const entry = findTool(name);
|
|
5830
6315
|
if (!entry) return unknownTool(name, io, opts.bin);
|
|
6316
|
+
if (entry.hostInstallUser === "root") {
|
|
6317
|
+
io.stderr(
|
|
6318
|
+
`${opts.bin} tool: ${entry.id} cannot be removed by this command.
|
|
6319
|
+
${opts.bin} does not remove system packages that it installed as root.
|
|
6320
|
+
Remove ${entry.id} by hand: ${ROOT_TOOL_REMOVAL_DOCS}
|
|
6321
|
+
`
|
|
6322
|
+
);
|
|
6323
|
+
return 1;
|
|
6324
|
+
}
|
|
5831
6325
|
if (entry.uninstallArgv === null) {
|
|
5832
6326
|
io.stderr(`${opts.bin} tool: ${entry.id} cannot be removed by this command.
|
|
5833
6327
|
|
|
@@ -5840,7 +6334,20 @@ async function runToolUninstall(name, opts, io) {
|
|
|
5840
6334
|
if (!isReachable2(await resolveTargetStatus(target))) {
|
|
5841
6335
|
return await uninstallOnHost2(entry, opts, io, run);
|
|
5842
6336
|
}
|
|
5843
|
-
|
|
6337
|
+
const outcome = await removeTool(entry, target, SANDBOX_HARNESS_PREFIX, "sandbox", opts, io);
|
|
6338
|
+
if (outcome.dropReceipt) {
|
|
6339
|
+
const cleared = await target.exec({
|
|
6340
|
+
argv: ["rm", "-f", sandboxMarkerPath2(entry)],
|
|
6341
|
+
user: "sandbox",
|
|
6342
|
+
stdio: "capture"
|
|
6343
|
+
});
|
|
6344
|
+
if (cleared.exitCode !== 0) {
|
|
6345
|
+
io.stderr(`${opts.bin} tool: could not clear the install record (exit ${cleared.exitCode}).
|
|
6346
|
+
`);
|
|
6347
|
+
return 1;
|
|
6348
|
+
}
|
|
6349
|
+
}
|
|
6350
|
+
return outcome.code;
|
|
5844
6351
|
}
|
|
5845
6352
|
|
|
5846
6353
|
// src/lib/remote.ts
|
|
@@ -5920,7 +6427,7 @@ var INTEGRATIONS = {
|
|
|
5920
6427
|
)
|
|
5921
6428
|
}
|
|
5922
6429
|
};
|
|
5923
|
-
function
|
|
6430
|
+
function isHelpFlag2(arg) {
|
|
5924
6431
|
return arg === "--help" || arg === "-h" || arg === "help";
|
|
5925
6432
|
}
|
|
5926
6433
|
function isVersionFlag(arg) {
|
|
@@ -5937,7 +6444,7 @@ function printAgroHelp(product = AGRO_PRODUCT) {
|
|
|
5937
6444
|
process.stdout.write(`${bin} \u2014 ${title} (v${AGRO_VERSION})
|
|
5938
6445
|
|
|
5939
6446
|
Usage:
|
|
5940
|
-
${bin} sandbox <args...> Create and
|
|
6447
|
+
${bin} sandbox <args...> Create, list, and upgrade sandboxes (install|list|upgrade)
|
|
5941
6448
|
${bin} shell [name] Open a zsh shell in the running sandbox container
|
|
5942
6449
|
${bin} config <args...> Read and write ${stateNames(bin).configFile} (show|set), or run a wizard
|
|
5943
6450
|
${bin} secret <args...> Read and write the gitignored root .env (set|list)
|
|
@@ -6087,66 +6594,6 @@ Flags:
|
|
|
6087
6594
|
--force Override the up-to-date / downgrade gate.
|
|
6088
6595
|
`);
|
|
6089
6596
|
}
|
|
6090
|
-
function runtimeLines() {
|
|
6091
|
-
const width = Math.max(...RUNTIME_CATALOG.map((r) => r.id.length));
|
|
6092
|
-
return RUNTIME_CATALOG.map(
|
|
6093
|
-
(r) => ` ${r.id.padEnd(width)} ${r.provisionable ? "provisionable" : "planned"}`
|
|
6094
|
-
).join("\n");
|
|
6095
|
-
}
|
|
6096
|
-
function printSandboxHelp(bin = AGRO_PRODUCT.bin) {
|
|
6097
|
-
process.stdout.write(`${bin} sandbox \u2014 Create and list sandboxes
|
|
6098
|
-
|
|
6099
|
-
Usage:
|
|
6100
|
-
${bin} sandbox install <runtime> [--name <name>] [--checkout <dir>]
|
|
6101
|
-
[--home-mount <dir>] [--yes]
|
|
6102
|
-
[--version <X.Y.Z> | --image[=<ref>]]
|
|
6103
|
-
[--no-build] [--print-argv]
|
|
6104
|
-
${bin} sandbox list [--json]
|
|
6105
|
-
|
|
6106
|
-
\`install\` writes a sandbox entry under \${${stateNames(bin).envPrefix}HOME:-~/${stateNames(bin).userStateDir}}/sandboxes/<name>/,
|
|
6107
|
-
materialises the compose files and the compose wrapper into it, then starts the
|
|
6108
|
-
container. It needs no project checkout and runs from any directory. Without
|
|
6109
|
-
--checkout the sandbox runs the prebuilt image; with --checkout <dir> that
|
|
6110
|
-
checkout is bound at /home/sandbox/harness; the sandbox builds locally only
|
|
6111
|
-
when that directory holds .devcontainer/Dockerfile.
|
|
6112
|
-
|
|
6113
|
-
On a terminal without --yes it asks for the sandbox name, the timezone, the git
|
|
6114
|
-
identity, SSH (with its host port), the host Docker socket, and the host path
|
|
6115
|
-
for /home/sandbox. With --checkout it seeds those answers from that
|
|
6116
|
-
checkout's ${stateNames(bin).configFile}.
|
|
6117
|
-
|
|
6118
|
-
Flags:
|
|
6119
|
-
--name <name> Registry entry name (default: the lowest free ${DEFAULT_NAME_PREFIX}<n>)
|
|
6120
|
-
--checkout <dir> Bind this checkout into the sandbox and seed the defaults
|
|
6121
|
-
from its ${stateNames(bin).configFile}. The sandbox builds
|
|
6122
|
-
locally only when that directory holds
|
|
6123
|
-
.devcontainer/Dockerfile
|
|
6124
|
-
--repo <dir> Deprecated alias for --checkout
|
|
6125
|
-
--home-mount <dir>
|
|
6126
|
-
Bind this host directory at /home/sandbox instead of the
|
|
6127
|
-
Docker-managed volume. Relative paths resolve against the
|
|
6128
|
-
working directory. The directory is created when absent
|
|
6129
|
-
--yes Non-interactive: keep every default and ask nothing
|
|
6130
|
-
--version <X.Y.Z>
|
|
6131
|
-
Run the official release image ghcr.io/mifunedev/agro:<X.Y.Z>
|
|
6132
|
-
(implies --image). A leading v and a -<channel>.<n>
|
|
6133
|
-
pre-release suffix are accepted
|
|
6134
|
-
--image Run the prebuilt image instead of building (implies
|
|
6135
|
-
--no-build). The ref resolves first-match: --version or
|
|
6136
|
-
--image=<ref> > ${stateNames(bin).envPrefix}SANDBOX_IMAGE >
|
|
6137
|
-
${stateNames(bin).configFile} image.ref > ${officialImageRef(AGRO_VERSION)}
|
|
6138
|
-
--image=<ref> Run a custom image (implies --image); conflicts with --version
|
|
6139
|
-
--no-build Suppress the local build and reuse an existing image
|
|
6140
|
-
--print-argv Print the docker compose argv that would run, then exit
|
|
6141
|
-
without writing an entry
|
|
6142
|
-
--json Machine-readable output (list)
|
|
6143
|
-
|
|
6144
|
-
Runtimes:
|
|
6145
|
-
${runtimeLines()}
|
|
6146
|
-
|
|
6147
|
-
Next: ${bin} shell <name>
|
|
6148
|
-
`);
|
|
6149
|
-
}
|
|
6150
6597
|
function printShellHelp(bin = AGRO_PRODUCT.bin) {
|
|
6151
6598
|
process.stdout.write(`${bin} shell \u2014 Open a shell in the running sandbox container
|
|
6152
6599
|
|
|
@@ -6171,8 +6618,8 @@ Usage:
|
|
|
6171
6618
|
|
|
6172
6619
|
\`install\` and \`uninstall\` act on the running sandbox. When no sandbox is
|
|
6173
6620
|
reachable they act on the host. A host install needs an existing AGRO workspace
|
|
6174
|
-
and creates none \u2014 run \`${bin} workspace create
|
|
6175
|
-
the workspace registry entry \`~/.agro/workspaces/
|
|
6621
|
+
and creates none \u2014 run \`${bin} workspace create\` first. The fallback root is
|
|
6622
|
+
the workspace registry entry \`~/.agro/workspaces/harness\`. \`--workspace <name>\`
|
|
6176
6623
|
chooses another entry and \`--path <dir>\` a directory outside the registry. A
|
|
6177
6624
|
successful install records the root as \`harnessRoot\` in \`~/.agro/config.json\`. The
|
|
6178
6625
|
install prefix is always \`~/.local\`.
|
|
@@ -6202,8 +6649,8 @@ Usage:
|
|
|
6202
6649
|
|
|
6203
6650
|
A host workspace is an AGRO checkout under \`~/.agro/workspaces/<name>\`. \`create\`
|
|
6204
6651
|
clones ${AGRO_REPO_URL} into that entry, and reuses an existing checkout. The
|
|
6205
|
-
|
|
6206
|
-
registry instead.
|
|
6652
|
+
implicit name is \`harness\`. Pass \`default\` to create that named workspace.
|
|
6653
|
+
\`--path <dir>\` creates the workspace outside the registry instead.
|
|
6207
6654
|
|
|
6208
6655
|
\`create\` records no default. A host install selects its root with
|
|
6209
6656
|
\`${bin} harness install <harness> --workspace <name>\`, and that install records the
|
|
@@ -6266,11 +6713,13 @@ only on these tools:
|
|
|
6266
6713
|
${hostCapableToolIds().map((t) => ` ${t}`).join("\n")}
|
|
6267
6714
|
|
|
6268
6715
|
A host install needs an existing AGRO workspace \u2014 \`--path <dir>\`, then
|
|
6269
|
-
\`harnessRoot\` in \`~/.agro/config.json\`, then \`~/.agro/workspaces/
|
|
6270
|
-
no workspace: run \`${bin} workspace create
|
|
6716
|
+
\`harnessRoot\` in \`~/.agro/config.json\`, then \`~/.agro/workspaces/harness\`. It creates
|
|
6717
|
+
no workspace: run \`${bin} workspace create\` first. It installs into
|
|
6271
6718
|
\`~/.local\` and records the install as \`hostTools\` in that same file. On the host,
|
|
6272
6719
|
\`uninstall\` removes only what \`install\` recorded, from the prefix in that record.
|
|
6273
6720
|
Without a record it refuses, and \`--force\` overrides.
|
|
6721
|
+
\`uninstall\` refuses each root-level tool, marked \`(root)\` in \`${bin} tool list\`,
|
|
6722
|
+
with and without \`--force\`. The refusal links the manual removal steps.
|
|
6274
6723
|
|
|
6275
6724
|
Flags:
|
|
6276
6725
|
--yes Accept a large download without prompting
|
|
@@ -6360,7 +6809,7 @@ function extractSandboxFlag(command, rest) {
|
|
|
6360
6809
|
}
|
|
6361
6810
|
var LANGFUSE_VERBS = ["apply", "status", "disable"];
|
|
6362
6811
|
function parseLangfuseArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
6363
|
-
if (rest.length === 0 ||
|
|
6812
|
+
if (rest.length === 0 || isHelpFlag2(rest[0])) return { ok: true, args: { help: true } };
|
|
6364
6813
|
const [head, ...tail] = rest;
|
|
6365
6814
|
if (!LANGFUSE_VERBS.includes(head)) {
|
|
6366
6815
|
return {
|
|
@@ -6369,7 +6818,7 @@ function parseLangfuseArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
|
6369
6818
|
showHelp: true
|
|
6370
6819
|
};
|
|
6371
6820
|
}
|
|
6372
|
-
if (
|
|
6821
|
+
if (isHelpFlag2(tail[0])) return { ok: true, args: { help: true } };
|
|
6373
6822
|
if (tail.length > 0) {
|
|
6374
6823
|
return { ok: false, error: `${bin} langfuse ${head}: unexpected argument "${tail[0]}"` };
|
|
6375
6824
|
}
|
|
@@ -6387,12 +6836,12 @@ function parseConfigArgs(input, bin = AGRO_PRODUCT.bin) {
|
|
|
6387
6836
|
...scoped.args.sandbox === void 0 ? {} : { sandbox: scoped.args.sandbox },
|
|
6388
6837
|
...forced ? { force: true } : {}
|
|
6389
6838
|
};
|
|
6390
|
-
if (rest.length === 0 ||
|
|
6839
|
+
if (rest.length === 0 || isHelpFlag2(rest[0])) {
|
|
6391
6840
|
return { ok: true, args: { ...args, help: true } };
|
|
6392
6841
|
}
|
|
6393
6842
|
const [head, ...tail] = rest;
|
|
6394
6843
|
if (!CONFIG_VERBS.includes(head)) {
|
|
6395
|
-
if (tail.length > 0 &&
|
|
6844
|
+
if (tail.length > 0 && isHelpFlag2(tail[0])) {
|
|
6396
6845
|
return { ok: true, args: { ...args, integration: head, integrationHelp: true } };
|
|
6397
6846
|
}
|
|
6398
6847
|
if (tail.length > 0) {
|
|
@@ -6404,7 +6853,7 @@ function parseConfigArgs(input, bin = AGRO_PRODUCT.bin) {
|
|
|
6404
6853
|
return { ok: true, args: { ...args, integration: head } };
|
|
6405
6854
|
}
|
|
6406
6855
|
const verb = head;
|
|
6407
|
-
if (
|
|
6856
|
+
if (isHelpFlag2(tail[0])) return { ok: true, args: { ...args, help: true } };
|
|
6408
6857
|
if (verb === "show" || verb === "repo") {
|
|
6409
6858
|
if (tail.length > 0) {
|
|
6410
6859
|
return { ok: false, error: `${bin} config ${verb}: unexpected argument "${tail[0]}"` };
|
|
@@ -6436,7 +6885,7 @@ function parseSecretArgs(input, bin = AGRO_PRODUCT.bin) {
|
|
|
6436
6885
|
help: false,
|
|
6437
6886
|
...scoped.args.sandbox === void 0 ? {} : { sandbox: scoped.args.sandbox }
|
|
6438
6887
|
};
|
|
6439
|
-
if (rest.length === 0 ||
|
|
6888
|
+
if (rest.length === 0 || isHelpFlag2(rest[0])) {
|
|
6440
6889
|
return { ok: true, args: { ...args, help: true } };
|
|
6441
6890
|
}
|
|
6442
6891
|
const [head, ...tail] = rest;
|
|
@@ -6448,7 +6897,7 @@ function parseSecretArgs(input, bin = AGRO_PRODUCT.bin) {
|
|
|
6448
6897
|
};
|
|
6449
6898
|
}
|
|
6450
6899
|
const verb = head;
|
|
6451
|
-
if (
|
|
6900
|
+
if (isHelpFlag2(tail[0])) return { ok: true, args: { ...args, help: true } };
|
|
6452
6901
|
if (verb === "list") {
|
|
6453
6902
|
if (tail.length > 0) {
|
|
6454
6903
|
return { ok: false, error: `${bin} secret list: unexpected argument "${tail[0]}"` };
|
|
@@ -6469,7 +6918,7 @@ function parseSecretArgs(input, bin = AGRO_PRODUCT.bin) {
|
|
|
6469
6918
|
}
|
|
6470
6919
|
function parseDestroyArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
6471
6920
|
const args = { help: false, yes: false };
|
|
6472
|
-
if (
|
|
6921
|
+
if (isHelpFlag2(rest[0])) return { ok: true, args: { ...args, help: true } };
|
|
6473
6922
|
for (const token of rest) {
|
|
6474
6923
|
if (token === "--yes") {
|
|
6475
6924
|
args.yes = true;
|
|
@@ -6488,7 +6937,7 @@ function parseDestroyArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
|
6488
6937
|
}
|
|
6489
6938
|
function parseComposeArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
6490
6939
|
const args = { help: false, passthrough: [] };
|
|
6491
|
-
if (rest.length === 0 ||
|
|
6940
|
+
if (rest.length === 0 || isHelpFlag2(rest[0])) {
|
|
6492
6941
|
return { ok: true, args: { ...args, help: true } };
|
|
6493
6942
|
}
|
|
6494
6943
|
if (rest[0] !== "config") {
|
|
@@ -6500,7 +6949,7 @@ function parseComposeArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
|
6500
6949
|
}
|
|
6501
6950
|
args.subcommand = "config";
|
|
6502
6951
|
const tail = rest.slice(1);
|
|
6503
|
-
if (
|
|
6952
|
+
if (isHelpFlag2(tail[0])) return { ok: true, args: { ...args, help: true } };
|
|
6504
6953
|
const sep4 = tail.indexOf("--");
|
|
6505
6954
|
if (sep4 === -1 && tail.length > 0) {
|
|
6506
6955
|
return {
|
|
@@ -6526,7 +6975,7 @@ function parseSelfUpgradeArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
|
6526
6975
|
args.dryRun = true;
|
|
6527
6976
|
continue;
|
|
6528
6977
|
}
|
|
6529
|
-
if (
|
|
6978
|
+
if (isHelpFlag2(arg)) {
|
|
6530
6979
|
args.help = true;
|
|
6531
6980
|
return { ok: true, args };
|
|
6532
6981
|
}
|
|
@@ -6568,7 +7017,7 @@ function parseVendorArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
|
6568
7017
|
args.force = true;
|
|
6569
7018
|
continue;
|
|
6570
7019
|
}
|
|
6571
|
-
if (
|
|
7020
|
+
if (isHelpFlag2(arg)) {
|
|
6572
7021
|
args.help = true;
|
|
6573
7022
|
return { ok: true, args };
|
|
6574
7023
|
}
|
|
@@ -6585,121 +7034,9 @@ function parseVendorArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
|
6585
7034
|
}
|
|
6586
7035
|
return { ok: true, args };
|
|
6587
7036
|
}
|
|
6588
|
-
var SANDBOX_VALUE_FLAGS = {
|
|
6589
|
-
"--name": "name",
|
|
6590
|
-
"--checkout": "checkout",
|
|
6591
|
-
"--repo": "checkout",
|
|
6592
|
-
"--home-mount": "homeMount"
|
|
6593
|
-
};
|
|
6594
|
-
function parseSandboxArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
6595
|
-
const args = {
|
|
6596
|
-
help: false,
|
|
6597
|
-
yes: false,
|
|
6598
|
-
image: false,
|
|
6599
|
-
noBuild: false,
|
|
6600
|
-
printArgv: false,
|
|
6601
|
-
json: false
|
|
6602
|
-
};
|
|
6603
|
-
if (rest.length === 0 || isHelpFlag(rest[0])) {
|
|
6604
|
-
return { ok: true, args: { ...args, help: true } };
|
|
6605
|
-
}
|
|
6606
|
-
const [head, ...tail] = rest;
|
|
6607
|
-
if (head !== "install" && head !== "list") {
|
|
6608
|
-
return {
|
|
6609
|
-
ok: false,
|
|
6610
|
-
error: `${bin} sandbox: unknown subcommand "${head}" \u2014 expected install or list`,
|
|
6611
|
-
showHelp: true
|
|
6612
|
-
};
|
|
6613
|
-
}
|
|
6614
|
-
args.subcommand = head;
|
|
6615
|
-
if (isHelpFlag(tail[0])) return { ok: true, args: { ...args, help: true } };
|
|
6616
|
-
const positionals = [];
|
|
6617
|
-
const checkoutSpellings = /* @__PURE__ */ new Set();
|
|
6618
|
-
let version;
|
|
6619
|
-
for (let i = 0; i < tail.length; i++) {
|
|
6620
|
-
const token = tail[i];
|
|
6621
|
-
const valueFlag = SANDBOX_VALUE_FLAGS[token];
|
|
6622
|
-
if (valueFlag !== void 0) {
|
|
6623
|
-
const value = tail[i + 1];
|
|
6624
|
-
if (value === void 0) {
|
|
6625
|
-
return { ok: false, error: `${bin} sandbox ${head}: ${token} requires a value` };
|
|
6626
|
-
}
|
|
6627
|
-
if (valueFlag === "checkout") checkoutSpellings.add(token);
|
|
6628
|
-
args[valueFlag] = value;
|
|
6629
|
-
i++;
|
|
6630
|
-
} else if (token === "--yes") {
|
|
6631
|
-
args.yes = true;
|
|
6632
|
-
} else if (token === "--no-build") {
|
|
6633
|
-
args.noBuild = true;
|
|
6634
|
-
} else if (token === "--print-argv") {
|
|
6635
|
-
args.printArgv = true;
|
|
6636
|
-
} else if (token === "--image") {
|
|
6637
|
-
args.image = true;
|
|
6638
|
-
} else if (token.startsWith("--image=")) {
|
|
6639
|
-
const ref = token.slice("--image=".length);
|
|
6640
|
-
if (ref === "") {
|
|
6641
|
-
return { ok: false, error: `${bin} sandbox: --image=<ref> requires a non-empty image ref` };
|
|
6642
|
-
}
|
|
6643
|
-
args.image = true;
|
|
6644
|
-
args.imageRef = ref;
|
|
6645
|
-
} else if (token === "--version" || token.startsWith("--version=")) {
|
|
6646
|
-
const value = token === "--version" ? tail[++i] : token.slice("--version=".length);
|
|
6647
|
-
if (value === void 0 || value === "") {
|
|
6648
|
-
return { ok: false, error: `${bin} sandbox ${head}: --version requires a value` };
|
|
6649
|
-
}
|
|
6650
|
-
version = parseReleaseVersion(value);
|
|
6651
|
-
if (version === void 0) {
|
|
6652
|
-
return {
|
|
6653
|
-
ok: false,
|
|
6654
|
-
error: `${bin} sandbox ${head}: --version "${value}" is not a release version \u2014 expected X.Y.Z`
|
|
6655
|
-
};
|
|
6656
|
-
}
|
|
6657
|
-
} else if (token === "--json") {
|
|
6658
|
-
args.json = true;
|
|
6659
|
-
} else if (token.startsWith("-")) {
|
|
6660
|
-
return { ok: false, error: `${bin} sandbox ${head}: unknown flag "${token}"` };
|
|
6661
|
-
} else {
|
|
6662
|
-
positionals.push(token);
|
|
6663
|
-
}
|
|
6664
|
-
}
|
|
6665
|
-
if (checkoutSpellings.has("--checkout") && checkoutSpellings.has("--repo")) {
|
|
6666
|
-
return {
|
|
6667
|
-
ok: false,
|
|
6668
|
-
error: `${bin} sandbox ${head}: --checkout conflicts with --repo \u2014 pass exactly one, and prefer --checkout`
|
|
6669
|
-
};
|
|
6670
|
-
}
|
|
6671
|
-
if (version !== void 0) {
|
|
6672
|
-
if (args.imageRef !== void 0) {
|
|
6673
|
-
return {
|
|
6674
|
-
ok: false,
|
|
6675
|
-
error: `${bin} sandbox ${head}: --version conflicts with --image=<ref> \u2014 pass --version for an official release or --image=<ref> for a custom image`
|
|
6676
|
-
};
|
|
6677
|
-
}
|
|
6678
|
-
args.image = true;
|
|
6679
|
-
args.imageRef = officialImageRef(version);
|
|
6680
|
-
}
|
|
6681
|
-
if (head === "list") {
|
|
6682
|
-
if (positionals.length > 0) {
|
|
6683
|
-
return { ok: false, error: `${bin} sandbox list: unexpected argument "${positionals[0]}"` };
|
|
6684
|
-
}
|
|
6685
|
-
return { ok: true, args };
|
|
6686
|
-
}
|
|
6687
|
-
if (positionals.length === 0) {
|
|
6688
|
-
return {
|
|
6689
|
-
ok: false,
|
|
6690
|
-
error: `${bin} sandbox install: a runtime is required, e.g. \`${bin} sandbox install docker\``,
|
|
6691
|
-
showHelp: true
|
|
6692
|
-
};
|
|
6693
|
-
}
|
|
6694
|
-
if (positionals.length > 1) {
|
|
6695
|
-
return { ok: false, error: `${bin} sandbox install: unexpected argument "${positionals[1]}"` };
|
|
6696
|
-
}
|
|
6697
|
-
args.runtime = positionals[0];
|
|
6698
|
-
return { ok: true, args };
|
|
6699
|
-
}
|
|
6700
7037
|
function parseShellArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
6701
7038
|
const args = { help: false };
|
|
6702
|
-
if (
|
|
7039
|
+
if (isHelpFlag2(rest[0])) return { ok: true, args: { help: true } };
|
|
6703
7040
|
for (const token of rest) {
|
|
6704
7041
|
if (token.startsWith("-")) {
|
|
6705
7042
|
return { ok: false, error: `${bin} shell: unknown flag "${token}"` };
|
|
@@ -6713,7 +7050,7 @@ function parseShellArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
|
6713
7050
|
}
|
|
6714
7051
|
function parseWorkspaceArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
6715
7052
|
const args = { help: false, json: false };
|
|
6716
|
-
if (rest.length === 0 ||
|
|
7053
|
+
if (rest.length === 0 || isHelpFlag2(rest[0])) {
|
|
6717
7054
|
return { ok: true, args: { ...args, help: true } };
|
|
6718
7055
|
}
|
|
6719
7056
|
const positionals = [];
|
|
@@ -6785,7 +7122,7 @@ function parseHarnessArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
|
6785
7122
|
host: false,
|
|
6786
7123
|
force: false
|
|
6787
7124
|
};
|
|
6788
|
-
if (rest.length === 0 ||
|
|
7125
|
+
if (rest.length === 0 || isHelpFlag2(rest[0])) {
|
|
6789
7126
|
return { ok: true, args: { ...args, help: true } };
|
|
6790
7127
|
}
|
|
6791
7128
|
const positionals = [];
|
|
@@ -6866,7 +7203,7 @@ function parseHarnessArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
|
6866
7203
|
}
|
|
6867
7204
|
function parseToolArgs(rest, bin = AGRO_PRODUCT.bin) {
|
|
6868
7205
|
const args = { help: false, yes: false, json: false, host: false, force: false };
|
|
6869
|
-
if (rest.length === 0 ||
|
|
7206
|
+
if (rest.length === 0 || isHelpFlag2(rest[0])) {
|
|
6870
7207
|
return { ok: true, args: { ...args, help: true } };
|
|
6871
7208
|
}
|
|
6872
7209
|
const positionals = [];
|
|
@@ -6924,11 +7261,11 @@ function parseGatewayArgs(rest) {
|
|
|
6924
7261
|
}
|
|
6925
7262
|
return { ok: true, args: { help: false, passthrough: [...rest] } };
|
|
6926
7263
|
}
|
|
6927
|
-
function bundledPayloadExists(bundled, exists =
|
|
6928
|
-
return exists(
|
|
7264
|
+
function bundledPayloadExists(bundled, exists = existsSync23) {
|
|
7265
|
+
return exists(join19(bundled.sourceControlDir, "manifest.json"));
|
|
6929
7266
|
}
|
|
6930
7267
|
function resolveVendorSource(args, bundled, bin = AGRO_PRODUCT.bin) {
|
|
6931
|
-
const exists = bundled.exists ??
|
|
7268
|
+
const exists = bundled.exists ?? existsSync23;
|
|
6932
7269
|
if (args.fromDir !== void 0) {
|
|
6933
7270
|
return { kind: "local", fromDir: resolve11(args.fromDir) };
|
|
6934
7271
|
}
|
|
@@ -6948,7 +7285,7 @@ function resolveVendorSource(args, bundled, bin = AGRO_PRODUCT.bin) {
|
|
|
6948
7285
|
function readPayloadVersion(checkoutDir) {
|
|
6949
7286
|
try {
|
|
6950
7287
|
const parsed = JSON.parse(
|
|
6951
|
-
|
|
7288
|
+
readFileSync13(join19(resolveControlDir(checkoutDir), "cli", "package.json"), "utf8")
|
|
6952
7289
|
);
|
|
6953
7290
|
if (parsed && typeof parsed.version === "string") return parsed.version;
|
|
6954
7291
|
} catch {
|
|
@@ -6957,7 +7294,7 @@ function readPayloadVersion(checkoutDir) {
|
|
|
6957
7294
|
}
|
|
6958
7295
|
async function runWithRemoteSource(hooks, fn) {
|
|
6959
7296
|
const fetch2 = hooks.fetch ?? fetchRemoteSource;
|
|
6960
|
-
const mkdtemp = hooks.mkdtemp ?? (() => mkdtempSync5(
|
|
7297
|
+
const mkdtemp = hooks.mkdtemp ?? (() => mkdtempSync5(join19(tmpdir4(), "oh-remote-")));
|
|
6961
7298
|
const rm = hooks.rm ?? ((dir) => rmSync6(dir, { recursive: true, force: true }));
|
|
6962
7299
|
const out = hooks.stdout ?? ((s) => process.stdout.write(s));
|
|
6963
7300
|
const checkoutDir = mkdtemp();
|
|
@@ -6974,7 +7311,7 @@ async function main(argv) {
|
|
|
6974
7311
|
const product = resolveProduct(process.argv[1]);
|
|
6975
7312
|
const bin = product.bin;
|
|
6976
7313
|
const [first, second] = argv;
|
|
6977
|
-
if (!first ||
|
|
7314
|
+
if (!first || isHelpFlag2(first)) {
|
|
6978
7315
|
printAgroHelp(product);
|
|
6979
7316
|
return 0;
|
|
6980
7317
|
}
|
|
@@ -7117,37 +7454,7 @@ async function main(argv) {
|
|
|
7117
7454
|
(checkoutDir) => runUpdate({ bin, targetDir, fromDir: checkoutDir, force, dryRun }, io)
|
|
7118
7455
|
);
|
|
7119
7456
|
}
|
|
7120
|
-
if (first === "sandbox")
|
|
7121
|
-
const parsed = parseSandboxArgs(argv.slice(1), bin);
|
|
7122
|
-
if (!parsed.ok) {
|
|
7123
|
-
process.stderr.write(`${parsed.error}
|
|
7124
|
-
`);
|
|
7125
|
-
if (parsed.showHelp) printSandboxHelp(bin);
|
|
7126
|
-
return 1;
|
|
7127
|
-
}
|
|
7128
|
-
const a = parsed.args;
|
|
7129
|
-
if (a.help) {
|
|
7130
|
-
printSandboxHelp(bin);
|
|
7131
|
-
return a.subcommand === void 0 ? 1 : 0;
|
|
7132
|
-
}
|
|
7133
|
-
const io = lifecycleIo();
|
|
7134
|
-
if (a.subcommand === "list") return await runSandboxList({ bin, json: a.json }, io);
|
|
7135
|
-
return await runSandboxInstall(
|
|
7136
|
-
{
|
|
7137
|
-
bin,
|
|
7138
|
-
runtime: a.runtime,
|
|
7139
|
-
...a.name !== void 0 ? { name: a.name } : {},
|
|
7140
|
-
...a.checkout !== void 0 ? { checkout: a.checkout } : {},
|
|
7141
|
-
...a.homeMount !== void 0 ? { homeMount: a.homeMount } : {},
|
|
7142
|
-
yes: a.yes,
|
|
7143
|
-
image: a.image,
|
|
7144
|
-
...a.imageRef !== void 0 ? { imageRef: a.imageRef } : {},
|
|
7145
|
-
noBuild: a.noBuild,
|
|
7146
|
-
printArgv: a.printArgv
|
|
7147
|
-
},
|
|
7148
|
-
io
|
|
7149
|
-
);
|
|
7150
|
-
}
|
|
7457
|
+
if (first === "sandbox") return runSandboxCommand(argv.slice(1), bin);
|
|
7151
7458
|
if (first === "shell") {
|
|
7152
7459
|
const parsed = parseShellArgs(argv.slice(1), bin);
|
|
7153
7460
|
if (!parsed.ok) {
|
|
@@ -7232,7 +7539,7 @@ async function main(argv) {
|
|
|
7232
7539
|
if (composeVerbs().includes(first)) {
|
|
7233
7540
|
const verb = first;
|
|
7234
7541
|
const rest = argv.slice(1);
|
|
7235
|
-
if (
|
|
7542
|
+
if (isHelpFlag2(rest[0])) {
|
|
7236
7543
|
printComposeVerbHelp(verb, bin);
|
|
7237
7544
|
return 0;
|
|
7238
7545
|
}
|
|
@@ -7362,7 +7669,7 @@ export {
|
|
|
7362
7669
|
SECRET_VERBS,
|
|
7363
7670
|
bundledPayloadExists,
|
|
7364
7671
|
extractSandboxFlag,
|
|
7365
|
-
isHelpFlag,
|
|
7672
|
+
isHelpFlag2 as isHelpFlag,
|
|
7366
7673
|
isVersionFlag,
|
|
7367
7674
|
parseComposeArgs,
|
|
7368
7675
|
parseConfigArgs,
|