@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.
Files changed (159) hide show
  1. package/.claude/agent-memory/tester/MEMORY.md +3 -0
  2. package/.claude/agent-memory/tester/project-ppm-test-conventions.md +32 -0
  3. package/.env.example +1 -0
  4. package/.github/workflows/release.yml +46 -0
  5. package/README.md +349 -0
  6. package/bun.lock +1217 -0
  7. package/components.json +21 -0
  8. package/docs/code-standards.md +574 -0
  9. package/docs/codebase-summary.md +294 -0
  10. package/docs/deployment-guide.md +631 -0
  11. package/docs/design-guidelines.md +661 -0
  12. package/docs/project-overview-pdr.md +142 -0
  13. package/docs/project-roadmap.md +400 -0
  14. package/docs/system-architecture.md +459 -0
  15. package/package.json +68 -0
  16. package/plans/260314-2009-ppm-implementation/phase-01-project-skeleton.md +81 -0
  17. package/plans/260314-2009-ppm-implementation/phase-02-backend-core.md +148 -0
  18. package/plans/260314-2009-ppm-implementation/phase-03-frontend-shell.md +256 -0
  19. package/plans/260314-2009-ppm-implementation/phase-04-file-explorer-editor.md +120 -0
  20. package/plans/260314-2009-ppm-implementation/phase-05-web-terminal.md +174 -0
  21. package/plans/260314-2009-ppm-implementation/phase-06-git-integration.md +244 -0
  22. package/plans/260314-2009-ppm-implementation/phase-07-ai-chat.md +242 -0
  23. package/plans/260314-2009-ppm-implementation/phase-08-cli-commands.md +143 -0
  24. package/plans/260314-2009-ppm-implementation/phase-09-pwa-build-deploy.md +209 -0
  25. package/plans/260314-2009-ppm-implementation/phase-10-testing.md +311 -0
  26. package/plans/260314-2009-ppm-implementation/plan.md +202 -0
  27. package/plans/260315-0356-project-scoped-api-refactor/phase-01-backend-project-router.md +145 -0
  28. package/plans/260315-0356-project-scoped-api-refactor/phase-02-frontend-api-migration.md +107 -0
  29. package/plans/260315-0356-project-scoped-api-refactor/phase-03-per-project-tabs.md +100 -0
  30. package/plans/260315-0356-project-scoped-api-refactor/phase-04-websocket-migration.md +66 -0
  31. package/plans/260315-0356-project-scoped-api-refactor/plan.md +87 -0
  32. package/plans/reports/brainstorm-260314-1938-final-techstack.md +342 -0
  33. package/plans/reports/docs-manager-260315-1314-documentation-creation.md +386 -0
  34. package/plans/reports/fullstack-developer-260314-2252-phase-02-backend-core.md +57 -0
  35. package/plans/reports/fullstack-developer-260314-2253-phase-03-frontend-shell.md +70 -0
  36. package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-api-terminal-ws.md +49 -0
  37. package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-explorer-editor-terminal.md +52 -0
  38. package/plans/reports/fullstack-developer-260314-2307-ai-chat-phase7.md +58 -0
  39. package/plans/reports/fullstack-developer-260314-2307-phase-06-git-integration.md +33 -0
  40. package/plans/reports/research-260314-1911-ppm-tech-stack.md +318 -0
  41. package/plans/reports/research-260314-1930-claude-code-integration.md +293 -0
  42. package/plans/reports/researcher-260314-2232-node-pty-bun-crash-analysis.md +305 -0
  43. package/plans/reports/researcher-260314-2232-ui-style.md +942 -0
  44. package/plans/reports/researcher-260315-0300-opcode-claude-interaction.md +745 -0
  45. package/plans/reports/researcher-260315-0303-opcode-deep-analysis.md +742 -0
  46. package/plans/reports/researcher-260315-0305-claude-agent-sdk-github-research.md +423 -0
  47. package/plans/reports/tester-260314-2053-initial-test-suite.md +81 -0
  48. package/ppm.example.yaml +14 -0
  49. package/repomix-output.xml +23745 -0
  50. package/scripts/build.ts +13 -0
  51. package/src/cli/commands/chat-cmd.ts +259 -0
  52. package/src/cli/commands/config-cmd.ts +121 -0
  53. package/src/cli/commands/git-cmd.ts +315 -0
  54. package/src/cli/commands/init.ts +57 -0
  55. package/src/cli/commands/open.ts +19 -0
  56. package/src/cli/commands/projects.ts +100 -0
  57. package/src/cli/commands/start.ts +3 -0
  58. package/src/cli/commands/stop.ts +33 -0
  59. package/src/cli/utils/project-resolver.ts +27 -0
  60. package/src/index.ts +59 -0
  61. package/src/providers/claude-agent-sdk.ts +499 -0
  62. package/src/providers/claude-binary-finder.ts +256 -0
  63. package/src/providers/claude-code-cli.ts +413 -0
  64. package/src/providers/claude-process-registry.ts +106 -0
  65. package/src/providers/mock-provider.ts +171 -0
  66. package/src/providers/provider.interface.ts +10 -0
  67. package/src/providers/registry.ts +45 -0
  68. package/src/server/helpers/resolve-project.ts +22 -0
  69. package/src/server/index.ts +181 -0
  70. package/src/server/middleware/auth.ts +30 -0
  71. package/src/server/routes/chat.ts +153 -0
  72. package/src/server/routes/files.ts +168 -0
  73. package/src/server/routes/git.ts +261 -0
  74. package/src/server/routes/project-scoped.ts +27 -0
  75. package/src/server/routes/projects.ts +57 -0
  76. package/src/server/routes/static.ts +26 -0
  77. package/src/server/ws/chat.ts +130 -0
  78. package/src/server/ws/terminal.ts +89 -0
  79. package/src/services/chat.service.ts +110 -0
  80. package/src/services/claude-usage.service.ts +113 -0
  81. package/src/services/config.service.ts +90 -0
  82. package/src/services/file.service.ts +261 -0
  83. package/src/services/git-dirs.service.ts +112 -0
  84. package/src/services/git.service.ts +372 -0
  85. package/src/services/project.service.ts +107 -0
  86. package/src/services/slash-items.service.ts +184 -0
  87. package/src/services/terminal.service.ts +212 -0
  88. package/src/types/api.ts +37 -0
  89. package/src/types/chat.ts +92 -0
  90. package/src/types/config.ts +41 -0
  91. package/src/types/git.ts +50 -0
  92. package/src/types/project.ts +18 -0
  93. package/src/types/terminal.ts +20 -0
  94. package/src/web/app.tsx +168 -0
  95. package/src/web/components/auth/login-screen.tsx +88 -0
  96. package/src/web/components/chat/attachment-chips.tsx +55 -0
  97. package/src/web/components/chat/chat-placeholder.tsx +10 -0
  98. package/src/web/components/chat/chat-tab.tsx +301 -0
  99. package/src/web/components/chat/file-picker.tsx +126 -0
  100. package/src/web/components/chat/message-input.tsx +420 -0
  101. package/src/web/components/chat/message-list.tsx +838 -0
  102. package/src/web/components/chat/session-picker.tsx +139 -0
  103. package/src/web/components/chat/slash-command-picker.tsx +135 -0
  104. package/src/web/components/chat/usage-badge.tsx +186 -0
  105. package/src/web/components/editor/code-editor.tsx +329 -0
  106. package/src/web/components/editor/diff-viewer.tsx +276 -0
  107. package/src/web/components/editor/editor-placeholder.tsx +10 -0
  108. package/src/web/components/explorer/file-actions.tsx +191 -0
  109. package/src/web/components/explorer/file-tree.tsx +298 -0
  110. package/src/web/components/git/git-graph.tsx +727 -0
  111. package/src/web/components/git/git-placeholder.tsx +55 -0
  112. package/src/web/components/git/git-status-panel.tsx +850 -0
  113. package/src/web/components/layout/mobile-drawer.tsx +137 -0
  114. package/src/web/components/layout/mobile-nav.tsx +103 -0
  115. package/src/web/components/layout/sidebar.tsx +90 -0
  116. package/src/web/components/layout/tab-bar.tsx +152 -0
  117. package/src/web/components/layout/tab-content.tsx +85 -0
  118. package/src/web/components/projects/dir-suggest.tsx +152 -0
  119. package/src/web/components/projects/project-list.tsx +187 -0
  120. package/src/web/components/settings/settings-tab.tsx +57 -0
  121. package/src/web/components/terminal/terminal-placeholder.tsx +10 -0
  122. package/src/web/components/terminal/terminal-tab.tsx +133 -0
  123. package/src/web/components/ui/button.tsx +64 -0
  124. package/src/web/components/ui/context-menu.tsx +250 -0
  125. package/src/web/components/ui/dialog.tsx +156 -0
  126. package/src/web/components/ui/dropdown-menu.tsx +257 -0
  127. package/src/web/components/ui/input.tsx +21 -0
  128. package/src/web/components/ui/scroll-area.tsx +56 -0
  129. package/src/web/components/ui/separator.tsx +26 -0
  130. package/src/web/components/ui/sonner.tsx +40 -0
  131. package/src/web/components/ui/tabs.tsx +91 -0
  132. package/src/web/components/ui/tooltip.tsx +57 -0
  133. package/src/web/hooks/use-chat.ts +420 -0
  134. package/src/web/hooks/use-terminal.ts +182 -0
  135. package/src/web/hooks/use-url-sync.ts +66 -0
  136. package/src/web/hooks/use-websocket.ts +48 -0
  137. package/src/web/index.html +16 -0
  138. package/src/web/lib/api-client.ts +90 -0
  139. package/src/web/lib/file-support.ts +68 -0
  140. package/src/web/lib/utils.ts +6 -0
  141. package/src/web/lib/ws-client.ts +100 -0
  142. package/src/web/main.tsx +10 -0
  143. package/src/web/public/icon-192.svg +5 -0
  144. package/src/web/public/icon-512.svg +5 -0
  145. package/src/web/stores/file-store.ts +81 -0
  146. package/src/web/stores/project-store.ts +50 -0
  147. package/src/web/stores/settings-store.ts +65 -0
  148. package/src/web/stores/tab-store.ts +187 -0
  149. package/src/web/styles/globals.css +227 -0
  150. package/src/web/vite-env.d.ts +1 -0
  151. package/tests/integration/api/chat-routes.test.ts +95 -0
  152. package/tests/integration/claude-agent-sdk-integration.test.ts +228 -0
  153. package/tests/integration/ws/chat-websocket.test.ts +312 -0
  154. package/tests/test-setup.ts +5 -0
  155. package/tests/unit/providers/claude-agent-sdk.test.ts +339 -0
  156. package/tests/unit/providers/mock-provider.test.ts +143 -0
  157. package/tests/unit/services/chat-service.test.ts +100 -0
  158. package/tsconfig.json +32 -0
  159. 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.