OXYGENHUB

Extension spec Draft 0.1, icon, ignore file 3006b700c514

Author
Andy McCall @andymccall <[email protected]>
When
· 2026-09-27 14:56 UTC
Signature
✔ signed by Andy McCall
Hash
3006b700c5140ef1baf26b5abe074db5ca1fe533f2fdf7eed86c0c1db92ff59c
Depends on
nothing: a root change
Depended on by
dac6876e4d08 dfa08ccebaf8 f6bda77ecb9f 9020cf612749 bed495a96408
In bookmarks
main
In tags
v0.16.0 v0.16.1 v0.17.0 v0.17.1 v0.18.0
Edits
3 atoms, 6 tree operations, 3 files

Browse the tree at this change

added .oxyignore +5 −0
1 +
/node_modules
2 +
/out
3 +
/dist
4 +
*.vsix
5 +
/.vscode-test
added assets/images/oxygen.svg +20 −0
1 +
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="100%" height="100%">
2 +
  <defs>
3 +
    <linearGradient id="oxyGrad" x1="0%" y1="0%" x2="100%" y2="100%">
4 +
      <stop offset="0%" stop-color="#00F0FF" />
5 +
      <stop offset="100%" stop-color="#0072FF" />
6 +
    </linearGradient>
7 +
8 +
    <g id="oxy-mark-mini">
9 +
      <path d="M -11 -6 L 11 -6" stroke="url(#oxyGrad)" stroke-width="3" stroke-linecap="round" />
10 +
      <path d="M -11 6 L 11 6" stroke="url(#oxyGrad)" stroke-width="3" stroke-linecap="round" />
11 +
      <circle cx="-11" cy="0" r="10" fill="none" stroke="url(#oxyGrad)" stroke-width="3" />
12 +
      <circle cx="-11" cy="0" r="3.5" fill="#00F0FF" />
13 +
      <circle cx="11" cy="0" r="10" fill="none" stroke="url(#oxyGrad)" stroke-width="3" />
14 +
      <circle cx="11" cy="0" r="3.5" fill="#FFFFFF" />
15 +
    </g>
16 +
  </defs>
17 +
18 +
  <rect width="64" height="64" rx="14" fill="#070c18" />
19 +
  <use href="#oxy-mark-mini" x="32" y="32" />
20 +
</svg>
added docs/spec.md +207 −0
1 +
# Oxygen for Visual Studio Code
2 +
3 +
| | |
4 +
|---|---|
5 +
| **Status** | Draft 0.1 |
6 +
| **Scope** | A VS Code extension giving Oxygen repositories the same integrated experience the built-in Git extension gives Git, plus what the Oxygen model makes possible |
7 +
| **Depends on** | `oxy` (reference implementation, spec Draft 0.8a) with the machine interface of §4 |
8 +
9 +
## 1. Goals
10 +
11 +
1. **Parity with the built-in Git extension.** Everything a VS Code user does with Git through the UI must be doable with Oxygen through the UI: see what changed, diff it, commit some or all of it, switch bookmarks, sync with a remote, see history, resolve conflicts, and get gutter and explorer decorations, without opening a terminal.
12 +
2. **Expose what Oxygen does better.** Exact blame, first-class conflicts with a resolution flow, undo of any operation, bisect, subrepositories, and the trust policy get first-class UI rather than being hidden behind the Git vocabulary.
13 +
3. **Never lie about state.** The extension shows what `oxy` reports and nothing it infers; every mutation goes through `oxy`, so the operation log stays the single source of truth and `oxy undo` works on what the extension did.
14 +
4. **Fast enough to run on every keystroke pause.** Status refresh after a file save must complete within the manifest stat-cache budget (tens of milliseconds on a warm repository, spec §12.4).
15 +
16 +
Non-goals for 1.0: a web UI, code review, issue tracking (those belong to `oxyhub`), a Git compatibility mode (the built-in Git extension already covers Git repositories), and remote development on a machine without `oxy`.
17 +
18 +
## 2. How it compares
19 +
20 +
| Built-in Git extension | Oxygen extension | Notes |
21 +
|---|---|---|
22 +
| Source Control view with Changes / Staged | Source Control view with **Changes** and **Conflicts** groups | No staging area; partial commits select paths or hunks at commit time (§5.3) |
23 +
| Commit box, `Ctrl+Enter` | Same | `oxy commit -m`; amend from the menu |
24 +
| Quick diff gutter | Same | Base content via `oxy cat` (§4) |
25 +
| File decorations (M, A, D, U, C) | M, A, D, R (renamed), X (mode), ‼ (conflict markers), ✔ (resolved) | From `oxy status --json` |
26 +
| Branch picker in the status bar | **Bookmark** picker: switch, create, merge | `oxy bookmark` |
27 +
| Sync (fetch, pull, push) | Same, plus per-bookmark push | Counts from `oxy bookmark list --json` |
28 +
| Timeline view (file history) | Timeline: changes that touched the file, from `oxy log --json --path` | Exact, follows renames |
29 +
| Merge conflict editor (Accept current / incoming / both) | **Conflict editor** over `oxy` markers with the same CodeLens actions, plus "Mark resolved" that runs `oxy resolve` | Markers name the contributing changes |
30 +
| Stash | Workspaces (`oxy workspace add`) | Stash has no equivalent; a second workspace is the honest answer |
31 +
| Git graph (via extensions) | **History view**: heads and dependencies as a graph | `oxy log --json` carries dependencies |
32 +
| Blame (via GitLens) | Inline blame toggle and a Blame view | `oxy blame --json` |
33 +
| Undo last commit | **Operation log** view: any operation undone with one click | `oxy op log --json`, `oxy undo` |
34 +
| Submodules | Subrepos node in the SCM view with update and status | `oxy submodule status --json` |
35 +
| — | Bisect panel | `oxy bisect` |
36 +
| — | Trust panel: signature status per change, policy summary | `oxy verify --json`, `oxy policy show --json` |
37 +
| Git output channel | Oxygen output channel with every command run | |
38 +
39 +
## 3. Architecture
40 +
41 +
- **Language and build.** TypeScript, bundled with esbuild, targeting the current VS Code engine. Tests with `@vscode/test-electron` against a fixture repository created with `oxy` in a temporary directory.
42 +
- **Process model.** The extension spawns `oxy` per operation with `--plain --json` (§4) and parses its output; it never reads `.oxy/` itself. Long operations (clone, push, fetch, bisect run) stream progress to a VS Code progress notification and can be cancelled by killing the process. One operation mutates a repository at a time; reads may run concurrently.
43 +
- **Repository model.** One `Repository` object per workspace folder containing (or nested under) an oxy repository, found with `oxy root` (§4). It holds the last `status --json`, `bookmark list --json`, and `prompt` results, and refreshes on: a file watcher over the workspace (debounced 250 ms, ignoring `.oxy/`), a watcher on `.oxy/ops/head` (any operation, including ones from a terminal), window focus, and after every command the extension runs itself.
44 +
- **Binary discovery.** `oxygen.path` setting, else `oxy` on `PATH`, else `~/.local/bin/oxy`. The extension checks `oxy --version` at activation and shows a one-click "Install or locate oxy" message if it is missing or older than the minimum it supports.
45 +
- **URIs.** `oxy:` URIs serve file content from a state: `oxy:/<path>?change=<hash>&repo=<root>`; `change` may be `@base` (the working copy's base), a ChangeHash, a ChangeId prefix, or a bookmark. A `TextDocumentContentProvider` answers them with `oxy cat`.
46 +
- **Activation.** On `workspaceContains:.oxy` and on the `oxygen.*` commands.
47 +
48 +
## 4. Machine interface required from `oxy`
49 +
50 +
The extension depends on stable JSON outputs. These are additions to the reference implementation, tracked as phase 3 in `oxygen/docs/plan.md`:
51 +
52 +
| Command | Output |
53 +
|---|---|
54 +
| `oxy root` | The repository root and workspace id for the current directory, or exit 1 |
55 +
| `oxy status --json` | Exists: paths with status, conflicts |
56 +
| `oxy log --json [-n N] [--path P] [--bookmark B]` | Changes with hash, ChangeId, author, date, message, deps, heads flag, signature status |
57 +
| `oxy show --json CHANGE` | The change's metadata plus per-file summaries |
58 +
| `oxy diff --json [CHANGE]` | Per file: kind of change and hunks with line ranges and text, for the working copy or a change |
59 +
| `oxy cat PATH [-r CHANGE]` | Raw content of a file at a state (default: the working copy's base) |
60 +
| `oxy hunks --json` | Numbered hunks of the working copy, as `commit -i` offers them |
61 +
| `oxy commit --hunks 1,4,5` | Non-interactive hunk selection |
62 +
| `oxy bookmark list --json` | Name, heads, current, ahead, behind |
63 +
| `oxy op log --json` | Operations with id, time, command, and whether undo can reach them |
64 +
| `oxy blame --json` | Exists |
65 +
| `oxy resolve --json` | Per conflicted path: resolved, markers, unresolved |
66 +
| `oxy submodule status --json` | Path, pin, actual, dirty, url |
67 +
| `oxy bisect status --json` | The `BisectStep` |
68 +
| `oxy verify --json [CHANGE]` | Signature status per change |
69 +
| `oxy policy show --json` | Roots, rules, revoked, expiry |
70 +
| `oxy remote list --json`, `fetch --json`, `pull --json`, `push --json` | Names, urls, results |
71 +
| `oxy prompt` | Exists; used for the status bar |
72 +
| `oxy discard PATH..` | Restore paths to the working copy's base (new; the extension's "Discard changes") |
73 +
| `oxy --version --json` | Version and protocol version |
74 +
75 +
Every JSON command MUST print one JSON document on stdout and nothing else, use exit status 0 for success, and put human-readable errors on stderr with a non-zero status. Ids are hex strings. Times are milliseconds since the epoch.
76 +
77 +
## 5. User interface
78 +
79 +
### 5.1 Source Control view
80 +
81 +
- Groups: **Conflicts** (only when present, listed first), **Changes**. Each entry shows the path, a status letter, and a tooltip with the status word; clicking opens the diff editor (working file against `oxy:` base content; for an added file the file itself; for a removed file the base content).
82 +
- Title actions: Commit (with message box), Refresh, Fetch, Pull, Push, More… (Amend, Undo last operation, Open history, Open operation log).
83 +
- Entry actions: Open file, Open changes, Discard changes (confirm), Commit only this path.
84 +
- Multi-select commit: selecting entries and choosing "Commit selected" runs `oxy commit PATH..`.
85 +
- The view's badge is the number of changed paths; the badge turns red with the conflict count while conflicts exist.
86 +
87 +
### 5.2 Diff editor and quick diff
88 +
89 +
- Quick diff decorations in the gutter come from the base content served over `oxy:`.
90 +
- The diff editor title is `path (base ↔ working copy)`; for history diffs, `path (change A ↔ change B)`.
91 +
- "Commit this hunk" and "Discard this hunk" CodeLens actions in the diff editor call `oxy commit --hunks` and `oxy discard --hunks` (the latter is a phase 3 addition to `oxy`).
92 +
93 +
### 5.3 Commit
94 +
95 +
- The message box supports multi-line messages; `Ctrl+Enter` commits everything, the dropdown offers **Commit selected paths**, **Commit hunks…** (opens a quick pick of hunks from `oxy hunks --json`), **Amend**, **Amend into…** (quick pick of changes), and **Commit and push**.
96 +
- Empty message: the extension opens an editor for the message, like Git's.
97 +
- A pre-commit hook veto shows its stderr in a notification with "Show output".
98 +
99 +
### 5.4 Status bar
100 +
101 +
- Left: `⚛ main 658990aa ✎` from `oxy prompt --glyphs`, coloured by state; click opens the bookmark picker.
102 +
- Next to it: `↑2 ↓1` sync counts; click runs Sync (fetch then pull then push, each confirmed on first use).
103 +
- A spinner while any command runs; conflicts show `‼ 2` in the warning colour; click opens the Conflicts group.
104 +
105 +
### 5.5 Bookmarks
106 +
107 +
- Picker: current bookmark marked, each with heads count and ahead/behind, plus **Create bookmark…**, **Merge bookmark into current…**, **Delete bookmark…**. Switching with uncommitted changes offers Discard or Cancel (never silently).
108 +
- Explorer context menu on a folder: "Open in new workspace" runs `oxy workspace add`.
109 +
110 +
### 5.6 History view
111 +
112 +
- A webview showing the bookmark's changes as a graph: nodes are changes, edges are dependencies, heads highlighted, the working copy at the top. Multiple heads render side by side with no fake merge nodes.
113 +
- Clicking a change opens its summary (message, author, files, signature); actions: checkout, describe, abandon, squash into…, rebase onto…, tag, blame this version of a file, open diff against parent.
114 +
- Filters: bookmark, author, path, text.
115 +
116 +
### 5.7 Conflicts
117 +
118 +
- Files with markers open in the editor with CodeLens over each region: **Accept side 1**, **Accept side 2**, **Accept both**, **Compare sides**. Side labels are the contributing changes' short ids and subjects, as the markers carry them.
119 +
- Tree conflicts (`.oxy-conflict-N` candidates) appear under Conflicts with actions "Keep this candidate" (renames it into place and removes the rest).
120 +
- "Mark resolved" runs `oxy resolve --json` and reports what remains; the commit action reads "Commit resolution" while conflicts are resolved but not committed.
121 +
122 +
### 5.8 Blame
123 +
124 +
- Command "Toggle inline blame" decorates each line's end with `changeid · author · age`; hovering shows the full message with a link to the change. A "Blame" side view lists the same per line. Uses `oxy blame --json` on the base content and adjusts for unsaved edits by dimming lines that differ from base.
125 +
126 +
### 5.9 Operation log
127 +
128 +
- A tree view listing operations newest first with time and command; each has **Undo to here**. The item corresponding to the current view is marked. Snapshot operations are hidden by default.
129 +
130 +
### 5.10 Subrepositories
131 +
132 +
- A **Subrepos** node in the SCM view when `.oxymodules` exists or subrepo nodes are tracked: each entry shows path, pin, and state (at pin, differs, dirty, missing) with actions Update, Update all (--init), Open folder.
133 +
134 +
### 5.11 Bisect
135 +
136 +
- Panel with Start, Good/Bad marking of the state under test, Run with a task or command, Skip, Reset, and a progress line ("7 candidates, about 3 steps"). The culprit opens in the history view.
137 +
138 +
### 5.12 Trust
139 +
140 +
- Each change in the history view shows a signature badge (signed, sealed, unsigned, invalid, revoked key). A **Trust** section in the SCM view summarises the policy (roots, rules, expiry) and flags an expired policy or an unverified remote.
141 +
142 +
### 5.13 Remotes and sync
143 +
144 +
- Remote picker for fetch/pull/push when more than one remote exists; results shown as notifications (rejected pushes explain why and offer Pull). Tokens are read from the repository configuration; the extension never stores secrets itself.
145 +
146 +
### 5.14 Settings
147 +
148 +
| Setting | Default | Meaning |
149 +
|---|---|---|
150 +
| `oxygen.path` | `""` | Path to the `oxy` binary |
151 +
| `oxygen.autoRefresh` | `true` | Watch the workspace and refresh |
152 +
| `oxygen.autoFetch` | `false` | Fetch every `oxygen.autoFetchPeriod` seconds (default 180) |
153 +
| `oxygen.inlineBlame` | `false` | Show inline blame by default |
154 +
| `oxygen.showSnapshotOperations` | `false` | List snapshot operations in the operation log |
155 +
| `oxygen.confirmSync` | `true` | Confirm before pushing |
156 +
| `oxygen.decorations.enabled` | `true` | Explorer and tab decorations |
157 +
158 +
### 5.15 Commands (all prefixed `Oxygen:`)
159 +
160 +
Commit, Commit Selected Paths, Commit Hunks…, Amend, Amend Into…, Discard Changes, Refresh, Fetch, Pull, Push, Push Bookmark…, Sync, Switch Bookmark…, Create Bookmark…, Merge Bookmark…, Delete Bookmark…, Open History, Open Operation Log, Undo Last Operation, Toggle Inline Blame, Show Blame, Resolve Conflicts, Mark Resolved, Checkout Change…, Describe Change…, Abandon Change…, Squash Into…, Rebase Onto…, Create Tag…, Add Workspace…, Update Subrepos, Bisect Start/Good/Bad/Skip/Run/Reset, Verify Signatures, Show Policy, Open Output, Clone Repository…, Initialize Repository.
161 +
162 +
Keybindings match the Git extension where a counterpart exists (for example `Ctrl+Enter` in the commit box).
163 +
164 +
## 6. Behaviour rules
165 +
166 +
- **Refresh is cheap and debounced**; a refresh never blocks the UI thread and never runs two `status` calls at once per repository.
167 +
- **Errors** from `oxy` appear verbatim in a notification with "Show output"; the output channel logs every command, its working directory, duration, and exit status.
168 +
- **Nothing destructive without a confirmation**: discard, delete bookmark, abandon, `--discard` switches, and force push all confirm, with a "Don't ask again" option per action.
169 +
- **Multi-root workspaces**: one repository model per folder; the SCM view shows a provider per repository, as Git does.
170 +
- **Files outside the sparse filter** are shown greyed with a tooltip.
171 +
- **Large repositories**: history and blame are paged (`-n`) and fetched on demand; decorations use `status --json` only.
172 +
173 +
## 7. Repository layout and tooling
174 +
175 +
```
176 +
oxygen-vscode/
177 +
  package.json          contributes: commands, views, menus, keybindings, settings, scm
178 +
  src/
179 +
    extension.ts        activation, repository discovery
180 +
    oxy.ts              process wrapper and JSON parsing (one function per §4 command)
181 +
    model/              Repository, status, bookmarks, operations
182 +
    scm/                SourceControl provider and resource groups
183 +
    views/              history (webview), operation log, blame, subrepos, bisect, trust
184 +
    editor/             oxy: content provider, quick diff, conflict CodeLens, inline blame
185 +
    commands/           one file per command group
186 +
  assets/images/        oxygen.svg (the extension icon), history webview assets
187 +
  test/                 integration tests against a fixture repository
188 +
  docs/spec.md          this document
189 +
```
190 +
191 +
Build with `npm run build` (esbuild), test with `npm test`, package with `vsce package`, publish to the Marketplace under the `oxygen` publisher once 1.0 is reached. CI runs lint, build, and tests on Linux, macOS, and Windows with a pinned `oxy` release.
192 +
193 +
## 8. Milestones
194 +
195 +
1. **0.1 Read-only**: activation, binary discovery, SCM view with Changes and Conflicts, diff editor over `oxy:`, quick diff, decorations, status bar. Requires `oxy root`, `cat`, `status --json` (exists), `prompt`.
196 +
2. **0.2 Write**: commit (all, paths, hunks, amend), discard, refresh on operations, undo, operation log view. Requires `hunks --json`, `commit --hunks`, `discard`, `op log --json`.
197 +
3. **0.3 Bookmarks and sync**: picker, create/switch/merge/delete, fetch/pull/push with results, remotes. Requires `bookmark list --json`, sync `--json` outputs.
198 +
4. **0.4 History and blame**: history webview, timeline, inline blame, show. Requires `log --json`, `show --json`, `diff --json`.
199 +
5. **0.5 Conflicts**: conflict editor CodeLens, tree conflict candidates, resolve flow. Requires `resolve --json`.
200 +
6. **0.6 The rest**: subrepos, bisect, trust, tags, workspaces, clone and init.
201 +
7. **1.0**: tests on three platforms, Marketplace listing, documentation.
202 +
203 +
## 9. Open questions
204 +
205 +
1. Whether the extension should ship `oxy` binaries for the three platforms or only locate one; shipping simplifies onboarding but ties releases together.
206 +
2. Whether inline blame should run on every edit (as GitLens does) or only on save; the stat cache makes per-save cheap, per-edit needs a content-aware diff against base in the extension.
207 +
3. Whether a long-lived `oxy` daemon (`oxy serve-ide`) is warranted for very large repositories, where spawning a process per refresh would dominate.