@hienlh/ppm 0.9.0-beta.9 → 0.9.2

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 (256) hide show
  1. package/.claude.bak/agent-memory/tester/MEMORY.md +3 -0
  2. package/.claude.bak/agent-memory/tester/project-ppm-test-conventions.md +32 -0
  3. package/CHANGELOG.md +240 -0
  4. package/bun.lock +17 -0
  5. package/dist/web/assets/{_basePickBy-3Xe18azI.js → _basePickBy-5PGDJbfF.js} +1 -1
  6. package/dist/web/assets/{_baseUniq-Yy35llnn.js → _baseUniq-BT4Ow4Kk.js} +1 -1
  7. package/dist/web/assets/api-settings-BUvk6Saw.js +1 -0
  8. package/dist/web/assets/{arc-B9n1Gvb5.js → arc-BAOivWpI.js} +1 -1
  9. package/dist/web/assets/architecture-PBZL5I3N-DEO2f3VD.js +1 -0
  10. package/dist/web/assets/{architectureDiagram-2XIMDMQ5-DqAZP_F6.js → architectureDiagram-2XIMDMQ5-Z-4eN4za.js} +1 -1
  11. package/dist/web/assets/arrow-up-BYhx9ckd.js +1 -0
  12. package/dist/web/assets/{blockDiagram-WCTKOSBZ-h3cDF2vI.js → blockDiagram-WCTKOSBZ-BCLqzhuZ.js} +1 -1
  13. package/dist/web/assets/browser-tab-CjUzlPYv.js +1 -0
  14. package/dist/web/assets/{c4Diagram-IC4MRINW--pF1r5lr.js → c4Diagram-IC4MRINW-0Vp0Jeas.js} +1 -1
  15. package/dist/web/assets/channel-By7bn0Yq.js +1 -0
  16. package/dist/web/assets/chat-tab-moB4W7-w.js +8 -0
  17. package/dist/web/assets/chevron-right-5HgK6l7K.js +1 -0
  18. package/dist/web/assets/{chunk-4BX2VUAB-C3aZvW7B.js → chunk-4BX2VUAB-D4tOov49.js} +1 -1
  19. package/dist/web/assets/{chunk-55IACEB6-D5cABeB9.js → chunk-55IACEB6-DJ6BynZ4.js} +1 -1
  20. package/dist/web/assets/{chunk-7E7YKBS2-CkFGv6Zs.js → chunk-7E7YKBS2-CiyUJxNI.js} +1 -1
  21. package/dist/web/assets/{chunk-7R4GIKGN-Dvbyu4Zw.js → chunk-7R4GIKGN-Dv-4cAYn.js} +2 -2
  22. package/dist/web/assets/{chunk-C72U2L5F-CtqKiH4q.js → chunk-C72U2L5F-D21mS_6G.js} +1 -1
  23. package/dist/web/assets/{chunk-EGIJ26TM-Cpr87sBR.js → chunk-EGIJ26TM-DzqmU2Z7.js} +1 -1
  24. package/dist/web/assets/{chunk-FMBD7UC4-D23YVTOU.js → chunk-FMBD7UC4-DXncblvW.js} +1 -1
  25. package/dist/web/assets/{chunk-GEFDOKGD-tDjHsAUs.js → chunk-GEFDOKGD-D-pKjlVd.js} +1 -1
  26. package/dist/web/assets/chunk-GLR3WWYH-DKikpoJM.js +2 -0
  27. package/dist/web/assets/chunk-HHEYEP7N-C7vxA5i9.js +1 -0
  28. package/dist/web/assets/{chunk-JSJVCQXG-BBmymCjA.js → chunk-JSJVCQXG-99JzIdPr.js} +1 -1
  29. package/dist/web/assets/{chunk-KX2RTZJC-DP36BDiU.js → chunk-KX2RTZJC-CRq1OBZv.js} +1 -1
  30. package/dist/web/assets/{chunk-KYZI473N-Djw13C-3.js → chunk-KYZI473N-Bb0MCaIO.js} +1 -1
  31. package/dist/web/assets/{chunk-L3YUKLVL-HG_eMj_C.js → chunk-L3YUKLVL-C7qGJrfV.js} +1 -1
  32. package/dist/web/assets/{chunk-MX3YWQON-C2UEioMs.js → chunk-MX3YWQON-BpS_PtKp.js} +1 -1
  33. package/dist/web/assets/{chunk-NQ4KR5QH-DXUTQ-BL.js → chunk-NQ4KR5QH-z_blpjxi.js} +1 -1
  34. package/dist/web/assets/{chunk-O4XLMI2P-BsUWb9d0.js → chunk-O4XLMI2P-nDhi_cVu.js} +1 -1
  35. package/dist/web/assets/{chunk-OZEHJAEY-rG0P22U9.js → chunk-OZEHJAEY-BXhYx3nO.js} +1 -1
  36. package/dist/web/assets/{chunk-PQ6SQG4A-DX0xW7kO.js → chunk-PQ6SQG4A-TF58UVMU.js} +1 -1
  37. package/dist/web/assets/{chunk-PU5JKC2W-C7Gry6md.js → chunk-PU5JKC2W-ek7k4QVB.js} +1 -1
  38. package/dist/web/assets/chunk-QZHKN3VN-CYaTbeZf.js +1 -0
  39. package/dist/web/assets/{chunk-R5LLSJPH-CMY0PkRK.js → chunk-R5LLSJPH-CFwSJijQ.js} +1 -1
  40. package/dist/web/assets/{chunk-WL4C6EOR-CXuQvlyu.js → chunk-WL4C6EOR-ByUrSRin.js} +1 -1
  41. package/dist/web/assets/{chunk-XIRO2GV7-DRJEb7Zb.js → chunk-XIRO2GV7-Djlmrely.js} +1 -1
  42. package/dist/web/assets/{chunk-XPW4576I-BPEX8KhL.js → chunk-XPW4576I-BPQQBakK.js} +1 -1
  43. package/dist/web/assets/{chunk-XZSTWKYB-Cb0iqycX.js → chunk-XZSTWKYB-DxAOx4hG.js} +1 -1
  44. package/dist/web/assets/{chunk-YBOYWFTD-av5aeHLq.js → chunk-YBOYWFTD-rQG3QH5s.js} +1 -1
  45. package/dist/web/assets/classDiagram-VBA2DB6C-BA8Nj-_C.js +1 -0
  46. package/dist/web/assets/classDiagram-v2-RAHNMMFH-DjYu-6mn.js +1 -0
  47. package/dist/web/assets/clone-LRxlvnMj.js +1 -0
  48. package/dist/web/assets/code-editor-aQQZUc2m.js +2 -0
  49. package/dist/web/assets/columns-2-cEVJHYd7.js +1 -0
  50. package/dist/web/assets/{cose-bilkent-S5V4N54A-qudEiMCT.js → cose-bilkent-S5V4N54A-B_AWZsOP.js} +1 -1
  51. package/dist/web/assets/createLucideIcon-PuMiQgHl.js +1 -0
  52. package/dist/web/assets/{csv-preview-DUbHtTAS.js → csv-preview-ncSOnJSC.js} +2 -2
  53. package/dist/web/assets/{dagre-BFcnKyBF.js → dagre-DHq9bhnd.js} +1 -1
  54. package/dist/web/assets/{dagre-KLK3FWXG-C3O-MTLf.js → dagre-KLK3FWXG-BdJr7Byp.js} +1 -1
  55. package/dist/web/assets/database-viewer-ChyP1N3c.js +1 -0
  56. package/dist/web/assets/{diagram-E7M64L7V-DxPjK7_c.js → diagram-E7M64L7V-_db4pBVA.js} +1 -1
  57. package/dist/web/assets/{diagram-IFDJBPK2-sqTog_XV.js → diagram-IFDJBPK2-xKoeuiJx.js} +1 -1
  58. package/dist/web/assets/{diagram-P4PSJMXO-hzmp0GHK.js → diagram-P4PSJMXO-C8tjJsev.js} +1 -1
  59. package/dist/web/assets/diff-viewer-ktwO5JbX.js +4 -0
  60. package/dist/web/assets/{dist-CALwEtco.js → dist-DIV6WgAG.js} +1 -1
  61. package/dist/web/assets/{dist-DGDPTxs1.js → dist-ovWkrgO-.js} +1 -1
  62. package/dist/web/assets/{erDiagram-INFDFZHY-DLeYhAAT.js → erDiagram-INFDFZHY-BSh2z9Df.js} +1 -1
  63. package/dist/web/assets/extension-webview-Bx1TlP6q.js +3 -0
  64. package/dist/web/assets/{flowDiagram-PKNHOUZH-CRxlE9Sr.js → flowDiagram-PKNHOUZH-oYaovqyp.js} +1 -1
  65. package/dist/web/assets/{ganttDiagram-A5KZAMGK-BdjmoMLS.js → ganttDiagram-A5KZAMGK-DmL26q2P.js} +1 -1
  66. package/dist/web/assets/git-graph-BIrGMX6e.js +1 -0
  67. package/dist/web/assets/gitGraph-HDMCJU4V-Bwna3and.js +1 -0
  68. package/dist/web/assets/{gitGraphDiagram-K3NZZRJ6-BeHSX7kk.js → gitGraphDiagram-K3NZZRJ6-CMoukSrY.js} +1 -1
  69. package/dist/web/assets/{graphlib-Duh_bWLa.js → graphlib-BcsNnGcW.js} +1 -1
  70. package/dist/web/assets/index-C6KLr58u.js +37 -0
  71. package/dist/web/assets/index-DpBKDbIW.css +2 -0
  72. package/dist/web/assets/info-3K5VOQVL-_vRxVNUm.js +1 -0
  73. package/dist/web/assets/infoDiagram-LFFYTUFH-DWwumDkq.js +2 -0
  74. package/dist/web/assets/{isEmpty-B9L-Ge-H.js → isEmpty-bnrF3Qbc.js} +1 -1
  75. package/dist/web/assets/{ishikawaDiagram-PHBUUO56-Cu0Rt1Ok.js → ishikawaDiagram-PHBUUO56-D05_LyL7.js} +1 -1
  76. package/dist/web/assets/{journeyDiagram-4ABVD52K-CgDI-UG4.js → journeyDiagram-4ABVD52K-B_L20qMe.js} +1 -1
  77. package/dist/web/assets/jsx-runtime-kMwlnEGE.js +1 -0
  78. package/dist/web/assets/{kanban-definition-K7BYSVSG-h4g10UHL.js → kanban-definition-K7BYSVSG-CZ535BbZ.js} +1 -1
  79. package/dist/web/assets/keybindings-store-D3Y5c5uS.js +1 -0
  80. package/dist/web/assets/{line-B75-Rx70.js → line-CVvo3dRu.js} +1 -1
  81. package/dist/web/assets/{linear-Bcjv9FQt.js → linear-DP4mkX3m.js} +1 -1
  82. package/dist/web/assets/{markdown-renderer-VIZB1GXE.js → markdown-renderer-A7J2gdKT.js} +5 -5
  83. package/dist/web/assets/{mermaid-parser.core-8u2leTXI.js → mermaid-parser.core-C7UwoIh6.js} +2 -2
  84. package/dist/web/assets/{mindmap-definition-YRQLILUH-BaOBwb-W.js → mindmap-definition-YRQLILUH-x0MTutJp.js} +1 -1
  85. package/dist/web/assets/{ordinal-LFEjVtwQ.js → ordinal-_K3x1fkz.js} +1 -1
  86. package/dist/web/assets/packet-RMMSAZCW-DY5PNnZU.js +1 -0
  87. package/dist/web/assets/pie-UPGHQEXC-BHncZutv.js +1 -0
  88. package/dist/web/assets/{pieDiagram-SKSYHLDU-At5Kz0KK.js → pieDiagram-SKSYHLDU-C1Gjrtzy.js} +1 -1
  89. package/dist/web/assets/postgres-viewer-C9-Acry_.js +1 -0
  90. package/dist/web/assets/{quadrantDiagram-337W2JSQ-CdjGIDfw.js → quadrantDiagram-337W2JSQ-C8bzJCjQ.js} +1 -1
  91. package/dist/web/assets/radar-KQ55EAFF-DH0AOkUy.js +1 -0
  92. package/dist/web/assets/{requirementDiagram-Z7DCOOCP-B9F_Cx_p.js → requirementDiagram-Z7DCOOCP-pQyah6WB.js} +1 -1
  93. package/dist/web/assets/{sankeyDiagram-WA2Y5GQK-RolPi8bU.js → sankeyDiagram-WA2Y5GQK-T6RgG-N8.js} +1 -1
  94. package/dist/web/assets/{sequenceDiagram-2WXFIKYE-DM-tMAhx.js → sequenceDiagram-2WXFIKYE-BQDJ4CVs.js} +1 -1
  95. package/dist/web/assets/settings-tab-C17exmRv.js +1 -0
  96. package/dist/web/assets/sqlite-viewer-Dr5oWCWA.js +1 -0
  97. package/dist/web/assets/{stateDiagram-RAJIS63D-C4EMl6jf.js → stateDiagram-RAJIS63D-66vhiIuk.js} +1 -1
  98. package/dist/web/assets/stateDiagram-v2-FVOUBMTO-BGVqj_g9.js +1 -0
  99. package/dist/web/assets/tab-store-BOgTrqRr.js +1 -0
  100. package/dist/web/assets/table-DFevCOMd.js +1 -0
  101. package/dist/web/assets/tag-CXMT0QB6.js +1 -0
  102. package/dist/web/assets/{terminal-tab-XhKfb4ei.js → terminal-tab-CpyKvyfC.js} +1 -1
  103. package/dist/web/assets/{timeline-definition-YZTLITO2-A4PN_Efm.js → timeline-definition-YZTLITO2-DwZqB3nn.js} +1 -1
  104. package/dist/web/assets/treemap-KZPCXAKY-B2Xkyv-K.js +1 -0
  105. package/dist/web/assets/{use-monaco-theme-0p0-84jJ.js → use-monaco-theme-BjPAik5w.js} +1 -1
  106. package/dist/web/assets/{vennDiagram-LZ73GAT5-ywK7LMaH.js → vennDiagram-LZ73GAT5-s9Z71fz-.js} +1 -1
  107. package/dist/web/assets/{xychartDiagram-JWTSCODW-DylHYNtJ.js → xychartDiagram-JWTSCODW-DRa_TH4B.js} +1 -1
  108. package/dist/web/index.html +10 -9
  109. package/dist/web/sw.js +1 -1
  110. package/docs/code-standards.md +128 -1
  111. package/docs/codebase-summary.md +79 -12
  112. package/docs/extension-development-guide.md +532 -0
  113. package/docs/project-changelog.md +51 -1
  114. package/docs/project-roadmap.md +9 -3
  115. package/docs/system-architecture.md +432 -3
  116. package/package.json +6 -3
  117. package/packages/ext-database/package.json +41 -0
  118. package/packages/ext-database/src/connection-tree.ts +142 -0
  119. package/packages/ext-database/src/extension.ts +346 -0
  120. package/packages/ext-database/src/query-panel.ts +120 -0
  121. package/packages/ext-database/src/table-viewer-panel.ts +410 -0
  122. package/packages/ext-database/tsconfig.json +8 -0
  123. package/packages/vscode-compat/package.json +16 -0
  124. package/packages/vscode-compat/src/commands.ts +39 -0
  125. package/packages/vscode-compat/src/context.ts +65 -0
  126. package/packages/vscode-compat/src/disposable.ts +21 -0
  127. package/packages/vscode-compat/src/env.ts +20 -0
  128. package/packages/vscode-compat/src/event-emitter.ts +28 -0
  129. package/packages/vscode-compat/src/index.ts +93 -0
  130. package/packages/vscode-compat/src/not-supported.ts +15 -0
  131. package/packages/vscode-compat/src/types.ts +167 -0
  132. package/packages/vscode-compat/src/uri.ts +65 -0
  133. package/packages/vscode-compat/src/window.ts +229 -0
  134. package/packages/vscode-compat/src/workspace.ts +76 -0
  135. package/packages/vscode-compat/tsconfig.json +10 -0
  136. package/src/cli/commands/autostart.ts +1 -1
  137. package/src/cli/commands/ext-cmd.ts +121 -0
  138. package/src/cli/commands/restart.ts +9 -1
  139. package/src/cli/commands/status.ts +19 -0
  140. package/src/index.ts +5 -3
  141. package/src/providers/claude-agent-sdk.ts +221 -17
  142. package/src/providers/cli-provider-base.ts +6 -0
  143. package/src/server/index.ts +55 -155
  144. package/src/server/routes/chat.ts +81 -11
  145. package/src/server/routes/extensions.ts +81 -0
  146. package/src/server/routes/project-scoped.ts +2 -0
  147. package/src/server/routes/settings.ts +27 -0
  148. package/src/server/routes/workspace.ts +35 -0
  149. package/src/server/ws/chat.ts +9 -3
  150. package/src/server/ws/extensions.ts +175 -0
  151. package/src/services/account-selector.service.ts +14 -5
  152. package/src/services/account.service.ts +7 -7
  153. package/src/services/claude-usage.service.ts +11 -11
  154. package/src/services/cloud-ws.service.ts +228 -0
  155. package/src/services/cloud.service.ts +1 -0
  156. package/src/services/contribution-registry.ts +110 -0
  157. package/src/services/db.service.ts +181 -4
  158. package/src/services/extension-host-worker.ts +160 -0
  159. package/src/services/extension-installer.ts +112 -0
  160. package/src/services/extension-manifest.ts +65 -0
  161. package/src/services/extension-rpc-handlers.ts +235 -0
  162. package/src/services/extension-rpc.ts +105 -0
  163. package/src/services/extension.service.ts +228 -0
  164. package/src/services/mcp-config.service.ts +15 -6
  165. package/src/services/supervisor.ts +271 -25
  166. package/src/types/api.ts +1 -0
  167. package/src/types/chat.ts +4 -0
  168. package/src/types/extension-messages.ts +64 -0
  169. package/src/types/extension.ts +131 -0
  170. package/src/web/app.tsx +69 -48
  171. package/src/web/components/chat/account-rotation-settings.tsx +163 -0
  172. package/src/web/components/chat/chat-history-bar.tsx +106 -10
  173. package/src/web/components/chat/chat-tab.tsx +15 -10
  174. package/src/web/components/chat/chat-welcome.tsx +148 -0
  175. package/src/web/components/chat/message-input.tsx +29 -29
  176. package/src/web/components/chat/message-list.tsx +19 -6
  177. package/src/web/components/chat/session-picker.tsx +80 -32
  178. package/src/web/components/chat/usage-badge.tsx +83 -10
  179. package/src/web/components/extensions/extension-inputbox.tsx +92 -0
  180. package/src/web/components/extensions/extension-quickpick.tsx +194 -0
  181. package/src/web/components/extensions/extension-tree-view.tsx +240 -0
  182. package/src/web/components/extensions/extension-webview.tsx +83 -0
  183. package/src/web/components/layout/command-palette.tsx +22 -2
  184. package/src/web/components/layout/editor-panel.tsx +163 -18
  185. package/src/web/components/layout/mobile-nav.tsx +2 -1
  186. package/src/web/components/layout/sidebar.tsx +21 -3
  187. package/src/web/components/layout/status-bar.tsx +64 -0
  188. package/src/web/components/layout/tab-bar.tsx +2 -0
  189. package/src/web/components/layout/tab-content.tsx +5 -0
  190. package/src/web/components/layout/upgrade-banner.tsx +15 -5
  191. package/src/web/components/settings/change-password-section.tsx +128 -0
  192. package/src/web/components/settings/extension-manager-section.tsx +214 -0
  193. package/src/web/components/settings/settings-tab.tsx +9 -2
  194. package/src/web/components/shared/connection-lost-overlay.tsx +89 -0
  195. package/src/web/hooks/use-chat.ts +28 -0
  196. package/src/web/hooks/use-extension-ws.ts +181 -0
  197. package/src/web/hooks/use-global-keybindings.ts +18 -2
  198. package/src/web/hooks/use-server-reload.ts +9 -0
  199. package/src/web/hooks/use-url-sync.ts +173 -21
  200. package/src/web/stores/connection-store.ts +39 -0
  201. package/src/web/stores/extension-store.ts +204 -0
  202. package/src/web/stores/panel-store.ts +63 -9
  203. package/src/web/stores/panel-utils.ts +145 -3
  204. package/src/web/stores/settings-store.ts +7 -2
  205. package/src/web/stores/tab-store.ts +2 -1
  206. package/tsconfig.json +3 -1
  207. package/dist/web/assets/api-settings-CEMxVMCV.js +0 -1
  208. package/dist/web/assets/architecture-PBZL5I3N-CFzkFKEL.js +0 -1
  209. package/dist/web/assets/arrow-up--LjUXLEt.js +0 -1
  210. package/dist/web/assets/browser-tab-D1Zua62g.js +0 -1
  211. package/dist/web/assets/channel-C2fMafck.js +0 -1
  212. package/dist/web/assets/chat-tab-BnD27Vp9.js +0 -7
  213. package/dist/web/assets/chevron-right-CHnjJt4E.js +0 -1
  214. package/dist/web/assets/chunk-GLR3WWYH-DBdWQ3zy.js +0 -2
  215. package/dist/web/assets/chunk-HHEYEP7N-BBw_z0fW.js +0 -1
  216. package/dist/web/assets/chunk-QZHKN3VN-DFKFM_C1.js +0 -1
  217. package/dist/web/assets/classDiagram-VBA2DB6C-Dp4Kk3Yb.js +0 -1
  218. package/dist/web/assets/classDiagram-v2-RAHNMMFH-D8IvcV_B.js +0 -1
  219. package/dist/web/assets/clone-B2hUek6n.js +0 -1
  220. package/dist/web/assets/code-editor-DGRg8stf.js +0 -2
  221. package/dist/web/assets/columns-2-DbesTfa7.js +0 -1
  222. package/dist/web/assets/database-viewer-DxCXZQcE.js +0 -1
  223. package/dist/web/assets/diff-viewer-C1sDJG35.js +0 -4
  224. package/dist/web/assets/git-graph-BDn-EiGE.js +0 -1
  225. package/dist/web/assets/gitGraph-HDMCJU4V-CNlas3Rz.js +0 -1
  226. package/dist/web/assets/index-Bun94AK3.js +0 -37
  227. package/dist/web/assets/index-Db8uky1a.css +0 -2
  228. package/dist/web/assets/info-3K5VOQVL-BDzTLc11.js +0 -1
  229. package/dist/web/assets/infoDiagram-LFFYTUFH-ZZmpgc6t.js +0 -2
  230. package/dist/web/assets/jsx-runtime-BRW_vwa9.js +0 -1
  231. package/dist/web/assets/keybindings-store-COmK4Dte.js +0 -1
  232. package/dist/web/assets/packet-RMMSAZCW-IVa5F-go.js +0 -1
  233. package/dist/web/assets/pie-UPGHQEXC-CvXHKAzp.js +0 -1
  234. package/dist/web/assets/postgres-viewer-CvQZ8gkh.js +0 -1
  235. package/dist/web/assets/radar-KQ55EAFF-Z-Tr5wtS.js +0 -1
  236. package/dist/web/assets/settings-tab-RCnvZ29H.js +0 -1
  237. package/dist/web/assets/sqlite-viewer-CEEm2W4C.js +0 -1
  238. package/dist/web/assets/stateDiagram-v2-FVOUBMTO-B-UjZch3.js +0 -1
  239. package/dist/web/assets/tab-store-Bjh6bXFP.js +0 -1
  240. package/dist/web/assets/table-CQVQM2SB.js +0 -1
  241. package/dist/web/assets/tag-Q2dZiSPX.js +0 -1
  242. package/dist/web/assets/treemap-KZPCXAKY-C9TYRE0k.js +0 -1
  243. /package/dist/web/assets/{api-client-BKIT_Qeg.js → api-client-BfBM3I7n.js} +0 -0
  244. /package/dist/web/assets/{array-DqLCdDFv.js → array-B9UHiPd-.js} +0 -0
  245. /package/dist/web/assets/{cytoscape.esm-CWPXKqbJ.js → cytoscape.esm-BW-DbntU.js} +0 -0
  246. /package/dist/web/assets/{defaultLocale-CrJzLgRD.js → defaultLocale-5eAKkKJC.js} +0 -0
  247. /package/dist/web/assets/{dist-Cep75xXf.js → dist-CSJdAyA9.js} +0 -0
  248. /package/dist/web/assets/{init-C0r9Gk5G.js → init-DlZdxViB.js} +0 -0
  249. /package/dist/web/assets/{isArrayLikeObject-CGBoxvCD.js → isArrayLikeObject-B_v2FtYn.js} +0 -0
  250. /package/dist/web/assets/{katex-DzXRfQ_m.js → katex-Bqvo_ZG0.js} +0 -0
  251. /package/dist/web/assets/{lib-BeaDXEkP.js → lib-BQ34Db2e.js} +0 -0
  252. /package/dist/web/assets/{math-y9zN1W-N.js → math-069Z4SuC.js} +0 -0
  253. /package/dist/web/assets/{path-DIKpVbHL.js → path-6uRLdFF7.js} +0 -0
  254. /package/dist/web/assets/{rough.esm-nHaDi0Kw.js → rough.esm-JX0wREDd.js} +0 -0
  255. /package/dist/web/assets/{src-Dw4QhedI.js → src-BqX54PbV.js} +0 -0
  256. /package/dist/web/assets/{utils-DMiycH3O.js → utils-BNytJOb1.js} +0 -0
@@ -0,0 +1,410 @@
1
+ /**
2
+ * Full-featured table viewer webview panel.
3
+ * Replicates ~90% of the built-in DatabaseViewer:
4
+ * - Toolbar with connection/table name, refresh, SQL toggle
5
+ * - Data grid with sticky headers, inline cell editing (double-click)
6
+ * - Pagination (prev/next, page X / total)
7
+ * - Toggleable SQL query panel with execute (Cmd+Enter)
8
+ * - NULL styling, row hover, loading states
9
+ */
10
+
11
+ function esc(s: string): string {
12
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
13
+ }
14
+
15
+ export interface TableViewerOptions {
16
+ connectionId: number;
17
+ connectionName: string;
18
+ tableName: string;
19
+ schemaName: string;
20
+ }
21
+
22
+ export function getTableViewerHtml(opts: TableViewerOptions): string {
23
+ return `<!DOCTYPE html>
24
+ <html>
25
+ <head>
26
+ <meta charset="utf-8">
27
+ <style>
28
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
29
+ :root {
30
+ --bg: #1e1e2e; --surface: #181825; --mantle: #11111b;
31
+ --overlay0: #6c7086; --overlay1: #7f849c;
32
+ --text: #cdd6f4; --subtext: #a6adc8; --subtle: #585b70;
33
+ --border: #313244; --border2: #45475a;
34
+ --blue: #89b4fa; --green: #a6e3a1; --red: #f38ba8; --yellow: #f9e2af;
35
+ --surface-hover: #313244;
36
+ }
37
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); font-size: 13px; display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
38
+
39
+ /* Toolbar */
40
+ .toolbar { display: flex; align-items: center; gap: 8px; padding: 6px 12px; border-bottom: 1px solid var(--border); background: var(--bg); flex-shrink: 0; }
41
+ .toolbar .icon { width: 14px; height: 14px; color: var(--overlay0); }
42
+ .toolbar .conn-name { font-size: 12px; color: var(--subtext); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
43
+ .toolbar .separator { color: var(--subtle); font-size: 12px; }
44
+ .toolbar .table-name { font-size: 12px; color: var(--subtext); }
45
+ .toolbar .spacer { flex: 1; }
46
+ .toolbar button { background: none; border: none; cursor: pointer; padding: 4px; border-radius: 4px; color: var(--subtext); transition: color 0.15s, background 0.15s; display: flex; align-items: center; justify-content: center; }
47
+ .toolbar button:hover { color: var(--text); background: var(--surface-hover); }
48
+ .toolbar button.active { background: var(--border); color: var(--text); }
49
+ .toolbar .btn-text { font-size: 12px; padding: 4px 8px; font-weight: 500; }
50
+
51
+ /* Grid container */
52
+ .grid-container { flex: 1; overflow: hidden; display: flex; flex-direction: column; min-height: 0; }
53
+ .grid-scroll { flex: 1; overflow: auto; min-height: 0; }
54
+
55
+ /* Table */
56
+ table { width: 100%; border-collapse: collapse; font-size: 12px; table-layout: auto; }
57
+ thead { position: sticky; top: 0; z-index: 10; }
58
+ th { background: var(--border); text-align: left; padding: 6px 8px; font-weight: 600; font-size: 11px; color: var(--subtext); white-space: nowrap; border-bottom: 1px solid var(--border2); }
59
+ th.pk { font-weight: 700; color: var(--yellow); }
60
+ td { padding: 4px 8px; border-bottom: 1px solid var(--border); max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: default; }
61
+ tr:hover td { background: var(--surface-hover); }
62
+ td.null-val { color: var(--subtle); font-style: italic; }
63
+ td.editing { padding: 2px 4px; }
64
+ td.editing input { width: 100%; background: transparent; border: 1px solid var(--blue); border-radius: 3px; color: var(--text); padding: 2px 4px; font-size: 12px; font-family: inherit; outline: none; }
65
+
66
+ /* Pagination */
67
+ .pagination { display: flex; align-items: center; justify-content: space-between; padding: 6px 12px; border-top: 1px solid var(--border); background: var(--bg); flex-shrink: 0; font-size: 12px; color: var(--subtext); }
68
+ .pagination .page-controls { display: flex; align-items: center; gap: 8px; }
69
+ .pagination button { background: none; border: none; cursor: pointer; padding: 2px; border-radius: 3px; color: var(--subtext); display: flex; align-items: center; }
70
+ .pagination button:hover:not(:disabled) { color: var(--text); background: var(--surface-hover); }
71
+ .pagination button:disabled { opacity: 0.3; cursor: default; }
72
+
73
+ /* SQL panel */
74
+ .sql-panel { border-top: 1px solid var(--border); display: flex; flex-direction: column; height: 40%; flex-shrink: 0; overflow: hidden; }
75
+ .sql-panel.hidden { display: none; }
76
+ .sql-header { display: flex; align-items: flex-start; gap: 4px; border-bottom: 1px solid var(--border); background: var(--bg); }
77
+ .sql-header textarea { flex: 1; background: transparent; border: none; color: var(--text); padding: 8px; font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; font-size: 12px; resize: none; outline: none; max-height: 120px; min-height: 60px; }
78
+ .sql-header button { margin: 4px; padding: 6px; border-radius: 4px; background: var(--blue); color: var(--mantle); border: none; cursor: pointer; font-weight: 600; font-size: 12px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
79
+ .sql-header button:hover { opacity: 0.9; }
80
+ .sql-header button:disabled { opacity: 0.5; }
81
+ .sql-results { flex: 1; overflow: auto; font-size: 12px; min-height: 0; }
82
+ .sql-results .sql-error { padding: 8px 12px; color: var(--red); background: rgba(243,139,168,0.05); }
83
+ .sql-results .sql-modify { padding: 8px 12px; color: var(--green); }
84
+ .sql-results .sql-empty { padding: 8px 12px; color: var(--subtext); }
85
+ .sql-results table th { background: var(--border); }
86
+
87
+ /* Loading / empty states */
88
+ .state-msg { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--overlay0); font-size: 12px; gap: 8px; }
89
+ .spinner { width: 16px; height: 16px; border: 2px solid var(--border2); border-top-color: var(--blue); border-radius: 50%; animation: spin 0.6s linear infinite; }
90
+ @keyframes spin { to { transform: rotate(360deg); } }
91
+ .refresh-spin { animation: spin 0.6s linear infinite; }
92
+
93
+ /* SVG icons inline */
94
+ svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
95
+ </style>
96
+ </head>
97
+ <body>
98
+ <!-- Toolbar -->
99
+ <div class="toolbar">
100
+ <svg class="icon" viewBox="0 0 24 24"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5V19A9 3 0 0 0 21 19V5"/><path d="M3 12A9 3 0 0 0 21 12"/></svg>
101
+ <span class="conn-name">${esc(opts.connectionName)}</span>
102
+ <span class="separator">/</span>
103
+ <span class="table-name">${esc(opts.tableName)}</span>
104
+ <span class="spacer"></span>
105
+ <button id="btn-refresh" title="Refresh data">
106
+ <svg id="refresh-icon" viewBox="0 0 24 24"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
107
+ </button>
108
+ <button id="btn-sql" class="btn-text" title="Toggle SQL query panel">SQL</button>
109
+ </div>
110
+
111
+ <!-- Data grid -->
112
+ <div class="grid-container" id="grid-container">
113
+ <div class="grid-scroll" id="grid-scroll">
114
+ <div class="state-msg" id="loading-msg"><div class="spinner"></div> Loading…</div>
115
+ </div>
116
+ </div>
117
+
118
+ <!-- Pagination -->
119
+ <div class="pagination" id="pagination" style="display:none">
120
+ <span id="row-count">0 rows</span>
121
+ <div class="page-controls">
122
+ <button id="btn-prev" disabled>
123
+ <svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
124
+ </button>
125
+ <span id="page-info">1 / 1</span>
126
+ <button id="btn-next" disabled>
127
+ <svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
128
+ </button>
129
+ </div>
130
+ </div>
131
+
132
+ <!-- SQL panel -->
133
+ <div class="sql-panel hidden" id="sql-panel">
134
+ <div class="sql-header">
135
+ <textarea id="sql-input" placeholder="Enter SQL query… (Cmd+Enter to execute)" rows="3">SELECT * FROM ${esc(opts.schemaName !== "main" && opts.schemaName !== "public" ? opts.schemaName + "." : "")}${esc(opts.tableName)} LIMIT 100;</textarea>
136
+ <button id="btn-run-sql" title="Execute (Cmd+Enter)">
137
+ <svg viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg>
138
+ </button>
139
+ </div>
140
+ <div class="sql-results" id="sql-results"></div>
141
+ </div>
142
+
143
+ <script>
144
+ (function() {
145
+ const vscode = acquireVsCodeApi();
146
+ const connId = ${opts.connectionId};
147
+ const tableName = "${esc(opts.tableName).replace(/\\/g, "\\\\").replace(/"/g, '\\"')}";
148
+ const schemaName = "${esc(opts.schemaName).replace(/\\/g, "\\\\").replace(/"/g, '\\"')}";
149
+
150
+ // State
151
+ let currentPage = 1;
152
+ let totalRows = 0;
153
+ let pageLimit = 100;
154
+ let columns = [];
155
+ let rows = [];
156
+ let schema = []; // { name, type, nullable, pk, defaultValue }
157
+ let pkCol = null;
158
+ let editingCell = null; // { rowIdx, col }
159
+ let loading = true;
160
+ let sqlPanelOpen = false;
161
+
162
+ // Elements
163
+ const gridScroll = document.getElementById('grid-scroll');
164
+ const gridContainer = document.getElementById('grid-container');
165
+ const pagination = document.getElementById('pagination');
166
+ const rowCountEl = document.getElementById('row-count');
167
+ const pageInfoEl = document.getElementById('page-info');
168
+ const btnPrev = document.getElementById('btn-prev');
169
+ const btnNext = document.getElementById('btn-next');
170
+ const btnRefresh = document.getElementById('btn-refresh');
171
+ const refreshIcon = document.getElementById('refresh-icon');
172
+ const btnSql = document.getElementById('btn-sql');
173
+ const sqlPanel = document.getElementById('sql-panel');
174
+ const sqlInput = document.getElementById('sql-input');
175
+ const sqlResults = document.getElementById('sql-results');
176
+ const btnRunSql = document.getElementById('btn-run-sql');
177
+
178
+ // -- Request initial data --
179
+ vscode.postMessage({ type: 'init', connectionId: connId, tableName, schemaName });
180
+
181
+ // -- Toolbar actions --
182
+ btnRefresh.addEventListener('click', () => {
183
+ loading = true;
184
+ refreshIcon.classList.add('refresh-spin');
185
+ vscode.postMessage({ type: 'refresh' });
186
+ });
187
+
188
+ btnSql.addEventListener('click', () => {
189
+ sqlPanelOpen = !sqlPanelOpen;
190
+ sqlPanel.classList.toggle('hidden', !sqlPanelOpen);
191
+ btnSql.classList.toggle('active', sqlPanelOpen);
192
+ if (sqlPanelOpen) {
193
+ gridContainer.style.maxHeight = '60%';
194
+ } else {
195
+ gridContainer.style.maxHeight = '';
196
+ }
197
+ });
198
+
199
+ // -- Pagination --
200
+ btnPrev.addEventListener('click', () => {
201
+ if (currentPage > 1) { currentPage--; fetchPage(); }
202
+ });
203
+ btnNext.addEventListener('click', () => {
204
+ const totalPages = Math.ceil(totalRows / pageLimit) || 1;
205
+ if (currentPage < totalPages) { currentPage++; fetchPage(); }
206
+ });
207
+
208
+ function fetchPage() {
209
+ loading = true;
210
+ renderGrid();
211
+ vscode.postMessage({ type: 'fetchPage', page: currentPage });
212
+ }
213
+
214
+ // -- SQL --
215
+ btnRunSql.addEventListener('click', runSql);
216
+ sqlInput.addEventListener('keydown', (e) => {
217
+ if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
218
+ e.preventDefault();
219
+ runSql();
220
+ }
221
+ });
222
+
223
+ function runSql() {
224
+ const sql = sqlInput.value.trim();
225
+ if (!sql) return;
226
+ btnRunSql.disabled = true;
227
+ sqlResults.innerHTML = '<div class="state-msg"><div class="spinner"></div></div>';
228
+ vscode.postMessage({ type: 'executeQuery', sql });
229
+ }
230
+
231
+ // -- Render data grid --
232
+ function renderGrid() {
233
+ if (loading && rows.length === 0) {
234
+ gridScroll.innerHTML = '<div class="state-msg"><div class="spinner"></div> Loading…</div>';
235
+ pagination.style.display = 'none';
236
+ return;
237
+ }
238
+ if (!columns.length) {
239
+ gridScroll.innerHTML = '<div class="state-msg">No data</div>';
240
+ pagination.style.display = 'none';
241
+ return;
242
+ }
243
+
244
+ let html = '<table><thead><tr>';
245
+ columns.forEach(col => {
246
+ const info = schema.find(s => s.name === col);
247
+ const isPk = info && info.pk;
248
+ html += '<th' + (isPk ? ' class="pk"' : '') + '>' + escH(col) + '</th>';
249
+ });
250
+ html += '</tr></thead><tbody>';
251
+
252
+ if (rows.length === 0) {
253
+ html += '<tr><td colspan="' + columns.length + '" style="text-align:center;padding:32px;color:var(--overlay0)">No data</td></tr>';
254
+ } else {
255
+ rows.forEach((row, rowIdx) => {
256
+ html += '<tr>';
257
+ columns.forEach(col => {
258
+ const val = row[col];
259
+ const isEditing = editingCell && editingCell.rowIdx === rowIdx && editingCell.col === col;
260
+ if (isEditing) {
261
+ const editVal = val == null ? '' : String(val);
262
+ html += '<td class="editing"><input data-row="' + rowIdx + '" data-col="' + escH(col) + '" value="' + escH(editVal) + '" /></td>';
263
+ } else if (val == null) {
264
+ html += '<td class="null-val" data-row="' + rowIdx + '" data-col="' + escH(col) + '">NULL</td>';
265
+ } else {
266
+ html += '<td data-row="' + rowIdx + '" data-col="' + escH(col) + '" title="' + escH(String(val)) + '">' + escH(String(val)) + '</td>';
267
+ }
268
+ });
269
+ html += '</tr>';
270
+ });
271
+ }
272
+ html += '</tbody></table>';
273
+ gridScroll.innerHTML = html;
274
+
275
+ // Attach edit handlers
276
+ if (pkCol) {
277
+ gridScroll.querySelectorAll('td:not(.editing)').forEach(td => {
278
+ td.addEventListener('dblclick', () => {
279
+ const r = parseInt(td.getAttribute('data-row'));
280
+ const c = td.getAttribute('data-col');
281
+ if (isNaN(r) || !c) return;
282
+ editingCell = { rowIdx: r, col: c };
283
+ renderGrid();
284
+ // Focus the input
285
+ setTimeout(() => {
286
+ const inp = gridScroll.querySelector('input[data-row="' + r + '"][data-col="' + c + '"]');
287
+ if (inp) { inp.focus(); inp.select(); }
288
+ }, 10);
289
+ });
290
+ });
291
+ }
292
+
293
+ // Edit input handlers
294
+ gridScroll.querySelectorAll('td.editing input').forEach(inp => {
295
+ inp.addEventListener('blur', () => commitEdit(inp));
296
+ inp.addEventListener('keydown', (e) => {
297
+ if (e.key === 'Enter') { e.preventDefault(); commitEdit(inp); }
298
+ if (e.key === 'Escape') { editingCell = null; renderGrid(); }
299
+ });
300
+ });
301
+
302
+ // Update pagination
303
+ const totalPages = Math.ceil(totalRows / pageLimit) || 1;
304
+ pagination.style.display = 'flex';
305
+ rowCountEl.textContent = totalRows.toLocaleString() + ' rows';
306
+ pageInfoEl.textContent = currentPage + ' / ' + totalPages;
307
+ btnPrev.disabled = currentPage <= 1;
308
+ btnNext.disabled = currentPage >= totalPages;
309
+ refreshIcon.classList.remove('refresh-spin');
310
+ }
311
+
312
+ function commitEdit(inp) {
313
+ if (!editingCell || !pkCol) return;
314
+ const rowIdx = editingCell.rowIdx;
315
+ const col = editingCell.col;
316
+ const newVal = inp.value;
317
+ const row = rows[rowIdx];
318
+ if (!row) { editingCell = null; renderGrid(); return; }
319
+ const oldVal = row[col];
320
+ editingCell = null;
321
+ if (String(oldVal ?? '') !== newVal) {
322
+ vscode.postMessage({
323
+ type: 'updateCell',
324
+ pkColumn: pkCol,
325
+ pkValue: row[pkCol],
326
+ column: col,
327
+ value: newVal === '' ? null : newVal,
328
+ });
329
+ }
330
+ renderGrid();
331
+ }
332
+
333
+ // -- Render SQL results --
334
+ function renderSqlResult(msg) {
335
+ btnRunSql.disabled = false;
336
+ if (msg.type === 'queryError') {
337
+ sqlResults.innerHTML = '<div class="sql-error">' + escH(msg.error) + '</div>';
338
+ return;
339
+ }
340
+ if (msg.changeType === 'modify') {
341
+ sqlResults.innerHTML = '<div class="sql-modify">Query executed. ' + (msg.rowsAffected ?? 0) + ' row(s) affected.' + (msg.duration ? ' (' + msg.duration + 'ms)' : '') + '</div>';
342
+ return;
343
+ }
344
+ // select
345
+ if (!msg.rows || msg.rows.length === 0) {
346
+ sqlResults.innerHTML = '<div class="sql-empty">No results' + (msg.duration ? ' (' + msg.duration + 'ms)' : '') + '</div>';
347
+ return;
348
+ }
349
+ const cols = msg.columns || Object.keys(msg.rows[0]);
350
+ let html = '<table><thead><tr>';
351
+ cols.forEach(c => { html += '<th>' + escH(c) + '</th>'; });
352
+ html += '</tr></thead><tbody>';
353
+ msg.rows.forEach(row => {
354
+ html += '<tr>';
355
+ cols.forEach(c => {
356
+ const v = row[c];
357
+ html += v == null
358
+ ? '<td class="null-val">NULL</td>'
359
+ : '<td title="' + escH(String(v)) + '">' + escH(String(v)) + '</td>';
360
+ });
361
+ html += '</tr>';
362
+ });
363
+ html += '</tbody></table>';
364
+ sqlResults.innerHTML = html;
365
+ }
366
+
367
+ // -- Message handler --
368
+ window.addEventListener('message', (event) => {
369
+ const msg = event.data;
370
+ switch (msg.type) {
371
+ case 'tableData':
372
+ columns = msg.columns || [];
373
+ rows = msg.rows || [];
374
+ totalRows = msg.total ?? rows.length;
375
+ pageLimit = msg.limit ?? 100;
376
+ currentPage = msg.page ?? currentPage;
377
+ schema = msg.schema || [];
378
+ pkCol = null;
379
+ for (const s of schema) { if (s.pk) { pkCol = s.name; break; } }
380
+ loading = false;
381
+ editingCell = null;
382
+ renderGrid();
383
+ break;
384
+ case 'queryResult':
385
+ renderSqlResult(msg);
386
+ // Refresh grid data if it was a modify query
387
+ if (msg.changeType === 'modify') {
388
+ vscode.postMessage({ type: 'refresh' });
389
+ }
390
+ break;
391
+ case 'queryError':
392
+ renderSqlResult(msg);
393
+ break;
394
+ case 'cellUpdated':
395
+ // Refresh to show updated data
396
+ vscode.postMessage({ type: 'refresh' });
397
+ break;
398
+ case 'error':
399
+ loading = false;
400
+ gridScroll.innerHTML = '<div class="state-msg" style="color:var(--red)">' + escH(msg.message || 'Error') + '</div>';
401
+ break;
402
+ }
403
+ });
404
+
405
+ function escH(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }
406
+ })();
407
+ </script>
408
+ </body>
409
+ </html>`;
410
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"]
8
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@ppm/vscode-compat",
3
+ "version": "0.1.0",
4
+ "description": "VSCode-compatible API shim for PPM extensions",
5
+ "type": "module",
6
+ "main": "src/index.ts",
7
+ "types": "src/index.ts",
8
+ "exports": {
9
+ ".": "./src/index.ts"
10
+ },
11
+ "files": ["src/", "dist/"],
12
+ "license": "MIT",
13
+ "peerDependencies": {
14
+ "typescript": "^5.0.0"
15
+ }
16
+ }
@@ -0,0 +1,39 @@
1
+ import { Disposable } from "./disposable.ts";
2
+ import type { RpcClient } from "./types.ts";
3
+
4
+ type CommandHandler = (...args: unknown[]) => unknown;
5
+
6
+ /** VSCode-compatible commands namespace — delegates to RPC */
7
+ export class CommandService {
8
+ private localHandlers = new Map<string, CommandHandler>();
9
+ private rpc: RpcClient;
10
+ private extId: string;
11
+
12
+ constructor(rpc: RpcClient, extId: string) {
13
+ this.rpc = rpc;
14
+ this.extId = extId;
15
+ }
16
+
17
+ registerCommand(command: string, callback: CommandHandler): Disposable {
18
+ this.localHandlers.set(command, callback);
19
+ // Notify main process about the registration
20
+ this.rpc.notify("commands:register", { extId: this.extId, command });
21
+ return new Disposable(() => {
22
+ this.localHandlers.delete(command);
23
+ this.rpc.notify("commands:unregister", { command });
24
+ });
25
+ }
26
+
27
+ async executeCommand<T = unknown>(command: string, ...args: unknown[]): Promise<T> {
28
+ // Try local handler first (same-worker commands)
29
+ const local = this.localHandlers.get(command);
30
+ if (local) return await local(...args) as T;
31
+ // Delegate to main process (cross-extension or built-in commands)
32
+ return this.rpc.request<T>("commands:execute", command, ...args);
33
+ }
34
+
35
+ async getCommands(filterInternal?: boolean): Promise<string[]> {
36
+ const remote = await this.rpc.request<string[]>("commands:list", filterInternal ?? false);
37
+ return [...new Set([...this.localHandlers.keys(), ...remote])];
38
+ }
39
+ }
@@ -0,0 +1,65 @@
1
+ import type { Disposable } from "./disposable.ts";
2
+ import type { RpcClient } from "./types.ts";
3
+
4
+ /** Memento — key-value state store backed by SQLite via RPC */
5
+ export class Memento {
6
+ private cache = new Map<string, unknown>();
7
+ private rpc: RpcClient;
8
+ private extId: string;
9
+ private scope: string;
10
+
11
+ constructor(rpc: RpcClient, extId: string, scope: string, initial?: Record<string, string | null>) {
12
+ this.rpc = rpc;
13
+ this.extId = extId;
14
+ this.scope = scope;
15
+ // Hydrate from persisted values
16
+ if (initial) {
17
+ for (const [key, val] of Object.entries(initial)) {
18
+ if (val !== null) {
19
+ try { this.cache.set(key, JSON.parse(val)); } catch { this.cache.set(key, val); }
20
+ }
21
+ }
22
+ }
23
+ }
24
+
25
+ get<T = unknown>(key: string, defaultValue?: T): T | undefined {
26
+ if (this.cache.has(key)) return this.cache.get(key) as T;
27
+ return defaultValue;
28
+ }
29
+
30
+ async update(key: string, value: unknown): Promise<void> {
31
+ this.cache.set(key, value);
32
+ await this.rpc.request("storage:set", this.extId, this.scope, key, JSON.stringify(value));
33
+ }
34
+
35
+ keys(): readonly string[] {
36
+ return [...this.cache.keys()];
37
+ }
38
+ }
39
+
40
+ /** VSCode-compatible ExtensionContext */
41
+ export interface ExtensionContext {
42
+ readonly extensionId: string;
43
+ readonly extensionPath: string;
44
+ readonly storagePath: string;
45
+ readonly globalState: Memento;
46
+ readonly workspaceState: Memento;
47
+ readonly subscriptions: Disposable[];
48
+ }
49
+
50
+ export function createExtensionContext(
51
+ rpc: RpcClient,
52
+ extId: string,
53
+ extensionPath: string,
54
+ storagePath: string,
55
+ storedState?: { global?: Record<string, string | null>; workspace?: Record<string, string | null> },
56
+ ): ExtensionContext {
57
+ return {
58
+ extensionId: extId,
59
+ extensionPath,
60
+ storagePath,
61
+ globalState: new Memento(rpc, extId, "global", storedState?.global),
62
+ workspaceState: new Memento(rpc, extId, "workspace", storedState?.workspace),
63
+ subscriptions: [],
64
+ };
65
+ }
@@ -0,0 +1,21 @@
1
+ /** VSCode-compatible Disposable */
2
+ export class Disposable {
3
+ private callOnDispose: () => void;
4
+ private disposed = false;
5
+
6
+ constructor(callOnDispose: () => void) {
7
+ this.callOnDispose = callOnDispose;
8
+ }
9
+
10
+ dispose(): void {
11
+ if (this.disposed) return;
12
+ this.disposed = true;
13
+ this.callOnDispose();
14
+ }
15
+
16
+ static from(...disposables: { dispose(): void }[]): Disposable {
17
+ return new Disposable(() => {
18
+ for (const d of disposables) d.dispose();
19
+ });
20
+ }
21
+ }
@@ -0,0 +1,20 @@
1
+ import { Uri } from "./uri.ts";
2
+
3
+ /** VSCode-compatible env namespace */
4
+ export function createEnvNamespace(appName: string, machineId: string) {
5
+ return {
6
+ appName,
7
+ appRoot: "",
8
+ language: "en",
9
+ machineId,
10
+ uriScheme: "ppm",
11
+ clipboard: {
12
+ async readText(): Promise<string> { return ""; },
13
+ async writeText(_value: string): Promise<void> {},
14
+ },
15
+ openExternal(target: Uri): Promise<boolean> {
16
+ // Cannot open browser from Worker — notify main process
17
+ return Promise.resolve(false);
18
+ },
19
+ };
20
+ }
@@ -0,0 +1,28 @@
1
+ import { Disposable } from "./disposable.ts";
2
+
3
+ /** VSCode-compatible Event type */
4
+ export type Event<T> = (listener: (e: T) => void, thisArgs?: unknown) => Disposable;
5
+
6
+ /** VSCode-compatible EventEmitter */
7
+ export class EventEmitter<T> {
8
+ private listeners = new Set<(e: T) => void>();
9
+
10
+ /** The event that listeners can subscribe to */
11
+ readonly event: Event<T> = (listener: (e: T) => void): Disposable => {
12
+ this.listeners.add(listener);
13
+ return new Disposable(() => this.listeners.delete(listener));
14
+ };
15
+
16
+ /** Fire the event, notifying all listeners */
17
+ fire(data: T): void {
18
+ for (const listener of this.listeners) {
19
+ try { listener(data); } catch (e) {
20
+ console.error("[EventEmitter] Listener error:", e);
21
+ }
22
+ }
23
+ }
24
+
25
+ dispose(): void {
26
+ this.listeners.clear();
27
+ }
28
+ }