Skip to content

feat(web): restore a deleted artifact when it is opened - #1369

Merged
danyaberezun merged 7 commits into
mainfrom
artifacts-open-restores
Nov 14, 2026
Merged

danyaberezun merged 7 commits into
mainfrom
artifacts-open-restores

Conversation

@danyaberezun

@danyaberezun danyaberezun commented Nov 14, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

The Artifacts tool (#1358) keeps every file the agent deleted as a "Deleted, not by you" row, but that row could not be opened. Its name was disabled, so seeing what the agent removed took two steps: Restore, then open. #1358 listed "open a deleted artifact without restoring it" as deferred.

Approach

Opening a deleted artifact restores it. Opening a file means asking for its contents, so a single click (preview) or a double click (kept tab) on a deleted row's name now restores the file from its kept copy, then opens it. Enter on the focused name does the same, and Mod+Enter (from #1370's keyboard trees) restores it into a kept tab.

  • Silent on success. The row simply becomes a normal one, with no toast and no Undo.
  • A failed restore opens nothing and shows the Restore button's error toast. That includes a new file that has taken the path since (ENTRY_EXISTS): it is not opened in place of the artifact the user clicked.
  • One restore per deletion. A row's restore is reused, in flight or done, for as long as the row shows the same deletion. For a deleted row the host's changedAt is when it saw the file gone, so a list refresh keeps it and a new deletion changes it; the contracts spec now states this. A double click, a click in the gap before the live snapshot, or a list refresh in between therefore never asks again; the host would refuse a row that is already live with ARTIFACT_UNKNOWN. A row the agent deletes again right after its restore gets a fresh one instead of getting stuck. A click, Mod+Enter, the Restore button and the menu's Restore all share it, keyed per workspace and path.
  • The click keeps its place. The center navigation is stamped at the click, before the restore (the request-time rule reviewSend follows). Opening another file while a slow restore runs is therefore never undone by the restored preview.
  • Web only. It reuses artifacts.restore and openFileInTab. A host method "restore and open" was rejected: no difference for the user, and it would need a protocol bump.

The Restore button and menu item stay. A deleted row still looks deleted until it is opened. Mention in chat and Reveal in Files remain hidden for deleted rows (deferred).

Changes

  • apps/web/src/panels/artifactActions.ts:
    • restoreArtifact now reports success;
    • new openArtifact(workspaceId, artifact, intent), which restores a deleted artifact first;
    • new restoreDeletedArtifact(workspaceId, artifact), which holds the one-restore-per-deletion rule per workspace and path without React.
  • ArtifactsPanel:
    • a deleted row's name is enabled (no longer aria-disabled) and opens through openArtifact;
    • feat(web): run the workbench and the sidebar trees from the keyboard #1370's tree marks every artifact row for Mod+Enter, and the Artifacts section's kept-open goes through openArtifact;
    • EntryMenu takes onRestore (present only for a deleted row) instead of a deleted flag plus its own restore call.
  • apps/web/src/panels/SPEC.md, packages/contracts/SPEC.md (a deleted row's changedAt) and README.md describe the new behaviour.

Screenshots

Same scenario and viewport: report.md was deleted outside ThinkRail, and its struck-through name is clicked.

Before: nothing opens and the row stays deleted.

Before: clicking a deleted artifact does nothing

After: the file is restored and opens in a tab, and the row is a normal one again.

After: clicking a deleted artifact restores and opens it

Related issues

Follow-up to #1358.

Checklist

  • Fast gates pass: bun run lint, bun run typecheck (26/26), bun run test (25/25 packages), plus check:deps, check:boundaries, check:seams, check:spec-surface, check:i18n, check:compiler
    • On the final tree, @thinkrail/server's backpressure test in host/snapshotConflation.test.ts timed out once while the machine was loaded. It fails the same way on main when run alone with -t, and this PR touches no server code. The whole server package then passed (2839).
  • E2E suite passes for app-affecting changes (bun run e2e, or bun run e2e:full when touching agent behavior):
    • bun run e2e → every Chromium test passes, including the new e2e/artifacts.spec.ts test "opening a deleted artifact restores it, once on a double click or Mod+Enter, and a failed restore opens nothing". Rerun after rebasing onto feat(web): run the workbench and the sidebar trees from the keyboard #1370. 25 WebKit tests could not start on the author's Linux machine ("Host system is missing dependencies"), so WebKit is unverified locally.
    • apps/web/src/panels/artifactActions.test.ts (5) covers the cases e2e can't reach: a taken path opens nothing, a click made during the restore keeps its place, plus each one-restore-per-deletion rule (reuse in flight or done across list refreshes, a fresh restore for a newer deletion, retry after a failure). Each test fails with its rule removed; the e2e test fails without the reuse or with Mod+Enter left disabled on deleted rows.
  • Before/after screenshots are included for frontend changes, or marked not applicable
  • Relevant SPEC.md / top-level specs updated to reflect any boundary, contract, or behavior change
  • I have read the Contributing guide and agree to the Code of Conduct

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

Comment thread apps/web/src/panels/artifactActions.ts Resolved

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

Comment thread apps/web/src/panels/artifactActions.ts Resolved
@danyaberezun
danyaberezun force-pushed the artifacts-open-restores branch from 813b0c8 to 93d50be Compare November 14, 2026 16:59

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

@danyaberezun
danyaberezun merged commit 44faca0 into main Nov 14, 2026
12 checks passed
@danyaberezun
danyaberezun deleted the artifacts-open-restores branch November 14, 2026 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant