Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d29b1b8
feat: bootstrap v2
cloud-on-prem Nov 30, 2025
8fc5816
feat: more scaffolding; discover goose binary
cloud-on-prem Nov 30, 2025
6b30b3b
feat: foundation ready
cloud-on-prem Nov 30, 2025
5e8806b
feat: add AGENTS.md
cloud-on-prem Nov 30, 2025
d6b8048
feat: add foundataions for chat ui
cloud-on-prem Nov 30, 2025
0a572fd
feat: add ui components - still not hooked up to server but they render
cloud-on-prem Nov 30, 2025
a6e0517
feat: markdown formatting and theming
cloud-on-prem Nov 30, 2025
b4ec034
feat: use mock messages to simulate agent response
cloud-on-prem Nov 30, 2025
fa7cca8
feat: polish the ui and add accessibility
cloud-on-prem Nov 30, 2025
3518062
feat: wire it up to real acp endpoints
cloud-on-prem Nov 30, 2025
31444fa
fix: npm registry
cloud-on-prem Nov 30, 2025
07c57f1
feat: support acp session/load for loading prev sesions
cloud-on-prem Dec 2, 2025
b356bd5
feat: add support for checking min version
cloud-on-prem Dec 19, 2025
64cd125
feat: add selection context features with @file picker
cloud-on-prem Dec 20, 2025
9ced54c
fix: ensure tab works when selecting files
cloud-on-prem Dec 20, 2025
4119865
fix: top bar is easier to navigate
cloud-on-prem Dec 20, 2025
b475fe2
feat: wip
cloud-on-prem Dec 20, 2025
dcdc519
fix: ensure dirs are relative in file chips
cloud-on-prem Dec 20, 2025
a4d0507
feat: ensure file content acp responses are formatted as collapsible
cloud-on-prem Dec 20, 2025
74d2302
fix: styling issue with top bar
cloud-on-prem Dec 20, 2025
7a96826
feat: clean up the new chat screen and the buttons
cloud-on-prem Dec 20, 2025
3c653b9
feat: make the top bar better
cloud-on-prem Dec 20, 2025
028c268
chore: agents.md
cloud-on-prem Dec 21, 2025
6c2709f
feat(test): add tests across the codebase
cloud-on-prem Dec 21, 2025
8bd7cbc
chore(ci): update gh actions to use bun
cloud-on-prem Dec 21, 2025
ae1e4c4
docs: update README
cloud-on-prem Dec 21, 2025
a181e61
docs: use a newer screenshot
cloud-on-prem Dec 21, 2025
425c003
fix: ensure all files are searched for
cloud-on-prem Dec 21, 2025
4d1cd82
feat: add python and rust file type icons
cloud-on-prem Dec 21, 2025
3a261ac
refactor: rm old one-off tests
cloud-on-prem Dec 21, 2025
8068274
chore: add bunfig
cloud-on-prem Dec 21, 2025
671a78f
chore: rm old unused files
cloud-on-prem Dec 21, 2025
2f755ef
feat: add biome
cloud-on-prem Dec 21, 2025
d95458d
refactor: fix all lints and format according to biome
cloud-on-prem Dec 21, 2025
f87b7b8
docs: add .rp1 context
cloud-on-prem Dec 21, 2025
bbf5cb3
docs: fix all dev docs
cloud-on-prem Dec 21, 2025
0e3aabc
fix(ci): ensure release config is correct
cloud-on-prem Dec 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 21 additions & 30 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,25 @@ jobs:
token: ${{ secrets.RELEASE_PLEASE_PAT }}

# The following steps only run if a release was created
- name: Setup Node.js
- name: Setup Bun
if: steps.release.outputs.release_created
uses: actions/setup-node@v4
uses: oven-sh/setup-bun@v2
with:
node-version: '20'
cache: 'npm'
bun-version: latest

- name: Install Dependencies (Root)
- name: Setup Node.js (for vsce)
if: steps.release.outputs.release_created
run: npm ci --no-fund --no-audit
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install Dependencies (Webview)
- name: Install Dependencies
if: steps.release.outputs.release_created
run: npm ci --no-fund --no-audit --prefix webview-ui
run: bun install --frozen-lockfile

- name: Build Extension and Webview
- name: Build Extension
if: steps.release.outputs.release_created
run: npm run compile
run: bun run build

- name: Package Extension
if: steps.release.outputs.release_created
Expand Down Expand Up @@ -101,29 +102,19 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
node-version: '20'
cache: 'npm'
bun-version: latest

- name: Install Dependencies
run: |
npm ci --no-fund --no-audit
npm ci --no-fund --no-audit --prefix webview-ui

- name: Lint
run: |
npm run lint
run: bun install --frozen-lockfile

- name: Install Xvfb
run: |
sudo apt-get update
sudo apt-get install -y xvfb
- name: Lint & Format Check
run: bun run ci

- name: Run Tests with Xvfb
run: |
xvfb-run -a sh -c "npm run test:all && npm run test:package"
- name: Run Tests
run: bun test

- name: Compile extension and webview
run: npm run compile # This includes build:webview
- name: Build
run: bun run build
38 changes: 13 additions & 25 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,21 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
# Checks out the code from the PR branch
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
node-version: '20'
cache: 'npm'
bun-version: latest

- name: Install Dependencies
run: |
npm ci --no-fund --no-audit
npm ci --no-fund --no-audit --prefix webview-ui

- name: Lint
run: |
npm run lint

- name: Install Xvfb
run: |
sudo apt-get update
sudo apt-get install -y xvfb

- name: Run Tests with Xvfb
run: |
# Run standard tests and the package activation test
xvfb-run -a sh -c "npm run test:all && npm run test:package"

- name: Compile extension and webview
run: npm run compile # This includes build:webview
run: bun install --frozen-lockfile

- name: Lint & Format Check
run: bun run ci

- name: Run Tests
run: bun test

- name: Build
run: bun run build
21 changes: 10 additions & 11 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,12 @@ out/
dist/
*.vsix
.vscode-test/
*.js
*.js.map

# Exclude these specific files from being ignored
!webview-ui/postcss.config.js
!webview-ui/tailwind.config.js

# Binary executables
bin/
bin/goosed
bin/goose
bin/*.exe

# Webview build assets
webview-ui/dist/
webview-ui/node_modules/

# TypeScript
*.tsbuildinfo

Expand All @@ -52,3 +42,12 @@ Thumbs.db
debug*.log
coverage/
eslint-report.*

# Bun lockfile (if using bun)
bun.lockb

# https://rp1.run knowledge files
!.rp1/
.rp1/*
!.rp1/context/
!.rp1/context/**
2 changes: 1 addition & 1 deletion .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -1 +1 @@
npx --no -- commitlint --edit $1
bunx --bun commitlint --edit $1
3 changes: 2 additions & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
npm run compile
bun run build
bun run ci
187 changes: 187 additions & 0 deletions .rp1/context/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# System Architecture

**Project**: VS Code Goose
**Architecture Pattern**: Bridge/Adapter with Message-Driven Communication
**Last Updated**: 2025-12-21

## High-Level Architecture

```mermaid
graph TB
subgraph VSCode["VS Code"]
UI["VS Code UI<br/>(Commands, Activity Bar)"]
ExtHost["Extension Host<br/>(Node.js)"]
Webview["Chat Webview<br/>(React/iframe)"]
end

subgraph Extension["Extension Host Components"]
ExtMain["extension.ts<br/>(Main Entry)"]
SubMgr["SubprocessManager<br/>(Process Lifecycle)"]
JsonRpc["JsonRpcClient<br/>(ACP Protocol)"]
SessMgr["SessionManager<br/>(Session State)"]
WebProv["WebviewProvider<br/>(UI Bridge)"]
VC["VersionChecker"]
FSS["FileSearchService"]
end

subgraph External["External"]
goose["goose Process<br/>(AI Daemon)"]
GS["globalState"]
end

UI -->|commands| ExtMain
ExtMain --> SubMgr
ExtMain --> SessMgr
ExtMain --> WebProv
SubMgr -->|spawn/stdin/stdout| goose
SubMgr --> JsonRpc
JsonRpc -->|JSON-RPC 2.0| goose
goose -->|stream notifications| JsonRpc
WebProv <-->|postMessage| Webview
SessMgr --> JsonRpc
SessMgr -->|persist| GS
VC -->|goose --version| goose
FSS -->|workspace.findFiles| UI
```

## Architectural Patterns

### Bridge/Adapter Architecture

The extension is deliberately minimal - a thin UI layer connecting VS Code webview to Goose backend via Agent Communication Protocol (ACP). No business logic in the extension itself.

### Layered Architecture

Four distinct layers with unidirectional dependencies:

1. **Webview** (presentation) - React components
2. **Extension** (orchestration) - VS Code integration
3. **ACP Client** (protocol) - JSON-RPC handling
4. **Goose subprocess** - External process communication

### Message-Driven Communication

All communication between webview and extension uses a strongly-typed message passing system with 24 message types, factory functions, and type guards.

### Gated Activation

Multi-stage activation gate: binary discovery → version validation → subprocess spawn. Each stage can block activation with appropriate user messaging.

## Component Architecture

### Extension Host Layer

**Location**: `src/extension/`
**Components**:

- `extension.ts` - Orchestrates activation, ACP session init, wires components
- `sessionManager.ts` - Session lifecycle, history replay, ACP coordination
- `webviewProvider.ts` - Webview lifecycle, message queue, ready sync
- `subprocessManager.ts` - Spawns goose binary, manages lifecycle events
- `jsonRpcClient.ts` - JSON-RPC 2.0 client with ndjson framing
- `versionChecker.ts` - Binary version validation (>= 1.16.0)
- `fileSearchService.ts` - Workspace file discovery for @ picker
- `commands.ts` - VS Code command registration (showLogs, restart, sendSelectionToChat)

### Webview Layer

**Location**: `src/webview/`
**Components**:

- `App.tsx` - Root component with status, session and chat state
- `bridge.ts` - postMessage abstraction for extension communication
- `ChatView.tsx` - Chat container with keyboard navigation
- `InputArea.tsx` - Input with chips, file picker integration
- `useChat.ts` - Reducer-based chat state management
- `useContextChips.ts` - Chip state management
- `useFilePicker.ts` - @ mention detection and search

### Shared Layer

**Location**: `src/shared/`
**Components**:

- `messages.ts` - 24 WebviewMessage types, payloads, factories, guards
- `types.ts` - ProcessStatus, ChatMessage, MessageContext
- `errors.ts` - GooseError discriminated union, factory functions
- `contextTypes.ts` - ContextChip, FileSearchResult
- `fileReferenceParser.ts` - Parse file references from markdown

## Key Data Flows

### User Chat Message Flow

```mermaid
sequenceDiagram
participant User
participant Webview
participant Extension
participant JsonRpc
participant goose

User->>Webview: Type message + Enter
Webview->>Extension: SEND_MESSAGE
Extension->>Extension: Build ACP content blocks
Extension->>JsonRpc: session/prompt request
JsonRpc->>goose: JSON-RPC via stdin

loop Streaming Response
goose-->>JsonRpc: session/update notification
JsonRpc-->>Extension: onNotification callback
Extension-->>Webview: STREAM_TOKEN
Webview-->>User: Render markdown chunk
end

Extension-->>Webview: GENERATION_COMPLETE
```

### Send Selection to Goose (Cmd+Shift+G)

1. User selects code and presses Cmd+Shift+G
2. `registerContextCommands` handler triggered
3. `goose.chatView.focus` reveals panel
4. `waitForReady()` ensures webview initialized
5. `createAddContextChipMessage()` sent with file/range
6. Webview displays chip and awaits user prompt

### File Search (@ Picker)

1. User types @ in chat input
2. `detectAtTrigger()` scans backwards for @ at word boundary
3. Webview sends FILE_SEARCH message with query
4. `fileSearchService.search()` uses `vscode.workspace.findFiles()`
5. Results sorted by recentScore
6. SEARCH_RESULTS message sent back
7. FilePicker dropdown displayed

### Version-Gated Activation

1. `discoverBinary()` locates goose binary
2. `checkVersion()` spawns `goose --version`
3. `meetsMinimumVersion()` validates >= 1.16.0
4. If version fails: `updateVersionStatus()` blocks UI
5. If version passes: spawn subprocess

## Integration Points

### Goose ACP Subprocess

- **Protocol**: JSON-RPC 2.0 over stdin/stdout (ndjson framing)
- **Methods**: `initialize`, `session/new`, `session/load`, `session/prompt`
- **Notifications**: `session/cancel`, `session/update`
- **Version Requirement**: >= 1.16.0

### VS Code APIs

- **Workspace**: `findFiles()` for @ picker
- **Commands**: `goose.showLogs`, `goose.restart`, `goose.sendSelectionToChat`
- **Keybindings**: Cmd+Shift+G for sendSelectionToChat
- **Context Menus**: editor/context menu integration

## Deployment

- **Distribution**: VS Code Marketplace via VSIX
- **Build**: Bun bundler, Webpack, Tailwind CSS v4
- **Linting**: Biome for formatting and linting
- **Webview Options**: `retainContextWhenHidden: true`
- **Version Gate**: Checks goose >= 1.16.0 before subprocess spawn
Loading