6 Commits

Author SHA1 Message Date
e48798ebff fix(ci): release.yml invalide, ': ' dans un nom d'étape cassait le YAML
All checks were successful
CI / Build & test (Node 22) (push) Successful in 10m13s
CI / Build & test (Node 24) (push) Successful in 10m6s
CI / No em/en dashes (push) Successful in 3s
Release / Publish to Gitea npm registry (push) Successful in 9m59s
CI / Pack & boot smoke (Node 22) (push) Successful in 9m58s
Séquelle du nettoyage des tirets : un tiret cadratin dans le nom de l'étape
« Publish » avait été remplacé par ' : ', or un scalaire YAML non quoté ne
peut pas contenir deux-points+espace ("mapping values are not allowed").
Remplacé par une virgule. Gitea refusait de lancer le workflow → la
publication npm du daemon sur un tag v* ne partait pas.
2026-07-17 21:55:53 +02:00
1a74576955 feat(desktop): logo de fenêtre, homepage vitrine, licence MIT ; attache release idempotente
Some checks failed
Desktop Release / Build Linux (AppImage + deb) (push) Successful in 13m34s
CI / Build & test (Node 22) (push) Has been cancelled
CI / Build & test (Node 24) (push) Has been cancelled
CI / Pack & boot smoke (Node 22) (push) Has been cancelled
CI / No em/en dashes (push) Has been cancelled
- Fenêtre principale : icône explicite (resolveIconPath partagé dans paths.ts,
  réutilisé par le tray) pour afficher le logo Arboretum en fenêtre/barre des
  tâches au lieu de l'icône Electron générique.
- package.json desktop : homepage -> https://git-arboretum.com (la vitrine, plus
  le dépôt Gitea) et champ license: MIT. Copyright daté avec le nom dans
  electron-builder.yml. Licence MIT + author aussi au package.json racine.
- desktop-release.yml : attache des assets idempotente (supprime l'asset de même
  nom avant ré-upload) pour que le dernier build gagne sur un re-run.
2026-07-17 21:46:22 +02:00
bd76e53570 docs(ci): documenter la portée write:repository requise de NPM_TOKEN
All checks were successful
CI / Build & test (Node 22) (push) Successful in 10m15s
CI / Build & test (Node 24) (push) Successful in 10m10s
CI / No em/en dashes (push) Successful in 3s
Desktop Release / Build Linux (AppImage + deb) (push) Successful in 14m1s
CI / Pack & boot smoke (Node 22) (push) Successful in 10m5s
L'attache des installeurs/VSIX à la release Gitea réutilise NPM_TOKEN ; ce
token doit porter write:repository EN PLUS de write:package, sinon l'API
release renvoie 403 (l'étape est best-effort, non bloquante : les artefacts
restent disponibles via upload-artifact).
2026-07-17 20:42:21 +02:00
b0a75df204 fix(desktop): métadonnées de packaging .deb (homepage, author.email, maintainer)
Some checks failed
CI / Build & test (Node 22) (push) Successful in 10m10s
CI / Build & test (Node 24) (push) Successful in 10m6s
CI / No em/en dashes (push) Successful in 5s
Desktop Release / Build Linux (AppImage + deb) (push) Successful in 13m39s
CI / Pack & boot smoke (Node 22) (push) Has been cancelled
electron-builder exige un homepage projet, un author.email et un maintainer
.deb : le build Linux produisait l'AppImage mais échouait sur la cible deb.
Ajoute ces champs au package.json desktop et fixe explicitement le
maintainer dans electron-builder.yml.
2026-07-17 20:04:50 +02:00
c7af406cbf release: IDE multi-projet + app native (git-arboretum 3.0.0, vscode 0.3.0, desktop 0.1.0)
Some checks failed
CI / Build & test (Node 22) (push) Successful in 10m13s
CI / Build & test (Node 24) (push) Successful in 10m6s
CI / No em/en dashes (push) Successful in 3s
VSCode Release / Package VSIX (push) Successful in 9m38s
CI / Pack & boot smoke (Node 22) (push) Successful in 9m56s
Desktop Release / Build Linux (AppImage + deb) (push) Failing after 6m11s
Daemon 3.0.0 : marque le cap « IDE IA multi-projet + app de bureau native » (refonte additive, PROTOCOL_VERSION inchangé ; le tarball embarque la nouvelle SPA IDE + le handshake token desktop). Extension VS Code 0.3.0 : deep-link « Open Worktree IDE » vers l'IDE multi-projet, encodage wt-key unifié via @arboretum/shared (CHANGELOG + README à jour). Paquet desktop 0.1.0 (première release).

package.json ET package-lock.json bumpés (npm ci strict). 431 tests, 0 tiret, builds daemon/web/vscode/site verts.
2026-07-17 18:31:37 +02:00
8042376f9c fix(site): fidélité des mockups au nouvel IDE (HeroMockup, ShowcaseSection)
Some checks failed
CI / Build & test (Node 24) (push) Has been cancelled
CI / Pack & boot smoke (Node 22) (push) Has been cancelled
CI / No em/en dashes (push) Has been cancelled
CI / Build & test (Node 22) (push) Has been cancelled
Deploy site (production) / build-and-deploy (push) Successful in 16s
HeroMockup : entrée de nav « IDE » active en tête (comme AppSidebar), badge version v2.0.0 (au lieu de v1.6.0 figé). ShowcaseSection : entrée « IDE » ajoutée à la barre d'onglets mobile (comme MobileTabBar). Clé i18n mIde (EN/FR). build:site vert, 0 tiret.
2026-07-17 18:28:04 +02:00
18 changed files with 391 additions and 88 deletions

View File

@@ -50,7 +50,9 @@ jobs:
packages/desktop/release/*.deb
packages/desktop/release/latest-linux.yml
# Best-effort : attache les installeurs (+ latest-linux.yml pour l'auto-update) à la release
# Gitea du tag (crée la release si absente). Réutilise NPM_TOKEN (même token Gitea).
# Gitea du tag (crée la release si absente). Réutilise NPM_TOKEN (même token Gitea) : ce token
# doit porter la portée write:repository en plus de write:package, sinon l'API release renvoie
# un 403 (l'attache est ignorée, les installeurs restent disponibles en artefact du run).
- name: Attach installers to Gitea release
continue-on-error: true
env:
@@ -72,6 +74,13 @@ jobs:
for f in packages/desktop/release/*.AppImage packages/desktop/release/*.deb packages/desktop/release/latest-linux.yml; do
[ -f "$f" ] || continue
name=$(basename "$f")
# Re-run idempotent : supprimer un asset existant du même nom avant de ré-uploader, pour
# que le dernier build gagne (l'API Gitea refuse sinon un asset déjà présent).
existing=$(curl -fsSL -H "$auth" "${api}/releases/${rid}/assets" | node -e "const a=JSON.parse(require('fs').readFileSync(0,'utf8'));const m=Array.isArray(a)?a.find(x=>x.name===process.argv[1]):null;process.stdout.write(m?String(m.id):'')" "$name" || true)
if [ -n "$existing" ]; then
echo "replacing existing $name (asset $existing)"
curl -fsSL -X DELETE -H "$auth" "${api}/releases/${rid}/assets/${existing}" || true
fi
echo "attaching $name"
curl -fsSL -X POST -H "$auth" -F "attachment=@${f}" "${api}/releases/${rid}/assets?name=${name}"
done

View File

@@ -44,7 +44,7 @@ jobs:
# `bash -eo pipefail` : on isole l'échec attendu dans la condition d'un `if` pour ne pas
# déclencher `set -e`. Le secret du registre est mappé sur NODE_AUTH_TOKEN lu par le .npmrc
# de setup-node.
- name: Publish (idempotent : tolère un 409 « already exists »)
- name: Publish (idempotent, tolère un 409 « already exists »)
run: |
if out="$(npm publish -w @johanleroy/git-arboretum 2>&1)"; then
printf '%s\n' "$out"

View File

@@ -46,9 +46,10 @@ jobs:
name: vsix
path: packages/vscode/*.vsix
# Best-effort : attache le VSIX à la release Gitea du tag (crée la release si absente).
# Réutilise le secret NPM_TOKEN (même token Gitea que la publication du daemon, droits
# repository suffisants pour l'API release). Sans lui, l'étape est ignorée sans faire échouer
# le job (continue-on-error) ; le VSIX reste disponible en artefact.
# Réutilise le secret NPM_TOKEN (même token Gitea que la publication du daemon) : ce token doit
# porter write:repository en plus de write:package, sinon l'API release renvoie un 403. Sans
# token, l'étape est ignorée sans faire échouer le job (continue-on-error) ; le VSIX reste
# disponible en artefact.
- name: Attach VSIX to Gitea release
continue-on-error: true
env:

4
package-lock.json generated
View File

@@ -7924,7 +7924,7 @@
},
"packages/server": {
"name": "@johanleroy/git-arboretum",
"version": "2.0.0",
"version": "3.0.0",
"license": "MIT",
"dependencies": {
"@fastify/cookie": "^11.0.0",
@@ -8053,7 +8053,7 @@
},
"packages/vscode": {
"name": "git-arboretum",
"version": "0.2.0",
"version": "0.3.0",
"license": "MIT",
"devDependencies": {
"@arboretum/shared": "0.1.0",

View File

@@ -2,6 +2,8 @@
"name": "arboretum-monorepo",
"private": true,
"version": "0.0.0",
"license": "MIT",
"author": "Johan LEROY <contact@johanleroy.fr>",
"type": "module",
"workspaces": [
"packages/shared",

View File

@@ -1,6 +1,6 @@
appId: fr.lidge.arboretum
productName: Arboretum
copyright: Copyright Johan Leroy
copyright: Copyright © 2026 Johan Leroy
directories:
output: release
@@ -32,6 +32,8 @@ linux:
deb:
# git est requis pour les operations de worktree ; claude n'est pas dans les depots (documente).
depends: [git]
# Mainteneur .deb explicite (electron-builder l'exige ; sinon derive de author.email du package.json).
maintainer: Johan LEROY <contact@johanleroy.fr>
win:
target:

View File

@@ -3,6 +3,12 @@
"private": true,
"version": "0.1.0",
"description": "Arboretum desktop app: Electron shell that runs the daemon and shows its web UI",
"homepage": "https://git-arboretum.com",
"license": "MIT",
"author": {
"name": "Johan LEROY",
"email": "contact@johanleroy.fr"
},
"main": "dist/main.js",
"type": "commonjs",
"scripts": {

View File

@@ -5,6 +5,7 @@ import { seedSessionCookie } from './auth';
import { loadWindowState, saveWindowState } from './window-state';
import { createTray } from './tray';
import { initUpdater } from './updater';
import { resolveIconPath } from './paths';
const PARTITION = 'persist:arboretum';
const PORT = 7317;
@@ -53,6 +54,8 @@ function createWindow(url: string): void {
width: state.width,
height: state.height,
backgroundColor: '#09090b',
// Logo de la fenêtre / barre des tâches (sinon icône Electron générique sous Linux/Windows).
icon: resolveIconPath(),
webPreferences: {
partition: PARTITION,
contextIsolation: true,

View File

@@ -14,6 +14,15 @@ export function resolveServerEntry(): string {
return join(__dirname, '..', '..', 'server', 'dist', 'index.js');
}
/** Logo de l'app (fenêtre, tray, barre des tâches) : le mark Arboretum embarqué. */
export function resolveIconPath(): string {
// packagé : extraResources copie resources/icon.png à la racine de resources/.
// dev : depuis dist/main.js -> ../resources/icon.png.
return app.isPackaged
? join(process.resourcesPath, 'icon.png')
: join(__dirname, '..', 'resources', 'icon.png');
}
/** Binaire Node qui exécute le daemon (>= 22.16 : node:sqlite + ABI node-pty maîtrisé). */
export function resolveNodeBin(): string {
if (app.isPackaged) {

View File

@@ -1,16 +1,10 @@
import { app, Menu, Tray, nativeImage } from 'electron';
import { join } from 'node:path';
import { Menu, Tray, nativeImage } from 'electron';
import { isAutoStartEnabled, setAutoStart } from './autostart';
function iconPath(): string {
return app.isPackaged
? join(process.resourcesPath, 'icon.png')
: join(__dirname, '..', 'resources', 'icon.png');
}
import { resolveIconPath } from './paths';
/** Icône de barre système : ouvrir la fenêtre, basculer le lancement au login, quitter. */
export function createTray(opts: { show: () => void; quit: () => void }): Tray {
const image = nativeImage.createFromPath(iconPath());
const image = nativeImage.createFromPath(resolveIconPath());
const tray = new Tray(image.isEmpty() ? nativeImage.createEmpty() : image.resize({ width: 18, height: 18 }));
tray.setToolTip('Arboretum');

View File

@@ -1,6 +1,6 @@
{
"name": "@johanleroy/git-arboretum",
"version": "2.0.0",
"version": "3.0.0",
"description": "Self-hosted web dashboard for git worktrees and the Claude Code sessions running on them",
"license": "MIT",
"type": "module",

View File

@@ -83,9 +83,13 @@ const dlgOptions = computed(() =>
<span class="rounded border border-zinc-700 px-[5px] py-px font-mono text-[10px] text-zinc-500">K</span>
</div>
<!-- nav primaire -->
<!-- nav primaire (fidèle à AppSidebar : IDE actif, puis Worktrees / Sessions / Groups) -->
<div class="flex flex-col gap-1">
<div class="flex items-center gap-2.5 rounded-lg bg-zinc-800 px-2.5 py-1.5 text-zinc-100">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2" /><path d="M3 9h18" /><path d="M9 21V9" /></svg>
<span class="flex-1 text-[12.5px] font-medium">{{ t('mIde') }}</span>
</div>
<div class="flex items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-zinc-400">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" x2="6" y1="3" y2="15" /><circle cx="18" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M18 9a9 9 0 0 1-9 9" /></svg>
<span class="flex-1 text-[12.5px] font-medium">{{ t('mWorktrees') }}</span>
</div>
@@ -131,7 +135,7 @@ const dlgOptions = computed(() =>
<span class="rounded border border-zinc-700 px-1.5 py-px font-mono text-[10px] text-zinc-400">{{ locale.toUpperCase() }}</span>
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#34d399" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.268 21a2 2 0 0 0 3.464 0" /><path d="M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326" /></svg>
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#71717a" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" /><polyline points="16 17 21 12 16 7" /><line x1="21" x2="9" y1="12" y2="12" /></svg>
<span class="ml-auto font-mono text-[10px] text-zinc-600">v1.6.0</span>
<span class="ml-auto font-mono text-[10px] text-zinc-600">v2.0.0</span>
</div>
</div>

View File

@@ -230,6 +230,10 @@ const dlgOpts = computed(() => DLG_OPTS[locale.value as AppLocale]);
<!-- barre d'onglets mobile (fidèle à MobileTabBar) -->
<div class="absolute inset-x-0 bottom-0 flex border-t border-zinc-800 bg-zinc-950/95 backdrop-blur">
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-zinc-500">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2" /><path d="M3 9h18" /><path d="M9 21V9" /></svg>
<span class="text-[10px]">{{ t('mIde') }}</span>
</div>
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-zinc-500">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" x2="6" y1="3" y2="15" /><circle cx="18" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M18 9a9 9 0 0 1-9 9" /></svg>
<span class="text-[10px]">{{ t('mWorktrees') }}</span>

View File

@@ -81,6 +81,7 @@ export default {
footTag: 'a garden of branches, one pane of glass.',
license: 'MIT License',
coffee: 'Buy me a coffee',
mIde: 'IDE',
mWorktrees: 'Worktrees',
mSessions: 'Sessions',
mGroups: 'Groups',

View File

@@ -81,6 +81,7 @@ export default {
footTag: 'un jardin de branches, une seule vitre.',
license: 'Licence MIT',
coffee: 'Paye-moi un café',
mIde: 'IDE',
mWorktrees: 'Worktrees',
mSessions: 'Sessions',
mGroups: 'Groupes',

View File

@@ -1,5 +1,17 @@
# Changelog
## 0.3.0
Aligns with the daemon's **multi-project IDE** milestone: the web UI is now a single IDE that holds all
your open projects at once (a unified project / worktree / session tree, a tabbed Monaco editor, and
Claude terminals docked at the bottom), and ships as a native desktop app too. The extension stays a
lightweight visual worktree manager (no editor duplicated here), and its deep-link now opens that IDE:
- **Open Worktree IDE** now deep-links into the multi-project IDE (route `/workspace/:repoId/:wt`) and
focuses the chosen worktree in its unified tree.
- Worktree deep-link encoding unified with the web front through the shared `encodeWtKey`
(`@arboretum/shared`), so links resolve consistently on both sides.
## 0.2.0
Follows the daemon's "worktree IDE" milestone (P7→P12), while keeping the extension a lightweight

View File

@@ -11,9 +11,9 @@ integration on top of the [Arboretum](https://git.lidge.fr/johanleroy/arboretum)
input: answer **Yes/No** without even opening the terminal (uses the daemon's `answer` command).
- **Git mutations** from the tree: create worktree, commit, push, fetch, pull, promote to main, with a
**detailed git status** on each worktree (staged / unstaged / conflicts and the last commit subject).
- **Open Worktree IDE**: jump from any worktree to its full `/workspace` view (file tree, Monaco editor,
inline diffs, integrated terminal) in the browser. The extension stays a lightweight visual worktree
manager: the heavy editing lives in the web IDE.
- **Open Worktree IDE**: jump from any worktree into the multi-project IDE (unified project / worktree /
session tree, tabbed Monaco editor with inline diffs, docked terminals), in the browser or the native
desktop app. The extension stays a lightweight visual worktree manager: the heavy editing lives in the IDE.
- **Workspace-aware**: the worktree matching your open folder is highlighted; start a session or create a
worktree for the current folder in one command.

View File

@@ -2,7 +2,7 @@
"name": "git-arboretum",
"displayName": "Arboretum",
"description": "Pilot your git worktrees and Claude Code sessions from VS Code: native terminals, live tree, waiting alerts.",
"version": "0.2.0",
"version": "0.3.0",
"private": true,
"publisher": "johanleroy",
"license": "MIT",
@@ -85,77 +85,332 @@
}
],
"commands": [
{ "command": "arboretum.signIn", "title": "Sign In", "category": "Arboretum" },
{ "command": "arboretum.signOut", "title": "Sign Out", "category": "Arboretum" },
{ "command": "arboretum.refresh", "title": "Refresh", "category": "Arboretum", "icon": "$(refresh)" },
{ "command": "arboretum.openDashboard", "title": "Open Dashboard in Browser", "category": "Arboretum", "icon": "$(globe)" },
{ "command": "arboretum.attachSession", "title": "Attach Terminal", "category": "Arboretum", "icon": "$(terminal)" },
{ "command": "arboretum.observeSession", "title": "Observe Terminal (read-only)", "category": "Arboretum", "icon": "$(eye)" },
{ "command": "arboretum.answerSession", "title": "Answer Prompt…", "category": "Arboretum", "icon": "$(comment-discussion)" },
{ "command": "arboretum.killSession", "title": "Kill Session", "category": "Arboretum", "icon": "$(trash)" },
{ "command": "arboretum.hideSession", "title": "Hide Session", "category": "Arboretum", "icon": "$(eye-closed)" },
{ "command": "arboretum.resumeSession", "title": "Resume Session", "category": "Arboretum", "icon": "$(debug-restart)" },
{ "command": "arboretum.forkSession", "title": "Fork Session", "category": "Arboretum", "icon": "$(git-branch)" },
{ "command": "arboretum.createWorktree", "title": "Create Worktree…", "category": "Arboretum", "icon": "$(add)" },
{ "command": "arboretum.commitWorktree", "title": "Commit…", "category": "Arboretum", "icon": "$(git-commit)" },
{ "command": "arboretum.pushWorktree", "title": "Push", "category": "Arboretum", "icon": "$(repo-push)" },
{ "command": "arboretum.fetchWorktree", "title": "Fetch", "category": "Arboretum", "icon": "$(cloud-download)" },
{ "command": "arboretum.pullWorktree", "title": "Pull…", "category": "Arboretum", "icon": "$(arrow-down)" },
{ "command": "arboretum.promoteWorktree", "title": "Promote to Main", "category": "Arboretum", "icon": "$(arrow-up)" },
{ "command": "arboretum.openWorktreeIde", "title": "Open Worktree IDE", "category": "Arboretum", "icon": "$(link-external)" },
{ "command": "arboretum.startSession", "title": "Start Claude Session", "category": "Arboretum", "icon": "$(play)" },
{ "command": "arboretum.startGroupSession", "title": "Start Group Session…", "category": "Arboretum", "icon": "$(play)" },
{ "command": "arboretum.startSessionHere", "title": "Start Session in Current Folder", "category": "Arboretum" },
{ "command": "arboretum.createWorktreeHere", "title": "Create Worktree for Current Folder…", "category": "Arboretum" },
{ "command": "arboretum.revealWorktree", "title": "Reveal Worktree for Current Folder", "category": "Arboretum" }
{
"command": "arboretum.signIn",
"title": "Sign In",
"category": "Arboretum"
},
{
"command": "arboretum.signOut",
"title": "Sign Out",
"category": "Arboretum"
},
{
"command": "arboretum.refresh",
"title": "Refresh",
"category": "Arboretum",
"icon": "$(refresh)"
},
{
"command": "arboretum.openDashboard",
"title": "Open Dashboard in Browser",
"category": "Arboretum",
"icon": "$(globe)"
},
{
"command": "arboretum.attachSession",
"title": "Attach Terminal",
"category": "Arboretum",
"icon": "$(terminal)"
},
{
"command": "arboretum.observeSession",
"title": "Observe Terminal (read-only)",
"category": "Arboretum",
"icon": "$(eye)"
},
{
"command": "arboretum.answerSession",
"title": "Answer Prompt…",
"category": "Arboretum",
"icon": "$(comment-discussion)"
},
{
"command": "arboretum.killSession",
"title": "Kill Session",
"category": "Arboretum",
"icon": "$(trash)"
},
{
"command": "arboretum.hideSession",
"title": "Hide Session",
"category": "Arboretum",
"icon": "$(eye-closed)"
},
{
"command": "arboretum.resumeSession",
"title": "Resume Session",
"category": "Arboretum",
"icon": "$(debug-restart)"
},
{
"command": "arboretum.forkSession",
"title": "Fork Session",
"category": "Arboretum",
"icon": "$(git-branch)"
},
{
"command": "arboretum.createWorktree",
"title": "Create Worktree…",
"category": "Arboretum",
"icon": "$(add)"
},
{
"command": "arboretum.commitWorktree",
"title": "Commit…",
"category": "Arboretum",
"icon": "$(git-commit)"
},
{
"command": "arboretum.pushWorktree",
"title": "Push",
"category": "Arboretum",
"icon": "$(repo-push)"
},
{
"command": "arboretum.fetchWorktree",
"title": "Fetch",
"category": "Arboretum",
"icon": "$(cloud-download)"
},
{
"command": "arboretum.pullWorktree",
"title": "Pull…",
"category": "Arboretum",
"icon": "$(arrow-down)"
},
{
"command": "arboretum.promoteWorktree",
"title": "Promote to Main",
"category": "Arboretum",
"icon": "$(arrow-up)"
},
{
"command": "arboretum.openWorktreeIde",
"title": "Open Worktree IDE",
"category": "Arboretum",
"icon": "$(link-external)"
},
{
"command": "arboretum.startSession",
"title": "Start Claude Session",
"category": "Arboretum",
"icon": "$(play)"
},
{
"command": "arboretum.startGroupSession",
"title": "Start Group Session…",
"category": "Arboretum",
"icon": "$(play)"
},
{
"command": "arboretum.startSessionHere",
"title": "Start Session in Current Folder",
"category": "Arboretum"
},
{
"command": "arboretum.createWorktreeHere",
"title": "Create Worktree for Current Folder…",
"category": "Arboretum"
},
{
"command": "arboretum.revealWorktree",
"title": "Reveal Worktree for Current Folder",
"category": "Arboretum"
}
],
"menus": {
"view/title": [
{ "command": "arboretum.refresh", "when": "view == arboretum.repos || view == arboretum.groups", "group": "navigation" },
{ "command": "arboretum.openDashboard", "when": "view == arboretum.repos", "group": "navigation" },
{ "command": "arboretum.signOut", "when": "view == arboretum.repos && arboretum.connected", "group": "1_auth" },
{ "command": "arboretum.signIn", "when": "view == arboretum.repos && !arboretum.connected", "group": "1_auth" }
{
"command": "arboretum.refresh",
"when": "view == arboretum.repos || view == arboretum.groups",
"group": "navigation"
},
{
"command": "arboretum.openDashboard",
"when": "view == arboretum.repos",
"group": "navigation"
},
{
"command": "arboretum.signOut",
"when": "view == arboretum.repos && arboretum.connected",
"group": "1_auth"
},
{
"command": "arboretum.signIn",
"when": "view == arboretum.repos && !arboretum.connected",
"group": "1_auth"
}
],
"view/item/context": [
{ "command": "arboretum.createWorktree", "when": "viewItem == arboretum:repo", "group": "inline" },
{ "command": "arboretum.startSession", "when": "viewItem == arboretum:repo", "group": "1_session" },
{ "command": "arboretum.openWorktreeIde", "when": "viewItem == arboretum:worktree", "group": "inline" },
{ "command": "arboretum.commitWorktree", "when": "viewItem == arboretum:worktree", "group": "1_git" },
{ "command": "arboretum.pushWorktree", "when": "viewItem == arboretum:worktree", "group": "1_git" },
{ "command": "arboretum.fetchWorktree", "when": "viewItem == arboretum:worktree", "group": "1_git" },
{ "command": "arboretum.pullWorktree", "when": "viewItem == arboretum:worktree", "group": "1_git" },
{ "command": "arboretum.promoteWorktree", "when": "viewItem == arboretum:worktree", "group": "2_git" },
{ "command": "arboretum.openWorktreeIde", "when": "viewItem == arboretum:worktree", "group": "2_git" },
{ "command": "arboretum.startSession", "when": "viewItem == arboretum:worktree", "group": "3_session" },
{ "command": "arboretum.attachSession", "when": "viewItem =~ /arboretum:session:live/", "group": "inline" },
{ "command": "arboretum.observeSession", "when": "viewItem =~ /arboretum:session:live/", "group": "1_term" },
{ "command": "arboretum.answerSession", "when": "viewItem =~ /arboretum:session:live:.*waiting/", "group": "1_term" },
{ "command": "arboretum.killSession", "when": "viewItem =~ /arboretum:session:live/", "group": "9_danger" },
{ "command": "arboretum.resumeSession", "when": "viewItem =~ /arboretum:session:dead/", "group": "inline" },
{ "command": "arboretum.forkSession", "when": "viewItem =~ /arboretum:session/", "group": "2_term" },
{ "command": "arboretum.hideSession", "when": "viewItem =~ /arboretum:session:.*discovered/", "group": "9_danger" },
{ "command": "arboretum.startGroupSession", "when": "viewItem == arboretum:group", "group": "inline" }
{
"command": "arboretum.createWorktree",
"when": "viewItem == arboretum:repo",
"group": "inline"
},
{
"command": "arboretum.startSession",
"when": "viewItem == arboretum:repo",
"group": "1_session"
},
{
"command": "arboretum.openWorktreeIde",
"when": "viewItem == arboretum:worktree",
"group": "inline"
},
{
"command": "arboretum.commitWorktree",
"when": "viewItem == arboretum:worktree",
"group": "1_git"
},
{
"command": "arboretum.pushWorktree",
"when": "viewItem == arboretum:worktree",
"group": "1_git"
},
{
"command": "arboretum.fetchWorktree",
"when": "viewItem == arboretum:worktree",
"group": "1_git"
},
{
"command": "arboretum.pullWorktree",
"when": "viewItem == arboretum:worktree",
"group": "1_git"
},
{
"command": "arboretum.promoteWorktree",
"when": "viewItem == arboretum:worktree",
"group": "2_git"
},
{
"command": "arboretum.openWorktreeIde",
"when": "viewItem == arboretum:worktree",
"group": "2_git"
},
{
"command": "arboretum.startSession",
"when": "viewItem == arboretum:worktree",
"group": "3_session"
},
{
"command": "arboretum.attachSession",
"when": "viewItem =~ /arboretum:session:live/",
"group": "inline"
},
{
"command": "arboretum.observeSession",
"when": "viewItem =~ /arboretum:session:live/",
"group": "1_term"
},
{
"command": "arboretum.answerSession",
"when": "viewItem =~ /arboretum:session:live:.*waiting/",
"group": "1_term"
},
{
"command": "arboretum.killSession",
"when": "viewItem =~ /arboretum:session:live/",
"group": "9_danger"
},
{
"command": "arboretum.resumeSession",
"when": "viewItem =~ /arboretum:session:dead/",
"group": "inline"
},
{
"command": "arboretum.forkSession",
"when": "viewItem =~ /arboretum:session/",
"group": "2_term"
},
{
"command": "arboretum.hideSession",
"when": "viewItem =~ /arboretum:session:.*discovered/",
"group": "9_danger"
},
{
"command": "arboretum.startGroupSession",
"when": "viewItem == arboretum:group",
"group": "inline"
}
],
"commandPalette": [
{ "command": "arboretum.refresh", "when": "arboretum.connected" },
{ "command": "arboretum.signOut", "when": "arboretum.connected" },
{ "command": "arboretum.attachSession", "when": "false" },
{ "command": "arboretum.observeSession", "when": "false" },
{ "command": "arboretum.answerSession", "when": "false" },
{ "command": "arboretum.killSession", "when": "false" },
{ "command": "arboretum.hideSession", "when": "false" },
{ "command": "arboretum.resumeSession", "when": "false" },
{ "command": "arboretum.forkSession", "when": "false" },
{ "command": "arboretum.createWorktree", "when": "false" },
{ "command": "arboretum.commitWorktree", "when": "false" },
{ "command": "arboretum.pushWorktree", "when": "false" },
{ "command": "arboretum.fetchWorktree", "when": "false" },
{ "command": "arboretum.pullWorktree", "when": "false" },
{ "command": "arboretum.promoteWorktree", "when": "false" },
{ "command": "arboretum.openWorktreeIde", "when": "false" },
{ "command": "arboretum.startSession", "when": "false" },
{ "command": "arboretum.startGroupSession", "when": "false" },
{ "command": "arboretum.revealWorktree", "when": "false" }
{
"command": "arboretum.refresh",
"when": "arboretum.connected"
},
{
"command": "arboretum.signOut",
"when": "arboretum.connected"
},
{
"command": "arboretum.attachSession",
"when": "false"
},
{
"command": "arboretum.observeSession",
"when": "false"
},
{
"command": "arboretum.answerSession",
"when": "false"
},
{
"command": "arboretum.killSession",
"when": "false"
},
{
"command": "arboretum.hideSession",
"when": "false"
},
{
"command": "arboretum.resumeSession",
"when": "false"
},
{
"command": "arboretum.forkSession",
"when": "false"
},
{
"command": "arboretum.createWorktree",
"when": "false"
},
{
"command": "arboretum.commitWorktree",
"when": "false"
},
{
"command": "arboretum.pushWorktree",
"when": "false"
},
{
"command": "arboretum.fetchWorktree",
"when": "false"
},
{
"command": "arboretum.pullWorktree",
"when": "false"
},
{
"command": "arboretum.promoteWorktree",
"when": "false"
},
{
"command": "arboretum.openWorktreeIde",
"when": "false"
},
{
"command": "arboretum.startSession",
"when": "false"
},
{
"command": "arboretum.startGroupSession",
"when": "false"
},
{
"command": "arboretum.revealWorktree",
"when": "false"
}
]
}
},