Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/vscode-extension.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: vscode-extension

# Code-level checks for the VS Code extension (extensions/vscode/) —
# type-check, lint, unit tests, and a production bundle. Kept out of
# test.yml's Go/Python matrix: the extension is its own npm ecosystem and
# only needs to run when its files change.

on:
push:
branches: [main, dev]
paths:
- 'extensions/vscode/**'
- '.github/workflows/vscode-extension.yml'
pull_request:
branches: [main, dev]
paths:
- 'extensions/vscode/**'
- '.github/workflows/vscode-extension.yml'

concurrency:
group: vscode-extension-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
build-and-test:
name: lint + test + build
runs-on: ubuntu-latest
defaults:
run:
working-directory: extensions/vscode
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
with:
node-version: '20'
cache: npm
cache-dependency-path: extensions/vscode/package-lock.json

- name: install
run: npm ci

- name: type-check
run: npm run check-types

- name: lint
run: npm run lint

- name: test
run: npm test

- name: bundle (production)
run: node esbuild.js --production
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

## [Unreleased]

### VS Code extension
- New `extensions/vscode/`: a zero-runtime-dependency VS Code client for the proxy HTTP API (#35) — chat sidebar with streamed turns, tool chips, and plan checklists; interactive permission flow (allow once / allow for session / deny, with pre-decision diff previews for `write_file` / `edit_file` / `ast_edit`); native diff review of applied changes; status bar from `/ready`; workspace-mismatch warning; service token in SecretStorage.
### CPU-torch images actually CPU-only again (2026-07-20)
- The lens and v3-service Dockerfiles pre-install torch from the CPU-only
index, but their pin (2.12.1) had drifted behind requirements.txt
Expand Down
2 changes: 1 addition & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,6 @@ A minimal client needs four things (plus one header):
3. **POST `/cancel`** with `{session_id}` when the user wants to abort.
4. *(Optional)* **GET `/events`** in a background goroutine/thread for the global typed-envelope feed if you want a pipeline-progress sidebar.

The TUI ([atlas tui](CLI.md)) is a Go reference implementation (~3 kloc) — its `model.go` shows how to handle every event type, and `panes.go` shows one approach to rendering them. Browse `tui/` in the repo for a complete worked example.
The TUI ([atlas tui](CLI.md)) is a Go reference implementation (~3 kloc) — its `model.go` shows how to handle every event type, and `panes.go` shows one approach to rendering them. Browse `tui/` in the repo for a complete worked example. The VS Code extension (`extensions/vscode/`) is a TypeScript client built exactly to this section's surface, with unit-tested SSE parsing and permission handling.

This document and the TUI source are the canonical reference for building a client.
1 change: 1 addition & 0 deletions docs/MAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ the documentation lives. For component internals see
|---|---|---|
| `proxy/` | Go agent loop: `/v1/agent`, grammar-constrained tool calls, gates, V3 routing, OpenAI passthrough | [proxy/README.md](../proxy/README.md) |
| `tui/` | Bubbletea terminal client — the canonical chat front-end, consumes proxy SSE streams | — |
| `extensions/` | IDE clients over the proxy HTTP API; `extensions/vscode/` is the VS Code extension (chat sidebar, permission flow, diff review) | [extensions/vscode/README.md](../extensions/vscode/README.md) |
| `atlas/` | Python CLI package: `atlas` subcommand dispatch (init, doctor, tier, model, onboard, lens, asa, publish, bench, compose, tui, upgrade, rollback, diagnostics, artifact, config) and pipe-mode REPL | — |
| `v3-service/` | Python HTTP wrapper for the V3 generation pipeline and the structural call-graph engine | — |
| `geometric-lens/` | Scoring (C(x)/G(x)), RAG indexing and retrieval, confidence routing, pattern cache, ASA control-vector build | [asa_calibration/README.md](../geometric-lens/asa_calibration/README.md) |
Expand Down
9 changes: 9 additions & 0 deletions extensions/vscode/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules/
dist/
out/
.vscode-test/
*.vsix

# Root .gitignore ignores these repo-wide; the extension needs them committed.
!package-lock.json
!.vscode/
5 changes: 5 additions & 0 deletions extensions/vscode/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": ["dbaeumer.vscode-eslint", "connor4312.esbuild-problem-matchers"]
}
21 changes: 21 additions & 0 deletions extensions/vscode/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
}
]
}
13 changes: 13 additions & 0 deletions extensions/vscode/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false, // set this to true to hide the "out" folder with the compiled JS files
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
},
"search.exclude": {
"out": true, // set this to false to include "out" folder in search results
"dist": true // set this to false to include "dist" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"js/ts.tsc.autoDetect": "off"
}
45 changes: 45 additions & 0 deletions extensions/vscode/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
"version": "2.0.0",
"tasks": [
{
"label": "watch",
"dependsOn": [
"npm: watch:tsc",
"npm: watch:esbuild"
],
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "watch:esbuild",
"group": "build",
"problemMatcher": "$esbuild-watch",
"isBackground": true,
"label": "npm: watch:esbuild",
"presentation": {
"group": "watch",
"reveal": "never"
}
},
{
"type": "npm",
"script": "watch:tsc",
"group": "build",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"label": "npm: watch:tsc",
"presentation": {
"group": "watch",
"reveal": "never"
}
}
]
}
12 changes: 12 additions & 0 deletions extensions/vscode/.vscodeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.vscode/**
.vscode-test/**
out/**
test/**
node_modules/**
src/**
.gitignore
esbuild.js
**/tsconfig.json
**/eslint.config.mjs
**/*.map
**/*.ts
64 changes: 64 additions & 0 deletions extensions/vscode/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# ATLAS VS Code Extension

A VS Code client for the [ATLAS](https://github.com/itigges22/ATLAS) agent proxy — a thin UI layer wrapping `atlas-proxy`'s agent loop (chat, tool calls, permission gating, diffs) with no agent logic in the extension itself.

**Status: Work in progress.** Tracking [issue #35](https://github.com/itigges22/ATLAS/issues/35). Chat, permission flow, diff review, status bar, and the workspace-mismatch warning are implemented.

## Diff review

* Permission prompts for `write_file` / `edit_file` / `ast_edit` offer **View Diff** — a side-by-side preview predicted client-side from the local file (`ast_edit` results carry no content, so its predictions use a best-effort selector splice and are labeled approximate).
* After a successful edit, the tool chip offers **View change** — the exact applied diff (pre-call snapshot vs on-disk), which also compensates for approximate `ast_edit` predictions. Falls back to `edit_file`'s server-computed `diff_preview` when the file is not readable in this workspace.
* `move_file` / `delete_file` / `run_command` prompt without a diff.

## How it works

The extension is a thin SSE client over the proxy HTTP API (see `docs/API.md`):

* `POST /v1/agent` — streams a turn (text tokens, tool calls/results, permission requests) as server-sent events
* `POST /v1/permission` — answers permission requests raised mid-turn
* `POST /cancel` — cancels the in-flight turn
* `GET /ready` — status bar connectivity polling

The TUI (`tui/`) is the reference client; the extension mirrors its session conventions (client-minted `session_id` per turn, `session_allowed_tools` re-sent each turn, cancel = abort + best-effort `POST /cancel`).

## Settings

* `atlas.proxyUrl` — base URL of the ATLAS proxy server (default `http://localhost:8090`)
* `atlas.serviceToken` — dev-override bearer token (prefer the `ATLAS: Set Service Token` command, which stores it in SecretStorage instead of plaintext settings)
* `atlas.permissionMode` — `default` / `accept-edits` / `yolo`
* `atlas.statusBar.enabled`, `atlas.statusBar.pollIntervalSec` — status bar connectivity polling

## Commands

* `ATLAS: Open Chat`
* `ATLAS: Cancel Current Turn`
* `ATLAS: Set Service Token`
* `ATLAS: New Conversation`

## Known limitations

* The proxy applies tool calls to its own mounted workspace (`ATLAS_WORKSPACE_DIR`). If the VS Code workspace folder is not the same directory, edits land elsewhere — the extension detects the mismatch heuristically and warns, but cannot verify the proxy's mount (no endpoint exposes it yet).

## Development

```bash
npm install
npm run compile # type-check + lint + bundle
npm test # vitest unit tests
```

Press `F5` in VS Code to launch an Extension Development Host for testing against a live proxy (`atlas up`).

## Layout

```
src/
├── extension.ts # activate(), command registration
├── client/ # proxy HTTP/SSE client (atlasClient, sse parser, API types)
├── session/ # turn lifecycle (session_id, history, permission flow)
├── ui/ # chat webview, status bar, diff provider
├── workspace/ # workspace-mismatch heuristic
└── util/ # error-envelope mapping
media/ # webview assets
test/ # vitest unit tests + mock proxy fixture
```
56 changes: 56 additions & 0 deletions extensions/vscode/esbuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const esbuild = require("esbuild");

const production = process.argv.includes('--production');
const watch = process.argv.includes('--watch');

/**
* @type {import('esbuild').Plugin}
*/
const esbuildProblemMatcherPlugin = {
name: 'esbuild-problem-matcher',

setup(build) {
build.onStart(() => {
console.log('[watch] build started');
});
build.onEnd((result) => {
result.errors.forEach(({ text, location }) => {
console.error(`✘ [ERROR] ${text}`);
console.error(` ${location.file}:${location.line}:${location.column}:`);
});
console.log('[watch] build finished');
});
},
};

async function main() {
const ctx = await esbuild.context({
entryPoints: [
'src/extension.ts'
],
bundle: true,
format: 'cjs',
minify: production,
sourcemap: !production,
sourcesContent: false,
platform: 'node',
outfile: 'dist/extension.js',
external: ['vscode'],
logLevel: 'silent',
plugins: [
/* add to the end of plugins array */
esbuildProblemMatcherPlugin,
],
});
if (watch) {
await ctx.watch();
} else {
await ctx.rebuild();
await ctx.dispose();
}
}

main().catch(e => {
console.error(e);
process.exit(1);
});
27 changes: 27 additions & 0 deletions extensions/vscode/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import typescriptEslint from "typescript-eslint";

export default [{
files: ["**/*.ts"],
}, {
plugins: {
"@typescript-eslint": typescriptEslint.plugin,
},

languageOptions: {
parser: typescriptEslint.parser,
ecmaVersion: 2022,
sourceType: "module",
},

rules: {
"@typescript-eslint/naming-convention": ["warn", {
selector: "import",
format: ["camelCase", "PascalCase"],
}],

curly: "warn",
eqeqeq: "warn",
"no-throw-literal": "warn",
semi: "warn",
},
}];
1 change: 1 addition & 0 deletions extensions/vscode/media/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Placeholder — webview assets (chat.js, chat.css, icon) land with the chat view commit.
6 changes: 6 additions & 0 deletions extensions/vscode/media/ATLAS.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading