feat: v2.7.8 — Artifacts hub, clone related repos as extra folders, quieter resume prompt
- Artifacts (/artifacts): claude.ai pages sessions publish (captured from the Artifact tool's hook), pinned workspace files, skills and plugins, each kept as a snapshot; shared ones appear in a Hub and a skill or plugin installs into the viewer's own account (server/lib/artifacts.js, /api/artifacts, docs/plans/artifacts/). - Workspace extra folders: clone one or more related repos beside the workspace and add them in one step (POST /api/lanes/:id/sources/clone). - A pane that ended by itself while tmux kept running is no longer offered for resume (tmux.serverStartedAt in reconcileOrphans). - Changes panel: a folder that is not a git repo opens on Files, and its files open from there. - Plus the parallel sessions' work in this tree: File Explorer button in the panel header, user delete, RSA SSH keys, chat/terminal and pet fixes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -150,6 +150,36 @@ describe("dashboard-runs", () => {
|
||||
assert.deepEqual(offered(), []);
|
||||
});
|
||||
|
||||
it("does not offer a pane that ended by itself while its tmux server ran on", () => {
|
||||
const { db } = require("../db");
|
||||
db.prepare("INSERT INTO lanes (id, title, cwd) VALUES (21, 'w', '/j')").run();
|
||||
const session = db.prepare(
|
||||
"INSERT INTO sessions (id, name, status, cwd) VALUES (?, ?, 'active', '/j')"
|
||||
);
|
||||
for (const id of ["q-codex", "q-signal", "q-crash", "q-reboot"]) session.run(id, id);
|
||||
db.prepare(
|
||||
"INSERT INTO events (session_id, event_type, data) VALUES ('q-signal', 'SessionEnd', ?)"
|
||||
).run(JSON.stringify({ reason: "other" }));
|
||||
start("agenthub-lane-21", { laneId: 21, sessionId: "q-codex", tool: "codex" });
|
||||
start("agenthub-lane-21-1", { laneId: 21, sessionId: "q-signal" });
|
||||
start("agenthub-lane-21-2", { laneId: 21, sessionId: "q-crash" });
|
||||
start("agenthub-lane-21-3", { laneId: 21, sessionId: "q-reboot", tool: "codex" });
|
||||
|
||||
// The host's tmux has run since long before; lane 21-3's server is gone.
|
||||
const since = (id) => (id === "agenthub-lane-21-3" ? null : 0);
|
||||
runs.reconcileOrphans((id) => !id.startsWith("agenthub-lane-21"), since);
|
||||
const status = (id) => runs.getRun(id).status;
|
||||
assert.equal(status("agenthub-lane-21"), "abandoned", "Codex quit by the user");
|
||||
assert.equal(status("agenthub-lane-21-1"), "abandoned", "closed, tmux ran on");
|
||||
assert.equal(status("agenthub-lane-21-2"), "interrupted", "Claude never said it ended");
|
||||
assert.equal(status("agenthub-lane-21-3"), "interrupted", "died with its server");
|
||||
|
||||
// A server newer than the run restarted under it: interrupted too.
|
||||
start("agenthub-lane-21-4", { laneId: 21, sessionId: "q-codex", tool: "codex" });
|
||||
runs.reconcileOrphans((id) => !id.startsWith("agenthub-lane-21"), () => Date.now());
|
||||
assert.equal(status("agenthub-lane-21-4"), "interrupted");
|
||||
});
|
||||
|
||||
it("gives a hookless tool's session the lane of the run it started in", () => {
|
||||
const { db } = require("../db");
|
||||
start("agenthub-lane-7-1", {
|
||||
|
||||
Reference in New Issue
Block a user