@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,305 @@
1
+ # Research Report: node-pty Crash in Bun Runtime
2
+
3
+ **Date:** 2026-03-14
4
+ **Researcher:** Claude Code
5
+ **Context:** PPM v1 crashed when node-pty `posix_spawnp` was called in WebSocket handlers. v2 must avoid this.
6
+
7
+ ---
8
+
9
+ ## Executive Summary
10
+
11
+ **Root Cause:** node-pty uses NAN (Native Abstractions for Node.js), not NAPI. Bun's runtime cannot resolve the required C++ symbols (`_node_module_register`, V8 API, libuv symbols), causing dyld linking errors on macOS and runtime crashes.
12
+
13
+ **Status:** This is a **hard incompatibility** — node-pty fundamentally cannot work with Bun's current architecture. No patches or workarounds exist.
14
+
15
+ **Recommended Path for PPM v2:** Use **Bun.spawn() with the native Terminal API** (POSIX-only, but acceptable for dev environment). Fallback to `script -q /dev/null` wrapper if resize features needed.
16
+
17
+ ---
18
+
19
+ ## Root Cause Analysis
20
+
21
+ ### The Incompatibility Chain
22
+
23
+ 1. **node-pty Architecture**
24
+ - Built on NAN (Native Abstractions for Node.js) — pre-2015 binding system
25
+ - Compiles to `pty.node` native addon with C++ code
26
+ - Requires V8 C++ APIs, libuv symbols, and the `_node_module_register` symbol at runtime
27
+
28
+ 2. **Bun's Module System**
29
+ - Implements NAPI (modern Node.js API) but NOT NAN
30
+ - Cannot resolve `_node_module_register` or most V8 C++ symbols
31
+ - Module loading fails immediately on `require('node-pty')`
32
+
33
+ 3. **Why It Crashes in WebSocket Context**
34
+ - Even if module loads partially, `posix_spawnp` syscall invocation in node-pty's native code crashes due to incomplete symbol binding
35
+ - Happens specifically in WebSocket handler because that's where PTY spawn is called
36
+ - Segfault takes down entire Bun process (no error catching possible)
37
+
38
+ ### Upstream Status
39
+
40
+ - **node-pty issue #632** (2024): Maintainers confirmed "Bun doesn't work with `nan`/`napi` so this isn't possible"
41
+ - **node-pty PR #644** (ongoing): Effort to port to NAPI, but still incomplete and unstable
42
+ - **Bun issue #4290** (2024-2026): Bun team tracking V8 C++ API support, no ETA
43
+ - **Closure:** Both projects closed Bun-related issues as "not planned"
44
+
45
+ **Verdict:** Don't wait for fixes. This won't be solved in the foreseeable future.
46
+
47
+ ---
48
+
49
+ ## What Works in claude_remote
50
+
51
+ Checked `/Users/hienlh/claude_remote/codepeer/`:
52
+
53
+ - **package.json:** Declares `node-pty@^1.0.0` as dependency
54
+ - **terminal.js:** Frontend-only file — uses xterm.js client-side, doesn't interact with PTY
55
+ - **Architecture:** Claude_remote is a **Node.js** project, not Bun — that's why node-pty works there
56
+
57
+ **Key Difference:** If claude_remote were ported to Bun, it would crash immediately on PTY spawn.
58
+
59
+ ---
60
+
61
+ ## Recommended Approaches for PPM v2
62
+
63
+ ### Option 1: Bun.spawn() with Native Terminal API ✅ RECOMMENDED
64
+
65
+ **Pros:**
66
+ - Zero external dependencies
67
+ - Built into Bun runtime, fully compatible
68
+ - Supports PTY features: colors, cursor movement, interactive input
69
+ - Can resize with `terminal.resize(cols, rows)`
70
+ - Simplest implementation
71
+
72
+ **Cons:**
73
+ - POSIX only (Linux, macOS) — but acceptable for web IDE dev environment
74
+ - Windows developers must use WSL or fall back to raw pipes
75
+
76
+ **Implementation:**
77
+ ```typescript
78
+ // src/services/terminal.service.ts
79
+ import { Subprocess } from 'bun';
80
+
81
+ interface TerminalSession {
82
+ id: string;
83
+ proc: Subprocess;
84
+ terminal: Terminal;
85
+ projectPath: string;
86
+ createdAt: Date;
87
+ }
88
+
89
+ class TerminalService {
90
+ private sessions: Map<string, TerminalSession> = new Map();
91
+
92
+ create(projectPath: string, shell: string = 'bash'): string {
93
+ const id = crypto.randomUUID();
94
+ let output = '';
95
+
96
+ const proc = Bun.spawn([shell], {
97
+ cwd: projectPath,
98
+ terminal: {
99
+ cols: 80,
100
+ rows: 24,
101
+ data(terminal, chunk) {
102
+ output += chunk.toString();
103
+ // Emit to all connected WebSocket clients
104
+ // (bridge via eventBus or direct WS handler)
105
+ },
106
+ },
107
+ });
108
+
109
+ this.sessions.set(id, {
110
+ id,
111
+ proc,
112
+ terminal: proc.terminal!,
113
+ projectPath,
114
+ createdAt: new Date(),
115
+ });
116
+
117
+ return id;
118
+ }
119
+
120
+ write(id: string, data: string): void {
121
+ const session = this.sessions.get(id);
122
+ if (session) {
123
+ session.terminal.write(data);
124
+ }
125
+ }
126
+
127
+ resize(id: string, cols: number, rows: number): void {
128
+ const session = this.sessions.get(id);
129
+ if (session) {
130
+ session.terminal.resize(cols, rows);
131
+ }
132
+ }
133
+
134
+ kill(id: string): void {
135
+ const session = this.sessions.get(id);
136
+ if (session) {
137
+ session.terminal.close();
138
+ session.proc.kill();
139
+ this.sessions.delete(id);
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ **WebSocket Handler:**
146
+ ```typescript
147
+ // src/server/ws/terminal.ts
148
+ import { TerminalService } from '../services/terminal.service';
149
+
150
+ const terminalService = new TerminalService();
151
+
152
+ export function handleTerminalWS(ws: WebSocket, req: Request) {
153
+ const sessionId = extractSessionId(req); // from URL
154
+
155
+ ws.onmessage = (event) => {
156
+ const msg = JSON.parse(event.data);
157
+
158
+ if (msg.type === 'input') {
159
+ terminalService.write(sessionId, msg.data);
160
+ }
161
+
162
+ if (msg.type === 'resize') {
163
+ terminalService.resize(sessionId, msg.cols, msg.rows);
164
+ }
165
+ };
166
+
167
+ ws.onerror = () => terminalService.kill(sessionId);
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ### Option 2: Bun.spawn() + `script -q /dev/null` Wrapper
174
+
175
+ **Use Case:** If targeting Windows or need maximum compatibility.
176
+
177
+ **How It Works:**
178
+ ```bash
179
+ script -q /dev/null /bin/bash
180
+ ```
181
+ The `script` utility (POSIX standard) allocates a PTY and runs the shell inside it.
182
+
183
+ **Pros:**
184
+ - Works on macOS and Linux
185
+ - No dependencies
186
+ - Allocates true PTY without node-pty
187
+
188
+ **Cons:**
189
+ - Extra process overhead (script utility wrapper)
190
+ - Less direct control over PTY
191
+ - Platform-specific edge cases
192
+
193
+ **Implementation:**
194
+ ```typescript
195
+ const proc = Bun.spawn(['script', '-q', '/dev/null', 'bash'], {
196
+ cwd: projectPath,
197
+ terminal: {
198
+ cols: 80,
199
+ rows: 24,
200
+ data(terminal, chunk) {
201
+ // Handle output
202
+ },
203
+ },
204
+ });
205
+ ```
206
+
207
+ **Not Recommended for PPM:** Option 1 is simpler and more direct.
208
+
209
+ ---
210
+
211
+ ### Option 3: Bun.spawn() + Raw Pipes (No PTY)
212
+
213
+ **Use Case:** Windows-only fallback, or if PTY features not critical.
214
+
215
+ **Pros:**
216
+ - Cross-platform (Windows, Linux, macOS)
217
+ - Works with raw process I/O
218
+
219
+ **Cons:**
220
+ - No terminal features: colors, cursor movement, job control fail
221
+ - `Ctrl+C` kills Bun process instead of shell
222
+ - Shell behaves as non-interactive
223
+
224
+ **Not Recommended:** Degrades user experience significantly. Use Option 1 instead.
225
+
226
+ ---
227
+
228
+ ### Option 4: Avoid PTY in v2, Use `bun-pty` Later
229
+
230
+ **Context:** Community package `@skitee3000/bun-pty` exists on npm.
231
+
232
+ **Status:** Bun-specific library built with Bun's FFI (Foreign Function Interface) to Rust's portable-pty. Early stage, not production-tested.
233
+
234
+ **Decision:** Skip for now. Option 1 (native Bun Terminal API) is more stable and maintainable.
235
+
236
+ ---
237
+
238
+ ## Compilation with `bun build --compile`
239
+
240
+ **Question from Task:** Can Bun.spawn() work when code is compiled with `bun build --compile`?
241
+
242
+ **Answer:** YES, but with important caveats.
243
+
244
+ - **Bun.spawn() works fine** — it's native Bun API, included in compiled binary
245
+ - **PTY support is included** — `terminal` option works in compiled apps
246
+ - **Shell availability required** — compiled app must run on system with bash/zsh at runtime
247
+ - **Caveat:** If compiled as standalone binary on macOS, ensure $PATH includes system shells
248
+
249
+ **Recommended:** For distributed compiled binaries, fall back to raw pipes or document shell requirement.
250
+
251
+ ---
252
+
253
+ ## Migration Path from PPM v1 → v2
254
+
255
+ **v1 Problem:**
256
+ ```typescript
257
+ // CRASHES BUNT PROCESS
258
+ const pty = require('node-pty').spawn('bash', [], { cwd: projectPath });
259
+ ```
260
+
261
+ **v2 Solution:**
262
+ ```typescript
263
+ // WORKS RELIABLY
264
+ const proc = Bun.spawn(['bash'], {
265
+ cwd: projectPath,
266
+ terminal: { cols: 80, rows: 24, data(t, chunk) { /* handle */ } }
267
+ });
268
+ ```
269
+
270
+ **No breaking changes to Frontend:** xterm.js, WebSocket protocol, and terminal-tab component unchanged.
271
+
272
+ ---
273
+
274
+ ## Summary Table
275
+
276
+ | Approach | Works | Portable | PTY Features | Dependency | Stability |
277
+ |----------|-------|----------|--------------|------------|-----------|
278
+ | node-pty | ❌ Crash | - | Yes | Native NAN | Dead |
279
+ | Bun.Terminal | ✅ | POSIX | Yes | Built-in | ✅ Stable |
280
+ | script wrapper | ✅ | POSIX | Yes | Bun + system | ✅ Good |
281
+ | Raw pipes | ✅ | All | No | Bun | Basic |
282
+ | bun-pty | ⚠️ Works | All | Yes | Rust FFI | Experimental |
283
+
284
+ ---
285
+
286
+ ## Unresolved Questions
287
+
288
+ 1. **Performance impact** of Bun.Terminal vs node-pty under heavy I/O (1000+ char/sec)? — Likely negligible, but worth benchmarking if terminal lag reported.
289
+
290
+ 2. **Windows support timeline** — If Windows devs become critical user base later, when would we port to `bun-pty` or implement fallback? Current: dev environment is macOS/Linux only, acceptable.
291
+
292
+ 3. **Compiled binary distribution** — If PPM released as standalone `ppm` executable, how to ensure shell availability in compiled form? Not in scope for v2, address in v3 deployment phase.
293
+
294
+ ---
295
+
296
+ ## References & Sources
297
+
298
+ - [Bun Spawn Documentation - Terminal API](https://bun.com/docs/runtime/child-process)
299
+ - [Bun.spawn SpawnOptions Reference](https://bun.com/reference/bun/Spawn/SpawnOptions)
300
+ - [GitHub: node-pty unable to be run from bun · Issue #7362 · oven-sh/bun](https://github.com/oven-sh/bun/issues/7362)
301
+ - [GitHub: Bun support · Issue #632 · microsoft/node-pty](https://github.com/microsoft/node-pty/issues/632)
302
+ - [GitHub: Port to NAPI · PR #644 · microsoft/node-pty](https://github.com/microsoft/node-pty/pull/644)
303
+ - [npm: @skitee3000/bun-pty](https://www.npmjs.com/package/@skitee3000/bun-pty)
304
+ - [GitHub: sursaone/bun-pty - Fork pseudoterminals in Bun](https://github.com/sursaone/bun-pty)
305
+ - [TTY Shell Upgrade Techniques - 0xffsec Handbook](https://0xffsec.com/handbook/shells/full-tty/)