host: sausage run with the userland bundle, real shell and services (T13)
- userland/bundle.nu builds the userland and assembles target/userland/bin (bin names, tools.txt aliases, brush as sh and bash). - run and sh take --userland (default SAUSAGE_USERLAND); /bin is read-only. - The console's bash tool runs through the process table with the conversation id; large output spills to the world's /tmp. - sausage run starts the services supervisor. P1 exit session (openai/gpt-6.1-sol, fresh world): write, read, edit, git init/add/commit/diff/log, grep -rn, rg, find and a sed|sort|uniq|wc pipeline.
This commit is contained in:
+27
-8
@@ -44318,7 +44318,7 @@ var path2 = (cwd, input) => {
|
||||
}
|
||||
return "/" + parts.join("/");
|
||||
};
|
||||
function environment(cwd = "/") {
|
||||
function environment(cwd = "/", conversation) {
|
||||
const call = (kind, p, bytes2 = []) => ops.op_file(kind, path2(cwd, p), bytes2);
|
||||
const env = {
|
||||
id: "world",
|
||||
@@ -44355,7 +44355,7 @@ function environment(cwd = "/") {
|
||||
const exists = await call("stat", current);
|
||||
if (!exists.ok) {
|
||||
const r = await call("mkdir", current);
|
||||
if (!r.ok) return r;
|
||||
if (!r.ok && (await call("stat", current)).value?.kind !== "directory") return r;
|
||||
}
|
||||
}
|
||||
return ok(void 0);
|
||||
@@ -44377,8 +44377,27 @@ function environment(cwd = "/") {
|
||||
});
|
||||
},
|
||||
exec: async (command, options, context) => {
|
||||
let spillPath;
|
||||
let pending = "", bytes2 = 0, lines2 = 0;
|
||||
const output = async (text2, stream2) => {
|
||||
options?.onOutput?.(text2, context, { stream: stream2 });
|
||||
if (!options?.spill) return;
|
||||
bytes2 += new TextEncoder().encode(text2).length;
|
||||
lines2 += text2.split("\n").length - 1;
|
||||
if (!spillPath) {
|
||||
pending += text2;
|
||||
if (bytes2 <= options.spill.afterBytes && lines2 + (pending.endsWith("\n") ? 0 : 1) <= options.spill.afterLines) return;
|
||||
spillPath = `/tmp/bash-${crypto.randomUUID()}.log`;
|
||||
const created = await env.writeFile(spillPath, pending);
|
||||
if (!created.ok) throw new Error(created.error.message);
|
||||
pending = "";
|
||||
} else {
|
||||
const appended = await call("append", spillPath, Array.from(new TextEncoder().encode(text2)));
|
||||
if (!appended.ok) throw new Error(appended.error.message);
|
||||
}
|
||||
};
|
||||
try {
|
||||
const rid = ops.op_exec(command, options?.cwd ?? cwd, options?.timeout);
|
||||
const rid = ops.op_exec(command, options?.cwd ?? cwd, options?.timeout, conversation);
|
||||
const decoders = { stdout: new TextDecoder(), stderr: new TextDecoder() };
|
||||
let result;
|
||||
while (true) {
|
||||
@@ -44387,16 +44406,16 @@ function environment(cwd = "/") {
|
||||
result = chunk;
|
||||
break;
|
||||
}
|
||||
options?.onOutput?.(decoders[chunk.stream].decode(new Uint8Array(chunk.bytes), { stream: true }), context, { stream: chunk.stream });
|
||||
await output(decoders[chunk.stream].decode(new Uint8Array(chunk.bytes), { stream: true }), chunk.stream);
|
||||
}
|
||||
if (result.error) throw new Error(result.error);
|
||||
for (const stream2 of ["stdout", "stderr"]) {
|
||||
const text2 = decoders[stream2].decode();
|
||||
if (text2) options?.onOutput?.(text2, context, { stream: stream2 });
|
||||
if (text2) await output(text2, stream2);
|
||||
}
|
||||
return ok({ exitCode: result.exitCode });
|
||||
return ok({ exitCode: result.exitCode, ...spillPath ? { spillPath } : {} });
|
||||
} catch (error) {
|
||||
return { ok: false, error };
|
||||
return { ok: false, error: Object.assign(new Error(String(error)), { code: "unknown", ...spillPath ? { spillPath } : {} }) };
|
||||
}
|
||||
},
|
||||
cleanup: async () => {
|
||||
@@ -44442,7 +44461,7 @@ registry.install(CodingTools);
|
||||
var harness = await Harness.open(await openStorage(globalThis.storagePath), {
|
||||
models,
|
||||
registry,
|
||||
env: (target) => environment(target.cwd ?? "/")
|
||||
env: (target) => environment(target.cwd ?? "/", target.conversationId)
|
||||
}, BACKGROUND_CONTEXT);
|
||||
var root = await harness.root(BACKGROUND_CONTEXT, { agent: { model: { provider: "openai", modelId: model2.id }, thinkingLevel: "low", cwd: "/", extensions: [CodingTools] } });
|
||||
var watch = await root.watch(BACKGROUND_CONTEXT);
|
||||
|
||||
Reference in New Issue
Block a user