@hienlh/ppm 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agent-memory/tester/MEMORY.md +3 -0
- package/.claude/agent-memory/tester/project-ppm-test-conventions.md +32 -0
- package/.env.example +1 -0
- package/.github/workflows/release.yml +46 -0
- package/README.md +349 -0
- package/bun.lock +1217 -0
- package/components.json +21 -0
- package/docs/code-standards.md +574 -0
- package/docs/codebase-summary.md +294 -0
- package/docs/deployment-guide.md +631 -0
- package/docs/design-guidelines.md +661 -0
- package/docs/project-overview-pdr.md +142 -0
- package/docs/project-roadmap.md +400 -0
- package/docs/system-architecture.md +459 -0
- package/package.json +68 -0
- package/plans/260314-2009-ppm-implementation/phase-01-project-skeleton.md +81 -0
- package/plans/260314-2009-ppm-implementation/phase-02-backend-core.md +148 -0
- package/plans/260314-2009-ppm-implementation/phase-03-frontend-shell.md +256 -0
- package/plans/260314-2009-ppm-implementation/phase-04-file-explorer-editor.md +120 -0
- package/plans/260314-2009-ppm-implementation/phase-05-web-terminal.md +174 -0
- package/plans/260314-2009-ppm-implementation/phase-06-git-integration.md +244 -0
- package/plans/260314-2009-ppm-implementation/phase-07-ai-chat.md +242 -0
- package/plans/260314-2009-ppm-implementation/phase-08-cli-commands.md +143 -0
- package/plans/260314-2009-ppm-implementation/phase-09-pwa-build-deploy.md +209 -0
- package/plans/260314-2009-ppm-implementation/phase-10-testing.md +311 -0
- package/plans/260314-2009-ppm-implementation/plan.md +202 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-01-backend-project-router.md +145 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-02-frontend-api-migration.md +107 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-03-per-project-tabs.md +100 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-04-websocket-migration.md +66 -0
- package/plans/260315-0356-project-scoped-api-refactor/plan.md +87 -0
- package/plans/reports/brainstorm-260314-1938-final-techstack.md +342 -0
- package/plans/reports/docs-manager-260315-1314-documentation-creation.md +386 -0
- package/plans/reports/fullstack-developer-260314-2252-phase-02-backend-core.md +57 -0
- package/plans/reports/fullstack-developer-260314-2253-phase-03-frontend-shell.md +70 -0
- package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-api-terminal-ws.md +49 -0
- package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-explorer-editor-terminal.md +52 -0
- package/plans/reports/fullstack-developer-260314-2307-ai-chat-phase7.md +58 -0
- package/plans/reports/fullstack-developer-260314-2307-phase-06-git-integration.md +33 -0
- package/plans/reports/research-260314-1911-ppm-tech-stack.md +318 -0
- package/plans/reports/research-260314-1930-claude-code-integration.md +293 -0
- package/plans/reports/researcher-260314-2232-node-pty-bun-crash-analysis.md +305 -0
- package/plans/reports/researcher-260314-2232-ui-style.md +942 -0
- package/plans/reports/researcher-260315-0300-opcode-claude-interaction.md +745 -0
- package/plans/reports/researcher-260315-0303-opcode-deep-analysis.md +742 -0
- package/plans/reports/researcher-260315-0305-claude-agent-sdk-github-research.md +423 -0
- package/plans/reports/tester-260314-2053-initial-test-suite.md +81 -0
- package/ppm.example.yaml +14 -0
- package/repomix-output.xml +23745 -0
- package/scripts/build.ts +13 -0
- package/src/cli/commands/chat-cmd.ts +259 -0
- package/src/cli/commands/config-cmd.ts +121 -0
- package/src/cli/commands/git-cmd.ts +315 -0
- package/src/cli/commands/init.ts +57 -0
- package/src/cli/commands/open.ts +19 -0
- package/src/cli/commands/projects.ts +100 -0
- package/src/cli/commands/start.ts +3 -0
- package/src/cli/commands/stop.ts +33 -0
- package/src/cli/utils/project-resolver.ts +27 -0
- package/src/index.ts +59 -0
- package/src/providers/claude-agent-sdk.ts +499 -0
- package/src/providers/claude-binary-finder.ts +256 -0
- package/src/providers/claude-code-cli.ts +413 -0
- package/src/providers/claude-process-registry.ts +106 -0
- package/src/providers/mock-provider.ts +171 -0
- package/src/providers/provider.interface.ts +10 -0
- package/src/providers/registry.ts +45 -0
- package/src/server/helpers/resolve-project.ts +22 -0
- package/src/server/index.ts +181 -0
- package/src/server/middleware/auth.ts +30 -0
- package/src/server/routes/chat.ts +153 -0
- package/src/server/routes/files.ts +168 -0
- package/src/server/routes/git.ts +261 -0
- package/src/server/routes/project-scoped.ts +27 -0
- package/src/server/routes/projects.ts +57 -0
- package/src/server/routes/static.ts +26 -0
- package/src/server/ws/chat.ts +130 -0
- package/src/server/ws/terminal.ts +89 -0
- package/src/services/chat.service.ts +110 -0
- package/src/services/claude-usage.service.ts +113 -0
- package/src/services/config.service.ts +90 -0
- package/src/services/file.service.ts +261 -0
- package/src/services/git-dirs.service.ts +112 -0
- package/src/services/git.service.ts +372 -0
- package/src/services/project.service.ts +107 -0
- package/src/services/slash-items.service.ts +184 -0
- package/src/services/terminal.service.ts +212 -0
- package/src/types/api.ts +37 -0
- package/src/types/chat.ts +92 -0
- package/src/types/config.ts +41 -0
- package/src/types/git.ts +50 -0
- package/src/types/project.ts +18 -0
- package/src/types/terminal.ts +20 -0
- package/src/web/app.tsx +168 -0
- package/src/web/components/auth/login-screen.tsx +88 -0
- package/src/web/components/chat/attachment-chips.tsx +55 -0
- package/src/web/components/chat/chat-placeholder.tsx +10 -0
- package/src/web/components/chat/chat-tab.tsx +301 -0
- package/src/web/components/chat/file-picker.tsx +126 -0
- package/src/web/components/chat/message-input.tsx +420 -0
- package/src/web/components/chat/message-list.tsx +838 -0
- package/src/web/components/chat/session-picker.tsx +139 -0
- package/src/web/components/chat/slash-command-picker.tsx +135 -0
- package/src/web/components/chat/usage-badge.tsx +186 -0
- package/src/web/components/editor/code-editor.tsx +329 -0
- package/src/web/components/editor/diff-viewer.tsx +276 -0
- package/src/web/components/editor/editor-placeholder.tsx +10 -0
- package/src/web/components/explorer/file-actions.tsx +191 -0
- package/src/web/components/explorer/file-tree.tsx +298 -0
- package/src/web/components/git/git-graph.tsx +727 -0
- package/src/web/components/git/git-placeholder.tsx +55 -0
- package/src/web/components/git/git-status-panel.tsx +850 -0
- package/src/web/components/layout/mobile-drawer.tsx +137 -0
- package/src/web/components/layout/mobile-nav.tsx +103 -0
- package/src/web/components/layout/sidebar.tsx +90 -0
- package/src/web/components/layout/tab-bar.tsx +152 -0
- package/src/web/components/layout/tab-content.tsx +85 -0
- package/src/web/components/projects/dir-suggest.tsx +152 -0
- package/src/web/components/projects/project-list.tsx +187 -0
- package/src/web/components/settings/settings-tab.tsx +57 -0
- package/src/web/components/terminal/terminal-placeholder.tsx +10 -0
- package/src/web/components/terminal/terminal-tab.tsx +133 -0
- package/src/web/components/ui/button.tsx +64 -0
- package/src/web/components/ui/context-menu.tsx +250 -0
- package/src/web/components/ui/dialog.tsx +156 -0
- package/src/web/components/ui/dropdown-menu.tsx +257 -0
- package/src/web/components/ui/input.tsx +21 -0
- package/src/web/components/ui/scroll-area.tsx +56 -0
- package/src/web/components/ui/separator.tsx +26 -0
- package/src/web/components/ui/sonner.tsx +40 -0
- package/src/web/components/ui/tabs.tsx +91 -0
- package/src/web/components/ui/tooltip.tsx +57 -0
- package/src/web/hooks/use-chat.ts +420 -0
- package/src/web/hooks/use-terminal.ts +182 -0
- package/src/web/hooks/use-url-sync.ts +66 -0
- package/src/web/hooks/use-websocket.ts +48 -0
- package/src/web/index.html +16 -0
- package/src/web/lib/api-client.ts +90 -0
- package/src/web/lib/file-support.ts +68 -0
- package/src/web/lib/utils.ts +6 -0
- package/src/web/lib/ws-client.ts +100 -0
- package/src/web/main.tsx +10 -0
- package/src/web/public/icon-192.svg +5 -0
- package/src/web/public/icon-512.svg +5 -0
- package/src/web/stores/file-store.ts +81 -0
- package/src/web/stores/project-store.ts +50 -0
- package/src/web/stores/settings-store.ts +65 -0
- package/src/web/stores/tab-store.ts +187 -0
- package/src/web/styles/globals.css +227 -0
- package/src/web/vite-env.d.ts +1 -0
- package/tests/integration/api/chat-routes.test.ts +95 -0
- package/tests/integration/claude-agent-sdk-integration.test.ts +228 -0
- package/tests/integration/ws/chat-websocket.test.ts +312 -0
- package/tests/test-setup.ts +5 -0
- package/tests/unit/providers/claude-agent-sdk.test.ts +339 -0
- package/tests/unit/providers/mock-provider.test.ts +143 -0
- package/tests/unit/services/chat-service.test.ts +100 -0
- package/tsconfig.json +32 -0
- package/vite.config.ts +62 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Phase 6: Git Integration — Implementation Report
|
|
2
|
+
|
|
3
|
+
**Status:** Completed
|
|
4
|
+
**Date:** 2026-03-14
|
|
5
|
+
|
|
6
|
+
## Files Created
|
|
7
|
+
- `src/services/git.service.ts` — GitService class (status, diff, stage/unstage, commit, push/pull, branches, graph, cherry-pick, revert, tag, PR URL)
|
|
8
|
+
- `src/server/routes/git.ts` — 17 Hono routes (GET + POST) for all git operations
|
|
9
|
+
- `src/web/components/git/git-status-panel.tsx` — Full status panel with stage/unstage/commit/push/pull
|
|
10
|
+
- `src/web/components/git/git-graph.tsx` — Commit graph with lane coloring, branch/tag labels, context menus
|
|
11
|
+
|
|
12
|
+
## Files Modified
|
|
13
|
+
- `src/server/index.ts` — Added git routes import + mount at `/api/git`
|
|
14
|
+
- `src/web/components/editor/diff-viewer.tsx` — Replaced placeholder with real @codemirror/merge unified diff viewer
|
|
15
|
+
- `src/web/components/layout/tab-content.tsx` — Wired real GitGraph + GitStatusPanel instead of placeholders
|
|
16
|
+
|
|
17
|
+
## Backend Summary
|
|
18
|
+
- **GitService**: Uses simple-git for all operations. `graphData()` uses `.log({ '--all': null, maxCount })` + raw `--format=%H %P` for parent hashes (per v1 lesson). PR URL parsing supports GitHub + GitLab SSH/HTTPS remotes.
|
|
19
|
+
- **Routes**: 5 GET + 12 POST endpoints. All use `ok()`/`err()` envelope. Project resolved by name via `resolveProjectPath()`.
|
|
20
|
+
|
|
21
|
+
## Frontend Summary
|
|
22
|
+
- **GitStatusPanel**: Two sections (Staged/Changes), per-file +/- stage/unstage, commit textarea with Cmd+Enter, push/pull buttons. Auto-refresh after actions.
|
|
23
|
+
- **GitGraph**: Scrollable commit list with lane-colored dots, abbreviated hash, subject, author, relative date. Branch labels as colored badges, tag labels in amber. Nested ContextMenus on both commits (checkout, create branch, cherry pick, revert, tag, copy hash, view diff) and branch labels (checkout, merge, push, create PR, delete).
|
|
24
|
+
- **DiffViewer**: Fetches diff from API, parses unified diff into original/modified, renders with `@codemirror/merge` `unifiedMergeView`. Syntax highlighting by file extension.
|
|
25
|
+
|
|
26
|
+
## Tests Status
|
|
27
|
+
- Type check: PASS (0 errors)
|
|
28
|
+
- Build: PASS (368ms)
|
|
29
|
+
|
|
30
|
+
## Design Decisions
|
|
31
|
+
- Git graph uses simple list layout (colored dots per lane) instead of SVG — KISS for v1, performant, works well on mobile
|
|
32
|
+
- Diff viewer uses inline unified merge view rather than side-by-side — better mobile experience
|
|
33
|
+
- Branch/tag labels parsed from both `git branch -a` and commit refs field
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Research Report: PPM Tech Stack Selection
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-03-14
|
|
4
|
+
**Sources consulted:** 15+
|
|
5
|
+
**Key search terms:** mobile-first code editor, web terminal, git graph visualization, Claude Code CLI integration, Go CLI web gateway
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Executive Summary
|
|
10
|
+
|
|
11
|
+
PPM (Personal Project Manager) cần: CLI backend chạy background serving web UI, mobile-first tab system giống VSCode, terminal/editor/git/AI chat trong browser. Sau khi research, recommend stack:
|
|
12
|
+
|
|
13
|
+
- **Backend:** Go + Cobra CLI + embedded SPA + WebSocket
|
|
14
|
+
- **Frontend:** React (Vite) + Tailwind CSS + shadcn/ui mobile
|
|
15
|
+
- **Editor:** CodeMirror 6 (mobile-first, 300KB vs Monaco 5-10MB)
|
|
16
|
+
- **Terminal:** xterm.js + WebSocket → PTY
|
|
17
|
+
- **Git:** go-git + custom SVG git graph + diff2html
|
|
18
|
+
- **AI Chat:** Claude Agent SDK / Anthropic API streaming via SSE
|
|
19
|
+
- **Tab System:** Custom React tab manager (inspired by VSCode workbench)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Key Findings
|
|
24
|
+
|
|
25
|
+
### 1. CLI Backend: Go
|
|
26
|
+
|
|
27
|
+
| Criteria | Go | Node.js | Rust |
|
|
28
|
+
|---|---|---|---|
|
|
29
|
+
| Single binary deploy | Yes | No (runtime needed) | Yes |
|
|
30
|
+
| Build speed | Fast (~2s) | N/A | Slow (~30s+) |
|
|
31
|
+
| Concurrency | Goroutines (lightweight) | Event loop + workers | Async/Tokio |
|
|
32
|
+
| WebSocket support | gorilla/websocket, nhooyr | ws, socket.io | tokio-tungstenite |
|
|
33
|
+
| PTY support | creack/pty | node-pty | portable-pty |
|
|
34
|
+
| Embed static files | embed.FS (built-in) | pkg/nexe (hacky) | rust-embed |
|
|
35
|
+
| Learning curve | Low-medium | Low | High |
|
|
36
|
+
| Dev productivity (solo) | High | High | Medium |
|
|
37
|
+
|
|
38
|
+
**Recommendation: Go**
|
|
39
|
+
- Single binary = dễ deploy lên VPS, chỉ cần copy binary + config
|
|
40
|
+
- `embed.FS` cho phép nhúng toàn bộ frontend build vào binary
|
|
41
|
+
- Cobra CLI framework cho CLI commands (init, start, config)
|
|
42
|
+
- gorilla/websocket cho terminal + chat streaming
|
|
43
|
+
- creack/pty cho PTY spawning
|
|
44
|
+
|
|
45
|
+
**Key libraries:**
|
|
46
|
+
- `spf13/cobra` - CLI framework
|
|
47
|
+
- `gorilla/websocket` - WebSocket server
|
|
48
|
+
- `creack/pty` - PTY management
|
|
49
|
+
- `go-git/go-git` - Pure Go git implementation (no git binary needed)
|
|
50
|
+
- `embed` (stdlib) - Embed frontend assets
|
|
51
|
+
|
|
52
|
+
### 2. Frontend: React + Vite + Tailwind
|
|
53
|
+
|
|
54
|
+
**Tại sao React thay vì Svelte?**
|
|
55
|
+
|
|
56
|
+
Gemini recommend Svelte nhưng tôi counter-argue:
|
|
57
|
+
- Ecosystem cho tab system, code editor wrappers, terminal components **lớn hơn nhiều** ở React
|
|
58
|
+
- `@anthropic-ai/claude-agent-sdk-demos` dùng React - dễ reference
|
|
59
|
+
- CodeMirror 6 có `@uiw/react-codemirror` wrapper tốt
|
|
60
|
+
- xterm.js có nhiều React wrappers
|
|
61
|
+
- shadcn/ui + Radix UI cho mobile-first components
|
|
62
|
+
- Solo dev đã quen React → productivity cao hơn
|
|
63
|
+
|
|
64
|
+
**Bundle size concern:** Vite tree-shaking + code splitting giải quyết. Lazy load tabs (terminal, editor, git graph) = initial load nhỏ.
|
|
65
|
+
|
|
66
|
+
**Key libraries:**
|
|
67
|
+
- `vite` - Build tool
|
|
68
|
+
- `tailwindcss` + `shadcn/ui` - Mobile-first UI
|
|
69
|
+
- `@tanstack/react-router` - File-based routing (nếu cần)
|
|
70
|
+
- `zustand` - State management (nhẹ, simple)
|
|
71
|
+
- `react-resizable-panels` - Split panes cho tab layout
|
|
72
|
+
|
|
73
|
+
### 3. Code Editor: CodeMirror 6
|
|
74
|
+
|
|
75
|
+
| Criteria | CodeMirror 6 | Monaco |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| Bundle size | ~300KB (core) | 5-10MB |
|
|
78
|
+
| Mobile/touch support | Native, built-in | Not officially supported |
|
|
79
|
+
| Modular | Yes, tree-shakable | Monolithic |
|
|
80
|
+
| Syntax highlighting | 100+ languages via @codemirror/lang-* | Built-in, extensive |
|
|
81
|
+
| Diff view | @codemirror/merge | Built-in, excellent |
|
|
82
|
+
|
|
83
|
+
**Winner: CodeMirror 6** - mobile-first requirement makes this a no-brainer.
|
|
84
|
+
- Replit switched to CM6, mobile retention tăng 70%
|
|
85
|
+
- Sourcegraph migrated Monaco → CM6 vì performance
|
|
86
|
+
|
|
87
|
+
**Key packages:**
|
|
88
|
+
- `@uiw/react-codemirror` - React wrapper
|
|
89
|
+
- `@codemirror/lang-*` - Language support
|
|
90
|
+
- `@codemirror/merge` - Diff/merge view
|
|
91
|
+
- `@codemirror/theme-one-dark` - Dark theme
|
|
92
|
+
|
|
93
|
+
### 4. Web Terminal: xterm.js
|
|
94
|
+
|
|
95
|
+
Industry standard, powers VSCode terminal. Architecture:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
Browser (xterm.js) ←WebSocket→ Go server ←PTY→ bash/zsh
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Key packages:**
|
|
102
|
+
- `@xterm/xterm` - Core terminal emulator
|
|
103
|
+
- `@xterm/addon-fit` - Auto-resize
|
|
104
|
+
- `@xterm/addon-web-links` - Clickable links
|
|
105
|
+
- `@xterm/addon-attach` - WebSocket attachment
|
|
106
|
+
|
|
107
|
+
Go side: `creack/pty` spawns PTY, `gorilla/websocket` bridges to frontend.
|
|
108
|
+
|
|
109
|
+
### 5. Git Integration
|
|
110
|
+
|
|
111
|
+
**Git operations:** `go-git/go-git` (pure Go, no git binary dependency)
|
|
112
|
+
- Clone, log, diff, status, branch - all natively
|
|
113
|
+
- Fallback to `os/exec` + `git` binary for complex ops
|
|
114
|
+
|
|
115
|
+
**Git graph visualization:**
|
|
116
|
+
- `gitgraph.js` archived → NOT recommended
|
|
117
|
+
- **Custom SVG rendering** using commit data from go-git
|
|
118
|
+
- Parse commit graph → layout algorithm → SVG/Canvas render
|
|
119
|
+
- Reference: VSCode Git Graph extension approach
|
|
120
|
+
- Libraries: `react-flow` hoặc custom SVG with D3 basics
|
|
121
|
+
|
|
122
|
+
**Git diff viewer:**
|
|
123
|
+
- `diff2html` (2.5k stars) - Parse unified diff → HTML
|
|
124
|
+
- Alternative: `@codemirror/merge` for inline editing + diff
|
|
125
|
+
|
|
126
|
+
### 6. AI Chat Integration
|
|
127
|
+
|
|
128
|
+
**Approach 1 (Recommended): Wrap Claude Code CLI**
|
|
129
|
+
```
|
|
130
|
+
Frontend Chat UI ←WebSocket→ Go server ←stdin/stdout→ claude CLI process
|
|
131
|
+
```
|
|
132
|
+
- Spawn `claude` process with PTY (giống terminal nhưng parse output)
|
|
133
|
+
- Giống hệt VSCode extension approach
|
|
134
|
+
- Hỗ trợ tool approvals, streaming, MCP
|
|
135
|
+
- Session = 1 claude process, CRUD = start/stop processes
|
|
136
|
+
|
|
137
|
+
**Approach 2: Direct API**
|
|
138
|
+
- Anthropic API streaming via SSE
|
|
139
|
+
- Mất hết claude code features (tools, MCP, permissions)
|
|
140
|
+
|
|
141
|
+
**Approach 3: Claude Agent SDK**
|
|
142
|
+
- TypeScript SDK cho building agents
|
|
143
|
+
- Phức tạp hơn nhưng flexible hơn
|
|
144
|
+
|
|
145
|
+
**Reference projects:**
|
|
146
|
+
- `siteboon/claudecodeui` - Self-hosted web UI for Claude Code sessions
|
|
147
|
+
- `Jinn` - Gateway daemon extending Claude CLI with web UI
|
|
148
|
+
- Claude Agent SDK demos - React + Express chat app
|
|
149
|
+
|
|
150
|
+
### 7. Tab System Architecture
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
┌─────────────────────────────────────────┐
|
|
154
|
+
│ Tab Bar (scrollable on mobile) │
|
|
155
|
+
│ [Terminal 1] [Chat: main] [editor.ts] X │
|
|
156
|
+
├─────────────────────────────────────────┤
|
|
157
|
+
│ │
|
|
158
|
+
│ Active Tab Content │
|
|
159
|
+
│ (lazy-loaded React component) │
|
|
160
|
+
│ │
|
|
161
|
+
└─────────────────────────────────────────┘
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- Each tab = `{ id, type, title, component, metadata }`
|
|
165
|
+
- Types: `terminal`, `chat`, `editor`, `git-graph`, `git-diff`, `settings`
|
|
166
|
+
- State: zustand store with tab CRUD
|
|
167
|
+
- Mobile: swipe gestures, bottom tab bar option
|
|
168
|
+
- Desktop: draggable tabs, split panes
|
|
169
|
+
|
|
170
|
+
### 8. Deployment & Config
|
|
171
|
+
|
|
172
|
+
**Config file (`ppm.yaml`):**
|
|
173
|
+
```yaml
|
|
174
|
+
port: 8080
|
|
175
|
+
host: 0.0.0.0
|
|
176
|
+
projects:
|
|
177
|
+
- path: /home/user/project-a
|
|
178
|
+
name: Project A
|
|
179
|
+
- path: /home/user/project-b
|
|
180
|
+
name: Project B
|
|
181
|
+
auth:
|
|
182
|
+
enabled: true
|
|
183
|
+
token: "xxx" # simple token auth for VPS
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Local onboarding:**
|
|
187
|
+
```bash
|
|
188
|
+
ppm init # Interactive setup, scan for .git folders
|
|
189
|
+
ppm start # Start server
|
|
190
|
+
ppm start -d # Daemon mode (background)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**VPS deployment:**
|
|
194
|
+
```bash
|
|
195
|
+
# Copy binary + config
|
|
196
|
+
scp ppm user@vps:/usr/local/bin/
|
|
197
|
+
scp ppm.yaml user@vps:/etc/ppm/
|
|
198
|
+
ssh user@vps "ppm start -c /etc/ppm/ppm.yaml -d"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Tailscale:** Just run `ppm start` on local machine, access via Tailscale IP.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Architecture Overview
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
┌──────────────────────────────────────────────────┐
|
|
209
|
+
│ PPM Binary (Go) │
|
|
210
|
+
│ │
|
|
211
|
+
│ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
|
|
212
|
+
│ │ Cobra CLI│ │ HTTP/WS │ │ Embedded SPA │ │
|
|
213
|
+
│ │ Commands │ │ Server │ │ (React build) │ │
|
|
214
|
+
│ └──────────┘ └────┬─────┘ └────────────────┘ │
|
|
215
|
+
│ │ │
|
|
216
|
+
│ ┌──────────┐ ┌────┴─────┐ ┌────────────────┐ │
|
|
217
|
+
│ │ PTY Mgr │ │ WS Hub │ │ Session Mgr │ │
|
|
218
|
+
│ │(terminal)│ │(routing) │ │ (AI processes) │ │
|
|
219
|
+
│ └──────────┘ └──────────┘ └────────────────┘ │
|
|
220
|
+
│ │
|
|
221
|
+
│ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
|
|
222
|
+
│ │ go-git │ │ Config │ │ File System │ │
|
|
223
|
+
│ │ (git ops)│ │ Manager │ │ Watcher │ │
|
|
224
|
+
│ └──────────┘ └──────────┘ └────────────────┘ │
|
|
225
|
+
└──────────────────────────────────────────────────┘
|
|
226
|
+
↕ WebSocket / HTTP
|
|
227
|
+
┌──────────────────────────────────────────────────┐
|
|
228
|
+
│ React SPA (Browser) │
|
|
229
|
+
│ │
|
|
230
|
+
│ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
|
|
231
|
+
│ │ Tab Mgr │ │ xterm.js │ │ CodeMirror 6 │ │
|
|
232
|
+
│ │ (zustand)│ │(terminal)│ │ (editor) │ │
|
|
233
|
+
│ └──────────┘ └──────────┘ └────────────────┘ │
|
|
234
|
+
│ │
|
|
235
|
+
│ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
|
|
236
|
+
│ │ Chat UI │ │ Git Graph│ │ File Explorer │ │
|
|
237
|
+
│ │(streaming│ │ (SVG) │ │ (tree view) │ │
|
|
238
|
+
│ └──────────┘ └──────────┘ └────────────────┘ │
|
|
239
|
+
└──────────────────────────────────────────────────┘
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Final Tech Stack Summary
|
|
245
|
+
|
|
246
|
+
| Component | Technology | Why |
|
|
247
|
+
|---|---|---|
|
|
248
|
+
| CLI + Backend | Go + Cobra | Single binary, embed frontend, fast, easy deploy |
|
|
249
|
+
| HTTP Server | Go stdlib `net/http` | No framework needed |
|
|
250
|
+
| WebSocket | gorilla/websocket | Battle-tested, Go standard |
|
|
251
|
+
| PTY | creack/pty | Terminal spawning |
|
|
252
|
+
| Git | go-git | Pure Go, no git binary dep |
|
|
253
|
+
| Frontend | React 19 + Vite | Ecosystem, AI SDK demos, component libs |
|
|
254
|
+
| Styling | Tailwind CSS + shadcn/ui | Mobile-first, accessible |
|
|
255
|
+
| State | zustand | Simple, lightweight |
|
|
256
|
+
| Editor | CodeMirror 6 | Mobile-first, 300KB, modular |
|
|
257
|
+
| Terminal | xterm.js v5 | Industry standard (VSCode uses it) |
|
|
258
|
+
| Git Graph | Custom SVG + D3 basics | No good maintained lib exists |
|
|
259
|
+
| Git Diff | diff2html or CM6 merge | Proven solutions |
|
|
260
|
+
| AI Chat | Claude CLI process via PTY | Full feature parity with VSCode ext |
|
|
261
|
+
| Config | YAML (viper) | Go standard for config |
|
|
262
|
+
| Auth | Simple token (VPS) | KISS for personal tool |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Implementation Recommendations
|
|
267
|
+
|
|
268
|
+
### Quick Start Order
|
|
269
|
+
1. Go CLI skeleton (Cobra) + config loading
|
|
270
|
+
2. HTTP server + embed empty React app
|
|
271
|
+
3. React tab system + routing
|
|
272
|
+
4. Terminal tab (xterm.js ↔ WebSocket ↔ PTY)
|
|
273
|
+
5. File explorer + CodeMirror editor tab
|
|
274
|
+
6. Git operations (status, log, diff)
|
|
275
|
+
7. Git graph visualization
|
|
276
|
+
8. AI chat integration (claude CLI wrapper)
|
|
277
|
+
9. Onboarding flow (`ppm init`)
|
|
278
|
+
10. VPS deployment mode
|
|
279
|
+
|
|
280
|
+
### Common Pitfalls
|
|
281
|
+
- Monaco Editor on mobile = broken. Use CodeMirror 6
|
|
282
|
+
- Don't use gitgraph.js (archived since 2023)
|
|
283
|
+
- PTY resize events must sync between xterm.js and server
|
|
284
|
+
- Claude CLI process management: handle crashes, timeouts, cleanup
|
|
285
|
+
- WebSocket reconnection logic essential for mobile (network drops)
|
|
286
|
+
- `go-git` doesn't support all git features — fallback to `git` binary
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## References
|
|
291
|
+
|
|
292
|
+
- [CodeMirror 6 vs Monaco comparison](https://agenthicks.com/research/codemirror-vs-monaco-editor-comparison)
|
|
293
|
+
- [Sourcegraph Monaco → CM6 migration](https://sourcegraph.com/blog/migrating-monaco-codemirror)
|
|
294
|
+
- [Replit code editor comparison](https://blog.replit.com/code-editors)
|
|
295
|
+
- [xterm.js](https://xtermjs.org/)
|
|
296
|
+
- [go-git](https://github.com/go-git/go-git)
|
|
297
|
+
- [Cobra CLI](https://github.com/spf13/cobra)
|
|
298
|
+
- [creack/pty](https://github.com/creack/pty)
|
|
299
|
+
- [gorilla/websocket](https://github.com/gorilla/websocket)
|
|
300
|
+
- [diff2html](https://github.com/rtfpessoa/diff2html)
|
|
301
|
+
- [Claude Agent SDK demos](https://github.com/anthropics/claude-agent-sdk-demos)
|
|
302
|
+
- [claudecodeui](https://github.com/siteboon/claudecodeui)
|
|
303
|
+
- [shadcn/ui](https://ui.shadcn.com/)
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## User Decisions (2026-03-14)
|
|
308
|
+
|
|
309
|
+
1. **Claude Code integration:** Reference projects: [vibe-kanban](https://github.com/BloopAI/vibe-kanban), [claude-code-chat](https://github.com/andrepimenta/claude-code-chat), [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview)
|
|
310
|
+
2. **Git scope:** Basic only (status, log, diff, graph). No advanced features (rebase, submodules)
|
|
311
|
+
3. **Auth:** Simple token OK. Design for extensibility (pluggable auth later)
|
|
312
|
+
4. **Editor:** CodeMirror 6 confirmed — works well on mobile
|
|
313
|
+
5. **PWA:** Yes, will implement PWA (offline caching, add to homescreen)
|
|
314
|
+
|
|
315
|
+
## Remaining Questions
|
|
316
|
+
|
|
317
|
+
1. **Claude CLI output parsing:** Exact JSON output format? Need to study vibe-kanban and claude-code-chat implementations
|
|
318
|
+
2. **Agent SDK vs CLI wrapping:** Which approach fits better? SDK = more control, CLI = full feature parity
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Research Report: Claude Code CLI Integration Patterns
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-03-14
|
|
4
|
+
**Sources:** 3 primary (vibe-kanban, claude-code-chat, Agent SDK docs) + 2 supplementary (sessions, user-input docs)
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Executive Summary
|
|
9
|
+
|
|
10
|
+
3 approaches exist for integrating Claude Code into a custom UI. After analyzing all sources, **Claude Agent SDK (TypeScript)** is the clear winner for PPM — it provides programmatic session management, streaming, tool approvals, and is the officially supported path. claude-code-chat validates the CLI subprocess approach works but Agent SDK is superior in every way.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Source Analysis
|
|
15
|
+
|
|
16
|
+
### 1. BloopAI/vibe-kanban
|
|
17
|
+
|
|
18
|
+
**Architecture:** Rust backend + React frontend. Full IDE-like tool for managing coding agents.
|
|
19
|
+
- Supports Claude Code, Codex, Gemini CLI, GitHub Copilot, Amp, etc.
|
|
20
|
+
- Runs agents in isolated workspaces (git worktrees) with terminal + dev server per workspace
|
|
21
|
+
- Backend: Rust (49.4%), Frontend: TypeScript/React (46.7%)
|
|
22
|
+
- Requires PostgreSQL
|
|
23
|
+
|
|
24
|
+
**Integration approach:** Agent-agnostic — treats all AI tools as terminal processes in workspaces. Does NOT deeply integrate with Claude Code internals, just provides terminal environments.
|
|
25
|
+
|
|
26
|
+
**Key takeaway for PPM:** Overkill for our needs. Uses Rust + PostgreSQL which adds complexity. But the "workspace = branch + terminal + dev server" concept is interesting.
|
|
27
|
+
|
|
28
|
+
### 2. andrepimenta/claude-code-chat
|
|
29
|
+
|
|
30
|
+
**Architecture:** VSCode extension wrapping Claude Code CLI as subprocess.
|
|
31
|
+
|
|
32
|
+
**Integration method: CLI Subprocess via stdin/stdout**
|
|
33
|
+
- Spawns `claude` CLI process
|
|
34
|
+
- Captures streaming stdout for real-time response display
|
|
35
|
+
- Sends user messages via stdin
|
|
36
|
+
- WSL path support for CLI binary (`/usr/local/bin/claude`)
|
|
37
|
+
|
|
38
|
+
**Session management:**
|
|
39
|
+
- Automatic conversation saving/restoration (file-based)
|
|
40
|
+
- Resume conversations where left off
|
|
41
|
+
- Workspace-scoped sessions
|
|
42
|
+
|
|
43
|
+
**Tool approvals — sophisticated permission system:**
|
|
44
|
+
- Interactive dialog showing tool info + command previews
|
|
45
|
+
- Smart pattern matching (npm, git, docker auto-approved)
|
|
46
|
+
- "Always Allow" functionality
|
|
47
|
+
- "YOLO Mode" — skip all permission checks
|
|
48
|
+
- Workspace-level granular permissions
|
|
49
|
+
|
|
50
|
+
**Streaming:** Real-time streaming responses with typing indicators, parsing CLI stdout.
|
|
51
|
+
|
|
52
|
+
**Key takeaway for PPM:** Validates CLI wrapping works well for chat UI. But this is VSCode-specific. For a web app, Agent SDK is better since it gives programmatic control without parsing CLI output.
|
|
53
|
+
|
|
54
|
+
### 3. Claude Agent SDK (Official) — **RECOMMENDED**
|
|
55
|
+
|
|
56
|
+
**Architecture:** Library that gives same capabilities as Claude Code CLI, programmable in TypeScript and Python.
|
|
57
|
+
|
|
58
|
+
**Package:** `@anthropic-ai/claude-agent-sdk` (TypeScript) / `claude-agent-sdk` (Python)
|
|
59
|
+
|
|
60
|
+
**Core API — `query()` function:**
|
|
61
|
+
```typescript
|
|
62
|
+
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
63
|
+
|
|
64
|
+
for await (const message of query({
|
|
65
|
+
prompt: "Find and fix the bug in auth.py",
|
|
66
|
+
options: { allowedTools: ["Read", "Edit", "Bash"] }
|
|
67
|
+
})) {
|
|
68
|
+
console.log(message);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Built-in tools (same as Claude Code CLI):**
|
|
73
|
+
| Tool | What it does |
|
|
74
|
+
|------|-------------|
|
|
75
|
+
| Read | Read files |
|
|
76
|
+
| Write | Create files |
|
|
77
|
+
| Edit | Precise edits |
|
|
78
|
+
| Bash | Terminal commands |
|
|
79
|
+
| Glob | Find files by pattern |
|
|
80
|
+
| Grep | Search file contents |
|
|
81
|
+
| WebSearch | Search web |
|
|
82
|
+
| WebFetch | Fetch web pages |
|
|
83
|
+
| AskUserQuestion | Ask user clarifying questions |
|
|
84
|
+
| Agent | Spawn subagents |
|
|
85
|
+
|
|
86
|
+
**Session Management — EXCELLENT:**
|
|
87
|
+
```typescript
|
|
88
|
+
// Create session — capture ID from init message
|
|
89
|
+
let sessionId: string;
|
|
90
|
+
for await (const message of query({
|
|
91
|
+
prompt: "Analyze auth module",
|
|
92
|
+
options: { allowedTools: ["Read", "Glob"] }
|
|
93
|
+
})) {
|
|
94
|
+
if (message.type === "system" && message.subtype === "init") {
|
|
95
|
+
sessionId = message.session_id;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Resume session with full context
|
|
100
|
+
for await (const message of query({
|
|
101
|
+
prompt: "Now find all places that call it",
|
|
102
|
+
options: { resume: sessionId }
|
|
103
|
+
})) {
|
|
104
|
+
// Has full context from first query
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Fork session to explore alternative
|
|
108
|
+
for await (const message of query({
|
|
109
|
+
prompt: "Try OAuth2 instead",
|
|
110
|
+
options: { resume: sessionId, forkSession: true }
|
|
111
|
+
})) {
|
|
112
|
+
// New session branched from original
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Continue most recent session (no ID needed)
|
|
116
|
+
for await (const message of query({
|
|
117
|
+
prompt: "Continue with previous task",
|
|
118
|
+
options: { continue: true }
|
|
119
|
+
})) {}
|
|
120
|
+
|
|
121
|
+
// List all sessions
|
|
122
|
+
import { listSessions, getSessionMessages } from "@anthropic-ai/claude-agent-sdk";
|
|
123
|
+
const sessions = await listSessions();
|
|
124
|
+
const messages = await getSessionMessages(sessionId);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Session storage:** `~/.claude/projects/<encoded-cwd>/<session-id>.jsonl`
|
|
128
|
+
|
|
129
|
+
**Tool Approvals — Full Control:**
|
|
130
|
+
```typescript
|
|
131
|
+
for await (const message of query({
|
|
132
|
+
prompt: "Refactor this code",
|
|
133
|
+
options: {
|
|
134
|
+
canUseTool: async (toolName, input) => {
|
|
135
|
+
if (toolName === "AskUserQuestion") {
|
|
136
|
+
// Handle clarifying questions from Claude
|
|
137
|
+
return handleQuestions(input);
|
|
138
|
+
}
|
|
139
|
+
// Show approval UI to user
|
|
140
|
+
const approved = await showApprovalDialog(toolName, input);
|
|
141
|
+
if (approved) {
|
|
142
|
+
return { behavior: "allow", updatedInput: input };
|
|
143
|
+
}
|
|
144
|
+
return { behavior: "deny", message: "User declined" };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
})) {}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Permission modes:** `allowedTools` pre-approves safe tools, `canUseTool` callback for interactive approval.
|
|
151
|
+
|
|
152
|
+
**Streaming:** Native async iterator — each `message` yields as it arrives. Message types:
|
|
153
|
+
- `system` (init with session_id)
|
|
154
|
+
- `assistant` (text blocks, tool calls)
|
|
155
|
+
- `tool` (tool results)
|
|
156
|
+
- `result` (final result with cost info)
|
|
157
|
+
|
|
158
|
+
**Hooks:** PreToolUse, PostToolUse, Stop, SessionStart, SessionEnd — same as Claude Code CLI.
|
|
159
|
+
|
|
160
|
+
**MCP Support:** Connect external MCP servers:
|
|
161
|
+
```typescript
|
|
162
|
+
options: {
|
|
163
|
+
mcpServers: {
|
|
164
|
+
playwright: { command: "npx", args: ["@playwright/mcp@latest"] }
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Subagents:** Spawn specialized agents from main agent.
|
|
170
|
+
|
|
171
|
+
**Claude Code features supported:** Skills, slash commands, CLAUDE.md memory, plugins.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Comparative Analysis
|
|
176
|
+
|
|
177
|
+
| Feature | CLI Subprocess | Agent SDK |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| Setup complexity | Low (just spawn process) | Low (npm install) |
|
|
180
|
+
| Streaming | Parse stdout (fragile) | Native async iterator (robust) |
|
|
181
|
+
| Session CRUD | Parse filesystem | `listSessions()`, `getSessionMessages()`, `resume`, `fork` |
|
|
182
|
+
| Tool approvals | Parse CLI prompts (very fragile) | `canUseTool` callback (clean API) |
|
|
183
|
+
| Multi-session | Multiple processes (heavy) | Multiple `query()` calls (lightweight) |
|
|
184
|
+
| Error handling | Process exit codes | Structured error messages |
|
|
185
|
+
| MCP support | Via CLI config | Programmatic |
|
|
186
|
+
| Hooks | Via CLI config files | Programmatic callbacks |
|
|
187
|
+
| Authentication | CLI handles it | API key in env var |
|
|
188
|
+
| Maintenance | Breaks on CLI output format changes | Stable SDK contract |
|
|
189
|
+
|
|
190
|
+
**Winner: Agent SDK** — vastly superior for building a web app.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Implementation Architecture for PPM
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
┌─────────────────────────────────────────────┐
|
|
198
|
+
│ React Frontend (Browser) │
|
|
199
|
+
│ │
|
|
200
|
+
│ Chat Tab ←→ WebSocket ←→ Go Backend │
|
|
201
|
+
│ - Message list (streaming) │
|
|
202
|
+
│ - Tool approval dialogs │
|
|
203
|
+
│ - AskUserQuestion UI │
|
|
204
|
+
│ - Session picker (list/resume/fork) │
|
|
205
|
+
└─────────────────────────────────────────────┘
|
|
206
|
+
↕ WebSocket (bidirectional)
|
|
207
|
+
┌─────────────────────────────────────────────┐
|
|
208
|
+
│ Go Backend Server │
|
|
209
|
+
│ │
|
|
210
|
+
│ Session Manager │
|
|
211
|
+
│ ├─ Map<sessionId, AgentSDKProcess> │
|
|
212
|
+
│ ├─ Create: spawn node process with SDK │
|
|
213
|
+
│ ├─ Resume: pass sessionId to SDK │
|
|
214
|
+
│ ├─ Fork: pass sessionId + forkSession │
|
|
215
|
+
│ ├─ List: call listSessions() │
|
|
216
|
+
│ └─ Delete: remove session file │
|
|
217
|
+
│ │
|
|
218
|
+
│ Agent SDK Bridge (Node.js sidecar) │
|
|
219
|
+
│ ├─ Runs @anthropic-ai/claude-agent-sdk │
|
|
220
|
+
│ ├─ Communicates with Go via stdio/WebSocket │
|
|
221
|
+
│ ├─ Handles query() streaming │
|
|
222
|
+
│ └─ Forwards canUseTool to frontend │
|
|
223
|
+
└─────────────────────────────────────────────┘
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Key architectural decision:** Since Agent SDK is TypeScript/Python, the Go backend needs a Node.js sidecar process to run the SDK. Communication: Go ↔ Node.js via stdio (JSON lines) or local WebSocket.
|
|
227
|
+
|
|
228
|
+
**Alternative:** Write backend in Node.js instead of Go to avoid sidecar. Trade-off: lose single binary deployment but gain simpler architecture.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Recommended Approach
|
|
233
|
+
|
|
234
|
+
### Option A: Go + Node.js Sidecar (Recommended if keeping Go)
|
|
235
|
+
- Go handles HTTP/WS server, file ops, git ops, terminal PTY
|
|
236
|
+
- Node.js sidecar runs Agent SDK, communicates via JSON-over-stdio
|
|
237
|
+
- Go spawns/manages sidecar processes (one per active session)
|
|
238
|
+
|
|
239
|
+
### Option B: Full Node.js Backend (Simpler)
|
|
240
|
+
- Single runtime for everything
|
|
241
|
+
- Agent SDK runs directly in backend
|
|
242
|
+
- Use `pkg` or `bun compile` for single binary
|
|
243
|
+
- Lose Go's PTY management elegance, but `node-pty` works fine
|
|
244
|
+
|
|
245
|
+
### Option C: Hybrid — Go binary embeds Node.js runtime
|
|
246
|
+
- Complex but achievable with embedded V8 or Bun
|
|
247
|
+
- Not recommended for solo dev
|
|
248
|
+
|
|
249
|
+
**Recommendation:** Start with **Option A** (Go + sidecar). The Go binary handles everything except AI chat. The sidecar is only spawned when user opens a chat tab. If sidecar management becomes painful, migrate to Option B later.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Key Code Patterns for PPM
|
|
254
|
+
|
|
255
|
+
### 1. Session List API
|
|
256
|
+
```typescript
|
|
257
|
+
// Node.js sidecar endpoint
|
|
258
|
+
import { listSessions } from "@anthropic-ai/claude-agent-sdk";
|
|
259
|
+
const sessions = await listSessions(); // Returns session metadata
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### 2. Streaming Chat via WebSocket
|
|
263
|
+
```typescript
|
|
264
|
+
// Sidecar: stream messages to Go backend
|
|
265
|
+
for await (const message of query({ prompt, options: { resume: sessionId } })) {
|
|
266
|
+
process.stdout.write(JSON.stringify(message) + '\n'); // JSON lines to Go
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 3. Tool Approval Flow
|
|
271
|
+
```
|
|
272
|
+
User sends prompt → Go → Sidecar starts query()
|
|
273
|
+
Claude wants to use Bash → canUseTool fires
|
|
274
|
+
Sidecar → Go → WebSocket → Frontend shows approval dialog
|
|
275
|
+
User clicks Allow → Frontend → WebSocket → Go → Sidecar returns allow
|
|
276
|
+
Claude executes tool → continues
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### 4. Multi-tab Chat
|
|
280
|
+
- Each chat tab = one session ID
|
|
281
|
+
- Frontend tracks `Map<tabId, sessionId>`
|
|
282
|
+
- Opening new chat tab = new `query()` call, captures new sessionId
|
|
283
|
+
- Switching tabs = just UI state, sessions persist on disk
|
|
284
|
+
- Resuming tab = `query({ options: { resume: savedSessionId } })`
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Remaining Questions
|
|
289
|
+
|
|
290
|
+
1. **Agent SDK + Go sidecar performance:** Spawning Node.js per session = memory overhead. Need to benchmark. Could pool sidecar processes.
|
|
291
|
+
2. **Agent SDK auth on VPS:** API key needed. How to securely store/inject on VPS deployment?
|
|
292
|
+
3. **V2 TypeScript SDK:** Preview available with `createSession()` pattern — more natural for multi-session. Worth tracking but unstable.
|
|
293
|
+
4. **Offline/PWA:** Agent SDK requires network. PWA caching useful for UI shell only, chat always needs connectivity.
|