@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,87 @@
1
+ ---
2
+ title: "Project-scoped API routes + per-project tab storage"
3
+ description: "Refactor all APIs under /api/project/:projectName/... and store tabs per-project"
4
+ status: pending
5
+ priority: P1
6
+ effort: 6h
7
+ branch: v2-fresh-start
8
+ tags: [refactor, api, tabs, project-scope]
9
+ created: 2026-03-15
10
+ ---
11
+
12
+ # Project-Scoped API Refactor
13
+
14
+ ## Overview
15
+
16
+ Two changes: (1) move all API routes under `/api/project/:projectName/...` prefix, (2) persist tabs per-project in Zustand so switching projects restores different tab sets.
17
+
18
+ ## Current State Analysis
19
+
20
+ ### Backend Route Structure
21
+ | Module | Current Mount | Project Param |
22
+ |--------|--------------|---------------|
23
+ | `chat.ts` | `/api/chat/...` | body/query (`projectName`, `dir`) |
24
+ | `git.ts` | `/api/git/...` | mixed: URL param (`:project`) for GET, body (`project`) for POST |
25
+ | `files.ts` | `/api/files/...` | URL param (`:project`) |
26
+ | `projects.ts` | `/api/projects` | N/A (lists all) |
27
+ | terminal WS | `/ws/terminal/:id?project=` | query param |
28
+ | chat WS | `/ws/chat/:sessionId` | none |
29
+
30
+ ### Frontend API Calls (all files)
31
+ - `api-client.ts` -- generic fetch wrapper, no project prefix
32
+ - `chat-tab.tsx` -- `/api/chat/sessions` POST
33
+ - `session-picker.tsx` -- `/api/chat/sessions` GET, DELETE
34
+ - `use-chat.ts` -- `/api/chat/sessions/:id/messages` GET, `/ws/chat/:id` WS
35
+ - `git-graph.tsx` -- `/api/git/graph/:project`, `/api/git/*` POST with body.project
36
+ - `git-status-panel.tsx` -- `/api/git/status/:project`, POST with body.project
37
+ - `file-store.ts` -- `/api/files/tree/:project`
38
+ - `code-editor.tsx` -- `/api/files/read/:project`, `/api/files/write/:project`
39
+ - `file-actions.tsx` -- `/api/files/create/:project`, etc.
40
+ - `diff-viewer.tsx` -- `/api/files/compare/:project`, `/api/git/file-diff/:project`
41
+ - `use-terminal.ts` -- `/ws/terminal/:id?project=`
42
+
43
+ ### Tab Store
44
+ - Single global `ppm-tabs` key in localStorage
45
+ - No project awareness; all tabs shared across projects
46
+
47
+ ---
48
+
49
+ ## Target Architecture
50
+
51
+ ### New URL Pattern
52
+ ```
53
+ /api/project/:projectName/chat/...
54
+ /api/project/:projectName/git/...
55
+ /api/project/:projectName/files/...
56
+ /ws/project/:projectName/terminal/:id
57
+ /ws/project/:projectName/chat/:sessionId
58
+ ```
59
+
60
+ `/api/projects` and `/api/auth/*` and `/api/health` stay global (no project scope).
61
+
62
+ ### Key Design Decisions
63
+
64
+ 1. **Hono middleware extracts `:projectName`** -- single `projectRouter` sub-app with middleware that resolves project path once, sets it on context. All child routes read from context instead of calling `resolveProjectPath` themselves.
65
+ 2. **Git POST routes drop `project` from body** -- project comes from URL; body only carries action-specific data.
66
+ 3. **Chat routes get project from URL** -- no more `dir` query or `projectName` body field.
67
+ 4. **Tab store keyed by project name** -- `ppm-tabs-{projectName}` in localStorage. On project switch, store swaps persisted state.
68
+ 5. **ApiClient gets `projectUrl(name)` helper** -- returns `/api/project/${encodeURIComponent(name)}` prefix; all feature calls use it.
69
+
70
+ ---
71
+
72
+ ## Phases
73
+
74
+ - [Phase 1: Backend project-scoped router](./phase-01-backend-project-router.md) -- 2h
75
+ - [Phase 2: Frontend API client + calls](./phase-02-frontend-api-migration.md) -- 2h
76
+ - [Phase 3: Per-project tab storage](./phase-03-per-project-tabs.md) -- 1.5h
77
+ - [Phase 4: WebSocket URL migration](./phase-04-websocket-migration.md) -- 0.5h
78
+
79
+ ## Dependencies
80
+ - Phase 2 depends on Phase 1 (new routes must exist)
81
+ - Phase 3 is independent (can parallel with Phase 2)
82
+ - Phase 4 depends on Phase 1 (WS upgrade paths change in server index)
83
+
84
+ ## Risk Assessment
85
+ - **Breaking change**: All frontend API calls change. No backward compat needed since this is a fresh v2 branch.
86
+ - **Chat sessions are currently global**: After refactor, sessions filter by project via URL. Existing sessions in storage may lack project association -- migration not needed since v2-fresh-start has no prod data.
87
+ - **Terminal WS path change**: Must update both foreground and daemon `Bun.serve()` blocks in `src/server/index.ts`.
@@ -0,0 +1,342 @@
1
+ # PPM Final Tech Stack Decision
2
+
3
+ **Date:** 2026-03-14
4
+ **Status:** Approved
5
+
6
+ ---
7
+
8
+ ## Project Overview
9
+
10
+ PPM (Personal Project Manager) — mobile-first web-based tool to manage code projects from phone/browser. Runs as CLI, serves web UI, deployable to VPS or accessible via Tailscale.
11
+
12
+ ---
13
+
14
+ ## Requirements
15
+
16
+ ### Core
17
+
18
+ - **Mobile-first UI:** Ưu tiên mobile UX, có thể làm việc hoàn toàn từ điện thoại
19
+ - **CLI gateway:** Chạy background như daemon, serve web UI (giống openclaw pattern)
20
+ - **Tab system:** Mọi thứ mở trong tab giống VSCode — terminal, chat, editor, git graph, git diff, settings
21
+ - **PWA:** Installable trên điện thoại, offline UI shell caching
22
+
23
+ ### Project Management
24
+
25
+ - **Project list:** Xem các folder project đã add vào
26
+ - **Auto-scan:** Khi `ppm init`, quét folder có `.git` và gợi ý add vào
27
+ - **File explorer:** Duyệt file tree trong project
28
+ - CRUD: tạo, xóa, rename, move files/folders
29
+ - Select 2 files để compare (diff) giống VSCode
30
+ - Drag & drop support (nice-to-have)
31
+
32
+ ### Code Editor
33
+
34
+ - **Syntax highlighting:** Xem và sửa code trong browser
35
+ - **Autocomplete:** Không bắt buộc nhưng dùng CM6 built-in autocomplete nếu có sẵn
36
+ - **File compare:** Mở diff view khi select 2 files từ explorer
37
+
38
+ ### Git Integration
39
+
40
+ - **Git graph:** Visualize commit history — giống [vscode-git-graph](https://github.com/mhutchie/vscode-git-graph)
41
+ - **Rendering:** SVG-based (same approach as vscode-git-graph: SVG paths for branch lines, SVG circles for commit nodes, color-coded lanes)
42
+ - **Data:** `git log --format=<custom>` + `git branch` + `git for-each-ref` (parsed server-side, sent as JSON)
43
+ - **Context menu actions on commits:** Checkout, Cherry Pick, Revert, Create Branch, Create Tag, Copy Hash
44
+ - **Context menu actions on branches:** Checkout, Merge into current, Delete, Rename, Push, Pull, Rebase
45
+ - **PR:** Mở browser URL tới GitHub/GitLab create PR page (không dùng `gh` CLI)
46
+ - **Branch visualization:** Lane allocation algorithm — mỗi branch 1 lane, color rotation, merge/fork lines
47
+ - **Git diff:** Xem thay đổi giữa commits/branches (CodeMirror 6 merge view)
48
+ - **Git status panel:**
49
+ - Xem files changed (modified, added, deleted)
50
+ - Xem files staged vs unstaged
51
+ - Stage/unstage individual files
52
+ - Commit input box + commit button
53
+ - Push/pull buttons
54
+ - **Git blame:** (nice-to-have) inline blame annotations
55
+
56
+ ### CLI (AI/Automation-friendly)
57
+
58
+ - **Mục đích:** CLI cho AI agents và automation điều khiển PPM, không cần CLI cho mọi feature
59
+ - **Project resolution:** CWD auto-detect (nếu trong registered project) + `-p <name>` flag override
60
+ ```bash
61
+ ppm git status # auto-detect từ CWD
62
+ ppm git status -p my-app # explicit project
63
+ ```
64
+
65
+ **CLI commands (chỉ những gì AI cần):**
66
+ - `ppm init` — onboarding wizard
67
+ - `ppm start [-d] [-c config.yaml]` / `ppm stop` — server lifecycle
68
+ - `ppm open` — mở browser tới web UI
69
+ - `ppm projects list|add|remove`
70
+ - `ppm config get|set`
71
+ - `ppm git status|log|diff` — đọc git state
72
+ - `ppm git stage|unstage|commit|push|pull` — git write actions
73
+ - `ppm git branch create|checkout|delete|merge`
74
+ - `ppm chat create|list|resume|delete|send` — AI-to-AI orchestration
75
+
76
+ **Không cần CLI (web-only hoặc đã có native CLI):**
77
+ - File operations → AI dùng `ls`, `cat`, `mv`, `rm` trực tiếp
78
+ - Terminal management → web-only feature
79
+ - Git graph visual → web-only
80
+ - Cherry-pick, revert, tag, rebase → AI dùng `git` CLI trực tiếp
81
+
82
+ ### Terminal
83
+
84
+ - **Web terminal:** Mở terminal thật trong tab, tương tác đầy đủ với shell
85
+
86
+ ### AI Chat
87
+
88
+ - **Claude Code integration:** Tương tác giống hệt Claude Code extension trên VSCode
89
+ - **Multi-provider:** Generic interface, bắt đầu với Claude, mở rộng sang provider khác sau
90
+ - **Session management:** CRUD sessions — tạo, xem, resume, xóa
91
+ - **Multi-tab chat:** Mở nhiều chat sessions cùng lúc trên nhiều tab
92
+ - **Tool approvals:** Hiển thị và xử lý tool permission requests trong UI
93
+
94
+ ### Deployment
95
+
96
+ - **Local:** `ppm init` → onboarding wizard → tạo config → `ppm start`
97
+ - **VPS:** Copy binary + config file → `ppm start -c config.yaml` (không cần onboarding)
98
+ - **Tailscale:** Chạy local, truy cập từ xa qua Tailscale IP
99
+ - **Single binary:** Deploy dễ dàng, không cần runtime
100
+
101
+ ### Open Source
102
+
103
+ - **OSS-friendly:** MIT/Apache 2.0 license
104
+ - **Cross-platform:** Build binaries cho Linux, macOS (ARM + x64)
105
+ - **Extensible:** Community có thể contribute AI providers, themes, plugins
106
+
107
+ ---
108
+
109
+ ## Tech Stack
110
+
111
+ ### Backend
112
+
113
+
114
+ | Component | Technology | Version | Why |
115
+ | -------------- | ---------------------------------- | ------- | ------------------------------------------------------------------------------------------ |
116
+ | Runtime | **Bun** | 1.2+ | Single binary (`bun build --compile`), native TS, fast startup (~30ms), built-in WebSocket |
117
+ | HTTP Framework | **Hono** | 4.x | 14KB, fastest TS framework, runtime-agnostic |
118
+ | CLI | **Commander.js** | 13.x | Simple, proven CLI framework |
119
+ | Config | **js-yaml** | 4.x | Parse ppm.yaml config |
120
+ | PTY (terminal) | **node-pty** | 1.x | Spawn real shell processes, battle-tested |
121
+ | Git | **simple-git** | 3.x | Wrapper over git binary, simple API |
122
+ | AI Chat | **@anthropic-ai/claude-agent-sdk** | latest | Claude Code as library — first provider |
123
+ | WebSocket | **Bun built-in** | — | No extra dependency needed |
124
+
125
+
126
+ ### Frontend
127
+
128
+
129
+ | Component | Technology | Version | Why |
130
+ | ---------- | -------------------------- | ------- | -------------------------------------------- |
131
+ | Framework | **React** | 19.x | Largest ecosystem, Agent SDK demos use React |
132
+ | Build | **Vite** | 6.x | Fast HMR, tree-shaking, code splitting |
133
+ | Styling | **Tailwind CSS** | 4.x | Mobile-first utility classes |
134
+ | Components | **shadcn/ui** | latest | Accessible, customizable, Radix UI based |
135
+ | State | **zustand** | 5.x | Lightweight (~1KB), simple API |
136
+ | Editor | **CodeMirror 6** | 6.x | Mobile-first (300KB), modular, touch support |
137
+ | Terminal | **xterm.js** | 5.x | Industry standard (VSCode uses it) |
138
+ | Git Diff | **diff2html** | 3.x | Parse unified diff → HTML |
139
+ | Git Graph | **Custom SVG** | — | No good maintained lib, build with basic SVG |
140
+ | PWA | **vite-plugin-pwa** | latest | Service worker, offline shell, installable |
141
+ | Panels | **react-resizable-panels** | latest | Split panes for tab layout |
142
+
143
+
144
+ ### Infrastructure
145
+
146
+
147
+ | Component | Technology | Why |
148
+ | ----------------- | ------------------------- | ------------------------------------------------- |
149
+ | Deploy (binary) | `bun build --compile` | Single executable, copy to VPS |
150
+ | Deploy (fallback) | Docker | If native addon (node-pty) fails with bun compile |
151
+ | Background daemon | Built-in (detach process) | `ppm start -d` |
152
+ | Remote access | Tailscale / direct VPS | Zero config networking |
153
+ | Auth | Simple token header | Extensible to OAuth later |
154
+
155
+
156
+ ---
157
+
158
+ ## Architecture
159
+
160
+ ```
161
+ ppm (single binary)
162
+
163
+ ├── CLI Layer (Commander.js) — calls same Service Layer as API
164
+ │ │ Project resolution: CWD auto-detect + `-p <name>` override
165
+ │ ├── ppm init / start / stop / open
166
+ │ ├── ppm projects list|add|remove
167
+ │ ├── ppm config get|set
168
+ │ ├── ppm git status|log|diff|stage|unstage|commit|push|pull
169
+ │ ├── ppm git branch create|checkout|delete|merge
170
+ │ └── ppm chat create|list|resume|delete|send
171
+
172
+ ├── Server Layer (Hono + Bun) — thin wrapper over Service Layer
173
+ │ ├── GET / # Serve React SPA (embedded)
174
+ │ ├── GET /api/projects # List managed projects
175
+ │ ├── CRUD /api/files/* # File tree + read/write/create/delete/rename/move
176
+ │ ├── GET /api/git/* # Git status, log, diff, graph
177
+ │ ├── POST /api/git/* # Stage, unstage, commit, push, pull, branch ops
178
+ │ ├── WS /ws/terminal/:id # PTY sessions (xterm.js ↔ node-pty)
179
+ │ └── WS /ws/chat/:id # AI chat sessions (streaming)
180
+
181
+ ├── Service Layer (shared business logic)
182
+ │ ├── project.service.ts # Project CRUD
183
+ │ ├── file.service.ts # File operations
184
+ │ ├── git.service.ts # All git operations (simple-git)
185
+ │ ├── terminal.service.ts # PTY management
186
+ │ └── chat.service.ts # AI provider sessions
187
+
188
+ ├── AI Provider Layer (generic)
189
+ │ ├── provider.interface.ts # AIProvider interface
190
+ │ ├── claude-agent-sdk.ts # Claude adapter (first)
191
+ │ ├── cli-subprocess.ts # Generic CLI adapter (future: Gemini, Aider...)
192
+ │ └── registry.ts # Provider registry + factory
193
+
194
+ ├── Terminal Manager
195
+ │ └── node-pty pool ↔ WebSocket bridge
196
+
197
+ ├── Git Service (simple-git)
198
+ │ └── status, log, diff, graph data extraction
199
+
200
+ └── Config (js-yaml)
201
+ └── ppm.yaml
202
+ ```
203
+
204
+ ### AI Provider Interface (generic, multi-provider ready)
205
+
206
+ ```typescript
207
+ interface AIProvider {
208
+ id: string;
209
+ name: string;
210
+ createSession(config: SessionConfig): Promise<Session>;
211
+ resumeSession(sessionId: string): Promise<Session>;
212
+ listSessions(): Promise<SessionInfo[]>;
213
+ deleteSession(sessionId: string): Promise<void>;
214
+ sendMessage(sessionId: string, message: string): AsyncIterable<ChatEvent>;
215
+ onToolApproval?: (callback: ToolApprovalHandler) => void;
216
+ }
217
+
218
+ type ChatEvent =
219
+ | { type: 'text'; content: string }
220
+ | { type: 'tool_use'; tool: string; input: any }
221
+ | { type: 'tool_result'; output: string }
222
+ | { type: 'approval_request'; tool: string; input: any }
223
+ | { type: 'error'; message: string }
224
+ | { type: 'done'; sessionId: string }
225
+ ```
226
+
227
+ ### Frontend Tab System
228
+
229
+ ```
230
+ ┌─────────────────────────────────────────────┐
231
+ │ [Projects] [Terminal 1] [Chat: main] [app.ts]│
232
+ ├─────────────────────────────────────────────┤
233
+ │ Active Tab Content │
234
+ │ (lazy-loaded per tab type) │
235
+ └─────────────────────────────────────────────┘
236
+
237
+ Tab types: projects | terminal | chat | editor | git-graph | git-diff | settings
238
+ Each tab = { id, type, title, metadata, component }
239
+ State managed by zustand
240
+ Mobile: scrollable tab bar, swipe gestures
241
+ ```
242
+
243
+ ---
244
+
245
+ ## Config File (ppm.yaml)
246
+
247
+ ```yaml
248
+ port: 8080
249
+ host: 0.0.0.0
250
+ auth:
251
+ enabled: true
252
+ token: "your-secret-token"
253
+ projects:
254
+ - path: /home/user/project-a
255
+ name: Project A
256
+ - path: /home/user/project-b
257
+ name: Project B
258
+ ai:
259
+ default_provider: claude
260
+ providers:
261
+ claude:
262
+ type: agent-sdk
263
+ api_key_env: ANTHROPIC_API_KEY # Read from env var
264
+ # Future:
265
+ # gemini:
266
+ # type: cli
267
+ # command: gemini
268
+ ```
269
+
270
+ ---
271
+
272
+ ## Key Design Decisions
273
+
274
+ 1. **Bun over Go:** Agent SDK is TypeScript-only → single runtime, no sidecar complexity
275
+ 2. **Bun over Node.js:** `bun build --compile` for single binary, 3-5x faster startup
276
+ 3. **Hono over Express:** 14KB vs 200KB+, faster, modern API
277
+ 4. **CodeMirror 6 over Monaco:** Mobile-first (300KB vs 5-10MB), touch native
278
+ 5. **simple-git over go-git:** Same runtime, proven wrapper, basic ops sufficient
279
+ 6. **Provider adapter pattern:** Start with Claude, extend to any AI tool later
280
+ 7. **zustand over Redux:** 1KB, zero boilerplate, perfect for tab state
281
+ 8. **PWA:** Installable on phone, offline UI shell caching
282
+ 9. **WebSocket only (no Socket.IO, no SSE):** Terminal requires bidirectional binary; chat needs bidirectional for tool approvals; Bun has WS built-in = zero deps, one protocol for everything
283
+ 10. **Open-source:** MIT/Apache 2.0 license, CI/CD for cross-platform binaries, contributor-friendly stack
284
+
285
+ ---
286
+
287
+ ## Risk Register
288
+
289
+
290
+ | Risk | Impact | Mitigation |
291
+ | ----------------------------------------- | ------------------------ | ---------------------------------------------------------------- |
292
+ | node-pty fails with `bun build --compile` | Can't ship single binary | Fallback: Docker container or Node.js runtime |
293
+ | Agent SDK incompatible with Bun | Chat feature broken | Test early (Phase 1). Fallback: run SDK in Node.js child process |
294
+ | CodeMirror 6 keyboard issues on iOS | Bad mobile editing UX | Test early on real device. CM6 known to work well on mobile |
295
+ | WebSocket drops on mobile network | Lost terminal/chat state | Auto-reconnect logic + session resume |
296
+
297
+
298
+ ---
299
+
300
+ ## Realtime Communication
301
+
302
+ **Decision: WebSocket only** (no Socket.IO, no SSE)
303
+
304
+
305
+ | Connection | Direction | Protocol |
306
+ | ------------------------------------ | --------------------- | --------------------- |
307
+ | Terminal (xterm.js ↔ PTY) | Bidirectional, binary | WS `/ws/terminal/:id` |
308
+ | AI Chat (streaming + tool approvals) | Bidirectional | WS `/ws/chat/:id` |
309
+ | File/git watcher (optional) | Server→Client | WS `/ws/events` |
310
+
311
+
312
+ **Why not Socket.IO:** +45KB client bundle, rooms/namespaces not needed, overkill.
313
+ **Why not SSE:** Terminal & chat both need bidirectional. Mixing SSE+HTTP POST = more complexity than single WS.
314
+ **Why WebSocket:** Bun built-in (zero deps), one protocol for all realtime, binary frame support for terminal.
315
+
316
+ ---
317
+
318
+ ## Open Source Considerations
319
+
320
+
321
+ | Item | Detail |
322
+ | -------------- | ----------------------------------------------------------------------- |
323
+ | License | MIT or Apache 2.0 |
324
+ | Config | `.env.example` + `ppm.yaml` schema validation |
325
+ | CI/CD | GitHub Actions — build binaries for linux-x64, darwin-arm64, darwin-x64 |
326
+ | Cross-platform | `bun build --compile --target=bun-{platform}-{arch}` |
327
+ | Plugin docs | Guide for contributing new AI providers |
328
+ | node-pty | Prebuilt binaries in CI for each platform |
329
+
330
+
331
+ ---
332
+
333
+ ## References
334
+
335
+ - [Tech stack research](../reports/research-260314-1911-ppm-tech-stack.md)
336
+ - [Claude Code integration research](../reports/research-260314-1930-claude-code-integration.md)
337
+ - [Claude Agent SDK docs](https://platform.claude.com/docs/en/agent-sdk/overview)
338
+ - [Hono](https://hono.dev)
339
+ - [CodeMirror 6](https://codemirror.net)
340
+ - [xterm.js](https://xtermjs.org)
341
+ - [simple-git](https://github.com/steveukx/git-js)
342
+