@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.
- package/CHANGELOG.md +10 -26
- package/dist/web/assets/{_basePickBy-CZovQgWd.js → _basePickBy-COwDPZl_.js} +1 -1
- package/dist/web/assets/{_baseUniq-ClnvscgW.js → _baseUniq-DCb0mkTp.js} +1 -1
- package/dist/web/assets/{api-settings--eVrUeZM.js → api-settings-CuUkz5gb.js} +1 -1
- package/dist/web/assets/{arc-C2Qaz-ch.js → arc-D0bJaFyD.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-281eTKQ3.js +1 -0
- package/dist/web/assets/{architectureDiagram-2XIMDMQ5-Jq91S_rs.js → architectureDiagram-2XIMDMQ5-BVEUkQYB.js} +1 -1
- package/dist/web/assets/arrow-left-C_j9Ki73.js +1 -0
- package/dist/web/assets/{blockDiagram-WCTKOSBZ-CKGufRTy.js → blockDiagram-WCTKOSBZ-CU2t4NHJ.js} +1 -1
- package/dist/web/assets/browser-tab-BhTdeeZd.js +1 -0
- package/dist/web/assets/{c4Diagram-IC4MRINW-BNP2L9r_.js → c4Diagram-IC4MRINW-DzjR91sM.js} +1 -1
- package/dist/web/assets/channel-CKNZAqoN.js +1 -0
- package/dist/web/assets/chat-tab-ZiiUVOxM.js +7 -0
- package/dist/web/assets/{chunk-4BX2VUAB-BptTlTyl.js → chunk-4BX2VUAB-0YMkpW2S.js} +1 -1
- package/dist/web/assets/{chunk-55IACEB6-C4mUdyio.js → chunk-55IACEB6-Dp0pTM5r.js} +1 -1
- package/dist/web/assets/{chunk-7E7YKBS2-6xAQfBwa.js → chunk-7E7YKBS2-CuYKSUgJ.js} +1 -1
- package/dist/web/assets/{chunk-7R4GIKGN-DXaGAn_K.js → chunk-7R4GIKGN-DvbvLUIN.js} +2 -2
- package/dist/web/assets/{chunk-C72U2L5F-DOtEiN5f.js → chunk-C72U2L5F-CcEW1AMZ.js} +1 -1
- package/dist/web/assets/{chunk-EGIJ26TM-D0KJTa_T.js → chunk-EGIJ26TM-Cgt-qg75.js} +1 -1
- package/dist/web/assets/{chunk-FMBD7UC4-C_1aG0eb.js → chunk-FMBD7UC4-JCLgVcaC.js} +1 -1
- package/dist/web/assets/{chunk-GEFDOKGD-DwVPiYfW.js → chunk-GEFDOKGD-B82RP9ow.js} +1 -1
- package/dist/web/assets/chunk-GLR3WWYH-Bx2UL5jF.js +2 -0
- package/dist/web/assets/chunk-HHEYEP7N-BnRVfNc5.js +1 -0
- package/dist/web/assets/{chunk-JSJVCQXG-BSrqCL_3.js → chunk-JSJVCQXG-Pb-JMOgO.js} +1 -1
- package/dist/web/assets/{chunk-KX2RTZJC-BCxGmbzy.js → chunk-KX2RTZJC-BRj-ZEvL.js} +1 -1
- package/dist/web/assets/{chunk-KYZI473N-BKO5gMeU.js → chunk-KYZI473N-CBRPKraG.js} +1 -1
- package/dist/web/assets/{chunk-L3YUKLVL-3wBgkSvL.js → chunk-L3YUKLVL-DNFj84V6.js} +1 -1
- package/dist/web/assets/{chunk-MX3YWQON-BgjSEzus.js → chunk-MX3YWQON-BnPzQK-O.js} +1 -1
- package/dist/web/assets/{chunk-NQ4KR5QH-DLrZwBEm.js → chunk-NQ4KR5QH-BRj25yO7.js} +1 -1
- package/dist/web/assets/{chunk-O4XLMI2P-BurQy8tt.js → chunk-O4XLMI2P-BdXwVXjJ.js} +1 -1
- package/dist/web/assets/{chunk-OZEHJAEY-YTn24bGg.js → chunk-OZEHJAEY-LfXT4p8B.js} +1 -1
- package/dist/web/assets/{chunk-PQ6SQG4A-BxtUGYhW.js → chunk-PQ6SQG4A-EdgQyTqa.js} +1 -1
- package/dist/web/assets/{chunk-PU5JKC2W-B66ELkQm.js → chunk-PU5JKC2W-D3thuSok.js} +1 -1
- package/dist/web/assets/chunk-QZHKN3VN-gaBt0Rbd.js +1 -0
- package/dist/web/assets/{chunk-R5LLSJPH-euR2RxLN.js → chunk-R5LLSJPH-LdG7RqsM.js} +1 -1
- package/dist/web/assets/{chunk-WL4C6EOR-_2CBOJdI.js → chunk-WL4C6EOR-BHFnnXOt.js} +1 -1
- package/dist/web/assets/{chunk-XIRO2GV7-kqQ0g6wW.js → chunk-XIRO2GV7-DUmQrLsF.js} +1 -1
- package/dist/web/assets/{chunk-XPW4576I-CtcaMb09.js → chunk-XPW4576I-CsGTseUr.js} +1 -1
- package/dist/web/assets/{chunk-XZSTWKYB-BYxFzZwS.js → chunk-XZSTWKYB-5W2emiq4.js} +1 -1
- package/dist/web/assets/{chunk-YBOYWFTD-Dx_fX35n.js → chunk-YBOYWFTD-COdZIaX4.js} +1 -1
- package/dist/web/assets/classDiagram-VBA2DB6C-CqaIqYPn.js +1 -0
- package/dist/web/assets/classDiagram-v2-RAHNMMFH-Bo5WN2ok.js +1 -0
- package/dist/web/assets/clone-DNDy9Sms.js +1 -0
- package/dist/web/assets/{code-editor-CQ7gq0Vj.js → code-editor-BRMOypkX.js} +1 -1
- package/dist/web/assets/{cose-bilkent-S5V4N54A-CHHjH2dV.js → cose-bilkent-S5V4N54A-C1QJ6GPW.js} +1 -1
- package/dist/web/assets/{dagre-CNtSxiE_.js → dagre-CWo8w9wK.js} +1 -1
- package/dist/web/assets/{dagre-KLK3FWXG-ChenfPp1.js → dagre-KLK3FWXG-Br4t5TRV.js} +1 -1
- package/dist/web/assets/database-viewer-CEoDpzPz.js +1 -0
- package/dist/web/assets/{diagram-E7M64L7V-CzKYZM0Y.js → diagram-E7M64L7V-CkDC2uAj.js} +1 -1
- package/dist/web/assets/{diagram-IFDJBPK2-ChB_paPo.js → diagram-IFDJBPK2-NvhckwcA.js} +1 -1
- package/dist/web/assets/{diagram-P4PSJMXO-D1eW1dkL.js → diagram-P4PSJMXO--nUaNiyB.js} +1 -1
- package/dist/web/assets/{diff-viewer-BjtTemkK.js → diff-viewer-jDU2bcGj.js} +1 -1
- package/dist/web/assets/{erDiagram-INFDFZHY-mCvUFSn6.js → erDiagram-INFDFZHY-DK4QEZYh.js} +1 -1
- package/dist/web/assets/{flowDiagram-PKNHOUZH-14ohZ1M1.js → flowDiagram-PKNHOUZH-B9h_Ba-v.js} +1 -1
- package/dist/web/assets/{ganttDiagram-A5KZAMGK-DIX0pLbk.js → ganttDiagram-A5KZAMGK-BVlftqyZ.js} +1 -1
- package/dist/web/assets/git-graph-DMQzw4Sp.js +1 -0
- package/dist/web/assets/gitGraph-HDMCJU4V-D5qEPjgs.js +1 -0
- package/dist/web/assets/{gitGraphDiagram-K3NZZRJ6-yEWZbdf_.js → gitGraphDiagram-K3NZZRJ6-L7sj3Bs-.js} +1 -1
- package/dist/web/assets/{graphlib-DhOZxqsh.js → graphlib-BbbiUImY.js} +1 -1
- package/dist/web/assets/index-B4Iz1Wbi.css +2 -0
- package/dist/web/assets/index-QiSWS6f-.js +37 -0
- package/dist/web/assets/info-3K5VOQVL-CbpovIYU.js +1 -0
- package/dist/web/assets/infoDiagram-LFFYTUFH-DFh9c-S2.js +2 -0
- package/dist/web/assets/input-DGlv6gt_.js +41 -0
- package/dist/web/assets/{isEmpty-C0YYdhYj.js → isEmpty-DXomfd7J.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-PHBUUO56-olazD6dZ.js → ishikawaDiagram-PHBUUO56-cW7SMLa_.js} +1 -1
- package/dist/web/assets/{journeyDiagram-4ABVD52K-CttDH9bb.js → journeyDiagram-4ABVD52K-DFQXUZsc.js} +1 -1
- package/dist/web/assets/{kanban-definition-K7BYSVSG-BBXbI37U.js → kanban-definition-K7BYSVSG-BMUhjxqj.js} +1 -1
- package/dist/web/assets/keybindings-store-BplH-yiN.js +1 -0
- package/dist/web/assets/{line-DBLLF7lH.js → line--xyfYP3x.js} +1 -1
- package/dist/web/assets/{linear-BLFWatDe.js → linear-BdqW7iQu.js} +1 -1
- package/dist/web/assets/{markdown-renderer-BtPXdzTv.js → markdown-renderer-BCjJbGP8.js} +5 -5
- package/dist/web/assets/{mermaid-parser.core-BKiGOTjR.js → mermaid-parser.core-BY8JfkE_.js} +2 -2
- package/dist/web/assets/{mindmap-definition-YRQLILUH-DoT7m4Sz.js → mindmap-definition-YRQLILUH-DIv-LMXG.js} +1 -1
- package/dist/web/assets/{ordinal-CCj7PWgZ.js → ordinal-CIoJK3nc.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-BbzPU9BK.js +1 -0
- package/dist/web/assets/pie-UPGHQEXC-B0h6hM1j.js +1 -0
- package/dist/web/assets/{pieDiagram-SKSYHLDU-Bkh2E4zE.js → pieDiagram-SKSYHLDU-seSK40d1.js} +1 -1
- package/dist/web/assets/postgres-viewer-s0snZ9CL.js +1 -0
- package/dist/web/assets/{quadrantDiagram-337W2JSQ-B7zgALOL.js → quadrantDiagram-337W2JSQ-BaRFqlsA.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-CHptMqVT.js +1 -0
- package/dist/web/assets/{requirementDiagram-Z7DCOOCP-D_5GXNRo.js → requirementDiagram-Z7DCOOCP-1WWjMQB_.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-WA2Y5GQK-BA9EFAAe.js → sankeyDiagram-WA2Y5GQK-DEGGYsk7.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-2WXFIKYE-fyWIrHiG.js → sequenceDiagram-2WXFIKYE-BtRvoUTC.js} +1 -1
- package/dist/web/assets/{settings-store-Bbhg_ptG.js → settings-store-D3dJqGhB.js} +2 -2
- package/dist/web/assets/settings-tab-2YkgmrY0.js +1 -0
- package/dist/web/assets/sqlite-viewer-B5GNwXaG.js +1 -0
- package/dist/web/assets/{stateDiagram-RAJIS63D-DfRBcaBu.js → stateDiagram-RAJIS63D-C16aO8tn.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-FVOUBMTO-D7qSAjnK.js +1 -0
- package/dist/web/assets/switch-mjGtIVDJ.js +1 -0
- package/dist/web/assets/{tab-store-dpsCvqhH.js → tab-store-DSz5PQI0.js} +1 -1
- package/dist/web/assets/{terminal-tab--Gw14HP3.js → terminal-tab-MRg8y1xF.js} +2 -2
- package/dist/web/assets/{timeline-definition-YZTLITO2-DYfwJ1jM.js → timeline-definition-YZTLITO2-DrjxCpEM.js} +1 -1
- package/dist/web/assets/treemap-KZPCXAKY-BL9OJq3X.js +1 -0
- package/dist/web/assets/{use-monaco-theme-DHbyUrzJ.js → use-monaco-theme-BQzvItNE.js} +1 -1
- package/dist/web/assets/{vennDiagram-LZ73GAT5-DqbKNRD9.js → vennDiagram-LZ73GAT5-DfYFnniI.js} +1 -1
- package/dist/web/assets/{xychartDiagram-JWTSCODW-DhUL86qT.js → xychartDiagram-JWTSCODW-BRvXOVlG.js} +1 -1
- package/dist/web/index.html +12 -10
- package/dist/web/sw.js +1 -1
- package/docs/code-standards.md +260 -7
- package/docs/codebase-summary.md +255 -95
- package/docs/project-changelog.md +88 -1
- package/docs/system-architecture.md +177 -12
- package/package.json +1 -1
- package/src/providers/claude-agent-sdk.ts +9 -0
- package/src/providers/cli-provider-base.ts +238 -0
- package/src/providers/cursor-cli/cursor-event-mapper.ts +85 -0
- package/src/providers/cursor-cli/cursor-history.ts +207 -0
- package/src/providers/cursor-cli/cursor-provider.ts +146 -0
- package/src/providers/mock-provider.ts +1 -1
- package/src/providers/provider.interface.ts +1 -0
- package/src/providers/registry.ts +43 -4
- package/src/server/index.ts +8 -0
- package/src/server/routes/browser-preview.ts +89 -0
- package/src/server/routes/chat.ts +14 -3
- package/src/server/routes/settings.ts +14 -0
- package/src/server/ws/chat.ts +24 -8
- package/src/services/chat.service.ts +10 -15
- package/src/types/chat.ts +21 -2
- package/src/types/config.ts +33 -11
- package/src/utils/ndjson-line-parser.ts +36 -0
- package/src/web/components/browser/browser-tab.tsx +269 -0
- package/src/web/components/chat/chat-history-bar.tsx +49 -29
- package/src/web/components/chat/chat-tab.tsx +14 -2
- package/src/web/components/chat/message-input.tsx +91 -3
- package/src/web/components/chat/provider-selector.tsx +150 -0
- package/src/web/components/chat/session-picker.tsx +3 -1
- package/src/web/components/layout/command-palette.tsx +4 -0
- package/src/web/components/layout/editor-panel.tsx +1 -0
- package/src/web/components/layout/mobile-nav.tsx +2 -2
- package/src/web/components/layout/panel-layout.tsx +17 -1
- package/src/web/components/layout/tab-bar.tsx +2 -0
- package/src/web/components/layout/tab-content.tsx +5 -0
- package/src/web/components/settings/ai-settings-section.tsx +196 -137
- package/src/web/hooks/use-chat.ts +11 -0
- package/src/web/hooks/use-global-keybindings.ts +7 -0
- package/src/web/hooks/use-voice-input.ts +111 -0
- package/src/web/stores/keybindings-store.ts +1 -0
- package/src/web/stores/panel-store.ts +10 -10
- package/src/web/stores/tab-store.ts +2 -1
- package/dist/web/assets/architecture-PBZL5I3N-ChOahOB7.js +0 -1
- package/dist/web/assets/channel-w7yboq56.js +0 -1
- package/dist/web/assets/chat-tab-DmF14O6G.js +0 -7
- package/dist/web/assets/chunk-GLR3WWYH-D9pZakqr.js +0 -2
- package/dist/web/assets/chunk-HHEYEP7N-Dld5BpGB.js +0 -1
- package/dist/web/assets/chunk-QZHKN3VN-DwSXwtjH.js +0 -1
- package/dist/web/assets/classDiagram-VBA2DB6C-BpJ6Oog2.js +0 -1
- package/dist/web/assets/classDiagram-v2-RAHNMMFH-Bj8gIhkP.js +0 -1
- package/dist/web/assets/clone-BSi6cgDh.js +0 -1
- package/dist/web/assets/database-viewer-B27aRtdQ.js +0 -1
- package/dist/web/assets/git-graph-BGXo0o-J.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-CEee2FCA.js +0 -1
- package/dist/web/assets/index-BAioKo_2.css +0 -2
- package/dist/web/assets/index-CfClIVo2.js +0 -37
- package/dist/web/assets/info-3K5VOQVL-ce_pi3En.js +0 -1
- package/dist/web/assets/infoDiagram-LFFYTUFH-BzqyoqXw.js +0 -2
- package/dist/web/assets/input-Brjz2Vv-.js +0 -41
- package/dist/web/assets/keybindings-store-nDbczFnq.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-CdYSLjRL.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-Bm5LiD-6.js +0 -1
- package/dist/web/assets/postgres-viewer-BMg-qFcO.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-C4PnyG7_.js +0 -1
- package/dist/web/assets/settings-tab-NPuwQHzs.js +0 -1
- package/dist/web/assets/sqlite-viewer-CAsUczio.js +0 -1
- package/dist/web/assets/stateDiagram-v2-FVOUBMTO-CMN4M2Em.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-2_y-mhkz.js +0 -1
- package/snapshot-state.md +0 -1526
- package/test-tokens.mjs +0 -212
- /package/dist/web/assets/{api-client-DpGMOZNf.js → api-client-icCZ-07C.js} +0 -0
- /package/dist/web/assets/{array-BGFCBI0e.js → array-CLwNaqU1.js} +0 -0
- /package/dist/web/assets/{columns-2-ChOTgl3e.js → columns-2-Bcg3QJBg.js} +0 -0
- /package/dist/web/assets/{cytoscape.esm-Ccan6xou.js → cytoscape.esm-B-QQuWwK.js} +0 -0
- /package/dist/web/assets/{defaultLocale-CRZydyG6.js → defaultLocale-D_VMtRaY.js} +0 -0
- /package/dist/web/assets/{dist-T0Vhi0Mh.js → dist-CMmNEgEP.js} +0 -0
- /package/dist/web/assets/{dist-Cce3efmT.js → dist-Ckxnw5rl.js} +0 -0
- /package/dist/web/assets/{init-B8gtcn7T.js → init-vVpfz1D6.js} +0 -0
- /package/dist/web/assets/{isArrayLikeObject-B4pdpV8V.js → isArrayLikeObject-DvHDmeBe.js} +0 -0
- /package/dist/web/assets/{katex-Bbu770d9.js → katex-C3cZrCvP.js} +0 -0
- /package/dist/web/assets/{math-DwgHI-Cu.js → math-a44lmFDa.js} +0 -0
- /package/dist/web/assets/{path-DZF-JdEe.js → path-CuyvWNAH.js} +0 -0
- /package/dist/web/assets/{preload-helper-qlgyTAkD.js → preload-helper-CsoeaaUJ.js} +0 -0
- /package/dist/web/assets/{react-BGf7KNLk.js → react-BPIfZRKM.js} +0 -0
- /package/dist/web/assets/{rough.esm-VLpapkIG.js → rough.esm-c4PR5shF.js} +0 -0
- /package/dist/web/assets/{src-BoSBNdA_.js → src-CLWraeNW.js} +0 -0
- /package/dist/web/assets/{table-Yo02WRH-.js → table-C9jDaRl2.js} +0 -0
- /package/dist/web/assets/{tag-CaC1ng2E.js → tag-CENGyt_L.js} +0 -0
- /package/dist/web/assets/{utils-btZ8C8-R.js → utils-Bslrbb-G.js} +0 -0
package/docs/codebase-summary.md
CHANGED
|
@@ -1,103 +1,100 @@
|
|
|
1
1
|
# PPM Codebase Summary
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
9
|
-
├──
|
|
10
|
-
│ ├──
|
|
11
|
-
│
|
|
12
|
-
│
|
|
13
|
-
|
|
14
|
-
│
|
|
15
|
-
│
|
|
16
|
-
│ │
|
|
17
|
-
│
|
|
18
|
-
│ │
|
|
19
|
-
│ │
|
|
20
|
-
│ │
|
|
21
|
-
│ │
|
|
22
|
-
│ │
|
|
23
|
-
│ │
|
|
24
|
-
│ │
|
|
25
|
-
│ │
|
|
26
|
-
│ │ └──
|
|
27
|
-
│
|
|
28
|
-
│
|
|
29
|
-
│
|
|
30
|
-
│
|
|
31
|
-
│
|
|
32
|
-
|
|
33
|
-
│
|
|
34
|
-
│
|
|
35
|
-
│
|
|
36
|
-
│ │
|
|
37
|
-
│
|
|
38
|
-
│
|
|
39
|
-
│
|
|
40
|
-
|
|
41
|
-
│
|
|
42
|
-
│
|
|
43
|
-
│
|
|
44
|
-
│
|
|
45
|
-
│
|
|
46
|
-
│
|
|
47
|
-
│ ├──
|
|
48
|
-
│
|
|
49
|
-
│
|
|
50
|
-
│ │ ├──
|
|
51
|
-
│ │
|
|
52
|
-
│ ├──
|
|
53
|
-
│ │
|
|
54
|
-
│
|
|
55
|
-
|
|
56
|
-
│
|
|
57
|
-
│
|
|
58
|
-
|
|
59
|
-
│
|
|
60
|
-
│
|
|
61
|
-
│
|
|
62
|
-
│
|
|
63
|
-
│
|
|
64
|
-
│
|
|
65
|
-
│
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
│
|
|
72
|
-
│ │
|
|
73
|
-
│ │
|
|
74
|
-
│ │
|
|
75
|
-
│ │
|
|
76
|
-
│ ├──
|
|
77
|
-
│ │
|
|
78
|
-
│
|
|
79
|
-
│
|
|
80
|
-
│
|
|
81
|
-
│
|
|
82
|
-
│
|
|
83
|
-
│
|
|
84
|
-
│
|
|
85
|
-
│
|
|
86
|
-
│
|
|
87
|
-
|
|
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.
|
|
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
|
|