@hienlh/ppm 0.9.52 → 0.9.54

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 (58) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/web/assets/{chat-tab-DvNEQYEe.js → chat-tab-C7LUU8uc.js} +1 -1
  3. package/dist/web/assets/{code-editor-CoT017Ah.js → code-editor-D8qEQfSv.js} +1 -1
  4. package/dist/web/assets/{database-viewer-C3wK7cDk.js → database-viewer-Duryc3Y0.js} +1 -1
  5. package/dist/web/assets/{diff-viewer-D0tuen4I.js → diff-viewer-UGOYufsF.js} +1 -1
  6. package/dist/web/assets/{extension-webview-Ba5aeo9r.js → extension-webview-fljR76zl.js} +1 -1
  7. package/dist/web/assets/{git-graph-BnJrVPxJ.js → git-graph-Ccyey8cC.js} +1 -1
  8. package/dist/web/assets/{index-DUQgLj0D.js → index-CgvhdpCl.js} +4 -4
  9. package/dist/web/assets/{index-BEfMoc_W.css → index-DVuSY0BZ.css} +1 -1
  10. package/dist/web/assets/keybindings-store-CGXc_Nqv.js +1 -0
  11. package/dist/web/assets/{markdown-renderer-BuGSrE3y.js → markdown-renderer-Fm0AKs27.js} +1 -1
  12. package/dist/web/assets/{port-forwarding-tab-DsbrWNUP.js → port-forwarding-tab-9XP7jh5d.js} +1 -1
  13. package/dist/web/assets/{postgres-viewer-Bh6YmZPq.js → postgres-viewer-BU2c67YN.js} +1 -1
  14. package/dist/web/assets/{settings-tab-BnzFtexC.js → settings-tab-kSrv-eTK.js} +1 -1
  15. package/dist/web/assets/sqlite-viewer-Ctlu51c-.js +1 -0
  16. package/dist/web/assets/{terminal-tab-fnZvscaH.js → terminal-tab-Cx6Wl0GQ.js} +1 -1
  17. package/dist/web/assets/{use-monaco-theme-BdcKAZ69.js → use-monaco-theme-DQ-JnmSE.js} +1 -1
  18. package/dist/web/index.html +2 -2
  19. package/dist/web/sw.js +1 -1
  20. package/docs/codebase-summary.md +52 -13
  21. package/docs/project-changelog.md +75 -1
  22. package/docs/project-roadmap.md +8 -7
  23. package/docs/system-architecture.md +193 -13
  24. package/package.json +1 -1
  25. package/src/cli/commands/bot-cmd.ts +144 -240
  26. package/src/cli/commands/restart.ts +29 -0
  27. package/src/cli/commands/stop.ts +67 -6
  28. package/src/index.ts +10 -1
  29. package/src/server/index.ts +131 -19
  30. package/src/server/routes/database.ts +31 -0
  31. package/src/server/routes/settings.ts +13 -0
  32. package/src/server/routes/sqlite.ts +14 -0
  33. package/src/services/autostart-generator.ts +8 -6
  34. package/src/services/database/postgres-adapter.ts +8 -0
  35. package/src/services/database/sqlite-adapter.ts +5 -0
  36. package/src/services/db.service.ts +109 -1
  37. package/src/services/postgres.service.ts +12 -0
  38. package/src/services/ppmbot/ppmbot-delegation.ts +112 -0
  39. package/src/services/ppmbot/ppmbot-service.ts +194 -369
  40. package/src/services/ppmbot/ppmbot-session.ts +85 -108
  41. package/src/services/ppmbot/ppmbot-telegram.ts +5 -16
  42. package/src/services/sqlite.service.ts +10 -0
  43. package/src/services/supervisor-state.ts +100 -0
  44. package/src/services/supervisor-stopped-page.ts +73 -0
  45. package/src/services/supervisor.ts +144 -50
  46. package/src/types/config.ts +1 -3
  47. package/src/types/database.ts +3 -0
  48. package/src/types/ppmbot.ts +21 -0
  49. package/src/web/components/settings/ppmbot-settings-section.tsx +87 -26
  50. package/src/web/components/sqlite/sqlite-data-grid.tsx +55 -8
  51. package/src/web/components/sqlite/sqlite-viewer.tsx +1 -0
  52. package/src/web/components/sqlite/use-sqlite.ts +16 -1
  53. package/dist/web/assets/keybindings-store-CkGFjxkX.js +0 -1
  54. package/dist/web/assets/sqlite-viewer-Cu3_hf07.js +0 -1
  55. package/docs/streaming-input-guide.md +0 -267
  56. package/snapshot-state.md +0 -1526
  57. package/test-session-ops.mjs +0 -444
  58. package/test-tokens.mjs +0 -212
@@ -193,14 +193,21 @@ Tab IDs are deterministic: `{type}:{identifier}` (e.g., `editor:src/index.ts`, `
193
193
  | **AccountService** | Account CRUD, token encryption/decryption | getAccounts, createAccount, updateAccount, deleteAccount |
194
194
  | **AccountSelectorService** | Select active account based on config | getActiveAccount, setActiveAccount, selectByProject |
195
195
  | **UpgradeService** | Version checking, installation, self-replace signaling | checkForUpdate, applyUpgrade, getInstallMethod, compareSemver |
196
- | **ClawBotService** | Telegram bot orchestrator | start, stop, handleMessage, routeToChat |
197
- | **ClawBotTelegramService** | Telegram long-polling, message ops | getUpdates, sendMessage, editMessage, setTyping, handleCommands |
198
- | **ClawBotSessionService** | chatID PPM sessionID mapping | mapSession, getSession, deleteSession |
199
- | **ClawBotMemoryService** | FTS5 memory persistence | saveMemory, recallMemories, decayMemories, searchByProject |
200
- | **ClawBotFormatterService** | Markdown Telegram HTML + chunking | formatMarkdown, chunkMessage |
201
- | **ClawBotStreamerService** | ChatEventprogressive Telegram edits | streamMessageEdits |
202
-
203
- **Key Files:** `src/services/*.service.ts`, `src/services/clawbot/*.ts`
196
+ | **PPMBotService** | Coordinator orchestrator (team leader, delegation mgmt) | start, stop, handleUpdate, checkPendingTasks |
197
+ | **PPMBotSessionManager** | Coordinator session per chat, project resolver | getCoordinatorSession, rotateCoordinatorSession, resolveProject |
198
+ | **PPMBotTelegramService** | Telegram long-polling, message ops | getUpdates, sendMessage, editMessage, setTyping, handleCommands |
199
+ | **PPMBotMemoryService** | SQLite project memory persistence | saveMemory, recallMemories, searchByProject |
200
+ | **executeDelegation()** | Task execution in isolated session, result capture | (async function, manages ChatService + result storage) |
201
+ | **PPMBotFormatterService** | Markdown → Telegram HTML + chunking | formatMarkdown, chunkMessage |
202
+ | **PPMBotStreamerService** | ChatEvent → progressive Telegram edits | streamMessageEdits |
203
+ | **ClawBotService** | LEGACY Telegram bot (deprecated v0.9.11) | (direct-chat model, replaced by coordinator) |
204
+ | **ClawBotTelegramService** | LEGACY Telegram API | (deprecated v0.9.11) |
205
+ | **ClawBotSessionService** | LEGACY chatID mapping | (deprecated v0.9.11) |
206
+ | **ClawBotMemoryService** | LEGACY FTS5 memory | (deprecated v0.9.11) |
207
+ | **ClawBotFormatterService** | LEGACY formatter | (deprecated v0.9.11) |
208
+ | **ClawBotStreamerService** | LEGACY streamer | (deprecated v0.9.11) |
209
+
210
+ **Key Files:** `src/services/*.service.ts`, `src/services/ppmbot/*.ts`, `src/cli/commands/bot-cmd.ts`
204
211
 
205
212
  ---
206
213
 
@@ -269,7 +276,112 @@ PPM supports multiple AI providers through a generic `AIProvider` interface and
269
276
 
270
277
  ---
271
278
 
272
- ### ClawBot Service Layer (Telegram Bot Integration)
279
+ ### PPMBot Coordinator Service Layer (Telegram-based Team Leader)
280
+ **Component:** PPMBot coordinator orchestrator + delegation executor
281
+
282
+ **Responsibilities:**
283
+ - Manage single persistent coordinator session per Telegram chat in `~/.ppm/bot/` workspace
284
+ - Route incoming Telegram messages to coordinator (ask/answer) or delegation tracking
285
+ - Decide when to answer directly vs. delegate to subagents (based on project context)
286
+ - Execute delegated tasks in isolated project sessions
287
+ - Track task status and report results back to Telegram
288
+ - Format responses as Telegram HTML with progressive message editing
289
+
290
+ **Architecture:**
291
+ ```
292
+ Telegram → PPMBotTelegramService (polling) → PPMBotService (orchestrator)
293
+
294
+ PPMBotSessionManager (coordinator session per chat)
295
+ coordinatorSession.id → chatService.sendMessage()
296
+ Task Poller (5s interval)
297
+
298
+ executeDelegation(taskId, telegram, providerId)
299
+ ├─ getBotTask(taskId) → prompt
300
+ ├─ chatService.createSession(providerId, projectPath)
301
+ ├─ run async generator (abort, 900s timeout)
302
+ └─ updateBotTaskStatus(taskId, "completed", {result})
303
+
304
+ telegram.sendMessage(chatId, result summary)
305
+ ```
306
+
307
+ **Services (src/services/ppmbot/):**
308
+ - **PPMBotService** — Lifecycle (start/stop), message queue, Telegram polling loop, task poller loop
309
+ - **PPMBotSessionManager** — Coordinator session cache per chatID, project resolver (case-insensitive, prefix match)
310
+ - **PPMBotTelegramService** — Telegram Bot API (getUpdates polling, sendMessage, editMessage, setTyping)
311
+ - **PPMBotMemoryService** — SQLite project memories, contextual recall
312
+ - **executeDelegation()** — Task execution in isolated session, result capture, timeout/abort handling
313
+ - **PPMBotFormatterService** — Markdown → Telegram HTML, 4096-char chunking
314
+ - **PPMBotStreamerService** — ChatEvent → progressive Telegram message edits (1s throttle)
315
+
316
+ **Coordinator Identity (Persistent Cross-Provider):**
317
+ - Location: `~/.ppm/bot/coordinator.md` (loaded on startup, cached in `coordinatorIdentity`)
318
+ - Role definition: Team leader, project coordinator, decision-maker
319
+ - Decision framework: Answer directly (no project context) vs. Delegate (file access needed)
320
+ - Coordination tools: Bash-safe CLI commands (`ppm bot delegate`, `ppm bot task-status`, etc.)
321
+ - Cross-provider: Identity text injected as XML context block, works with Claude SDK + CLI providers
322
+
323
+ **Delegation Flow:**
324
+ 1. User asks task in Telegram
325
+ 2. Coordinator decides: delegate? → yes
326
+ 3. Coordinator calls bash: `ppm bot delegate --chat <chatId> --project <name> --prompt "<enriched>"`
327
+ 4. CLI creates `bot_tasks` row, returns taskId
328
+ 5. Service tells user: "Working on it, I'll notify you when done"
329
+ 6. Background poller (5s) detects pending task
330
+ 7. Executes: `chatService.createSession()` in target project
331
+ 8. Streams response, captures summary + full output
332
+ 9. Updates task status → "completed"
333
+ 10. Sends Telegram notification with result
334
+
335
+ **Task Execution (Isolation & Safety):**
336
+ - Each task = fresh isolated session (no shared context)
337
+ - Timeout: 900s default (configurable per task)
338
+ - Abort: AbortController on timeout, can be canceled mid-execution
339
+ - Result capture: Both summary (for notification) and full text (for detailed review)
340
+ - Error handling: Task status → "failed", error message stored, user notified
341
+
342
+ **Database Schema (v14):**
343
+ - `bot_tasks` — id (UUID), chatId, projectName, projectPath, prompt, status, resultSummary, resultFull, sessionId, error, reported, timeoutMs, createdAt, startedAt, completedAt
344
+ - Indexes: `idx_bot_tasks_status` (fast poller lookup), `idx_bot_tasks_chat` (history queries)
345
+
346
+ **Key Design Decisions:**
347
+ 1. **Single coordinator session** — Per chat, persistent, one identity (vs. per-task sessions in ClawBot)
348
+ 2. **Delegation via CLI** — Coordinator calls bash commands (safer than direct DB writes, auditable)
349
+ 3. **Isolated task execution** — Each delegated task spawns fresh session (no context bleed)
350
+ 4. **Background polling** — Task execution decoupled from message handler (non-blocking)
351
+ 5. **Result summary + full** — Notification shows short summary; user can fetch full output via CLI
352
+ 6. **Cross-provider identity** — Single `coordinator.md` works with any AI provider
353
+ 7. **Bash-safe tools only** — Coordinator restricted to Bash, Read, Write, Edit, Glob, Grep (safe delegation)
354
+
355
+ **CLI Expansion (ppm bot commands):**
356
+ ```
357
+ ppm bot delegate --chat <id> --project <name> --prompt "<text>" # Create task
358
+ ppm bot task-status <id> # Check status
359
+ ppm bot task-result <id> # Get full output
360
+ ppm bot tasks [--chat <id>] # List recent
361
+ ppm bot project list # Available projects
362
+ ppm bot project current # Active project
363
+ ppm bot project switch <name> # Switch project
364
+ ppm bot session new <title> # Create session
365
+ ppm bot session list # List sessions
366
+ ppm bot session resume <id> # Resume session
367
+ ppm bot session stop <id> # Stop session
368
+ ppm bot status # Bot health
369
+ ppm bot version # PPM version
370
+ ppm bot restart # Restart service
371
+ ppm bot help # Help
372
+ ```
373
+
374
+ **Settings UI (ppmbot-settings-section.tsx):**
375
+ - Enable/disable PPMBot
376
+ - Paired Telegram chats (approval management)
377
+ - Default project selection
378
+ - System prompt customization
379
+ - Task auto-refresh (poll interval, max history)
380
+ - Delegated tasks panel (status, result preview, delete)
381
+
382
+ ---
383
+
384
+ ### ClawBot Service Layer (Telegram Bot Integration) — LEGACY (v0.9.10)
273
385
  **Component:** Telegram bot service + subsidiary services
274
386
 
275
387
  **Responsibilities:**
@@ -1628,13 +1740,81 @@ $ ppm upgrade
1628
1740
  → Works in headless environments (no OS autostart dependency)
1629
1741
 
1630
1742
  $ ppm stop
1631
- Reads ~/.ppm/status.json first (new format)
1632
- Falls back to ppm.pid (compat)
1633
- Sends SIGTERM to daemon
1743
+ SOFT STOP: kills server only, supervisor stays alive with Cloud WS + tunnel
1744
+ Supervisor transitions to "stopped" state
1745
+ Minimal HTML page served on port (503 status on /api/health)
1746
+ → Tunnel and Cloud connectivity remain active
1747
+ → `ppm start` resumes without restarting supervisor process
1748
+
1749
+ $ ppm stop --kill OR ppm down
1750
+ → FULL SHUTDOWN: kills everything (supervisor + server + tunnel)
1751
+ → Supervisor transitions to "upgrading" then terminates
1634
1752
  → Cleans up status.json and ppm.pid
1635
- → Graceful shutdown (close WS, cleanup PTY, stop tunnel)
1753
+ → Graceful cleanup (close WS, cleanup PTY, stop tunnel)
1754
+ ```
1755
+
1756
+ ### Supervisor Architecture (v0.9.11+)
1757
+
1758
+ The supervisor is a long-lived parent process that manages server + tunnel children with resilience and state management.
1759
+
1760
+ **Architecture:**
1761
+ ```
1762
+ Supervisor Process (parent)
1763
+ ├── Server Child (Hono HTTP server)
1764
+ │ ├── Health checks every 30s (/api/health)
1765
+ │ ├── Auto-restart on crash (exponential backoff, max 10 restarts)
1766
+ │ └── If in "stopped" state, serves minimal 503 page instead of restarting
1767
+
1768
+ ├── Tunnel Child (Cloudflare Quick Tunnel, if --share)
1769
+ │ ├── URL probe every 2min
1770
+ │ ├── Auto-reconnect on failure
1771
+ │ └── URL persisted to status.json
1772
+
1773
+ ├── State Machine: "running" | "paused" | "stopped" | "upgrading"
1774
+ │ ├── running — Server spawned, tunnel optional, serving requests
1775
+ │ ├── paused — Supervisor paused (resume via signal)
1776
+ │ ├── stopped — Server stopped (soft stop), tunnel alive, Cloud WS active
1777
+ │ └── upgrading — Self-replace in progress
1778
+
1779
+ ├── Upgrade Check (every 15min)
1780
+ │ └── npm registry poll → availableVersion written to status.json
1781
+
1782
+ ├── Stopped Page Server
1783
+ │ ├── Lightweight HTTP handler on same port as server
1784
+ │ ├── Returns 503 on /api/health
1785
+ │ └── Tunnels Cloud WS calls through to PPM Cloud
1786
+
1787
+ └── Error Resilience
1788
+ ├── uncaughtException → log + exit gracefully
1789
+ ├── unhandledRejection → log + continue
1790
+ └── Signal handlers: SIGTERM (full shutdown), SIGUSR1 (self-replace), SIGUSR2 (restart skip backoff)
1636
1791
  ```
1637
1792
 
1793
+ **Soft Stop vs Full Shutdown:**
1794
+ | Command | Server | Supervisor | Tunnel | Use Case |
1795
+ |---------|--------|------------|--------|----------|
1796
+ | `ppm stop` | Killed | Stays alive | Stays alive | Restart later with `ppm start` |
1797
+ | `ppm stop --kill` | Killed | Killed | Killed | Full cleanup, exit |
1798
+ | `ppm down` | Killed | Killed | Killed | Full cleanup, exit |
1799
+
1800
+ **State Persistence:**
1801
+ - Status file: `~/.ppm/status.json` — PID, port, host, shareUrl, supervisorPid, availableVersion, state
1802
+ - Lock file: `~/.ppm/.start-lock` — Prevent concurrent starts
1803
+ - Command file: `~/.ppm/.supervisor-cmd` — IPC for soft_stop, resume, self_replace
1804
+
1805
+ **Stopped Page Implementation:**
1806
+ - Minimal HTTP server on same port as main server
1807
+ - Serves `503 Service Unavailable` on /api/health
1808
+ - Proxies Cloud WS calls to PPM Cloud (if tunnel configured)
1809
+ - Allows `ppm start` to resume without supervisor restart
1810
+
1811
+ **Files (Modular Design):**
1812
+ - `src/services/supervisor.ts` — Main orchestrator (spawn, health checks, upgrade checks)
1813
+ - `src/services/supervisor-state.ts` — State machine, IPC command handling, signal routing
1814
+ - `src/services/supervisor-stopped-page.ts` — Minimal 503 page + Cloud WS proxy
1815
+
1816
+ ---
1817
+
1638
1818
  ### Future: Multi-Machine (Not in v2)
1639
1819
  Would require:
1640
1820
  - Central state server (Redis/Postgres)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.9.52",
3
+ "version": "0.9.54",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "MIT",