@hienlh/ppm 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agent-memory/tester/MEMORY.md +3 -0
- package/.claude/agent-memory/tester/project-ppm-test-conventions.md +32 -0
- package/.env.example +1 -0
- package/.github/workflows/release.yml +46 -0
- package/README.md +349 -0
- package/bun.lock +1217 -0
- package/components.json +21 -0
- package/docs/code-standards.md +574 -0
- package/docs/codebase-summary.md +294 -0
- package/docs/deployment-guide.md +631 -0
- package/docs/design-guidelines.md +661 -0
- package/docs/project-overview-pdr.md +142 -0
- package/docs/project-roadmap.md +400 -0
- package/docs/system-architecture.md +459 -0
- package/package.json +68 -0
- package/plans/260314-2009-ppm-implementation/phase-01-project-skeleton.md +81 -0
- package/plans/260314-2009-ppm-implementation/phase-02-backend-core.md +148 -0
- package/plans/260314-2009-ppm-implementation/phase-03-frontend-shell.md +256 -0
- package/plans/260314-2009-ppm-implementation/phase-04-file-explorer-editor.md +120 -0
- package/plans/260314-2009-ppm-implementation/phase-05-web-terminal.md +174 -0
- package/plans/260314-2009-ppm-implementation/phase-06-git-integration.md +244 -0
- package/plans/260314-2009-ppm-implementation/phase-07-ai-chat.md +242 -0
- package/plans/260314-2009-ppm-implementation/phase-08-cli-commands.md +143 -0
- package/plans/260314-2009-ppm-implementation/phase-09-pwa-build-deploy.md +209 -0
- package/plans/260314-2009-ppm-implementation/phase-10-testing.md +311 -0
- package/plans/260314-2009-ppm-implementation/plan.md +202 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-01-backend-project-router.md +145 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-02-frontend-api-migration.md +107 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-03-per-project-tabs.md +100 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-04-websocket-migration.md +66 -0
- package/plans/260315-0356-project-scoped-api-refactor/plan.md +87 -0
- package/plans/reports/brainstorm-260314-1938-final-techstack.md +342 -0
- package/plans/reports/docs-manager-260315-1314-documentation-creation.md +386 -0
- package/plans/reports/fullstack-developer-260314-2252-phase-02-backend-core.md +57 -0
- package/plans/reports/fullstack-developer-260314-2253-phase-03-frontend-shell.md +70 -0
- package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-api-terminal-ws.md +49 -0
- package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-explorer-editor-terminal.md +52 -0
- package/plans/reports/fullstack-developer-260314-2307-ai-chat-phase7.md +58 -0
- package/plans/reports/fullstack-developer-260314-2307-phase-06-git-integration.md +33 -0
- package/plans/reports/research-260314-1911-ppm-tech-stack.md +318 -0
- package/plans/reports/research-260314-1930-claude-code-integration.md +293 -0
- package/plans/reports/researcher-260314-2232-node-pty-bun-crash-analysis.md +305 -0
- package/plans/reports/researcher-260314-2232-ui-style.md +942 -0
- package/plans/reports/researcher-260315-0300-opcode-claude-interaction.md +745 -0
- package/plans/reports/researcher-260315-0303-opcode-deep-analysis.md +742 -0
- package/plans/reports/researcher-260315-0305-claude-agent-sdk-github-research.md +423 -0
- package/plans/reports/tester-260314-2053-initial-test-suite.md +81 -0
- package/ppm.example.yaml +14 -0
- package/repomix-output.xml +23745 -0
- package/scripts/build.ts +13 -0
- package/src/cli/commands/chat-cmd.ts +259 -0
- package/src/cli/commands/config-cmd.ts +121 -0
- package/src/cli/commands/git-cmd.ts +315 -0
- package/src/cli/commands/init.ts +57 -0
- package/src/cli/commands/open.ts +19 -0
- package/src/cli/commands/projects.ts +100 -0
- package/src/cli/commands/start.ts +3 -0
- package/src/cli/commands/stop.ts +33 -0
- package/src/cli/utils/project-resolver.ts +27 -0
- package/src/index.ts +59 -0
- package/src/providers/claude-agent-sdk.ts +499 -0
- package/src/providers/claude-binary-finder.ts +256 -0
- package/src/providers/claude-code-cli.ts +413 -0
- package/src/providers/claude-process-registry.ts +106 -0
- package/src/providers/mock-provider.ts +171 -0
- package/src/providers/provider.interface.ts +10 -0
- package/src/providers/registry.ts +45 -0
- package/src/server/helpers/resolve-project.ts +22 -0
- package/src/server/index.ts +181 -0
- package/src/server/middleware/auth.ts +30 -0
- package/src/server/routes/chat.ts +153 -0
- package/src/server/routes/files.ts +168 -0
- package/src/server/routes/git.ts +261 -0
- package/src/server/routes/project-scoped.ts +27 -0
- package/src/server/routes/projects.ts +57 -0
- package/src/server/routes/static.ts +26 -0
- package/src/server/ws/chat.ts +130 -0
- package/src/server/ws/terminal.ts +89 -0
- package/src/services/chat.service.ts +110 -0
- package/src/services/claude-usage.service.ts +113 -0
- package/src/services/config.service.ts +90 -0
- package/src/services/file.service.ts +261 -0
- package/src/services/git-dirs.service.ts +112 -0
- package/src/services/git.service.ts +372 -0
- package/src/services/project.service.ts +107 -0
- package/src/services/slash-items.service.ts +184 -0
- package/src/services/terminal.service.ts +212 -0
- package/src/types/api.ts +37 -0
- package/src/types/chat.ts +92 -0
- package/src/types/config.ts +41 -0
- package/src/types/git.ts +50 -0
- package/src/types/project.ts +18 -0
- package/src/types/terminal.ts +20 -0
- package/src/web/app.tsx +168 -0
- package/src/web/components/auth/login-screen.tsx +88 -0
- package/src/web/components/chat/attachment-chips.tsx +55 -0
- package/src/web/components/chat/chat-placeholder.tsx +10 -0
- package/src/web/components/chat/chat-tab.tsx +301 -0
- package/src/web/components/chat/file-picker.tsx +126 -0
- package/src/web/components/chat/message-input.tsx +420 -0
- package/src/web/components/chat/message-list.tsx +838 -0
- package/src/web/components/chat/session-picker.tsx +139 -0
- package/src/web/components/chat/slash-command-picker.tsx +135 -0
- package/src/web/components/chat/usage-badge.tsx +186 -0
- package/src/web/components/editor/code-editor.tsx +329 -0
- package/src/web/components/editor/diff-viewer.tsx +276 -0
- package/src/web/components/editor/editor-placeholder.tsx +10 -0
- package/src/web/components/explorer/file-actions.tsx +191 -0
- package/src/web/components/explorer/file-tree.tsx +298 -0
- package/src/web/components/git/git-graph.tsx +727 -0
- package/src/web/components/git/git-placeholder.tsx +55 -0
- package/src/web/components/git/git-status-panel.tsx +850 -0
- package/src/web/components/layout/mobile-drawer.tsx +137 -0
- package/src/web/components/layout/mobile-nav.tsx +103 -0
- package/src/web/components/layout/sidebar.tsx +90 -0
- package/src/web/components/layout/tab-bar.tsx +152 -0
- package/src/web/components/layout/tab-content.tsx +85 -0
- package/src/web/components/projects/dir-suggest.tsx +152 -0
- package/src/web/components/projects/project-list.tsx +187 -0
- package/src/web/components/settings/settings-tab.tsx +57 -0
- package/src/web/components/terminal/terminal-placeholder.tsx +10 -0
- package/src/web/components/terminal/terminal-tab.tsx +133 -0
- package/src/web/components/ui/button.tsx +64 -0
- package/src/web/components/ui/context-menu.tsx +250 -0
- package/src/web/components/ui/dialog.tsx +156 -0
- package/src/web/components/ui/dropdown-menu.tsx +257 -0
- package/src/web/components/ui/input.tsx +21 -0
- package/src/web/components/ui/scroll-area.tsx +56 -0
- package/src/web/components/ui/separator.tsx +26 -0
- package/src/web/components/ui/sonner.tsx +40 -0
- package/src/web/components/ui/tabs.tsx +91 -0
- package/src/web/components/ui/tooltip.tsx +57 -0
- package/src/web/hooks/use-chat.ts +420 -0
- package/src/web/hooks/use-terminal.ts +182 -0
- package/src/web/hooks/use-url-sync.ts +66 -0
- package/src/web/hooks/use-websocket.ts +48 -0
- package/src/web/index.html +16 -0
- package/src/web/lib/api-client.ts +90 -0
- package/src/web/lib/file-support.ts +68 -0
- package/src/web/lib/utils.ts +6 -0
- package/src/web/lib/ws-client.ts +100 -0
- package/src/web/main.tsx +10 -0
- package/src/web/public/icon-192.svg +5 -0
- package/src/web/public/icon-512.svg +5 -0
- package/src/web/stores/file-store.ts +81 -0
- package/src/web/stores/project-store.ts +50 -0
- package/src/web/stores/settings-store.ts +65 -0
- package/src/web/stores/tab-store.ts +187 -0
- package/src/web/styles/globals.css +227 -0
- package/src/web/vite-env.d.ts +1 -0
- package/tests/integration/api/chat-routes.test.ts +95 -0
- package/tests/integration/claude-agent-sdk-integration.test.ts +228 -0
- package/tests/integration/ws/chat-websocket.test.ts +312 -0
- package/tests/test-setup.ts +5 -0
- package/tests/unit/providers/claude-agent-sdk.test.ts +339 -0
- package/tests/unit/providers/mock-provider.test.ts +143 -0
- package/tests/unit/services/chat-service.test.ts +100 -0
- package/tsconfig.json +32 -0
- package/vite.config.ts +62 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
status: pending
|
|
3
|
+
created: 2026-03-14
|
|
4
|
+
updated: 2026-03-14
|
|
5
|
+
slug: ppm-implementation
|
|
6
|
+
version: 3
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# PPM Implementation Plan (v2)
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Build PPM (Personal Project Manager) — mobile-first web IDE running as CLI daemon.
|
|
14
|
+
Tech: Bun + Hono (backend), React 19 + Vite + Tailwind + shadcn/ui (frontend).
|
|
15
|
+
|
|
16
|
+
## Context
|
|
17
|
+
|
|
18
|
+
- [Final Tech Stack](../reports/brainstorm-260314-1938-final-techstack.md)
|
|
19
|
+
- [Tech Stack Research](../reports/research-260314-1911-ppm-tech-stack.md)
|
|
20
|
+
- [Claude Code Integration Research](../reports/research-260314-1930-claude-code-integration.md)
|
|
21
|
+
- [UI Style Guide](../reports/researcher-260314-2232-ui-style.md)
|
|
22
|
+
- [node-pty Research](../reports/researcher-260314-2232-node-pty-bun-crash-analysis.md)
|
|
23
|
+
|
|
24
|
+
## V1 Lessons (MUST follow)
|
|
25
|
+
|
|
26
|
+
These were bugs/issues found during v1 browser E2E testing. V2 must build them in from the start:
|
|
27
|
+
|
|
28
|
+
1. **API envelope auto-unwrap:** `api-client.get<T>()` returns `T` directly, not `{ok, data: T}`. Backend wraps in `{ok, data}`, client unwraps.
|
|
29
|
+
2. **Project resolution by NAME:** All API routes accept project name (e.g. "ppm"), not filesystem path. Use `resolveProjectPath(name)` helper in every route.
|
|
30
|
+
3. **Terminal: Bun native Terminal API:** Use `Bun.spawn()` with `terminal` option (full PTY). node-pty uses NAN bindings incompatible with Bun — hard crash, no fix possible. See [research](../reports/researcher-260314-2232-node-pty-bun-crash-analysis.md).
|
|
31
|
+
4. **Git log: use simple-git built-in:** Don't parse `git log --format` manually. Use `simple-git`'s `.log()` method which handles parsing correctly.
|
|
32
|
+
5. **Metadata on all tab openers:** Both tab-bar AND mobile-nav must pass `{ projectName }` metadata when opening git/file tabs.
|
|
33
|
+
6. **Mobile sidebar = overlay drawer:** Don't use `hidden md:flex`. Use absolute positioned overlay with backdrop that slides in on hamburger click.
|
|
34
|
+
|
|
35
|
+
## Team
|
|
36
|
+
|
|
37
|
+
| Agent | Role | File Ownership |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| **Lead** (main) | Coordinator, shared types, config files | `src/types/**`, `package.json`, configs, `CLAUDE.md` |
|
|
40
|
+
| **backend-dev** | Server, CLI, services | `src/cli/**`, `src/server/**`, `src/services/**`, `src/providers/**` |
|
|
41
|
+
| **frontend-dev** | React UI, all components | `src/web/**`, `public/**`, `index.html` |
|
|
42
|
+
| **tester** | Unit + integration tests | `tests/**`, `*.test.ts` (read-only on src) |
|
|
43
|
+
|
|
44
|
+
## Phases
|
|
45
|
+
|
|
46
|
+
| # | Phase | Owner | Depends | Status |
|
|
47
|
+
|---|---|---|---|---|
|
|
48
|
+
| 1 | [Project Skeleton + Shared Types](phase-01-project-skeleton.md) | Lead | — | pending |
|
|
49
|
+
| 2 | [Backend Core (Server + CLI + Config)](phase-02-backend-core.md) | backend-dev | 1 | pending |
|
|
50
|
+
| 3 | [Frontend Shell (Tab System + Layout)](phase-03-frontend-shell.md) | frontend-dev | 1 | pending |
|
|
51
|
+
| 4 | [File Explorer + Editor](phase-04-file-explorer-editor.md) | backend-dev + frontend-dev | 2, 3 | pending |
|
|
52
|
+
| 5 | [Web Terminal](phase-05-web-terminal.md) | backend-dev + frontend-dev | 2, 3 | pending |
|
|
53
|
+
| 6 | [Git Integration](phase-06-git-integration.md) | backend-dev + frontend-dev | 4 | pending |
|
|
54
|
+
| 7 | [AI Chat](phase-07-ai-chat.md) | backend-dev + frontend-dev | 2, 3 | pending |
|
|
55
|
+
| 8 | [CLI Commands](phase-08-cli-commands.md) | backend-dev | 2, 6, 7 | pending |
|
|
56
|
+
| 9 | [PWA + Build + Deploy](phase-09-pwa-build-deploy.md) | Lead | all | pending |
|
|
57
|
+
| 10 | [Testing](phase-10-testing.md) | tester | per phase | pending |
|
|
58
|
+
|
|
59
|
+
## Execution Order
|
|
60
|
+
|
|
61
|
+
Backend phases run **sequentially** (single agent, 200K context limit). Frontend can parallel where independent.
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Phase 1 (Lead)
|
|
65
|
+
├── Phase 2 (backend-dev) ──→ Phase 4-BE ──→ Phase 5-BE ──→ Phase 6-BE ──→ Phase 7-BE ──→ Phase 8
|
|
66
|
+
├── Phase 3 (frontend-dev) ──→ Phase 4-FE ──→ Phase 5-FE ──→ Phase 6-FE ──→ Phase 7-FE
|
|
67
|
+
│
|
|
68
|
+
Phase 9 (Lead, after all)
|
|
69
|
+
Phase 10 (tester, continuous after each phase)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Note: Each phase's backend + frontend can run in parallel (separate agents), but backend phases are sequential among themselves.
|
|
73
|
+
|
|
74
|
+
## Project Structure
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
ppm/
|
|
78
|
+
├── package.json
|
|
79
|
+
├── tsconfig.json
|
|
80
|
+
├── bunfig.toml
|
|
81
|
+
├── vite.config.ts
|
|
82
|
+
├── ppm.example.yaml
|
|
83
|
+
├── .env.example
|
|
84
|
+
├── LICENSE (MIT)
|
|
85
|
+
├── README.md
|
|
86
|
+
├── CLAUDE.md
|
|
87
|
+
├── src/
|
|
88
|
+
│ ├── index.ts # Entry point (CLI)
|
|
89
|
+
│ ├── types/
|
|
90
|
+
│ │ ├── config.ts # Config types
|
|
91
|
+
│ │ ├── project.ts # Project types
|
|
92
|
+
│ │ ├── git.ts # Git types (commit, branch, graph)
|
|
93
|
+
│ │ ├── chat.ts # Chat/AI types (ChatEvent, AIProvider)
|
|
94
|
+
│ │ ├── terminal.ts # Terminal session types
|
|
95
|
+
│ │ └── api.ts # API request/response types
|
|
96
|
+
│ ├── cli/
|
|
97
|
+
│ │ ├── index.ts # Commander.js setup
|
|
98
|
+
│ │ ├── commands/
|
|
99
|
+
│ │ │ ├── init.ts
|
|
100
|
+
│ │ │ ├── start.ts
|
|
101
|
+
│ │ │ ├── stop.ts
|
|
102
|
+
│ │ │ ├── open.ts
|
|
103
|
+
│ │ │ ├── projects.ts
|
|
104
|
+
│ │ │ ├── config.ts
|
|
105
|
+
│ │ │ ├── git.ts
|
|
106
|
+
│ │ │ └── chat.ts
|
|
107
|
+
│ │ └── utils/
|
|
108
|
+
│ │ └── project-resolver.ts # CWD auto-detect + -p flag
|
|
109
|
+
│ ├── server/
|
|
110
|
+
│ │ ├── index.ts # Hono app + Bun.serve + WS upgrade
|
|
111
|
+
│ │ ├── middleware/
|
|
112
|
+
│ │ │ └── auth.ts # Token auth middleware
|
|
113
|
+
│ │ ├── routes/
|
|
114
|
+
│ │ │ ├── projects.ts
|
|
115
|
+
│ │ │ ├── files.ts
|
|
116
|
+
│ │ │ ├── git.ts
|
|
117
|
+
│ │ │ └── static.ts # Serve embedded SPA
|
|
118
|
+
│ │ ├── ws/
|
|
119
|
+
│ │ │ ├── terminal.ts # WS /ws/terminal/:id
|
|
120
|
+
│ │ │ └── chat.ts # WS /ws/chat/:id
|
|
121
|
+
│ │ └── helpers/
|
|
122
|
+
│ │ └── resolve-project.ts # Shared: name → path resolver
|
|
123
|
+
│ ├── services/
|
|
124
|
+
│ │ ├── config.service.ts
|
|
125
|
+
│ │ ├── project.service.ts
|
|
126
|
+
│ │ ├── file.service.ts
|
|
127
|
+
│ │ ├── git.service.ts
|
|
128
|
+
│ │ ├── terminal.service.ts # Uses Bun.spawn (NOT node-pty)
|
|
129
|
+
│ │ └── chat.service.ts
|
|
130
|
+
│ ├── providers/
|
|
131
|
+
│ │ ├── provider.interface.ts
|
|
132
|
+
│ │ ├── claude-agent-sdk.ts
|
|
133
|
+
│ │ ├── cli-subprocess.ts # Future generic CLI provider
|
|
134
|
+
│ │ └── registry.ts
|
|
135
|
+
│ └── web/ # React SPA (Vite)
|
|
136
|
+
│ ├── index.html
|
|
137
|
+
│ ├── main.tsx
|
|
138
|
+
│ ├── app.tsx
|
|
139
|
+
│ ├── vite-env.d.ts
|
|
140
|
+
│ ├── components/
|
|
141
|
+
│ │ ├── auth/
|
|
142
|
+
│ │ │ └── login-screen.tsx # Token input screen
|
|
143
|
+
│ │ ├── layout/
|
|
144
|
+
│ │ │ ├── tab-bar.tsx
|
|
145
|
+
│ │ │ ├── tab-content.tsx
|
|
146
|
+
│ │ │ ├── sidebar.tsx # Desktop sidebar
|
|
147
|
+
│ │ │ ├── mobile-drawer.tsx # Mobile overlay sidebar
|
|
148
|
+
│ │ │ └── mobile-nav.tsx
|
|
149
|
+
│ │ ├── projects/
|
|
150
|
+
│ │ │ ├── project-list.tsx
|
|
151
|
+
│ │ │ └── project-card.tsx
|
|
152
|
+
│ │ ├── explorer/
|
|
153
|
+
│ │ │ ├── file-tree.tsx
|
|
154
|
+
│ │ │ └── file-actions.tsx
|
|
155
|
+
│ │ ├── editor/
|
|
156
|
+
│ │ │ ├── code-editor.tsx
|
|
157
|
+
│ │ │ └── diff-viewer.tsx
|
|
158
|
+
│ │ ├── terminal/
|
|
159
|
+
│ │ │ └── terminal-tab.tsx
|
|
160
|
+
│ │ ├── chat/
|
|
161
|
+
│ │ │ ├── chat-tab.tsx
|
|
162
|
+
│ │ │ ├── message-list.tsx
|
|
163
|
+
│ │ │ ├── message-input.tsx
|
|
164
|
+
│ │ │ ├── tool-approval.tsx
|
|
165
|
+
│ │ │ └── session-picker.tsx
|
|
166
|
+
│ │ ├── git/
|
|
167
|
+
│ │ │ ├── git-graph.tsx
|
|
168
|
+
│ │ │ ├── git-graph-renderer.tsx
|
|
169
|
+
│ │ │ ├── git-status-panel.tsx
|
|
170
|
+
│ │ │ ├── git-diff-tab.tsx
|
|
171
|
+
│ │ │ └── commit-context-menu.tsx
|
|
172
|
+
│ │ └── ui/ # shadcn/ui components
|
|
173
|
+
│ │ └── ...
|
|
174
|
+
│ ├── stores/
|
|
175
|
+
│ │ ├── tab.store.ts
|
|
176
|
+
│ │ ├── project.store.ts
|
|
177
|
+
│ │ └── settings.store.ts
|
|
178
|
+
│ ├── hooks/
|
|
179
|
+
│ │ ├── use-websocket.ts
|
|
180
|
+
│ │ ├── use-terminal.ts
|
|
181
|
+
│ │ └── use-chat.ts
|
|
182
|
+
│ ├── lib/
|
|
183
|
+
│ │ ├── api-client.ts # Auto-unwraps {ok, data} envelope
|
|
184
|
+
│ │ ├── ws-client.ts # WebSocket client with reconnect
|
|
185
|
+
│ │ └── git-graph-layout.ts
|
|
186
|
+
│ └── styles/
|
|
187
|
+
│ └── globals.css
|
|
188
|
+
├── tests/
|
|
189
|
+
│ ├── unit/
|
|
190
|
+
│ │ ├── services/
|
|
191
|
+
│ │ └── providers/
|
|
192
|
+
│ ├── integration/
|
|
193
|
+
│ │ ├── api/
|
|
194
|
+
│ │ └── ws/
|
|
195
|
+
│ └── setup.ts
|
|
196
|
+
├── scripts/
|
|
197
|
+
│ └── build.ts
|
|
198
|
+
└── docs/
|
|
199
|
+
├── project-overview-pdr.md
|
|
200
|
+
├── code-standards.md
|
|
201
|
+
└── system-architecture.md
|
|
202
|
+
```
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
phase: 1
|
|
3
|
+
title: "Backend project-scoped router"
|
|
4
|
+
status: completed
|
|
5
|
+
effort: 2h
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Phase 1: Backend Project-Scoped Router
|
|
9
|
+
|
|
10
|
+
## Context
|
|
11
|
+
- [plan.md](./plan.md)
|
|
12
|
+
- `src/server/index.ts` -- main app, route mounting, WS upgrade
|
|
13
|
+
- `src/server/routes/chat.ts`, `git.ts`, `files.ts`
|
|
14
|
+
- `src/server/helpers/resolve-project.ts`
|
|
15
|
+
- `src/server/ws/terminal.ts`, `chat.ts`
|
|
16
|
+
|
|
17
|
+
## Overview
|
|
18
|
+
Create a Hono sub-router mounted at `/api/project/:projectName` with middleware that resolves the project path. Remount chat, git, files routes under it. Remove per-route `resolveProjectPath` calls.
|
|
19
|
+
|
|
20
|
+
## Architecture
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
app.route("/api/project/:projectName", projectScopedRouter)
|
|
24
|
+
-> middleware: resolve projectName, set c.set("projectPath", path)
|
|
25
|
+
-> projectScopedRouter.route("/chat", chatRoutes)
|
|
26
|
+
-> projectScopedRouter.route("/git", gitRoutes)
|
|
27
|
+
-> projectScopedRouter.route("/files", fileRoutes)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Related Code Files
|
|
31
|
+
|
|
32
|
+
### Files to modify
|
|
33
|
+
- `src/server/index.ts` -- new mount point, update WS upgrade paths
|
|
34
|
+
- `src/server/routes/chat.ts` -- read projectPath from context, remove dir/projectName from query/body
|
|
35
|
+
- `src/server/routes/git.ts` -- read projectPath from context, remove `:project` param from each route, remove `project` from POST bodies
|
|
36
|
+
- `src/server/routes/files.ts` -- read projectPath from context, remove `:project` param from each route
|
|
37
|
+
|
|
38
|
+
### Files to create
|
|
39
|
+
- `src/server/routes/project-scoped.ts` -- the sub-router with middleware
|
|
40
|
+
|
|
41
|
+
### Files unchanged
|
|
42
|
+
- `src/server/routes/projects.ts` -- stays at `/api/projects` (global)
|
|
43
|
+
- `src/server/routes/static.ts` -- unchanged
|
|
44
|
+
- `src/server/middleware/auth.ts` -- unchanged
|
|
45
|
+
|
|
46
|
+
## Implementation Steps
|
|
47
|
+
|
|
48
|
+
### 1. Create project-scoped router (`src/server/routes/project-scoped.ts`)
|
|
49
|
+
```ts
|
|
50
|
+
import { Hono } from "hono";
|
|
51
|
+
import { resolveProjectPath } from "../helpers/resolve-project.ts";
|
|
52
|
+
import { chatRoutes } from "./chat.ts";
|
|
53
|
+
import { gitRoutes } from "./git.ts";
|
|
54
|
+
import { fileRoutes } from "./files.ts";
|
|
55
|
+
|
|
56
|
+
type Env = { Variables: { projectPath: string; projectName: string } };
|
|
57
|
+
|
|
58
|
+
export const projectScopedRouter = new Hono<Env>();
|
|
59
|
+
|
|
60
|
+
// Middleware: resolve project name to path
|
|
61
|
+
projectScopedRouter.use("*", async (c, next) => {
|
|
62
|
+
const name = c.req.param("projectName");
|
|
63
|
+
if (!name) return c.json({ ok: false, error: "Missing project name" }, 400);
|
|
64
|
+
const projectPath = resolveProjectPath(name);
|
|
65
|
+
c.set("projectPath", projectPath);
|
|
66
|
+
c.set("projectName", name);
|
|
67
|
+
await next();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
projectScopedRouter.route("/chat", chatRoutes);
|
|
71
|
+
projectScopedRouter.route("/git", gitRoutes);
|
|
72
|
+
projectScopedRouter.route("/files", fileRoutes);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2. Update `src/server/index.ts`
|
|
76
|
+
- Replace separate route mounts:
|
|
77
|
+
```diff
|
|
78
|
+
- app.route("/api/files", fileRoutes);
|
|
79
|
+
- app.route("/api/chat", chatRoutes);
|
|
80
|
+
- app.route("/api/git", gitRoutes);
|
|
81
|
+
+ app.route("/api/project/:projectName", projectScopedRouter);
|
|
82
|
+
```
|
|
83
|
+
- Keep: `app.route("/api/projects", projectRoutes)`
|
|
84
|
+
- Update WS upgrade paths (see Phase 4, but do now for consistency):
|
|
85
|
+
```diff
|
|
86
|
+
- if (url.pathname.startsWith("/ws/terminal/"))
|
|
87
|
+
+ if (url.pathname.startsWith("/ws/project/"))
|
|
88
|
+
```
|
|
89
|
+
Parse: `/ws/project/:projectName/terminal/:id` and `/ws/project/:projectName/chat/:sessionId`
|
|
90
|
+
|
|
91
|
+
### 3. Refactor `src/server/routes/git.ts`
|
|
92
|
+
- Remove `resolveProjectPath` import
|
|
93
|
+
- GET routes: remove `/:project` param segment; read `c.get("projectPath")` from context
|
|
94
|
+
- `/status/:project` -> `/status`
|
|
95
|
+
- `/diff/:project` -> `/diff`
|
|
96
|
+
- `/diff-stat/:project` -> `/diff-stat`
|
|
97
|
+
- `/file-diff/:project` -> `/file-diff`
|
|
98
|
+
- `/graph/:project` -> `/graph`
|
|
99
|
+
- `/branches/:project` -> `/branches`
|
|
100
|
+
- `/pr-url/:project` -> `/pr-url`
|
|
101
|
+
- POST routes: remove `project` from `c.req.json()` destructuring; use `c.get("projectPath")`
|
|
102
|
+
- `/stage`, `/unstage`, `/commit`, `/push`, `/pull`, `/branch/create`, `/checkout`, `/branch/delete`, `/merge`, `/cherry-pick`, `/revert`, `/tag`
|
|
103
|
+
|
|
104
|
+
### 4. Refactor `src/server/routes/files.ts`
|
|
105
|
+
- Remove `resolveProjectPath` import
|
|
106
|
+
- All routes: remove `/:project` param; use `c.get("projectPath")`
|
|
107
|
+
- `/tree/:project` -> `/tree`
|
|
108
|
+
- `/read/:project` -> `/read`
|
|
109
|
+
- `/write/:project` -> `/write`
|
|
110
|
+
- `/create/:project` -> `/create`
|
|
111
|
+
- `/delete/:project` -> `/delete`
|
|
112
|
+
- `/compare/:project` -> `/compare`
|
|
113
|
+
- `/rename/:project` -> `/rename`
|
|
114
|
+
- `/move/:project` -> `/move`
|
|
115
|
+
|
|
116
|
+
### 5. Refactor `src/server/routes/chat.ts`
|
|
117
|
+
- Remove `dir` query param from sessions list; project comes from URL context
|
|
118
|
+
- Remove `projectName` from POST body on session creation; use `c.get("projectName")`
|
|
119
|
+
- Keep `/providers` endpoint -- move to project-scoped or keep global. Decision: keep project-scoped since providers may vary per project in future.
|
|
120
|
+
- Sessions list: filter by `c.get("projectName")` instead of `dir` query
|
|
121
|
+
|
|
122
|
+
### 6. Update WS handlers in `src/server/index.ts`
|
|
123
|
+
- Terminal WS: `/ws/project/:projectName/terminal/:id`
|
|
124
|
+
- Parse projectName from URL, pass to ws.data
|
|
125
|
+
- Remove `?project=` query param
|
|
126
|
+
- Chat WS: `/ws/project/:projectName/chat/:sessionId`
|
|
127
|
+
- Parse projectName from URL, pass to ws.data
|
|
128
|
+
|
|
129
|
+
### 7. Update daemon `Bun.serve()` block (bottom of index.ts)
|
|
130
|
+
- Same WS path changes as foreground server
|
|
131
|
+
|
|
132
|
+
## Todo List
|
|
133
|
+
- [x] Create `src/server/routes/project-scoped.ts`
|
|
134
|
+
- [x] Update `src/server/index.ts` mounting
|
|
135
|
+
- [x] Refactor `git.ts` routes (17 endpoints)
|
|
136
|
+
- [x] Refactor `files.ts` routes (8 endpoints)
|
|
137
|
+
- [x] Refactor `chat.ts` routes (4 endpoints)
|
|
138
|
+
- [x] Update WS upgrade paths (foreground + daemon)
|
|
139
|
+
- [x] Verify compile with `bun build`
|
|
140
|
+
|
|
141
|
+
## Success Criteria
|
|
142
|
+
- All routes respond at new paths
|
|
143
|
+
- No `resolveProjectPath` calls in individual route files (only in middleware)
|
|
144
|
+
- Git POST routes no longer require `project` in body
|
|
145
|
+
- WS connections work at new paths
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
phase: 2
|
|
3
|
+
title: "Frontend API client + calls migration"
|
|
4
|
+
status: pending
|
|
5
|
+
effort: 2h
|
|
6
|
+
depends_on: [1]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Phase 2: Frontend API Client + Calls Migration
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
- [plan.md](./plan.md)
|
|
13
|
+
- [phase-01](./phase-01-backend-project-router.md)
|
|
14
|
+
- `src/web/lib/api-client.ts`
|
|
15
|
+
- All frontend components calling `/api/...`
|
|
16
|
+
|
|
17
|
+
## Overview
|
|
18
|
+
Add project-scoped URL helper to ApiClient. Update all frontend API calls to use `/api/project/:projectName/...` pattern. Remove `project` from POST bodies for git operations.
|
|
19
|
+
|
|
20
|
+
## Key Insight
|
|
21
|
+
Most components already have access to `projectName` via `useProjectStore` or props. The migration is mechanical: prefix every API path with `/api/project/${projectName}`.
|
|
22
|
+
|
|
23
|
+
## Related Code Files
|
|
24
|
+
|
|
25
|
+
### Files to modify
|
|
26
|
+
- `src/web/lib/api-client.ts` -- add `projectUrl()` helper
|
|
27
|
+
- `src/web/components/chat/chat-tab.tsx` -- session creation URL
|
|
28
|
+
- `src/web/components/chat/session-picker.tsx` -- session list/delete URLs
|
|
29
|
+
- `src/web/hooks/use-chat.ts` -- message history URL
|
|
30
|
+
- `src/web/components/git/git-graph.tsx` -- all git API calls (~12 calls)
|
|
31
|
+
- `src/web/components/git/git-status-panel.tsx` -- status, stage, unstage, commit, push, pull
|
|
32
|
+
- `src/web/stores/file-store.ts` -- file tree URL
|
|
33
|
+
- `src/web/components/editor/code-editor.tsx` -- read/write URLs
|
|
34
|
+
- `src/web/components/explorer/file-actions.tsx` -- create/rename/delete URLs
|
|
35
|
+
- `src/web/components/editor/diff-viewer.tsx` -- compare/diff URLs
|
|
36
|
+
|
|
37
|
+
## Implementation Steps
|
|
38
|
+
|
|
39
|
+
### 1. Add helper to `api-client.ts`
|
|
40
|
+
```ts
|
|
41
|
+
/** Build project-scoped API path prefix */
|
|
42
|
+
export function projectUrl(projectName: string): string {
|
|
43
|
+
return `/api/project/${encodeURIComponent(projectName)}`;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Update git-graph.tsx
|
|
48
|
+
Before:
|
|
49
|
+
```ts
|
|
50
|
+
`/api/git/graph/${encodeURIComponent(projectName)}?max=200`
|
|
51
|
+
gitAction("/api/git/checkout", { project: projectName, ref });
|
|
52
|
+
```
|
|
53
|
+
After:
|
|
54
|
+
```ts
|
|
55
|
+
`${projectUrl(projectName)}/git/graph?max=200`
|
|
56
|
+
gitAction(`${projectUrl(projectName)}/git/checkout`, { ref });
|
|
57
|
+
```
|
|
58
|
+
- Remove `project` field from all `gitAction` call bodies
|
|
59
|
+
- Update all GET URLs: `/api/git/status/:project` -> `${projectUrl(name)}/git/status`
|
|
60
|
+
|
|
61
|
+
### 3. Update git-status-panel.tsx
|
|
62
|
+
Same pattern:
|
|
63
|
+
- GET `/api/git/status/${name}` -> `${projectUrl(name)}/git/status`
|
|
64
|
+
- POST bodies: remove `project: projectName` field from stage/unstage/commit/push/pull
|
|
65
|
+
|
|
66
|
+
### 4. Update file-related components
|
|
67
|
+
- `file-store.ts`: `/api/files/tree/${name}` -> `${projectUrl(name)}/files/tree`
|
|
68
|
+
- `code-editor.tsx`: `/api/files/read/${name}?path=` -> `${projectUrl(name)}/files/read?path=`
|
|
69
|
+
- `file-actions.tsx`: same pattern for create/rename/delete
|
|
70
|
+
- `diff-viewer.tsx`: same pattern for compare/file-diff/diff
|
|
71
|
+
|
|
72
|
+
### 5. Update chat components
|
|
73
|
+
- `chat-tab.tsx`: `/api/chat/sessions` -> `${projectUrl(name)}/chat/sessions`
|
|
74
|
+
- Remove `projectName` from POST body
|
|
75
|
+
- `session-picker.tsx`: same prefix, remove `?dir=` query
|
|
76
|
+
- `use-chat.ts`: `/api/chat/sessions/:id/messages` -> `${projectUrl(name)}/chat/sessions/:id/messages`
|
|
77
|
+
- Need to pass projectName into `useChat` hook (add param)
|
|
78
|
+
|
|
79
|
+
### 6. Update use-chat.ts signature
|
|
80
|
+
```ts
|
|
81
|
+
export function useChat(
|
|
82
|
+
sessionId: string | null,
|
|
83
|
+
providerId: string,
|
|
84
|
+
projectName: string, // NEW
|
|
85
|
+
): UseChatReturn
|
|
86
|
+
```
|
|
87
|
+
- History fetch: `${projectUrl(projectName)}/chat/sessions/${sessionId}/messages?providerId=${providerId}`
|
|
88
|
+
- WS URL change handled in Phase 4
|
|
89
|
+
|
|
90
|
+
## Todo List
|
|
91
|
+
- [ ] Add `projectUrl()` to api-client.ts
|
|
92
|
+
- [ ] Update git-graph.tsx (~15 call sites)
|
|
93
|
+
- [ ] Update git-status-panel.tsx (~6 call sites)
|
|
94
|
+
- [ ] Update file-store.ts (1 call)
|
|
95
|
+
- [ ] Update code-editor.tsx (2 calls)
|
|
96
|
+
- [ ] Update file-actions.tsx (3 calls)
|
|
97
|
+
- [ ] Update diff-viewer.tsx (4 calls)
|
|
98
|
+
- [ ] Update chat-tab.tsx (1 call)
|
|
99
|
+
- [ ] Update session-picker.tsx (2 calls)
|
|
100
|
+
- [ ] Update use-chat.ts (1 call + signature)
|
|
101
|
+
- [ ] Verify compile
|
|
102
|
+
|
|
103
|
+
## Success Criteria
|
|
104
|
+
- All API calls use `/api/project/:projectName/...` prefix
|
|
105
|
+
- No `project` field in git POST bodies
|
|
106
|
+
- No `dir` query param in chat session list
|
|
107
|
+
- TypeScript compiles clean
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
phase: 3
|
|
3
|
+
title: "Per-project tab storage"
|
|
4
|
+
status: pending
|
|
5
|
+
effort: 1.5h
|
|
6
|
+
depends_on: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Phase 3: Per-Project Tab Storage
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
- [plan.md](./plan.md)
|
|
13
|
+
- `src/web/stores/tab-store.ts` -- current global tab store
|
|
14
|
+
- `src/web/stores/project-store.ts` -- project selection
|
|
15
|
+
- `src/web/app.tsx` -- default tab opening logic
|
|
16
|
+
|
|
17
|
+
## Overview
|
|
18
|
+
Make tabs project-scoped: each project gets its own tab set persisted under `ppm-tabs-{projectName}`. When user switches project, the tab bar swaps to that project's tabs.
|
|
19
|
+
|
|
20
|
+
## Key Design Decision
|
|
21
|
+
**Approach: Dynamic storage key** -- Zustand `persist` middleware does not natively support dynamic keys. Two options:
|
|
22
|
+
|
|
23
|
+
**Option A (chosen): Manual localStorage swap.** On project change, serialize current tabs to `ppm-tabs-{oldProject}`, load from `ppm-tabs-{newProject}`, hydrate store. Simple, no lib changes.
|
|
24
|
+
|
|
25
|
+
**Option B (rejected): Multiple store instances.** One store per project. Over-engineered for this use case.
|
|
26
|
+
|
|
27
|
+
## Related Code Files
|
|
28
|
+
|
|
29
|
+
### Files to modify
|
|
30
|
+
- `src/web/stores/tab-store.ts` -- add project-aware persist, swap logic
|
|
31
|
+
- `src/web/app.tsx` -- pass project context on default tab, react to project switch
|
|
32
|
+
|
|
33
|
+
## Implementation Steps
|
|
34
|
+
|
|
35
|
+
### 1. Refactor tab-store.ts
|
|
36
|
+
|
|
37
|
+
Remove Zustand `persist` middleware. Replace with manual localStorage read/write:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
const STORAGE_PREFIX = "ppm-tabs-";
|
|
41
|
+
|
|
42
|
+
function storageKey(projectName: string): string {
|
|
43
|
+
return `${STORAGE_PREFIX}${projectName}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function loadTabs(projectName: string): { tabs: Tab[]; activeTabId: string | null } {
|
|
47
|
+
try {
|
|
48
|
+
const raw = localStorage.getItem(storageKey(projectName));
|
|
49
|
+
if (raw) return JSON.parse(raw);
|
|
50
|
+
} catch { /* ignore */ }
|
|
51
|
+
return { tabs: [], activeTabId: null };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function saveTabs(projectName: string, state: { tabs: Tab[]; activeTabId: string | null }) {
|
|
55
|
+
localStorage.setItem(storageKey(projectName), JSON.stringify(state));
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Add to store:
|
|
60
|
+
```ts
|
|
61
|
+
interface TabStore {
|
|
62
|
+
// existing...
|
|
63
|
+
currentProject: string | null;
|
|
64
|
+
switchProject: (projectName: string) => void;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`switchProject(newProject)`:
|
|
69
|
+
1. If `currentProject` exists, save current tabs to localStorage under old key
|
|
70
|
+
2. Load tabs from new key
|
|
71
|
+
3. Set `currentProject = newProject`, hydrate tabs
|
|
72
|
+
4. If no tabs loaded, open default "Projects" tab
|
|
73
|
+
|
|
74
|
+
### 2. Auto-save on tab mutations
|
|
75
|
+
After every `openTab`, `closeTab`, `setActiveTab`, `updateTab` -- call `saveTabs(currentProject, { tabs, activeTabId })`. Use Zustand `subscribe` to batch this.
|
|
76
|
+
|
|
77
|
+
### 3. Update app.tsx
|
|
78
|
+
- On project change (when `activeProject` changes), call `useTabStore.getState().switchProject(activeProject.name)`
|
|
79
|
+
- Remove the "open default tab if none" effect -- let `switchProject` handle defaults
|
|
80
|
+
|
|
81
|
+
### 4. Clean up old storage
|
|
82
|
+
- Remove old `ppm-tabs` key migration: not needed on v2-fresh-start branch
|
|
83
|
+
|
|
84
|
+
### 5. Fix nextId collision
|
|
85
|
+
Current `nextId` is a module-level counter. On project switch, tabs from different projects may have overlapping IDs. Fix: derive nextId from loaded tabs on every switch.
|
|
86
|
+
|
|
87
|
+
## Todo List
|
|
88
|
+
- [ ] Remove `persist` middleware from tab-store
|
|
89
|
+
- [ ] Add manual localStorage read/write functions
|
|
90
|
+
- [ ] Add `currentProject` and `switchProject` to store
|
|
91
|
+
- [ ] Add `subscribe` auto-save
|
|
92
|
+
- [ ] Update `app.tsx` to call `switchProject` on project change
|
|
93
|
+
- [ ] Fix nextId derivation on hydration
|
|
94
|
+
- [ ] Test: switch project -> tabs change, switch back -> original tabs restored
|
|
95
|
+
|
|
96
|
+
## Success Criteria
|
|
97
|
+
- Each project has independent tab state in localStorage
|
|
98
|
+
- Switching project instantly swaps visible tabs
|
|
99
|
+
- Closing all tabs in project A does not affect project B
|
|
100
|
+
- Default "Projects" tab opens if project has no saved tabs
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
phase: 4
|
|
3
|
+
title: "WebSocket URL migration"
|
|
4
|
+
status: pending
|
|
5
|
+
effort: 0.5h
|
|
6
|
+
depends_on: [1]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Phase 4: WebSocket URL Migration
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
- [plan.md](./plan.md)
|
|
13
|
+
- [phase-01](./phase-01-backend-project-router.md) -- backend WS path changes
|
|
14
|
+
- `src/web/hooks/use-terminal.ts` -- terminal WS connection
|
|
15
|
+
- `src/web/hooks/use-chat.ts` -- chat WS connection (via use-websocket)
|
|
16
|
+
|
|
17
|
+
## Overview
|
|
18
|
+
Update frontend WS URLs to match new `/ws/project/:projectName/...` paths.
|
|
19
|
+
|
|
20
|
+
## Related Code Files
|
|
21
|
+
|
|
22
|
+
### Files to modify
|
|
23
|
+
- `src/web/hooks/use-terminal.ts` -- WS URL construction
|
|
24
|
+
- `src/web/hooks/use-chat.ts` -- WS URL passed to `useWebSocket`
|
|
25
|
+
|
|
26
|
+
## Implementation Steps
|
|
27
|
+
|
|
28
|
+
### 1. Update use-terminal.ts
|
|
29
|
+
Before:
|
|
30
|
+
```ts
|
|
31
|
+
const url = `${protocol}//${host}/ws/terminal/${sid}${projectParam ? `?project=${encodeURIComponent(projectParam)}` : ""}`;
|
|
32
|
+
```
|
|
33
|
+
After:
|
|
34
|
+
```ts
|
|
35
|
+
const url = `${protocol}//${host}/ws/project/${encodeURIComponent(options.projectName!)}/terminal/${sid}`;
|
|
36
|
+
```
|
|
37
|
+
- Remove `?project=` query param -- project is in path
|
|
38
|
+
- `projectName` is now required (not optional) in `UseTerminalOptions`
|
|
39
|
+
|
|
40
|
+
### 2. Update use-chat.ts
|
|
41
|
+
Before:
|
|
42
|
+
```ts
|
|
43
|
+
url: sessionId ? `/ws/chat/${sessionId}` : "",
|
|
44
|
+
```
|
|
45
|
+
After:
|
|
46
|
+
```ts
|
|
47
|
+
url: sessionId && projectName ? `/ws/project/${encodeURIComponent(projectName)}/chat/${sessionId}` : "",
|
|
48
|
+
```
|
|
49
|
+
- `projectName` param was added in Phase 2
|
|
50
|
+
|
|
51
|
+
### 3. Ensure backend parses new WS paths
|
|
52
|
+
Already handled in Phase 1, step 6. Verify:
|
|
53
|
+
- `/ws/project/:projectName/terminal/:id` extracts both projectName and id
|
|
54
|
+
- `/ws/project/:projectName/chat/:sessionId` extracts both
|
|
55
|
+
|
|
56
|
+
## Todo List
|
|
57
|
+
- [ ] Update `use-terminal.ts` WS URL
|
|
58
|
+
- [ ] Make `projectName` required in `UseTerminalOptions`
|
|
59
|
+
- [ ] Update `use-chat.ts` WS URL
|
|
60
|
+
- [ ] Verify both WS connections work end-to-end
|
|
61
|
+
|
|
62
|
+
## Success Criteria
|
|
63
|
+
- Terminal WS connects at `/ws/project/:projectName/terminal/:id`
|
|
64
|
+
- Chat WS connects at `/ws/project/:projectName/chat/:sessionId`
|
|
65
|
+
- No query params for project identification
|
|
66
|
+
- Both foreground and daemon server blocks handle new paths
|