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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules/
dist/
out/
.vsix-stage/
.vscode-test/
*.vsix
.DS_Store
Expand All @@ -9,3 +10,5 @@ Thumbs.db
.env.*
!.env.example
coverage/
asked.txt
shielded.txt
36 changes: 27 additions & 9 deletions .vscodeignore
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
# Source and build tooling (rebuilt by esbuild, never shipped).
src/
test/
.vscode/
.github/
docs/
gui/
docs/
scripts/
esbuild.js
eslint.config.js

# Dev config.
.vscode/
.github/
.kilo/
.freebuff/
.vscode-test.mjs
eslint.config.mjs
prettier.config.js
vitest.config.ts
tsconfig.json
tsconfig.gui.json
tsconfig.test.json

# Repo/dev artifacts that must never ship in a VSIX.
.gitignore
.vscodeignore
.vsix-stage/
pnpm-lock.yaml
AI_PROJECT_CONTEXT.md
CONTRIBUTING.md
asked.txt
shielded.txt

# Maps are dev-only; the compiled bundles stay.
**/*.map
**/*.test.ts
node_modules/@cursor/sdk/dist/cjs/**
node_modules/@cursor/sdk/dist/esm/**
node_modules/@cursor/sdk/dist/bundled/**
node_modules/@cursor/sdk/README.md
node_modules/@cursor/sdk/LICENSE.md

# NOTE: runtime dependencies (node_modules, incl. @cursor/sdk and its
# @cursor/sdk-<platform> native packages) are staged and packaged by
# scripts/stage-vsix.js — see that file before changing anything here.
35 changes: 27 additions & 8 deletions AI_PROJECT_CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

- **What it is:** Spider (package id `codevia-cursor`, VS Code publisher
`codevia`) is a VS Code extension providing an AI coding-agent experience
inside the sidebar as a webview view (`codeviaCursor.agent`).
as an **editor-area tab** (Codex / Cline / Kilo style, `spider.openAgent`
/ `spider.openAgentEditor`) plus the same agent in the activity-bar
sidebar webview view (`codeviaCursor.agent`).
- **Primary purpose:** a coding agent that chats, calls workspace tools
(read/write/edit/list/search/move/delete files, run commands), and streams
its progress — modeled on Continue / Roo Code / Cline UX.
Expand All @@ -27,7 +29,10 @@
Settings IA (sidebar sections), Spider watermark empty state** (2026-09-27),
**chat-UI redesign: Copy/Delete message actions with stable transcript ids,
collapsible tool/command output, live command stdout/stderr streaming**
(2026-09-28).
(2026-09-28), **editor-area Spider tab (Codex/Cline/Kilo style) sharing
one AgentWebviewHost with the sidebar, clickable Spider logo header
button + status-bar item that opens/focuses the tab, History as a real
editor tab** (2026-09-29).
- **Identity note:** internal identifiers (`codeviaCursor`, `CodeviaSession`,
storage keys `codeviaCursor.*`, package name `codevia-cursor`) intentionally
keep the old name. Only user-facing strings say "Spider". Do NOT rename
Expand All @@ -38,9 +43,10 @@
Actual implemented flow (verified against source):

```
User (webview GUI, gui/src/main.ts)
User (webview GUI, gui/src/main.ts — sidebar view OR editor tab)
↓ GuiToHost messages (bridge.ts postMessage)
AgentViewProvider (src/webview/agentViewProvider.ts)
AgentWebviewHost (src/webview/agentWebviewHost.ts) ← every surface; OPEN_HISTORY /
OPEN_AGENT_EDITOR (clickable Spider logo) handled here
↓
MessageRouter (src/webview/messageRouter.ts) ← validates every message shape
↓
Expand Down Expand Up @@ -570,10 +576,23 @@ views, batches UI syncs (`scheduleUiSync` → one rAF per event burst).
`GuiToHost` messages (SEND_PROMPT, NEW_SESSION, SELECT_SESSION,
GET_TRANSCRIPT, CONNECT_*, SELECT_*_MODEL, APPROVE/DENY_PERMISSION,
SET_RUNTIME_AUTO_APPROVE, GET/SET_PERMISSION_RULE, GET_EXTENSION_INFO, ...)
→ `AgentViewProvider.onDidReceiveMessage` → `MessageRouter.handleMessage`
(result forwarded back if `shouldForwardResult`). Runtime events flow
continuously: `RuntimeManager.onDidPublishEvent` → `toRuntimeExtensionMessage`
→ `webview.postMessage`.
→ `AgentWebviewHost.attach` (sidebar view or editor tab) →
`MessageRouter.handleMessage` (result forwarded back if
`shouldForwardResult`). Runtime events flow continuously:
`RuntimeManager.onDidPublishEvent` → `toRuntimeExtensionMessage` →
`AgentWebviewHost.postMessage` → **every attached surface** (sidebar and
editor tab stay in sync, side by side).

**Editor-area tab (2026-09-29):** `AgentEditorPanel` is a
`WebviewPanel` (`spider.agentEditor`, tab title "Spider Agent",
`panel.iconPath` = the spider mark) hosting the SAME GUI through the
shared host. The clickable Spider logo in the webview header
(`brand-btn` → `OPEN_AGENT_EDITOR`) and the status-bar Spider item both
call `AgentEditorPanel.createOrShow` (singleton; reveals when open).
`AgentViewProvider` (sidebar) only attaches its webview to the same
host — it owns no webview logic. History is a second `WebviewPanel`
(`HistoryPanel`); picking a conversation loads the transcript in the
editor tab (or focuses the sidebar when no tab is open).

### Execution UI
Tool/command lifecycle rendered as exec boxes: `tool_requested → running →
Expand Down
10 changes: 8 additions & 2 deletions esbuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ const extensionOptions = {
logLevel: "info",
};

/**
* Two webview clients share one stylesheet: the sidebar Agent view (`main.ts`)
* and the History editor tab (`history.ts`). Multiple entry points require an
* outdir; both land next to the copied HTML/CSS in dist/gui.
*/
const guiOptions = {
entryPoints: ["gui/src/main.ts"],
entryPoints: ["gui/src/main.ts", "gui/src/history.ts"],
bundle: true,
platform: "browser",
target: "es2022",
format: "iife",
outfile: "dist/gui/main.js",
outdir: "dist/gui",
sourcemap: true,
logLevel: "info",
};
Expand All @@ -31,6 +36,7 @@ function copyGuiAssets() {
const outDir = path.join("dist", "gui");
fs.mkdirSync(outDir, { recursive: true });
fs.copyFileSync(path.join("gui", "index.html"), path.join(outDir, "index.html"));
fs.copyFileSync(path.join("gui", "history.html"), path.join(outDir, "history.html"));
fs.copyFileSync(path.join("gui", "styles", "main.css"), path.join(outDir, "main.css"));
// Spider mark for the empty-chat watermark (single asset, no duplication).
fs.copyFileSync(path.join("assets", "spider-icon.png"), path.join(outDir, "spider-icon.png"));
Expand Down
33 changes: 33 additions & 0 deletions gui/history.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; style-src {{cspSource}}; script-src 'nonce-{{nonce}}'; img-src {{cspSource}} data:;">
<title>Spider History</title>
<link rel="stylesheet" href="{{styleUri}}">
</head>

<body class="history-body">
<div id="history-app">
<header class="history-header">
<h1>Conversation history</h1>
<p class="hint">Select a conversation to open it in the sidebar. The preview is read-only.</p>
</header>
<div class="history-layout">
<div class="history-list-pane">
<div id="history-list" class="history-list" role="list"></div>
<p id="history-empty" class="history-empty" hidden>No conversations yet. Start one from the Spider sidebar.</p>
</div>
<section class="history-preview" aria-label="Conversation preview">
<div id="history-preview-body" class="history-preview-body"></div>
<p id="history-preview-empty" class="history-empty">Select a conversation to preview it.</p>
</section>
</div>
</div>
<script nonce="{{nonce}}" src="{{scriptUri}}"></script>
</body>

</html>
53 changes: 44 additions & 9 deletions gui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,77 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; style-src {{cspSource}}; script-src 'nonce-{{nonce}}'; img-src {{cspSource}} data:;">

<title>Spider</title>
<link rel="stylesheet" href="{{styleUri}}">
</head>

<body>
<div id="app">

<header class="app-header">
<div class="brand">Spider</div>
<div id="runtime-pill" class="runtime-pill">Cursor</div>
<button id="settings-btn" class="icon-btn" type="button" aria-label="Open Spider settings"
title="Settings">Settings</button>
<button id="brand-btn" class="brand" type="button" aria-label="Open Spider agent editor" title="Open Spider agent">
<img class="brand-logo" src="{{logoUri}}" alt="Spider logo">
<span class="brand-name">Spider</span>
</button>

<div id="runtime-pill" class="runtime-pill">
Cursor
</div>

<div class="header-actions">

<button id="history-btn" class="icon-btn" type="button" aria-label="Open conversation history" title="History">
History
</button>

<button id="new-session-btn" class="icon-btn icon-btn-plus" type="button" aria-label="Start a new conversation"
title="New conversation">
+
</button>

<button id="settings-btn" class="icon-btn" type="button" aria-label="Open Spider settings" title="Settings">
Settings
</button>

</div>
</header>

<main id="chat-view" class="view">
<div id="setup-banner" class="setup-banner" hidden></div>
<div id="session-bar" class="session-bar"></div>

<div id="message-list" class="message-list"></div>

<div id="composer" class="composer"></div>
</main>

<section id="settings-view" class="view settings-view" hidden>

<div class="settings-heading">
<div>
<h1>Settings</h1>
<p class="hint">Choose how Spider runs your coding agent.</p>
<p class="hint">
Choose how Spider runs your coding agent.
</p>
</div>
<button id="settings-back" class="btn btn-ghost" type="button">Back to chat</button>

<button id="settings-back" class="btn btn-ghost" type="button">
Back to chat
</button>
</div>

<div id="provider-settings"></div>

<p id="auth-feedback" class="feedback" hidden></p>

</section>
</div>
<script nonce="{{nonce}}" src="{{scriptUri}}" data-spider-logo="{{logoUri}}"></script>

</div> <script nonce="{{nonce}}" src="{{scriptUri}}" data-spider-logo="{{logoUri}}"></script>
<meta name="spider-logo" content="{{logoUri}}">
<meta name="spider-show-settings" content="{{showSettings}}">
</body>

</html>
34 changes: 0 additions & 34 deletions gui/src/components/sessionBar.ts

This file was deleted.

Loading
Loading