feat: Discard all, claude-style image pastes, large local drops, per-account / list

- Changes panel: **Discard all** beside Commit discards every non-conflicted
  file in one `discard`, after a dialog naming how many untracked files go.
- Terminal: a `claude` pane gets dropped/pasted images as bare paths (shown as
  `[Image #n]`) and other files as `@` mentions (`claudePastes`); a local
  browser's copied `file://` paths and text-drag file lists paste by path.
- `POST /api/run/drop-file`: a loopback browser outside server mode may drop
  up to 2 GB, streamed to disk; remote stays 20 MB.
- cc-config skills/commands/plugins read the USER scope of the account the
  pane runs as (S3 member home by `cwd`), never another user's or the host's
  for a non-admin without an account; the run form passes its cwd to plugins.
This commit is contained in:
2026-10-21 14:27:36 +07:00
parent 0547488f13
commit aee4fc190e
16 changed files with 380 additions and 65 deletions
@@ -770,6 +770,24 @@ describe("LaneChangesPanel", () => {
});
});
it("discards every file at once only after the dialog is confirmed", async () => {
const user = userEvent.setup();
render(<LaneChangesPanel laneId={7} />);
await screen.findByTestId("lane-changes-overview");
vi.mocked(confirmDialog).mockResolvedValueOnce(false);
await user.click(screen.getByTestId("lane-changes-discard-all"));
expect(api.lanes.gitAction).not.toHaveBeenCalled();
await user.click(screen.getByTestId("lane-changes-discard-all"));
await waitFor(() =>
expect(api.lanes.gitAction).toHaveBeenCalledWith(7, "discard", {
paths: ["server/lib/git-ops.js", "notes.txt", "docs/API.md"],
confirm: true,
})
);
});
it("right-click on a changed file offers Commit File, a two-click discard, copy path and patch", async () => {
const user = userEvent.setup();
render(<LaneChangesPanel laneId={7} />);