@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,459 @@
1
+ # PPM System Architecture
2
+
3
+ ## High-Level Architecture
4
+
5
+ ```
6
+ ┌──────────────────────────────────────────────────────────────────────┐
7
+ │ User Devices │
8
+ │ ┌─────────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │
9
+ │ │ Desktop/Tab │ │ Mobile/iPad │ │ Terminal (CLI mode) │ │
10
+ │ │ Web Browser │ │ Web Browser │ │ STDIN → ppm chat │ │
11
+ │ └────────┬────────┘ └──────┬───────┘ └────────────┬─────────────┘ │
12
+ │ │ │ │ │
13
+ │ └───────────────────┼────────────────────────┘ │
14
+ │ │ HTTP/WebSocket │
15
+ ├──────────────────────────────┼────────────────────────────────────────┤
16
+ │ PPM Server (Bun) │
17
+ │ ┌────────────────────────────────────────────────────────────────┐ │
18
+ │ │ Hono HTTP Framework (Port 8080) │ │
19
+ │ ├────────────────────────────────────────────────────────────────┤ │
20
+ │ │ Routes (src/server/routes/) │ │
21
+ │ │ ┌──────────────────┐ ┌──────────────────┐ ┌─────────────┐ │ │
22
+ │ │ │ /api/projects │ │ /api/project/:n/ │ │ /api/health │ │ │
23
+ │ │ │ (CRUD projects) │ │ (scoped routes) │ │ (status) │ │ │
24
+ │ │ └──────────────────┘ └──────────────────┘ └─────────────┘ │ │
25
+ │ ├────────────────────────────────────────────────────────────────┤ │
26
+ │ │ Services (src/services/) │ │
27
+ │ │ ┌───────────────────────────────────────────────────────────┐│ │
28
+ │ │ │ ChatService │ GitService │ FileService │ TerminalService ││ │
29
+ │ │ │ (streaming │ (simple- │ (read/write │ (PTY/shell) ││ │
30
+ │ │ │ messages) │ git) │ files) │ (Bun.spawn) ││ │
31
+ │ │ └───────────────────────────────────────────────────────────┘│ │
32
+ │ ├────────────────────────────────────────────────────────────────┤ │
33
+ │ │ Providers (src/providers/) │ │
34
+ │ │ ┌──────────────────────────────────────────────────────────┐ │ │
35
+ │ │ │ ProviderRegistry (routes to active AI provider) │ │ │
36
+ │ │ │ ┌───────────────────────┬──────────────────────────┐ │ │ │
37
+ │ │ │ │ claude-agent-sdk │ claude-code-cli (CLI) │ │ │ │
38
+ │ │ │ │ @anthropic/SDK (prim) │ Fallback subprocess │ │ │ │
39
+ │ │ │ └───────────────────────┴──────────────────────────┘ │ │ │
40
+ │ │ └──────────────────────────────────────────────────────────┘ │ │
41
+ │ └────────────────────────────────────────────────────────────────┘ │
42
+ │ │
43
+ │ Config & State (src/services/) │
44
+ │ ┌──────────────────┐ ┌──────────────────┐ ┌─────────────────┐ │
45
+ │ │ ppm.yaml │ │ Git Repos │ │ Session Storage │ │
46
+ │ │ (projects list) │ │ (local disk) │ │ (in-memory only)│ │
47
+ │ │ (auth token) │ │ │ │ │ │
48
+ │ └──────────────────┘ └──────────────────┘ └─────────────────┘ │
49
+ └──────────────────────────────────────────────────────────────────────┘
50
+ ↓↑
51
+ ┌────────────────────────────────────────────────┐
52
+ │ Filesystem Access (Local Only) │
53
+ │ • Project directories (git repos) │
54
+ │ • File read/write operations │
55
+ │ • Config file (ppm.yaml) │
56
+ └────────────────────────────────────────────────┘
57
+ ```
58
+
59
+ ## Layer Descriptions
60
+
61
+ ### Presentation Layer (Browser/CLI)
62
+ **Components:** React frontend + CLI commands
63
+
64
+ **Responsibilities:**
65
+ - Render UI for file explorer, editor, terminal, chat
66
+ - Capture user input (text, file uploads, terminal commands)
67
+ - Display streaming responses, terminal output
68
+ - Handle authentication (token in localStorage)
69
+
70
+ **Key Files:**
71
+ - `src/web/app.tsx` — Root React component
72
+ - `src/web/components/` — UI components
73
+ - `src/cli/commands/` — CLI command handlers
74
+
75
+ ---
76
+
77
+ ### HTTP API Layer (Hono)
78
+ **Component:** Hono framework, request routing
79
+
80
+ **Responsibilities:**
81
+ - Parse HTTP requests, validate tokens
82
+ - Route to correct handler (projects, chat, git, files)
83
+ - Format responses in `ApiResponse` envelope
84
+ - Handle WebSocket upgrades
85
+
86
+ **Key Files:**
87
+ - `src/server/index.ts` — Server setup, middleware chain
88
+ - `src/server/routes/projects.ts` — Project CRUD
89
+ - `src/server/routes/project-scoped.ts` — Mount per-project routes
90
+ - `src/server/middleware/auth.ts` — Token validation
91
+
92
+ **Routes:**
93
+ ```
94
+ GET /api/health → Health check
95
+ GET /api/auth/check → Verify auth token
96
+ POST /api/projects → Create project
97
+ GET /api/projects → List projects
98
+ DELETE /api/projects/:name → Delete project
99
+ GET /api/project/:name/chat/sessions → List sessions
100
+ POST /api/project/:name/chat/sessions → Create session
101
+ GET /api/project/:name/chat/sessions/:id/messages → Get history
102
+ DELETE /api/project/:name/chat/sessions/:id → Delete session
103
+ GET /api/project/:name/git/status → Git status
104
+ GET /api/project/:name/git/diff → Diff
105
+ POST /api/project/:name/git/stage → Stage file
106
+ POST /api/project/:name/git/commit → Commit
107
+ GET /api/project/:name/files/tree → Directory tree
108
+ GET /api/project/:name/files/raw → File content
109
+ PUT /api/project/:name/files/write → Write file
110
+ WS /ws/project/:name/chat/:sessionId → Chat streaming
111
+ WS /ws/project/:name/terminal/:id → Terminal I/O
112
+ ```
113
+
114
+ ---
115
+
116
+ ### Service Layer (Business Logic)
117
+ **Components:** Singleton service modules
118
+
119
+ **Responsibilities:**
120
+ - Implement core business logic (chat, git, files, terminal)
121
+ - Manage dependencies (file paths, command execution)
122
+ - Coordinate between providers and data sources
123
+ - Validate input and propagate errors
124
+
125
+ **Services:**
126
+
127
+ | Service | Purpose | Key Methods |
128
+ |---------|---------|-------------|
129
+ | **ChatService** | Session management, message streaming | createSession, streamMessage, getHistory |
130
+ | **GitService** | Git command execution | status, diff, commit, stage, branch |
131
+ | **FileService** | File operations with validation | read, write, tree, delete, mkdir |
132
+ | **TerminalService** | PTY lifecycle, shell spawning | spawn, write, kill |
133
+ | **ProjectService** | Project registry (YAML) | add, remove, get, list |
134
+ | **ConfigService** | Config file management | load, save, getToken |
135
+ | **ProviderRegistry** | AI provider routing | getDefault, send (delegates) |
136
+
137
+ **Key Files:** `src/services/*.service.ts`
138
+
139
+ ---
140
+
141
+ ### Provider Layer (AI Adapters)
142
+ **Component:** Provider interface + implementations
143
+
144
+ **Responsibilities:**
145
+ - Abstract AI model differences behind common interface
146
+ - Stream responses as async generators
147
+ - Handle tool use and approval flows
148
+ - Track token usage
149
+
150
+ **Interface (src/providers/provider.interface.ts):**
151
+ ```typescript
152
+ interface AIProvider {
153
+ createSession(): Promise<Session>;
154
+ sendMessage(sessionId: string, message: string, context?: FileContext[]): AsyncIterable<ChatEvent>;
155
+ onToolApproval(sessionId: string, requestId: string, approved: boolean, data?: unknown): Promise<void>;
156
+ }
157
+ ```
158
+
159
+ **Implementations:**
160
+ - **claude-agent-sdk** (Primary) — @anthropic-ai/claude-agent-sdk, streaming, tool use
161
+ - **claude-code-cli** (Fallback) — Claude CLI subprocess, for offline environments
162
+ - **mock-provider** (Testing) — Returns canned responses
163
+
164
+ ---
165
+
166
+ ### Data Access Layer (Filesystem + Git)
167
+ **Components:** Direct filesystem access, simple-git wrapper
168
+
169
+ **Responsibilities:**
170
+ - Read/write project files with path validation
171
+ - Execute git commands via simple-git
172
+ - Cache directory listings
173
+ - Enforce security (no parent directory access)
174
+
175
+ **Key Patterns:**
176
+ - Path validation: `projectPath/relativePath` only, reject `..`
177
+ - Caching: Directory trees cached with TTL
178
+ - Error handling: Descriptive messages (file not found, permission denied)
179
+
180
+ ---
181
+
182
+ ### State Management (Frontend)
183
+ **Component:** Zustand stores in browser
184
+
185
+ **Stores:**
186
+ - **projectStore** — Active project, project list
187
+ - **tabStore** — Open tabs (chat, editor, git, terminal)
188
+ - **fileStore** — Selected files, editor content
189
+ - **settingsStore** — Auth token, theme preference
190
+
191
+ **Pattern:** Selectors for subscriptions (only re-render affected components)
192
+
193
+ ```typescript
194
+ const messages = chatStore((s) => s.messages); // Subscribe to messages only
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Communication Protocols
200
+
201
+ ### REST API (Request/Response)
202
+ **Protocol:** HTTP/1.1 with JSON
203
+
204
+ **Pattern:**
205
+ 1. Client sends request with auth token header
206
+ 2. Server validates token (middleware)
207
+ 3. Service processes request
208
+ 4. Response formatted as `ApiResponse<T>` envelope
209
+ 5. HTTP status set (200, 400, 404, 500)
210
+
211
+ **Example:**
212
+ ```
213
+ POST /api/project/my-project/chat/sessions/abc/messages HTTP/1.1
214
+ Authorization: Bearer <token>
215
+ Content-Type: application/json
216
+
217
+ { "content": "What does this code do?" }
218
+
219
+ HTTP/1.1 200 OK
220
+ {
221
+ "ok": true,
222
+ "data": {
223
+ "messageId": "msg-123",
224
+ "sessionId": "abc"
225
+ }
226
+ }
227
+ ```
228
+
229
+ ---
230
+
231
+ ### WebSocket (Streaming)
232
+ **Protocol:** WebSocket over HTTP/1.1
233
+
234
+ **Chat Streaming Flow:**
235
+ 1. Client connects: `WS /ws/project/:name/chat/:sessionId`
236
+ 2. Client sends: `{ type: "message", content: "..." }`
237
+ 3. Server streams messages:
238
+ - `{ type: "text", content: "..." }` (incremental)
239
+ - `{ type: "tool_use", tool: "file_read", input: {...} }`
240
+ - `{ type: "approval_request", requestId, tool, input }`
241
+ - `{ type: "done", sessionId }`
242
+ 4. Client approves tool: `{ type: "approval_response", requestId, approved: true }`
243
+
244
+ **Terminal I/O Flow:**
245
+ 1. Client connects: `WS /ws/project/:name/terminal/:id`
246
+ 2. Client sends: `{ type: "input", data: "ls\n" }`
247
+ 3. Server sends: `{ type: "output", data: "file1 file2\n" }`
248
+ 4. Client sends: `{ type: "resize", cols: 80, rows: 24 }`
249
+
250
+ ---
251
+
252
+ ## Authentication Flow
253
+
254
+ ```
255
+ User opens http://localhost:8080
256
+
257
+ App checks localStorage for auth token
258
+
259
+ If no token:
260
+ → LoginScreen shown (prompt for token)
261
+ → GET /api/auth/check to validate token
262
+
263
+ If valid token:
264
+ → Store in localStorage
265
+ → Load projects: GET /api/projects
266
+ → Main UI rendered
267
+
268
+ For each API request:
269
+ → Include "Authorization: Bearer <token>" header
270
+ → Middleware validates token
271
+ → If invalid → 401 Unauthorized
272
+ ```
273
+
274
+ **Token Management:**
275
+ - Generated on `ppm init` → stored in `ppm.yaml`
276
+ - Sent from CLI via `-c <config>` flag
277
+ - Stored in browser localStorage for session persistence
278
+ - No expiry (single-user, local environment)
279
+
280
+ ---
281
+
282
+ ## Chat Streaming Flow
283
+
284
+ ```
285
+ User types: "Debug this function"
286
+
287
+ MessageInput.tsx calls useChat.sendMessage()
288
+
289
+ useChat opens WebSocket: WS /ws/project/:name/chat/:sessionId
290
+
291
+ Sends: { type: "message", content: "Debug..." }
292
+
293
+ Server routes to ChatService.streamMessage()
294
+
295
+ ChatService calls provider.sendMessage() (async generator)
296
+
297
+ Provider (Claude SDK) streams response:
298
+ 1. Yields: { type: "text", content: "Here's what..." }
299
+ 2. Yields: { type: "text", content: " happens..." }
300
+ 3. Yields: { type: "tool_use", tool: "read_file", input: {...} }
301
+
302
+ ChatService wraps as WebSocket messages:
303
+ { type: "text", content: "Here's what..." }
304
+ { type: "text", content: " happens..." }
305
+ { type: "tool_use", tool: "read_file", input: {...} }
306
+ { type: "approval_request", requestId, tool, input }
307
+
308
+ Client receives, displays message incrementally
309
+
310
+ User sees tool approval prompt, clicks "Approve"
311
+
312
+ Client sends: { type: "approval_response", requestId, approved: true }
313
+
314
+ ChatService.onToolApproval() executes tool (file_read, git commands, etc.)
315
+
316
+ Provider continues streaming with tool result
317
+
318
+ Final response streamed, then: { type: "done", sessionId }
319
+
320
+ useChat closes WebSocket, saves message to store
321
+ ```
322
+
323
+ ---
324
+
325
+ ## Terminal Flow
326
+
327
+ ```
328
+ User clicks Terminal tab
329
+
330
+ TerminalTab.tsx mounts
331
+
332
+ useTerminal hook opens WebSocket: WS /ws/project/:name/terminal/:id
333
+
334
+ TerminalService.spawn() creates PTY (Bun.spawn)
335
+
336
+ xterm.js renders terminal emulator
337
+
338
+ User types: "npm test"
339
+
340
+ xterm.js captures key event
341
+
342
+ Sends via WebSocket: { type: "input", data: "npm test\n" }
343
+
344
+ TerminalService.write(pty, "npm test\n")
345
+
346
+ npm process spawned inside PTY
347
+
348
+ Output captured: "PASS: all tests\n"
349
+
350
+ TerminalService sends: { type: "output", data: "PASS: all tests\n" }
351
+
352
+ xterm.js renders output
353
+
354
+ User resizes window → xterm.js resizes terminal
355
+
356
+ Sends: { type: "resize", cols: 120, rows: 40 }
357
+
358
+ TerminalService calls pty.resize()
359
+
360
+ Shell (bash/zsh) receives SIGWINCH signal
361
+
362
+ Terminal state updated
363
+ ```
364
+
365
+ ---
366
+
367
+ ## Git Integration Flow
368
+
369
+ ```
370
+ User right-clicks file in FileTree
371
+
372
+ Context menu shows "Stage" option
373
+
374
+ User clicks "Stage"
375
+
376
+ FileActions.tsx calls POST /api/project/:name/git/stage
377
+
378
+ Sends: { path: "src/index.ts" }
379
+
380
+ GitService.stage(projectPath, "src/index.ts")
381
+
382
+ Executes: git add src/index.ts (via simple-git)
383
+
384
+ Returns: { ok: true }
385
+
386
+ GitStatusPanel.tsx refreshes: GET /api/project/:name/git/status
387
+
388
+ GitService.status() returns:
389
+ {
390
+ current: "main",
391
+ staged: ["src/index.ts"],
392
+ unstaged: ["README.md"],
393
+ untracked: ["temp.log"]
394
+ }
395
+
396
+ UI updates: "src/index.ts" moves from "Unstaged" to "Staged"
397
+ ```
398
+
399
+ ---
400
+
401
+ ## Deployment Architecture
402
+
403
+ ### Single-Machine Deployment (Current)
404
+ ```
405
+ Linux/macOS Host
406
+ ├── ppm (compiled binary)
407
+ │ └── Embeds: server code, frontend assets
408
+ ├── ppm.yaml (config, auto-generated)
409
+ └── ~/.ppm/ (optional: session cache, logs)
410
+ ```
411
+
412
+ ### Daemon Mode (Optional)
413
+ ```
414
+ $ ppm start --daemon
415
+ → Background process (nohup or systemd)
416
+ → Logs to ~/.ppm/server.log
417
+ → PID saved to ~/.ppm/server.pid
418
+
419
+ $ ppm stop
420
+ → Reads PID
421
+ → Sends SIGTERM
422
+ → Graceful shutdown (close WS, cleanup PTY)
423
+ ```
424
+
425
+ ### Future: Multi-Machine (Not in v2)
426
+ Would require:
427
+ - Central state server (Redis/Postgres)
428
+ - Session sharing across servers
429
+ - Shared filesystem or file sync protocol
430
+ - Load balancer
431
+
432
+ ---
433
+
434
+ ## Error Handling Strategy
435
+
436
+ | Layer | Error Type | Handling |
437
+ |-------|-----------|----------|
438
+ | **Presentation** | Network error | Retry, show toast |
439
+ | **API** | Invalid input | 400 Bad Request, error message |
440
+ | **Service** | File not found | Throw Error, API returns 404 |
441
+ | **Service** | Git failed | Throw Error with git output |
442
+ | **Provider** | Token invalid | Return error event |
443
+ | **Filesystem** | Permission denied | Throw Error with context |
444
+
445
+ **Pattern:** Bottom-up exception bubbling with context addition at each layer.
446
+
447
+ ---
448
+
449
+ ## Security Architecture
450
+
451
+ | Component | Security Measure | Implementation |
452
+ |-----------|-----------------|-----------------|
453
+ | **Auth** | Token validation | Middleware checks header token vs config |
454
+ | **Path Traversal** | Path validation | FileService rejects paths with `..` |
455
+ | **WebSocket** | Token in URL query | WS connects with `?token=...` or via session |
456
+ | **CLI** | Config file permissions | 0600 (user read/write only) |
457
+ | **API** | No sensitive data in logs | Token masked in debug output |
458
+ | **CORS** | Same-origin only | WS on same host as HTTP API |
459
+
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@hienlh/ppm",
3
+ "version": "0.1.0",
4
+ "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
+ "module": "src/index.ts",
6
+ "type": "module",
7
+ "bin": {
8
+ "ppm": "src/index.ts"
9
+ },
10
+ "scripts": {
11
+ "dev": "bun run --hot src/index.ts start",
12
+ "dev:web": "bun run vite --config vite.config.ts",
13
+ "build:web": "bun run vite build --config vite.config.ts",
14
+ "build": "bun run build:web && bun build src/index.ts --compile --outfile dist/ppm",
15
+ "start": "bun run src/index.ts start",
16
+ "typecheck": "bunx tsc --noEmit",
17
+ "postinstall": "node node_modules/ccburn/scripts/postinstall.js"
18
+ },
19
+ "devDependencies": {
20
+ "@tailwindcss/vite": "^4.2.1",
21
+ "@types/bun": "latest",
22
+ "@types/js-yaml": "^4.0.9",
23
+ "@types/node": "^25.5.0",
24
+ "@types/react": "^19.2.14",
25
+ "@types/react-dom": "^19.2.3",
26
+ "@vitejs/plugin-react": "^6.0.1",
27
+ "tailwindcss": "^4.2.1",
28
+ "vite": "^8.0.0",
29
+ "vite-plugin-pwa": "^1.2.0"
30
+ },
31
+ "peerDependencies": {
32
+ "typescript": "^5.9.3"
33
+ },
34
+ "dependencies": {
35
+ "@anthropic-ai/claude-agent-sdk": "^0.2.76",
36
+ "@codemirror/autocomplete": "^6.20.1",
37
+ "@codemirror/lang-css": "^6.3.1",
38
+ "@codemirror/lang-html": "^6.4.11",
39
+ "@codemirror/lang-javascript": "^6.2.5",
40
+ "@codemirror/lang-json": "^6.0.2",
41
+ "@codemirror/lang-markdown": "^6.5.0",
42
+ "@codemirror/lang-python": "^6.2.1",
43
+ "@codemirror/merge": "^6.12.1",
44
+ "@codemirror/theme-one-dark": "^6.1.3",
45
+ "@uiw/react-codemirror": "^4.25.8",
46
+ "@xterm/addon-fit": "^0.11.0",
47
+ "@xterm/addon-web-links": "^0.12.0",
48
+ "@xterm/xterm": "^6.0.0",
49
+ "ccburn": "^0.6.0",
50
+ "clsx": "^2.1.1",
51
+ "codemirror": "^6.0.2",
52
+ "commander": "^14.0.3",
53
+ "diff2html": "^3.4.56",
54
+ "hono": "^4.12.8",
55
+ "js-yaml": "^4.1.1",
56
+ "lucide-react": "^0.577.0",
57
+ "marked": "^17.0.4",
58
+ "next-themes": "^0.4.6",
59
+ "radix-ui": "^1.4.3",
60
+ "react": "^19.2.4",
61
+ "react-dom": "^19.2.4",
62
+ "react-resizable-panels": "^4.7.3",
63
+ "simple-git": "^3.33.0",
64
+ "sonner": "^2.0.7",
65
+ "tailwind-merge": "^3.5.0",
66
+ "zustand": "^5.0.11"
67
+ }
68
+ }
@@ -0,0 +1,81 @@
1
+ # Phase 1: Project Skeleton + Shared Types
2
+
3
+ **Owner:** Lead
4
+ **Priority:** Critical
5
+ **Depends on:** None
6
+ **Effort:** Small
7
+
8
+ ## Overview
9
+
10
+ Initialize monorepo, install dependencies, create shared types, config files. This unblocks all other phases.
11
+
12
+ ## Steps
13
+
14
+ 1. **Init Bun project**
15
+ ```bash
16
+ bun init
17
+ ```
18
+
19
+ 2. **Install backend dependencies**
20
+ ```bash
21
+ bun add hono commander js-yaml simple-git @anthropic-ai/claude-agent-sdk
22
+ bun add -d @types/node typescript
23
+ ```
24
+
25
+ 3. **Install frontend dependencies**
26
+ ```bash
27
+ bun add react react-dom zustand @tanstack/react-query
28
+ bun add -d vite @vitejs/plugin-react tailwindcss @tailwindcss/vite vite-plugin-pwa
29
+ bun add codemirror @codemirror/lang-javascript @codemirror/lang-typescript @codemirror/lang-python @codemirror/lang-html @codemirror/lang-css @codemirror/lang-json @codemirror/lang-markdown @codemirror/autocomplete @codemirror/merge @codemirror/theme-one-dark @uiw/react-codemirror
30
+ bun add @xterm/xterm @xterm/addon-fit @xterm/addon-web-links
31
+ bun add diff2html react-resizable-panels lucide-react
32
+ ```
33
+
34
+ 4. **Init shadcn/ui**
35
+ ```bash
36
+ bunx --bun shadcn@latest init
37
+ bunx --bun shadcn@latest add button dialog dropdown-menu context-menu input tabs scroll-area tooltip separator sonner
38
+ ```
39
+
40
+ 5. **Create config files**
41
+ - `tsconfig.json` — strict, paths alias `@/` → `src/web/`
42
+ - `vite.config.ts` — React plugin, Tailwind, PWA plugin, build output to `dist/web`
43
+ - `tailwind.config.ts` — shadcn/ui preset, mobile-first
44
+ - `bunfig.toml` — Bun config
45
+ - `ppm.example.yaml` — example config
46
+ - `.env.example` — `ANTHROPIC_API_KEY=`
47
+ - `.gitignore`
48
+
49
+ 6. **Create shared types** (`src/types/`)
50
+ - `config.ts` — PpmConfig, AuthConfig, ProjectConfig, AIProviderConfig
51
+ - `project.ts` — Project, ProjectInfo
52
+ - `git.ts` — GitCommit, GitBranch, GitStatus, GitGraphData, GitDiffResult, GitFileChange
53
+ - `chat.ts` — AIProvider interface, ChatEvent, SessionConfig, SessionInfo, ToolApprovalRequest
54
+ - `terminal.ts` — TerminalSession, TerminalResize
55
+ - `api.ts` — API request/response wrappers
56
+
57
+ 7. **Create entry point** `src/index.ts` — minimal Commander.js setup with `start` command placeholder
58
+
59
+ 8. **Create README.md** with project description, setup instructions
60
+
61
+ 9. **Create CLAUDE.md** with project conventions
62
+
63
+ 10. **Verify build**
64
+ ```bash
65
+ bun run src/index.ts --help
66
+ ```
67
+
68
+ ## Files to Create
69
+
70
+ - `package.json`, `tsconfig.json`, `vite.config.ts`, `tailwind.config.ts`, `bunfig.toml`
71
+ - `ppm.example.yaml`, `.env.example`, `.gitignore`
72
+ - `src/index.ts`
73
+ - `src/types/*.ts` (6 files)
74
+ - `README.md`, `CLAUDE.md`, `LICENSE`
75
+
76
+ ## Success Criteria
77
+
78
+ - [x] `bun run src/index.ts --help` shows CLI help
79
+ - [x] `bun run --hot src/web/main.tsx` (via vite) starts dev server
80
+ - [x] All shared types compile without errors
81
+ - [x] shadcn/ui components installed and importable