Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),

### Added

- Complete Files CRUD with inline file/folder creation and rename, duplication, cut/copy/paste moves, system Trash deletion, file-manager reveal, active-file reveal, and secure worktree-relative Main-process operations.
- Public contribution, security, support, conduct, issue, and pull request guidance.
- Cross-platform development packaging for macOS arm64, Windows x64, and Linux x64.
- Projects, managed worktrees, file editing, Git changes, terminals, multi-tab pi Agent chat, settings, and support for user-installed standard Pi resources.

### Changed

- Upgraded Git Changes into an Orca-inspired Source Control panel with filtering, collapsible conflict-aware groups, rich status metadata, safe stage/unstage/discard actions, and per-worktree commit drafts.
- Refined the workbench with quieter neutral chrome, a narrower Chat reading column, accessible icon tooltips, and a System appearance option that follows the operating system theme.

### Removed
Expand Down
23 changes: 23 additions & 0 deletions docs/files-crud/intent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Files CRUD Intent

## Problem

SpireCode's Files panel can browse and open files but cannot create, rename, move, copy, or delete project content. Users must leave the app for routine project organization, and external mutations can leave editor tabs and the tree out of sync.

## Outcome

Make Files a complete, accessible project file manager while preserving SpireCode's Electron security boundary: Renderer operations identify a worktree and relative paths only; Main resolves canonical roots, rejects traversal and .git access, and owns every filesystem mutation.

Users can create files and folders, rename or move entries, duplicate them, and move them to the operating system Trash. The tree refreshes without losing context, active files can be revealed, and open editor resources follow successful path mutations.

## Non-goals

- Exposing Node, Electron, absolute project paths, generic filesystem APIs, or shell command strings to Renderer.
- Permanent deletion as the default or a silent fallback when Trash fails.
- Following symlinks during recursive copy or allowing operations through symlinked parents.
- Cross-worktree moves, multi-selection, file-operation undo/redo, or tree virtualization in this delivery.
- Overwrite-on-conflict; mutations fail closed when a destination exists.

## Risk

High risk: this changes filesystem/path-isolation behavior and the Renderer/Main IPC contract, and includes destructive user-visible operations. The user explicitly confirmed the design and requested implementation after these risks and behaviors were described.
43 changes: 43 additions & 0 deletions docs/files-crud/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Files CRUD Plan

## 1. Contract and domain tests

- Extend generated-facing TypeScript types, command allowlists, argument validation, bindings, and IPC dispatch.
- Add failing filesystem-domain tests for create, rename, move, recursive copy, Trash injection, conflicts, root rejection, .git/traversal, symlink-parent escape, and directory-into-descendant rejection.
- Implement operations in `FilesystemService` using exclusive creation and existing path guards; inject Trash from `AppState`.

Proof: filesystem and IPC contract tests pass, including platform-conditional symlink cases.

## 2. Store consistency tests

- Add failing tests for directory-targeted invalidation, collapse-all/expansion helpers, editor path remapping, affected dirty-tab inspection, and tab removal after Trash.
- Implement focused FileTree and editor-store mutation APIs, including persisted tab IDs and draft remapping support.

Proof: file-tree store, filesystem event, and editor store tests pass.

## 3. Files interactions

- Add toolbar, menu, inline input, operation error, clipboard state, and Trash confirmation to Files.
- Wire commands so state changes occur only after Main success.
- Add active-file ancestor expansion and scroll-to-row behavior.
- Add localized strings and neutral semantic styling consistent with the current workbench.

Proof: component tests exercise keyboard create/rename cancellation and submission, CRUD command arguments, conflict errors, confirmation, clipboard move/copy, and editor synchronization.

## 4. Refresh behavior and integration

- Refresh only affected cached directories from non-truncated watcher payloads; preserve full invalidation for truncated payloads.
- Reuse existing Git invalidation and editor reload behavior without broadening Renderer authority.
- Update Changelog.

Proof: watcher event tests cover exact, ancestor, and truncated invalidation.

## 5. Verification and review

- Run targeted red-green suites during each step.
- Run formatting, localization/brand/security guards, lint, both TypeScript projects, all Renderer/Electron tests, release tests, and production build through `pnpm check` and `pnpm build`.
- Inspect the final diff for raw paths, shell strings, unsafe overwrite, permanent-delete fallback, unlocalized copy, and contract drift.

## Delivery note

This branch is stacked on the current Orca-inspired P0 branch because it reuses the shared Tooltip and visual tokens. It should be merged only after its base change or rebased onto main.
60 changes: 60 additions & 0 deletions docs/files-crud/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Files CRUD Specification

## Main contract

Add narrow allowlisted commands:

- `fs_create_file(worktreeId, relativePath)`
- `fs_create_directory(worktreeId, relativePath)`
- `fs_rename(worktreeId, relativePath, newName)`
- `fs_move(worktreeId, sourceRelativePath, destinationRelativePath)`
- `fs_copy(worktreeId, sourceRelativePath, destinationRelativePath)`
- `fs_trash(worktreeId, relativePath)`
- `fs_reveal(worktreeId, relativePath)`

Mutations return a typed result containing operation kind, source path when applicable, destination path when applicable, and entry kind. No command accepts an absolute path. `fs_rename` accepts only a leaf name; arbitrary relocation uses `fs_move`.

## Path and mutation safety

- Resolve worktree IDs to canonical roots in Main.
- Reject absolute paths, empty mutation paths, `.`, `..`, NUL, and any `.git` component.
- Require canonical existing parents and reject symlink-parent traversal or escape.
- Never overwrite an existing destination.
- Reject moving/copying a directory into itself or a descendant.
- Copy symlinks as symlinks without traversing them; reject copied symlinks whose target would escape the worktree.
- Create files with exclusive creation and create directories without recursive missing-parent creation.
- Trash uses Electron `shell.trashItem`; failure is surfaced and never falls back to permanent deletion.
- The worktree root cannot be renamed, moved, copied, or trashed.

## Files UI

- A compact toolbar exposes only New File and New Folder with accessible labels and tooltips; filesystem watching keeps the tree current without manual Refresh, and users collapse directories directly in the tree.
- Context menus expose context-appropriate New File/Folder, Rename, Duplicate, Cut, Copy, Paste, Copy Relative Path, Reveal in Finder, and Move to Trash.
- Creation and rename use an inline input. Enter submits, Escape cancels, and validation or command errors remain visible without losing the input.
- Copy stores a source entry and Paste invokes copy. Cut stores a source entry and Paste invokes move. Clipboard state is scoped to one worktree and clears after a successful cut/move.
- Trash requires confirmation. If affected file tabs contain unsaved changes, the confirmation explicitly warns that local drafts will be lost.
- Filesystem failures are localized and announced. Existing tree content remains visible during refresh.

## Editor and tree consistency

- Successful rename/move remaps all open file and diff tabs at the exact source path or below a moved directory, preserving active tab, preview/pinned state, and dirty metadata.
- Draft buffers are keyed by tab ID and are remapped with tabs so unsaved content survives rename/move.
- Successful Trash closes affected tabs only after confirmation; unrelated tabs stay open.
- Copy/create refresh affected directories; rename/move/trash refresh source and destination parents.
- The active file is automatically revealed by expanding ancestors and scrolling it into view without stealing focus.
- Watcher events use their changed paths for directory-level invalidation when not truncated; truncated events retain full-worktree invalidation.

## Accessibility and localization

- Existing ARIA tree semantics and keyboard navigation remain intact.
- Menu and dialog controls are keyboard accessible; inline inputs have localized labels and errors.
- Every user-visible string exists in English and Simplified Chinese catalogs.

## Acceptance criteria

1. Every Main mutation rejects traversal, .git, root operations, symlink escape, descendant moves/copies, and destination conflicts in deterministic tests.
2. Create file/folder, rename, duplicate, cut/paste move, copy/paste, Trash, and Reveal are available from Files UI.
3. Rename/move preserves dirty open editor tabs and updates resource IDs; Trash warns and closes affected tabs only after success.
4. Failed operations do not optimistically corrupt tree or editor state.
5. Existing preview/pinned opening, keyboard tree navigation, ignore filtering, file saves, and watcher behavior remain covered.
6. `pnpm check` and `pnpm build` pass.
20 changes: 20 additions & 0 deletions docs/orca-aligned-source-control/intent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Intent: Orca-aligned Source Control

## Problem

SpireCode Changes is a safe, automatically refreshed Git status and diff viewer, but it does not yet support the source-control interactions users expect beside an editor. Status detail already returned by Main is underused, group headers imply collapse without supporting it, and common stage, unstage, discard, and commit workflows require leaving the panel for a terminal.

## Outcome

Turn Changes into a compact Source Control panel inspired by Orca while preserving SpireCode's Project -> Worktree -> Editor model, keyboard-accessible tree, automatic refresh, and strict Renderer/Main boundary.

Success means users can filter and inspect accurate change metadata, stage or unstage individual/groups of files, safely discard eligible worktree changes, and commit staged changes without exposing paths, shell commands, or generic Git execution to Renderer.

## Non-goals

- Push, pull, sync, publish branch, or force push.
- Pull request or hosted review workflows.
- AI-generated commit messages or conflict repair.
- Git history or branch comparison.
- Multi-selection, virtualized rows, submodule expansion, or remote runtime routing.
- A manual refresh control; watcher-driven refresh remains authoritative.
25 changes: 25 additions & 0 deletions docs/orca-aligned-source-control/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Plan: Orca-aligned Source Control

## Phase 1: Rich read-only interaction

1. Add a projection layer for conflicts, staged, unstaged, and untracked sections.
2. Add filtering, collapsible section headers, and an overflow view-mode menu without reintroducing manual refresh.
3. Render status-specific decoration, parent/original paths, numstat, active Diff state, and correct ARIA structure.
4. Add focused tests for projection, filtering, grouping, collapse, keyboard navigation, and status display.

This phase is independently usable as a richer diff browser.

## Phase 2: Safe Git mutations

1. Add narrow command contracts, IPC argument validation, bindings, and GitService methods for stage, unstage, discard, and commit.
2. Extend backend tests first for normal operation, rename, path attacks, symlink escape, untracked deletion, Git failures, and per-worktree serialization.
3. Add row and section actions with mutation state and post-success refresh.
4. Add a destructive discard dialog and coordinate dirty/in-flight editor saves before mutation.
5. Add per-worktree commit drafts, eligibility, keyboard submit, single-flight execution, and post-commit refresh.
6. Verify focused tests, the full quality gate, production build, and final diff.

This phase is independently usable without future remote, PR, history, AI, multi-select, or virtualization work.

## Rollback

The feature stores no migration state. Reverting the narrow commands, panel interactions, and styles restores the prior read-only viewer. Git mutations themselves are explicit user actions and are not automatically reversible; discard therefore remains confirmation-gated.
71 changes: 71 additions & 0 deletions docs/orca-aligned-source-control/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Spec: Orca-aligned Source Control

## Panel structure

- The header shows the unique changed-file count, a compact path filter, and an overflow menu containing List and Tree view choices.
- There is no manual Refresh action.
- Entries are projected into Conflicts, Staged Changes, Changes, and Untracked Files. Empty sections are omitted.
- Sections are collapsible buttons with `aria-expanded`, visible counts, and eligible section actions.
- Filtering matches the full relative path case-insensitively. Section-wide actions are hidden while filtering so visible results cannot be mistaken for the mutation scope.

## Change rows

- Rows retain roving tree focus, Arrow/Home/End navigation, Enter/Space preview opening, single-click preview, and double-click pinning.
- Rows show filename, muted parent path in list mode, accurate status labels and colors, rename origin when present, and available addition/deletion counts.
- Conflicts are shown before normal groups and are not presented as untracked changes.
- Active Diff rows remain visibly selected.
- Eligible hover/focus actions are Stage, Unstage, and Discard.

## Git mutations

Renderer receives only narrow commands:

- `git_stage(worktreeId, relativePath)`
- `git_unstage(worktreeId, relativePath)`; Main derives any rename origin from current status
- `git_discard(worktreeId, relativePath, untracked)`
- `git_commit(worktreeId, message)`

Main resolves worktree IDs to registered roots and validates every relative path. It rejects empty/absolute/traversal/NUL/`.git` paths and symlink escape. Git commands use argument arrays through the hardened runner, clear repository/index redirect environment variables, disable system Git config, and execute serially per worktree. Repositories selecting executable Git filters fail closed and must use the terminal for those operations.

- Stage uses literal pathspec separation.
- Unstage restores the index from HEAD and includes both rename paths when required.
- Discard tracked restores only the selected worktree path.
- Discard untracked moves only the validated selected file or symlink entry to system Trash; it never invokes repository-wide clean, never follows the leaf symlink, and rejects directories.
- Commit requires a non-empty message within the IPC limit and commits staged content only.
- Mutation success and subsequent refresh failure are reported separately; successful mutations are never presented as failed solely because refresh failed.

## Discard safety

- Discard always requires an explicit destructive confirmation describing the target.
- Unresolved conflicts cannot be discarded from the panel.
- A dirty file cannot be discarded until its in-flight editor save has settled; the confirmation warns that unsaved content will be lost.
- After successful discard, file and diff resource caches are invalidated and visible editors reload from disk. For discarded untracked files, affected tabs are removed only after Main succeeds.
- Failure leaves editor state and caches intact.

## Commit

- Commit drafts are session-scoped and keyed by worktree ID.
- Commit is enabled only when staged entries exist, the trimmed message is non-empty, there is no unresolved conflict, and no mutation is active.
- Command/Ctrl+Enter submits only when Commit is eligible and ignores IME composition.
- Submission is single-flight. Success clears the draft only if the user has not edited it during the request, then refreshes status and open diffs.

## Refresh and concurrency

- Existing `git://changed` watcher refresh remains active.
- Renderer mutation state prevents duplicate operations.
- Changes and Diff generation guards continue to reject stale results.
- Main serializes status, diff, save, and Git mutations per worktree through the existing worktree operation queue boundary.

## Accessibility

- Header controls expose toolbar/group semantics and labels.
- Section headers expose expanded state and action labels.
- Row actions are keyboard-focusable and do not steal row preview activation.
- Dialogs trap focus, close on Escape when idle, and expose descriptions/errors through ARIA.

## Acceptance

- Happy paths: stage, unstage, tracked discard, untracked discard, and commit update the repository and panel correctly.
- Error paths: Git failure, path rejection, stale refresh failure, save conflict, and duplicate invocation preserve consistent state.
- Edge paths: rename, staged+unstaged file, deleted file, untracked file, unresolved conflict, detached HEAD, empty repository, and worktree switch are covered.
- `pnpm check`, `pnpm build`, and `git diff --check` pass.
15 changes: 15 additions & 0 deletions docs/project-files-surface-alignment/intent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Intent: Align Projects overlays with Files

## Problem

Projects currently uses older overlay styling for worktree dialogs, project/worktree action menus, and branch options. Their borders, radii, spacing, typography, hover states, and widths differ from the newer Files dialog and context-menu surfaces, making adjacent navigation modules feel unrelated.

## Outcome

Projects overlays use the same visual language as Files while retaining their existing behavior, accessibility semantics, and project/worktree workflows.

## Non-goals

- Changing project or worktree operations.
- Replacing existing dialog focus management.
- Changing Files behavior or introducing new dependencies.
6 changes: 6 additions & 0 deletions docs/project-files-surface-alignment/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Plan: Align Projects overlays with Files

1. Consolidate Projects menu selectors with the Files context-menu dimensions and semantic tokens.
2. Align worktree dialog geometry, typography, controls, and actions with the Files confirmation dialog.
3. Align branch option rows with Files menu rows while preserving listbox selection behavior.
4. Run focused Projects tests and the full repository quality gate.
18 changes: 18 additions & 0 deletions docs/project-files-surface-alignment/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Spec: Align Projects overlays with Files

## Dialogs

- Worktree create, rename, and delete dialogs match the Files confirmation dialog's width, border, radius, background, shadow, title typography, and compact spacing.
- Form controls and action buttons continue to expose clear focus, primary, destructive, disabled, and pending states.

## Menus

- Project actions, worktree actions, and the origin-branch option list match the Files context menu's popover surface, border, radius, shadow, minimum row height, typography, and neutral hover state.
- Destructive actions remain visually distinct.
- Existing menu roles, listbox roles, keyboard behavior, and action semantics remain unchanged.

## Acceptance

- Projects and Files overlays use the same semantic surface and interaction tokens.
- Existing Projects and Files tests pass.
- Formatting, lint, type checking, and all repository tests pass.
Loading
Loading