5084334d81
Desktop-parity phase 6, following Claude Desktop: - the workspace home's Worktree checkbox starts the pane with `claude --worktree=<name>`, so Claude Code makes, populates (.worktreeinclude, WorktreeCreate hook) and cleans up <repo>/.claude/worktrees/<name>; AgentHub only excludes /.claude/worktrees/ at the repo root (Claude does not) - server/lib/session-worktree.js resolves a session's worktree from the session row only (owned by the workspace, registered by git worktree list); every lane git route takes ?session= and answers ENOWORKTREE instead of falling back to the main folder - the session view's Changes panel works in the opened run's worktree (dashboard_runs.worktree, GitTarget in the client api) - Resume/Fork start in the session's worktree; a gone one is ENOWORKTREE - Archive of a worktree session removes the worktree after asking: git worktree remove without --force, git branch -d (unmerged work keeps its branch), a lock held by a live pid refused, a stale one cleared - listWorktrees reads `locked <reason>` locks - tests scrub GIT_* env so the pre-commit suite cannot act on this repo
40 lines
1.4 KiB
TypeScript
40 lines
1.4 KiB
TypeScript
/**
|
|
* @file Pins where a workspace git call goes: the workspace's own routes, or —
|
|
* for a session's worktree target — the same routes with `?session=`, which
|
|
* the server resolves to that session's worktree.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
import { api, gitTarget } from "../api";
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
function stubFetch() {
|
|
const spy = vi.fn().mockResolvedValue({
|
|
ok: true,
|
|
status: 200,
|
|
headers: { get: () => "application/json" },
|
|
json: async () => ({}),
|
|
});
|
|
vi.stubGlobal("fetch", spy);
|
|
return spy;
|
|
}
|
|
|
|
describe("git targets", () => {
|
|
it("adds session= for a worktree target and nothing for the workspace", async () => {
|
|
const spy = stubFetch();
|
|
await api.lanes.changes(3, { range: "work" });
|
|
await api.lanes.changes(gitTarget(3, "s-1"), { range: "work" });
|
|
await api.lanes.gitAction(gitTarget(3, "s-1"), "stage", { paths: ["a"] });
|
|
await api.lanes.git(gitTarget(3, null));
|
|
const urls = spy.mock.calls.map((c) => String(c[0]));
|
|
expect(urls[0]).toMatch(/\/lanes\/3\/git\/changes\?range=work$/);
|
|
expect(urls[1]).toMatch(/\/lanes\/3\/git\/changes\?range=work&session=s-1$/);
|
|
expect(urls[2]).toMatch(/\/lanes\/3\/git\/stage\?session=s-1$/);
|
|
expect(urls[3]).toMatch(/\/lanes\/3\/git$/);
|
|
});
|
|
});
|