Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5a7dd2f
feat(sidebar): webview shell + header buttons + cleanup (#674)
jeonghun-jj-lee Aug 31, 2026
24b1cde
feat(sidebar): project tree with lazy file browsing (#675)
jeonghun-jj-lee Aug 31, 2026
2e250e3
feat(sidebar): context menus and file operations (#676)
jeonghun-jj-lee Aug 31, 2026
9cd432c
feat(sidebar): session-aware project highlighting (#677)
jeonghun-jj-lee Aug 31, 2026
84f0f22
fix(test): update golden fixture for project type field
jeonghun-jj-lee Aug 31, 2026
4b3b7c2
feat(sidebar): file icons, context menu fix, drag-drop, git colors, a…
jeonghun-jj-lee Aug 31, 2026
65bbfb2
fix(creds): downgrade model/provider mismatch to soft warning
jeonghun-jj-lee Aug 31, 2026
8b1cc27
fix(sidebar): use VS Code icon theme, fix file/folder indent alignment
jeonghun-jj-lee Sep 1, 2026
058dbb1
feat(sidebar): reactive git status coloring via extension subscription
jeonghun-jj-lee Sep 1, 2026
50a5ed9
feat(sidebar): inline editing for rename, new file, new folder (#673)
jeonghun-jj-lee Sep 1, 2026
ca2489b
fix(sidebar): re-insert inline edit temp row after children arrive
jeonghun-jj-lee Sep 1, 2026
32b8552
fix(sidebar): inline edit on never-opened folder — suppress blur duri…
jeonghun-jj-lee Sep 1, 2026
2f84d21
feat(sidebar): drag-drop onto file rows and children gap resolves to …
jeonghun-jj-lee Sep 1, 2026
628550f
feat(sidebar): VS Code-style drag image pill replaces default browser…
jeonghun-jj-lee Sep 1, 2026
4f3bdbf
fix(sidebar): push git-status after every roots re-render to prevent …
jeonghun-jj-lee Sep 1, 2026
5c22f46
feat(sidebar): animated section expand/collapse (RESEARCH, DEV, FLEET)
jeonghun-jj-lee Sep 1, 2026
5c6b864
feat(sidebar): outline chevrons with CSS rotation, replacing filled t…
jeonghun-jj-lee Sep 1, 2026
6bb2ee6
fix(sidebar): smooth section animation — height transition working wi…
jeonghun-jj-lee Sep 1, 2026
12d30c3
fix(sidebar): replace CSS transition with rAF animation for section t…
jeonghun-jj-lee Sep 1, 2026
733e17f
fix(sidebar): inline CSS height transitions for section toggle (VS Co…
jeonghun-jj-lee Sep 1, 2026
2882420
Replace flex section layout with pixel-positioned sections (#697)
jeonghun-jj-lee Sep 1, 2026
25ea793
Bottom-align collapsed sections in pixel layout (#697)
jeonghun-jj-lee Sep 1, 2026
bbbb3e0
Fix sash positioning in pixel layout (#697)
jeonghun-jj-lee Sep 1, 2026
0f96920
Fix section overflow after sash drag + toggle (#697)
jeonghun-jj-lee Sep 1, 2026
a987a9f
Clear all sectionSizes on toggle so re-expanded sections get equal sh…
jeonghun-jj-lee Sep 1, 2026
860970b
Wire '+ New Project' button: save dialog → mkdir → session (#698)
jeonghun-jj-lee Sep 1, 2026
4db5720
Delete confirms before trashing, removes workspace root folders (#673)
jeonghun-jj-lee Sep 1, 2026
444a277
Remove status pill from sidebar project names (#673)
jeonghun-jj-lee Sep 1, 2026
9f5f02d
isModelConfigured recognizes the model field, not just provider entries
jeonghun-jj-lee Sep 1, 2026
67974c8
Workspace-backed project selector below the composer (#663)
jeonghun-jj-lee Sep 1, 2026
26006f2
feat: sidebar focus on project selection (#663)
jeonghun-jj-lee Sep 1, 2026
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
10 changes: 9 additions & 1 deletion packages/app-bundle/overlay/packages/app/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import "@/index.css"
import * as Sentry from "@sentry/solid"
import { requestComputeConnect } from "@/components/amicode-defaults-capsule"
import { adoptWorkspaceProjects } from "@/utils/amicode-workspace-projects"
import { I18nProvider } from "@opencode-ai/ui/context"
import { DialogProvider } from "@opencode-ai/ui/context/dialog"
import { FileComponentProvider } from "@opencode-ai/ui/context/file"
Expand Down Expand Up @@ -425,7 +426,14 @@ function AmicodeThemeBridge() {
if (d.kind === "open-bug-report" || d.kind === "close-bug-report") {
bugDockController.handleBridgeMessage(d)
return
} if (d.kind !== "theme") return
}
// amicode#663: workspace-projects push from the extension host — the
// project selector below the composer reads from this signal.
if (d.kind === "workspace-projects") {
adoptWorkspaceProjects((d as { projects?: unknown[] }).projects as Parameters<typeof adoptWorkspaceProjects>[0])
return
}
if (d.kind !== "theme") return
if (d.colorScheme === "light" || d.colorScheme === "dark") theme.setColorScheme(d.colorScheme)
}
window.addEventListener("message", onMsg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { type Accessor, createMemo } from "solid-js"
import type { PromptInputControls } from "@/components/prompt-input/contracts"
import type { PromptProjectControls } from "@/components/prompt-project-selector"
import { hiddenProjectWorktree } from "@/utils/amicode-hidden-project"
import { workspaceProjects, requestAddWorkspaceProject } from "@/utils/amicode-workspace-projects"
import { useDirectoryPicker } from "@/components/directory-picker"
import { useGlobal } from "@/context/global"
import { useLayout } from "@/context/layout"
Expand Down Expand Up @@ -74,6 +75,20 @@ export function createPromptProjectControls() {
const projectServer = () => serverSDK().server
const projectServerCtx = createMemo(() => global.ensureServerCtx(projectServer()))
const projects = createMemo(() => {
// amicode#663: when the extension host pushes workspace folder data, use
// it as the canonical project list (type-grouped, workspace-backed). The
// signal is empty until the first push — standalone opencode never pushes,
// so the fallback below handles it.
const wsProjects = workspaceProjects()
if (wsProjects.length > 0) {
return wsProjects.map((p) => ({
name: p.name,
worktree: p.worktree,
type: p.type as "research" | "dev",
status: p.status,
}))
}
// Fallback: opencode-native project discovery (standalone / no extension).
const list =
server.list.length <= 1
? search.draftId
Expand Down Expand Up @@ -118,6 +133,16 @@ export function createPromptProjectControls() {
}

const addProject = (title: string, serverKey?: string) => {
// amicode#663: when workspace-backed (running inside the amicode
// extension webview), delegate folder picking to the extension host —
// it shows VS Code's native showOpenDialog and adds the result as a
// workspace folder. The workspace-change listener then pushes an
// updated project list via postMessage.
if (hiddenProjectWorktree()) {
requestAddWorkspaceProject()
return
}
// Standalone opencode: use the server's directory picker.
const conn = serverKey ? server.list.find((conn) => ServerConnection.key(conn) === serverKey) : projectServer()
if (!conn) return
pickDirectory({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// amicode#663: workspace-projects signal — the chat iframe's project selector
// reads from this reactive store. The extension host pushes the list via
// postMessage on app-ready and on workspace-folder change; the bridge handler
// below adopts it into a SolidJS signal.
//
// Pattern follows amicode-hidden-project.ts — module-scoped signal, no
// component tree dependency, importable from any context.

import { createSignal } from "solid-js"

export interface WorkspaceProject {
name: string
worktree: string
type: "research" | "dev"
status?: string
}

const [projects, setProjects] = createSignal<WorkspaceProject[]>([])

/** Adopt a workspace-projects push from the extension host. Replaces the
* entire list (the extension always sends the full set). */
export function adoptWorkspaceProjects(data: WorkspaceProject[]): void {
setProjects(Array.isArray(data) ? data : [])
}

/** Reactive accessor — returns the current workspace project list. */
export function workspaceProjects(): WorkspaceProject[] {
return projects()
}

/** Post an add-workspace-project request to the extension host. The extension
* shows a native folder picker, adds the selected folder to the VS Code
* workspace, and pushes an updated workspace-projects message back. */
export function requestAddWorkspaceProject(): void {
window.parent.postMessage(
{ source: "amicode", kind: "add-workspace-project" },
"*",
)
}
12 changes: 12 additions & 0 deletions packages/extension/esbuild.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,18 @@ const targets = [
minify: false,
logLevel: "info",
},
// Sidebar webview bundle — workspace panel (#673)
{
entryPoints: ["src/sidebar_webview.ts"],
bundle: true,
platform: "browser",
target: "es2022",
format: "iife",
outfile: "dist/sidebar_webview.js",
sourcemap: true,
minify: false,
logLevel: "info",
},
];

if (watch) {
Expand Down
136 changes: 11 additions & 125 deletions packages/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"activationEvents": [
"onCommand:amicode.openChat",
"onCommand:amicode.newChat",
"onCommand:amicode.newProject",
"onCommand:amicode.chatDeck",
"onView:amicode.workspace",
"onStartupFinished"
Expand All @@ -50,7 +51,7 @@
"activitybar": [
{
"id": "amicode",
"title": "Amicode",
"title": "AMICODE",
"icon": "media/amico_reduced.svg"
}
]
Expand All @@ -59,17 +60,11 @@
"amicode": [
{
"id": "amicode.workspace",
"name": "Workspace",
"type": "tree"
"name": "AMICODE",
"type": "webview"
}
]
},
"viewsWelcome": [
{
"view": "amicode.workspace",
"contents": "No folders in this workspace.\n[Add Folder](command:amicode.workspace.addFolder)"
}
],
"commands": [
{
"command": "amicode.onboarding.open",
Expand All @@ -88,6 +83,11 @@
"title": "Amicode: New Chat (Side by Side)",
"icon": "$(add)"
},
{
"command": "amicode.newProject",
"title": "Amicode: New Project",
"icon": "$(new-folder)"
},
{
"command": "amicode.chatDeck",
"title": "Amicode: Open Chat Deck (Panes in One Tab)",
Expand Down Expand Up @@ -175,53 +175,6 @@
"title": "Amicode: Update canonical opencode (check + adopt)",
"category": "Amicode"
},
{
"command": "amicode.workspace.newFile",
"title": "New File",
"icon": "$(new-file)"
},
{
"command": "amicode.workspace.newFolder",
"title": "New Folder",
"icon": "$(new-folder)"
},
{
"command": "amicode.workspace.rename",
"title": "Rename"
},
{
"command": "amicode.workspace.delete",
"title": "Delete"
},
{
"command": "amicode.workspace.copyPath",
"title": "Copy Path"
},
{
"command": "amicode.workspace.copyRelativePath",
"title": "Copy Relative Path"
},
{
"command": "amicode.workspace.revealInOS",
"title": "Reveal in Finder"
},
{
"command": "amicode.workspace.openInTerminal",
"title": "Open in Terminal"
},
{
"command": "amicode.workspace.openToSide",
"title": "Open to the Side"
},
{
"command": "amicode.workspace.removeFromWorkspace",
"title": "Remove Folder from Workspace"
},
{
"command": "amicode.workspace.addFolder",
"title": "Add Folder to Workspace",
"icon": "$(root-folder-opened)"
},
{
"command": "amicode.restartHub",
"title": "Amicode: Restart Hub Server (fleet)"
Expand Down Expand Up @@ -406,75 +359,8 @@
"group": "navigation"
}
],
"view/title": [
{
"command": "amicode.workspace.newFile",
"when": "view == amicode.workspace",
"group": "navigation"
},
{
"command": "amicode.workspace.newFolder",
"when": "view == amicode.workspace",
"group": "navigation"
},
{
"command": "amicode.workspace.addFolder",
"when": "view == amicode.workspace",
"group": "navigation"
}
],
"view/item/context": [
{
"command": "amicode.workspace.newFile",
"when": "view == amicode.workspace",
"group": "2_workspace@1"
},
{
"command": "amicode.workspace.newFolder",
"when": "view == amicode.workspace",
"group": "2_workspace@2"
},
{
"command": "amicode.workspace.openToSide",
"when": "view == amicode.workspace && viewItem == workspaceFile",
"group": "3_open@1"
},
{
"command": "amicode.workspace.rename",
"when": "view == amicode.workspace",
"group": "7_modification@1"
},
{
"command": "amicode.workspace.delete",
"when": "view == amicode.workspace",
"group": "7_modification@2"
},
{
"command": "amicode.workspace.copyPath",
"when": "view == amicode.workspace",
"group": "9_cutcopypaste@1"
},
{
"command": "amicode.workspace.copyRelativePath",
"when": "view == amicode.workspace",
"group": "9_cutcopypaste@2"
},
{
"command": "amicode.workspace.revealInOS",
"when": "view == amicode.workspace",
"group": "9_cutcopypaste@3"
},
{
"command": "amicode.workspace.openInTerminal",
"when": "view == amicode.workspace && viewItem =~ /workspaceFolder|workspaceRoot/",
"group": "9_cutcopypaste@4"
},
{
"command": "amicode.workspace.removeFromWorkspace",
"when": "view == amicode.workspace && viewItem == workspaceRoot",
"group": "10_workspace@1"
}
]
"view/title": [],
"view/item/context": []
}
},
"scripts": {
Expand Down
Loading
Loading