cli, seat, harness: a project clone in each role workspace (#1585)
Row 91, round 3. Darkwing built it, Dewey approved it (comment 28150) on manifest ca570607 (8 paths, base2b2a9e14). At each launch the host makes or updates a git clone of the project in the role's workspace, and the session prompt names each clone. Round 3 closes Filbert's round 2 escape: a clone with a submodule is kept as it is, and no host git recurses into one (decision 130 thread). Live at the next bus restart; the prompt lines appear only when the launcher passes checkouts. Sage gate onfc6d5822plus the patch, 14:18:25Z to 14:22:27Z: bus 115, business 60, cli 131, control-board 124, conversation 182, discord 178, harness 67, ledger 78, mosaic 69, queue 150, runs 43, seat 89, tasks 89, webui 104, all fail 0. Every scripts/test-*.sh exited 0; test-release ran 14 cases. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -24,7 +24,10 @@
|
||||
//
|
||||
// Steps 2 to 8 refuse through the broker's refuse(), so every refusal is an
|
||||
// action.refused event; step 9's refusals the broker records itself. Then
|
||||
// the host builds the bundle, spawns the runner in its sandbox
|
||||
// the host makes sure the workspace has a clone of each project
|
||||
// (packages/seat/src/checkout.mjs): one it can't make refuses
|
||||
// checkout-failed, and one it leaves alone is a checkout-kept record in the
|
||||
// launch log. Then it builds the bundle, spawns the runner in its sandbox
|
||||
// (packages/seat/src/sandbox.mjs) with the paths it may see, binds the run's
|
||||
// process identity (the outer bwrap pid) and writes the new capability on
|
||||
// the runner's stdin. When the runner exits, the host ends the launch.
|
||||
@@ -57,6 +60,7 @@ import {
|
||||
writeSessionFile,
|
||||
} from "../../seat/src/session.mjs";
|
||||
import { BWRAP, sandboxProblem } from "../../seat/src/sandbox.mjs";
|
||||
import { CheckoutError, ensureCheckouts } from "../../seat/src/checkout.mjs";
|
||||
import { cmdlineOf, startTimeOf } from "../../seat/src/proc.mjs";
|
||||
import { REPO, rolesDir } from "./config.mjs";
|
||||
import { CliError } from "./errors.mjs";
|
||||
@@ -169,9 +173,22 @@ export function createLauncher({
|
||||
// Bundle, spawn, bind, register, hand over the capability.
|
||||
async function start({ instance, launchedBy, resolved, model, fam }) {
|
||||
const credentials = await host.op({ op: "credentialStatus", business: b.id, role: instance });
|
||||
const { run, runDir } = newRun(dataRoot, b.id);
|
||||
// The clones come before the run, so one that can't be made leaves no
|
||||
// run behind. The host's git treats each clone as hostile, and its
|
||||
// checks hold only while no session writes the workspace: a workspace
|
||||
// is one instance's, check() refused instance-running, and launches are
|
||||
// serialized, so none does.
|
||||
const workspace = workspaceDir(dataRoot, b.id, instance);
|
||||
mkdirSync(workspace, { recursive: true, mode: 0o700 });
|
||||
let checkouts;
|
||||
try {
|
||||
checkouts = await ensureCheckouts({ workspace, projects: b.projects, env });
|
||||
} catch (e) {
|
||||
if (e instanceof CheckoutError) throw new Refusal("checkout-failed", `${e.project}: ${e.message}`);
|
||||
throw e;
|
||||
}
|
||||
for (const c of checkouts) if (c.outcome === "kept") record({ event: "checkout-kept", instance, project: c.project, reason: c.reason });
|
||||
const { run, runDir } = newRun(dataRoot, b.id);
|
||||
const sessionDir = join(runDir, "session");
|
||||
mkdirSync(sessionDir, { mode: 0o700 });
|
||||
const toolSocket = join(runDir, "tools.sock");
|
||||
@@ -184,7 +201,7 @@ export function createLauncher({
|
||||
arbiter: Object.values(b.arbiters).includes(instance),
|
||||
tracker,
|
||||
credentials,
|
||||
session: { run, launchedBy, workspace, toolSocket, turnMarker },
|
||||
session: { run, launchedBy, workspace, toolSocket, turnMarker, checkouts },
|
||||
piVersion: v.pi,
|
||||
claudeVersion: v.claude,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user