@hienlh/ppm 0.9.0-beta.2 → 0.9.0-beta.4

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 (187) hide show
  1. package/CHANGELOG.md +10 -26
  2. package/dist/web/assets/{_basePickBy-CZovQgWd.js → _basePickBy-COwDPZl_.js} +1 -1
  3. package/dist/web/assets/{_baseUniq-ClnvscgW.js → _baseUniq-DCb0mkTp.js} +1 -1
  4. package/dist/web/assets/{api-settings--eVrUeZM.js → api-settings-CuUkz5gb.js} +1 -1
  5. package/dist/web/assets/{arc-C2Qaz-ch.js → arc-D0bJaFyD.js} +1 -1
  6. package/dist/web/assets/architecture-PBZL5I3N-281eTKQ3.js +1 -0
  7. package/dist/web/assets/{architectureDiagram-2XIMDMQ5-Jq91S_rs.js → architectureDiagram-2XIMDMQ5-BVEUkQYB.js} +1 -1
  8. package/dist/web/assets/arrow-left-C_j9Ki73.js +1 -0
  9. package/dist/web/assets/{blockDiagram-WCTKOSBZ-CKGufRTy.js → blockDiagram-WCTKOSBZ-CU2t4NHJ.js} +1 -1
  10. package/dist/web/assets/browser-tab-BhTdeeZd.js +1 -0
  11. package/dist/web/assets/{c4Diagram-IC4MRINW-BNP2L9r_.js → c4Diagram-IC4MRINW-DzjR91sM.js} +1 -1
  12. package/dist/web/assets/channel-CKNZAqoN.js +1 -0
  13. package/dist/web/assets/chat-tab-ZiiUVOxM.js +7 -0
  14. package/dist/web/assets/{chunk-4BX2VUAB-BptTlTyl.js → chunk-4BX2VUAB-0YMkpW2S.js} +1 -1
  15. package/dist/web/assets/{chunk-55IACEB6-C4mUdyio.js → chunk-55IACEB6-Dp0pTM5r.js} +1 -1
  16. package/dist/web/assets/{chunk-7E7YKBS2-6xAQfBwa.js → chunk-7E7YKBS2-CuYKSUgJ.js} +1 -1
  17. package/dist/web/assets/{chunk-7R4GIKGN-DXaGAn_K.js → chunk-7R4GIKGN-DvbvLUIN.js} +2 -2
  18. package/dist/web/assets/{chunk-C72U2L5F-DOtEiN5f.js → chunk-C72U2L5F-CcEW1AMZ.js} +1 -1
  19. package/dist/web/assets/{chunk-EGIJ26TM-D0KJTa_T.js → chunk-EGIJ26TM-Cgt-qg75.js} +1 -1
  20. package/dist/web/assets/{chunk-FMBD7UC4-C_1aG0eb.js → chunk-FMBD7UC4-JCLgVcaC.js} +1 -1
  21. package/dist/web/assets/{chunk-GEFDOKGD-DwVPiYfW.js → chunk-GEFDOKGD-B82RP9ow.js} +1 -1
  22. package/dist/web/assets/chunk-GLR3WWYH-Bx2UL5jF.js +2 -0
  23. package/dist/web/assets/chunk-HHEYEP7N-BnRVfNc5.js +1 -0
  24. package/dist/web/assets/{chunk-JSJVCQXG-BSrqCL_3.js → chunk-JSJVCQXG-Pb-JMOgO.js} +1 -1
  25. package/dist/web/assets/{chunk-KX2RTZJC-BCxGmbzy.js → chunk-KX2RTZJC-BRj-ZEvL.js} +1 -1
  26. package/dist/web/assets/{chunk-KYZI473N-BKO5gMeU.js → chunk-KYZI473N-CBRPKraG.js} +1 -1
  27. package/dist/web/assets/{chunk-L3YUKLVL-3wBgkSvL.js → chunk-L3YUKLVL-DNFj84V6.js} +1 -1
  28. package/dist/web/assets/{chunk-MX3YWQON-BgjSEzus.js → chunk-MX3YWQON-BnPzQK-O.js} +1 -1
  29. package/dist/web/assets/{chunk-NQ4KR5QH-DLrZwBEm.js → chunk-NQ4KR5QH-BRj25yO7.js} +1 -1
  30. package/dist/web/assets/{chunk-O4XLMI2P-BurQy8tt.js → chunk-O4XLMI2P-BdXwVXjJ.js} +1 -1
  31. package/dist/web/assets/{chunk-OZEHJAEY-YTn24bGg.js → chunk-OZEHJAEY-LfXT4p8B.js} +1 -1
  32. package/dist/web/assets/{chunk-PQ6SQG4A-BxtUGYhW.js → chunk-PQ6SQG4A-EdgQyTqa.js} +1 -1
  33. package/dist/web/assets/{chunk-PU5JKC2W-B66ELkQm.js → chunk-PU5JKC2W-D3thuSok.js} +1 -1
  34. package/dist/web/assets/chunk-QZHKN3VN-gaBt0Rbd.js +1 -0
  35. package/dist/web/assets/{chunk-R5LLSJPH-euR2RxLN.js → chunk-R5LLSJPH-LdG7RqsM.js} +1 -1
  36. package/dist/web/assets/{chunk-WL4C6EOR-_2CBOJdI.js → chunk-WL4C6EOR-BHFnnXOt.js} +1 -1
  37. package/dist/web/assets/{chunk-XIRO2GV7-kqQ0g6wW.js → chunk-XIRO2GV7-DUmQrLsF.js} +1 -1
  38. package/dist/web/assets/{chunk-XPW4576I-CtcaMb09.js → chunk-XPW4576I-CsGTseUr.js} +1 -1
  39. package/dist/web/assets/{chunk-XZSTWKYB-BYxFzZwS.js → chunk-XZSTWKYB-5W2emiq4.js} +1 -1
  40. package/dist/web/assets/{chunk-YBOYWFTD-Dx_fX35n.js → chunk-YBOYWFTD-COdZIaX4.js} +1 -1
  41. package/dist/web/assets/classDiagram-VBA2DB6C-CqaIqYPn.js +1 -0
  42. package/dist/web/assets/classDiagram-v2-RAHNMMFH-Bo5WN2ok.js +1 -0
  43. package/dist/web/assets/clone-DNDy9Sms.js +1 -0
  44. package/dist/web/assets/{code-editor-CQ7gq0Vj.js → code-editor-BRMOypkX.js} +1 -1
  45. package/dist/web/assets/{cose-bilkent-S5V4N54A-CHHjH2dV.js → cose-bilkent-S5V4N54A-C1QJ6GPW.js} +1 -1
  46. package/dist/web/assets/{dagre-CNtSxiE_.js → dagre-CWo8w9wK.js} +1 -1
  47. package/dist/web/assets/{dagre-KLK3FWXG-ChenfPp1.js → dagre-KLK3FWXG-Br4t5TRV.js} +1 -1
  48. package/dist/web/assets/database-viewer-CEoDpzPz.js +1 -0
  49. package/dist/web/assets/{diagram-E7M64L7V-CzKYZM0Y.js → diagram-E7M64L7V-CkDC2uAj.js} +1 -1
  50. package/dist/web/assets/{diagram-IFDJBPK2-ChB_paPo.js → diagram-IFDJBPK2-NvhckwcA.js} +1 -1
  51. package/dist/web/assets/{diagram-P4PSJMXO-D1eW1dkL.js → diagram-P4PSJMXO--nUaNiyB.js} +1 -1
  52. package/dist/web/assets/{diff-viewer-BjtTemkK.js → diff-viewer-jDU2bcGj.js} +1 -1
  53. package/dist/web/assets/{erDiagram-INFDFZHY-mCvUFSn6.js → erDiagram-INFDFZHY-DK4QEZYh.js} +1 -1
  54. package/dist/web/assets/{flowDiagram-PKNHOUZH-14ohZ1M1.js → flowDiagram-PKNHOUZH-B9h_Ba-v.js} +1 -1
  55. package/dist/web/assets/{ganttDiagram-A5KZAMGK-DIX0pLbk.js → ganttDiagram-A5KZAMGK-BVlftqyZ.js} +1 -1
  56. package/dist/web/assets/git-graph-DMQzw4Sp.js +1 -0
  57. package/dist/web/assets/gitGraph-HDMCJU4V-D5qEPjgs.js +1 -0
  58. package/dist/web/assets/{gitGraphDiagram-K3NZZRJ6-yEWZbdf_.js → gitGraphDiagram-K3NZZRJ6-L7sj3Bs-.js} +1 -1
  59. package/dist/web/assets/{graphlib-DhOZxqsh.js → graphlib-BbbiUImY.js} +1 -1
  60. package/dist/web/assets/index-B4Iz1Wbi.css +2 -0
  61. package/dist/web/assets/index-QiSWS6f-.js +37 -0
  62. package/dist/web/assets/info-3K5VOQVL-CbpovIYU.js +1 -0
  63. package/dist/web/assets/infoDiagram-LFFYTUFH-DFh9c-S2.js +2 -0
  64. package/dist/web/assets/input-DGlv6gt_.js +41 -0
  65. package/dist/web/assets/{isEmpty-C0YYdhYj.js → isEmpty-DXomfd7J.js} +1 -1
  66. package/dist/web/assets/{ishikawaDiagram-PHBUUO56-olazD6dZ.js → ishikawaDiagram-PHBUUO56-cW7SMLa_.js} +1 -1
  67. package/dist/web/assets/{journeyDiagram-4ABVD52K-CttDH9bb.js → journeyDiagram-4ABVD52K-DFQXUZsc.js} +1 -1
  68. package/dist/web/assets/{kanban-definition-K7BYSVSG-BBXbI37U.js → kanban-definition-K7BYSVSG-BMUhjxqj.js} +1 -1
  69. package/dist/web/assets/keybindings-store-BplH-yiN.js +1 -0
  70. package/dist/web/assets/{line-DBLLF7lH.js → line--xyfYP3x.js} +1 -1
  71. package/dist/web/assets/{linear-BLFWatDe.js → linear-BdqW7iQu.js} +1 -1
  72. package/dist/web/assets/{markdown-renderer-BtPXdzTv.js → markdown-renderer-BCjJbGP8.js} +5 -5
  73. package/dist/web/assets/{mermaid-parser.core-BKiGOTjR.js → mermaid-parser.core-BY8JfkE_.js} +2 -2
  74. package/dist/web/assets/{mindmap-definition-YRQLILUH-DoT7m4Sz.js → mindmap-definition-YRQLILUH-DIv-LMXG.js} +1 -1
  75. package/dist/web/assets/{ordinal-CCj7PWgZ.js → ordinal-CIoJK3nc.js} +1 -1
  76. package/dist/web/assets/packet-RMMSAZCW-BbzPU9BK.js +1 -0
  77. package/dist/web/assets/pie-UPGHQEXC-B0h6hM1j.js +1 -0
  78. package/dist/web/assets/{pieDiagram-SKSYHLDU-Bkh2E4zE.js → pieDiagram-SKSYHLDU-seSK40d1.js} +1 -1
  79. package/dist/web/assets/postgres-viewer-s0snZ9CL.js +1 -0
  80. package/dist/web/assets/{quadrantDiagram-337W2JSQ-B7zgALOL.js → quadrantDiagram-337W2JSQ-BaRFqlsA.js} +1 -1
  81. package/dist/web/assets/radar-KQ55EAFF-CHptMqVT.js +1 -0
  82. package/dist/web/assets/{requirementDiagram-Z7DCOOCP-D_5GXNRo.js → requirementDiagram-Z7DCOOCP-1WWjMQB_.js} +1 -1
  83. package/dist/web/assets/{sankeyDiagram-WA2Y5GQK-BA9EFAAe.js → sankeyDiagram-WA2Y5GQK-DEGGYsk7.js} +1 -1
  84. package/dist/web/assets/{sequenceDiagram-2WXFIKYE-fyWIrHiG.js → sequenceDiagram-2WXFIKYE-BtRvoUTC.js} +1 -1
  85. package/dist/web/assets/{settings-store-Bbhg_ptG.js → settings-store-D3dJqGhB.js} +2 -2
  86. package/dist/web/assets/settings-tab-2YkgmrY0.js +1 -0
  87. package/dist/web/assets/sqlite-viewer-B5GNwXaG.js +1 -0
  88. package/dist/web/assets/{stateDiagram-RAJIS63D-DfRBcaBu.js → stateDiagram-RAJIS63D-C16aO8tn.js} +1 -1
  89. package/dist/web/assets/stateDiagram-v2-FVOUBMTO-D7qSAjnK.js +1 -0
  90. package/dist/web/assets/switch-mjGtIVDJ.js +1 -0
  91. package/dist/web/assets/{tab-store-dpsCvqhH.js → tab-store-DSz5PQI0.js} +1 -1
  92. package/dist/web/assets/{terminal-tab--Gw14HP3.js → terminal-tab-MRg8y1xF.js} +2 -2
  93. package/dist/web/assets/{timeline-definition-YZTLITO2-DYfwJ1jM.js → timeline-definition-YZTLITO2-DrjxCpEM.js} +1 -1
  94. package/dist/web/assets/treemap-KZPCXAKY-BL9OJq3X.js +1 -0
  95. package/dist/web/assets/{use-monaco-theme-DHbyUrzJ.js → use-monaco-theme-BQzvItNE.js} +1 -1
  96. package/dist/web/assets/{vennDiagram-LZ73GAT5-DqbKNRD9.js → vennDiagram-LZ73GAT5-DfYFnniI.js} +1 -1
  97. package/dist/web/assets/{xychartDiagram-JWTSCODW-DhUL86qT.js → xychartDiagram-JWTSCODW-BRvXOVlG.js} +1 -1
  98. package/dist/web/index.html +12 -10
  99. package/dist/web/sw.js +1 -1
  100. package/docs/code-standards.md +260 -7
  101. package/docs/codebase-summary.md +255 -95
  102. package/docs/project-changelog.md +88 -1
  103. package/docs/system-architecture.md +177 -12
  104. package/package.json +1 -1
  105. package/src/providers/claude-agent-sdk.ts +9 -0
  106. package/src/providers/cli-provider-base.ts +238 -0
  107. package/src/providers/cursor-cli/cursor-event-mapper.ts +85 -0
  108. package/src/providers/cursor-cli/cursor-history.ts +207 -0
  109. package/src/providers/cursor-cli/cursor-provider.ts +146 -0
  110. package/src/providers/mock-provider.ts +1 -1
  111. package/src/providers/provider.interface.ts +1 -0
  112. package/src/providers/registry.ts +43 -4
  113. package/src/server/index.ts +8 -0
  114. package/src/server/routes/browser-preview.ts +89 -0
  115. package/src/server/routes/chat.ts +14 -3
  116. package/src/server/routes/settings.ts +14 -0
  117. package/src/server/ws/chat.ts +24 -8
  118. package/src/services/chat.service.ts +10 -15
  119. package/src/types/chat.ts +21 -2
  120. package/src/types/config.ts +33 -11
  121. package/src/utils/ndjson-line-parser.ts +36 -0
  122. package/src/web/components/browser/browser-tab.tsx +269 -0
  123. package/src/web/components/chat/chat-history-bar.tsx +49 -29
  124. package/src/web/components/chat/chat-tab.tsx +14 -2
  125. package/src/web/components/chat/message-input.tsx +91 -3
  126. package/src/web/components/chat/provider-selector.tsx +150 -0
  127. package/src/web/components/chat/session-picker.tsx +3 -1
  128. package/src/web/components/layout/command-palette.tsx +4 -0
  129. package/src/web/components/layout/editor-panel.tsx +1 -0
  130. package/src/web/components/layout/mobile-nav.tsx +2 -2
  131. package/src/web/components/layout/panel-layout.tsx +17 -1
  132. package/src/web/components/layout/tab-bar.tsx +2 -0
  133. package/src/web/components/layout/tab-content.tsx +5 -0
  134. package/src/web/components/settings/ai-settings-section.tsx +196 -137
  135. package/src/web/hooks/use-chat.ts +11 -0
  136. package/src/web/hooks/use-global-keybindings.ts +7 -0
  137. package/src/web/hooks/use-voice-input.ts +111 -0
  138. package/src/web/stores/keybindings-store.ts +1 -0
  139. package/src/web/stores/panel-store.ts +10 -10
  140. package/src/web/stores/tab-store.ts +2 -1
  141. package/dist/web/assets/architecture-PBZL5I3N-ChOahOB7.js +0 -1
  142. package/dist/web/assets/channel-w7yboq56.js +0 -1
  143. package/dist/web/assets/chat-tab-DmF14O6G.js +0 -7
  144. package/dist/web/assets/chunk-GLR3WWYH-D9pZakqr.js +0 -2
  145. package/dist/web/assets/chunk-HHEYEP7N-Dld5BpGB.js +0 -1
  146. package/dist/web/assets/chunk-QZHKN3VN-DwSXwtjH.js +0 -1
  147. package/dist/web/assets/classDiagram-VBA2DB6C-BpJ6Oog2.js +0 -1
  148. package/dist/web/assets/classDiagram-v2-RAHNMMFH-Bj8gIhkP.js +0 -1
  149. package/dist/web/assets/clone-BSi6cgDh.js +0 -1
  150. package/dist/web/assets/database-viewer-B27aRtdQ.js +0 -1
  151. package/dist/web/assets/git-graph-BGXo0o-J.js +0 -1
  152. package/dist/web/assets/gitGraph-HDMCJU4V-CEee2FCA.js +0 -1
  153. package/dist/web/assets/index-BAioKo_2.css +0 -2
  154. package/dist/web/assets/index-CfClIVo2.js +0 -37
  155. package/dist/web/assets/info-3K5VOQVL-ce_pi3En.js +0 -1
  156. package/dist/web/assets/infoDiagram-LFFYTUFH-BzqyoqXw.js +0 -2
  157. package/dist/web/assets/input-Brjz2Vv-.js +0 -41
  158. package/dist/web/assets/keybindings-store-nDbczFnq.js +0 -1
  159. package/dist/web/assets/packet-RMMSAZCW-CdYSLjRL.js +0 -1
  160. package/dist/web/assets/pie-UPGHQEXC-Bm5LiD-6.js +0 -1
  161. package/dist/web/assets/postgres-viewer-BMg-qFcO.js +0 -1
  162. package/dist/web/assets/radar-KQ55EAFF-C4PnyG7_.js +0 -1
  163. package/dist/web/assets/settings-tab-NPuwQHzs.js +0 -1
  164. package/dist/web/assets/sqlite-viewer-CAsUczio.js +0 -1
  165. package/dist/web/assets/stateDiagram-v2-FVOUBMTO-CMN4M2Em.js +0 -1
  166. package/dist/web/assets/treemap-KZPCXAKY-2_y-mhkz.js +0 -1
  167. package/snapshot-state.md +0 -1526
  168. package/test-tokens.mjs +0 -212
  169. /package/dist/web/assets/{api-client-DpGMOZNf.js → api-client-icCZ-07C.js} +0 -0
  170. /package/dist/web/assets/{array-BGFCBI0e.js → array-CLwNaqU1.js} +0 -0
  171. /package/dist/web/assets/{columns-2-ChOTgl3e.js → columns-2-Bcg3QJBg.js} +0 -0
  172. /package/dist/web/assets/{cytoscape.esm-Ccan6xou.js → cytoscape.esm-B-QQuWwK.js} +0 -0
  173. /package/dist/web/assets/{defaultLocale-CRZydyG6.js → defaultLocale-D_VMtRaY.js} +0 -0
  174. /package/dist/web/assets/{dist-T0Vhi0Mh.js → dist-CMmNEgEP.js} +0 -0
  175. /package/dist/web/assets/{dist-Cce3efmT.js → dist-Ckxnw5rl.js} +0 -0
  176. /package/dist/web/assets/{init-B8gtcn7T.js → init-vVpfz1D6.js} +0 -0
  177. /package/dist/web/assets/{isArrayLikeObject-B4pdpV8V.js → isArrayLikeObject-DvHDmeBe.js} +0 -0
  178. /package/dist/web/assets/{katex-Bbu770d9.js → katex-C3cZrCvP.js} +0 -0
  179. /package/dist/web/assets/{math-DwgHI-Cu.js → math-a44lmFDa.js} +0 -0
  180. /package/dist/web/assets/{path-DZF-JdEe.js → path-CuyvWNAH.js} +0 -0
  181. /package/dist/web/assets/{preload-helper-qlgyTAkD.js → preload-helper-CsoeaaUJ.js} +0 -0
  182. /package/dist/web/assets/{react-BGf7KNLk.js → react-BPIfZRKM.js} +0 -0
  183. /package/dist/web/assets/{rough.esm-VLpapkIG.js → rough.esm-c4PR5shF.js} +0 -0
  184. /package/dist/web/assets/{src-BoSBNdA_.js → src-CLWraeNW.js} +0 -0
  185. /package/dist/web/assets/{table-Yo02WRH-.js → table-C9jDaRl2.js} +0 -0
  186. /package/dist/web/assets/{tag-CaC1ng2E.js → tag-CENGyt_L.js} +0 -0
  187. /package/dist/web/assets/{utils-btZ8C8-R.js → utils-Bslrbb-G.js} +0 -0
@@ -1,103 +1,100 @@
1
1
  # PPM Codebase Summary
2
2
 
3
- Generated from codebase analysis of 135+ TypeScript files, ~22.5K LOC (including multi-account feature).
3
+ **Last Updated:** 2026-03-26
4
+ **Version:** 0.8.60
5
+ **Repository:** PPM (Project & Process Manager) — Multi-provider web IDE/project manager with Claude Agent SDK
6
+
7
+ **Core Statistics:**
8
+ - **303 files** across CLI, server, web, and test layers
9
+ - **490,667 tokens** total codebase size
10
+ - **492 passing tests** (13 new tests for provider models API)
11
+ - **Tech Stack:** Bun (runtime), Hono (HTTP), React (UI), Claude Agent SDK (AI)
12
+
13
+ ---
4
14
 
5
15
  ## Directory Structure
6
16
 
7
17
  ```
8
- ppm/
9
- ├── src/
10
- │ ├── index.ts # CLI entry point (Commander.js program)
11
- ├── cli/
12
- │ ├── commands/ # CLI command implementations (14 files, 1700 LOC)
13
- │ │ │ ├── start.ts # Start server (background by default, --foreground/-f, --share/-s for tunnel)
14
- │ │ ├── stop.ts # Stop daemon (reads status.json or ppm.pid, graceful shutdown)
15
- │ │ ├── restart.ts # Restart daemon (keeps tunnel alive)
16
- │ │ │ ├── status.ts # Show daemon status
17
- │ │ ├── open.ts # Open browser to http://localhost:PORT
18
- │ │ ├── logs.ts # Tail daemon logs
19
- │ │ ├── report.ts # File bug report on GitHub
20
- │ │ ├── init.ts # Initialize config (scan git repos, DB profile support)
21
- │ │ ├── projects.ts # Add/remove/list/scan projects
22
- │ │ ├── config-cmd.ts # View/set config values
23
- │ │ ├── git-cmd.ts # Git operations (status, diff, log, commit)
24
- │ │ ├── chat-cmd.ts # Chat CLI (send messages, manage sessions)
25
- │ │ │ └── db-cmd.ts # Database CLI (list, query, manage connections)
26
- │ │ └── utils/
27
- │ └── project-resolver.ts # Resolve project name -> path
28
- ├── server/
29
- │ ├── index.ts # Hono server setup, Bun.serve, WebSocket upgrade
30
- ├── middleware/
31
- │ │ └── auth.ts # Token validation middleware
32
- │ │ ├── routes/
33
- │ │ ├── settings.ts # GET/PUT /api/settings/ai (AI provider config)
34
- │ │ ├── projects.ts # GET/POST /api/projects, DELETE /:name
35
- │ │ ├── accounts.ts # GET/POST/PUT/DELETE /api/accounts, POST activate
36
- │ │ │ ├── project-scoped.ts # Mount chat, git, files under /api/project/:name/*
37
- │ │ ├── chat.ts # GET/POST/DELETE sessions, GET messages, usage, slash-items
38
- │ │ ├── git.ts # GET status, diff, log, graph; POST commit, stage, discard
39
- │ │ ├── files.ts # GET tree, read, diff; PUT write; POST mkdir, delete
40
- │ │ │ ├── database.ts # GET/POST/PUT/DELETE /api/db/connections (CRUD), query execution
41
- │ │ └── static.ts # Serve dist/web/index.html (frontend)
42
- ├── helpers/
43
- │ │ └── resolve-project.ts # Helper to resolve project from request params
44
- │ └── ws/
45
- ├── chat.ts # WebSocket chat streaming (220 LOC)
46
- │ └── terminal.ts # WebSocket terminal I/O (terminal.service.ts integration)
47
- │ ├── providers/ # AI Provider adapters (4 files, 1190 LOC)
48
- ├── provider.interface.ts # AIProvider interface (createSession, sendMessage, onToolApproval)
49
- ├── claude-agent-sdk.ts # Primary: SDK integration, tool approval, Windows CLI fallback, .env poisoning mitigation
50
- │ │ ├── mock-provider.ts # Test provider (ignores config)
51
- │ │ └── registry.ts # ProviderRegistry (singleton, router to active provider)
52
- │ ├── services/ # Business logic (20 files, 3300+ LOC)
53
- │ │ ├── chat.service.ts # Session lifecycle, message streaming
54
- │ ├── config.service.ts # Config loading (YAML→SQLite migration)
55
- │ │ ├── db.service.ts # SQLite persistence (schema v5, WAL mode, 9 tables, connection/account CRUD)
56
- ├── account.service.ts # Account CRUD, token encryption/decryption, active selection
57
- │ ├── account-selector.service.ts # Select active account based on config
58
- │ │ ├── project.service.ts # Project CRUD, scanning, resolution
59
- ├── file.service.ts # File ops with path validation
60
- ├── git.service.ts # Git operations (status, diff, log, graph)
61
- ├── terminal.service.ts # PTY management, Bun.spawn native shell
62
- ├── claude-usage.service.ts # Token tracking, cost calculation
63
- ├── push-notification.service.ts # Web push subscriptions
64
- ├── session-log.service.ts # Session audit logs with redaction
65
- │ ├── slash-items.service.ts # /slash command detection & completion
66
- │ │ ├── git-dirs.service.ts # Cached git directory discovery
67
- │ │ ├── cloudflared.service.ts # Download cloudflared binary (platform-specific)
68
- │ │ ├── tunnel.service.ts # Cloudflare Quick Tunnel lifecycle
69
- │ │ ├── table-cache.service.ts # Table metadata cache & search for DB connections
70
- │ │ └── database/ # Database adapters & registry
71
- ├── adapter-registry.ts # DatabaseAdapter registry (extensible)
72
- │ │ ├── sqlite-adapter.ts # SQLite connection, query execution
73
- │ │ ├── postgres-adapter.ts # PostgreSQL connection, query execution
74
- │ │ ├── init-adapters.ts # Initialize adapters at server start
75
- │ │ └── readonly-check.ts # isReadOnlyQuery() safety regex (CTE-safe)
76
- │ ├── lib/ # Shared utilities (2 files)
77
- │ │ ├── account-crypto.ts # AES-256 encryption/decryption for API keys
78
- │ └── network-utils.ts # Network utility helpers
79
- ├── types/ # TypeScript interfaces (7 files, 450 LOC)
80
- ├── api.ts # ApiResponse envelope, WebSocket message types
81
- ├── chat.ts # Session, Message, ChatEvent types
82
- ├── config.ts # Config schema
83
- ├── database.ts # DatabaseAdapter, DbConnectionConfig, DbTableInfo, etc.
84
- ├── git.ts # GitStatus, GitDiff, GitCommit types
85
- ├── project.ts # Project interface
86
- └── terminal.ts # Terminal types
87
- └── web/ # React frontend (Vite)
88
- │ ├── main.tsx # React mount (<App> into #root)
89
- │ ├── app.tsx # Root component (auth check, project load, theme)
90
- │ ├── stores/ # Zustand state stores (6 files)
91
- │ │ ├── project-store.ts # Active project, projects list, localStorage persistence
92
- │ │ ├── tab-store.ts # Tab facade, delegates to panel-store
93
- │ │ ├── panel-store.ts # Grid layout, panel creation/movement, keep-alive snapshots
94
- │ │ ├── panel-utils.ts # Layout algorithm helpers, grid manipulation
95
- │ │ ├── file-store.ts # File cache
96
- │ │ └── settings-store.ts # Theme, sidebar state, git view mode, device name
97
- │ ├── hooks/ # Custom React hooks (9 files)
98
- │ │ ├── use-chat.ts # Chat streaming, messages, approvals, context window tracking
99
- │ │ ├── use-websocket.ts # WebSocket connection with auto-reconnect
100
- │ │ ├── use-terminal.ts # Terminal connection and streaming
18
+ src/
19
+ ├── cli/
20
+ │ ├── commands/ # 13 CLI commands (start, stop, init, config, chat, db, git, etc.)
21
+ └── utils/
22
+ └── project-resolver.ts # Resolve project name -> path
23
+ ├── server/
24
+ │ ├── index.ts # Hono server setup, Bun.serve, WebSocket upgrade
25
+ │ ├── middleware/
26
+ │ │ └── auth.ts # Token validation middleware
27
+ │ ├── routes/
28
+ │ │ ├── settings.ts # GET/PUT /api/settings/ai, GET /api/settings/ai/providers/:id/models
29
+ │ │ ├── chat.ts # Sessions, messages, GET /chat/providers/:providerId/models
30
+ │ │ ├── projects.ts # Project CRUD, reorder, color
31
+ │ │ ├── accounts.ts # Account management (multi-account support)
32
+ │ │ ├── database.ts # DB connection CRUD, schema management
33
+ │ │ ├── git.ts # Git operations (status, commit, log, graph)
34
+ │ │ ├── files.ts # File operations (read, write, tree)
35
+ │ │ ├── upgrade.ts # Version checking, upgrade
36
+ │ │ └── static.ts # Serve frontend (dist/web)
37
+ ├── helpers/
38
+ │ └── resolve-project.ts # Resolve project from request params
39
+ └── ws/
40
+ ├── chat.ts # WebSocket chat streaming
41
+ └── terminal.ts # WebSocket terminal I/O
42
+ ├── providers/ # AI Provider adapters
43
+ │ ├── provider.interface.ts # AIProvider interface (ADDED: listModels?())
44
+ │ ├── claude-agent-sdk.ts # Primary provider (listModels: hardcoded 2 models)
45
+ │ ├── cursor-cli/
46
+ │ │ └── cursor-provider.ts # CLI-based provider (listModels: subprocess with TTL cache)
47
+ │ ├── cli-provider-base.ts # Abstract base for CLI providers
48
+ │ ├── mock-provider.ts # Test provider
49
+ └── registry.ts # Provider routing (list() vs listAll())
50
+ ├── services/ # Business logic (25+ files)
51
+ ├── chat.service.ts # Session/message streaming
52
+ │ ├── config.service.ts # Config loading/persistence
53
+ ├── db.service.ts # SQLite CRUD
54
+ ├── file.service.ts # File operations
55
+ │ ├── git.service.ts # Git commands
56
+ ├── terminal.service.ts # PTY management
57
+ │ ├── account.service.ts # Account CRUD & encryption
58
+ │ ├── upgrade.service.ts # Version checking, installation
59
+ │ ├── database/
60
+ │ │ ├── adapter-registry.ts # SQLite/Postgres adapter registry
61
+ │ │ ├── sqlite-adapter.ts
62
+ ├── postgres-adapter.ts
63
+ │ │ └── readonly-check.ts # CTE-safe readonly validation
64
+ └── ... (20+ other services)
65
+ ├── lib/
66
+ │ ├── account-crypto.ts # AES-256 encryption
67
+ └── network-utils.ts
68
+ ├── types/
69
+ │ ├── chat.ts # Session, Message, ChatEvent, ModelOption, AIProvider
70
+ │ ├── api.ts # ApiResponse envelope
71
+ │ ├── config.ts
72
+ │ ├── database.ts
73
+ │ ├── git.ts
74
+ │ ├── project.ts
75
+ └── terminal.ts
76
+ └── web/ # React frontend (Vite + React 18)
77
+ ├── app.tsx # Root component
78
+ ├── stores/ # Zustand state (6 stores)
79
+ ├── hooks/ # Custom hooks (9 hooks)
80
+ ├── components/
81
+ │ ├── chat/
82
+ │ │ ├── chat-tab.tsx
83
+ │ │ ├── message-list.tsx
84
+ │ │ ├── message-input.tsx
85
+ │ │ ├── provider-selector.tsx
86
+ ├── chat-history-bar.tsx # ADDED: Provider badges, provider-aware usage
87
+ │ │ └── ... (6 other chat components)
88
+ ├── settings/
89
+ │ └── ai-settings-section.tsx # UPDATED: Per-provider tabs, dynamic model dropdowns
90
+ │ ├── database/
91
+ │ ├── editor/
92
+ │ ├── explorer/
93
+ │ ├── git/
94
+ │ ├── layout/
95
+ │ ├── terminal/
96
+ │ └── ui/
97
+ └── lib/
101
98
  │ │ ├── use-url-sync.ts # Sync browser URL with active project/tab state
102
99
  │ │ ├── use-tab-drag.ts # Tab drag-and-drop logic
103
100
  │ │ ├── use-global-keybindings.ts # Global shortcuts (Shift+Shift palette, Alt+[/] tab cycling)
@@ -364,11 +361,174 @@ UI updates staged/unstaged lists
364
361
  - PWA manifest, service worker
365
362
  - Assets (~500KB gzipped)
366
363
 
364
+ ## Multi-Provider Architecture (v0.8.60)
365
+
366
+ ### Dynamic Model Listing Feature
367
+
368
+ **Problem:** Different AI providers expose different models. Claude has hardcoded models, but CLI-based providers (e.g., Cursor) discover models at runtime.
369
+
370
+ **Solution:** Optional `listModels()` method on `AIProvider` interface
371
+
372
+ ### Provider Interface
373
+
374
+ ```typescript
375
+ // src/types/chat.ts
376
+ export interface ModelOption {
377
+ value: string; // Model ID (e.g., "claude-sonnet-4-6")
378
+ label: string; // Display name (e.g., "Claude Sonnet 4.6")
379
+ }
380
+
381
+ interface AIProvider {
382
+ // Required methods
383
+ createSession(): Promise<Session>;
384
+ sendMessage(sessionId, message, context?): AsyncIterable<ChatEvent>;
385
+
386
+ // Optional methods
387
+ listModels?(): Promise<ModelOption[]>;
388
+ isAvailable?(): Promise<boolean>;
389
+ // ... (5 other optional methods)
390
+ }
391
+ ```
392
+
393
+ ### Provider Implementations
394
+
395
+ #### Claude (agent-sdk.ts)
396
+ - `listModels()` returns hardcoded 2 models: Sonnet 4.6, Opus 4.6
397
+ - Direct implementation (no subprocess)
398
+
399
+ #### Cursor (cursor-provider.ts)
400
+ - `listModels()` runs `cursor-agent --list-models` subprocess
401
+ - 5-minute TTL cache (prevents repeated subprocess calls)
402
+ - 10-second timeout (graceful fallback to empty list)
403
+ - Extends `CliProvider` abstract base
404
+
405
+ #### Mock (mock-provider.ts)
406
+ - For testing; returns canned models
407
+
408
+ ### API Endpoints
409
+
410
+ **Global Models Endpoint** (`GET /api/settings/ai/providers/:id/models`)
411
+ ```typescript
412
+ // Used in Settings UI (no project context needed)
413
+ settingsRoutes.get("/ai/providers/:id/models", async (c) => {
414
+ const provider = providerRegistry.get(c.req.param("id"));
415
+ const models = await provider.listModels?.() ?? [];
416
+ return c.json(ok(models));
417
+ });
418
+ ```
419
+
420
+ **Project-Scoped Models Endpoint** (`GET /api/project/:name/chat/providers/:providerId/models`)
421
+ ```typescript
422
+ // Used in Chat tab (scoped to project for consistency)
423
+ chatRoutes.get("/providers/:providerId/models", async (c) => {
424
+ const provider = providerRegistry.get(c.req.param("providerId"));
425
+ const models = await provider.listModels?.() ?? [];
426
+ return c.json(ok(models));
427
+ });
428
+ ```
429
+
430
+ ### Provider Registry Pattern
431
+
432
+ **list() — User-facing providers:**
433
+ ```typescript
434
+ list(): ProviderInfo[] {
435
+ return [
436
+ { id: "claude", name: "Claude" },
437
+ { id: "cursor", name: "Cursor" }
438
+ // mock excluded
439
+ ];
440
+ }
441
+ ```
442
+
443
+ **listAll() — All providers (internal):**
444
+ ```typescript
445
+ listAll(): ProviderInfo[] {
446
+ return [..., { id: "mock", name: "Mock" }];
447
+ }
448
+ ```
449
+
450
+ **Auto-Bootstrap:**
451
+ ```typescript
452
+ // On startup, detect CLI providers
453
+ async bootstrapProviders() {
454
+ const cursor = this.providers.get("cursor");
455
+ if (cursor && await cursor.isAvailable?.()) {
456
+ // Auto-create config entry if detected
457
+ // Save config (only if new)
458
+ }
459
+ }
460
+ ```
461
+
462
+ ### UI Components
463
+
464
+ #### AI Settings Section (ai-settings-section.tsx) — UPDATED
465
+ - Per-provider tabs (Claude, Cursor, etc.)
466
+ - Dynamic model dropdowns fetched from `/api/settings/ai/providers/:id/models`
467
+ - Fallback to hardcoded models if API call fails
468
+ - Provider-aware settings (SDK vs CLI options)
469
+
470
+ #### Chat History Bar (chat-history-bar.tsx) — ADDED
471
+ - Provider badges showing active provider for each session
472
+ - Provider-aware usage display:
473
+ - **Claude:** Full stats `(tokens_in:X, tokens_out:Y, cost: $Z)`
474
+ - **Other:** Context-only `(tokens: X)`
475
+
476
+ ### Configuration
477
+
478
+ ```yaml
479
+ ai:
480
+ default_provider: claude
481
+ providers:
482
+ claude:
483
+ type: agent-sdk
484
+ model: claude-sonnet-4-6 # from listModels()
485
+ effort: high
486
+ max_turns: 100
487
+ cursor:
488
+ type: cli
489
+ model: cursor-fast # from listModels()
490
+ ```
491
+
492
+ ### Testing
493
+
494
+ **New Integration Tests (13 tests):**
495
+ - `provider-models-api.test.ts` — Model API endpoints
496
+ - `chat-service-multi-provider.test.ts` — Multi-provider flows
497
+ - `cursor-provider.test.ts` — Subprocess TTL cache, timeout handling
498
+
499
+ ---
500
+
367
501
  ## Testing Strategy
368
502
 
369
503
  | Test Type | Location | Coverage |
370
504
  |-----------|----------|----------|
371
505
  | Unit | tests/unit/ | Services, utilities |
372
- | Integration | tests/integration/ | API routes, WebSocket |
506
+ | Integration | tests/integration/ | API routes, WebSocket, provider models |
373
507
  | E2E | None yet | Planned for v3 |
374
508
 
509
+ **Key Gotchas:**
510
+ - Test DB isolated per test (never writes to ~/.ppm/ppm.db)
511
+ - Auth disabled in test mode (test-setup.ts)
512
+ - Mock provider used for deterministic responses
513
+ - 492 passing tests (0 failures, v0.8.60)
514
+
515
+ ---
516
+
517
+ ## Recent Changes (v0.8.60)
518
+
519
+ ### Added
520
+ - **Dynamic Model Listing** — `listModels?()` on AIProvider interface
521
+ - **Provider Models APIs** — Global and project-scoped endpoints
522
+ - **AI Settings UI** — Per-provider tabs with dynamic model dropdowns
523
+ - **Chat History Badges** — Provider-aware usage display
524
+ - **13 new integration tests** for provider models API
525
+
526
+ ### Technical Details
527
+ - `ModelOption` type: `{ value: string; label: string }`
528
+ - Claude: Hardcoded 2 models
529
+ - Cursor: Subprocess with 5-min TTL cache, 10s timeout
530
+ - Registry: `list()` vs `listAll()` distinction
531
+ - Bootstrap: Auto-detect CLI providers on startup
532
+
533
+ ---
534
+
@@ -2,7 +2,94 @@
2
2
 
3
3
  All notable changes to PPM are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/).
4
4
 
5
- **Current Version:** v0.8.53
5
+ **Current Version:** v0.8.62
6
+
7
+ ---
8
+
9
+ ## [0.8.62] — 2026-03-26
10
+
11
+ ### Added
12
+ - **Cmd+Shift+V shortcut** — Command palette entry for voice input
13
+ - **Voice input** — Web Speech API integration for chat
14
+
15
+ ---
16
+
17
+ ## [0.8.61] — 2026-03-26 (Beta)
18
+
19
+ ### Added
20
+ - **Multi-Provider Architecture** — Generic AI provider system supporting Claude (SDK-based) and CLI-spawning providers
21
+ - `AIProvider` interface with optional capability methods (`abortQuery?`, `getMessages?`, `listSessionsByDir?`)
22
+ - `CliProvider` abstract base class for CLI-spawning providers (Cursor, Codex, Gemini)
23
+ - `CursorCliProvider` implementation — spawns `cursor-agent` with NDJSON streaming
24
+ - NDJSON line parser utility for TCP packet boundary handling
25
+ - Cursor event mapper — normalizes Cursor NDJSON → standard ChatEvent union
26
+ - Cursor history reader — loads sessions from `~/.cursor/chats/` SQLite DAG
27
+ - Provider selector UI component — users can choose provider when creating chat
28
+ - Async provider bootstrap — checks binary availability, registers only if available
29
+ - Workspace trust auto-retry — detects trust prompts, retries with `--trust` flag
30
+ - Process lifecycle management — SIGTERM → SIGKILL escalation, orphan cleanup
31
+
32
+ ### Technical Details
33
+ - **Files Created:**
34
+ - `src/utils/ndjson-line-parser.ts` — NDJSON streaming parser
35
+ - `src/providers/cli-provider-base.ts` — Abstract CliProvider base class
36
+ - `src/providers/cursor-cli/cursor-provider.ts` — CursorCliProvider
37
+ - `src/providers/cursor-cli/cursor-event-mapper.ts` — Event mapping
38
+ - `src/providers/cursor-cli/cursor-history.ts` — SQLite history reader
39
+ - `src/web/components/chat/provider-selector.tsx` — Provider selection UI
40
+ - `tests/unit/ndjson-line-parser.test.ts` — Parser tests
41
+ - `tests/unit/cursor-event-mapper.test.ts` — Mapper tests
42
+ - `tests/integration/cursor-provider.test.ts` — Integration tests
43
+ - `tests/integration/chat-service-multi-provider.test.ts` — Service tests
44
+ - **Files Modified:**
45
+ - `src/types/chat.ts` — Added optional capability methods to AIProvider, added `system` event type
46
+ - `src/types/config.ts` — Added `"cli"` type, `cli_command` field to AIProviderConfig
47
+ - `src/providers/registry.ts` — Added async `bootstrapProviders()` for conditional registration
48
+ - `src/server/ws/chat.ts` — Removed `as any` casts, use optional chaining for capabilities
49
+ - `src/services/chat.service.ts` — Use optional methods instead of duck-typing
50
+ - `src/web/components/chat/session-picker.tsx` — Integrated provider selector
51
+ - **Breaking Changes:** None (backward compatible, all tests passing)
52
+ - **Architecture:** All phases complete (6/6), 555 tests passing
53
+
54
+ ### Benefits
55
+ - Extensible foundation for Codex, Gemini, and future providers (~100-150 lines each)
56
+ - No more `as any` casts for provider methods — type-safe optional capability pattern
57
+ - CLI providers can override session history reading (e.g., Cursor SQLite DAG)
58
+ - Graceful degradation — missing CLI binary doesn't crash, logs info, skips provider
59
+
60
+ ---
61
+
62
+ ## [0.8.55] — 2026-03-26
63
+
64
+ ### Added
65
+ - **Streaming Input Migration** — Persistent AsyncGenerator session model for chat
66
+ - Provider maintains long-lived streaming input per session (not per message)
67
+ - Follow-up messages push into existing generator instead of abort-and-replace
68
+ - Single streaming loop decoupled from WebSocket message handler
69
+ - Message priority support (`now`/`next`/`later`) for intelligent message ordering
70
+ - Image attachment support in message sending
71
+ - Session state persistence across FE disconnections (5-minute cleanup timeout)
72
+ - Event buffering on reconnect: clients receive buffered turn events after reconnection
73
+ - Phase transitions: `idle` → `initializing` → `connecting` → `thinking`/`streaming` → `idle`
74
+
75
+ ### Technical Details
76
+ - **Provider Layer** (`src/providers/claude-agent-sdk.ts`): Maintains streaming session per sessionId
77
+ - **WebSocket Handler** (`src/server/ws/chat.ts`):
78
+ - `runStreamLoop()` executes independently (detached from WS scope)
79
+ - `activeSessions` map persists session state across FE disconnections
80
+ - `startSessionConsumer()` pattern replaces per-message `runStreamLoop()` calls
81
+ - Event buffering (turnEvents array, max 10k events) for reconnect sync
82
+ - Per-client ping intervals (15s keepalive)
83
+ - **Types** (`src/types/api.ts`, `src/types/chat.ts`):
84
+ - `ChatWsClientMessage` extended with `priority?: string` and optional `images`
85
+ - `SessionPhase` = "initializing" | "connecting" | "thinking" | "streaming" | "idle"
86
+ - `SessionEntry` tracks clients, abort handle, phase, pending approvals, buffered events
87
+ - **Frontend** (`src/web/components/chat/message-input.tsx`): PriorityToggle component (visible during streaming)
88
+ - **Benefits**:
89
+ - No SDK subprocess restarts between messages (faster context preservation)
90
+ - Tool approvals integrated into streaming (no query restart)
91
+ - Message buffering prevents loss on FE reconnection
92
+ - Cleaner architecture: BE owns Claude connection, FE disconnect ≠ abort
6
93
 
7
94
  ---
8
95