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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ ui/coverage/
.npm/
.yarn/
.pnpm-store/
ui/.vite/
*.tgz
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# ── Environment & secrets ─────────────────────────────────────────────────────

Expand Down
12 changes: 0 additions & 12 deletions .npmignore

This file was deleted.

6 changes: 4 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# gitlocal Development Guidelines

Auto-generated from all feature plans. Last updated: 2026-04-02
Auto-generated from all feature plans. Last updated: 2026-04-04

## Active Technologies
- **Runtime**: Node.js 22+ (active LTS), TypeScript 5.x
Expand All @@ -14,6 +14,8 @@ Auto-generated from all feature plans. Last updated: 2026-04-02
- No database; runtime state is derived from the filesystem, git metadata, browser URL state, and in-memory UI state (004-copy-control-polish)
- TypeScript 5.x on Node.js 22+ for server and CLI, TypeScript + React 18 for the UI + Hono, @hono/node-server, React 18, Vite 7, react-markdown, rehype-highlight, highlight.js, Vitest, React Testing Library, esbuild (005-version-line-numbers)
- No database; runtime state comes from local filesystem metadata, git metadata, build/package metadata, URL state, and in-memory server state (005-version-line-numbers)
- TypeScript 5.x on Node.js 22+ for server and CLI, TypeScript + React 18 for the UI + Hono, @hono/node-server, React 18, @tanstack/react-query, Vite 7, Vitest, React Testing Library, esbuild (006-manual-file-editing)
- No database; runtime state is derived from the local filesystem, git metadata, browser URL state, and in-memory server/UI state (006-manual-file-editing)

## Project Structure

Expand All @@ -39,9 +41,9 @@ npm run verify # Run tests, builds, and dependency audits
TypeScript 5.x + Node.js 22+: follow standard conventions. Use `.js` extensions on all imports (NodeNext module resolution). No Go, no Makefile, no shell scripts.

## Recent Changes
- 006-manual-file-editing: Added TypeScript 5.x on Node.js 22+ for server and CLI, TypeScript + React 18 for the UI + Hono, @hono/node-server, React 18, @tanstack/react-query, Vite 7, Vitest, React Testing Library, esbuild
- 005-version-line-numbers: Added TypeScript 5.x on Node.js 22+ for server and CLI, TypeScript + React 18 for the UI + Hono, @hono/node-server, React 18, Vite 7, react-markdown, rehype-highlight, highlight.js, Vitest, React Testing Library, esbuild
- 004-copy-control-polish: Added TypeScript 5.x on Node.js 22+ for server and CLI, TypeScript + React 18 for the UI + Hono, @hono/node-server, React 18, Vite 7, @tanstack/react-query, react-markdown, remark-gfm, rehype-highlight, highlight.js, Vitest, esbuild
- 004-copy-control-polish: Added TypeScript 5.x on Node.js 22+ for server and CLI, TypeScript + React 18 for the UI + Hono, @hono/node-server, React 18, Vite 7, @tanstack/react-query, react-markdown, remark-gfm, rehype-highlight, highlight.js, Vitest, esbuild

<!-- MANUAL ADDITIONS START -->
<!-- MANUAL ADDITIONS END -->
35 changes: 35 additions & 0 deletions specs/006-manual-file-editing/checklists/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Specification Quality Checklist: Manual Local File Editing

**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-04-04
**Feature**: [spec.md](../spec.md)

## Content Quality

- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
- [x] All mandatory sections completed

## Requirement Completeness

- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Success criteria are technology-agnostic (no implementation details)
- [x] All acceptance scenarios are defined
- [x] Edge cases are identified
- [x] Scope is clearly bounded
- [x] Dependencies and assumptions identified

## Feature Readiness

- [x] All functional requirements have clear acceptance criteria
- [x] User scenarios cover primary flows
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification

## Notes

- Validation pass 1 completed with all checklist items satisfied.
- The specification intentionally bounds the feature to lightweight text-file operations and excludes IDE-scale editing workflows.
52 changes: 52 additions & 0 deletions specs/006-manual-file-editing/contracts/manual-file-operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Manual File Operations Contract

## File Read Contract

- `GET /api/file` continues to return the current file content payload for viewer rendering.
- For working-tree text files, the payload also includes:
- `editable`: whether inline editing is allowed in the current context.
- `revisionToken`: the snapshot token required for guarded update and delete requests.
- Non-text files and non-working-tree contexts must return `editable: false`.

## Create File Contract

- `POST /api/file` creates a new local file inside the opened repository.
- Request body:
- `path`: repository-relative target path.
- `content`: initial file content.
- Success behavior:
- Returns `ok: true`, `operation: "create"`, `status: "created"`, and the created `path`.
- Failure behavior:
- Blocks requests for existing paths, invalid paths, and paths outside the repository boundary.

## Update File Contract

- `PUT /api/file` saves manual edits to an existing local text file.
- Request body:
- `path`: repository-relative target path.
- `content`: replacement file content.
- `revisionToken`: snapshot token from the last successful read.
- Success behavior:
- Returns `ok: true`, `operation: "update"`, `status: "updated"`, and the updated `path`.
- Failure behavior:
- Returns `status: "conflict"` when the revision token no longer matches the on-disk file state.
- Returns a blocked or failed result for invalid paths, missing files, non-text files, or non-working-tree contexts.

## Delete File Contract

- `DELETE /api/file` removes an existing local file after UI confirmation.
- Request body:
- `path`: repository-relative target path.
- `revisionToken`: snapshot token from the last successful read.
- Success behavior:
- Returns `ok: true`, `operation: "delete"`, `status: "deleted"`, and the deleted `path`.
- Failure behavior:
- Returns `status: "conflict"` when the file changed after it was opened.
- Returns a blocked or failed result if the path is outside the repository boundary or cannot be removed.

## UI Interaction Contract

- Inline editing controls appear only for editable working-tree text files.
- New-file creation can be started from the repository view without leaving the app.
- Delete actions always require a confirmation step before the request is sent.
- After any successful create, update, or delete, the UI refreshes file and tree data from the server and updates the current selection accordingly.
80 changes: 80 additions & 0 deletions specs/006-manual-file-editing/data-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Data Model: Manual Local File Editing

## Editable File Snapshot

- **Description**: The server-provided representation of a local text file that can be shown in the content panel and, when allowed, edited inline.
- **Fields**:
- `path`: Repository-relative file path.
- `content`: Current text content.
- `type`: Textual presentation type used by the viewer.
- `language`: Optional language hint for display.
- `editable`: Whether inline editing is allowed for this file in the current context.
- `revisionToken`: Snapshot token representing the file state at read time.
- **Validation rules**:
- `path` must stay inside the opened repository boundary.
- `editable` is false for non-text files and non-working-tree contexts.
- `revisionToken` must change when the underlying file content changes on disk.
- **Relationships**:
- Returned by the file-read contract.
- Used to initialize an inline edit session.

## New File Draft

- **Description**: The in-progress user input collected before creating a new file.
- **Fields**:
- `path`: Proposed repository-relative file path.
- `content`: Initial file content.
- **Validation rules**:
- `path` must not be empty.
- `path` must resolve inside the repository boundary.
- `path` must not already exist as a file or directory.
- **Relationships**:
- Submitted through the create-file contract.
- On success, becomes an editable file snapshot.

## File Mutation Request

- **Description**: A create, update, or delete action sent from the UI to the server.
- **Fields**:
- `operation`: `create`, `update`, or `delete`.
- `path`: Target repository-relative file path.
- `content`: New text content for create/update operations.
- `revisionToken`: Required for update and delete operations against an existing file snapshot.
- **Validation rules**:
- `create` requires `path` and allows optional empty `content`.
- `update` requires `path`, `content`, and `revisionToken`.
- `delete` requires `path`, `revisionToken`, and explicit user confirmation before the request is sent.
- **Relationships**:
- Processed by server-side file mutation handlers.
- Produces either a successful file operation result or a conflict/error result.

## File Operation Result

- **Description**: The normalized server response after a file mutation attempt.
- **Fields**:
- `ok`: Whether the operation succeeded.
- `operation`: `create`, `update`, or `delete`.
- `path`: The affected repository-relative path.
- `status`: `created`, `updated`, `deleted`, `conflict`, `blocked`, or `failed`.
- `message`: User-displayable outcome summary.
- **Validation rules**:
- Failed results must not imply a filesystem change when none occurred.
- Conflict results must be used when the stored `revisionToken` no longer matches the on-disk file snapshot.
- **Relationships**:
- Drives status messaging, query invalidation, and selection updates in the UI.

## Inline Edit Session

- **Description**: The UI-only state for a lightweight manual editing flow.
- **Fields**:
- `mode`: `view`, `edit`, `create`, or `confirm-delete`.
- `draftPath`: Current path input for file creation.
- `draftContent`: Current unsaved content.
- `dirty`: Whether the user has unsaved changes.
- `baseRevisionToken`: Revision token captured from the last successful file read.
- **Validation rules**:
- `dirty` becomes true after user changes content or a new-file path.
- Leaving a dirty session requires a warning or explicit discard action.
- **Relationships**:
- Initialized from an editable file snapshot or an empty new file draft.
- Cleared or reset after successful save, delete, or discard.
94 changes: 94 additions & 0 deletions specs/006-manual-file-editing/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Implementation Plan: Manual Local File Editing

**Branch**: `006-manual-file-editing` | **Date**: 2026-04-04 | **Spec**: `specs/006-manual-file-editing/spec.md`
**Input**: Feature specification from `specs/006-manual-file-editing/spec.md`

**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/plan-template.md` for the execution workflow.

## Summary

Add a lightweight manual editing workflow to GitLocal so users can make small local file changes without leaving the app: edit existing text files, create new files, and delete files safely. The implementation stays inside the current Hono + React architecture by extending the file handler surface with guarded working-tree mutation endpoints, teaching the working-tree tree view to reflect real filesystem state, and layering a small inline editor flow into the existing content panel with conflict and unsaved-change protection.

## Technical Context

**Language/Version**: TypeScript 5.x on Node.js 22+ for server and CLI, TypeScript + React 18 for the UI
**Primary Dependencies**: Hono, @hono/node-server, React 18, @tanstack/react-query, Vite 7, Vitest, React Testing Library, esbuild
**Storage**: No database; runtime state is derived from the local filesystem, git metadata, browser URL state, and in-memory server/UI state
**Testing**: Vitest for backend and frontend, React Testing Library for UI workflows, Hono integration tests for file API behavior
**Target Platform**: Local desktop browser sessions on macOS, Windows, and Linux, served by the local Node.js process
**Project Type**: Local-first CLI application with a Node.js-served React single-page app
**Performance Goals**: File create, update, and delete actions should complete fast enough to feel immediate for ordinary text files, and the file tree should reflect successful changes without a full page reload
**Constraints**: Fully local runtime only, maintain at least 90% per-file coverage, keep generated artifacts repository-relative, preserve GitLocal's lightweight GitHub-like browsing experience, restrict mutation to the current working tree, and avoid expanding the feature into a multi-file IDE workflow
**Scale/Scope**: One open repository at a time, one active inline edit session in the content area, and lightweight text-file operations only for the current working-tree branch

## Constitution Check

*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*

- **TypeScript-First**: Pass. All planned server and UI work remains in the existing TypeScript codebase.
- **Test Coverage**: Pass. The plan includes backend handler tests, tree behavior tests, and UI workflow tests to preserve the ≥90% per-file requirement.
- **Fully Local**: Pass. File reads and mutations operate only on the local filesystem within the opened repository.
- **Node.js-Served React UI**: Pass. The feature extends the existing Hono-served SPA rather than changing the product architecture.
- **Clean & Useful UI**: Pass. The editing workflow stays focused on small manual interventions and avoids turning the app into a full IDE.
- **Free & Open Source**: Pass. No new proprietary or gated dependencies are introduced.
- **Repository-Relative Paths**: Pass. All generated planning artifacts use repository-relative paths.

**Post-Design Check**: Pass. The design stays within the local TypeScript/React architecture, uses server-truth refresh after mutations, and explicitly bounds the UI to a single lightweight edit flow rather than IDE-scale editing.

## Project Structure

### Documentation (this feature)

```text
specs/006-manual-file-editing/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│ └── manual-file-operations.md
└── tasks.md
```

### Source Code (repository root)

```text
src/
├── git/
│ ├── repo.ts
│ └── tree.ts
├── handlers/
│ └── files.ts
├── server.ts
└── types.ts

tests/
├── integration/
│ └── server.test.ts
└── unit/
└── handlers/
└── files.test.ts

ui/
├── src/
│ ├── App.css
│ ├── App.tsx
│ ├── services/
│ │ └── api.ts
│ ├── types/
│ │ └── index.ts
│ └── components/
│ ├── ContentPanel/
│ │ ├── ContentPanel.tsx
│ │ ├── ContentPanel.test.tsx
│ │ └── [new lightweight editor helpers as needed]
│ └── FileTree/
│ ├── FileTree.tsx
│ └── FileTree.test.tsx
```

**Structure Decision**: Keep the feature inside the current single-project Hono + React layout. Server-side repository and path safety logic stays centralized in `src/git/` and `src/handlers/files.ts`, while the UI work remains in the existing content panel, file tree, shared API client, and app-level selection/query refresh flow.

## Complexity Tracking

No constitutional violations or exceptional complexity allowances are required for this feature.
25 changes: 25 additions & 0 deletions specs/006-manual-file-editing/quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Quickstart: Manual Local File Editing

## Prerequisites

- Install dependencies with `npm ci` and `npm --prefix ui ci`.
- Start GitLocal against a local git repository that contains text files and at least one nested directory.

## Validation Flow

1. Start the app in a local repository and open a text file on the current branch.
2. Enter inline edit mode, change a small piece of text, save, and confirm the updated content is shown afterward.
3. Begin another edit, modify the content without saving, then navigate away and confirm GitLocal warns before discarding the unsaved change.
4. Create a new file in an existing folder, save it, and confirm the new file appears in the file tree and opens immediately.
5. Attempt to create a file at a path that already exists and confirm the app blocks the action with a clear explanation.
6. Delete an existing file, confirm the deletion in the confirmation step, and verify the file disappears from the tree and content view.
7. Trigger a delete flow and cancel it, then confirm the file remains available.
8. Change a file outside the app after opening it in edit mode, then try to save or delete from GitLocal and confirm the app reports a conflict instead of overwriting silently.
9. Open a binary or image file and confirm inline text editing is not offered.
10. Switch to a non-current branch view, if available, and confirm create, update, and delete actions are unavailable there.

## Automated Checks

- Run `npm test`.
- Run `npm run lint`.
- Run `npm run build`.
Loading
Loading