feat(lanes): per-lane database, Redis, and .env isolation (A1+A2)
Gives each lane its own slot-derived runtime (ports, detached process lifecycle, profile-driven hooks) and its own database/Redis logical index/.env file, so two lanes running the same repo's stack at once no longer share state. Machine-level DB/Redis credentials live at ~/.ccam/secrets.env (mode 0600, never returned by any route); a hook's output is redacted of that password (raw and URL-encoded forms) before it reaches a log file or the lane_hook_output websocket broadcast. Wired into provision/up/reset/remove; reset accepts --keep-db to skip the drop/recreate/migrate/reseed block entirely.
This commit is contained in:
@@ -493,6 +493,32 @@ try {
|
||||
db.prepare("ALTER TABLE lanes ADD COLUMN detected_at TEXT").run();
|
||||
}
|
||||
|
||||
// Migrate: per-lane runtime allocation. `slot` is the small integer every runtime
|
||||
// fact derives from (ports now; database name and Redis index later) — the
|
||||
// numbering Shipyard gets for free from its fixed lane1..lane9 directories and
|
||||
// CCAM, keyed by cwd, has to allocate. `ports` is a JSON map name -> port,
|
||||
// recording the number a lane ACTUALLY got: the preferred `base + slot` may be
|
||||
// taken by something outside CCAM, so the allocator steps aside and the real
|
||||
// number has to survive a restart or the next boot would move a live lane.
|
||||
//
|
||||
// Allocation is lazy — a lane that is only ever watched never takes a slot — so
|
||||
// the column is nullable and the uniqueness constraint is partial. That index is
|
||||
// the backstop under the lock in lane-slots.js, not a substitute for it.
|
||||
// One probe per column, same reasoning as the detection columns above.
|
||||
try {
|
||||
db.prepare("SELECT slot FROM lanes LIMIT 1").get();
|
||||
} catch {
|
||||
db.prepare("ALTER TABLE lanes ADD COLUMN slot INTEGER").run();
|
||||
}
|
||||
try {
|
||||
db.prepare("SELECT ports FROM lanes LIMIT 1").get();
|
||||
} catch {
|
||||
db.prepare("ALTER TABLE lanes ADD COLUMN ports TEXT NOT NULL DEFAULT '{}'").run();
|
||||
}
|
||||
db.prepare(
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS idx_lanes_slot ON lanes(slot) WHERE slot IS NOT NULL"
|
||||
).run();
|
||||
|
||||
// Migrate: link agent rows to a workflow run. Workflow inner-agents are already
|
||||
// ingested as subagents (same subagents/ dir); these columns add the grouping +
|
||||
// phase that the run journal provides. Additive, safe on existing DBs.
|
||||
|
||||
Reference in New Issue
Block a user