lastlight 0.4.0 → 0.6.1
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/.claude-plugin/marketplace.json +14 -0
- package/README.md +56 -6
- package/agent-context/rules.md +0 -38
- package/agent-context/soul.md +0 -11
- package/deploy/entrypoint.sh +21 -6
- package/deploy/sandbox-entrypoint.sh +1 -1
- package/dist/cli.js +24 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +13 -2
- package/dist/config.js +29 -9
- package/dist/config.js.map +1 -1
- package/dist/connectors/messaging/base.js +22 -9
- package/dist/connectors/messaging/base.js.map +1 -1
- package/dist/connectors/slack/connector.d.ts +62 -9
- package/dist/connectors/slack/connector.js +216 -63
- package/dist/connectors/slack/connector.js.map +1 -1
- package/dist/connectors/slack/connector.test.d.ts +1 -0
- package/dist/connectors/slack/connector.test.js +135 -0
- package/dist/connectors/slack/connector.test.js.map +1 -0
- package/dist/connectors/types.d.ts +7 -0
- package/dist/engine/agent-executor.d.ts +29 -144
- package/dist/engine/agent-executor.js +280 -962
- package/dist/engine/agent-executor.js.map +1 -1
- package/dist/engine/agent-executor.seam.test.d.ts +1 -0
- package/dist/engine/agent-executor.seam.test.js +57 -0
- package/dist/engine/agent-executor.seam.test.js.map +1 -0
- package/dist/engine/dispatcher.d.ts +13 -0
- package/dist/engine/dispatcher.js +26 -7
- package/dist/engine/dispatcher.js.map +1 -1
- package/dist/engine/dispatcher.test.js.map +1 -1
- package/dist/engine/executors/backends.d.ts +41 -0
- package/dist/engine/executors/backends.js +541 -0
- package/dist/engine/executors/backends.js.map +1 -0
- package/dist/engine/executors/shared.d.ts +189 -0
- package/dist/engine/executors/shared.js +612 -0
- package/dist/engine/executors/shared.js.map +1 -0
- package/dist/engine/message-batcher.d.ts +32 -0
- package/dist/engine/message-batcher.js +109 -0
- package/dist/engine/message-batcher.js.map +1 -0
- package/dist/engine/message-batcher.test.d.ts +1 -0
- package/dist/engine/message-batcher.test.js +109 -0
- package/dist/engine/message-batcher.test.js.map +1 -0
- package/dist/engine/profiles.d.ts +9 -0
- package/dist/engine/profiles.js.map +1 -1
- package/dist/evals-api.d.ts +24 -0
- package/dist/evals-api.js +22 -0
- package/dist/evals-api.js.map +1 -0
- package/dist/index.js +41 -4
- package/dist/index.js.map +1 -1
- package/dist/sandbox/command-exec.integration.test.d.ts +1 -0
- package/dist/sandbox/command-exec.integration.test.js +183 -0
- package/dist/sandbox/command-exec.integration.test.js.map +1 -0
- package/dist/sandbox/docker.d.ts +32 -0
- package/dist/sandbox/docker.js +109 -4
- package/dist/sandbox/docker.js.map +1 -1
- package/dist/sandbox/index.d.ts +1 -1
- package/dist/sandbox/index.js +1 -1
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/smol.d.ts +162 -0
- package/dist/sandbox/smol.integration.test.d.ts +1 -0
- package/dist/sandbox/smol.integration.test.js +130 -0
- package/dist/sandbox/smol.integration.test.js.map +1 -0
- package/dist/sandbox/smol.js +485 -0
- package/dist/sandbox/smol.js.map +1 -0
- package/dist/skills-install.d.ts +12 -0
- package/dist/skills-install.js +179 -0
- package/dist/skills-install.js.map +1 -0
- package/dist/workflows/loader.test.js +83 -0
- package/dist/workflows/loader.test.js.map +1 -1
- package/dist/workflows/phase-executor.d.ts +28 -3
- package/dist/workflows/phase-executor.js +170 -45
- package/dist/workflows/phase-executor.js.map +1 -1
- package/dist/workflows/phase-executor.test.js +64 -1
- package/dist/workflows/phase-executor.test.js.map +1 -1
- package/dist/workflows/runner.test.js +32 -27
- package/dist/workflows/runner.test.js.map +1 -1
- package/dist/workflows/schema.d.ts +20 -0
- package/dist/workflows/schema.js +72 -2
- package/dist/workflows/schema.js.map +1 -1
- package/package.json +15 -3
- package/plugins/lastlight/.claude-plugin/plugin.json +12 -0
- package/plugins/lastlight/README.md +44 -0
- package/plugins/lastlight/skills/lastlight-client/SKILL.md +82 -0
- package/plugins/lastlight/skills/lastlight-evals/SKILL.md +97 -0
- package/plugins/lastlight/skills/lastlight-evals/references/instance-schema.md +84 -0
- package/plugins/lastlight/skills/lastlight-evals/references/models-json.md +42 -0
- package/plugins/lastlight/skills/lastlight-overlay/SKILL.md +72 -0
- package/plugins/lastlight/skills/lastlight-overlay/references/forking.md +55 -0
- package/plugins/lastlight/skills/lastlight-overlay/references/overlay-layout.md +52 -0
- package/plugins/lastlight/skills/lastlight-server/SKILL.md +124 -0
- package/plugins/lastlight/skills/lastlight-server/references/env-schema.md +103 -0
- package/plugins/lastlight/skills/lastlight-server/references/operations.md +60 -0
- package/sandbox.Dockerfile +7 -0
- package/skills/browser-qa/scripts/agent-browser.mjs +15 -0
- package/skills/demo/SKILL.md +45 -19
- package/skills/demo/scripts/compose-demo.sh +77 -39
- package/workflows/examples/bash-smoke.yaml +41 -0
- package/workflows/prompts/demo.md +27 -5
- package/workflows/qa-test.yaml +1 -1
- package/workflows/verify.yaml +1 -1
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
import { execFileSync, execFile as execFileCb, spawn } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
import { lookup } from "node:dns/promises";
|
|
4
|
+
import { existsSync, readdirSync } from "fs";
|
|
5
|
+
import { join, resolve } from "path";
|
|
6
|
+
import { randomUUID } from "crypto";
|
|
7
|
+
const execFileAsync = promisify(execFileCb);
|
|
8
|
+
/**
|
|
9
|
+
* smolvm sandbox manager — runs agent tasks inside local micro-VMs.
|
|
10
|
+
*
|
|
11
|
+
* Structural peer of {@link DockerSandbox}: Last Light owns the isolation
|
|
12
|
+
* boundary, bind-mounts the per-task workspace, runs `agentic-pi run --sandbox
|
|
13
|
+
* none` *inside* the machine, and parses the JSONL event stream exactly as the
|
|
14
|
+
* docker path does. Differences from docker:
|
|
15
|
+
*
|
|
16
|
+
* - **Isolation** is a real micro-VM (own kernel) via smolvm's host
|
|
17
|
+
* hypervisor (Apple Silicon Hypervisor.framework / Linux KVM), not a
|
|
18
|
+
* sibling container. No daemon, no Docker (smolvm drives the hypervisor
|
|
19
|
+
* directly).
|
|
20
|
+
* - **Egress** is enforced natively per-machine via `--allow-host` (sourced
|
|
21
|
+
* from `egress-allowlist.ts`), so this backend needs none of the coredns +
|
|
22
|
+
* nginx-egress sidecar stack. `--allow-host` implies `--net`; we always
|
|
23
|
+
* enable networking (the agent must reach the LLM provider).
|
|
24
|
+
* - **Secrets** (provider keys, GITHUB_TOKEN) are injected via smolvm's
|
|
25
|
+
* `--secret-env GUEST=HOST` so values never appear on the argv — the host
|
|
26
|
+
* env of the spawned `smolvm` process carries them; smolvm resolves them
|
|
27
|
+
* into the guest at start.
|
|
28
|
+
* - **Image** is whatever `SMOLVM_IMAGE` names. smolvm's `-I` accepts a
|
|
29
|
+
* registry ref OR a local `docker save` archive (`./img.tar`) / unpacked
|
|
30
|
+
* rootfs dir — the latter needs NO registry, so it works under the strict
|
|
31
|
+
* egress allowlist. The lastlight sandbox image (built locally by docker)
|
|
32
|
+
* is consumed offline via `docker save lastlight-sandbox:latest -o img.tar`
|
|
33
|
+
* then `SMOLVM_IMAGE=img.tar`. Archives are cached by hash; `start` resolves
|
|
34
|
+
* from cache, not the network.
|
|
35
|
+
*
|
|
36
|
+
* Driven via the **smolvm CLI** (`execFile`), verified against smolvm 1.2.5.
|
|
37
|
+
*
|
|
38
|
+
* Feasibility-spike scope (documented gaps vs docker):
|
|
39
|
+
* - We exec `agentic-pi` directly rather than running the sandbox image's
|
|
40
|
+
* entrypoint, so the entrypoint's git-credential-helper setup is skipped.
|
|
41
|
+
* Read-only profiles (agentic-pi's built-in github tools + minted
|
|
42
|
+
* GITHUB_TOKEN) work; repo-write `git push` from the workspace is out of
|
|
43
|
+
* scope here.
|
|
44
|
+
* - The workload runs VM-grade (root) by default; workspace writes land as
|
|
45
|
+
* root on the host bind mount. No shared package-manager cache, no SSRF
|
|
46
|
+
* metadata floor in unrestricted mode, no in-network OTEL collector.
|
|
47
|
+
* - The image (`SMOLVM_IMAGE`) must be resolvable by smolvm (a registry ref,
|
|
48
|
+
* or a local image it can load) — see the spike plan's verification steps.
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* Where the per-task workspace is bind-mounted inside the guest. smolvm treats
|
|
52
|
+
* `/workspace` specially — a `-v <host>:/workspace` mount "takes priority" and
|
|
53
|
+
* the host share is used directly (instead of the VM's storage-disk workspace),
|
|
54
|
+
* which avoids the `virtiofs` carve-out other mount targets get. The probe in
|
|
55
|
+
* {@link SmolSandbox.resolveHostWorkspace} still confirms the actual host path.
|
|
56
|
+
*/
|
|
57
|
+
export const SMOL_WORKSPACE_DIR = "/workspace";
|
|
58
|
+
/** Binary used to drive smolvm. Overridable for dev/CI (e.g. a vendored build). */
|
|
59
|
+
function smolBin() {
|
|
60
|
+
return process.env.SMOLVM_BIN || "smolvm";
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* OCI image the micro-VM boots. Reuses the lean lastlight sandbox image by
|
|
64
|
+
* default (agentic-pi + node + git + gh baked in); the image must be
|
|
65
|
+
* resolvable by smolvm (see the spike plan's verification steps).
|
|
66
|
+
*/
|
|
67
|
+
function smolImage() {
|
|
68
|
+
return process.env.SMOLVM_IMAGE || "lastlight-sandbox:latest";
|
|
69
|
+
}
|
|
70
|
+
/** Cached probe — only check the smolvm binary once per process. */
|
|
71
|
+
let _smolAvailable = null;
|
|
72
|
+
/** True when the smolvm CLI is invocable on this host. */
|
|
73
|
+
export function smolAvailable() {
|
|
74
|
+
if (_smolAvailable === null) {
|
|
75
|
+
try {
|
|
76
|
+
execFileSync(smolBin(), ["--version"], { stdio: "ignore", timeout: 5000 });
|
|
77
|
+
_smolAvailable = true;
|
|
78
|
+
console.log(`[smol] smolvm available (image: ${smolImage()})`);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
_smolAvailable = false;
|
|
82
|
+
console.log("[smol] smolvm CLI not available — smol backend unavailable");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return _smolAvailable;
|
|
86
|
+
}
|
|
87
|
+
const THINKING = new Set(["off", "minimal", "low", "medium", "high", "xhigh"]);
|
|
88
|
+
const PROFILES = new Set(["read", "issues-write", "review-write", "repo-write"]);
|
|
89
|
+
const WEB_SEARCH_PROVIDERS = new Set(["tavily", "brave", "exa"]);
|
|
90
|
+
const HOST_RE = /^[A-Za-z0-9.-]+$/;
|
|
91
|
+
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
92
|
+
const PATH_RE = /^[A-Za-z0-9/_.-]+$/;
|
|
93
|
+
export class SmolSandbox {
|
|
94
|
+
config;
|
|
95
|
+
machines = new Map();
|
|
96
|
+
constructor(config) {
|
|
97
|
+
this.config = config;
|
|
98
|
+
}
|
|
99
|
+
/** Create + start a micro-VM with the workspace bind-mounted and egress locked. */
|
|
100
|
+
async create(opts) {
|
|
101
|
+
const machineName = `lastlight-smol-${sanitizeName(opts.taskId)}-${randomUUID().slice(0, 8)}`;
|
|
102
|
+
const worktreePath = resolve(opts.worktreePath);
|
|
103
|
+
// smolvm machine create -n <name> -I <image> -v <host>:<guest> \
|
|
104
|
+
// --net [--allow-host <h>]...
|
|
105
|
+
// smolvm machine start --name <name>
|
|
106
|
+
const allowFlags = (await this.resolvableAllowHosts()).flatMap((h) => ["--allow-host", h]);
|
|
107
|
+
const args = [
|
|
108
|
+
"machine", "create",
|
|
109
|
+
"-n", machineName,
|
|
110
|
+
"-I", this.config.imageName || smolImage(),
|
|
111
|
+
"-v", `${worktreePath}:${SMOL_WORKSPACE_DIR}`,
|
|
112
|
+
"--net",
|
|
113
|
+
...allowFlags,
|
|
114
|
+
];
|
|
115
|
+
try {
|
|
116
|
+
execCmd(smolBin(), args, { timeout: 60_000 });
|
|
117
|
+
execCmd(smolBin(), ["machine", "start", "--name", machineName], { timeout: 120_000 });
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
execSafe(smolBin(), ["machine", "delete", "-f", "--name", machineName]);
|
|
121
|
+
throw new Error(`Failed to create smol sandbox: ${err.message}`);
|
|
122
|
+
}
|
|
123
|
+
console.log(`[smol] Created: ${machineName}`);
|
|
124
|
+
await this.waitForReady(machineName);
|
|
125
|
+
const hostWorkspace = await this.resolveHostWorkspace(machineName, worktreePath);
|
|
126
|
+
const info = { machineName, worktreePath, hostWorkspace };
|
|
127
|
+
this.machines.set(opts.taskId, info);
|
|
128
|
+
return info;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Discover the host directory that backs the guest workspace mount. Writes a
|
|
132
|
+
* sentinel file from inside the guest at {@link SMOL_WORKSPACE_DIR}, then
|
|
133
|
+
* locates it under the mount source on the host — its parent dir is the
|
|
134
|
+
* host-side workspace root. Falls back to the source root if not found
|
|
135
|
+
* (e.g. a future smolvm that shares the source directly and the scan misses).
|
|
136
|
+
*/
|
|
137
|
+
async resolveHostWorkspace(machineName, worktreePath) {
|
|
138
|
+
const sentinel = `.smol-probe-${randomUUID().slice(0, 8)}`;
|
|
139
|
+
try {
|
|
140
|
+
await execFileAsync(smolBin(), ["machine", "exec", "--name", machineName, "--", "sh", "-c", `: > ${SMOL_WORKSPACE_DIR}/${sentinel}`], { timeout: 10_000 });
|
|
141
|
+
const hit = findFileUnder(worktreePath, sentinel, 4);
|
|
142
|
+
await execFileAsync(smolBin(), ["machine", "exec", "--name", machineName, "--", "rm", "-f", `${SMOL_WORKSPACE_DIR}/${sentinel}`], { timeout: 10_000 }).catch(() => { });
|
|
143
|
+
if (hit) {
|
|
144
|
+
const dir = hit.slice(0, hit.length - sentinel.length - 1);
|
|
145
|
+
if (dir !== worktreePath)
|
|
146
|
+
console.log(`[smol] Workspace share lands at ${dir} (not the source root)`);
|
|
147
|
+
return dir;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
console.warn(`[smol] Could not probe workspace mount (${err.message}) — assuming source root`);
|
|
152
|
+
}
|
|
153
|
+
return worktreePath;
|
|
154
|
+
}
|
|
155
|
+
/** Wait until the machine can run a trivial command (boot completion). */
|
|
156
|
+
async waitForReady(machineName, timeoutMs = 20000) {
|
|
157
|
+
const start = Date.now();
|
|
158
|
+
while (Date.now() - start < timeoutMs) {
|
|
159
|
+
try {
|
|
160
|
+
await execFileAsync(smolBin(), ["machine", "exec", "--name", machineName, "--", "true"], { timeout: 5000 });
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
console.warn(`[smol] Timed out waiting for ${machineName} to be ready — proceeding anyway`);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Run `agentic-pi run --sandbox none …` inside the machine. Mirrors
|
|
171
|
+
* {@link DockerSandbox.runAgent}: streams stdout line-by-line for the live
|
|
172
|
+
* shim and writes the prompt to the child's stdin (`-i`). The agentic-pi
|
|
173
|
+
* argv is passed directly after `--` (no `sh -c`), so no shell quoting.
|
|
174
|
+
*/
|
|
175
|
+
async runAgent(taskId, prompt, opts) {
|
|
176
|
+
const info = this.machines.get(taskId);
|
|
177
|
+
if (!info)
|
|
178
|
+
throw new Error(`No smol machine for task ${taskId}`);
|
|
179
|
+
const model = opts?.model || "anthropic/claude-sonnet-4-6";
|
|
180
|
+
const timeout = this.config.timeoutSeconds || 1800;
|
|
181
|
+
const piArgs = ["agentic-pi", "run", "--model", model, "--sandbox", "none"];
|
|
182
|
+
if (opts?.thinking) {
|
|
183
|
+
if (!THINKING.has(opts.thinking)) {
|
|
184
|
+
throw new Error(`Refusing to pass thinking "${opts.thinking}" — must be one of ${[...THINKING].join("|")}`);
|
|
185
|
+
}
|
|
186
|
+
piArgs.push("--thinking", opts.thinking);
|
|
187
|
+
}
|
|
188
|
+
if (opts?.profile) {
|
|
189
|
+
if (!PROFILES.has(opts.profile)) {
|
|
190
|
+
throw new Error(`Refusing to pass profile "${opts.profile}" — must be one of ${[...PROFILES].join("|")}`);
|
|
191
|
+
}
|
|
192
|
+
piArgs.push("--profile", opts.profile);
|
|
193
|
+
}
|
|
194
|
+
if (opts?.webSearch === true) {
|
|
195
|
+
if (opts.webSearchProvider) {
|
|
196
|
+
if (!WEB_SEARCH_PROVIDERS.has(opts.webSearchProvider)) {
|
|
197
|
+
throw new Error(`Refusing to pass web-search-provider "${opts.webSearchProvider}" — must be one of ${[...WEB_SEARCH_PROVIDERS].join("|")}`);
|
|
198
|
+
}
|
|
199
|
+
piArgs.push("--web-search-provider", opts.webSearchProvider);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
piArgs.push("--no-web-search");
|
|
204
|
+
}
|
|
205
|
+
for (const dir of opts?.skillDirs ?? []) {
|
|
206
|
+
if (!dir.startsWith(SMOL_WORKSPACE_DIR) || !PATH_RE.test(dir)) {
|
|
207
|
+
throw new Error(`Refusing to pass skill dir "${dir}" — must live under ${SMOL_WORKSPACE_DIR}`);
|
|
208
|
+
}
|
|
209
|
+
piArgs.push("--skill", dir);
|
|
210
|
+
}
|
|
211
|
+
if (!PATH_RE.test(model)) {
|
|
212
|
+
throw new Error(`Refusing to pass model "${model}" — bad charset`);
|
|
213
|
+
}
|
|
214
|
+
// Passed as a single argv token each (no shell), so `KEY=VALUE` is literal.
|
|
215
|
+
for (const [k, v] of Object.entries(opts?.sandboxEnv ?? {})) {
|
|
216
|
+
if (!ENV_KEY_RE.test(k))
|
|
217
|
+
throw new Error(`Refusing sandbox-env key "${k}" — bad charset`);
|
|
218
|
+
if (/[\n\r]/.test(v))
|
|
219
|
+
throw new Error(`Refusing sandbox-env value for "${k}" — contains newline`);
|
|
220
|
+
piArgs.push("--sandbox-env", `${k}=${v}`);
|
|
221
|
+
}
|
|
222
|
+
const workdir = opts?.agentCwd ?? SMOL_WORKSPACE_DIR;
|
|
223
|
+
if (!workdir.startsWith(SMOL_WORKSPACE_DIR) || !PATH_RE.test(workdir)) {
|
|
224
|
+
throw new Error(`Refusing to pass agent cwd "${workdir}" — must live under ${SMOL_WORKSPACE_DIR}`);
|
|
225
|
+
}
|
|
226
|
+
const { flags: secretFlags, childEnv } = this.secretEnv();
|
|
227
|
+
const argv = [
|
|
228
|
+
"machine", "exec", "--name", info.machineName,
|
|
229
|
+
"-w", workdir, "-i",
|
|
230
|
+
...secretFlags,
|
|
231
|
+
"--", ...piArgs,
|
|
232
|
+
];
|
|
233
|
+
const STDERR_TAIL_BYTES = 8 * 1024;
|
|
234
|
+
return await new Promise((resolvePromise, reject) => {
|
|
235
|
+
const child = spawn(smolBin(), argv, { stdio: ["pipe", "pipe", "pipe"], env: childEnv });
|
|
236
|
+
child.stdin.write(prompt);
|
|
237
|
+
child.stdin.end();
|
|
238
|
+
let stderrTail = "";
|
|
239
|
+
let buf = "";
|
|
240
|
+
const timer = setTimeout(() => {
|
|
241
|
+
child.kill("SIGKILL");
|
|
242
|
+
reject(new Error(`Smol agent timed out after ${timeout}s`));
|
|
243
|
+
}, timeout * 1000);
|
|
244
|
+
child.stdout.setEncoding("utf-8");
|
|
245
|
+
child.stdout.on("data", (chunk) => {
|
|
246
|
+
if (!opts?.onLine)
|
|
247
|
+
return;
|
|
248
|
+
buf += chunk;
|
|
249
|
+
let nl;
|
|
250
|
+
while ((nl = buf.indexOf("\n")) >= 0) {
|
|
251
|
+
const line = buf.slice(0, nl);
|
|
252
|
+
buf = buf.slice(nl + 1);
|
|
253
|
+
if (line.length > 0) {
|
|
254
|
+
try {
|
|
255
|
+
opts.onLine(line);
|
|
256
|
+
}
|
|
257
|
+
catch { /* swallow listener errors */ }
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
child.stderr.setEncoding("utf-8");
|
|
262
|
+
child.stderr.on("data", (chunk) => {
|
|
263
|
+
stderrTail += chunk;
|
|
264
|
+
if (stderrTail.length > STDERR_TAIL_BYTES)
|
|
265
|
+
stderrTail = stderrTail.slice(-STDERR_TAIL_BYTES);
|
|
266
|
+
});
|
|
267
|
+
child.on("error", (err) => {
|
|
268
|
+
clearTimeout(timer);
|
|
269
|
+
reject(new Error(`Smol agent spawn failed: ${err.message}`));
|
|
270
|
+
});
|
|
271
|
+
child.on("close", (code) => {
|
|
272
|
+
clearTimeout(timer);
|
|
273
|
+
if (buf.length > 0 && opts?.onLine) {
|
|
274
|
+
try {
|
|
275
|
+
opts.onLine(buf);
|
|
276
|
+
}
|
|
277
|
+
catch { /* ignore */ }
|
|
278
|
+
}
|
|
279
|
+
if (code === 0)
|
|
280
|
+
resolvePromise();
|
|
281
|
+
else
|
|
282
|
+
reject(new Error(`Smol agent failed (exit ${code}): ${stderrTail || "no output"}`));
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Run a deterministic shell command in the machine and resolve with its exit
|
|
288
|
+
* code + bounded output. Non-agent sibling of {@link runAgent}; powers
|
|
289
|
+
* `type: bash` / `type: script` phases. The command is a shell string, so it
|
|
290
|
+
* runs under `sh -c`.
|
|
291
|
+
*/
|
|
292
|
+
async runCommand(taskId, command, opts) {
|
|
293
|
+
const info = this.machines.get(taskId);
|
|
294
|
+
if (!info)
|
|
295
|
+
throw new Error(`No smol machine for task ${taskId}`);
|
|
296
|
+
const timeout = opts?.timeoutSeconds || this.config.timeoutSeconds || 1800;
|
|
297
|
+
const workdir = opts?.cwd ?? SMOL_WORKSPACE_DIR;
|
|
298
|
+
if (!workdir.startsWith(SMOL_WORKSPACE_DIR) || !PATH_RE.test(workdir)) {
|
|
299
|
+
throw new Error(`Refusing to run command in cwd "${workdir}" — must live under ${SMOL_WORKSPACE_DIR}`);
|
|
300
|
+
}
|
|
301
|
+
const envFlags = [];
|
|
302
|
+
for (const [k, v] of Object.entries(opts?.sandboxEnv ?? {})) {
|
|
303
|
+
if (!ENV_KEY_RE.test(k))
|
|
304
|
+
throw new Error(`Refusing sandbox-env key "${k}" — bad charset`);
|
|
305
|
+
if (/[\n\r]/.test(v))
|
|
306
|
+
throw new Error(`Refusing sandbox-env value for "${k}" — contains newline`);
|
|
307
|
+
envFlags.push("-e", `${k}=${v}`);
|
|
308
|
+
}
|
|
309
|
+
const { flags: secretFlags, childEnv } = this.secretEnv();
|
|
310
|
+
const argv = [
|
|
311
|
+
"machine", "exec", "--name", info.machineName,
|
|
312
|
+
"-w", workdir,
|
|
313
|
+
...envFlags, ...secretFlags,
|
|
314
|
+
"--", "sh", "-c", command,
|
|
315
|
+
];
|
|
316
|
+
const STDOUT_TAIL_BYTES = 256 * 1024;
|
|
317
|
+
const STDERR_TAIL_BYTES = 32 * 1024;
|
|
318
|
+
return await new Promise((resolvePromise, reject) => {
|
|
319
|
+
const child = spawn(smolBin(), argv, { stdio: ["ignore", "pipe", "pipe"], env: childEnv });
|
|
320
|
+
let stdoutTail = "";
|
|
321
|
+
let stderrTail = "";
|
|
322
|
+
let buf = "";
|
|
323
|
+
let timedOut = false;
|
|
324
|
+
const timer = setTimeout(() => {
|
|
325
|
+
timedOut = true;
|
|
326
|
+
child.kill("SIGKILL");
|
|
327
|
+
}, timeout * 1000);
|
|
328
|
+
child.stdout.setEncoding("utf-8");
|
|
329
|
+
child.stdout.on("data", (chunk) => {
|
|
330
|
+
stdoutTail += chunk;
|
|
331
|
+
if (stdoutTail.length > STDOUT_TAIL_BYTES)
|
|
332
|
+
stdoutTail = stdoutTail.slice(-STDOUT_TAIL_BYTES);
|
|
333
|
+
if (!opts?.onLine)
|
|
334
|
+
return;
|
|
335
|
+
buf += chunk;
|
|
336
|
+
let nl;
|
|
337
|
+
while ((nl = buf.indexOf("\n")) >= 0) {
|
|
338
|
+
const line = buf.slice(0, nl);
|
|
339
|
+
buf = buf.slice(nl + 1);
|
|
340
|
+
if (line.length > 0) {
|
|
341
|
+
try {
|
|
342
|
+
opts.onLine(line);
|
|
343
|
+
}
|
|
344
|
+
catch { /* swallow listener errors */ }
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
child.stderr.setEncoding("utf-8");
|
|
349
|
+
child.stderr.on("data", (chunk) => {
|
|
350
|
+
stderrTail += chunk;
|
|
351
|
+
if (stderrTail.length > STDERR_TAIL_BYTES)
|
|
352
|
+
stderrTail = stderrTail.slice(-STDERR_TAIL_BYTES);
|
|
353
|
+
});
|
|
354
|
+
child.on("error", (err) => {
|
|
355
|
+
clearTimeout(timer);
|
|
356
|
+
reject(new Error(`Smol command spawn failed: ${err.message}`));
|
|
357
|
+
});
|
|
358
|
+
child.on("close", (code) => {
|
|
359
|
+
clearTimeout(timer);
|
|
360
|
+
if (buf.length > 0 && opts?.onLine) {
|
|
361
|
+
try {
|
|
362
|
+
opts.onLine(buf);
|
|
363
|
+
}
|
|
364
|
+
catch { /* ignore */ }
|
|
365
|
+
}
|
|
366
|
+
resolvePromise({
|
|
367
|
+
exitCode: timedOut ? 124 : (code ?? 1),
|
|
368
|
+
stdout: stdoutTail,
|
|
369
|
+
stderr: stderrTail,
|
|
370
|
+
timedOut,
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
/** Stop + delete the machine. */
|
|
376
|
+
async destroy(taskId) {
|
|
377
|
+
const info = this.machines.get(taskId);
|
|
378
|
+
if (!info)
|
|
379
|
+
return;
|
|
380
|
+
execSafe(smolBin(), ["machine", "stop", "--name", info.machineName]);
|
|
381
|
+
execSafe(smolBin(), ["machine", "delete", "-f", "--name", info.machineName]);
|
|
382
|
+
this.machines.delete(taskId);
|
|
383
|
+
console.log(`[smol] Destroyed: ${info.machineName}`);
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* The allowlist hosts that smolvm can actually use, in original order.
|
|
387
|
+
*
|
|
388
|
+
* smolvm resolves every `--allow-host` to its IP(s) AT VM START and aborts
|
|
389
|
+
* `create` if ANY entry fails to resolve. Our `egress-allowlist.ts` follows an
|
|
390
|
+
* apex+subdomain convention (e.g. `githubusercontent.com`), and some of those
|
|
391
|
+
* bare apexes have no A record — they'd abort the whole VM. So we pre-resolve
|
|
392
|
+
* here and drop the unresolvable ones.
|
|
393
|
+
*
|
|
394
|
+
* CAVEAT: unlike docker (SNI) / gondolin (hostname), smolvm's filter is
|
|
395
|
+
* IP-pinned at start — `--allow-host github.com` allows github.com's IPs only,
|
|
396
|
+
* NOT api.github.com or rotating CDN IPs. A faithful apex+subdomain policy
|
|
397
|
+
* would need each concrete subdomain enumerated; that's a spike gap.
|
|
398
|
+
*/
|
|
399
|
+
async resolvableAllowHosts() {
|
|
400
|
+
if (!this.config.allowHosts)
|
|
401
|
+
return [];
|
|
402
|
+
const ok = new Set();
|
|
403
|
+
const dropped = [];
|
|
404
|
+
await Promise.all(this.config.allowHosts.map(async (h) => {
|
|
405
|
+
if (!HOST_RE.test(h))
|
|
406
|
+
throw new Error(`Refusing to pass allow-host "${h}" — bad charset`);
|
|
407
|
+
try {
|
|
408
|
+
await lookup(h);
|
|
409
|
+
ok.add(h);
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
dropped.push(h);
|
|
413
|
+
}
|
|
414
|
+
}));
|
|
415
|
+
if (dropped.length) {
|
|
416
|
+
console.warn(`[smol] Dropping unresolvable allow-host entries (smolvm resolves each at VM start): ${dropped.join(", ")}`);
|
|
417
|
+
}
|
|
418
|
+
return this.config.allowHosts.filter((h) => ok.has(h));
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Build `--secret-env GUEST=GUEST` flags for every machine-env var plus the
|
|
422
|
+
* child-process env that carries their values, so secrets (tokens, provider
|
|
423
|
+
* keys) reach the guest via smolvm's secret channel rather than the argv.
|
|
424
|
+
*/
|
|
425
|
+
secretEnv() {
|
|
426
|
+
const flags = [];
|
|
427
|
+
const childEnv = { ...process.env };
|
|
428
|
+
for (const [k, v] of Object.entries(this.config.env)) {
|
|
429
|
+
if (!ENV_KEY_RE.test(k) || /[\n\r]/.test(v))
|
|
430
|
+
continue;
|
|
431
|
+
flags.push("--secret-env", `${k}=${k}`);
|
|
432
|
+
childEnv[k] = v;
|
|
433
|
+
}
|
|
434
|
+
return { flags, childEnv };
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
/** Strip a taskId down to the charset smolvm accepts in a machine name. */
|
|
438
|
+
function sanitizeName(taskId) {
|
|
439
|
+
return taskId.replace(/[^A-Za-z0-9_-]/g, "-").slice(0, 48);
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Depth-limited search for a file named `name` under `root`, returning its
|
|
443
|
+
* absolute path (or null). Used to locate the mount-probe sentinel; the share
|
|
444
|
+
* lands at most a couple of levels deep, so a shallow walk suffices and avoids
|
|
445
|
+
* descending into a large checkout.
|
|
446
|
+
*/
|
|
447
|
+
function findFileUnder(root, name, maxDepth) {
|
|
448
|
+
if (!existsSync(root))
|
|
449
|
+
return null;
|
|
450
|
+
let entries;
|
|
451
|
+
try {
|
|
452
|
+
entries = readdirSync(root, { withFileTypes: true });
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
for (const e of entries) {
|
|
458
|
+
if (e.isFile() && e.name === name)
|
|
459
|
+
return join(root, name);
|
|
460
|
+
}
|
|
461
|
+
if (maxDepth <= 0)
|
|
462
|
+
return null;
|
|
463
|
+
for (const e of entries) {
|
|
464
|
+
if (e.isDirectory()) {
|
|
465
|
+
const hit = findFileUnder(join(root, e.name), name, maxDepth - 1);
|
|
466
|
+
if (hit)
|
|
467
|
+
return hit;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
function execCmd(cmd, args, opts) {
|
|
473
|
+
return execFileSync(cmd, args, {
|
|
474
|
+
encoding: "utf-8",
|
|
475
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
476
|
+
timeout: opts?.timeout,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
function execSafe(cmd, args) {
|
|
480
|
+
try {
|
|
481
|
+
execFileSync(cmd, args, { stdio: "ignore" });
|
|
482
|
+
}
|
|
483
|
+
catch { /* ignore */ }
|
|
484
|
+
}
|
|
485
|
+
//# sourceMappingURL=smol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smol.js","sourceRoot":"","sources":["../../src/sandbox/smol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type SkillScope = "user" | "project";
|
|
2
|
+
export interface SkillsOpts {
|
|
3
|
+
/** Install scope — `user` (~/.claude) or `project` (<cwd>/.claude). Default `user`. */
|
|
4
|
+
scope?: SkillScope;
|
|
5
|
+
/** Skip the `claude` marketplace path and always copy skill dirs directly. */
|
|
6
|
+
noMarketplace?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function skillsInstall(opts: SkillsOpts): Promise<void>;
|
|
9
|
+
export declare function skillsList(opts: SkillsOpts): Promise<void>;
|
|
10
|
+
export declare function skillsUninstall(opts: SkillsOpts): Promise<void>;
|
|
11
|
+
/** Entry point dispatched from `src/cli.ts` for `lastlight skills …`. */
|
|
12
|
+
export declare function skills(args: string[], opts: SkillsOpts): Promise<void>;
|