feat(ui): a Claude-Desktop-style home for every workspace

/workspace?lane=<id> opens on the workspace's home (WorkspaceHome): a prompt
box whose Start opens a new session in the first free pane slot, Recents (a
live session attaches its pane, any other opens its transcript, nothing
resumes), and Instructions / Memory / Context / Folder. Instructions live in
lanes.instructions, extra folders and uploaded files in the new lane_sources
table (copies under <data dir>/workspace-context/<lane id>/); spawnRun reads
them from the lane's rows and hands Claude --add-dir + an appended system
prompt file, Codex --add-dir + developer_instructions. Memory is read-only.

Every dashboard pane carries AGENTHUB_RUN_ID; hooks forward it and the run
records which session the pane holds (a Claude pane follows /clear and
/resume but not a nested claude -p), so the sidebar and notifications open
the right pane (&run=). Settings loses its Projects group; Worktrees now
decides which worktrees Add folder suggests.
This commit is contained in:
2026-10-02 01:10:58 +07:00
parent 2e051e23b6
commit d0535af626
44 changed files with 2515 additions and 466 deletions
+24
View File
@@ -721,6 +721,30 @@ try {
db.prepare("ALTER TABLE lanes ADD COLUMN needs_action_session TEXT").run();
}
// Migrate: a workspace's own context, as on a Claude Desktop project page
// (server/lib/lane-sources.js). `instructions` is appended to every pane's
// system prompt; `lane_sources` holds extra folders (the user's, never
// deleted) and uploaded context files (AgentHub's own copies under
// <data dir>/workspace-context/<lane id>/). Both additive.
try {
db.prepare("SELECT instructions FROM lanes LIMIT 1").get();
} catch {
db.prepare("ALTER TABLE lanes ADD COLUMN instructions TEXT").run();
}
db.exec(`
CREATE TABLE IF NOT EXISTS lane_sources (
id INTEGER PRIMARY KEY,
lane_id INTEGER NOT NULL,
kind TEXT NOT NULL CHECK (kind IN ('folder', 'file')),
path TEXT NOT NULL,
name TEXT NOT NULL,
size INTEGER,
added_at TEXT NOT NULL,
FOREIGN KEY (lane_id) REFERENCES lanes(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_lane_sources_lane ON lane_sources(lane_id);
`);
// Seed lane_stage_events from the snapshots that predate it, so upgrading does
// not read as "every pipeline has never run". Each lane's live `stages` blob
// becomes one run; each archived feature becomes one more. That is all the