diff --git a/.agents/skills/pr-visual-evidence/SKILL.md b/.agents/skills/pr-visual-evidence/SKILL.md index c18a5229..474d59b8 100644 --- a/.agents/skills/pr-visual-evidence/SKILL.md +++ b/.agents/skills/pr-visual-evidence/SKILL.md @@ -1,10 +1,7 @@ --- + name: pr-visual-evidence -description: - 'Create requested PR visual evidence for Roamgate: a leading screenshot and - scripted video for animation, transitions, or multi-step interactions. Use - when the user requests PR screenshots, before/after, video evidence, or visual - guidance. UI changes alone do not require capture or upload.' +description: "Create requested PR visual evidence for Roamgate: a leading screenshot and scripted video for animation, transitions, or multi-step interactions. Use when the user requests PR screenshots, before/after, video evidence, or visual guidance. UI changes alone do not require capture or upload." --- # Roamgate PR visual evidence @@ -24,12 +21,12 @@ Read the diff and identify the visible behavior to prove. A backend, CI, docs, or tooling change that renders identically needs no image. For visible changes, choose the smallest relevant case: -| Roamgate change | Evidence | -| --- | --- | -| Layout, theme, copy, file preview or diff rendering | Focused screenshot; labeled before/after when comparison helps. | -| Dialog, menu, inspector resize, terminal composer or multi-step workflow | Screenshot of the result plus a scripted video of the interaction. | -| Terminal streaming, connection recovery, agent history or Ranger state | Real Herdr-backed state; preserve relevant loading and reconnect behavior. | -| Mobile layout or keyboard behavior | Narrow viewport capture; real device verification for platform keyboard, IME, and touch behavior. | +| Roamgate change | Evidence | +| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- | +| Layout, theme, copy, file preview or diff rendering | Focused screenshot; labeled before/after when comparison helps. | +| Dialog, menu, inspector resize, terminal composer or multi-step workflow | Screenshot of the result plus a scripted video of the interaction. | +| Terminal streaming, connection recovery, agent history or Ranger state | Real Herdr-backed state; preserve relevant loading and reconnect behavior. | +| Mobile layout or keyboard behavior | Narrow viewport capture; real device verification for platform keyboard, IME, and touch behavior. | Keep evidence on the PR's current revision. Record the commit, any uncommitted changes, route, browser, viewport, and scenario with the local artifacts. Do not diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 79f909f9..cbee560a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -3,7 +3,6 @@ ## Project overview Roamgate is an independent community Web and PWA client for Herdr. It has two parts: - - `server/src`: Bun-powered local bridge server (HTTP + WebSocket) that talks to the local Herdr socket. - `web/src`: React + Vite frontend. Reusable UI lives in `web/src/components`, @@ -19,7 +18,6 @@ build artifacts; they must not be edited or committed. ## Review priorities When reviewing pull requests, focus on: - - Correctness of the Bun bridge: HTTP/WebSocket message handling, socket lifecycle, reconnection and error paths, and cleanup of listeners, timers, and subprocesses. @@ -50,7 +48,6 @@ Install all workspace dependencies once with `bun install --frozen-lockfile` from the repo root. The root `bun.lock` is authoritative. Changes are expected to pass, from the repo root: - - `bun run format:check` - `bun run lint` - `bun run test` diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4a5a7e12..e1e15dd9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,63 +1,63 @@ version: 2 updates: - - package-ecosystem: bun - directory: / - schedule: - interval: weekly - day: monday - time: "06:00" - timezone: Etc/UTC - open-pull-requests-limit: 5 - # Bun groups use package patterns, not unsupported dependency-type filters. - # Major upgrades stay separate except for coupled React and xterm families. - groups: - codemirror: - patterns: ["@codemirror/*", "@lezer/*", "codemirror"] - update-types: [minor, patch] - syntax-highlighting: - patterns: ["@shikijs/*", "shiki"] - update-types: [minor, patch] - diff-highlighting: - patterns: ["diff2html", "highlight.js"] - update-types: [minor, patch] - radix-ui: - # cmdk shares Radix primitives with the popover runtime. - patterns: ["@radix-ui/*", "cmdk"] - update-types: [minor, patch] - react: - # Runtime, DOM renderer, and types must move together, including majors. - # Keep manual review for compatibility and bundle size; never auto-merge. - patterns: ["react", "react-dom", "@types/react", "@types/react-dom"] - xterm-core-fit: - # No update-types filter: same-core beta bumps are neither minor - # nor patch to Dependabot. Review this coupled pair together, - # including any future major upgrades; never auto-merge it. - patterns: ["@xterm/xterm", "@xterm/addon-fit"] - xterm-addons: - patterns: ["@xterm/*"] - exclude-patterns: ["@xterm/xterm", "@xterm/addon-fit"] - update-types: [minor, patch] - tooling: - patterns: - - "@biomejs/*" - - "@vitejs/*" - - "bun-types" - - "happy-dom" - - "oxlint" - - "typescript" - - "vite" - update-types: [minor, patch] + - package-ecosystem: bun + directory: / + schedule: + interval: weekly + day: monday + time: "06:00" + timezone: Etc/UTC + open-pull-requests-limit: 5 + # Bun groups use package patterns, not unsupported dependency-type filters. + # Major upgrades stay separate except for coupled React and xterm families. + groups: + codemirror: + patterns: ["@codemirror/*", "@lezer/*", "codemirror"] + update-types: [minor, patch] + syntax-highlighting: + patterns: ["@shikijs/*", "shiki"] + update-types: [minor, patch] + diff-highlighting: + patterns: ["diff2html", "highlight.js"] + update-types: [minor, patch] + radix-ui: + # cmdk shares Radix primitives with the popover runtime. + patterns: ["@radix-ui/*", "cmdk"] + update-types: [minor, patch] + react: + # Runtime, DOM renderer, and types must move together, including majors. + # Keep manual review for compatibility and bundle size; never auto-merge. + patterns: ["react", "react-dom", "@types/react", "@types/react-dom"] + xterm-core-fit: + # No update-types filter: same-core beta bumps are neither minor + # nor patch to Dependabot. Review this coupled pair together, + # including any future major upgrades; never auto-merge it. + patterns: ["@xterm/xterm", "@xterm/addon-fit"] + xterm-addons: + patterns: ["@xterm/*"] + exclude-patterns: ["@xterm/xterm", "@xterm/addon-fit"] + update-types: [minor, patch] + tooling: + patterns: + - "@biomejs/*" + - "@vitejs/*" + - "bun-types" + - "happy-dom" + - "oxlint" + - "typescript" + - "vite" + update-types: [minor, patch] - - package-ecosystem: github-actions - directory: / - schedule: - interval: weekly - day: monday - time: "06:30" - timezone: Etc/UTC - open-pull-requests-limit: 3 - groups: - actions: - patterns: ["*"] - update-types: [minor, patch] + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + day: monday + time: "06:30" + timezone: Etc/UTC + open-pull-requests-limit: 3 + groups: + actions: + patterns: ["*"] + update-types: [minor, patch] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cdcf6a16..990b1dfe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,27 +1,27 @@ name: CI on: - pull_request: - workflow_dispatch: + pull_request: + workflow_dispatch: permissions: - contents: read + contents: read jobs: - validate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - with: - persist-credentials: false - - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - with: - bun-version: "1.4.4" - no-cache: true - - run: bun install --frozen-lockfile - - run: bun run format:check - - run: bun run lint - - run: bun run typecheck - - run: bun run typecheck:bun - - run: bun run build:site - - run: bun run test:quick + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: "1.4.4" + no-cache: true + - run: bun install --frozen-lockfile + - run: bun run format:check + - run: bun run lint + - run: bun run typecheck + - run: bun run typecheck:bun + - run: bun run build:site + - run: bun run test:quick diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9e18e320..5a8d9d8d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,43 +1,43 @@ name: CodeQL on: - pull_request: - branches: [main] - push: - branches: [main] - schedule: - - cron: "23 4 * * 1" - workflow_dispatch: + pull_request: + branches: [main] + push: + branches: [main] + schedule: + - cron: "23 4 * * 1" + workflow_dispatch: permissions: {} concurrency: - group: codeql-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - analyze: - name: Analyze (${{ matrix.language }}) - runs-on: ubuntu-latest - timeout-minutes: 30 - permissions: - contents: read - security-events: write - strategy: - fail-fast: false - matrix: - language: [javascript-typescript, actions] - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - with: - persist-credentials: false - # Neither language needs a build or dependency installation. Keep - # untrusted PR code out of executable steps in this upload job. - - uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4 - with: - languages: ${{ matrix.language }} - build-mode: none - # The default query suite is used for both languages. - - uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4 - with: - category: "/language:${{ matrix.language }}" + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [javascript-typescript, actions] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + # Neither language needs a build or dependency installation. Keep + # untrusted PR code out of executable steps in this upload job. + - uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4 + with: + languages: ${{ matrix.language }} + build-mode: none + # The default query suite is used for both languages. + - uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/dependency-audit.yml b/.github/workflows/dependency-audit.yml index 9d55ab13..da5a6d64 100644 --- a/.github/workflows/dependency-audit.yml +++ b/.github/workflows/dependency-audit.yml @@ -1,37 +1,37 @@ name: Dependency Audit on: - pull_request: - paths: - - "**/package.json" - - "bun.lock" - - "**/bunfig.toml" - - "**/.npmrc" - - ".github/workflows/dependency-audit.yml" - schedule: - - cron: "41 4 * * 1" - workflow_dispatch: + pull_request: + paths: + - "**/package.json" + - "bun.lock" + - "**/bunfig.toml" + - "**/.npmrc" + - ".github/workflows/dependency-audit.yml" + schedule: + - cron: "41 4 * * 1" + workflow_dispatch: permissions: - contents: read + contents: read concurrency: - group: dependency-audit-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + group: dependency-audit-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - audit: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - with: - persist-credentials: false - - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - with: - bun-version: "1.4.4" - no-cache: true - # Audit the lockfile directly, including dev dependencies, without - # installing packages or running lifecycle scripts. JSON retains - # lower-severity findings; high/critical findings fail the job. - - run: bun audit --json --audit-level=high + audit: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: "1.4.4" + no-cache: true + # Audit the lockfile directly, including dev dependencies, without + # installing packages or running lifecycle scripts. JSON retains + # lower-severity findings; high/critical findings fail the job. + - run: bun audit --json --audit-level=high diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index a7f96fd2..76d6c387 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,71 +1,71 @@ name: Deploy Pages on: - push: - branches: [main] - paths: - - site/** - - docs/TUTORIAL.md - - docs/images/** - - scripts/build-pages.ts - - scripts/pages-*.test.ts - - .github/workflows/pages.yml - workflow_dispatch: + push: + branches: [main] + paths: + - site/** + - docs/TUTORIAL.md + - docs/images/** + - scripts/build-pages.ts + - scripts/pages-*.test.ts + - .github/workflows/pages.yml + workflow_dispatch: permissions: - contents: read + contents: read concurrency: - group: pages - cancel-in-progress: true + group: pages + cancel-in-progress: true jobs: - build: - permissions: - contents: read - pages: write - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - with: - persist-credentials: false - - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - with: - bun-version: "1.4.4" - no-cache: true - - name: Verify live Roamgate installer - run: | - set -eu - status=$(curl --fail --silent --show-error --location \ - --proto '=https' --proto-redir '=https' \ - --connect-timeout 10 --max-time 60 --output /dev/null \ - --write-out '%{http_code}' \ - https://github.com/powerfooI/roamgate/releases/latest/download/install-roamgate.sh) \ - && [ "$status" = 200 ] \ - || { echo 'Publish a Roamgate release as Latest before deploying Pages.' >&2; exit 1; } - - name: Configure Pages - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - with: - enablement: true - - name: Test tutorial rendering and site references - run: bun test scripts/pages-content.test.ts scripts/pages-workflow.test.ts - - name: Build landing page and tutorial - run: bun run build:site - - name: Upload Pages artifact - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 - with: - path: .pages-dist + build: + permissions: + contents: read + pages: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: "1.4.4" + no-cache: true + - name: Verify live Roamgate installer + run: | + set -eu + status=$(curl --fail --silent --show-error --location \ + --proto '=https' --proto-redir '=https' \ + --connect-timeout 10 --max-time 60 --output /dev/null \ + --write-out '%{http_code}' \ + https://github.com/powerfooI/roamgate/releases/latest/download/install-roamgate.sh) \ + && [ "$status" = 200 ] \ + || { echo 'Publish a Roamgate release as Latest before deploying Pages.' >&2; exit 1; } + - name: Configure Pages + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + with: + enablement: true + - name: Test tutorial rendering and site references + run: bun test scripts/pages-content.test.ts scripts/pages-workflow.test.ts + - name: Build landing page and tutorial + run: bun run build:site + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + with: + path: .pages-dist - deploy: - permissions: - pages: write - id-token: write - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 + deploy: + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/AGENTS.md b/AGENTS.md index 750eb1f2..8aa76915 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,7 +20,6 @@ Install all Bun workspace dependencies from the repository root with `bun install --frozen-lockfile` (Bun 1.4.4 or newer). The root `bun.lock` is the only lockfile; shared TypeScript, Bun types, and lint/format tooling belong in the root manifest. Keep runtime dependencies in their owning workspace. - - `bun run dev:web`: start the Vite frontend on port 5173. - `bun run dev:server`: start the Bun bridge with hot reload. - `bun run build`: build frontend assets and the default standalone server binary. @@ -105,7 +104,6 @@ from the release notes. Leave detailed records in PRs, external artifacts, or Git history. Stable releases use separate prepare and publish phases: - 1. Run the **Prepare Release** workflow with `X.Y.Z` or `patch`/`minor`/`major`. It updates the three `package.json` versions plus `herdr-plugin.toml` and opens a normal release PR. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5758ca99..b3cdde28 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,13 +28,13 @@ lockfile changes together. On a fresh checkout, run `bun run typecheck` once to generate the web assets that process-level tests need. Then iterate with focused checks: -| Check | Command | -| --- | --- | -| Format | `bun run format ` or `bun run format:check` | -| Types | `bun run typecheck:quick` (no asset rebuild) | -| Lint | `bun run lint` (Oxlint; rules in `.oxlintrc.json`) | -| Tests | `bun test `, `bun run test` (serial), or `bun run test:quick` (four workers) | -| Frontend build | `bun run build:web` (required for frontend changes) | +| Check | Command | +| -------------- | ---------------------------------------------------------------------------------- | +| Format | `bun run format ` or `bun run format:check` | +| Types | `bun run typecheck:quick` (no asset rebuild) | +| Lint | `bun run lint` (Oxlint; rules in `.oxlintrc.json`) | +| Tests | `bun test `, `bun run test` (serial), or `bun run test:quick` (four workers) | +| Frontend build | `bun run build:web` (required for frontend changes) | The pre-commit hook runs lint and `bun run typecheck:bun` (Bun's native `bun check` across the root, web, and server projects). Let it run instead of @@ -50,7 +50,6 @@ and the [release policy](AGENTS.md#release-notes). Automated tests do not launch browsers. For affected UI, check against a real backend and record the device/browser and results in the PR: - - Dialog focus and keyboard navigation, scaled layouts, and HTML preview isolation (CSP, direct navigation). - iOS Safari and Android Chrome: keyboard open/close, IME, selecting while output @@ -86,7 +85,6 @@ bun test server/src/connections/windows-ssh-live.test.ts Nothing auto-merges. When reviewing updates: - - Review `@xterm/xterm` and `@xterm/addon-fit` together and check terminal rendering, sizing, input, and touch scrolling. - CodeMirror/Lezer, diff2html/highlight.js, and Radix/cmdk are coupled: check the @@ -101,13 +99,13 @@ When reviewing updates: ## Style Organization -| Path under `web/src/` | Responsibility | -| --- | --- | -| `styles/tokens.css` | Theme variables (`:root`, `data-theme`, `data-accent`) | -| `styles/base.css` | Resets and shared primitives: modals, forms, badges, panels | -| `styles/vendor.css` | Shared syntax/diff overrides | -| `styles/layout/*.css` | App-shell regions, imported once by `App.tsx` | -| `components/.css` | Component styles, imported and deleted with the component | +| Path under `web/src/` | Responsibility | +| ----------------------- | ----------------------------------------------------------- | +| `styles/tokens.css` | Theme variables (`:root`, `data-theme`, `data-accent`) | +| `styles/base.css` | Resets and shared primitives: modals, forms, badges, panels | +| `styles/vendor.css` | Shared syntax/diff overrides | +| `styles/layout/*.css` | App-shell regions, imported once by `App.tsx` | +| `components/.css` | Component styles, imported and deleted with the component | Prefix classes with the component name and keep media queries beside their rules. Lazily loaded features must import the shared styles they need rather diff --git a/FEATURES.md b/FEATURES.md index 7e777646..d8f5dc6d 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -70,7 +70,6 @@ Herdr 0.9.1+ resolves URLs that wrap across lines. See Open **Files**, **Changes**, **Commits**, or **Agent History** from the Inspector button, shortcuts, or workspace/agent menus. - - Dock right or bottom, resize, or expand. Narrow layouts use drill-down views. - Single-click opens a temporary preview tab; double-click keeps it. Open files are restored per connection and checkout. @@ -161,7 +160,6 @@ See [History synchronization](docs/HISTORY.md). Ranger is an **experimental** assistant that answers questions about your workspaces and can manage them. Open it from the topbar, the mobile **⋮** menu, or its shortcut. - - **Setup:** connect a model provider in **Settings** and choose which workspaces Ranger may access (none by default). See [model setup](docs/DEPLOYMENT.md#ranger-model-connection). @@ -191,7 +189,6 @@ has the same [full authority](SECURITY.md#trust-model) as any Roamgate user. ## Git Worktree Lifecycle Open **Worktree Lifecycle** from a workspace menu or the command menu to: - - Create a worktree from `origin`'s freshly fetched default branch without touching the current checkout. Creation stops if the remote is unavailable. - See each worktree's path, branch status, uncommitted changes, and PR/MR badge. @@ -230,7 +227,6 @@ conflicts are aborted, and nothing is ever pushed. ## Review Annotations Open **Annotations** independently of the Inspector. - 1. Comment on diff lines, source lines, rendered Markdown, or selected terminal text. 2. Edit and reorder comments, then copy them or pre-fill an agent's input. @@ -338,37 +334,37 @@ On desktop, press `Cmd+Shift+K` (`Ctrl+Alt+Shift+K` on Windows/Linux) or choose **Menu > Configuration > Behavior > Keyboard shortcuts** (up to three per action, with JSON import/export). -| Action | macOS / iOS | Windows / Linux / Android | -| --- | --- | --- | -| Command menu | `Cmd+K` | `Ctrl+Alt+K` | -| Shortcut cheat sheet (desktop) | `Cmd+Shift+K` | `Ctrl+Alt+Shift+K` | -| Sidebar | `Cmd+B` | `Ctrl+Alt+B` | -| Workspace Inspector | `Cmd+Shift+B` | `Ctrl+Alt+Shift+B` | -| Expand / restore Inspector (desktop) | `Cmd+Option+Enter` | `Ctrl+Alt+Shift+Enter` | -| Annotations | `Cmd+Option+A` | `Ctrl+Alt+A` | -| Ranger | `Cmd+Option+Shift+A` | `Ctrl+Alt+Shift+A` | -| Zen mode (desktop) | `Cmd+Shift+Z` | `Ctrl+Alt+Z` | -| Recent pane switcher | `Ctrl+Tab` | `Ctrl+Alt+J` | -| Search panes | `Alt+K` | `Alt+K` | -| Focus terminal input (desktop) | ``Ctrl+` `` | ``Ctrl+` `` | -| Create / close tab or pane | `Cmd+T` / `Cmd+W` | `Ctrl+Alt+T` / `Ctrl+Alt+W` | -| Previous / next tab | `Cmd+Option+Left/Right` | `Alt+Shift+Left/Right` | -| Focus neighboring pane | `Cmd+Ctrl+Arrow` | `Ctrl+Shift+Arrow` | -| Move pane (swap with neighbor) | `Cmd+Ctrl+Shift+Arrow` | `Ctrl+Alt+Shift+Arrow` | -| Split right / down | `Cmd+D` / `Cmd+Shift+D` | `Ctrl+Alt+D` / `Ctrl+Alt+Shift+D` | -| Zoom / restore pane | `Cmd+Shift+Enter` | `Ctrl+Alt+Enter` | -| Numbered tab | `Ctrl+1…9` | `Ctrl+Alt+1…9` | -| Numbered command menu action | `Option+1…9` | `Alt+1…9` | -| Workspaces | `Ctrl+Shift+W` | `Ctrl+Alt+O` | -| File Explorer | `Cmd+Shift+E` | `Ctrl+Alt+E` | -| Diff Viewer | `Ctrl+Shift+G` | `Ctrl+Alt+G` | -| Agent history | `Cmd+Shift+H` | `Ctrl+Alt+H` | -| Search raw preview / diff | `Cmd+F` | `Ctrl+F` | -| Send composer / add review comment / pre-fill agent (focused surface) | `Cmd+Enter` | `Ctrl+Enter` | -| Copy review feedback (in Annotations) | `Cmd+Shift+C` | `Ctrl+Shift+C` | -| Copy terminal selection | `Cmd+C` | `Ctrl+Shift+C` / `Ctrl+Insert` | -| Terminal paste | `Cmd+V` | `Ctrl+V` (also `Ctrl+Shift+V` on Linux) | -| Open terminal links / file paths | `Cmd+Click` | `Ctrl+Click` | +| Action | macOS / iOS | Windows / Linux / Android | +| --------------------------------------------------------------------- | ----------------------- | --------------------------------------- | +| Command menu | `Cmd+K` | `Ctrl+Alt+K` | +| Shortcut cheat sheet (desktop) | `Cmd+Shift+K` | `Ctrl+Alt+Shift+K` | +| Sidebar | `Cmd+B` | `Ctrl+Alt+B` | +| Workspace Inspector | `Cmd+Shift+B` | `Ctrl+Alt+Shift+B` | +| Expand / restore Inspector (desktop) | `Cmd+Option+Enter` | `Ctrl+Alt+Shift+Enter` | +| Annotations | `Cmd+Option+A` | `Ctrl+Alt+A` | +| Ranger | `Cmd+Option+Shift+A` | `Ctrl+Alt+Shift+A` | +| Zen mode (desktop) | `Cmd+Shift+Z` | `Ctrl+Alt+Z` | +| Recent pane switcher | `Ctrl+Tab` | `Ctrl+Alt+J` | +| Search panes | `Alt+K` | `Alt+K` | +| Focus terminal input (desktop) | ``Ctrl+` `` | ``Ctrl+` `` | +| Create / close tab or pane | `Cmd+T` / `Cmd+W` | `Ctrl+Alt+T` / `Ctrl+Alt+W` | +| Previous / next tab | `Cmd+Option+Left/Right` | `Alt+Shift+Left/Right` | +| Focus neighboring pane | `Cmd+Ctrl+Arrow` | `Ctrl+Shift+Arrow` | +| Move pane (swap with neighbor) | `Cmd+Ctrl+Shift+Arrow` | `Ctrl+Alt+Shift+Arrow` | +| Split right / down | `Cmd+D` / `Cmd+Shift+D` | `Ctrl+Alt+D` / `Ctrl+Alt+Shift+D` | +| Zoom / restore pane | `Cmd+Shift+Enter` | `Ctrl+Alt+Enter` | +| Numbered tab | `Ctrl+1…9` | `Ctrl+Alt+1…9` | +| Numbered command menu action | `Option+1…9` | `Alt+1…9` | +| Workspaces | `Ctrl+Shift+W` | `Ctrl+Alt+O` | +| File Explorer | `Cmd+Shift+E` | `Ctrl+Alt+E` | +| Diff Viewer | `Ctrl+Shift+G` | `Ctrl+Alt+G` | +| Agent history | `Cmd+Shift+H` | `Ctrl+Alt+H` | +| Search raw preview / diff | `Cmd+F` | `Ctrl+F` | +| Send composer / add review comment / pre-fill agent (focused surface) | `Cmd+Enter` | `Ctrl+Enter` | +| Copy review feedback (in Annotations) | `Cmd+Shift+C` | `Ctrl+Shift+C` | +| Copy terminal selection | `Cmd+C` | `Ctrl+Shift+C` / `Ctrl+Insert` | +| Terminal paste | `Cmd+V` | `Ctrl+V` (also `Ctrl+Shift+V` on Linux) | +| Open terminal links / file paths | `Cmd+Click` | `Ctrl+Click` | On Linux/Android, new tab is `Ctrl+Alt+Shift+T`, split right is `Ctrl+Alt+Shift+D`, and split down is `Ctrl+Alt+Shift+S`, avoiding diff --git a/README.md b/README.md index 30b1ca35..03dbcdcb 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,6 @@ See [deployment](./docs/DEPLOYMENT.md) for configuration, services, and updates. **Recommended for daily use:** a separate app window without browser tabs or the address bar. Log in to Roamgate, then install: - - **iPhone/iPad Safari:** Share -> Add to Home Screen. - **macOS Safari 17+:** File -> Add to Dock. - **Chrome/Edge:** browser menu -> Install app. diff --git a/SECURITY.md b/SECURITY.md index 0275d6bf..1b85211b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -15,7 +15,6 @@ GitHub-profile contact address. **Anyone who can use the UI has the Roamgate user's full authority:** terminals, repository hooks, session data, and file uploads/deletions. Roamgate is single-user administration, not a sandbox or multi-user permission system. - - The default bind is `127.0.0.1`. **Login is required, including on loopback.** The only exception is `NODE_ENV=development` bound to `127.0.0.1`, `localhost`, or `::1` (what `bun run dev:server` uses). Never @@ -54,7 +53,6 @@ including password sessions. ### Access and session safety **Do not expose Roamgate directly to the public internet.** For remote access: - - Prefer `ROAMGATE_PASSWORD` over `--password`, which is visible in process arguments. - Use [native HTTPS](docs/DEPLOYMENT.md#native-https), an HTTPS proxy, or a diff --git a/biome.json b/biome.json index fab8479e..eb3f8a47 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.5.9/schema.json", + "$schema": "https://biomejs.dev/schemas/2.6.2/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/bun.lock b/bun.lock index f13c668a..147c97c5 100644 --- a/bun.lock +++ b/bun.lock @@ -5,14 +5,14 @@ "": { "name": "roamgate", "devDependencies": { - "@biomejs/biome": "2.5.15", + "@biomejs/biome": "2.6.2", "@types/jsdom": "^30.0.0", "@types/proper-lockfile": "4.1.4", "@types/web-push": "^3.6.4", "bun-types": "1.4.4", "happy-dom": "^21.0.4", "jsdom": "^30.1.3", - "oxlint": "1.88.0", + "oxlint": "1.89.0", "typescript": "^7.0.2", }, }, @@ -85,7 +85,7 @@ "@types/react": "^19.3.0", "@types/react-dom": "^19.3.0", "@vitejs/plugin-react": "^6.1.2", - "vite": "^8.3.4", + "vite": "^8.3.5", }, }, }, @@ -140,23 +140,27 @@ "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="], - "@biomejs/biome": ["@biomejs/biome@2.5.15", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.5.15", "@biomejs/cli-darwin-x64": "2.5.15", "@biomejs/cli-linux-arm64": "2.5.15", "@biomejs/cli-linux-arm64-musl": "2.5.15", "@biomejs/cli-linux-x64": "2.5.15", "@biomejs/cli-linux-x64-musl": "2.5.15", "@biomejs/cli-win32-arm64": "2.5.15", "@biomejs/cli-win32-x64": "2.5.15" }, "bin": { "biome": "bin/biome" } }, "sha512-WZTW4slm/pdkh92K6t/3aEN++44JD1PQ7squ7RCMLI1flHGl43DVOIGXvCjHiZgBMO1V4uYxoFNtqrIA4qGuIQ=="], + "@biomejs/biome": ["@biomejs/biome@2.6.2", "", { "optionalDependencies": { "@biomejs/cli-android-arm64": "2.6.2", "@biomejs/cli-android-x64": "2.6.2", "@biomejs/cli-darwin-arm64": "2.6.2", "@biomejs/cli-darwin-x64": "2.6.2", "@biomejs/cli-linux-arm64": "2.6.2", "@biomejs/cli-linux-arm64-musl": "2.6.2", "@biomejs/cli-linux-x64": "2.6.2", "@biomejs/cli-linux-x64-musl": "2.6.2", "@biomejs/cli-win32-arm64": "2.6.2", "@biomejs/cli-win32-x64": "2.6.2" }, "bin": { "biome": "bin/biome" } }, "sha512-JLTFAFF9vfJcWwLhwuL4ZHflLg+XfTEC4IUnAlJRX1cMRt57++Xd1Ysb9Fdmlh9YUrvyCXfPEHjjEIqKJGdPKw=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.5.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BZVzFhJ/mUvTLMYbc9x6el0o2Uv5zP7bACYyhFb6fSc1giroXm7PL0a5KqMJ9F+/BnkYRjagD/ROSDVOZ6eapg=="], + "@biomejs/cli-android-arm64": ["@biomejs/cli-android-arm64@2.6.2", "", { "os": "android", "cpu": "arm64" }, "sha512-dMpdpH7zFEL5FxuIA9LJW+RoNyC3oeDB7PJyjqVVwtMNoKB5uo8OZYmrVSBikn71txzYwy/3xga7UME6bJQZ6A=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.5.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-V5Kw63V+fVGNFhFrizDxMbGXAzZCh8kYzJpy3GI6gTapWDg7bZK9oYC9CbVgQSEdTnupz0U5Efz8Ev+5vdBBXw=="], + "@biomejs/cli-android-x64": ["@biomejs/cli-android-x64@2.6.2", "", { "os": "android", "cpu": "x64" }, "sha512-XCwEhPBGYzuRA502dRkCcQ+5cefQwuxQR7f9wa4do92dvIcuBL6VMLMFB/fL9hlpZ4dGSfHdpGFSIDlp52mg0A=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.5.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-XaG7P7eeSLYETD3K9grfB0mQmpLQZjygdbsxekWBJAg4am79fGAtRpfRyNnTvXB2fZFNnJZG3nXm7HBat0+VUw=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.6.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rpXtabRgyZNz3aCjd/cRoSZGYi92R9eAXdUUe1sigIsRDyfMwgThaa98Yxt1fiZ7mxquqkAyIHIo08N/e1ToBA=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.5.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-tGzZUTcJCV7tj5Adh/Gn6nR4MycqA3iohq2LEcrarAgRBkU0h0OKd2UzCRkOsOYOuUGaUJb4YmqRqyy2feGGSw=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.6.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-7GGzlm1GxUKoQ9CNV8tQZ+XXad4sz+v+uzNsWlhaGjsnZqUOVBw1OmAMpG3uNV/Mr0UrCpRJvSK0qvfuqSQOjg=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.5.15", "", { "os": "linux", "cpu": "x64" }, "sha512-xE4iEW/3LqlYj9GFgGrFsFSH51dEEpUbYWBfeOv0q87WkUDxK2o/HhreSb7qMJqck70RVM6Lg96hgedcAYcOkA=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.6.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qs4CofCE8MdkjZFfEjswh2NAcbyQ7IVYtGSzQBvLqFlla/CSXroGbktUFndWG/kVSTywadauzAspYWtSfqAc2g=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.5.15", "", { "os": "linux", "cpu": "x64" }, "sha512-IlxUcyxilVGPsE008x13pWdkTbU3nQpP2i9b5UrbOYj6goBkKsRX1XB7yJLcV+O1H9LBchIIm4adOaVLZBX0ZQ=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.6.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-I+FYCLVSmR3cYfKcQ+KNeLOZ5w0wRd9fQFlw3JbSvy7bkegvTqdHaBRRcJzHQB/1ldldTLIcG21ka6X2cTWmJw=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.5.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-2kPKzhNlm8C+Ru3GcO0Me2ODkCBLrVOUNuyi84RJyWDVKAA4+Kjj3jMjL938lF6BRfvltC4vB2nPY9SvN51Ovg=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.6.2", "", { "os": "linux", "cpu": "x64" }, "sha512-FJKsb95418139xDdbv9XnNJsIIwvsgR21Of0aE9B9U+nQlOtRq5gJl2ps0jZUmYBxTaOlP9BKo8N+Ff8+Rui1g=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.5.15", "", { "os": "win32", "cpu": "x64" }, "sha512-yAzh4UqEImV6Hcy0zjUqNfJAsUhoD64FBQCdTG8Md/Z2wQeVP/ZmJ3XRYAs1g8J9fjTFyl2fCtc5FB5til47+g=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.6.2", "", { "os": "linux", "cpu": "x64" }, "sha512-wnjEXAK2pDd2j8r9gKI3L+44sIxjkYzS5aHmD1+K57RNJ3sFyT4n22NH6QFPqqeVdRBxN54H3kckUUCrFKCcJw=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.6.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-/PEOo6evlgrQOfKhMNtC/4Gk8ai3hySXXEtjUzCqZe/4iAbMdqelpp7qvZEDyLxlZS+BjOMQFpq2gXI/BPaAqw=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.6.2", "", { "os": "win32", "cpu": "x64" }, "sha512-FVlWD+mDDz8nN5LWKRWUhhb7wKIK0VE3oXQvQBX7Fwwj00CvqMVhMyiz1iz8O5aZGmnkhFlKSwJPrUvMh5prQw=="], "@bramus/specificity": ["@bramus/specificity@2.4.2", "", { "dependencies": { "css-tree": "^3.0.0" }, "bin": { "specificity": "bin/cli.js" } }, "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw=="], @@ -290,45 +294,45 @@ "@marijn/find-cluster-break": ["@marijn/find-cluster-break@1.0.2", "", {}, "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="], - "@oxc-project/types": ["@oxc-project/types@0.152.0", "", {}, "sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw=="], + "@oxc-project/types": ["@oxc-project/types@0.155.0", "", {}, "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q=="], - "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.88.0", "", { "os": "android", "cpu": "arm" }, "sha512-k6Fgkf86ubfeH4GvqYsRolfuVAp0pfYVZvifSlXNHPdMaWUOfxUrmLEeDD7hF6U2oJuhsVxhSWq86/xCJ+9MmA=="], + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.89.0", "", { "os": "android", "cpu": "arm" }, "sha512-Pflpba5F3gRAQ12sWglRxvWTHEdAusNDvmi4Y5N1T5SY1AGkM7AixOnET8qkrnLJ/F32qAlNokO6eCknT8tmnw=="], - "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.88.0", "", { "os": "android", "cpu": "arm64" }, "sha512-AsIyhl9o1ejwtac7NMbhKpMdSml6NWR0ljKjZERxC8OHYDAW8o/Om9n1QHVLi4VCEUo42Zte2/Op9kyoGpJZMg=="], + "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.89.0", "", { "os": "android", "cpu": "arm64" }, "sha512-dYmyD1x7LaPlb79vZWUcpTShk8dI9z1I+IubtqrBxWNJaDhQdPHwcsvg7q5StTU4xWyd9AwPfLaTYFZY8NZgtQ=="], - "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.88.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-qgBjB7eEKcCB4RqjXGuoSZq74g0wD09fWFJ+HWcCJcKaga8TeUHtb+BY0SsxdleSLBgx4RZ7qmgo0EzqEq7JoQ=="], + "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.89.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Z/oxOPiIqiS7fItRdxaaOEC+6GD3OpGi0IxoR0dMefzQHolsKLzScw2DNcu/5gUPok3tv+G9mslvYB5bo3i0qg=="], - "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.88.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-sCz3X5Mw/xdzEzn4fsCt1Iq8NKJnGNfhR+b9B5k+4DysYAHsmIhYoocnBPiQ9kvY3+pUun2A0Z8Vtun/Nv6YoQ=="], + "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.89.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-eAjTkHSjAxrdCPJxO6y5sPQL5pYLKb2kvxZz9UU7tXnOZk9I/HLtkvx9S7GHY883k+AmL/eC7mqFt+w7WCwk0w=="], - "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.88.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-xTOdYOIqCufgIj0knvxu86FBfovP6QBiD7ngNva01gb8xPQCD5gXkE5APGczH35zStim1O3zqvFbLQmY85xXRg=="], + "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.89.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0lNCA9Tl1n1FKpqy2/9ckp0kIuSrtJ/l9bMRgaEhOtM7TsOHshFuwOcvW8oA9teXLMOJT61LjEKWiaHDFGxF/w=="], - "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.88.0", "", { "os": "linux", "cpu": "arm" }, "sha512-BLadtw88NdYJBrAtC1dYzrPfSP2d5zgx6iuZycdD0YmZBJ2Nqbit9Z4PSaIb6gxK25dweArGMPbOmq/0ugwUPg=="], + "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.89.0", "", { "os": "linux", "cpu": "arm" }, "sha512-OTFEvi9W+JczaZD1Caj17SGCoW8H7TE+fvx0D7ATEWa1Lohn91UMxFQ6r145SiGy/yCxeIwptMys/RAM7gSVSQ=="], - "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.88.0", "", { "os": "linux", "cpu": "arm" }, "sha512-wILSczl/DaZsCcf7j7tvNbssp8hxEHIJxrv4j7+JjI3TAL1U/JTWbeUtoJJC/vo8+2hkTmHLYoKJjmiNbijdXw=="], + "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.89.0", "", { "os": "linux", "cpu": "arm" }, "sha512-fRxgNHvBLswj6MrhW2uBq5UDhPRQlCbHeq/Nf8yuG9zOxhDsXqX/mi2PX1axgsQxMm88el7HLiJAzglAnflYxw=="], - "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.88.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jutT2Hy8JCuZuMwIFHo2HtyxfOfBJHyQxlBHBK1SL9W2f8n/WhjAP0FnDMz9d/mjhv9+QA0mx5AdQ9fDjsrFFg=="], + "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.89.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-v9ENzHvwrQoYSWTtviH1pOYc7R9UovDxVofnck50cNmPihRRTcrg5X0UlRbLOZ7IVtxPOlh2hb7kDO+FpE8SfQ=="], - "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.88.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-8N8iGV9hh4Lkeuq7QsEkjoXNRRflqR1G2qyoGYXcA0k5qllrdqmfylKEXyHIVERxqNDyMO4StqDQ0uLxXcBQAg=="], + "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.89.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-vfffe8mQ484AzVadlUOFpgL+JDwhvs9hrzxTgQP1FVfi4ZEUUYeffXlzC9dFV7Dgnu5s/KrNKvfmG6HxBd/ISQ=="], - "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.88.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-5ydcQt3znNQ/rGEWYRvpS2cK9+T18P2VYgnyJ+eloEAwi9YUmsXy5VGrRqNWIK6qzWwHGnEE3ojVqqQNo+f0hA=="], + "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.89.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Buonlp4hVS7RGNP5M7bPpGNQrenyzA2C64JcO/oz9C1c6dGOXJ7VEAnaiAMY7voou0JYyCJdvDVlFQc5DZX3DQ=="], - "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.88.0", "", { "os": "linux", "cpu": "none" }, "sha512-iGx0uvFT54b/5DPJdEBCxYIrVB3v0uTy+JhRh3CyEp8/22BXDkG8rffkFwREdLsdj9mOrPbJYVOZw8ipcBuzjw=="], + "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.89.0", "", { "os": "linux", "cpu": "none" }, "sha512-1eVwJJrJ3lYIPT+cm7BcBBZZXY6IQZP/oyonaruTor/MrVyWOpvnwt1oD5CLdsHg5aVBIxXodQSvt+1gK6ck5w=="], - "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.88.0", "", { "os": "linux", "cpu": "none" }, "sha512-Wt47mKMWelVjRjuR7BCFxXkB0m79K1sTEbqMHRWciKUgo5iv7sWsF4RXSOyFYHD9zerNrkRZblnN273rhwOA1Q=="], + "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.89.0", "", { "os": "linux", "cpu": "none" }, "sha512-fRQQsKUGShdEL5Fl9o9uhj3grkZbeXKLv0icQ5tspUCNYSDy8wzzEcP1WC2bKdTQ0rSszbKlO3iiHORxV22DLg=="], - "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.88.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-g3L12KCS4+1gtUt3RbJ4F+Yxx4LNmmZLEPfhd8rAHEJjJk2lAgNfnjGoP/phJyhG5WS6VbNYbJtadJelNfvTMA=="], + "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.89.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-dEtYjIy6+fHcjKklsmtmMkZRhwHr2UbzjmpvuPtQYSeN9awQ2hx5JLms5Wvri+8P/NZtD8v5hfgHALUql+/Ycg=="], - "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.88.0", "", { "os": "linux", "cpu": "x64" }, "sha512-og/XHVDOD9ZJgRiZkT9DgzQd4sr+JZW7e4l17Q/jVMZiIbeEd4uIu9iAoUbTF1gIvVZoRc4QDOxyVUvQGp4WHg=="], + "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.89.0", "", { "os": "linux", "cpu": "x64" }, "sha512-hqjwIj5KOYM8Wjef/p7IruNi1iByLhSzbMBk62y22P/E8q7Jj0Pp+DeUTKTRYyZYCDtU1wEGlnWOnttHbyNIww=="], - "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.88.0", "", { "os": "linux", "cpu": "x64" }, "sha512-EmhBsp+xuKb6YbZNEMLBo80Xw71AZOIm18do8ni/GLX/Lw1XzNhVYpbxO1KasYtoAvrGtCOdCPULRlIE0bPbTQ=="], + "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.89.0", "", { "os": "linux", "cpu": "x64" }, "sha512-iAQN3e6o9UgUCcdGwqRx/jYcKbG3HK7ur3rH6lTqVcQeNGZ85AeWIg6cgn/edwFQ0ofEZZItMwkzyCVTahnvEA=="], - "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.88.0", "", { "os": "none", "cpu": "arm64" }, "sha512-DBUcx/KwYdg1DAz+G01P/GFv512J04EsZadbHptx2FTpWT/MWRg21ZToNHt9pnsfQRBQ3et/g+vqzbvrdAVbuA=="], + "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.89.0", "", { "os": "none", "cpu": "arm64" }, "sha512-MNxjEByz3N/7Q4qFQuPWvc14TpN9LoD3pECEDsJTZbP/wyB7U+hduUXEl7QAbbgVezFwsb9sWtNUO6XVBndOhg=="], - "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.88.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-xeVd0n4XG5HvynxfYvXi6uB+JvZbVZataowPS8cYpMbYg9mwE4sSyElFQd4LVJFifq8bRLDSR18XgEildmcXAg=="], + "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.89.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-xxe+i9wfuFso/VnoL4mfj0UlzE+cfCFiUB06vkXCMyQdgVVmItF5FfAF4tATAktSU6uHruWR+FjqvAT9cHZZzg=="], - "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.88.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-MA6iOw//amleaz2mVMsZrA7NHlEexjTrhIxSMFCXQi6IUuQO+3Od00GZhr2iCYw6RFzMW36jkKK/WHBXMsoQAw=="], + "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.89.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-saFy07cO94E664glwgLmKLI40HgTL1PY86y4T6+ud4niX4H0Kdqjcmqmjps7mQNdBytV5guGbXDdyQtRfeLbLA=="], - "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.88.0", "", { "os": "win32", "cpu": "x64" }, "sha512-3Sz6rVWe8Dy+ufsXurFN1GX2dX43F/lQMSLelK9gFjiba7nHvLlqlhR5cHlWVnCpSqUY1hN9pyCX9XToe6ve6g=="], + "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.89.0", "", { "os": "win32", "cpu": "x64" }, "sha512-hLFJ/o0f/dTJh/EW0vmcbREYSQO9tYgfiAAlsOkiLFiJuRRWvYtFELUXN5o2ijpSo/tlO1n+YlWN58tZwPG18A=="], "@pierre/diffs": ["@pierre/diffs@1.5.1", "", { "dependencies": { "@pierre/theme": "2.0.0", "@pierre/theming": "1.0.1", "@shikijs/transformers": "^3.0.0 || ^4.0.0", "diff": "9.0.0", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "^3.0.0 || ^4.0.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-+EXNfz4ZXI6FHr7P6ToWEORwyYiPVfAmzhA70xF+0y/oNvj7gbNTLJJ6jNzkBjuMbRlu564TAmgYZLc5OyHURA=="], @@ -400,35 +404,35 @@ "@radix-ui/rect": ["@radix-ui/rect@1.1.3", "", {}, "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw=="], - "@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.12", "", { "os": "android", "cpu": "arm" }, "sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A=="], + "@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.15", "", { "os": "android", "cpu": "arm" }, "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw=="], - "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.12", "", { "os": "android", "cpu": "arm64" }, "sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg=="], + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.15", "", { "os": "android", "cpu": "arm64" }, "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg=="], - "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w=="], + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA=="], - "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA=="], + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A=="], - "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ=="], + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.15", "", { "os": "freebsd", "cpu": "x64" }, "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ=="], - "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.12", "", { "os": "linux", "cpu": "arm" }, "sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g=="], + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.15", "", { "os": "linux", "cpu": "arm" }, "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ=="], - "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw=="], + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw=="], - "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw=="], + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ=="], - "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ=="], + "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.15", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw=="], - "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw=="], + "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.15", "", { "os": "linux", "cpu": "s390x" }, "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA=="], - "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.12", "", { "os": "linux", "cpu": "x64" }, "sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw=="], + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.15", "", { "os": "linux", "cpu": "x64" }, "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw=="], - "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.12", "", { "os": "linux", "cpu": "x64" }, "sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g=="], + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.15", "", { "os": "linux", "cpu": "x64" }, "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ=="], - "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA=="], + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.15", "", { "os": "none", "cpu": "arm64" }, "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w=="], - "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew=="], + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg=="], - "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.12", "", { "os": "win32", "cpu": "x64" }, "sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ=="], + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.15", "", { "os": "win32", "cpu": "x64" }, "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ=="], "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="], @@ -766,7 +770,7 @@ "openai": ["openai@7.19.0", "", { "peerDependencies": { "@aws-sdk/credential-provider-node": ">=3.972.0 <4", "@smithy/hash-node": ">=4.3.0 <5", "@smithy/signature-v4": ">=5.4.0 <6", "undici": ">=5 <9", "ws": "^8.21.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["@aws-sdk/credential-provider-node", "@smithy/hash-node", "@smithy/signature-v4", "undici", "ws", "zod"] }, "sha512-MX2s3u2L5racTO0CC/SWpCOasJQBCJrqLKXK+l82cAhdeF8mPMBEe/gxMm0ZFa2xpKpOFLRjxv5afYEZbBXmbQ=="], - "oxlint": ["oxlint@1.88.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.88.0", "@oxlint/binding-android-arm64": "1.88.0", "@oxlint/binding-darwin-arm64": "1.88.0", "@oxlint/binding-darwin-x64": "1.88.0", "@oxlint/binding-freebsd-x64": "1.88.0", "@oxlint/binding-linux-arm-gnueabihf": "1.88.0", "@oxlint/binding-linux-arm-musleabihf": "1.88.0", "@oxlint/binding-linux-arm64-gnu": "1.88.0", "@oxlint/binding-linux-arm64-musl": "1.88.0", "@oxlint/binding-linux-ppc64-gnu": "1.88.0", "@oxlint/binding-linux-riscv64-gnu": "1.88.0", "@oxlint/binding-linux-riscv64-musl": "1.88.0", "@oxlint/binding-linux-s390x-gnu": "1.88.0", "@oxlint/binding-linux-x64-gnu": "1.88.0", "@oxlint/binding-linux-x64-musl": "1.88.0", "@oxlint/binding-openharmony-arm64": "1.88.0", "@oxlint/binding-win32-arm64-msvc": "1.88.0", "@oxlint/binding-win32-ia32-msvc": "1.88.0", "@oxlint/binding-win32-x64-msvc": "1.88.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2003", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-uIcFgw8BmqvFRGzH5+r7d2zJMEexwNSrEmM6WQNnGh3VkO0XYTEFoyxyNE6tjKMUib9Cue4XJA2DoWruO5D6aw=="], + "oxlint": ["oxlint@1.89.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.89.0", "@oxlint/binding-android-arm64": "1.89.0", "@oxlint/binding-darwin-arm64": "1.89.0", "@oxlint/binding-darwin-x64": "1.89.0", "@oxlint/binding-freebsd-x64": "1.89.0", "@oxlint/binding-linux-arm-gnueabihf": "1.89.0", "@oxlint/binding-linux-arm-musleabihf": "1.89.0", "@oxlint/binding-linux-arm64-gnu": "1.89.0", "@oxlint/binding-linux-arm64-musl": "1.89.0", "@oxlint/binding-linux-ppc64-gnu": "1.89.0", "@oxlint/binding-linux-riscv64-gnu": "1.89.0", "@oxlint/binding-linux-riscv64-musl": "1.89.0", "@oxlint/binding-linux-s390x-gnu": "1.89.0", "@oxlint/binding-linux-x64-gnu": "1.89.0", "@oxlint/binding-linux-x64-musl": "1.89.0", "@oxlint/binding-openharmony-arm64": "1.89.0", "@oxlint/binding-win32-arm64-msvc": "1.89.0", "@oxlint/binding-win32-ia32-msvc": "1.89.0", "@oxlint/binding-win32-x64-msvc": "1.89.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2003", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-a25hkfo61okGPvJz432fRIPoxlKtNnOVy9w4rzrmGgNm4iVTPwpSQlmdqNWnp6p9QyyPVfAZRgnf5XvSBZFk/A=="], "p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="], @@ -780,7 +784,7 @@ "picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="], - "postcss": ["postcss@8.5.29", "", { "dependencies": { "nanoid": "^3.3.19", "picocolors": "^1.1.1", "source-map-js": "^1.2.2" } }, "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ=="], + "postcss": ["postcss@8.5.32", "", { "dependencies": { "nanoid": "^3.3.20", "picocolors": "^1.1.1", "source-map-js": "^1.2.2" } }, "sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g=="], "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], @@ -820,7 +824,7 @@ "roamgate-web": ["roamgate-web@workspace:web"], - "rolldown": ["rolldown@1.2.12", "", { "dependencies": { "@oxc-project/types": "=0.152.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.12", "@rolldown/binding-android-arm64": "1.2.12", "@rolldown/binding-darwin-arm64": "1.2.12", "@rolldown/binding-darwin-x64": "1.2.12", "@rolldown/binding-freebsd-x64": "1.2.12", "@rolldown/binding-linux-arm-gnueabihf": "1.2.12", "@rolldown/binding-linux-arm64-gnu": "1.2.12", "@rolldown/binding-linux-arm64-musl": "1.2.12", "@rolldown/binding-linux-ppc64-gnu": "1.2.12", "@rolldown/binding-linux-s390x-gnu": "1.2.12", "@rolldown/binding-linux-x64-gnu": "1.2.12", "@rolldown/binding-linux-x64-musl": "1.2.12", "@rolldown/binding-openharmony-arm64": "1.2.12", "@rolldown/binding-win32-arm64-msvc": "1.2.12", "@rolldown/binding-win32-x64-msvc": "1.2.12" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ=="], + "rolldown": ["rolldown@1.2.15", "", { "dependencies": { "@oxc-project/types": "=0.155.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.15", "@rolldown/binding-android-arm64": "1.2.15", "@rolldown/binding-darwin-arm64": "1.2.15", "@rolldown/binding-darwin-x64": "1.2.15", "@rolldown/binding-freebsd-x64": "1.2.15", "@rolldown/binding-linux-arm-gnueabihf": "1.2.15", "@rolldown/binding-linux-arm64-gnu": "1.2.15", "@rolldown/binding-linux-arm64-musl": "1.2.15", "@rolldown/binding-linux-ppc64-gnu": "1.2.15", "@rolldown/binding-linux-s390x-gnu": "1.2.15", "@rolldown/binding-linux-x64-gnu": "1.2.15", "@rolldown/binding-linux-x64-musl": "1.2.15", "@rolldown/binding-openharmony-arm64": "1.2.15", "@rolldown/binding-win32-arm64-msvc": "1.2.15", "@rolldown/binding-win32-x64-msvc": "1.2.15" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g=="], "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], @@ -894,7 +898,7 @@ "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], - "vite": ["vite@8.3.4", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", "postcss": "^8.5.29", "rolldown": "~1.2.12", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ=="], + "vite": ["vite@8.3.5", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", "postcss": "^8.5.30", "rolldown": "~1.2.14", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.7.1 || ^0.8.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ=="], "w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="], diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index eaf1ad89..093f9481 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -29,7 +29,6 @@ missed changes but is not a replayable event log. `ConnectionManager` owns the shared profiles and one `ConnectionRuntime` per profile. Each runtime owns its transport, viewers, subscriptions, caches, and reconnect lifecycle. Disconnecting stops the runtime and SSH tunnel, never Herdr. - - Every downstream request carries a connection ID and runtime generation and holds a lease on a ready runtime. Replies, events, and frames carry the same identity; mismatched or stale identities fail without fallback. @@ -69,12 +68,12 @@ unknown fails closed. Each viewer crops its pane from the shared tab surface. Capabilities are negotiated per terminal socket and rechecked at dispatch: -| Capability | Contract | -| --- | --- | -| `pane.focus` | Required to attach; no legacy fallback without it. | -| `pane.scroll` | Gates explicit history scrolling. | -| `tab.create`, `workspace.create` | Gate creation from the existing endpoint. | -| `health_check` | Enables ping/pong. | +| Capability | Contract | +| -------------------------------- | -------------------------------------------------- | +| `pane.focus` | Required to attach; no legacy fallback without it. | +| `pane.scroll` | Gates explicit history scrolling. | +| `tab.create`, `workspace.create` | Gate creation from the existing endpoint. | +| `health_check` | Enables ping/pong. | `surface_delta` and `surface_reuse` are requested by default and stored per connection (`settings.terminal_transport`). Changing them makes viewers reattach @@ -88,7 +87,6 @@ shown. `terminal.attach` sends the pane's `cols`/`rows` and optionally the tab's `surface_cols`/`surface_rows`. Terminals cancel the UI's CSS zoom and scale the xterm font instead, so mouse and IME coordinates stay correct. - - Input waits for readiness, revalidates its lease, and is never replayed into a replacement terminal. - Endpoint keyboard input uses basic CSI-u for ambiguous modified keys @@ -236,7 +234,6 @@ The bridge runs one Pi Durable assistant service, independent of the selected connection and shared by all authenticated browsers through bridge-global `bridge.assistant.*` RPC and revisioned snapshot pushes. Reconnecting fetches state; sends are never replayed. - - **Tools** are defined in `server/src/assistant/tools.ts` and run through `callWorkspaceTool` against the turn's approved scope. Pi's built-in tools, extensions, skills, and project instructions are disabled, and workspace @@ -320,10 +317,10 @@ terminal frames are dropped. State-changing HTTP endpoints need authentication plus a marker header; the push and settings endpoints also reject cross-site requests: -| Endpoint | Required header | -| --- | --- | -| Updates | `x-roamgate-update: 1` (legacy `x-herdr-gui-update: 1` is accepted; the new header wins) | -| Web Push subscriptions | `x-roamgate-push: 1`, JSON body | -| Instance settings | `x-roamgate-settings`, JSON body | +| Endpoint | Required header | +| ---------------------- | ---------------------------------------------------------------------------------------- | +| Updates | `x-roamgate-update: 1` (legacy `x-herdr-gui-update: 1` is accepted; the new header wins) | +| Web Push subscriptions | `x-roamgate-push: 1`, JSON body | +| Instance settings | `x-roamgate-settings`, JSON body | Login bodies are limited to 16 KiB (`413`). Headers never replace login. diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index 8f0687fb..9f1facde 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -15,17 +15,16 @@ remote access, see the [tutorial](./TUTORIAL.md#networking). ### Herdr compatibility -| Herdr | Support | -| --- | --- | -| 0.7.0–0.8.2 (protocols 14–20) | Legacy terminal mode | -| 0.9.0 and 0.9.4 (protocol 22) | Endpoint terminal mode (recommended) | -| Protocol 21 and unknown versions | Rejected | +| Herdr | Support | +| -------------------------------- | ------------------------------------ | +| 0.7.0–0.8.2 (protocols 14–20) | Legacy terminal mode | +| 0.9.0 and 0.9.4 (protocol 22) | Endpoint terminal mode (recommended) | +| Protocol 21 and unknown versions | Rejected | Do not downgrade a live Herdr server. The [plugin](#herdr-plugin) and tab reordering need Herdr 0.7.2+. `ROAMGATE_DISABLE_ENDPOINT=1` forces legacy mode. Known limitations: - - Endpoint mode shares pane focus, layout, and terminal size between clients; only workspace/tab selection is per browser. Legacy mode shares everything and may take over the terminal from another client. @@ -63,11 +62,11 @@ with `Get-FileHash`, extract with `tar.exe`, and run `roamgate.exe`. Installer settings go on the `sh` side of the pipe (`curl ... | sh`): -| Installer setting | Example / behavior | -| --- | --- | -| Pin a version | `ROAMGATE_VERSION=X.Y.Z sh` (no `v`; empty means latest) | -| Install directory | `sudo env ROAMGATE_INSTALL_DIR=/usr/local/bin sh` | -| Release mirror | `ROAMGATE_RELEASE_BASE_URL= sh` | +| Installer setting | Example / behavior | +| ----------------- | -------------------------------------------------------------------- | +| Pin a version | `ROAMGATE_VERSION=X.Y.Z sh` (no `v`; empty means latest) | +| Install directory | `sudo env ROAMGATE_INSTALL_DIR=/usr/local/bin sh` | +| Release mirror | `ROAMGATE_RELEASE_BASE_URL= sh` | ## Managed Herdr setup @@ -106,7 +105,6 @@ or `%APPDATA%\roamgate\herdr-task.ps1`). **Herdr Studio / herdr-gui 0.6.2 and earlier cannot auto-update to Roamgate.** Their update channel no longer receives fixes. Service, data, and plugin migration needs Roamgate **0.7.1+**. - 1. Back up the executable, service definition, and config, keeping permissions: `~/.config/herdr-gui/`, plus `%APPDATA%\herdr-gui\` on Windows (Windows also keeps settings and connections in `~/.config/herdr-gui/`). @@ -194,39 +192,39 @@ Flags override environment variables, which override defaults. Release binaries ignore `.env` files: export variables, pass flags, or edit the service environment file. `roamgate --help` lists everything. -| Flag | Environment variable | Default | -| --- | --- | --- | -| `--host ` | `HOST` | `127.0.0.1` | -| `--port ` | `PORT` | `8787` | -| `--password ` | `ROAMGATE_PASSWORD` | Generated token | -| None | `ROAMGATE_PIN` | Disabled; see [PIN login](#optional-pin-login) | -| `--tls-cert ` | `ROAMGATE_TLS_CERT` | Disabled; PEM chain | -| `--tls-key ` | `ROAMGATE_TLS_KEY` | Disabled; PEM key | -| `--socket-path ` | `HERDR_SOCKET_PATH` | Default control socket | -| `--client-socket-path ` | `HERDR_CLIENT_SOCKET_PATH` | Default render socket | -| `--ssh-host ` | `HERDR_SSH_HOST` | Disabled; Linux/macOS only | -| `--session ` | `HERDR_SESSION` | Default session | -| `--public-dir ` | `PUBLIC_DIR` | Embedded assets | -| `--log-level ` | `ROAMGATE_LOG_LEVEL` | `info` | -| `--notification-source ` | `ROAMGATE_NOTIFICATION_SOURCE` | `herdr` | -| `--profile` | `ROAMGATE_PROFILE=1` | Disabled; see [profiling](#performance-profiling) | -| `--profile-duration ` | `ROAMGATE_PROFILE_DURATION` | `30` (1-300) | -| `--profile-dir ` | `ROAMGATE_PROFILE_DIR` | `/profiles` | -| `--open` | `OPEN_BROWSER=1` | Disabled | - -| Other environment variable | Purpose | -| --- | --- | -| `ROAMGATE_UPDATE_BASE_URL` | HTTPS update mirror directory | -| `ROAMGATE_DISABLE_UPDATE_CHECK=1` | Disable update checks | -| `ROAMGATE_RESTART_SUPERVISOR=0\|1` | Override supervisor detection | -| `ROAMGATE_DISABLE_ENDPOINT=1` | Force legacy terminal mode | -| `ROAMGATE_ALLOW_FILE_REVEAL=1` | Enable [host file reveal](#host-file-reveal) | -| `ROAMGATE_UPLOAD_MAX_BYTES` | Max terminal upload size (default 100 MiB) | -| `ROAMGATE_UPLOAD_RETENTION_HOURS` | Upload retention (default 24) | -| `ROAMGATE_SETTINGS_PATH` | GUI settings file (one per bridge) | -| `ROAMGATE_CONNECTIONS_PATH` | Connection profiles file | -| `ROAMGATE_ASSISTANT_DIR` | Ranger data directory | -| `ROAMGATE_WEB_PUSH_PATH` / `ROAMGATE_WEB_PUSH_SUBJECT` | [Web Push](#web-push-notifications) | +| Flag | Environment variable | Default | +| --------------------------------------- | ------------------------------ | ------------------------------------------------- | +| `--host ` | `HOST` | `127.0.0.1` | +| `--port ` | `PORT` | `8787` | +| `--password ` | `ROAMGATE_PASSWORD` | Generated token | +| None | `ROAMGATE_PIN` | Disabled; see [PIN login](#optional-pin-login) | +| `--tls-cert ` | `ROAMGATE_TLS_CERT` | Disabled; PEM chain | +| `--tls-key ` | `ROAMGATE_TLS_KEY` | Disabled; PEM key | +| `--socket-path ` | `HERDR_SOCKET_PATH` | Default control socket | +| `--client-socket-path ` | `HERDR_CLIENT_SOCKET_PATH` | Default render socket | +| `--ssh-host ` | `HERDR_SSH_HOST` | Disabled; Linux/macOS only | +| `--session ` | `HERDR_SESSION` | Default session | +| `--public-dir ` | `PUBLIC_DIR` | Embedded assets | +| `--log-level ` | `ROAMGATE_LOG_LEVEL` | `info` | +| `--notification-source ` | `ROAMGATE_NOTIFICATION_SOURCE` | `herdr` | +| `--profile` | `ROAMGATE_PROFILE=1` | Disabled; see [profiling](#performance-profiling) | +| `--profile-duration ` | `ROAMGATE_PROFILE_DURATION` | `30` (1-300) | +| `--profile-dir ` | `ROAMGATE_PROFILE_DIR` | `/profiles` | +| `--open` | `OPEN_BROWSER=1` | Disabled | + +| Other environment variable | Purpose | +| ------------------------------------------------------ | -------------------------------------------- | +| `ROAMGATE_UPDATE_BASE_URL` | HTTPS update mirror directory | +| `ROAMGATE_DISABLE_UPDATE_CHECK=1` | Disable update checks | +| `ROAMGATE_RESTART_SUPERVISOR=0\|1` | Override supervisor detection | +| `ROAMGATE_DISABLE_ENDPOINT=1` | Force legacy terminal mode | +| `ROAMGATE_ALLOW_FILE_REVEAL=1` | Enable [host file reveal](#host-file-reveal) | +| `ROAMGATE_UPLOAD_MAX_BYTES` | Max terminal upload size (default 100 MiB) | +| `ROAMGATE_UPLOAD_RETENTION_HOURS` | Upload retention (default 24) | +| `ROAMGATE_SETTINGS_PATH` | GUI settings file (one per bridge) | +| `ROAMGATE_CONNECTIONS_PATH` | Connection profiles file | +| `ROAMGATE_ASSISTANT_DIR` | Ranger data directory | +| `ROAMGATE_WEB_PUSH_PATH` / `ROAMGATE_WEB_PUSH_SUBJECT` | [Web Push](#web-push-notifications) | Legacy `HERDR_GUI_*` names still work; the `ROAMGATE_*` name wins, even when empty. @@ -290,7 +288,6 @@ certificates; services need absolute paths. Open **Ranger > Settings**, choose a **Provider**, and **Sign in** or **Enter API key**. Then pick a model, allow workspaces under **Workspace access**, and **Save settings**. - - **Shared Pi credentials** reuses Pi's `auth.json` and `models.json` for the bridge account instead of Ranger's own store. - **Custom models** add an OpenAI- or Anthropic-compatible endpoint; use a @@ -448,12 +445,12 @@ Configure hooks in `roamgate.json` at the repository root: } ``` -| Hook | When / working directory | -| --- | --- | -| `setup` | After create/open; new worktree | -| `opened` | After opening an existing worktree; that worktree | -| `teardown` | Before removal; target worktree | -| `removed` | After removal; source checkout | +| Hook | When / working directory | +| ---------- | ------------------------------------------------- | +| `setup` | After create/open; new worktree | +| `opened` | After opening an existing worktree; that worktree | +| `teardown` | Before removal; target worktree | +| `removed` | After removal; source checkout | Roamgate uses the first file found, in order: target `roamgate.json`, source `roamgate.json`, target `paseo.json`, source `paseo.json` (legacy). Files are @@ -461,11 +458,11 @@ never merged. `{}` disables fallback; invalid files report an error. Hooks run with `sh -c` on the connected (local or SSH) host. To migrate, rename `paseo.json` to `roamgate.json`. -| Variable | Value | -| --- | --- | -| `ROAMGATE_HOOK_EVENT` | `worktree.created`, `worktree.opened`, `worktree.before_remove`, or `worktree.removed` | -| `ROAMGATE_HOOK_CHECKOUT_PATH` | Target worktree path | -| `ROAMGATE_HOOK_SOURCE_CHECKOUT_PATH` | Source checkout, when known | +| Variable | Value | +| ------------------------------------ | -------------------------------------------------------------------------------------- | +| `ROAMGATE_HOOK_EVENT` | `worktree.created`, `worktree.opened`, `worktree.before_remove`, or `worktree.removed` | +| `ROAMGATE_HOOK_CHECKOUT_PATH` | Target worktree path | +| `ROAMGATE_HOOK_SOURCE_CHECKOUT_PATH` | Source checkout, when known | `HERDR_GUI_HOOK_*` and `PASEO_HOOK` / `PASEO_CHECKOUT_PATH` / `PASEO_SOURCE_CHECKOUT_PATH` are also set. @@ -477,21 +474,21 @@ failures do not undo completed steps. ## Run as a user service -| Command | Behavior | -| --- | --- | -| `roamgate service install` | Create or update the service and start it | -| `roamgate service install --force` | Replace a non-Roamgate definition | -| `roamgate service status` | Show status | -| `roamgate service restart` | Restart after config changes | -| `roamgate service reload` | Reload the definition, then restart | -| `roamgate service uninstall` | Stop and remove; keeps config and tokens | -| `roamgate service logs [-f]` | Show recent output | - -| Platform | Definition | -| --- | --- | -| Linux | `~/.config/systemd/user/roamgate.service` (`Restart=always`) | -| macOS | `~/Library/LaunchAgents/dev.roamgate.plist` (`KeepAlive`); logs in `~/Library/Logs/roamgate.*.log` | -| Windows | Scheduled task `dev.roamgate-` running `%APPDATA%\roamgate\roamgate-task.ps1` at login | +| Command | Behavior | +| ---------------------------------- | ----------------------------------------- | +| `roamgate service install` | Create or update the service and start it | +| `roamgate service install --force` | Replace a non-Roamgate definition | +| `roamgate service status` | Show status | +| `roamgate service restart` | Restart after config changes | +| `roamgate service reload` | Reload the definition, then restart | +| `roamgate service uninstall` | Stop and remove; keeps config and tokens | +| `roamgate service logs [-f]` | Show recent output | + +| Platform | Definition | +| -------- | -------------------------------------------------------------------------------------------------- | +| Linux | `~/.config/systemd/user/roamgate.service` (`Restart=always`) | +| macOS | `~/Library/LaunchAgents/dev.roamgate.plist` (`KeepAlive`); logs in `~/Library/Logs/roamgate.*.log` | +| Windows | Scheduled task `dev.roamgate-` running `%APPDATA%\roamgate\roamgate-task.ps1` at login | **New services listen on `0.0.0.0:8787`** with a generated token and print localhost/LAN login URLs. Settings live in `~/.config/roamgate/roamgate.env` @@ -515,7 +512,6 @@ curl -fsS http://127.0.0.1:8787/healthz URL logs in and sets a cookie. Cookies are signed by a separate secret in the same directory (`session-secret.json`, or `session-secret-.json` when `ROAMGATE_SETTINGS_PATH` is set). Protect both like passwords. - - `roamgate auth rotate` replaces the token, signs out every browser, and restarts the service. **Do not just delete `auth-token`**: after a migration, the legacy token is copied back on the next start. To rotate by hand, stop @@ -545,17 +541,17 @@ These commands act on the [user service](#run-as-a-user-service)'s config and data, not on the current shell's flags. They exit 0 on success, 1 on failure, and 2 on bad arguments; many accept `--json`. -| Command | Purpose | -| --- | --- | -| `roamgate doctor [--offline]` | Check config, credentials, TLS, service, network exposure, Herdr, connections, Web Push, and updates, with a fix for each problem. Prints no secrets. | -| `roamgate url [--qr] [--address ]` | Print login URLs; `--qr` shows a QR code for a phone (it contains the token); `--address` substitutes a VPN or Tailscale name. | -| `roamgate config show\|get\|set\|unset\|edit\|path` | Read or change `roamgate.env` atomically. `--restart` restarts the service; `KEY=-` reads a secret from stdin. | -| `roamgate auth show\|rotate\|revoke-sessions` | Show the login method, replace the token, or sign out every browser. | +| Command | Purpose | +| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `roamgate doctor [--offline]` | Check config, credentials, TLS, service, network exposure, Herdr, connections, Web Push, and updates, with a fix for each problem. Prints no secrets. | +| `roamgate url [--qr] [--address ]` | Print login URLs; `--qr` shows a QR code for a phone (it contains the token); `--address` substitutes a VPN or Tailscale name. | +| `roamgate config show\|get\|set\|unset\|edit\|path` | Read or change `roamgate.env` atomically. `--restart` restarts the service; `KEY=-` reads a secret from stdin. | +| `roamgate auth show\|rotate\|revoke-sessions` | Show the login method, replace the token, or sign out every browser. | | `roamgate connections list\|test\|add\|remove\|set-default` | Manage [connection profiles](#multiple-and-remote-herdr-connections). Edits are refused while the managed service runs unless `--restart` is given. Only the service config's address is checked, so stop other processes sharing the registry (such as a foreground run on another port) first. | -| `roamgate push test` | Send a test [Web Push](#web-push-notifications) notification. | -| `roamgate update [--check]` / `roamgate rollback` | Update to the latest release or restore `roamgate.previous` (Linux/macOS). | -| `roamgate service logs [-f] [-n ]` | Show service output (not available for Windows tasks). | -| `roamgate completion bash\|zsh\|fish` | Print a shell completion script. | +| `roamgate push test` | Send a test [Web Push](#web-push-notifications) notification. | +| `roamgate update [--check]` / `roamgate rollback` | Update to the latest release or restore `roamgate.previous` (Linux/macOS). | +| `roamgate service logs [-f] [-n ]` | Show service output (not available for Windows tasks). | +| `roamgate completion bash\|zsh\|fish` | Print a shell completion script. | ## Build a standalone executable @@ -568,11 +564,11 @@ Afterwards `bun run build` rebuilds. Cross-compile with `bun run build:` or package with `bun run package:`; `bun run build:all` builds every target: -| Targets | Architectures | -| --- | --- | -| `linux-x64`, `linux-arm64` | Linux x86-64 / ARM64 (glibc; musl is unsupported) | -| `darwin-x64`, `darwin-arm64` | macOS Intel / Apple Silicon | -| `windows-x64`, `windows-arm64` | Windows x86-64 / ARM64 | +| Targets | Architectures | +| ------------------------------ | ------------------------------------------------- | +| `linux-x64`, `linux-arm64` | Linux x86-64 / ARM64 (glibc; musl is unsupported) | +| `darwin-x64`, `darwin-arm64` | macOS Intel / Apple Silicon | +| `windows-x64`, `windows-arm64` | Windows x86-64 / ARM64 | `bun run clean` removes builds. Releases follow [AGENTS.md](../AGENTS.md#release-notes). @@ -584,12 +580,14 @@ its tar and run it to get readable stack traces. To build one locally, run ## Troubleshooting -| Symptom | Action | -| --- | --- | -| Not sure what is wrong | Run `roamgate doctor`. | -| Cannot connect to Herdr | Check that Herdr runs and both sockets exist; try `roamgate herdr setup`. | -| Another device cannot open the page | Check the bind address, token URL, firewall, and [private access setup](./TUTORIAL.md#networking). | -| SSH profile connects locally | Remove socket flags and `HERDR_SOCKET_PATH`/`HERDR_CLIENT_SOCKET_PATH`; they override tunnels. | -| Want the browser to open automatically | Use `roamgate --open` or `OPEN_BROWSER=1`. | +| Symptom | Action | +| -------------------------------------- | ---------------------------------------------------------------------------------------------- | +| Not sure what is wrong | Run `roamgate doctor`. | +| Cannot connect to Herdr | Check that Herdr runs and both sockets exist; try `roamgate herdr setup`. | +| Another device cannot open the page | Check the bind address, token URL, firewall, and [private access setup][private-access]. | +| SSH profile connects locally | Remove socket flags and `HERDR_SOCKET_PATH`/`HERDR_CLIENT_SOCKET_PATH`; they override tunnels. | +| Want the browser to open automatically | Use `roamgate --open` or `OPEN_BROWSER=1`. | For step-by-step diagnosis, see [the tutorial](./TUTORIAL.md#troubleshooting). + +[private-access]: ./TUTORIAL.md#networking diff --git a/docs/HISTORY.md b/docs/HISTORY.md index 645c19db..3952f4ce 100644 --- a/docs/HISTORY.md +++ b/docs/HISTORY.md @@ -51,10 +51,10 @@ Send `history_version: 2` to `agent_history.get`, optionally with the last accepted `cursor: { epoch, revision }`. Legacy callers get conversation-only `messages`. -| Mode | Response | -| --- | --- | -| `snapshot` | `entries` replaces the window. Returned for a missing session, an invalid or expired cursor, a replaced connection, eviction, or file replacement/truncation. | -| `delta` | `base_revision`, `upserts`, `removed`, and the full ID `order` only when membership or order changed. An unchanged reply keeps the revision with empty changes. | +| Mode | Response | +| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `snapshot` | `entries` replaces the window. Returned for a missing session, an invalid or expired cursor, a replaced connection, eviction, or file replacement/truncation. | +| `delta` | `base_revision`, `upserts`, `removed`, and the full ID `order` only when membership or order changed. An unchanged reply keeps the revision with empty changes. | The window holds the latest **200 conversation entries** (including errors); associated tool calls do not count. Raw and ATIF exports stay complete. Entry IDs diff --git a/docs/SCREENSHOTS.md b/docs/SCREENSHOTS.md index 60816c28..a9b589bd 100644 --- a/docs/SCREENSHOTS.md +++ b/docs/SCREENSHOTS.md @@ -28,10 +28,10 @@ mkdir -p /tmp/roamgate-demo git clone --branch main https://github.com/powerfooI/northstar-demo.git /tmp/roamgate-demo/northstar ``` -| Scene | Initial state | Use | -| --- | --- | --- | -| Baseline | Clean `main` clone | Give a real agent the task from the README. | -| Review | `main` plus the example implementation as unstaged changes | Files, diff, preview, annotation, and PR shots. | +| Scene | Initial state | Use | +| -------- | ---------------------------------------------------------- | ----------------------------------------------- | +| Baseline | Clean `main` clone | Give a real agent the task from the README. | +| Review | `main` plus the example implementation as unstaged changes | Files, diff, preview, annotation, and PR shots. | For the review scene, run this **only in the fresh clone**: @@ -152,17 +152,17 @@ For the annotation shot, add `Keep the status filter combined with title search. Clearing both filters should restore all six tasks.` on new line 27 of `tasks.ts`, pin the review panel, and leave the comment as a draft. -| Asset stem | Layout and selection | Ready condition | -| --- | --- | --- | -| `roamgate-desktop-changes` | Nested sidebar; Pi in Implementation above Checks; Inspector right (~55%); Working tree, `tasks.ts` | 3+ workspaces and 2+ agent rows visible; Pi running; five files loaded; tests finished. | -| `roamgate-desktop-files` | Nested sidebar; expanded Inspector; Files, `index.html` Preview scrolled to Release checklist | Styles loaded; heading, filters, and all six cards visible. | -| `roamgate-desktop-annotations` | Nested sidebar; `tasks.ts` unified diff with the draft | Correct line and full comment visible. | -| `roamgate-desktop-history` | Agent History, all types enabled | The real task and its test tool call visible. | -| `roamgate-desktop-ranger` | Ranger pinned beside Northstar | A real answer with sources, using only demo workspaces. | -| `roamgate-mobile-changes` | Mobile Changes, Working tree, `tasks.ts` | Key changed function readable. | -| `roamgate-mobile-terminal` | Mobile Checks pane with Composer and shortcuts | Real Git status and test summary visible. | -| `roamgate-mobile-files` | Mobile Files, `index.html` Preview | Heading, filters, and first card readable. | -| `roamgate-mobile-ranger` | Mobile Ranger chat | The same real conversation with input and model controls. | +| Asset stem | Layout and selection | Ready condition | +| ------------------------------ | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| `roamgate-desktop-changes` | Nested sidebar; Pi in Implementation above Checks; Inspector right (~55%); Working tree, `tasks.ts` | 3+ workspaces and 2+ agent rows visible; Pi running; five files loaded; tests finished. | +| `roamgate-desktop-files` | Nested sidebar; expanded Inspector; Files, `index.html` Preview scrolled to Release checklist | Styles loaded; heading, filters, and all six cards visible. | +| `roamgate-desktop-annotations` | Nested sidebar; `tasks.ts` unified diff with the draft | Correct line and full comment visible. | +| `roamgate-desktop-history` | Agent History, all types enabled | The real task and its test tool call visible. | +| `roamgate-desktop-ranger` | Ranger pinned beside Northstar | A real answer with sources, using only demo workspaces. | +| `roamgate-mobile-changes` | Mobile Changes, Working tree, `tasks.ts` | Key changed function readable. | +| `roamgate-mobile-terminal` | Mobile Checks pane with Composer and shortcuts | Real Git status and test summary visible. | +| `roamgate-mobile-files` | Mobile Files, `index.html` Preview | Heading, filters, and first card readable. | +| `roamgate-mobile-ranger` | Mobile Ranger chat | The same real conversation with input and model controls. | For Ranger, connect a model in the capture environment, allow only the demo workspaces, and ask it to summarize Northstar's uncommitted changes and test diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md index 932f2cb5..c782ea8e 100644 --- a/docs/TUTORIAL.md +++ b/docs/TUTORIAL.md @@ -19,7 +19,6 @@ Browser / PWA -> Roamgate (HTTP + WebSocket) -> Herdr -> shell / agent Herdr owns the terminals, Roamgate is the browser UI, and agents remain CLIs. Roamgate does not provide models or install agents. Closing the browser leaves terminals running; sleeping or shutting down the host stops them. - 1. Start Herdr with a trusted project open ([herdr.dev](https://herdr.dev)), or run `roamgate herdr setup` after [installing Roamgate](./DEPLOYMENT.md#install-a-release). 2. Run `roamgate` (`roamgate.exe` on Windows) on the same computer and leave it @@ -38,12 +37,12 @@ first. ![Desktop workspace with project navigation, terminals, and changed files](./images/roamgate-desktop-changes.png) -| Object | Meaning | -| --- | --- | +| Object | Meaning | +| --------- | -------------------------------------------------- | | Workspace | A working environment, usually a project directory | -| Tab | A layout within a workspace | -| Pane | One terminal in a tab | -| Worktree | A separate Git checkout directory and branch | +| Tab | A layout within a workspace | +| Pane | One terminal in a tab | +| Worktree | A separate Git checkout directory and branch | **Splitting panes does not isolate files.** Use worktrees for parallel edits. @@ -122,18 +121,17 @@ Save wanted results before removing a worktree; a Set up [Tailscale + Serve](#tailscale) first: `127.0.0.1` on a phone means the phone itself. - 1. Open Roamgate's HTTPS URL on your phone, log in, and select your pane. 2. Use the floating shortcuts for Ctrl and arrow keys, and open Changes to review the diff. 3. Adjust **Configuration > Appearance** scale or terminal font size if needed, then install the PWA: -| Browser | Install action | -| --- | --- | +| Browser | Install action | +| ------------------ | -------------------------- | | iPhone/iPad Safari | Share > Add to Home Screen | -| macOS Safari 17+ | File > Add to Dock | -| Chrome/Edge | Browser menu > Install app | +| macOS Safari 17+ | File > Add to Dock | +| Chrome/Edge | Browser menu > Install app | **You are done when:** the home-screen icon opens your project. Install your Roamgate URL, not this tutorial site. @@ -149,12 +147,12 @@ share the URL like a read-only link. -| Goal | Route | -| --- | --- | -| Regular phone/computer access | [Tailscale + Serve](#tailscale) | -| Local Roamgate controlling a remote Herdr | [SSH profile](#ssh) (Linux/macOS bridge) | -| Another computer using a remote Roamgate | [SSH port forwarding](#ssh) | -| Temporary access between your own computers | [Tailcat](#tailcat) | +| Goal | Route | +| ------------------------------------------- | ---------------------------------------- | +| Regular phone/computer access | [Tailscale + Serve](#tailscale) | +| Local Roamgate controlling a remote Herdr | [SSH profile](#ssh) (Linux/macOS bridge) | +| Another computer using a remote Roamgate | [SSH port forwarding](#ssh) | +| Temporary access between your own computers | [Tailcat](#tailcat) | None of these need router port forwarding. @@ -173,7 +171,6 @@ None of these need router port forwarding. Tailscale connects your devices privately; Serve gives Roamgate an HTTPS address reachable only inside your tailnet. - 1. Install [Tailscale](https://tailscale.com/download) on both devices, join the same tailnet, and check `tailscale status`. 2. [Restrict access](https://tailscale.com/docs/features/access-control) to the @@ -219,7 +216,6 @@ loopback. **Option A: local Roamgate, remote Herdr** (needs a Linux/macOS bridge; the remote host can be Unix or Windows). - 1. Make sure plain `ssh` works non-interactively, put keys, ports, and jump hosts in `~/.ssh/config` (for example alias `workbox`), and start Herdr remotely. 2. In Roamgate's connection selector, add an SSH profile with destination @@ -253,7 +249,6 @@ host's credential. Ctrl+C stops forwarding. Tailscale tool that connects two computers without a tailnet account. It has no access policies and this project has not verified it end to end. Use Tailscale for phones. - 1. Run Roamgate at `127.0.0.1:8787` on your work computer and check it locally. 2. In another terminal there, run: @@ -280,7 +275,6 @@ address as a secret: it contains a key. See Tailcat's Check in order: - 1. On the Roamgate host, run `curl -fsS http://127.0.0.1:8787/healthz` (`curl.exe` in PowerShell). If refused, check the process, port, or service. 2. Open the page locally. If terminals fail, check Herdr, the selected @@ -290,14 +284,14 @@ Check in order: 4. If typing fails, check the selected pane and that your proxy supports WebSockets. -| Symptom | First check | -| --- | --- | -| Phone cannot reach `localhost` | Use Serve's HTTPS hostname. | -| Password set but no login page | Try a private window; an existing cookie or token URL may have logged you in. | -| Login returns `429` | Wait for `Retry-After`; clients behind one proxy share [login limits](../SECURITY.md#trust-model). | -| Address already in use | A service or plugin may already run Roamgate. | -| SSH history is empty | Check [session lookup limits](../FEATURES.md#agent-awareness-and-session-inspection). | -| Clipboard or PWA restricted | Use trusted HTTPS without certificate warnings. | +| Symptom | First check | +| ------------------------------ | -------------------------------------------------------------------------------------------------- | +| Phone cannot reach `localhost` | Use Serve's HTTPS hostname. | +| Password set but no login page | Try a private window; an existing cookie or token URL may have logged you in. | +| Login returns `429` | Wait for `Retry-After`; clients behind one proxy share [login limits](../SECURITY.md#trust-model). | +| Address already in use | A service or plugin may already run Roamgate. | +| SSH history is empty | Check [session lookup limits](../FEATURES.md#agent-awareness-and-session-inspection). | +| Clipboard or PWA restricted | Use trusted HTTPS without certificate warnings. | `roamgate doctor` checks most of this automatically. See [Deployment](./DEPLOYMENT.md) for tokens, services, and debug logs. Never diff --git a/package.json b/package.json index 17f375c9..d246d387 100644 --- a/package.json +++ b/package.json @@ -66,14 +66,14 @@ "start:server": "bun run --filter roamgate-server start" }, "devDependencies": { - "@biomejs/biome": "2.5.15", + "@biomejs/biome": "2.6.2", "@types/jsdom": "^30.0.0", "@types/proper-lockfile": "4.1.4", "@types/web-push": "^3.6.4", "bun-types": "1.4.4", "happy-dom": "^21.0.4", "jsdom": "^30.1.3", - "oxlint": "1.88.0", + "oxlint": "1.89.0", "typescript": "^7.0.2" }, "overrides": { diff --git a/scripts/bench-terminal/README.md b/scripts/bench-terminal/README.md index a820532d..a8b40624 100644 --- a/scripts/bench-terminal/README.md +++ b/scripts/bench-terminal/README.md @@ -44,7 +44,6 @@ applications, scheduler placement and thermal changes remain uncontrolled. Input is a **predecoded, trusted synthetic cell grid**, not captured terminal contents. No live sockets, private sessions, service restarts or user settings are involved. Timed work is: - 1. Crop a pane (Bun imports production `cropFrame`). 2. Serialize the content-identity fields used by `onSurface`, including cells. 3. Encode a full ANSI repaint (Bun imports production `frameToAnsi`). @@ -74,7 +73,6 @@ Sparse frames still traverse and repaint the grid in both implementations. ## Results and interpretation Each fresh output directory contains: - - `metadata.json`: compiler/runtime/host identity, settings and source/fixture hashes. - `verification.json` and `fixtures.json`: byte-equivalence evidence and exact inputs. - `samples.jsonl`: one raw record per process, preserved as runs complete. diff --git a/web/package.json b/web/package.json index 4d83d0d9..8fdf7da6 100644 --- a/web/package.json +++ b/web/package.json @@ -62,6 +62,6 @@ "@types/react": "^19.3.0", "@types/react-dom": "^19.3.0", "@vitejs/plugin-react": "^6.1.2", - "vite": "^8.3.4" + "vite": "^8.3.5" } }