Archive any workspace from the app (#2003)

* feat(app): expose archive for every workspace

Workspace actions now archive one workspace by id. The daemon remains responsible for backing-specific cleanup, including removing a managed worktree only after its final workspace is archived.

* refactor(app): clarify archive descriptor name

* fix(app): preserve workspace archive safety

* fix(app): allow archive without upstream

* refactor(app): remove stale archive callback

* test(app): cover workspace archive ownership
This commit is contained in:
Mohamed Boudra
2026-07-11 18:22:31 +02:00
committed by GitHub
parent ada0955334
commit 03dcda7c41
40 changed files with 369 additions and 757 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ export type KeyboardActionId =
| "workspace.terminal.new"
| "workspace.new"
| "worktree.new"
| "worktree.archive"
| "workspace.archive"
| "view.toggle.focus"
| "theme.cycle"
| "message-input.action";
@@ -29,7 +29,7 @@ export type KeyboardActionId =
| "sidebar.toggle.right"
| "workspace.new"
| "worktree.new"
| "worktree.archive";
| "workspace.archive";
export type KeyboardActionDefinition =
| { id: "agent.interrupt"; scope: KeyboardActionScope }
@@ -60,7 +60,7 @@ export type KeyboardActionDefinition =
| { id: "sidebar.toggle.right"; scope: KeyboardActionScope }
| { id: "workspace.new"; scope: KeyboardActionScope }
| { id: "worktree.new"; scope: KeyboardActionScope }
| { id: "worktree.archive"; scope: KeyboardActionScope };
| { id: "workspace.archive"; scope: KeyboardActionScope };
export interface KeyboardActionHandler {
handlerId: string;
@@ -121,7 +121,7 @@ const SHORTCUT_HELP_SECTION_LABEL_KEYS: Record<ShortcutSectionId, string> = {
const SHORTCUT_HELP_LABEL_KEYS: Record<string, string> = {
"new-agent": "settings.shortcuts.help.openProject",
"new-workspace": "settings.shortcuts.help.newWorkspace",
"archive-worktree": "settings.shortcuts.help.archiveWorktree",
"archive-workspace": "settings.shortcuts.help.archiveWorkspace",
"workspace-tab-new": "settings.shortcuts.help.newTab",
"workspace-tab-close-current": "settings.shortcuts.help.closeCurrentTab",
"workspace-jump-index": "settings.shortcuts.help.jumpToWorkspace",
@@ -221,28 +221,32 @@ const SHORTCUT_BINDINGS: readonly ShortcutBinding[] = [
},
},
// --- Archive worktree ---
// --- Archive workspace ---
{
// COMPAT(workspaceArchiveShortcutOverride): added in v0.1.106; remove after
// 2027-01-11 with a stored-override migration. Keeps existing custom chords.
id: "worktree-archive-cmd-shift-backspace-mac",
action: "worktree.archive",
action: "workspace.archive",
combo: "Cmd+Shift+Backspace",
when: { mac: true, commandCenter: false },
help: {
id: "archive-worktree",
id: "archive-workspace",
section: "projects",
label: "Archive worktree",
label: "Archive workspace",
keys: ["mod", "shift", "Backspace"],
},
},
{
// COMPAT(workspaceArchiveShortcutOverride): added in v0.1.106; remove after
// 2027-01-11 with a stored-override migration. Keeps existing custom chords.
id: "worktree-archive-ctrl-shift-backspace-non-mac",
action: "worktree.archive",
action: "workspace.archive",
combo: "Ctrl+Shift+Backspace",
when: { mac: false, commandCenter: false, terminal: false },
help: {
id: "archive-worktree",
id: "archive-workspace",
section: "projects",
label: "Archive worktree",
label: "Archive workspace",
keys: ["mod", "shift", "Backspace"],
},
},
@@ -30,7 +30,7 @@ describe("routeKeyboardShortcut — dispatch passthroughs", () => {
["agent.interrupt", { id: "agent.interrupt", scope: "global" }],
["workspace.tab.new", { id: "workspace.tab.new", scope: "workspace" }],
["workspace.new", { id: "workspace.new", scope: "sidebar" }],
["worktree.archive", { id: "worktree.archive", scope: "sidebar" }],
["workspace.archive", { id: "workspace.archive", scope: "sidebar" }],
["worktree.new", { id: "worktree.new", scope: "sidebar" }],
["workspace.terminal.new", { id: "workspace.terminal.new", scope: "workspace" }],
["workspace.tab.close.current", { id: "workspace.tab.close-current", scope: "workspace" }],
+1 -1
View File
@@ -46,7 +46,7 @@ const PASSTHROUGH_DISPATCH: Record<string, KeyboardActionDefinition> = {
"agent.interrupt": { id: "agent.interrupt", scope: "global" },
"workspace.tab.new": { id: "workspace.tab.new", scope: "workspace" },
"workspace.new": { id: "workspace.new", scope: "sidebar" },
"worktree.archive": { id: "worktree.archive", scope: "sidebar" },
"workspace.archive": { id: "workspace.archive", scope: "sidebar" },
"worktree.new": { id: "worktree.new", scope: "sidebar" },
"workspace.terminal.new": { id: "workspace.terminal.new", scope: "workspace" },
"workspace.tab.close.current": { id: "workspace.tab.close-current", scope: "workspace" },