Skip to content
Open
Show file tree
Hide file tree
Changes from 107 commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
35bc738
docs(specs): scaffold 005-project-git-versioning
yuto-trd Jul 28, 2026
90800d4
docs(specs): clarify 005-project-git-versioning
yuto-trd Jul 28, 2026
c6981da
docs(specs): plan 005-project-git-versioning
yuto-trd Jul 28, 2026
8b7f98e
docs(specs): tasks 005-project-git-versioning
yuto-trd Jul 28, 2026
c27a56e
feat!: keep project files byte-stable across saves
yuto-trd Jul 28, 2026
b9df98a
fix: normalize scene element patterns to '/' separators
yuto-trd Jul 28, 2026
88551da
feat: name new element files by element id
yuto-trd Jul 28, 2026
d479482
feat: add version control configuration and strings
yuto-trd Jul 28, 2026
d969519
feat: add git CLI version control core
yuto-trd Jul 28, 2026
cad8731
feat: add repository init and snapshot commits to the version control…
yuto-trd Jul 28, 2026
393ad47
feat: snapshot projects on save and close from the editor shell
yuto-trd Jul 28, 2026
ce120c4
feat: add history queries and worktree restore to the version control…
yuto-trd Jul 28, 2026
5a1b8dc
feat: add the Version Control tool tab with history browsing and restore
yuto-trd Jul 28, 2026
bd010d2
feat: scope version control safely inside enclosing repositories
yuto-trd Jul 28, 2026
83211b9
feat: degrade version control gracefully and guard conflicted project…
yuto-trd Jul 28, 2026
937043f
feat: add branches, remotes, and media policy to the version control …
yuto-trd Jul 28, 2026
482828f
feat: add manual commits, branch switching, and remote sync to the sh…
yuto-trd Jul 28, 2026
4a54b1b
test: add version control stress, scope, performance, and menu-comple…
yuto-trd Jul 28, 2026
23fcc19
style: fix file encodings and import ordering flagged by dotnet format
yuto-trd Jul 28, 2026
1fb7055
test: assert the context-command mapping for Enable Version Control a…
yuto-trd Jul 28, 2026
8acce38
feat: improve Version Control tab usability
yuto-trd Jul 28, 2026
e2a229e
feat: make the Version Control tab layout adapt to its width
yuto-trd Jul 28, 2026
c075819
feat: replace the version control action row with a VS Code-style con…
yuto-trd Jul 28, 2026
909652d
fix: recognize an already-initialized repository in a restored Versio…
yuto-trd Jul 29, 2026
12e0ebb
feat: move branch controls into a JetBrains-style title-bar widget
yuto-trd Jul 29, 2026
17da844
feat: restyle the title-bar branch flyout as a structured popup
yuto-trd Jul 29, 2026
31aabab
feat: dock the branch button beside the title-bar breadcrumb with mat…
yuto-trd Jul 29, 2026
194806d
refactor: drop the branch search box from the title-bar flyout
yuto-trd Jul 29, 2026
6efc61d
refactor: share one compact flyout theme between the breadcrumb and b…
yuto-trd Jul 29, 2026
61248ce
fix: improve version control tab interactions
yuto-trd Jul 31, 2026
af58fc9
fix: move version control spacing inside scroll views
yuto-trd Jul 31, 2026
e79e45b
fix: refine version control interactions
yuto-trd Jul 31, 2026
57fa63c
test: normalize version control test encoding
yuto-trd Jul 31, 2026
c779525
fix!: address version control review findings
yuto-trd Jul 31, 2026
47746a5
refactor!: make project version-control transitions transactional
yuto-trd Jul 31, 2026
ca74157
fix: harden asynchronous application teardown
yuto-trd Aug 1, 2026
5f40222
refactor!: complete project version-control review hardening
yuto-trd Aug 1, 2026
4d6d848
fix: bound snapshot ignore detection
yuto-trd Aug 1, 2026
1af75ea
fix: address remaining version control reviews
yuto-trd Aug 1, 2026
86394e8
fix: harden version control integration boundaries
yuto-trd Aug 1, 2026
c0515d5
refactor!: complete version control recovery hardening
yuto-trd Aug 1, 2026
c7958a0
fix: address post-CI version control reviews
yuto-trd Aug 1, 2026
c9b7c4e
fix: accept canonical repository aliases
yuto-trd Aug 1, 2026
c6743f9
refactor!: harden repository operation boundaries
yuto-trd Aug 1, 2026
5d19c58
fix: close remaining repository safety gaps
yuto-trd Aug 1, 2026
8199000
fix: preserve version control assets and history
yuto-trd Aug 1, 2026
ac2f67b
fix: harden repository transitions and identity
yuto-trd Aug 1, 2026
31ffd7c
refactor!: drain render jobs before shutdown
yuto-trd Aug 1, 2026
191ecaa
fix: keep repository LFS policy current
yuto-trd Aug 1, 2026
dda96cc
fix(review): harden package export staging and conflict detection
yuto-trd Aug 8, 2026
0f32afe
fix(review): bind prompts to the originating service generation
yuto-trd Aug 8, 2026
8166f38
fix(review): cover project-wide media with the LFS policy
yuto-trd Aug 8, 2026
460b480
fix(review): recover stale remote-tracking ref locks
yuto-trd Aug 8, 2026
3aaa13d
fix(review): address PR #2164 findings
yuto-trd Aug 9, 2026
d5cd23d
fix(review): preserve Unix watcher paths
yuto-trd Aug 9, 2026
512d06b
fix(review): gate proxy generation against restores
yuto-trd Aug 9, 2026
fcf6a7a
fix(review): harden LFS worktree transitions
yuto-trd Aug 9, 2026
890c8a8
fix(review): exclude local state from initial snapshots
yuto-trd Aug 9, 2026
6f1559c
fix(review): harden pull and persisted project state
yuto-trd Aug 9, 2026
d04a9ec
fix(review): reject credential-bearing remote URLs
yuto-trd Aug 9, 2026
7830198
fix(review): preserve relocated file source state
yuto-trd Aug 9, 2026
2803fb6
fix(review): harden snapshot and remote boundaries
yuto-trd Aug 9, 2026
f16f83a
fix(review): harden LFS staging and snapshot safety
yuto-trd Aug 9, 2026
e147365
fix(review): redact remote URL query credentials
yuto-trd Aug 9, 2026
e4464f4
fix(review): isolate Git author identity
yuto-trd Aug 9, 2026
8724762
fix(review): serialize status notifications
yuto-trd Aug 9, 2026
79cc4d9
Merge origin/main into yuto-trd/project-git-version-control
yuto-trd Aug 9, 2026
267a804
fix(agent-toolkit): lease motion analysis output
yuto-trd Aug 9, 2026
608d2f2
fix(version-control): cover repository metadata edge cases
yuto-trd Aug 9, 2026
653c1fa
fix!: preserve version control operation consistency
yuto-trd Aug 9, 2026
1189525
fix(version-control): recognize Git config lock errors
yuto-trd Aug 9, 2026
465bd5a
fix(version-control): hide credentials from remote prompt
yuto-trd Aug 9, 2026
79e5f0b
fix(version-control): address repository review findings
yuto-trd Aug 9, 2026
1abb8aa
fix(version-control): close remaining review races
yuto-trd Aug 9, 2026
e46ece9
fix(version-control): preserve project data across Git operations
yuto-trd Aug 9, 2026
2b906f9
refactor!: coordinate workspace-safe output and persistence
yuto-trd Aug 9, 2026
4450c7b
fix(version-control): persist in-memory edits before restore and rese…
yuto-trd Aug 9, 2026
a1cdadd
fix!: close the save and version-control workspace races
yuto-trd Aug 12, 2026
92207db
fix(version-control): close the review findings on PR 2164
yuto-trd Aug 12, 2026
87791fc
fix(version-control): key opening-recovery markers canonically
yuto-trd Aug 12, 2026
8077e7f
feat(version-control): offer to untrack reserved project state on ini…
yuto-trd Aug 13, 2026
cabb139
fix(version-control): correct path identity, export leasing and shutd…
yuto-trd Aug 13, 2026
77d35a4
fix(version-control)!: gate repository adoption and persist edits bef…
yuto-trd Aug 15, 2026
815b9f4
Merge branch 'main' into yuto-trd/project-git-version-control
yuto-trd Aug 16, 2026
3ead9d7
test(headless): clear the latched shutdown request between test cases
yuto-trd Aug 16, 2026
8ec5684
fix: reserve the workspace for every export and repair the stale test…
yuto-trd Aug 16, 2026
91e448c
fix(version-control): recover a missing project file before refusing …
yuto-trd Aug 16, 2026
0a0da95
fix(version-control): abort the close when the pre-close save fails
yuto-trd Aug 16, 2026
9056e15
fix(version-control): normalize on-disk casing on every case-insensit…
yuto-trd Aug 17, 2026
cc4764f
fix(version-control): prefetch LFS objects before pull and restore ch…
yuto-trd Aug 17, 2026
5979f46
fix(version-control): settle the branch widget on the current status,…
yuto-trd Aug 17, 2026
f9cf969
refactor(version-control): make the tool tab the only version control…
yuto-trd Aug 20, 2026
f736589
feat(version-control): report the enable operation as running in the …
yuto-trd Aug 20, 2026
bbf7328
refactor(extensibility): let handlers publish their own context comma…
yuto-trd Aug 20, 2026
12946cb
fix(version-control): restore the index when untracking reserved path…
yuto-trd Aug 20, 2026
45893fe
fix(version-control): save again before retrying a manual commit afte…
yuto-trd Aug 20, 2026
6ad42c9
fix(version-control): resume tracking an adopted enclosing repository…
yuto-trd Aug 20, 2026
9652668
fix(version-control): prefetch pull LFS objects at the fetched upstre…
yuto-trd Aug 20, 2026
600c18f
fix(version-control): clear the repository LFS path filters during wo…
yuto-trd Aug 20, 2026
569cc44
fix(version-control): keep restore-to-a-new-branch scoped to the project
yuto-trd Aug 20, 2026
41ea3a2
fix(agent-host): treat a suspended editor as an unavailable live session
yuto-trd Aug 20, 2026
699b677
fix(version-control): exclude reserved watcher directories by the fil…
yuto-trd Aug 20, 2026
2914e87
fix(version-control): fail a transition when a failed LFS prefetch le…
yuto-trd Aug 21, 2026
7754b5c
fix(version-control): retain only a bounded tail of progress-bearing …
yuto-trd Aug 21, 2026
60ba1e8
fix(version-control): refresh status when repository-local attributes…
yuto-trd Aug 21, 2026
9576a96
fix(editor): serialize a package export against project-file writes
yuto-trd Aug 21, 2026
fa3c6fa
fix(version-control): stop a branch switch from clobbering ignored fi…
yuto-trd Aug 21, 2026
4c9f5ab
fix(shell): resolve the macOS extension menus by header instead of po…
yuto-trd Aug 21, 2026
8a50133
fix(version-control): bound progress records and find Git without the…
yuto-trd Aug 21, 2026
a809af2
fix(version-control): follow the project graph for conflict scans, sn…
yuto-trd Aug 21, 2026
6fc391e
fix(shell): keep the application open when a close abandons itself, a…
yuto-trd Aug 21, 2026
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: 1 addition & 1 deletion .specify/feature.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"feature_directory": "docs/specs/002-proxy-media"
"feature_directory": "docs/specs/005-project-git-versioning"
}
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ For large, parallelizable work that splits into independent units — dead-code/

- **001 — Agent Editing Toolkit** (ACTIVE): plan at [`docs/specs/001-agent-editing-toolkit/plan.md`](docs/specs/001-agent-editing-toolkit/plan.md) (spec/research/data-model/contracts in the same dir). An **MCP server + Skills + Subagents** so external AI agents author/edit Beutl projects **headlessly** (no live-GUI automation). **Declarative-first**: the agent reads an identity-anchored JSON document and submits a desired end-state — a full document or a **JSON Merge Patch (RFC 7396)** — which the toolkit reconciles by **`CoreObject.Id` diff** into Beutl's **undoable `HistoryManager` operations** via the `CoreObjectOperationObserver` recording pipeline (**never raw `PopulateFromJsonObject`/`SetValue` on the live root** — that mints new children, destroying `Id` identity and bypassing undo), behind a **plan/apply** dry-run. Schema/capability discovery comes from `PropertyRegistry` **plus `EngineObject.Properties`** (the modern per-object `IProperty` surface holds most editable params; `PropertyRegistry` alone misses them); `$type` via `JsonHelper.WriteDiscriminator` (`TypeFormat` is internal). Two new **MIT `net10.0`** projects — `Beutl.AgentToolkit` (core lib) + `Beutl.AgentToolkit.Mcp` (stdio console exe, SDK `ModelContextProtocol` 1.4.0, logs→STDERR). Headless still render via `SceneRenderer`/`Renderer.Snapshot` (SKSL runs on CPU; GLSL/3D run on the Vulkan backend — hardware, MoltenVK, or the bundled SwiftShader software fallback — so shader/3D effects are always available, just slower on the software path); **video export in v1** reaches the GPL worker **only via `Beutl.FFmpegIpc`** (no `Beutl.FFmpegWorker` `ProjectReference`). Writes confined to a configured **workspace root** (read anywhere); audio is first-class. **Real-time UI reflection** is delivered by **in-app hosting**: the running editor hosts a loopback HTTP/SSE MCP endpoint (`ModelContextProtocol.AspNetCore`) bound to the active `EditViewModel`'s live `Scene`+`HistoryManager` (**one writer; no new IPC** — Beutl has none into the running app), so agent edits update the preview/timeline/undo stack live; the headless stdio exe handles the no-GUI case via a file-opened session (the `Sessions/` *source* seam swaps file↔live). **Do NOT** add a live-GUI-*automation* (simulated-input) path, a JSON-patch dependency, a universal byte-identity rule, or a GPL `ProjectReference`; in-app live *observation* of the shared model IS in scope and is **not** GUI automation. When building this toolkit, consult that plan + contracts.
- **002 — Proxy Media Workflow** (ACTIVE): plan at [`docs/specs/002-proxy-media/plan.md`](docs/specs/002-proxy-media/plan.md). Spec, research, data-model, contracts, and quickstart live in the same directory.
- **005 — Git Version Control for Editing Projects** (ACTIVE): plan at [`docs/specs/005-project-git-versioning/plan.md`](docs/specs/005-project-git-versioning/plan.md) (spec/research/data-model/contracts/quickstart in the same dir). In-app Git versioning uses the **user's installed `git` CLI only** (≥ 2.23; **no LibGit2Sharp**, no bundled git; graceful degradation when absent). Snapshots fire on **explicit Save/Save All/close only** (never per autosave tick or timer), plus manual commits; automatic messages are stable English with a `Beutl-Snapshot:` trailer. The Avalonia-free public `IProjectVersionControlService` in `src/Beutl.Editor/VersionControl/` is **read/query only**; `VersionControlCoordinator` owns the internal Active→Retiring→Retired backend, all user-level version-control mutations, and one exclusive **durably preserve → close → operation-specific transaction → reopen** cycle. Consented stale-lock removal remains the sole narrow mutation exposed separately through `IRepositoryLockRecoveryService`. `IProjectVersionControlInitializer.InitializeCurrentProjectAsync(Project expectedProject, ...)` requires the exact currently open project as a concurrency guard, forwards the exact operation token to the identity callback, and rejects initialization if another project becomes current; the identity flyout observes that token and closes itself on the UI thread when cancellation is requested. This is a breaking migration with no parameterless shim, so use `feat!:`/`refactor!:` plus a `BREAKING CHANGE:` footer naming the callback change. Dirty restore/switch makes a Safety commit; dirty pull writes `refs/beutl/safety/*` without moving the branch, builds the merged tree and Safety commit off-ref, then applies that exact state. Restore is **restore-as-new-commit**; a post-commit failure appends a compensating Recovery commit. Tree transitions hold the worktree-private `HEAD.lock`, validate scoped worktree/index fingerprints, and compare-and-swap the same attached branch from its exact expected tip as the final durable step; external ref movement yields `OwnershipLost`, unverified recovery yields `RecoveryFailed`, and neither may be overwritten or reopened automatically. `RepositoryDirty` is reserved for actual cleanliness-precondition failures; the coordinator renders either unsafe transition state as exactly the localized uncertain-transition failure without composing inner result text. Enclosing repositories are detected and project-file mutations are **pathspec-scoped to the project directory**; branch/push/pull, whole-repository cleanliness checks, and guarded branch CAS retain disclosed repository-wide semantics. Four serialization prerequisites land first: `{Id:N}.belm` naming (`ElementFileNaming`), appVersion migration semantics (`feat!:`), Include/Exclude `/` normalization, and `JsonHelper` `NewLine="\n"` pinning. **Do NOT** expose merge (beyond fast-forward pull), rebase, destructive reset, force-push, other history rewriting, detached HEAD on the user's project worktree, partial staging, timer checkpoints, or LibGit2Sharp; never parse human-facing Git output (porcelain v2 `-z` only), and always set `GIT_TERMINAL_PROMPT=0` + `GIT_OPTIONAL_LOCKS=0` + `GIT_LITERAL_PATHSPECS=1`, except the validated NUL-delimited `check-ignore --stdin -z` probe sets literal pathspecs to `0` so ignore patterns are evaluated. When building this feature, consult that plan and contracts.
- **003 — Resolution-Independent Rendering Pipeline** (delivered; guardrails still apply): plan at [`docs/specs/003-resolution-independent-pipeline/plan.md`](docs/specs/003-resolution-independent-pipeline/plan.md) (spec + research + data-model + contracts in the same dir). **Supply-driven** scale model (logical properties; output scale `RenderNodeContext.OutputScale` = final target only; per-op `EffectiveScale`, vector = `Unbounded`; computed working scale `w` via `ResolveWorkingScale` — **no per-effect policy** (the `ResolutionPolicy` type was removed; an effect needing a non-supply `w` overrides `Process` in a custom `FilterEffectRenderNode` from `FilterEffect.Resource.CreateRenderNode()`); root surface `ceil(FrameSize × s_out)`); at `s_out = 1.0` the golden content set (vector / text / Skia-filter / unscaled bitmap) stays byte-identical, but byte-identity is **no longer a universal guarantee** — a scaled bitmap feeding an effect renders at its coherent supply density (FR-019; the universal constraint was abolished in `32634977c`). **Do NOT revert to top-down single-scale or output-capped intermediates** — `s_out` never clamps an intermediate (FR-016/FR-036). **Do NOT reintroduce a universal byte-identity-at-`s_out=1` rule, a `ResolutionPolicy` enum, or a `PreserveSource` policy** (all removed); the only **global** working-scale bound is `MaxWorkingScale` (FR-037; preview `2×s_out`, export `+∞` — no quality ceiling; per-buffer allocatability is bounded by `ClampWorkingScaleToBufferBudget`) — additionally the per-buffer dimension clamp (FR-037(b), `ClampWorkingScaleToBufferBudget`, 16384 px per axis) may further reduce `w` at effect boundaries to keep buffers allocatable (two distinct bounds, do not conflate them). Breaking public surface (`refactor!`/`feat!` + `BREAKING CHANGE:`). When touching `Beutl.Engine` graphics rendering / filter effects, consult that plan and the contracts.
<!-- SPECKIT END -->
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
<PackageVersion Include="NuGet.ProjectModel" Version="7.9.0" />
<PackageVersion Include="NuGet.Protocol" Version="7.9.0" />
<PackageVersion Include="NuGet.Resolver" Version="7.9.0" />
<PackageVersion Include="NuGet.Versioning" Version="7.9.0" />
<PackageVersion Include="Nuke.Common" Version="10.1.0" />
<PackageVersion Include="NUnit" Version="4.6.1" />
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ Create a Beutl account to acquire extensions or publish your own developed exten
### 🧰 Rich Effects
From basic effects like color filters, blurs, shadows, and LUTs, to minor effects like outlines, inner shadows, and long shadows, Beutl offers a wide range of effects. These can be further expanded through extensions.

### 🕘 Version Control
Track a project's editing history with Git, restore earlier versions, create experimental branches, and back up work to a remote repository from within Beutl.

## 📥 Installation
Refer to the [documentation](https://docs.beutl.beditor.net/get-started/install) here.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Specification Quality Checklist: Git Version Control for Editing Projects

**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-07-28
**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

- "Git" appears throughout as a product-level domain concept (the user-approved scope is Git-based versioning with remotes), not as an implementation choice; engine selection (CLI vs library) is deliberately absent and deferred to plan/research.
- Four assumptions are marked *(to be confirmed in clarification)* — creation-default, timer checkpoints, Save As history, LFS default. They carry informed defaults, so no [NEEDS CLARIFICATION] markers were needed; `/speckit-clarify` will confirm or adjust them.
Loading
Loading