Changeset 0.19.1 (#83)

This commit is contained in:
2026-03-01 00:28:58 +00:00
parent 748f49bedd
commit 37a9b1a68e
12 changed files with 580 additions and 22 deletions

194
docs/DESIGN-0.19.1.md Normal file
View File

@@ -0,0 +1,194 @@
# v0.19.1 — Active Projects, Project System Prompt, Project Detail Panel
**Status:** Implementation
**Depends on:** v0.19.0 Projects/Workspaces
---
## Overview
Three tightly-scoped improvements that make projects genuinely usable
for daily workflow rather than just organizational containers:
1. **Active Project** — one-click project activation so new chats
auto-assign without drag-drop.
2. **Project System Prompt** — per-project instructions injected into
every chat within the project at completion time.
3. **Project Detail Panel** — side panel UI for managing a project's
system prompt, KB bindings, and notes.
---
## 1. Active Project
### State
| Location | Key | Type |
|----------|-----|------|
| `App.activeProjectId` | runtime | `string \| null` |
| `localStorage` | `cs-active-project` | `string \| null` |
### Behavior
- Click project header's **pin icon** (or "Set as active" in ⋯ menu)
to activate.
- Active project gets a visual indicator: left accent border + subtle
background tint using the project's color.
- Creating a new chat (via `sendMessage` when `!App.currentChatId`)
auto-calls `addChannelToProject(activeProjectId, newChannelId)` and
sets `chat.projectId` client-side.
- Only one project can be active at a time. Clicking the pin on an
already-active project deactivates it.
- Active state persists across page reloads via `localStorage`.
- If the active project is deleted, `activeProjectId` is cleared.
### Files Changed
| File | Change |
|------|--------|
| `src/js/app.js` | Add `activeProjectId: null` to App, restore from localStorage on init |
| `src/js/projects-ui.js` | `setActiveProject(id)`, `clearActiveProject()`, menu items, pin icon |
| `src/js/chat.js` | Auto-assign in `sendMessage` after channel creation |
| `src/js/ui-core.js` | `.active` class on project group in `renderChatList` |
| `src/css/styles.css` | `.project-group.active` styling |
---
## 2. Project System Prompt
### Injection Order
```
1. Admin system prompt (global policy — no opt-out)
2. Persona OR channel prompt (role/character definition)
3. ▸ PROJECT system prompt (project-specific context) ← NEW
4. KB hint (available knowledge bases)
5. Memory hint (user facts from v0.18.0)
6. Summary / conversation (message history)
```
The project prompt sits between the role definition and the KB hint.
This lets a persona define "you are a coding assistant" while the
project adds "this project is the React dashboard for client X."
### Backend Flow (completion.go)
In `loadConversation`, after the persona/channel system prompt block:
```go
// ── Project system prompt (v0.19.1) ──
if h.stores.Projects != nil {
projID, _ := h.stores.Projects.GetProjectIDForChannel(ctx, channelID)
if projID != "" {
proj, err := h.stores.Projects.GetByID(ctx, projID)
if err == nil {
if sp, ok := proj.Settings["system_prompt"].(string); ok && sp != "" {
messages = append(messages, providers.Message{
Role: "system",
Content: sp,
})
}
}
}
}
```
### Storage
Uses existing `projects.settings` JSONB column. No migration needed.
```json
{
"system_prompt": "You are helping build the Chat Switchboard project..."
}
```
### Files Changed
| File | Change |
|------|--------|
| `server/handlers/completion.go` | Inject project system prompt in `loadConversation` |
---
## 3. Project Detail Panel
### Registration
Follows the same `PanelRegistry.register()` pattern as notes and
preview panels. Registered during app init via `_registerProjectPanel()`.
### Panel Layout
```
┌─────────────────────────────┐
│ Project: <name> [✕] │ ← header (editable name)
├─────────────────────────────┤
│ System Prompt │
│ ┌─────────────────────────┐ │
│ │ textarea (auto-resize) │ │
│ └─────────────────────────┘ │
│ [Save] │
├─────────────────────────────┤
│ Knowledge Bases [+] │
│ ┌─────────────────────────┐ │
│ │ • KB Alpha [✕] │ │
│ │ • KB Beta [✕] │ │
│ └─────────────────────────┘ │
│ (empty: "No KBs bound") │
├─────────────────────────────┤
│ Notes │
│ ┌─────────────────────────┐ │
│ │ • Meeting notes [✕] │ │
│ │ • Design spec [✕] │ │
│ └─────────────────────────┘ │
│ (empty: "No notes") │
├─────────────────────────────┤
│ Color [●] │
│ Archived [ ] │
└─────────────────────────────┘
```
### Interactions
- **System prompt:** Textarea with debounced save (1s) or explicit Save
button. Writes to `PUT /projects/:id` with
`settings: { system_prompt: "..." }`.
- **KB add:** [+] opens a dropdown of available KBs (from
`GET /knowledge-bases`), filtered to exclude already-bound ones.
Calls `POST /projects/:id/knowledge-bases`.
- **KB remove:** [✕] calls `DELETE /projects/:id/knowledge-bases/:kbId`.
- **Notes:** Read-only list with [✕] to unbind. Notes are auto-associated
from channel creation (v0.19.0).
- **Color:** Reuses the invisible color picker pattern from
`setProjectColor()`.
- **Open trigger:** Click project name in sidebar header, or
"Project details" in ⋯ menu.
### Files Changed
| File | Change |
|------|--------|
| `src/index.html` | Add `#sidePanelProject` div inside `#sidePanelBody` |
| `src/js/projects-ui.js` | `openProjectPanel(id)`, `_registerProjectPanel()`, panel rendering, KB/note management |
| `src/js/app.js` | Call `_registerProjectPanel()` in init |
| `src/css/styles.css` | `.project-panel-*` styles |
---
## Files Summary
| File | Phase | Type |
|------|-------|------|
| `server/handlers/completion.go` | 2 | Modified |
| `src/js/app.js` | 1,3 | Modified |
| `src/js/projects-ui.js` | 1,3 | Modified |
| `src/js/chat.js` | 1 | Modified |
| `src/js/ui-core.js` | 1 | Modified |
| `src/css/styles.css` | 1,3 | Modified |
| `src/index.html` | 3 | Modified |
| `VERSION` | — | Modified (0.19.0 → 0.19.1) |
| `CHANGELOG.md` | — | Modified |
No new files. No migrations. Backend change is a single injection
point in completion.go.