@madarco/agentbox 0.14.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/CHANGELOG.md +108 -0
- package/dist/{_cloud-attach-GUBB5RH2.js → _cloud-attach-5KJWOASL.js} +4 -4
- package/dist/{chunk-RSKG7AFU.js → chunk-3WCEB6RE.js} +2 -2
- package/dist/{chunk-XKH7NTT7.js → chunk-DBBUDKKB.js} +248 -5
- package/dist/chunk-DBBUDKKB.js.map +1 -0
- package/dist/{chunk-TCS5HXJX.js → chunk-GXJNJUEV.js} +1090 -527
- package/dist/chunk-GXJNJUEV.js.map +1 -0
- package/dist/{chunk-LDMYHWUS.js → chunk-NW2UZQV6.js} +10 -6
- package/dist/chunk-NW2UZQV6.js.map +1 -0
- package/dist/{chunk-TBSIJVSN.js → chunk-PIK47622.js} +37 -17
- package/dist/chunk-PIK47622.js.map +1 -0
- package/dist/{chunk-BKU34KYY.js → chunk-QXFNLKJJ.js} +9 -3
- package/dist/{chunk-BKU34KYY.js.map → chunk-QXFNLKJJ.js.map} +1 -1
- package/dist/{chunk-BYCLD6D6.js → chunk-SB4QTF2T.js} +98 -54
- package/dist/chunk-SB4QTF2T.js.map +1 -0
- package/dist/{chunk-VATTS2MR.js → chunk-SENASAU4.js} +10 -6
- package/dist/{chunk-VATTS2MR.js.map → chunk-SENASAU4.js.map} +1 -1
- package/dist/{dist-34RKQ74M.js → dist-4IQFJJQI.js} +5 -5
- package/dist/{dist-4DPOL5A7.js → dist-7YB7BMNG.js} +5 -5
- package/dist/{dist-3IMQNTTV.js → dist-SL2QSMBE.js} +5 -5
- package/dist/{dist-J2IHD5T7.js → dist-VHI5QOSQ.js} +6 -6
- package/dist/{dist-57M6ZA7H.js → dist-XC47DSCR.js} +5 -5
- package/dist/index.js +1043 -333
- package/dist/index.js.map +1 -1
- package/dist/{prepared-state-MQHD3M5F-Q27AZU53.js → prepared-state-MQHD3M5F-2LANTRL7.js} +2 -2
- package/package.json +6 -5
- package/runtime/docker/Dockerfile.box +21 -2
- package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +112 -29
- package/runtime/docker/packages/ctl/dist/bin.cjs +10353 -8575
- package/runtime/docker/packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup +5 -2
- package/runtime/docker/packages/sandbox-docker/scripts/linear-shim +181 -0
- package/runtime/docker/packages/sandbox-docker/scripts/ntn-shim +95 -0
- package/runtime/e2b/agentbox-checkpoint-cleanup +5 -2
- package/runtime/e2b/agentbox-setup-skill.md +112 -29
- package/runtime/e2b/ctl.cjs +10353 -8575
- package/runtime/e2b/linear-shim +181 -0
- package/runtime/e2b/ntn-shim +95 -0
- package/runtime/e2b/scripts/build-template.sh +13 -7
- package/runtime/hetzner/agentbox-checkpoint-cleanup +5 -2
- package/runtime/hetzner/agentbox-setup-skill.md +112 -29
- package/runtime/hetzner/ctl.cjs +10353 -8575
- package/runtime/hetzner/linear-shim +181 -0
- package/runtime/hetzner/ntn-shim +95 -0
- package/runtime/hetzner/scripts/install-box.sh +19 -9
- package/runtime/relay/bin.cjs +3707 -2828
- package/runtime/vercel/agentbox-checkpoint-cleanup +5 -2
- package/runtime/vercel/agentbox-setup-skill.md +112 -29
- package/runtime/vercel/ctl.cjs +10353 -8575
- package/runtime/vercel/linear-shim +181 -0
- package/runtime/vercel/ntn-shim +95 -0
- package/runtime/vercel/scripts/provision.sh +13 -7
- package/share/agentbox-setup/SKILL.md +112 -29
- package/share/host-skills/agentbox-info/SKILL.md +22 -2
- package/dist/chunk-BYCLD6D6.js.map +0 -1
- package/dist/chunk-LDMYHWUS.js.map +0 -1
- package/dist/chunk-TBSIJVSN.js.map +0 -1
- package/dist/chunk-TCS5HXJX.js.map +0 -1
- package/dist/chunk-XKH7NTT7.js.map +0 -1
- /package/dist/{_cloud-attach-GUBB5RH2.js.map → _cloud-attach-5KJWOASL.js.map} +0 -0
- /package/dist/{chunk-RSKG7AFU.js.map → chunk-3WCEB6RE.js.map} +0 -0
- /package/dist/{dist-34RKQ74M.js.map → dist-4IQFJJQI.js.map} +0 -0
- /package/dist/{dist-4DPOL5A7.js.map → dist-7YB7BMNG.js.map} +0 -0
- /package/dist/{dist-3IMQNTTV.js.map → dist-SL2QSMBE.js.map} +0 -0
- /package/dist/{dist-J2IHD5T7.js.map → dist-VHI5QOSQ.js.map} +0 -0
- /package/dist/{dist-57M6ZA7H.js.map → dist-XC47DSCR.js.map} +0 -0
- /package/dist/{prepared-state-MQHD3M5F-Q27AZU53.js.map → prepared-state-MQHD3M5F-2LANTRL7.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,114 @@ Entries are generated from the commit history with `/release-notes` and then
|
|
|
9
9
|
hand-reviewed — they describe what changed for someone using the `agentbox`
|
|
10
10
|
CLI, not the raw commits.
|
|
11
11
|
|
|
12
|
+
## [0.16.0] - 2026-06-07
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **Notion integration.** A box can now call Notion through the host's
|
|
17
|
+
authenticated `ntn` CLI without the Notion token ever entering the box. The
|
|
18
|
+
in-box `ntn`/`notion` shim proxies to the host relay: reads pass straight
|
|
19
|
+
through, writes (`pages create`/`pages update`) prompt for host approval.
|
|
20
|
+
`ntn api` is read-only — GET to any endpoint plus the read-only POSTs
|
|
21
|
+
`v1/search`, `v1/databases/<id>/query`, and `v1/data_sources/<id>/query`
|
|
22
|
+
(full JSON bodies via `-d '<json>'`); every other method/endpoint is refused.
|
|
23
|
+
Off by default; enable per project with
|
|
24
|
+
`agentbox config set --project integrations.notion.enabled true`. Shows up in
|
|
25
|
+
`agentbox doctor`.
|
|
26
|
+
- **Linear integration.** Same model for `@schpet/linear-cli`: read issues,
|
|
27
|
+
teams, and filtered queries plus a GraphQL **query** passthrough
|
|
28
|
+
(`linear api`); `mutation`/`subscription` are refused. `issue create`/
|
|
29
|
+
`update`/`comment add` prompt for host approval; `auth token` is hard-rejected
|
|
30
|
+
so the key stays on the host. Enable with `integrations.linear.enabled`.
|
|
31
|
+
- **`run_once:` tasks** in `agentbox.yaml` (renamed from `idempotent:`): a task
|
|
32
|
+
that runs only on a cold box and is skipped on warm boots, tracked by a
|
|
33
|
+
durable marker.
|
|
34
|
+
- **`agentbox.yaml` replacement engine** with an `{{AGENTBOX_AUTO_SECRET}}`
|
|
35
|
+
generator (stable per-project secret) and a new `agentbox render` command to
|
|
36
|
+
preview the resolved file. Replacements also apply to `carry:` targets.
|
|
37
|
+
- **Docker `image:` services.** Sidecar containers declared under `image:` now
|
|
38
|
+
take their `ports`/`env` nested under `image:` as well, keeping all
|
|
39
|
+
image-level config in one place.
|
|
40
|
+
- **Codex plugin marketplace.** AgentBox installs as a Codex plugin straight
|
|
41
|
+
from the repo (`codex plugin marketplace add madarco/agentbox`).
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- `carry:` and `agentbox cp` copy files via `docker exec tar` instead of
|
|
46
|
+
`docker cp`, fixing "read/write on closed pipe" failures into the
|
|
47
|
+
bind-mounted workspace and relative-path targets (e.g. `./backups/...`).
|
|
48
|
+
- `agentbox doctor` integration probes are time-bounded and stdin-isolated, so
|
|
49
|
+
doctor no longer hangs when a connector's auth check blocks; a timed-out
|
|
50
|
+
probe now reports a timeout rather than "not logged in".
|
|
51
|
+
|
|
52
|
+
### Security
|
|
53
|
+
|
|
54
|
+
- The Notion `ntn api` gate is fail-closed: it refuses any unrecognized flag
|
|
55
|
+
rather than ignoring it, closing a bypass where ntn's value-consuming global
|
|
56
|
+
flags (`--workers-config-file`, `--env`) could shift the real request
|
|
57
|
+
endpoint past the read classification. Host-file (`--file`/`--input`) bodies
|
|
58
|
+
and `.`/`..` path segments are refused.
|
|
59
|
+
|
|
60
|
+
## [0.15.0] - 2026-06-05
|
|
61
|
+
|
|
62
|
+
### Breaking
|
|
63
|
+
|
|
64
|
+
- Carry and `cp` now share a single size cap. The `AGENTBOX_CARRY_MAX_BYTES`
|
|
65
|
+
env var is removed; both the `carry:` step and `agentbox cp` are governed by
|
|
66
|
+
the `box.cpMaxBytes` config key (default 100 MiB, up from carry's old 50 MiB).
|
|
67
|
+
Scripts that set `AGENTBOX_CARRY_MAX_BYTES` no longer have any effect — set
|
|
68
|
+
`box.cpMaxBytes` instead.
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
|
|
72
|
+
- `queue.openIn` config key: when a background `-i` job's box becomes ready,
|
|
73
|
+
optionally open an attached terminal onto it — `split`, `window`, or `tab`
|
|
74
|
+
(default `none`, the previous behavior). Fires only when you submit from
|
|
75
|
+
inside tmux, cmux, or iTerm2.
|
|
76
|
+
- `agentbox cp` (and the `carry:` copy step) now stream the tar instead of
|
|
77
|
+
buffering it, so copies are no longer capped by Node's buffer limit (large
|
|
78
|
+
folders that silently failed with "tar: Write error" now work). Added a
|
|
79
|
+
repeatable `--exclude=<glob|name>` and `--no-default-excludes`; heavy
|
|
80
|
+
regenerable dirs (`.git`, `node_modules`, `dist`, `.next`, `target`, …) are
|
|
81
|
+
excluded by default. Copies larger than `box.cpMaxBytes` are blocked with a
|
|
82
|
+
du-style tree of the biggest folders and a suggested strategy unless `--yes`.
|
|
83
|
+
- `agentbox agent approvals` / `agentbox agent approve`: inspect and answer
|
|
84
|
+
relay host-action confirmations (git push, `cp`, `gh` PR writes, checkpoint)
|
|
85
|
+
from a host orchestrator, instead of hand-curling the loopback endpoint.
|
|
86
|
+
Prompt ids are content-derived, so a prompt that changed since you listed it
|
|
87
|
+
is refused rather than mis-answered. Adds an opt-in per-box
|
|
88
|
+
`box.autoApproveHostActions` (default off, audited) for unattended runs.
|
|
89
|
+
- The attach footer's `(...)` slot now shows aggregate box service status —
|
|
90
|
+
`starting N/M…` while services boot, `service error` on a crash/failed task,
|
|
91
|
+
`ready` once all are up (probe-aware: a `ready_when` service counts as up only
|
|
92
|
+
once its probe passes, so the footer no longer flashes `ready` early). Boxes
|
|
93
|
+
with no services fall back to the agent activity label.
|
|
94
|
+
|
|
95
|
+
### Changed
|
|
96
|
+
|
|
97
|
+
- `queue.openIn` under cmux: `split` and `tab` queued jobs now open in the
|
|
98
|
+
workspace you submitted from (split targets the original pane, falling back to
|
|
99
|
+
the parent workspace) instead of always spawning a new top-level workspace.
|
|
100
|
+
`window` still opens a separate workspace.
|
|
101
|
+
- `agentbox config set queue.openIn` now warns that the feature only fires
|
|
102
|
+
inside tmux/cmux/iTerm2, and that cmux additionally needs `socketControlMode`
|
|
103
|
+
set to `automation`/`password` plus `cmux reload-config`.
|
|
104
|
+
|
|
105
|
+
### Fixed
|
|
106
|
+
|
|
107
|
+
- The `carry:` block is now documented in the published `agentbox.yaml` JSON
|
|
108
|
+
schema, so editors and in-box agents that fetch the schema no longer see it as
|
|
109
|
+
invalid or undiscoverable.
|
|
110
|
+
- The stale default-checkpoint recreate prompt now fires for already-configured
|
|
111
|
+
projects too (it was skipped for them, silently booting old base layers), and
|
|
112
|
+
on recreate it reuses the existing `agentbox.yaml` instead of telling the agent
|
|
113
|
+
to regenerate a config that already exists.
|
|
114
|
+
- `agentbox cp` now enforces `box.cpMaxBytes` on single-file uploads, not just
|
|
115
|
+
directories.
|
|
116
|
+
- A supervisor screen-scrape safety net flips a stuck Claude `working` state to
|
|
117
|
+
`waiting` when its hooks miss a prompt (MCP dialogs, dropped notifications), so
|
|
118
|
+
`agent wait-for input-needed` reliably wakes.
|
|
119
|
+
|
|
12
120
|
## [0.14.0] - 2026-06-04
|
|
13
121
|
|
|
14
122
|
### Added
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
buildCloudAttachInnerCommand,
|
|
4
4
|
cloudAgentAttach,
|
|
5
5
|
cloudAgentStartDetached
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-SB4QTF2T.js";
|
|
7
|
+
import "./chunk-GXJNJUEV.js";
|
|
8
|
+
import "./chunk-DBBUDKKB.js";
|
|
9
9
|
import "./chunk-G3H2L3O2.js";
|
|
10
10
|
export {
|
|
11
11
|
buildCloudAttachInnerCommand,
|
|
12
12
|
cloudAgentAttach,
|
|
13
13
|
cloudAgentStartDetached
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=_cloud-attach-
|
|
15
|
+
//# sourceMappingURL=_cloud-attach-5KJWOASL.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
readPreparedStateRaw,
|
|
8
8
|
resolveContextFilesFrom,
|
|
9
9
|
writePreparedStateRaw
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-DBBUDKKB.js";
|
|
11
11
|
|
|
12
12
|
// ../../packages/sandbox-daytona/dist/chunk-35HJOOGT.js
|
|
13
13
|
import { existsSync } from "fs";
|
|
@@ -830,4 +830,4 @@ export {
|
|
|
830
830
|
writePreparedDaytonaState,
|
|
831
831
|
preparedMatches
|
|
832
832
|
};
|
|
833
|
-
//# sourceMappingURL=chunk-
|
|
833
|
+
//# sourceMappingURL=chunk-3WCEB6RE.js.map
|
|
@@ -1,5 +1,195 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// ../../packages/core/dist/index.js
|
|
4
|
+
import { randomBytes } from "crypto";
|
|
5
|
+
var claudeCodeLauncher = {
|
|
6
|
+
kind: "claude-code",
|
|
7
|
+
// claude treats its first positional argument as the seed user turn in
|
|
8
|
+
// interactive mode (`claude "<message>"`), so we slot the initial message
|
|
9
|
+
// ahead of any user-passed flags.
|
|
10
|
+
buildArgs(initialMessage, userArgs) {
|
|
11
|
+
if (!initialMessage) return [...userArgs];
|
|
12
|
+
return [initialMessage, ...userArgs];
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var codexLauncher = {
|
|
16
|
+
kind: "codex",
|
|
17
|
+
buildArgs(initialMessage, userArgs) {
|
|
18
|
+
if (!initialMessage) return [...userArgs];
|
|
19
|
+
return [initialMessage, ...userArgs];
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var opencodeLauncher = {
|
|
23
|
+
kind: "opencode",
|
|
24
|
+
buildArgs(initialMessage, userArgs) {
|
|
25
|
+
if (!initialMessage) return [...userArgs];
|
|
26
|
+
return [initialMessage, ...userArgs];
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
function resolveAgentLauncher(kind) {
|
|
30
|
+
if (kind === "claude-code") return claudeCodeLauncher;
|
|
31
|
+
if (kind === "codex") return codexLauncher;
|
|
32
|
+
if (kind === "opencode") return opencodeLauncher;
|
|
33
|
+
throw new Error(`unknown agent kind: ${String(kind)}`);
|
|
34
|
+
}
|
|
35
|
+
var PLACEHOLDER_KEYS = [
|
|
36
|
+
"AGENTBOX_BOX_NAME",
|
|
37
|
+
"AGENTBOX_BOX_ID",
|
|
38
|
+
"AGENTBOX_BOX_KIND",
|
|
39
|
+
"AGENTBOX_HOST_WORKSPACE",
|
|
40
|
+
"AGENTBOX_PROJECT_ROOT",
|
|
41
|
+
// Convenience: the portless host this box publishes (`<box-name>.localhost`).
|
|
42
|
+
// Derived from AGENTBOX_BOX_NAME when not set explicitly.
|
|
43
|
+
"AGENTBOX_BOX_HOST"
|
|
44
|
+
];
|
|
45
|
+
var PLACEHOLDER_SET = new Set(PLACEHOLDER_KEYS);
|
|
46
|
+
var ReplaceError = class extends Error {
|
|
47
|
+
constructor(message) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.name = "ReplaceError";
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var PLACEHOLDER_RE = /\{\{\s*([A-Z0-9_]+)\s*\}\}/g;
|
|
53
|
+
function substitutePlaceholders(text, context, onWarn) {
|
|
54
|
+
return text.replace(PLACEHOLDER_RE, (match, name) => {
|
|
55
|
+
if (!PLACEHOLDER_SET.has(name)) return match;
|
|
56
|
+
const value = context[name];
|
|
57
|
+
if (value === void 0) {
|
|
58
|
+
onWarn?.(`placeholder {{${name}}} has no value in this context \u2014 left untouched`);
|
|
59
|
+
return match;
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function applyReplacements(content, opts) {
|
|
65
|
+
let out = content;
|
|
66
|
+
if (opts.env) {
|
|
67
|
+
out = substitutePlaceholders(out, opts.context, opts.onWarn);
|
|
68
|
+
}
|
|
69
|
+
for (const rule of opts.rules ?? []) {
|
|
70
|
+
const to = substitutePlaceholders(rule.to, opts.context, opts.onWarn);
|
|
71
|
+
if (rule.regex) {
|
|
72
|
+
let re;
|
|
73
|
+
try {
|
|
74
|
+
re = new RegExp(rule.from, rule.flags ?? "g");
|
|
75
|
+
} catch (err) {
|
|
76
|
+
throw new ReplaceError(
|
|
77
|
+
`invalid regex "${rule.from}": ${err instanceof Error ? err.message : String(err)}`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
out = out.replace(re, to);
|
|
81
|
+
} else {
|
|
82
|
+
out = out.split(rule.from).join(to);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
function deriveBoxHost(ctx) {
|
|
88
|
+
if (ctx.AGENTBOX_BOX_HOST === void 0 && ctx.AGENTBOX_BOX_NAME !== void 0) {
|
|
89
|
+
ctx.AGENTBOX_BOX_HOST = `${ctx.AGENTBOX_BOX_NAME}.localhost`;
|
|
90
|
+
}
|
|
91
|
+
return ctx;
|
|
92
|
+
}
|
|
93
|
+
function isPlainObject(v) {
|
|
94
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
95
|
+
}
|
|
96
|
+
var RULE_KEYS = /* @__PURE__ */ new Set(["from", "to", "regex", "flags"]);
|
|
97
|
+
function parseReplaceRule(raw, where) {
|
|
98
|
+
if (!isPlainObject(raw)) {
|
|
99
|
+
throw new ReplaceError(`${where} must be a mapping with at least { from, to }`);
|
|
100
|
+
}
|
|
101
|
+
for (const key of Object.keys(raw)) {
|
|
102
|
+
if (!RULE_KEYS.has(key)) throw new ReplaceError(`${where} has unknown key "${key}"`);
|
|
103
|
+
}
|
|
104
|
+
if (typeof raw.from !== "string" || raw.from.length === 0) {
|
|
105
|
+
throw new ReplaceError(`${where}.from must be a non-empty string`);
|
|
106
|
+
}
|
|
107
|
+
if (typeof raw.to !== "string") {
|
|
108
|
+
throw new ReplaceError(`${where}.to must be a string`);
|
|
109
|
+
}
|
|
110
|
+
const rule = { from: raw.from, to: raw.to };
|
|
111
|
+
if (raw.regex !== void 0 && raw.regex !== null) {
|
|
112
|
+
if (typeof raw.regex !== "boolean") throw new ReplaceError(`${where}.regex must be a boolean`);
|
|
113
|
+
rule.regex = raw.regex;
|
|
114
|
+
}
|
|
115
|
+
if (raw.flags !== void 0 && raw.flags !== null) {
|
|
116
|
+
if (typeof raw.flags !== "string") throw new ReplaceError(`${where}.flags must be a string`);
|
|
117
|
+
rule.flags = raw.flags;
|
|
118
|
+
}
|
|
119
|
+
if (rule.regex) {
|
|
120
|
+
try {
|
|
121
|
+
new RegExp(rule.from, rule.flags ?? "g");
|
|
122
|
+
} catch (err) {
|
|
123
|
+
throw new ReplaceError(
|
|
124
|
+
`${where}.from is not a valid regex: ${err instanceof Error ? err.message : String(err)}`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return rule;
|
|
129
|
+
}
|
|
130
|
+
function parseReplaceRules(raw, where) {
|
|
131
|
+
if (raw === void 0 || raw === null) return [];
|
|
132
|
+
if (!Array.isArray(raw)) throw new ReplaceError(`${where} must be a list of rules`);
|
|
133
|
+
return raw.map((r, i) => parseReplaceRule(r, `${where}[${String(i)}]`));
|
|
134
|
+
}
|
|
135
|
+
function parseReplacements(raw) {
|
|
136
|
+
if (raw === void 0 || raw === null) return {};
|
|
137
|
+
if (!isPlainObject(raw)) {
|
|
138
|
+
throw new ReplaceError("replacements must be a mapping of name \u2192 rule list");
|
|
139
|
+
}
|
|
140
|
+
const out = {};
|
|
141
|
+
for (const [name, rules] of Object.entries(raw)) {
|
|
142
|
+
if (!/^[A-Za-z0-9_-]+$/.test(name)) {
|
|
143
|
+
throw new ReplaceError(`replacements.${name}: name must match [A-Za-z0-9_-]+`);
|
|
144
|
+
}
|
|
145
|
+
out[name] = parseReplaceRules(rules, `replacements.${name}`);
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
function resolveRuleRefs(refs, replacements, where) {
|
|
150
|
+
const out = [];
|
|
151
|
+
for (const name of refs) {
|
|
152
|
+
const set = replacements[name];
|
|
153
|
+
if (set === void 0) {
|
|
154
|
+
const known = Object.keys(replacements);
|
|
155
|
+
throw new ReplaceError(
|
|
156
|
+
`${where}: unknown replacements rule-set "${name}"` + (known.length > 0 ? ` (known: ${known.join(", ")})` : " (none declared)")
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
out.push(...set);
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
var UserFacingError = class extends Error {
|
|
164
|
+
constructor(message) {
|
|
165
|
+
super(message);
|
|
166
|
+
this.name = "UserFacingError";
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var BoxNotFoundError = class extends Error {
|
|
170
|
+
constructor(query) {
|
|
171
|
+
super(`no agentbox matches "${query}"`);
|
|
172
|
+
this.query = query;
|
|
173
|
+
this.name = "BoxNotFoundError";
|
|
174
|
+
}
|
|
175
|
+
query;
|
|
176
|
+
};
|
|
177
|
+
var AmbiguousBoxError = class extends Error {
|
|
178
|
+
constructor(query, matches) {
|
|
179
|
+
const ids = matches.map((m) => m.id).join(", ");
|
|
180
|
+
super(`"${query}" matches multiple boxes: ${ids}`);
|
|
181
|
+
this.query = query;
|
|
182
|
+
this.matches = matches;
|
|
183
|
+
this.name = "AmbiguousBoxError";
|
|
184
|
+
}
|
|
185
|
+
query;
|
|
186
|
+
matches;
|
|
187
|
+
};
|
|
188
|
+
var BOX_ID_PREFIX = "b";
|
|
189
|
+
function generateBoxId() {
|
|
190
|
+
return `${BOX_ID_PREFIX}${randomBytes(4).toString("hex")}`;
|
|
191
|
+
}
|
|
192
|
+
|
|
3
193
|
// ../../packages/sandbox-core/dist/index.js
|
|
4
194
|
import { mkdir, open, readFile, rename, rm, stat, writeFile } from "fs/promises";
|
|
5
195
|
import { homedir } from "os";
|
|
@@ -8,9 +198,12 @@ import { setTimeout as delay } from "timers/promises";
|
|
|
8
198
|
import { execa } from "execa";
|
|
9
199
|
import { readdir, stat as stat2 } from "fs/promises";
|
|
10
200
|
import { join as join2 } from "path";
|
|
201
|
+
import { mkdtemp, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
202
|
+
import { tmpdir } from "os";
|
|
203
|
+
import { basename, join as join3 } from "path";
|
|
11
204
|
import { createHash } from "crypto";
|
|
12
205
|
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
13
|
-
import { readFile as
|
|
206
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
14
207
|
import { homedir as homedir2 } from "os";
|
|
15
208
|
import { dirname as dirname2, resolve as pathResolve } from "path";
|
|
16
209
|
var STATE_DIR = join(homedir(), ".agentbox");
|
|
@@ -238,6 +431,46 @@ var GitWorktreeError = class extends Error {
|
|
|
238
431
|
function hostOpenCommand() {
|
|
239
432
|
return process.platform === "linux" ? "xdg-open" : "open";
|
|
240
433
|
}
|
|
434
|
+
function carryPlaceholderContext(ctx) {
|
|
435
|
+
const out = {};
|
|
436
|
+
if (ctx.name) out.AGENTBOX_BOX_NAME = ctx.name;
|
|
437
|
+
if (ctx.id) out.AGENTBOX_BOX_ID = ctx.id;
|
|
438
|
+
if (ctx.kind) out.AGENTBOX_BOX_KIND = ctx.kind;
|
|
439
|
+
if (ctx.hostWorkspace) out.AGENTBOX_HOST_WORKSPACE = ctx.hostWorkspace;
|
|
440
|
+
if (ctx.projectRoot) out.AGENTBOX_PROJECT_ROOT = ctx.projectRoot;
|
|
441
|
+
return deriveBoxHost(out);
|
|
442
|
+
}
|
|
443
|
+
function wantsRender(e) {
|
|
444
|
+
return e.kind === "file" && (!!e.replaceEnvs || (e.replace?.length ?? 0) > 0);
|
|
445
|
+
}
|
|
446
|
+
async function renderCarryEntries(entries, ctx, onLog) {
|
|
447
|
+
if (!entries.some(wantsRender)) return entries;
|
|
448
|
+
const context = carryPlaceholderContext(ctx);
|
|
449
|
+
const stage = await mkdtemp(join3(tmpdir(), "agentbox-carry-render-"));
|
|
450
|
+
const out = [];
|
|
451
|
+
for (const [i, entry] of entries.entries()) {
|
|
452
|
+
if (!wantsRender(entry)) {
|
|
453
|
+
out.push(entry);
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
const content = await readFile2(entry.absSrc, "utf8");
|
|
457
|
+
const rendered = applyReplacements(content, {
|
|
458
|
+
env: entry.replaceEnvs,
|
|
459
|
+
rules: entry.replace,
|
|
460
|
+
context,
|
|
461
|
+
onWarn: (msg) => onLog?.(`carry: ${entry.rawSrc}: ${msg}`)
|
|
462
|
+
});
|
|
463
|
+
const tmp = join3(stage, `${String(i)}-${basename(entry.absSrc)}`);
|
|
464
|
+
await writeFile2(tmp, rendered, "utf8");
|
|
465
|
+
out.push({ ...entry, absSrc: tmp, bytes: Buffer.byteLength(rendered) });
|
|
466
|
+
const what = [
|
|
467
|
+
...entry.replaceEnvs ? ["env"] : [],
|
|
468
|
+
...entry.replace?.length ? [`${String(entry.replace.length)} rule(s)`] : []
|
|
469
|
+
].join("+");
|
|
470
|
+
onLog?.(`carry: rendered ${entry.rawSrc} (${what})`);
|
|
471
|
+
}
|
|
472
|
+
return out;
|
|
473
|
+
}
|
|
241
474
|
function preparedStatePathFor(provider) {
|
|
242
475
|
return pathResolve(homedir2(), ".agentbox", `${provider}-prepared.json`);
|
|
243
476
|
}
|
|
@@ -259,7 +492,7 @@ function writePreparedStateRaw(provider, state) {
|
|
|
259
492
|
renameSync(tmp, path);
|
|
260
493
|
}
|
|
261
494
|
async function sha256OfFile(path) {
|
|
262
|
-
const buf = await
|
|
495
|
+
const buf = await readFile3(path);
|
|
263
496
|
return createHash("sha256").update(buf).digest("hex");
|
|
264
497
|
}
|
|
265
498
|
async function computeContextSha256(files) {
|
|
@@ -430,7 +663,7 @@ async function buildImage(opts = {}) {
|
|
|
430
663
|
return ref;
|
|
431
664
|
}
|
|
432
665
|
async function pullOrBuild(ref, fingerprint, opts = {}) {
|
|
433
|
-
const { writePreparedDockerState: writePreparedDockerState2 } = await import("./prepared-state-MQHD3M5F-
|
|
666
|
+
const { writePreparedDockerState: writePreparedDockerState2 } = await import("./prepared-state-MQHD3M5F-2LANTRL7.js");
|
|
434
667
|
const registry = opts.registry ?? BOX_IMAGE_REGISTRY;
|
|
435
668
|
const allowPull = opts.allowPull !== false;
|
|
436
669
|
if (allowPull && registry && fingerprint) {
|
|
@@ -456,7 +689,7 @@ async function pullOrBuild(ref, fingerprint, opts = {}) {
|
|
|
456
689
|
return { source: "built" };
|
|
457
690
|
}
|
|
458
691
|
async function ensureImage(ref = DEFAULT_BOX_IMAGE, opts = {}) {
|
|
459
|
-
const { computeDockerContextFingerprint: computeDockerContextFingerprint2, readPreparedDockerState: readPreparedDockerState2, preparedMatches: preparedMatches2 } = await import("./prepared-state-MQHD3M5F-
|
|
692
|
+
const { computeDockerContextFingerprint: computeDockerContextFingerprint2, readPreparedDockerState: readPreparedDockerState2, preparedMatches: preparedMatches2 } = await import("./prepared-state-MQHD3M5F-2LANTRL7.js");
|
|
460
693
|
const fingerprint = await computeDockerContextFingerprint2({
|
|
461
694
|
contextDir: opts.contextDir
|
|
462
695
|
});
|
|
@@ -526,6 +759,15 @@ function preparedMatches(state, current) {
|
|
|
526
759
|
}
|
|
527
760
|
|
|
528
761
|
export {
|
|
762
|
+
resolveAgentLauncher,
|
|
763
|
+
ReplaceError,
|
|
764
|
+
parseReplaceRules,
|
|
765
|
+
parseReplacements,
|
|
766
|
+
resolveRuleRefs,
|
|
767
|
+
UserFacingError,
|
|
768
|
+
BoxNotFoundError,
|
|
769
|
+
AmbiguousBoxError,
|
|
770
|
+
generateBoxId,
|
|
529
771
|
STATE_DIR,
|
|
530
772
|
STATE_FILE,
|
|
531
773
|
readState,
|
|
@@ -540,6 +782,7 @@ export {
|
|
|
540
782
|
pickFreshBranch,
|
|
541
783
|
GitWorktreeError,
|
|
542
784
|
hostOpenCommand,
|
|
785
|
+
renderCarryEntries,
|
|
543
786
|
preparedStatePathFor,
|
|
544
787
|
readPreparedStateRaw,
|
|
545
788
|
writePreparedStateRaw,
|
|
@@ -563,4 +806,4 @@ export {
|
|
|
563
806
|
writePreparedDockerState,
|
|
564
807
|
preparedMatches
|
|
565
808
|
};
|
|
566
|
-
//# sourceMappingURL=chunk-
|
|
809
|
+
//# sourceMappingURL=chunk-DBBUDKKB.js.map
|