Skip to content
Open
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
65 changes: 64 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,23 @@ Monitor GitHub Projects V2 for a repository.
- Double-click to force refresh
- Requires `Projects: Read` permission on fine-grained token

### 🎯 Active Repo

Shows the repo and branch you're currently editing, plus live working-tree status — staged, unstaged, untracked, ahead/behind upstream. Works on both keypad and encoder. Re-renders sub-second on every save / stage / commit / branch switch in your editor.

- **Keypad** — compact summary: repo, branch, `3↑ 1↓ ⚠5` status line
- **Encoder** — rotatable between two view modes:
- **Branch + sync** — branch name, ahead/behind counts, upstream name
- **Working tree** — staged / unstaged / untracked columns with traffic-light dots
- **Press** — opens the workspace in the editor that wrote the bridge file (Cursor or VS Code; configurable)
- **Long press** — opens the repo on GitHub
- **Rotate the dial** — switch view mode (persisted)
- **Accent bar color** summarizes overall state: green (clean + synced), yellow (dirty), orange (unpushed commits), red (behind upstream or merge conflicts)
- Requires the Cursor / VS Code [bridge extension](bridge-extension/) — the action reads local git state from the bridge file only; no GitHub API calls, no token needed for this specific action

### Stream Deck+ Encoder Support

All 14 actions support the Stream Deck+ encoder with rich touch strip visualizations:
All 15 actions support the Stream Deck+ encoder with rich touch strip visualizations:

| Interaction | Action |
|-------------|--------|
Expand All @@ -199,6 +213,55 @@ The Property Inspector features a dynamic, auto-populated UX:
- **Visual feedback** — status indicators show token validation and loading states
- Private repos are indicated with a lock icon

### Dynamic Repo Mode

Every repo picker in this plugin shows a **★ Current Active Repo (Cursor/VS Code)** option at the top of the dropdown. Pick it once and the button follows whatever repo your editor currently has focused — no reconfiguration when you switch projects.

**How it works.** A companion extension in Cursor / VS Code writes a small JSON bridge file whenever the active workspace changes. The plugin reads that file on every refresh and retargets the button automatically. Repo data is cached for 10 minutes across project switches, so flipping A → B → A within the window serves from cache instead of hitting the GitHub API again.

**Bridge file path**

- macOS: `~/Library/Application Support/stream-deck-github-utilities/active-repo.json`
- Windows: `%APPDATA%\stream-deck-github-utilities\active-repo.json`
- Linux / other: `$XDG_CONFIG_HOME/stream-deck-github-utilities/active-repo.json` (falls back to `~/.config/...`)

**Schema (v2)**

```json
{
"version": 2,
"repo": "owner/repo",
"remoteUrl": "git@github.com:owner/repo.git",
"workspacePath": "/Users/you/Projects/owner/repo",
"sourceApp": "Cursor",
"updatedAt": "2026-04-23T22:10:00.000Z",
"branch": "feat/x",
"headSha": "a3f91c0",
"upstream": "origin/main",
"ahead": 3,
"behind": 1,
"staged": 2,
"unstaged": 5,
"untracked": 1,
"conflicts": 0,
"isDirty": true
}
```

- `repo` (preferred) or `remoteUrl` (fallback) is required for any action to resolve. All other fields are optional.
- **v1 bridges still work** — every v2 field is optional, so older companions that only write `repo` + `remoteUrl` continue to drive all actions except Active Repo (which needs `branch` / `isDirty` / counts to render its full UI and falls back to a "git state unavailable" hint when they're absent).
- `remoteUrl` accepts both SSH (`git@github.com:owner/repo.git`) and HTTPS (`https://github.com/owner/repo.git`) forms.
- The plugin watches file mtime — just rewrite the file atomically and buttons retarget within one refresh interval (or instantly on touch-tap / key refresh).

**Special cases**

- **PR Review Queue** — empty repo still means "all repos, unscoped". The sentinel scopes to the current active repo only. A missing bridge file shows an error state rather than silently falling back to cross-repo (so you never leak activity across projects).
- **Contribution Heatmap** — only applies when the data source is **Repo**. The **User** profile mode stays global and ignores the bridge file.

**Companion extension (Cursor / VS Code).** This repo ships the companion at [`bridge-extension/`](bridge-extension/). It writes the bridge file automatically on startup, workspace-folder changes, and window focus changes. Build with `npm run build && npm run package` inside `bridge-extension/`, then install the resulting `.vsix` via **Extensions → Install from VSIX…** in Cursor or VS Code. A single install covers both editors since Cursor is a VS Code fork.

If you'd rather integrate a different tool, anything that writes the JSON schema above to the default path will work — the plugin reads the file and parses it; it doesn't care how it got there.

### Authentication

Uses a GitHub Personal Access Token (PAT) stored as a global plugin setting (shared across all actions).
Expand Down
4 changes: 4 additions & 0 deletions bridge-extension/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
out/
dist/
*.vsix
10 changes: 10 additions & 0 deletions bridge-extension/.vscodeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.vscode/**
.vscode-test/**
src/**
tsconfig.json
vitest.config.ts
**/*.map
**/.DS_Store
**/node_modules/**
**/*.test.ts
dist/**
21 changes: 21 additions & 0 deletions bridge-extension/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Pedro Fuentes

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
93 changes: 93 additions & 0 deletions bridge-extension/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Stream Deck GitHub Utilities — Active Repo Bridge

A tiny VS Code / Cursor extension that writes your currently-focused workspace's GitHub repo **plus its live working-tree state** (branch, ahead/behind upstream, staged / unstaged / untracked counts, merge conflicts) to a small JSON file. The [Stream Deck GitHub Utilities](https://github.com/pedrofuentes/stream-deck-github-utilities) plugin reads that file so any button with the **★ Current Active Repo** setting follows your editor focus in real time, and the dedicated **Active Repo** action renders branch / dirty state on the Stream Deck LCD without any GitHub API calls.

## Install

### From source

```bash
cd bridge-extension
npm install
npm run build
npm run package # produces dist/stream-deck-github-bridge-x.y.z.vsix
```

Then in Cursor or VS Code: **Extensions → "…" menu → Install from VSIX…** and pick the file in `dist/`.

### Dev loop

Open this folder in VS Code / Cursor and press **F5** to launch an Extension Development Host. Changes in `src/extension.ts` rebuild on save if you have `npm run watch` running.

## What it does

Triggers on:

- Startup of a focused editor window
- Workspace folder add / remove / switch
- Window focus changes (the last-focused window wins — switching windows updates the bridge)
- **Active text editor changes** — flipping between tabs in the same window
- **Git state changes** — every save, stage, commit, or branch switch in the active repo
- The **Stream Deck Bridge: Refresh Active Repo** command (manual override)

The extension caches the last successful git-state snapshot per workspace and falls back to it when Cursor's git API drops the repo briefly during transitions — so the Stream Deck LCD stays stable instead of flickering to "git state unavailable".

Git state is read via the built-in `vscode.git` extension (declared as an `extensionDependencies`), so no extra `git` subprocess is spawned on every tick — just a subscription to `Repository.state.onDidChange`.

For the primary workspace folder, it runs `git remote get-url origin` once to resolve the GitHub remote, then writes the JSON payload atomically on every relevant event:

```json
{
"version": 2,
"sourceApp": "Cursor",
"workspacePath": "/Users/you/Projects/owner/repo",
"repo": "owner/repo",
"remoteUrl": "git@github.com:owner/repo.git",
"updatedAt": "2026-04-23T22:10:00.000Z",
"branch": "feat/x",
"headSha": "a3f91c0",
"upstream": "origin/main",
"ahead": 3,
"behind": 1,
"staged": 2,
"unstaged": 5,
"untracked": 1,
"conflicts": 0,
"isDirty": true
}
```

Writes that would only change `updatedAt` (no meaningful state change) are suppressed, so the Stream Deck's 1 s mtime watcher doesn't fire for noops.

## Where it writes

Default path (matches the Stream Deck plugin's default):

- **macOS** `~/Library/Application Support/stream-deck-github-utilities/active-repo.json`
- **Windows** `%APPDATA%\stream-deck-github-utilities\active-repo.json`
- **Linux / other** `$XDG_CONFIG_HOME/stream-deck-github-utilities/active-repo.json` (fallback `~/.config/…`)

Override via `streamDeckGitHubBridge.bridgePath` in settings — only needed if you also override the path on the Stream Deck plugin side.

## Settings

| Key | Default | Purpose |
|-----|---------|---------|
| `streamDeckGitHubBridge.bridgePath` | `""` (use OS default) | Absolute path to write the bridge file |
| `streamDeckGitHubBridge.debounceMs` | `300` | How long (ms) to wait after a workspace/focus change before writing |

## Behavior notes

- **Non-git workspace:** no write. The bridge file keeps pointing at the last known repo — the Stream Deck keeps showing that repo's data until you open another git project.
- **Non-GitHub remote:** no write. Same as above.
- **Multiple windows:** whichever window you focus last owns the bridge file. Useful when you juggle two projects across two windows.
- **Multi-root workspaces:** the first folder wins. Rearrange your workspace folders if you need a different primary.
- **Git lookup timeout:** 3 seconds. A slow git or networked path won't hang the extension.

## Troubleshooting

Open **Output → "Stream Deck GitHub Bridge"** to see every trigger and skipped-write reason. Useful for diagnosing "button says No Active Repo but I have a repo open" issues.

## License

MIT — see the parent repo.
Loading