@hienlh/ppm 0.18.11 → 0.18.13
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/AGENTS.md +17 -5
- package/CHANGELOG.md +27 -0
- package/CLAUDE.md +3 -0
- package/README.md +87 -29
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +19 -1
- package/dist/web/assets/{adaptive-context-menu-DGCKKeTy.js → adaptive-context-menu-CbgPYQmj.js} +1 -1
- package/dist/web/assets/{ai-resource-editor-BOHHTTe7.js → ai-resource-editor-unM2HNmg.js} +1 -1
- package/dist/web/assets/{ai-settings-section-BigC_nZR.js → ai-settings-section-CdktdrwF.js} +1 -1
- package/dist/web/assets/{angular-html-BYPaydvh.js → angular-html-DcpbdcNG.js} +1 -1
- package/dist/web/assets/{angular-ts-Bb4AMKlk.js → angular-ts-Bv_WIk34.js} +1 -1
- package/dist/web/assets/api-client-BogqsFna.js +1 -0
- package/dist/web/assets/{api-settings-Bd3M4YpI.js → api-settings-BdCtex9i.js} +1 -1
- package/dist/web/assets/api-settings-DfXViPKz.js +1 -0
- package/dist/web/assets/{api-themes-Cpx419SL.js → api-themes-pRRoLvgD.js} +1 -1
- package/dist/web/assets/{apl-DB2VjFCS.js → apl-D5_lLszu.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-BzFm9ELu.js +1 -0
- package/dist/web/assets/{astro-BeoJdVpk.js → astro-CBHwddYL.js} +1 -1
- package/dist/web/assets/{audio-preview-BgFuTn-0.js → audio-preview-BD1iDovf.js} +1 -1
- package/dist/web/assets/{blade-Cf2q1sPf.js → blade-DGe1d2Pq.js} +1 -1
- package/dist/web/assets/{bsl-W1kOaNpu.js → bsl-2lyAzRJA.js} +1 -1
- package/dist/web/assets/{button-5zTrkEoN.js → button-2WCAS8dI.js} +1 -1
- package/dist/web/assets/{cairo-BoAZFcje.js → cairo-DjzZeJrq.js} +1 -1
- package/dist/web/assets/chat-tab-DzK8LGti.js +15 -0
- package/dist/web/assets/{cobol-B0Nm7RXj.js → cobol-cC3XIuAJ.js} +1 -1
- package/dist/web/assets/code-editor-CuMfPN9X.js +10 -0
- package/dist/web/assets/{coffee-BakMn3on.js → coffee-4eGboVoU.js} +1 -1
- package/dist/web/assets/{conflict-editor-BUs5k9q_.js → conflict-editor-DdJag4QK.js} +1 -1
- package/dist/web/assets/{context-menu-Bq92km4s.js → context-menu-BO1c9jKy.js} +1 -1
- package/dist/web/assets/{cpp-BRAJQHK2.js → cpp-DF9_G-OU.js} +1 -1
- package/dist/web/assets/{crystal-kqqO3zkK.js → crystal-OavZlzcm.js} +1 -1
- package/dist/web/assets/{csv-preview-ByoDgLAZ.js → csv-preview-DnXwouF3.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-Brkf9z41.js → data-grid-overlay-editor-B9Gpjm3l.js} +1 -1
- package/dist/web/assets/{database-viewer-Btc3h8Yu.js → database-viewer-Dk8oGyZx.js} +1 -1
- package/dist/web/assets/{dialog-DwtGlowE.js → dialog-B-l2ZxVm.js} +1 -1
- package/dist/web/assets/{diff-viewer-CZaDnR4w.js → diff-viewer-eaUBjLCH.js} +1 -1
- package/dist/web/assets/{docx-preview-DAD_vg59.js → docx-preview-DAdHPlhZ.js} +1 -1
- package/dist/web/assets/{edge-Cq1ZKZuE.js → edge-TzYh8OlN.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-B_VE7ppQ.js → edit-diff-preview-DlwP3UIU.js} +1 -1
- package/dist/web/assets/{elixir-BM_JoJRk.js → elixir-Cy3RhKKH.js} +1 -1
- package/dist/web/assets/{elm-Dw7oO08Y.js → elm-BTBZdweK.js} +1 -1
- package/dist/web/assets/{erb-CfKOGAfk.js → erb-dv1mI0y4.js} +1 -1
- package/dist/web/assets/{erlang-DlDmGVeE.js → erlang-DjeiDrkl.js} +1 -1
- package/dist/web/assets/{esm-DGAP0GFh.js → esm-FRwvcesu.js} +1 -1
- package/dist/web/assets/explorer-body-DkCkSVrN.js +2 -0
- package/dist/web/assets/explorer-window-content-MsnTVngu.js +1 -0
- package/dist/web/assets/{extension-store-Cpfh2vMm.js → extension-store-DUaZINyC.js} +1 -1
- package/dist/web/assets/{extension-webview-B2OnjuCu.js → extension-webview-W0qRfaAU.js} +1 -1
- package/dist/web/assets/{file-store-aOERIEo-.js → file-store-yReVbR8q.js} +1 -1
- package/dist/web/assets/{fortran-fixed-form-XnAhQWxS.js → fortran-fixed-form-BCH9DAIJ.js} +1 -1
- package/dist/web/assets/{fsharp-CdNvy0PG.js → fsharp-C93NYKYD.js} +1 -1
- package/dist/web/assets/{gdresource-DxuG5i8i.js → gdresource-BcIEE2eX.js} +1 -1
- package/dist/web/assets/{git-commit-3lMonsur.js → git-commit-BVjlXEy8.js} +1 -1
- package/dist/web/assets/{git-log-panel-Co0PBPHC.js → git-log-panel-2_4HuP47.js} +1 -1
- package/dist/web/assets/{git-rebase-N8Z9kIMf.js → git-rebase-Bj_21B1V.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-B72vcb2r.js +1 -0
- package/dist/web/assets/glide-data-grid-B0IY6n_Q.js +138 -0
- package/dist/web/assets/{glimmer-js-Dp9OXiib.js → glimmer-js-C20yj4Zv.js} +1 -1
- package/dist/web/assets/{glimmer-ts-CDVKBcDj.js → glimmer-ts-ipbYC7kh.js} +1 -1
- package/dist/web/assets/{glsl-DPJxI4us.js → glsl-Dovazu3t.js} +1 -1
- package/dist/web/assets/{graphql-BrFhaQQl.js → graphql-DpMlM7hC.js} +1 -1
- package/dist/web/assets/{group-chat-tab-rOd8J8GC.js → group-chat-tab-DRLDHOp6.js} +1 -1
- package/dist/web/assets/{hack-BzXbDMlA.js → hack-gc7LCBuV.js} +1 -1
- package/dist/web/assets/{haml-CPpkX0s5.js → haml-vtlFm9gm.js} +1 -1
- package/dist/web/assets/{handlebars-BqrApy52.js → handlebars-DGKhpCji.js} +1 -1
- package/dist/web/assets/{html-DmjUl-OA.js → html-DvfhQbXb.js} +1 -1
- package/dist/web/assets/{html-derivative-Cnd6XFR5.js → html-derivative-C3oTSSCN.js} +1 -1
- package/dist/web/assets/{http-DMLWYun2.js → http-SG6zLTo7.js} +1 -1
- package/dist/web/assets/{hurl-CKkCVxbj.js → hurl-BWXsYlqW.js} +1 -1
- package/dist/web/assets/{hxml-CAx19TtQ.js → hxml-DUdMzaoh.js} +1 -1
- package/dist/web/assets/{image-preview-DHUoylQ1.js → image-preview-DxgFOV1T.js} +1 -1
- package/dist/web/assets/index-CBn4SOoT.js +52 -0
- package/dist/web/assets/index-DWpNR3nB.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-3irPxRK_.js +1 -0
- package/dist/web/assets/{input-DcEk7mA3.js → input-DuAF-Stj.js} +1 -1
- package/dist/web/assets/{jinja-BmB9YN9l.js → jinja-955w9RKM.js} +1 -1
- package/dist/web/assets/{jison-BaVsKKpw.js → jison-WWfqPo50.js} +1 -1
- package/dist/web/assets/{julia-BgVBLveX.js → julia-BFrfnaNl.js} +1 -1
- package/dist/web/assets/{just-C2ENIbl9.js → just-BrZdyR_I.js} +1 -1
- package/dist/web/assets/{keybindings-store-BGIyqXHI.js → keybindings-store-0Wqfa7Qp.js} +1 -1
- package/dist/web/assets/keybindings-store-d54pv2NK.js +1 -0
- package/dist/web/assets/{latex-BiDIWxKL.js → latex-CwtPPASD.js} +1 -1
- package/dist/web/assets/{liquid-NxpapreE.js → liquid-CYZuvDDd.js} +1 -1
- package/dist/web/assets/{lua-DVepQvwH.js → lua-BV095ZyY.js} +1 -1
- package/dist/web/assets/markdown-renderer-BTS8ifdu.js +1 -0
- package/dist/web/assets/{markdown-renderer-DlcDhgrF.js → markdown-renderer-CnRcKK3d.js} +3 -3
- package/dist/web/assets/{marko-CJ2606Xl.js → marko-CNeljZ1C.js} +1 -1
- package/dist/web/assets/{mdc-D2bjqclE.js → mdc-JfGapShy.js} +1 -1
- package/dist/web/assets/{media-url-H17XJF-I.js → media-url-Bm4PsduE.js} +1 -1
- package/dist/web/assets/{mobile-bottom-sheet-g-r2hCFa.js → mobile-bottom-sheet-M5iZDX7y.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-BqK2-WuN.js +1 -0
- package/dist/web/assets/{nextflow-BtJwUbfF.js → nextflow-DD5C8nqX.js} +1 -1
- package/dist/web/assets/{nginx-j4gyIhHE.js → nginx-Ca7B__x_.js} +1 -1
- package/dist/web/assets/{nim-ClH_gjP5.js → nim-B8FogsDw.js} +1 -1
- package/dist/web/assets/notification-store-Yvy1I8gd.js +1 -0
- package/dist/web/assets/{number-overlay-editor-C1EqJnWq.js → number-overlay-editor-DG9xJwEG.js} +1 -1
- package/dist/web/assets/{overview-panel-vTeeJYVZ.js → overview-panel-s53bnl0q.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-Z5jWjFCV.js +1 -0
- package/dist/web/assets/{panel-store-BSnkjgHt.js → panel-store-B4rijFKN.js} +1 -1
- package/dist/web/assets/{pdf-preview-CqFGRY0Z.js → pdf-preview-DYt3aBzM.js} +1 -1
- package/dist/web/assets/{perl-C9H7X7CT.js → perl-BR78hS8R.js} +1 -1
- package/dist/web/assets/{php-Bx2U-cQ_.js → php-DXBOMC9z.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-Bq7UMi8P.js +1 -0
- package/dist/web/assets/{postgres-viewer-DHwcQucn.js → postgres-viewer-BvoWSuoZ.js} +3 -3
- package/dist/web/assets/{process-table-BGRJNlpn.js → process-table-BYwKigiD.js} +1 -1
- package/dist/web/assets/{project-store--nvQiy75.js → project-store-BuY7rxn_.js} +1 -1
- package/dist/web/assets/{pug-Cw74sKsE.js → pug-CvTwVVKV.js} +1 -1
- package/dist/web/assets/{qml-BXD94Eqz.js → qml-CPSoZ1-B.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-BLo4BOTD.js +1 -0
- package/dist/web/assets/{razor-DZ0-Ge0S.js → razor-BUA1YKtF.js} +1 -1
- package/dist/web/assets/{rst-Dtdh0QUj.js → rst-BJsq7ISz.js} +1 -1
- package/dist/web/assets/{ruby-BC51BW2Q.js → ruby-DSDMeYf5.js} +1 -1
- package/dist/web/assets/{run-in-terminal-Sd3KyjN4.js → run-in-terminal-C9xpskFn.js} +1 -1
- package/dist/web/assets/{sas-BN8i4qOU.js → sas-B1nJOjbN.js} +1 -1
- package/dist/web/assets/{scroll-area-0gljZ6lF.js → scroll-area-DBcG1fQo.js} +1 -1
- package/dist/web/assets/{scss-H-QtA7Rz.js → scss-BZFyRiQn.js} +1 -1
- package/dist/web/assets/{send-to-chat-u6m8l-rH.js → send-to-chat-BIg70MUZ.js} +1 -1
- package/dist/web/assets/{settings-store-CHY6Kzin.js → settings-store-GV5pkkke.js} +2 -2
- package/dist/web/assets/{settings-tab-IY6K1MiZ.js → settings-tab-BePvIcjd.js} +1 -1
- package/dist/web/assets/settings-tab-Br-lJSPa.js +1 -0
- package/dist/web/assets/{shaderlab-CalNsj_x.js → shaderlab-laINRXBo.js} +1 -1
- package/dist/web/assets/{shellsession-BFrcoR8x.js → shellsession-BpOOvWVR.js} +1 -1
- package/dist/web/assets/{soy-CNbku7vP.js → soy-BW4d91Sa.js} +1 -1
- package/dist/web/assets/{sparql-BN_orcVp.js → sparql-BsvvyoHn.js} +1 -1
- package/dist/web/assets/{sql-query-editor-C6pC3I8l.js → sql-query-editor-qQce5QJ6.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-DTr5PzUb.js → sqlite-viewer-yhc0YNvu.js} +1 -1
- package/dist/web/assets/{stata-C6a5Ijzq.js → stata-K-dZInUt.js} +1 -1
- package/dist/web/assets/{surrealql-ClplI_HY.js → surrealql-CpNp2sgf.js} +1 -1
- package/dist/web/assets/{svelte-DNm-UNXB.js → svelte-BG6iBA8R.js} +1 -1
- package/dist/web/assets/{switch-DKvKya9y.js → switch-_NcrktLe.js} +1 -1
- package/dist/web/assets/system-monitor-body-D8Z5QXBB.js +2 -0
- package/dist/web/assets/system-monitor-tab-BclYXFTe.js +1 -0
- package/dist/web/assets/{system-monitor-window-content-BUqRsPK2.js → system-monitor-window-content-CaOhD0AU.js} +1 -1
- package/dist/web/assets/{tab-host-window-content-BnqGPu8a.js → tab-host-window-content-f_Rc5rJK.js} +1 -1
- package/dist/web/assets/{tab-store-CJuJRapl.js → tab-store-tFnyPmm4.js} +1 -1
- package/dist/web/assets/team-member-sheet-QDHoYCs0.js +2 -0
- package/dist/web/assets/{team-member-window-content-T4Q5JI-G.js → team-member-window-content-B1jkKkDi.js} +1 -1
- package/dist/web/assets/{templ-CSdqVobu.js → templ-gxNKXmt3.js} +1 -1
- package/dist/web/assets/{terminal-tab-Bb2rZegQ.js → terminal-tab-UvwM0sty.js} +3 -3
- package/dist/web/assets/{tex-DzSJ4kcZ.js → tex-C0ON27g5.js} +1 -1
- package/dist/web/assets/{tool-cards-lhqhrDTT.js → tool-cards-jB7GT-wj.js} +4 -4
- package/dist/web/assets/treemap-KZPCXAKY-dyrE6SW2.js +1 -0
- package/dist/web/assets/{ts-tags-C28w3bTg.js → ts-tags-BX_CTVgQ.js} +1 -1
- package/dist/web/assets/{twig-i5jY3QXB.js → twig-CwL7XnU0.js} +1 -1
- package/dist/web/assets/{use-blob-url-Dsq9OjTh.js → use-blob-url-DcRcjNTE.js} +1 -1
- package/dist/web/assets/use-coarse-long-press-BmI_GVW5.js +1 -0
- package/dist/web/assets/{use-monaco-theme-BZvlsoBv.js → use-monaco-theme--9tOOkDA.js} +1 -1
- package/dist/web/assets/{use-open-team-member-DkiEjFYE.js → use-open-team-member-1hRsHLKg.js} +1 -1
- package/dist/web/assets/{use-websocket-B8R50f7f.js → use-websocket-rxJLbFqy.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-By4AVvJY.js → vendor-mermaid-CHTa6D69.js} +1 -1
- package/dist/web/assets/video-preview-DMhnf2Gi.js +1 -0
- package/dist/web/assets/{vue-Ceyet_lv.js → vue-Bykm6wSS.js} +1 -1
- package/dist/web/assets/{vue-html-GuU7g_hg.js → vue-html-CETdK_iV.js} +1 -1
- package/dist/web/assets/{vue-vine-CxXoaJr2.js → vue-vine-DiJb6fO5.js} +1 -1
- package/dist/web/assets/{window-store-CsEW6jiE.js → window-store-CQ1lghvv.js} +1 -1
- package/dist/web/assets/{xml-CbqOVhkP.js → xml-BNw8J5YW.js} +1 -1
- package/dist/web/assets/{xsl-KfAmCauy.js → xsl-CsG9L31b.js} +1 -1
- package/dist/web/index.html +46 -45
- package/dist/web/sw.js +1 -1
- package/docs/architecture/ai-chat-and-providers.md +309 -0
- package/docs/architecture/data-and-storage.md +356 -0
- package/docs/architecture/extensions.md +496 -0
- package/docs/architecture/integrations.md +214 -0
- package/docs/architecture/workspace-and-ui.md +391 -0
- package/docs/claude-agent-sdk-reference.md +1 -1
- package/docs/code-patterns.md +361 -0
- package/docs/code-standards.md +8 -358
- package/docs/codebase-subsystems.md +364 -0
- package/docs/codebase-summary.md +34 -379
- package/docs/deployment-guide.md +280 -490
- package/docs/design-guidelines.md +1 -1
- package/docs/lessons-learned.md +27 -10
- package/docs/project-changelog.md +18 -806
- package/docs/project-overview-pdr.md +117 -111
- package/docs/project-roadmap.md +89 -133
- package/docs/system-architecture.md +77 -1826
- package/package.json +2 -2
- package/src/cli/commands/autostart.ts +2 -2
- package/src/cli/commands/config-cmd.ts +12 -3
- package/src/cli/commands/status.ts +3 -2
- package/src/cli/commands/stop.ts +32 -4
- package/src/server/index.ts +17 -3
- package/src/server/routes/chat-unread.ts +36 -0
- package/src/server/routes/named-tunnel.ts +132 -0
- package/src/server/routes/tunnel.ts +13 -0
- package/src/server/ws/chat.ts +5 -2
- package/src/services/autostart-register.ts +47 -29
- package/src/services/cloud.service.ts +26 -1
- package/src/services/config-secret-keys.ts +48 -0
- package/src/services/config.service.ts +1 -1
- package/src/services/db.service.ts +62 -12
- package/src/services/extension-rpc-handlers.ts +9 -1
- package/src/services/file-watcher/watch-tree.ts +67 -33
- package/src/services/file-watcher.service.ts +28 -10
- package/src/services/fs-credential-path-guard.ts +103 -0
- package/src/services/fs-path-guard.service.ts +14 -66
- package/src/services/named-tunnel/cloudflare-dns-api.ts +40 -0
- package/src/services/named-tunnel/cloudflare-zone-api.ts +28 -0
- package/src/services/named-tunnel/cloudflared-cert.ts +95 -0
- package/src/services/named-tunnel/cloudflared-exec.ts +50 -0
- package/src/services/named-tunnel/cloudflared-login-helpers.ts +98 -0
- package/src/services/named-tunnel/cloudflared-login.service.ts +182 -0
- package/src/services/named-tunnel/hostname-rules.ts +58 -0
- package/src/services/named-tunnel/login-output-parser.ts +36 -0
- package/src/services/named-tunnel/named-tunnel-args.ts +110 -0
- package/src/services/named-tunnel/named-tunnel-config.ts +67 -0
- package/src/services/named-tunnel/named-tunnel-probe-state.ts +95 -0
- package/src/services/named-tunnel/named-tunnel-readiness.ts +59 -0
- package/src/services/named-tunnel/named-tunnel-runtime.ts +42 -0
- package/src/services/named-tunnel/named-tunnel-setup-confirm.ts +98 -0
- package/src/services/named-tunnel/named-tunnel-setup.service.ts +191 -0
- package/src/services/supervisor-state.ts +67 -2
- package/src/services/supervisor.ts +454 -157
- package/src/services/tunnel-registry-parse.ts +27 -0
- package/src/services/tunnel-registry.service.ts +2 -15
- package/src/services/tunnel.service.ts +12 -3
- package/src/types/config.ts +31 -0
- package/src/web/app.tsx +5 -0
- package/src/web/components/chat/chat-history-bar.tsx +95 -98
- package/src/web/components/chat/chat-toolbar-overflow-menu.tsx +57 -0
- package/src/web/components/chat/session-debug-dialog.tsx +35 -27
- package/src/web/components/layout/cloud-share-named-tunnel-row.tsx +111 -0
- package/src/web/components/layout/cloud-share-popover.tsx +56 -14
- package/src/web/components/shared/connection-lost-overlay.tsx +44 -5
- package/src/web/components/tunnels/named-tunnel/hostname-validation.ts +14 -0
- package/src/web/components/tunnels/named-tunnel/named-tunnel-copy.ts +96 -0
- package/src/web/components/tunnels/named-tunnel/named-tunnel-hostname-field.tsx +51 -0
- package/src/web/components/tunnels/named-tunnel/named-tunnel-login-step.tsx +105 -0
- package/src/web/components/tunnels/named-tunnel/named-tunnel-section.tsx +159 -0
- package/src/web/components/tunnels/named-tunnel/named-tunnel-setup-content.tsx +197 -0
- package/src/web/components/tunnels/named-tunnel/named-tunnel-setup-popup.tsx +57 -0
- package/src/web/components/tunnels/named-tunnel/named-tunnel-step-reducer.ts +191 -0
- package/src/web/components/tunnels/named-tunnel/use-named-tunnel-setup.ts +212 -0
- package/src/web/components/tunnels/tunnel-manager-tab.tsx +4 -0
- package/src/web/hooks/use-global-events.ts +3 -1
- package/src/web/lib/api-named-tunnel.ts +54 -0
- package/src/web/lib/last-known-local-url.ts +23 -0
- package/src/web/stores/notification-store.ts +20 -1
- package/.spike/cdp-client.ts +0 -116
- package/.spike/cleanup-ppm-workspace.mjs +0 -44
- package/.spike/group-protected-probe.ts +0 -21
- package/.spike/pip-eval.ts +0 -17
- package/.spike/pip-page-helpers.js +0 -119
- package/.spike/pip-results-editor-glue.json +0 -105
- package/.spike/pip-results-editor.json +0 -158
- package/.spike/pip-results-input-isolation.json +0 -28
- package/.spike/pip-results-key-probe.json +0 -58
- package/.spike/pip-results-listener-survival.json +0 -98
- package/.spike/pip-results-listeners.json +0 -36
- package/.spike/pip-results-pagehide.json +0 -92
- package/.spike/pip-results-resize.json +0 -104
- package/.spike/pip-results-terminal-debug.json +0 -99
- package/.spike/pip-results-terminal-v2.json +0 -191
- package/.spike/pip-results-terminal.json +0 -220
- package/.spike/pip-results-xterm-trace.json +0 -73
- package/.spike/pip-spike-common.ts +0 -83
- package/.spike/pip-spike-editor-glue.ts +0 -82
- package/.spike/pip-spike-editor.ts +0 -129
- package/.spike/pip-spike-input-isolation.ts +0 -38
- package/.spike/pip-spike-key-probe.ts +0 -34
- package/.spike/pip-spike-listener-survival.ts +0 -54
- package/.spike/pip-spike-listeners.ts +0 -19
- package/.spike/pip-spike-pagehide.ts +0 -59
- package/.spike/pip-spike-resize.ts +0 -42
- package/.spike/pip-spike-setup.ts +0 -63
- package/.spike/pip-spike-terminal-debug.ts +0 -81
- package/.spike/pip-spike-terminal-v2.ts +0 -139
- package/.spike/pip-spike-terminal.ts +0 -169
- package/.spike/pip-spike-xterm-trace.ts +0 -36
- package/.spike/probe-drag-memo-error.mjs +0 -67
- package/.spike/read-dev-db.ts +0 -15
- package/.spike/s.err +0 -63
- package/.spike/scratch-editor-target.ts +0 -7
- package/.spike/smoke-unified-chrome-pip.mjs +0 -353
- package/.spike/tunnel.err +0 -63
- package/.spike/vite-restart.err +0 -663
- package/.spike/w.err +0 -571
- package/dist/web/assets/api-client-DTZEgjBQ.js +0 -1
- package/dist/web/assets/api-settings-kd1j4iR8.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-8dCMT9r7.js +0 -1
- package/dist/web/assets/chat-tab-E3bf_V8X.js +0 -15
- package/dist/web/assets/code-editor-BUlM2gXk.js +0 -10
- package/dist/web/assets/explorer-body-9aBmyVpZ.js +0 -2
- package/dist/web/assets/explorer-window-content-DRtqoSPA.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-2e_8dfbs.js +0 -1
- package/dist/web/assets/glide-data-grid-C4_zIneN.js +0 -138
- package/dist/web/assets/index-BImUaigO.js +0 -52
- package/dist/web/assets/index-CSfi6DSU.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-BZi1Gha1.js +0 -1
- package/dist/web/assets/keybindings-store-CzV2sPls.js +0 -1
- package/dist/web/assets/markdown-renderer-CcbR33VG.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-SIwQXlwA.js +0 -1
- package/dist/web/assets/notification-store-DV5QtUTg.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-o5htEcin.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-BXAIFSAD.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-Dbt2Aebl.js +0 -1
- package/dist/web/assets/settings-tab-Dic6TKkU.js +0 -1
- package/dist/web/assets/system-monitor-body-iwGiCns9.js +0 -2
- package/dist/web/assets/system-monitor-tab-DdXQhEel.js +0 -1
- package/dist/web/assets/team-member-sheet-LkAFSCvb.js +0 -2
- package/dist/web/assets/treemap-KZPCXAKY-DUbnl9dz.js +0 -1
- package/dist/web/assets/video-preview-m0-3p7QZ.js +0 -1
- /package/dist/web/assets/{abap-C6nB04tn.js → abap-DGlrX_8G.js} +0 -0
- /package/dist/web/assets/{actionscript-3-Vx4rw2sC.js → actionscript-3-CUqRtUJE.js} +0 -0
- /package/dist/web/assets/{ada-Ccd8vM20.js → ada-CY3Spa33.js} +0 -0
- /package/dist/web/assets/{andromeeda-DnBX5xMg.js → andromeeda-Lxs2TJn7.js} +0 -0
- /package/dist/web/assets/{apache-B-9_sx0g.js → apache-DfxgGdgM.js} +0 -0
- /package/dist/web/assets/{apex-_wPVBYoL.js → apex-QVDF1dnI.js} +0 -0
- /package/dist/web/assets/{api-client-aQb5hHE5.js → api-client-oY1tC3tM.js} +0 -0
- /package/dist/web/assets/{applescript-CcvD-qr0.js → applescript-pwJ8QXh-.js} +0 -0
- /package/dist/web/assets/{apply-theme-BeLRfsSu.js → apply-theme-B_bMVL6a.js} +0 -0
- /package/dist/web/assets/{ara-C40Ztoms.js → ara-mPjeX5YX.js} +0 -0
- /package/dist/web/assets/{asciidoc-CybYkJV4.js → asciidoc-Bf7LsDkI.js} +0 -0
- /package/dist/web/assets/{asm-9eOKwzR0.js → asm-rRKC1OUx.js} +0 -0
- /package/dist/web/assets/{aurora-x-B5ZH4t7t.js → aurora-x-DwQr0DkG.js} +0 -0
- /package/dist/web/assets/{awk-Dqilob-2.js → awk-Bpt768fN.js} +0 -0
- /package/dist/web/assets/{ayu-dark-CPgRhf5r.js → ayu-dark-D9lwQHMs.js} +0 -0
- /package/dist/web/assets/{ayu-light-Do06Q52f.js → ayu-light-B4-ptrU5.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-_BhxcrxY.js → ayu-mirage-DAyRzH5Q.js} +0 -0
- /package/dist/web/assets/{ballerina-DDwK54QW.js → ballerina-Cgdpj1HC.js} +0 -0
- /package/dist/web/assets/{bat-BGyGlzGk.js → bat-4FrN36S2.js} +0 -0
- /package/dist/web/assets/{beancount-CRWBdapI.js → beancount-DkcxQER3.js} +0 -0
- /package/dist/web/assets/{berry-DbSFn2gO.js → berry-Dnuut-Ml.js} +0 -0
- /package/dist/web/assets/{bibtex-QpsV9gm9.js → bibtex-CCDwmbuA.js} +0 -0
- /package/dist/web/assets/{bicep-CxS8CUve.js → bicep-BC0ryoGM.js} +0 -0
- /package/dist/web/assets/{bird2-CuZhQzYR.js → bird2-C50V_A-0.js} +0 -0
- /package/dist/web/assets/{c-9bnDqE3g.js → c-Ddorhq0U.js} +0 -0
- /package/dist/web/assets/{c3-JMZTrOhA.js → c3-DdIf5r9E.js} +0 -0
- /package/dist/web/assets/{cadence-DsDNayJS.js → cadence-s9pd1Wng.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-BJfpynya.js → can-open-in-ppm-C6hZV1OP.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-DYIKXXBe.js → catppuccin-frappe-CzJNTyu-.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-IYYOnUJ8.js → catppuccin-latte-BNpt-m7s.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-BrJ_7mfS.js → catppuccin-macchiato-FYGkfsJ5.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-gzSu7v7-.js → catppuccin-mocha-it2g5D1q.js} +0 -0
- /package/dist/web/assets/{clarity-DLzsC0Hb.js → clarity-BVFBTjMe.js} +0 -0
- /package/dist/web/assets/{clipboard-7fw0Shic.js → clipboard-BWznymz7.js} +0 -0
- /package/dist/web/assets/{clojure-DS1BvoTt.js → clojure-BSYvXMI8.js} +0 -0
- /package/dist/web/assets/{cmake-CDvsJwYp.js → cmake-DGEqH-Np.js} +0 -0
- /package/dist/web/assets/{codeowners-BjsYiflJ.js → codeowners-D8FCOxWg.js} +0 -0
- /package/dist/web/assets/{codeql-CG-7ARat.js → codeql-COV0eluG.js} +0 -0
- /package/dist/web/assets/{common-lisp-DSO1Lbh9.js → common-lisp-xHnZUlgt.js} +0 -0
- /package/dist/web/assets/{coq-DYdh3oP_.js → coq-Cs_2i3Xg.js} +0 -0
- /package/dist/web/assets/{csharp-DxEBz5s0.js → csharp-B1ONB4PT.js} +0 -0
- /package/dist/web/assets/{css-dal3Q-8C.js → css-BgGQbvrZ.js} +0 -0
- /package/dist/web/assets/{csv-CpqjMGiA.js → csv-CNHmQBzs.js} +0 -0
- /package/dist/web/assets/{csv-parser-3umBA4NY.js → csv-parser-DWR24J17.js} +0 -0
- /package/dist/web/assets/{cue-DinoJ_5k.js → cue-ZXAKzwIy.js} +0 -0
- /package/dist/web/assets/{cypher-DzxqmkUW.js → cypher-4PL5bmT5.js} +0 -0
- /package/dist/web/assets/{d-BxNwJuEC.js → d-CEsV3RT2.js} +0 -0
- /package/dist/web/assets/{dark-plus-Clmv3V-0.js → dark-plus-NtFnYSDz.js} +0 -0
- /package/dist/web/assets/{dart-BWVtXD35.js → dart-CKHn4mDf.js} +0 -0
- /package/dist/web/assets/{data-grid-types-B4n51Fck.js → data-grid-types-CxU8oo-j.js} +0 -0
- /package/dist/web/assets/{dax-DsImuWgJ.js → dax-Cmkj1I_M.js} +0 -0
- /package/dist/web/assets/{desktop-B0jJuG2r.js → desktop-DJLalvPQ.js} +0 -0
- /package/dist/web/assets/{diff-CWqAAxoE.js → diff-BnS2wpj6.js} +0 -0
- /package/dist/web/assets/{dist-C0eNNfbt.js → dist-CuIdRyUB.js} +0 -0
- /package/dist/web/assets/{dist-B-EXdSYE.js → dist-uYjs3Wv6.js} +0 -0
- /package/dist/web/assets/{docker-CYFCJdIL.js → docker-CovNy7ml.js} +0 -0
- /package/dist/web/assets/{dotenv-CKDUjURg.js → dotenv-Gh4w3I6B.js} +0 -0
- /package/dist/web/assets/{dracula-CSoPspHE.js → dracula-NF0tAHXl.js} +0 -0
- /package/dist/web/assets/{dracula-soft-BuFjw5L1.js → dracula-soft-Cj_qBurK.js} +0 -0
- /package/dist/web/assets/{dream-maker-B6PdDRZu.js → dream-maker-CRuZPcl7.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-CMcXvD0G.js → emacs-lisp-BACmC9qj.js} +0 -0
- /package/dist/web/assets/{everforest-dark-cU8-wYzi.js → everforest-dark-Dd9av4QG.js} +0 -0
- /package/dist/web/assets/{everforest-light-KhorllqK.js → everforest-light-C-jsss-B.js} +0 -0
- /package/dist/web/assets/{external-link-B8BynhvY.js → external-link-B6Hl0U4X.js} +0 -0
- /package/dist/web/assets/{fennel-BCELZK87.js → fennel-BJA9XnL8.js} +0 -0
- /package/dist/web/assets/{file-exclamation-point-CZ4DiR75.js → file-exclamation-point-JzhTU2TX.js} +0 -0
- /package/dist/web/assets/{fish-BQc0y_jy.js → fish-CKlhNSc2.js} +0 -0
- /package/dist/web/assets/{fluent-BTINnwF6.js → fluent-wfglRk5D.js} +0 -0
- /package/dist/web/assets/{folder-symlink-B8XrtvQK.js → folder-symlink-Dx1hOk8X.js} +0 -0
- /package/dist/web/assets/{format-bytes-WVcFxJuT.js → format-bytes-utwHMTry.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-BQim9wDz.js → fortran-free-form-BlXCdid3.js} +0 -0
- /package/dist/web/assets/{gdscript-03w5u8un.js → gdscript-BwAVG6Et.js} +0 -0
- /package/dist/web/assets/{gdshader-Dp2daNzU.js → gdshader-DPc_T7ib.js} +0 -0
- /package/dist/web/assets/{genie-CoNcjPiD.js → genie-B-zZSLCX.js} +0 -0
- /package/dist/web/assets/{gherkin-NrPOSPQL.js → gherkin-CJ0ajpGs.js} +0 -0
- /package/dist/web/assets/{github-dark-z4RE9ZqA.js → github-dark-Dz8ZkzSP.js} +0 -0
- /package/dist/web/assets/{github-dark-default-DOKw-1cI.js → github-dark-default-CNUYo_kp.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-DJRNMkEA.js → github-dark-dimmed-241z_Ycx.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-Bj7jJ_Gs.js → github-dark-high-contrast-7r6yZZYH.js} +0 -0
- /package/dist/web/assets/{github-light-B4k_yMFu.js → github-light-C8gmZn-D.js} +0 -0
- /package/dist/web/assets/{github-light-default-BHc-Uzhs.js → github-light-default-GAEgq1eA.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-CHisIywL.js → github-light-high-contrast-3z91352E.js} +0 -0
- /package/dist/web/assets/{gleam-CfbypZ4q.js → gleam-C7vxW5zd.js} +0 -0
- /package/dist/web/assets/{gn-YoAjyhJa.js → gn-CyJIXwHP.js} +0 -0
- /package/dist/web/assets/{gnuplot-xVkc1f1c.js → gnuplot-CqLbGgPd.js} +0 -0
- /package/dist/web/assets/{go-GPCwP3Gu.js → go-DdDcK9aX.js} +0 -0
- /package/dist/web/assets/{groovy-Crh4Yww9.js → groovy-UYHggEqH.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-BluUFuDS.js → gruvbox-dark-hard-B4ierkJn.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-Cxk1FWQp.js → gruvbox-dark-medium-DYwkDSZ6.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-CHXMiFmj.js → gruvbox-dark-soft-CVL4P-Lz.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-B6eKPjAD.js → gruvbox-light-hard-BJ0LewUZ.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-pDwMm1ut.js → gruvbox-light-medium-CaqqjeGJ.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-Cxu6kHqK.js → gruvbox-light-soft-ByKMoVNr.js} +0 -0
- /package/dist/web/assets/{haskell-C6JKHjbK.js → haskell-BilYRVPp.js} +0 -0
- /package/dist/web/assets/{haxe-BuBNdF0a.js → haxe-Brs9Bj1s.js} +0 -0
- /package/dist/web/assets/{hcl-DZpDdGj2.js → hcl-ClrZpol-.js} +0 -0
- /package/dist/web/assets/{hjson-CBkhYRuo.js → hjson-9PvHnYMX.js} +0 -0
- /package/dist/web/assets/{hlsl-C5nMxnp9.js → hlsl-BbBk4vqV.js} +0 -0
- /package/dist/web/assets/{horizon-VAFvA6R6.js → horizon-E5Py0cny.js} +0 -0
- /package/dist/web/assets/{horizon-bright-BC0xn7T3.js → horizon-bright-DVCsNGEk.js} +0 -0
- /package/dist/web/assets/{houston-BxrUivmz.js → houston-JdFEax9Y.js} +0 -0
- /package/dist/web/assets/{hy-DLtOXoaH.js → hy-W_W3tLKT.js} +0 -0
- /package/dist/web/assets/{image-gallery-Gnf7TdCR.js → image-gallery-5IURd6db.js} +0 -0
- /package/dist/web/assets/{imba-BdpFXM2W.js → imba-CfAqJz7T.js} +0 -0
- /package/dist/web/assets/{ini-BInJO_T0.js → ini-C_3gvKWs.js} +0 -0
- /package/dist/web/assets/{java-Dxuddnkb.js → java-CKqtXZ-j.js} +0 -0
- /package/dist/web/assets/{javascript-CVamJfLY.js → javascript-C7gSEfae.js} +0 -0
- /package/dist/web/assets/{json-BLZ0ozYk.js → json-BoN6e11T.js} +0 -0
- /package/dist/web/assets/{json5-BnXzmMKs.js → json5-CgE7C8HW.js} +0 -0
- /package/dist/web/assets/{jsonc-CSgkSga7.js → jsonc-DjyoattY.js} +0 -0
- /package/dist/web/assets/{jsonl-CY5W2nF2.js → jsonl-lI82wGSw.js} +0 -0
- /package/dist/web/assets/{jsonnet-CEJYH3sF.js → jsonnet-CszEI8va.js} +0 -0
- /package/dist/web/assets/{jssm-CsJc7Uhk.js → jssm-CZXDlszb.js} +0 -0
- /package/dist/web/assets/{jsx-jCiRaHU7.js → jsx-BeRz0eEz.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-DfoA_GxX.js → kanagawa-dragon-BOmnUiyd.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-BOLYJpWd.js → kanagawa-lotus-ffU_P5w-.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-DfKlbT1G.js → kanagawa-wave-DKTJZrMu.js} +0 -0
- /package/dist/web/assets/{kdl-CmssIFTi.js → kdl-BWECJveH.js} +0 -0
- /package/dist/web/assets/{kotlin-BRsNgp6x.js → kotlin-DpVwBCSt.js} +0 -0
- /package/dist/web/assets/{kusto-T8X9jUab.js → kusto-BgVqjUZA.js} +0 -0
- /package/dist/web/assets/{laserwave-DkJMVJ8Z.js → laserwave-CEVCi8em.js} +0 -0
- /package/dist/web/assets/{lean-C65KGVPq.js → lean-CGyfRhLJ.js} +0 -0
- /package/dist/web/assets/{less-exIPdDlf.js → less-B0_H10Ku.js} +0 -0
- /package/dist/web/assets/{lib-mC1NZfuw.js → lib-hrC3bruJ.js} +0 -0
- /package/dist/web/assets/{libesm-DSutUtl1.js → libesm-DVpFmwJu.js} +0 -0
- /package/dist/web/assets/{light-plus-DiHUXAZt.js → light-plus-DqzMqPID.js} +0 -0
- /package/dist/web/assets/{llvm-CJBnEzFM.js → llvm-9ucnfNiF.js} +0 -0
- /package/dist/web/assets/{loader-circle-gSPVxfvH.js → loader-circle-Dpqcv0eS.js} +0 -0
- /package/dist/web/assets/{lock-Did-87UV.js → lock-DldbT31x.js} +0 -0
- /package/dist/web/assets/{log-DxMyUMuP.js → log-m6A2dOSj.js} +0 -0
- /package/dist/web/assets/{logo-CC9NKzca.js → logo-ByPcsC9P.js} +0 -0
- /package/dist/web/assets/{luau-Bw10I6zf.js → luau-DFCo8nBn.js} +0 -0
- /package/dist/web/assets/{make-C_6M90m6.js → make-C90w3MeA.js} +0 -0
- /package/dist/web/assets/{markdown-bR9_R-LF.js → markdown-DT0uywZG.js} +0 -0
- /package/dist/web/assets/{material-theme-BUx2Qujn.js → material-theme-BVUO93tJ.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-CRJrPgKm.js → material-theme-darker-xXgGDwnF.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-CUAYppPa.js → material-theme-lighter-BjStPzWB.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-DuINF1fg.js → material-theme-ocean-wFmSiKjy.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-W6_icGCj.js → material-theme-palenight-e-0CtRoe.js} +0 -0
- /package/dist/web/assets/{matlab-rfqn_b3z.js → matlab-BNaNQAUH.js} +0 -0
- /package/dist/web/assets/{mdx-Bh1B_YOJ.js → mdx-DfpVWAqO.js} +0 -0
- /package/dist/web/assets/{mermaid-Dxf6Ya2k.js → mermaid-Bpq7wFCP.js} +0 -0
- /package/dist/web/assets/{min-dark-CivZ2L0h.js → min-dark-CL2Y0WH6.js} +0 -0
- /package/dist/web/assets/{min-light-B1Ykqtma.js → min-light-DOgr_IdP.js} +0 -0
- /package/dist/web/assets/{mipsasm-DynHaM0d.js → mipsasm-C9ie2zlB.js} +0 -0
- /package/dist/web/assets/{mojo-Clw5PbGH.js → mojo-Md2A2sJy.js} +0 -0
- /package/dist/web/assets/{monitor-Dv8vn_6O.js → monitor-4vWfqzuN.js} +0 -0
- /package/dist/web/assets/{monokai-DFIooFZT.js → monokai-nbXIEySB.js} +0 -0
- /package/dist/web/assets/{moonbit-DnBSZWGM.js → moonbit-CJ-T-s4A.js} +0 -0
- /package/dist/web/assets/{move-CCcL2PfL.js → move-DwEehLIK.js} +0 -0
- /package/dist/web/assets/{narrat-BDarg5Lk.js → narrat-CuF4sIKr.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-DrZOeCNW.js → nextflow-groovy-1dYhfPfq.js} +0 -0
- /package/dist/web/assets/{night-owl-BnZZCK7v.js → night-owl-gZS5mfzY.js} +0 -0
- /package/dist/web/assets/{night-owl-light-CEwBsVHS.js → night-owl-light-DDAster5.js} +0 -0
- /package/dist/web/assets/{nix-amCzOPMR.js → nix-BlbEYs2c.js} +0 -0
- /package/dist/web/assets/{nord-BIs2BC6q.js → nord-BRiPb8Vy.js} +0 -0
- /package/dist/web/assets/{nushell-Y02fo4yw.js → nushell-DgWicB1i.js} +0 -0
- /package/dist/web/assets/{objective-c-7xOZtWW1.js → objective-c-D8mPZ42Y.js} +0 -0
- /package/dist/web/assets/{objective-cpp-eVtjUvVB.js → objective-cpp-B0pNXzuj.js} +0 -0
- /package/dist/web/assets/{ocaml-Bi6ZwqG4.js → ocaml-lQd7aK5d.js} +0 -0
- /package/dist/web/assets/{odin-8xf1Y0S9.js → odin-CxtIOBjm.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-hVv-_y_b.js → one-dark-pro-T_UFnWfe.js} +0 -0
- /package/dist/web/assets/{one-light-CJJ3MtHt.js → one-light-LBVqwyV-.js} +0 -0
- /package/dist/web/assets/{openscad-B2HcywLk.js → openscad-C5dnS6J7.js} +0 -0
- /package/dist/web/assets/{pascal-C7fllV_7.js → pascal-CmWCWQML.js} +0 -0
- /package/dist/web/assets/{pkl-qvLC1IWP.js → pkl-BWWOtDQk.js} +0 -0
- /package/dist/web/assets/{plastic-BT1wHZv2.js → plastic-ekhupckF.js} +0 -0
- /package/dist/web/assets/{play-4MZi1Axp.js → play-CpCAoQRZ.js} +0 -0
- /package/dist/web/assets/{plsql-1MsmdmJD.js → plsql-BPsDHXx4.js} +0 -0
- /package/dist/web/assets/{plus-BhMZqFsN.js → plus-BR0qewJI.js} +0 -0
- /package/dist/web/assets/{po-BigskytD.js → po-BX2FiuW2.js} +0 -0
- /package/dist/web/assets/{poimandres-DuklniF7.js → poimandres-DzXOdZcN.js} +0 -0
- /package/dist/web/assets/{polar-e2pjN_sp.js → polar-DDRXgJzG.js} +0 -0
- /package/dist/web/assets/{portal-container-context-Cm5HipFr.js → portal-container-context-a399Hd9F.js} +0 -0
- /package/dist/web/assets/{postcss-DtAeYjWw.js → postcss-BHW6XBhx.js} +0 -0
- /package/dist/web/assets/{powerquery-Cr2PtehI.js → powerquery-B89c2NBb.js} +0 -0
- /package/dist/web/assets/{powershell-BxFTGLJ4.js → powershell-Dvxrd3Tu.js} +0 -0
- /package/dist/web/assets/{prisma-COWJiwdZ.js → prisma-lMK8EFLU.js} +0 -0
- /package/dist/web/assets/{prolog-DFvGKRx6.js → prolog-D0YrtMG4.js} +0 -0
- /package/dist/web/assets/{proto-CcK80lFt.js → proto-J0mM25aw.js} +0 -0
- /package/dist/web/assets/{puppet-BF60bZ4F.js → puppet-CUT0xkhh.js} +0 -0
- /package/dist/web/assets/{purescript-zL_69MzU.js → purescript-CoJWSGRp.js} +0 -0
- /package/dist/web/assets/{python-CIwKhfb_.js → python-BBrmuz6P.js} +0 -0
- /package/dist/web/assets/{qmldir-CXNe04Lo.js → qmldir-CUtzs4Q7.js} +0 -0
- /package/dist/web/assets/{qss-C8lAWe6G.js → qss-Dm1RZ8aL.js} +0 -0
- /package/dist/web/assets/{r-CL5ZVL3_.js → r-BGP7qZTe.js} +0 -0
- /package/dist/web/assets/{racket-BBfh0uh0.js → racket-K_6U1lqJ.js} +0 -0
- /package/dist/web/assets/{raku-o6E8R5Q3.js → raku-bNSiZeW_.js} +0 -0
- /package/dist/web/assets/{react-CBTnT4sY.js → react-X4jUntEf.js} +0 -0
- /package/dist/web/assets/{red-GomRF2Xp.js → red-uVeIEF0f.js} +0 -0
- /package/dist/web/assets/{refresh-cw-B06yaBrW.js → refresh-cw-B9iv7csb.js} +0 -0
- /package/dist/web/assets/{reg-_ffDIvx9.js → reg-DSm9GWjh.js} +0 -0
- /package/dist/web/assets/{regexp-Bl5sF65W.js → regexp-CljRm_j_.js} +0 -0
- /package/dist/web/assets/{rel-DgMdqDuj.js → rel-d3JcopZg.js} +0 -0
- /package/dist/web/assets/{resolve-theme-CRt_7wpd.js → resolve-theme-DLKmm-lE.js} +0 -0
- /package/dist/web/assets/{riscv-8b3-Ye4X.js → riscv-CJmaELjT.js} +0 -0
- /package/dist/web/assets/{ron-DrmU1KHP.js → ron-D0g9B1rW.js} +0 -0
- /package/dist/web/assets/{rose-pine-C_-E2tF1.js → rose-pine-DOrD2BSH.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-DEfhNlFH.js → rose-pine-dawn-CzZQ-LCF.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-BdvX3gdn.js → rose-pine-moon-CdmsYp7C.js} +0 -0
- /package/dist/web/assets/{rosmsg-B6GhGpd5.js → rosmsg-CmDth6pO.js} +0 -0
- /package/dist/web/assets/{rotate-ccw-COXu_9oj.js → rotate-ccw-DnuPzJRE.js} +0 -0
- /package/dist/web/assets/{rust-DmC97M1-.js → rust-DGdP6jiR.js} +0 -0
- /package/dist/web/assets/{sass-B0tJOHLM.js → sass-Dkgt2FKZ.js} +0 -0
- /package/dist/web/assets/{save-CtIGOjmx.js → save-DxonD4y1.js} +0 -0
- /package/dist/web/assets/{scala-n8zaFOXv.js → scala-BQLTON6C.js} +0 -0
- /package/dist/web/assets/{scheme-BKD9ztBU.js → scheme-DKlxUGCi.js} +0 -0
- /package/dist/web/assets/{sdbl-D8gB5-rS.js → sdbl-C3iZJQeZ.js} +0 -0
- /package/dist/web/assets/{send-BlyNJAzy.js → send-B-t5Mz26.js} +0 -0
- /package/dist/web/assets/{shallow-DYo6goJ4.js → shallow-jwPzEunk.js} +0 -0
- /package/dist/web/assets/{shellscript-BfXlf_Ao.js → shellscript-BRu-ZQAx.js} +0 -0
- /package/dist/web/assets/{shield-check-B0iGUiOK.js → shield-check-CdTiK1j2.js} +0 -0
- /package/dist/web/assets/{shield-off-BNLWBhcq.js → shield-off-DuetkXKM.js} +0 -0
- /package/dist/web/assets/{slack-dark-CylEddse.js → slack-dark-qkm_u2zz.js} +0 -0
- /package/dist/web/assets/{slack-ochin-w8wg8vuC.js → slack-ochin-BP8_8e4m.js} +0 -0
- /package/dist/web/assets/{smalltalk-hiAXA64u.js → smalltalk-Bnz4gt07.js} +0 -0
- /package/dist/web/assets/{snazzy-light-BwlV3Xty.js → snazzy-light-fbPZg5io.js} +0 -0
- /package/dist/web/assets/{solarized-dark-vmNGdykz.js → solarized-dark-CM0vTRoi.js} +0 -0
- /package/dist/web/assets/{solarized-light-DGv_0JXq.js → solarized-light-C4_W9mvs.js} +0 -0
- /package/dist/web/assets/{solidity-Y7QSH0B1.js → solidity-Bz6v1PoD.js} +0 -0
- /package/dist/web/assets/{splunk-BtgpLjHi.js → splunk-DyNxu-0i.js} +0 -0
- /package/dist/web/assets/{sql-CRHYhOia.js → sql-DXRL1gw1.js} +0 -0
- /package/dist/web/assets/{ssh-config-DOqSs3au.js → ssh-config-2z1QHuOG.js} +0 -0
- /package/dist/web/assets/{stylus-crCAEaBT.js → stylus-D4I-VaeY.js} +0 -0
- /package/dist/web/assets/{swift-eE3rT7TC.js → swift-C_2G-tIc.js} +0 -0
- /package/dist/web/assets/{synthwave-84-BWy14LBX.js → synthwave-84-osBjChRP.js} +0 -0
- /package/dist/web/assets/{system-verilog-DC0-DZM4.js → system-verilog-zQP2qPNU.js} +0 -0
- /package/dist/web/assets/{systemd-to5p6N8I.js → systemd-UGfjRSBM.js} +0 -0
- /package/dist/web/assets/{table-Bbc783ko.js → table-FLU8ei8b.js} +0 -0
- /package/dist/web/assets/{talonscript-DoTcU8wm.js → talonscript-C1XrFPwo.js} +0 -0
- /package/dist/web/assets/{tasl-cNZvUs95.js → tasl-B5raVn43.js} +0 -0
- /package/dist/web/assets/{tcl-mZE8sZH8.js → tcl-3-vbeMIc.js} +0 -0
- /package/dist/web/assets/{terraform-CqHPpIfu.js → terraform-a8VXZDm9.js} +0 -0
- /package/dist/web/assets/{text-wrap-CBT4Gxtg.js → text-wrap-B05VGRa-.js} +0 -0
- /package/dist/web/assets/{tokyo-night-Tp2rTIZd.js → tokyo-night-4SRhf-Hz.js} +0 -0
- /package/dist/web/assets/{toml-CU_vscgn.js → toml-B4N0i8wT.js} +0 -0
- /package/dist/web/assets/{trash-2-Bk4yYlck.js → trash-2-CTXlTflF.js} +0 -0
- /package/dist/web/assets/{triangle-alert-B8EYecpe.js → triangle-alert-BRq0VAfd.js} +0 -0
- /package/dist/web/assets/{tsv-ik7iFB9D.js → tsv-DA5k9Lvw.js} +0 -0
- /package/dist/web/assets/{tsx-BMvvMKiv.js → tsx-D9SZ8owC.js} +0 -0
- /package/dist/web/assets/{turtle-DBqKCq9o.js → turtle-BTHTvyY_.js} +0 -0
- /package/dist/web/assets/{typescript-DXJDmMZZ.js → typescript-DYzV9p5L.js} +0 -0
- /package/dist/web/assets/{typespec-CBseCMtZ.js → typespec-BC15eh7F.js} +0 -0
- /package/dist/web/assets/{typst-4oY25U9y.js → typst-BJUqzA6D.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-D1weanbj.js → use-is-mobile-DFWViA4S.js} +0 -0
- /package/dist/web/assets/{utils-BNRH507E.js → utils-C9OjCrou.js} +0 -0
- /package/dist/web/assets/{v-BXaZ_1oy.js → v-50Lps6oA.js} +0 -0
- /package/dist/web/assets/{vala-BImWJE7z.js → vala-8wiUvvrD.js} +0 -0
- /package/dist/web/assets/{vb-CLfj2_sy.js → vb-BlgPLt6B.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-_yyu5n32.js → vendor-xterm-BZOrwF_F.js} +0 -0
- /package/dist/web/assets/{verilog-BWa8Ed2b.js → verilog-CD9pVW5p.js} +0 -0
- /package/dist/web/assets/{vesper-BGj1cg6m.js → vesper-BrivW4PT.js} +0 -0
- /package/dist/web/assets/{vhdl-mByK7mlx.js → vhdl-Bunxfa7N.js} +0 -0
- /package/dist/web/assets/{viml-CugmlW5g.js → viml-DndUb2qM.js} +0 -0
- /package/dist/web/assets/{vitesse-black-vPdpy9TL.js → vitesse-black-BurZSkxW.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-BuQK3dUh.js → vitesse-dark-8UShspzC.js} +0 -0
- /package/dist/web/assets/{vitesse-light-B3nz1XL9.js → vitesse-light-DghCAZ90.js} +0 -0
- /package/dist/web/assets/{vyper-DH_GTIHG.js → vyper-b-Clr-8u.js} +0 -0
- /package/dist/web/assets/{wasm-DfVbVJlW.js → wasm-C5v2T06Y.js} +0 -0
- /package/dist/web/assets/{wasm-C-LF9GjX.js → wasm-CpcKStkw.js} +0 -0
- /package/dist/web/assets/{wenyan-CzQkHyHx.js → wenyan-Dz2srLZR.js} +0 -0
- /package/dist/web/assets/{wgsl-Du_M1DW9.js → wgsl-CeD1-dRb.js} +0 -0
- /package/dist/web/assets/{wikitext-BWN_w5S7.js → wikitext-CyeS-9FH.js} +0 -0
- /package/dist/web/assets/{wit-BR13v5HD.js → wit-Kr-q-qBQ.js} +0 -0
- /package/dist/web/assets/{wolfram-BoXxp_Xl.js → wolfram-BKm8bmln.js} +0 -0
- /package/dist/web/assets/{x-nhriOX9o.js → x-YDu4m2Iq.js} +0 -0
- /package/dist/web/assets/{yaml-DpR_EF-d.js → yaml-2XSxomjM.js} +0 -0
- /package/dist/web/assets/{zenscript-C-EdUtUd.js → zenscript-CKIS34vf.js} +0 -0
- /package/dist/web/assets/{zig-BD4eA5nU.js → zig-DdHGNllX.js} +0 -0
package/docs/deployment-guide.md
CHANGED
|
@@ -3,78 +3,56 @@
|
|
|
3
3
|
## Prerequisites
|
|
4
4
|
|
|
5
5
|
### System Requirements
|
|
6
|
-
- **OS:** Linux or
|
|
6
|
+
- **OS:** macOS, Linux or Windows (all three are supported targets)
|
|
7
7
|
- **RAM:** 512 MB minimum, 2 GB recommended
|
|
8
|
-
- **Disk:** 500 MB for binary
|
|
9
|
-
- **Network:** localhost
|
|
8
|
+
- **Disk:** ~500 MB for the binary, plus ~15 MB for the cloudflared binary PPM downloads on first start
|
|
9
|
+
- **Network:** localhost is enough; internet access is needed for the tunnel and for AI providers
|
|
10
10
|
|
|
11
11
|
### Required Software
|
|
12
|
-
- **Bun
|
|
13
|
-
|
|
14
|
-
- **
|
|
12
|
+
- **Bun** v1.3.6+ (https://bun.sh) — **only** for the `bunx`/`bun add -g`/from-source paths. The
|
|
13
|
+
released binary bundles its own runtime and needs nothing installed.
|
|
14
|
+
- **Git** v2.0+ — for the git features
|
|
15
|
+
- **Claude Code** (`claude` CLI, logged in) — for AI chat via the Claude Agent SDK
|
|
15
16
|
|
|
16
17
|
### Optional
|
|
17
|
-
-
|
|
18
|
-
-
|
|
18
|
+
- `@openai/codex` or `cursor-agent` on PATH — each registers an extra AI provider when present
|
|
19
|
+
- `ffmpeg` — on-the-fly transcoding for video formats the browser cannot play
|
|
20
|
+
- `psql` / a PostgreSQL server — for the Postgres side of the database viewer
|
|
19
21
|
|
|
20
22
|
---
|
|
21
23
|
|
|
22
24
|
## Installation
|
|
23
25
|
|
|
24
|
-
### Option 1:
|
|
26
|
+
### Option 1: Installer script (recommended)
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
**macOS / Linux:**
|
|
27
29
|
```bash
|
|
28
|
-
|
|
29
|
-
bun --version # Should be 1.3.6+
|
|
30
|
-
|
|
31
|
-
# Clone repository
|
|
32
|
-
git clone https://github.com/hienlh/ppm.git
|
|
33
|
-
cd ppm
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
#### Install & Build
|
|
37
|
-
```bash
|
|
38
|
-
# Install dependencies
|
|
39
|
-
bun install
|
|
40
|
-
|
|
41
|
-
# Build frontend + CLI binary
|
|
42
|
-
bun run build
|
|
43
|
-
|
|
44
|
-
# Output: dist/ppm (compiled binary)
|
|
30
|
+
curl -fsSL https://ppm.sh/install | sh
|
|
45
31
|
```
|
|
46
32
|
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
bun run start
|
|
51
|
-
|
|
52
|
-
# Or use compiled binary
|
|
53
|
-
./dist/ppm start
|
|
33
|
+
**Windows (PowerShell):**
|
|
34
|
+
```powershell
|
|
35
|
+
irm https://ppm.sh/install.ps1 | iex
|
|
54
36
|
```
|
|
55
37
|
|
|
56
|
-
|
|
38
|
+
Downloads the matching release archive, unpacks it to `~/.ppm/bin` (override with `PPM_INSTALL_DIR`)
|
|
39
|
+
and adds it to PATH. Re-run to upgrade, or use `ppm upgrade`.
|
|
57
40
|
|
|
58
|
-
### Option 2:
|
|
41
|
+
### Option 2: Via Bun
|
|
59
42
|
|
|
60
|
-
#### Download
|
|
61
43
|
```bash
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
chmod +x ppm-macos-x64
|
|
65
|
-
|
|
66
|
-
# Or for Linux
|
|
67
|
-
wget https://github.com/hienlh/ppm/releases/download/v2.0/ppm-linux-x64
|
|
68
|
-
chmod +x ppm-linux-x64
|
|
44
|
+
bunx @hienlh/ppm start # run without installing
|
|
45
|
+
bun add -g @hienlh/ppm # or install globally
|
|
69
46
|
```
|
|
70
47
|
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
# Copy to PATH for global access
|
|
74
|
-
sudo cp ppm-macos-x64 /usr/local/bin/ppm
|
|
48
|
+
### Option 3: Build from source (development)
|
|
75
49
|
|
|
76
|
-
|
|
77
|
-
ppm
|
|
50
|
+
```bash
|
|
51
|
+
git clone https://github.com/hienlh/ppm.git
|
|
52
|
+
cd ppm
|
|
53
|
+
bun install
|
|
54
|
+
bun run build # frontend + compiled binary → dist/ppm
|
|
55
|
+
./dist/ppm start
|
|
78
56
|
```
|
|
79
57
|
|
|
80
58
|
---
|
|
@@ -84,321 +62,243 @@ ppm --version
|
|
|
84
62
|
### Initial Setup
|
|
85
63
|
|
|
86
64
|
```bash
|
|
87
|
-
#
|
|
88
|
-
ppm init
|
|
89
|
-
|
|
90
|
-
# Output: ~/.ppm/ppm.db (SQLite database)
|
|
91
|
-
# Auto-generates auth token
|
|
65
|
+
ppm init # interactive wizard
|
|
66
|
+
ppm init -y # non-interactive: defaults + auto-generated password
|
|
92
67
|
```
|
|
93
68
|
|
|
69
|
+
Writes `~/.ppm/ppm.db` (SQLite) and generates an auth token. `ppm start` runs the wizard
|
|
70
|
+
automatically if no config exists.
|
|
71
|
+
|
|
94
72
|
### Dev vs Production Config
|
|
95
73
|
|
|
96
|
-
|
|
74
|
+
| Profile | Database | Conventional port |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| Production | `~/.ppm/ppm.db` | 3210 (what `ppm init` writes) |
|
|
77
|
+
| Development | `~/.ppm/ppm.dev.db` | 8081 |
|
|
97
78
|
|
|
98
|
-
|
|
99
|
-
|
|
79
|
+
`bun dev:server` selects the dev database via the `dev` profile; `ppm start --profile dev` does the
|
|
80
|
+
same for a compiled binary. On a new machine run `ppm init`, then `ppm config set port 8081` for dev.
|
|
100
81
|
|
|
101
|
-
|
|
82
|
+
> Both databases live in the same directory, and so does `.server-port`. Running `dev:server` while
|
|
83
|
+
> production is up can therefore steal the tunnel's route — stop one before starting the other.
|
|
102
84
|
|
|
103
85
|
### Config Structure (SQLite)
|
|
104
86
|
|
|
105
|
-
Config
|
|
87
|
+
Config lives in the `config` table as dotted key/value pairs. The shape is defined by
|
|
88
|
+
`DEFAULT_CONFIG` in `src/types/config.ts` — that struct is the source of truth:
|
|
106
89
|
|
|
107
90
|
```
|
|
108
|
-
port
|
|
109
|
-
host
|
|
110
|
-
|
|
111
|
-
auth.token
|
|
112
|
-
|
|
91
|
+
port 8080 ← struct default; `ppm init` writes 3210
|
|
92
|
+
host 0.0.0.0
|
|
93
|
+
theme.style / theme.mode aurora / system
|
|
94
|
+
auth.enabled / auth.token true / auto-generated
|
|
95
|
+
ai.default_provider claude
|
|
96
|
+
ai.providers.claude.model claude-opus-5
|
|
97
|
+
ai.providers.claude.effort high
|
|
98
|
+
ai.providers.claude.permission_mode bypassPermissions
|
|
113
99
|
```
|
|
114
100
|
|
|
115
|
-
Projects
|
|
101
|
+
Projects, accounts, sessions, schedules, usage and audit logs each live in their own table.
|
|
102
|
+
|
|
103
|
+
Never build a `~/.ppm` path by hand in service code — import `getPpmDir()` from
|
|
104
|
+
`src/services/ppm-dir.ts` so `PPM_HOME` can redirect it in tests.
|
|
116
105
|
|
|
117
106
|
### Customize Configuration
|
|
118
107
|
|
|
119
|
-
#### Change Port
|
|
120
108
|
```bash
|
|
121
|
-
#
|
|
109
|
+
# Port
|
|
122
110
|
ppm config set port 3000
|
|
111
|
+
ppm start -p 3000 # or per-start
|
|
123
112
|
|
|
124
|
-
#
|
|
125
|
-
ppm start --port 3000
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
#### Add/Remove Projects
|
|
129
|
-
```bash
|
|
130
|
-
# Add project
|
|
113
|
+
# Projects
|
|
131
114
|
ppm projects add my-project /path/to/my-project
|
|
132
|
-
|
|
133
|
-
# List projects
|
|
134
115
|
ppm projects list
|
|
135
|
-
|
|
136
|
-
# Remove project
|
|
137
116
|
ppm projects remove my-project
|
|
138
|
-
```
|
|
139
117
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
ppm config set providers.default mock
|
|
118
|
+
# AI provider / model
|
|
119
|
+
ppm config set ai.default_provider claude # claude | codex | cursor
|
|
120
|
+
ppm config set ai.providers.claude.model claude-opus-5
|
|
144
121
|
|
|
145
|
-
#
|
|
146
|
-
ppm config set
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
#### Change Authentication Token
|
|
150
|
-
```bash
|
|
151
|
-
# Generate new random token
|
|
152
|
-
ppm config set auth.token "$(openssl rand -hex 32)"
|
|
122
|
+
# Auth
|
|
123
|
+
ppm config set auth.enabled true
|
|
153
124
|
```
|
|
154
125
|
|
|
155
126
|
---
|
|
156
127
|
|
|
157
128
|
## Running the Server
|
|
158
129
|
|
|
159
|
-
|
|
130
|
+
`ppm start` always runs as a **background daemon under a supervisor**, and always brings up a
|
|
131
|
+
Cloudflare Quick Tunnel. There is no foreground mode.
|
|
160
132
|
|
|
161
133
|
```bash
|
|
162
|
-
ppm start
|
|
134
|
+
ppm start # daemon + tunnel; blocks until the URL is known, then exits 0
|
|
135
|
+
ppm start -p 4000 # custom port
|
|
136
|
+
ppm start --profile dev # use ppm.dev.db
|
|
163
137
|
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
|
|
167
|
-
#
|
|
138
|
+
ppm status # human-readable
|
|
139
|
+
ppm status --json # machine-readable — `.shareUrl` is the public URL
|
|
140
|
+
ppm logs -f # follow ~/.ppm/ppm.log
|
|
141
|
+
ppm restart # reload, keeping the tunnel URL
|
|
168
142
|
```
|
|
169
143
|
|
|
170
|
-
|
|
144
|
+
Startup prints `➜ Local`, `➜ Share` and a QR code for the share URL. It waits up to 35s for the
|
|
145
|
+
tunnel; if the URL has not appeared it warns and tells you to check `ppm status`.
|
|
171
146
|
|
|
172
|
-
###
|
|
147
|
+
### Stopping: `stop` vs `down`
|
|
173
148
|
|
|
174
|
-
|
|
149
|
+
| Command | Server | Supervisor | Tunnel / Cloud link |
|
|
150
|
+
|---|---|---|---|
|
|
151
|
+
| `ppm stop` | stopped | **stays alive** (`stopped` state) | **stays up** |
|
|
152
|
+
| `ppm down` (= `ppm stop --kill`) | stopped | stopped | stopped |
|
|
153
|
+
| `ppm stop --all` | stopped | stopped | kills every PPM + cloudflared process, tracked or not |
|
|
175
154
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
ppm start
|
|
179
|
-
|
|
180
|
-
# Tunnel and public URL are enabled automatically on start
|
|
181
|
-
ppm start
|
|
155
|
+
The split exists so a restart does not rotate the public URL. Use `down` for a real shutdown; use
|
|
156
|
+
`stop --all` only when something is wedged — it kills by scan, not by tracked PID.
|
|
182
157
|
|
|
183
|
-
|
|
184
|
-
ppm start --foreground
|
|
158
|
+
### Logs
|
|
185
159
|
|
|
186
|
-
|
|
187
|
-
|
|
160
|
+
The daemon writes to `~/.ppm/ppm.log` (inside `getPpmDir()`). `ppm logs -n 200`, `ppm logs -f` and
|
|
161
|
+
`ppm logs --clear` read and manage it. There is no separate logging config.
|
|
188
162
|
|
|
189
|
-
|
|
190
|
-
ps aux | grep ppm
|
|
163
|
+
---
|
|
191
164
|
|
|
192
|
-
|
|
193
|
-
ppm stop
|
|
165
|
+
## Start at Boot
|
|
194
166
|
|
|
195
|
-
|
|
196
|
-
```
|
|
167
|
+
Use the built-in command rather than hand-writing a service file:
|
|
197
168
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
"port": 8080,
|
|
203
|
-
"host": "0.0.0.0",
|
|
204
|
-
"shareUrl": "https://abc-123.trycloudflare.com"
|
|
205
|
-
}
|
|
169
|
+
```bash
|
|
170
|
+
ppm autostart enable
|
|
171
|
+
ppm autostart status
|
|
172
|
+
ppm autostart disable
|
|
206
173
|
```
|
|
207
174
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
### Public URL Sharing via Cloudflare Tunnel
|
|
175
|
+
It generates the right artifact per OS:
|
|
211
176
|
|
|
212
|
-
|
|
177
|
+
| OS | Artifact |
|
|
178
|
+
|---|---|
|
|
179
|
+
| macOS | `~/Library/LaunchAgents/com.hienlh.ppm.plist` |
|
|
180
|
+
| Linux | `~/.config/systemd/user/ppm.service` (`Type=notify`) |
|
|
181
|
+
| Windows | Task Scheduler task `PPM`, registered from an XML task definition at logon |
|
|
213
182
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
4. Tunnel URL extracted from stderr (e.g., `https://abc-123.trycloudflare.com`)
|
|
219
|
-
5. URL saved to `~/.ppm/status.json` for easy access
|
|
220
|
-
6. Parent displays public URL in terminal output
|
|
183
|
+
`ppm start` enables autostart on first run and migrates a stale systemd unit, so in most cases you
|
|
184
|
+
never call this directly. On Windows the task is created from XML rather than plain `schtasks
|
|
185
|
+
/SC ONLOGON` — that flag cannot target a single user's logon without an all-users change, and it
|
|
186
|
+
would otherwise impose a 72-hour run limit.
|
|
221
187
|
|
|
222
|
-
|
|
223
|
-
- Internet connectivity (tunnel uses Cloudflare's infrastructure)
|
|
224
|
-
- ~15 MB disk space for cloudflared binary (downloaded once, cached)
|
|
188
|
+
---
|
|
225
189
|
|
|
226
|
-
|
|
227
|
-
If `auth.enabled` is false, PPM displays warning:
|
|
228
|
-
```
|
|
229
|
-
⚠ Warning: auth is disabled — your IDE is publicly accessible!
|
|
230
|
-
Enable auth: run 'ppm config set auth.enabled true' before using tunnel.
|
|
231
|
-
```
|
|
190
|
+
## Public URL Sharing via Cloudflare Tunnel
|
|
232
191
|
|
|
233
|
-
|
|
192
|
+
1. `ppm start` spawns the supervisor and server
|
|
193
|
+
2. cloudflared is downloaded to `~/.ppm/bin/` on first use (~15 MB, cached)
|
|
194
|
+
3. The tunnel runs as a child process; its URL is parsed from stderr
|
|
195
|
+
4. The URL is written to `~/.ppm/status.json` and printed with a QR code
|
|
234
196
|
|
|
235
|
-
**
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
ppm start # Safe: public URL + auth required
|
|
197
|
+
**The quick-tunnel URL rotates on every fresh tunnel.** For a stable address, either link the machine
|
|
198
|
+
to PPM Cloud (`ppm cloud login`) for a permanent alias, or set up a named tunnel on a domain you
|
|
199
|
+
already have on Cloudflare — see the next section.
|
|
239
200
|
|
|
240
|
-
|
|
241
|
-
|
|
201
|
+
**Security:** if `auth.enabled` is false while the tunnel is up, PPM warns that the IDE is publicly
|
|
202
|
+
reachable. Always keep auth on when sharing. The session token is required on the WebSocket
|
|
203
|
+
handshake too, not just on HTTP.
|
|
242
204
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
```
|
|
205
|
+
Per-port forwarding for local dev servers is separate: the dock's Cloudflare Tunnels panel drives
|
|
206
|
+
`/api/tunnels`, which spawns one quick tunnel per port.
|
|
246
207
|
|
|
247
|
-
|
|
248
|
-
- `ppm stop` gracefully shuts down the tunnel
|
|
249
|
-
- Cloudflared process killed via SIGTERM
|
|
250
|
-
- No dangling tunnels left behind
|
|
208
|
+
---
|
|
251
209
|
|
|
252
|
-
|
|
210
|
+
## Stable Public URL with Your Own Domain
|
|
253
211
|
|
|
254
|
-
|
|
212
|
+
A named tunnel pins PPM to `https://<prefix>.<your-zone>` — the same hostname across restarts,
|
|
213
|
+
hibernate, and crashes, unlike the quick tunnel's rotating `*.trycloudflare.com` URL. It requires:
|
|
255
214
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
215
|
+
- A domain already added as a zone in your Cloudflare account.
|
|
216
|
+
- `auth.enabled` set to `true` — a stable, guessable hostname must never be reachable by an
|
|
217
|
+
unauthenticated request, so the setup popup stays hidden and every mutating endpoint 403s while
|
|
218
|
+
auth is off.
|
|
260
219
|
|
|
261
|
-
|
|
262
|
-
Type=simple
|
|
263
|
-
User=<username>
|
|
264
|
-
WorkingDirectory=/home/<username>
|
|
265
|
-
ExecStart=/usr/local/bin/ppm start
|
|
266
|
-
Restart=always
|
|
267
|
-
RestartSec=10
|
|
220
|
+
### Setup flow
|
|
268
221
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
222
|
+
A first-run popup asks whether you have a domain on Cloudflare. Answering yes opens a Cloudflare
|
|
223
|
+
login link — copy it to a phone or another browser if this machine has no browser of its own. The
|
|
224
|
+
login stays open while you finish it: after 60 seconds idle you get a "still logging in?" prompt
|
|
225
|
+
(the login keeps running), and after 5 minutes with no login it times out and lets you retry with a
|
|
226
|
+
fresh link. Once logged in, PPM reads the zone from the new credential and proposes a hostname
|
|
227
|
+
(`ppm.<zone>` by default) — you can pick a different prefix, but it must be exactly one label under
|
|
228
|
+
the zone (no apex record, no `www`; Cloudflare's free certificate only covers one subdomain level,
|
|
229
|
+
and anything deeper would serve a TLS error).
|
|
272
230
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
sudo systemctl daemon-reload
|
|
276
|
-
sudo systemctl enable ppm
|
|
277
|
-
sudo systemctl start ppm
|
|
231
|
+
The Tunnel Manager section (in the app, alongside the quick-tunnel controls) is where the flow lives
|
|
232
|
+
permanently — the popup only covers first-run:
|
|
278
233
|
|
|
279
|
-
|
|
280
|
-
|
|
234
|
+
- **Disable** switches back to the quick tunnel. The named-tunnel configuration is kept (not deleted)
|
|
235
|
+
so re-enabling doesn't require logging in again.
|
|
236
|
+
- **Re-login** ("Log in again") is what to use when the domain's zone changes, or whenever PPM
|
|
237
|
+
reports the Cloudflare credential looks stale (wrong account, unreadable file). It moves the
|
|
238
|
+
existing credential aside (`cert.pem` → `cert.pem.bak-<timestamp>`) rather than deleting it, then
|
|
239
|
+
starts a fresh login — never edit or delete `~/.cloudflared/cert.pem` by hand.
|
|
281
240
|
|
|
282
|
-
|
|
283
|
-
sudo journalctl -u ppm -f
|
|
284
|
-
```
|
|
241
|
+
### Troubleshooting
|
|
285
242
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
292
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
293
|
-
<plist version="1.0">
|
|
294
|
-
<dict>
|
|
295
|
-
<key>Label</key>
|
|
296
|
-
<string>com.ppm.server</string>
|
|
297
|
-
<key>ProgramArguments</key>
|
|
298
|
-
<array>
|
|
299
|
-
<string>/usr/local/bin/ppm</string>
|
|
300
|
-
<string>start</string>
|
|
301
|
-
</array>
|
|
302
|
-
<key>RunAtLoad</key>
|
|
303
|
-
<true/>
|
|
304
|
-
<key>KeepAlive</key>
|
|
305
|
-
<true/>
|
|
306
|
-
<key>StandardOutPath</key>
|
|
307
|
-
<string>/tmp/ppm.log</string>
|
|
308
|
-
<key>StandardErrorPath</key>
|
|
309
|
-
<string>/tmp/ppm-error.log</string>
|
|
310
|
-
</dict>
|
|
311
|
-
</plist>
|
|
312
|
-
```
|
|
243
|
+
**"Hostname unreachable" warning** — shown when the DNS record for your named tunnel stops
|
|
244
|
+
resolving (for example, the CNAME was deleted in the Cloudflare dashboard outside PPM). PPM restarts
|
|
245
|
+
the tunnel connector once to rule out a transient failure; if the hostname is still unreachable after
|
|
246
|
+
that it stops retrying and leaves the warning up rather than restarting forever. Recreate the DNS
|
|
247
|
+
record in Cloudflare (or use Re-login if the whole zone changed) to clear it.
|
|
313
248
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
```
|
|
249
|
+
**Setup finishes but says "pending" / asks you to run `ppm restart`** — the setup call always
|
|
250
|
+
succeeds once cloudflared provisions the tunnel; picking it up without a full restart needs a
|
|
251
|
+
supervisor version that understands the `retunnel` command. On an older supervisor (from before a
|
|
252
|
+
PPM upgrade), run `ppm restart` once to finish applying it.
|
|
319
253
|
|
|
320
254
|
---
|
|
321
255
|
|
|
322
256
|
## Environment Variables
|
|
323
257
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
Instead of `ppm.yaml`, configure via environment variables:
|
|
327
|
-
|
|
328
|
-
```bash
|
|
329
|
-
export PPM_PORT=8080
|
|
330
|
-
export PPM_HOST=0.0.0.0
|
|
331
|
-
export PPM_AUTH_TOKEN="my-secure-token"
|
|
332
|
-
export PPM_DEFAULT_PROVIDER="claude-agent-sdk"
|
|
333
|
-
export PPM_DB_PATH="/etc/ppm/ppm.db" # Custom database location
|
|
258
|
+
Only these are read by PPM:
|
|
334
259
|
|
|
335
|
-
|
|
336
|
-
|
|
260
|
+
| Variable | Read by | Purpose |
|
|
261
|
+
|---|---|---|
|
|
262
|
+
| `PPM_HOME` | `src/services/ppm-dir.ts` | Override the `~/.ppm` directory. Used for test isolation. |
|
|
263
|
+
| `PPM_CLAUDE_CLI` | Claude provider / CLI resolver | Explicit path to the `claude` binary when discovery fails |
|
|
264
|
+
| `PPM_SKILLS_DIR` | `slash-discovery` | Extra directory to discover skills from |
|
|
265
|
+
| `PPM_TERMINAL` | `ppm cloud` | Set to `1` to force terminal-mode output |
|
|
266
|
+
| `PPM_INSTALL_DIR` | `scripts/install.sh` / `install.ps1` | Install location (default `~/.ppm/bin`) |
|
|
267
|
+
| `PPM_DEV_API` | `vite.config.ts` | Dev-server proxy target (default `http://localhost:8081`) |
|
|
337
268
|
|
|
338
|
-
|
|
269
|
+
There is **no** `PPM_PORT`, `PPM_HOST`, `PPM_DB_PATH` or `PPM_DEFAULT_PROVIDER` — all of those are
|
|
270
|
+
config keys, set with `ppm config set`.
|
|
339
271
|
|
|
340
|
-
|
|
341
|
-
```bash
|
|
342
|
-
export ANTHROPIC_API_KEY="sk-ant-..." # Your Anthropic API key
|
|
343
|
-
ppm start
|
|
344
|
-
```
|
|
272
|
+
### AI provider environment
|
|
345
273
|
|
|
346
|
-
|
|
274
|
+
The SDK authenticates through the logged-in `claude` CLI; an `ANTHROPIC_API_KEY` is not required.
|
|
275
|
+
Note that a *project's* `.env` containing `ANTHROPIC_API_KEY` can break SDK tool execution, so the
|
|
276
|
+
provider neutralizes those variables for spawned tools. See `lessons-learned.md`.
|
|
347
277
|
|
|
348
278
|
---
|
|
349
279
|
|
|
350
280
|
## Build & Deployment Commands
|
|
351
281
|
|
|
352
|
-
### Full Build Pipeline
|
|
353
|
-
|
|
354
282
|
```bash
|
|
355
|
-
# 1. Install dependencies
|
|
356
283
|
bun install
|
|
357
|
-
|
|
358
|
-
#
|
|
359
|
-
bun run
|
|
360
|
-
|
|
361
|
-
# 3. Build frontend
|
|
362
|
-
bun run build:web
|
|
363
|
-
|
|
364
|
-
# 4. Compile CLI binary (single executable)
|
|
365
|
-
bun run build
|
|
366
|
-
|
|
367
|
-
# Output: dist/ppm (~50-150 MB depending on platform)
|
|
368
|
-
|
|
369
|
-
# 5. Test (optional, currently partial coverage)
|
|
284
|
+
bun run typecheck # bunx tsc --noEmit
|
|
285
|
+
bun run build:web # frontend only
|
|
286
|
+
bun run build # frontend + compiled binary → dist/ppm
|
|
370
287
|
bun test
|
|
371
288
|
```
|
|
372
289
|
|
|
373
290
|
### Output Artifacts
|
|
374
291
|
|
|
375
|
-
After `bun run build`:
|
|
376
|
-
|
|
377
292
|
```
|
|
378
293
|
dist/
|
|
379
|
-
├── ppm #
|
|
380
|
-
└── web/ #
|
|
294
|
+
├── ppm # compiled binary (embeds the runtime)
|
|
295
|
+
└── web/ # frontend assets served by the binary
|
|
381
296
|
├── index.html
|
|
382
|
-
├── assets/
|
|
383
|
-
│ ├── index-*.js # Main JS bundle
|
|
384
|
-
│ ├── index-*.css # Tailwind styles
|
|
385
|
-
│ └── ... # Other chunks
|
|
297
|
+
├── assets/ # JS/CSS chunks
|
|
386
298
|
└── manifest.json # PWA manifest
|
|
387
299
|
```
|
|
388
300
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
```bash
|
|
392
|
-
# Check bundle size before/after
|
|
393
|
-
bun run build:web
|
|
394
|
-
du -sh dist/web/assets/
|
|
395
|
-
|
|
396
|
-
# Typical sizes:
|
|
397
|
-
# - JS bundles: 200-300 KB gzipped
|
|
398
|
-
# - CSS: 100-150 KB gzipped
|
|
399
|
-
# - Total frontend: 400-500 KB gzipped
|
|
400
|
-
# - CLI binary: 80-120 MB (includes runtime)
|
|
401
|
-
```
|
|
301
|
+
Typical sizes: frontend ~400–500 KB gzipped; binary ~80–120 MB (the runtime dominates).
|
|
402
302
|
|
|
403
303
|
---
|
|
404
304
|
|
|
@@ -466,160 +366,130 @@ Every step is idempotent — safe to re-run if it fails partway (e.g. npm alread
|
|
|
466
366
|
|
|
467
367
|
---
|
|
468
368
|
|
|
469
|
-
##
|
|
369
|
+
## Upgrading
|
|
470
370
|
|
|
471
371
|
```bash
|
|
472
|
-
#
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
# 2. Clone/build PPM
|
|
477
|
-
git clone https://github.com/hienlh/ppm.git
|
|
478
|
-
cd ppm
|
|
479
|
-
bun install
|
|
480
|
-
bun run build
|
|
481
|
-
|
|
482
|
-
# 3. Initialize config
|
|
483
|
-
./dist/ppm init
|
|
484
|
-
# Follow prompts to add projects
|
|
372
|
+
ppm upgrade --check # see whether a newer version exists
|
|
373
|
+
ppm upgrade # download, verify and swap the binary in place
|
|
374
|
+
```
|
|
485
375
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
376
|
+
The supervisor also polls for new versions and surfaces a one-click upgrade banner in the UI. For
|
|
377
|
+
Bun installs, `bun update -g @hienlh/ppm` works as well; for installer-script installs, re-running
|
|
378
|
+
the installer is equivalent.
|
|
489
379
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
# Enter token from step 4
|
|
493
|
-
# Select project and start using
|
|
380
|
+
Config carries over — `~/.ppm/ppm.db` is untouched by an upgrade. Back it up first if you want a
|
|
381
|
+
guaranteed rollback point:
|
|
494
382
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
# - Open terminal and run commands
|
|
498
|
-
# - Chat with Claude (requires ANTHROPIC_API_KEY)
|
|
383
|
+
```bash
|
|
384
|
+
cp ~/.ppm/ppm.db ~/.ppm/ppm.db.backup
|
|
499
385
|
```
|
|
500
386
|
|
|
501
387
|
---
|
|
502
388
|
|
|
503
|
-
##
|
|
504
|
-
|
|
505
|
-
### Port Already in Use
|
|
389
|
+
## First-Time Setup Checklist
|
|
506
390
|
|
|
507
391
|
```bash
|
|
508
|
-
#
|
|
509
|
-
|
|
510
|
-
# Kill process
|
|
511
|
-
kill -9 <PID>
|
|
392
|
+
# 1. Install
|
|
393
|
+
curl -fsSL https://ppm.sh/install | sh
|
|
512
394
|
|
|
513
|
-
#
|
|
514
|
-
ppm
|
|
515
|
-
```
|
|
395
|
+
# 2. Initialize (interactive: port, password, scan dir, AI settings)
|
|
396
|
+
ppm init
|
|
516
397
|
|
|
517
|
-
|
|
398
|
+
# 3. Start — prints Local + Share URLs and a QR code
|
|
399
|
+
ppm start
|
|
518
400
|
|
|
519
|
-
|
|
520
|
-
# Ensure PPM has read/write access to project directory
|
|
521
|
-
chmod -R u+rw /path/to/project
|
|
401
|
+
# 4. Open the printed URL, enter the access password
|
|
522
402
|
|
|
523
|
-
#
|
|
524
|
-
sudo -u <username> ppm start
|
|
403
|
+
# 5. Verify: browse files, open a terminal, run a git status, send a chat message
|
|
525
404
|
```
|
|
526
405
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
```bash
|
|
530
|
-
# Verify git is installed
|
|
531
|
-
git --version
|
|
406
|
+
---
|
|
532
407
|
|
|
533
|
-
|
|
534
|
-
cd /path/to/project
|
|
535
|
-
git status
|
|
408
|
+
## Troubleshooting
|
|
536
409
|
|
|
537
|
-
|
|
538
|
-
|
|
410
|
+
### Port already in use
|
|
411
|
+
```bash
|
|
412
|
+
ppm status # is PPM itself already running?
|
|
413
|
+
lsof -i :3210 # macOS/Linux
|
|
414
|
+
netstat -ano | findstr :3210 # Windows
|
|
415
|
+
ppm start -p 4000 # or just move
|
|
539
416
|
```
|
|
417
|
+
If PPM was killed uncleanly the port can stay wedged by an orphaned child. `ppm stop --all` clears
|
|
418
|
+
tracked and untracked PPM/cloudflared processes; on Windows a zombie-port reaper also runs at start.
|
|
540
419
|
|
|
541
|
-
###
|
|
542
|
-
|
|
420
|
+
### Server won't start
|
|
543
421
|
```bash
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
#
|
|
548
|
-
# Windows may require WSL or special configuration
|
|
422
|
+
ppm status --json
|
|
423
|
+
ppm logs -n 200 # the daemon logs to ~/.ppm/ppm.log
|
|
424
|
+
ppm config get port
|
|
425
|
+
ppm down && ppm start # full restart, including the supervisor
|
|
549
426
|
```
|
|
550
427
|
|
|
551
|
-
###
|
|
552
|
-
|
|
428
|
+
### Tunnel URL missing or unreachable
|
|
553
429
|
```bash
|
|
554
|
-
#
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
# Verify network connectivity
|
|
558
|
-
curl https://api.anthropic.com
|
|
559
|
-
|
|
560
|
-
# Check provider is working
|
|
561
|
-
ppm chat send "test message" 2>&1
|
|
430
|
+
ppm status # shareUrl present?
|
|
431
|
+
ls ~/.ppm/bin/cloudflared # binary downloaded?
|
|
432
|
+
ppm down && ppm start # re-establish; the URL will change
|
|
562
433
|
```
|
|
434
|
+
A resolver that filters `*.trycloudflare.com` (some VPN/DNS setups) will make a *valid* URL look
|
|
435
|
+
dead — test the same URL from another network before assuming the tunnel failed.
|
|
563
436
|
|
|
564
|
-
###
|
|
565
|
-
|
|
437
|
+
### Chat not responding
|
|
566
438
|
```bash
|
|
567
|
-
#
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
# View logs (foreground mode only)
|
|
574
|
-
ppm start --foreground # Shows real-time logs
|
|
439
|
+
claude --version # is Claude Code installed and logged in?
|
|
440
|
+
ppm logs -f # provider errors are logged here
|
|
441
|
+
```
|
|
442
|
+
If the CLI cannot be found, set `PPM_CLAUDE_CLI=/path/to/claude`. If the project has an `.env` with
|
|
443
|
+
`ANTHROPIC_API_KEY`, see the SDK note above.
|
|
575
444
|
|
|
576
|
-
|
|
577
|
-
|
|
445
|
+
### Terminal not working
|
|
446
|
+
```bash
|
|
447
|
+
which bash zsh # macOS/Linux
|
|
448
|
+
```
|
|
449
|
+
Windows uses ConPTY via `@skitee3000/bun-pty`; macOS and Linux use Bun's native PTY. Both are behind
|
|
450
|
+
one `PtyHandle` interface in `terminal.service.ts`.
|
|
578
451
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
452
|
+
### Git commands failing
|
|
453
|
+
```bash
|
|
454
|
+
git --version
|
|
455
|
+
cd /path/to/project && git status # is it actually a repo?
|
|
582
456
|
```
|
|
583
457
|
|
|
584
|
-
|
|
458
|
+
### Permission denied on file operations
|
|
459
|
+
Confirm the PPM process user can read/write the project directory. PPM refuses paths outside its
|
|
460
|
+
allowed scope by design — protected system roots and the PPM directory itself are shielded, so a
|
|
461
|
+
403 on `~/.ppm` is expected behaviour, not a bug.
|
|
585
462
|
|
|
586
463
|
---
|
|
587
464
|
|
|
588
465
|
## Security Checklist
|
|
589
466
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
- [ ]
|
|
593
|
-
- [ ]
|
|
594
|
-
- [ ]
|
|
595
|
-
- [ ] Keep Bun updated: `bun upgrade`
|
|
596
|
-
- [ ]
|
|
597
|
-
- [ ] Review firewall rules (localhost only recommended)
|
|
598
|
-
- [ ] Disable password-less sudo if running as daemon
|
|
599
|
-
- [ ] Use HTTPS if exposing to network (via reverse proxy, e.g., nginx)
|
|
600
|
-
- [ ] Regularly backup `ppm.yaml` and project data
|
|
467
|
+
- [ ] Keep `auth.enabled` true — mandatory whenever the tunnel is up
|
|
468
|
+
- [ ] Rotate the token if it leaks: `ppm config set auth.token "$(openssl rand -hex 32)"`
|
|
469
|
+
- [ ] Restrict the config DB: `chmod 600 ~/.ppm/ppm.db` (it holds account credentials)
|
|
470
|
+
- [ ] Review which projects are registered: `ppm projects list`
|
|
471
|
+
- [ ] Keep the proxy auth key secret if the API proxy is enabled
|
|
472
|
+
- [ ] Keep Bun and PPM updated: `bun upgrade`, `ppm upgrade`
|
|
473
|
+
- [ ] Prefer the tunnel over opening a firewall port
|
|
601
474
|
|
|
602
|
-
###
|
|
475
|
+
### Direct network exposure (not recommended)
|
|
603
476
|
|
|
604
|
-
If you must expose
|
|
477
|
+
The tunnel is the supported path. If you must expose the port directly, terminate TLS in front:
|
|
605
478
|
|
|
606
479
|
```nginx
|
|
607
|
-
|
|
608
|
-
upstream ppm {
|
|
609
|
-
server localhost:8080;
|
|
610
|
-
}
|
|
480
|
+
upstream ppm { server localhost:3210; }
|
|
611
481
|
|
|
612
482
|
server {
|
|
613
483
|
listen 443 ssl http2;
|
|
614
484
|
server_name ppm.example.com;
|
|
615
485
|
|
|
616
|
-
ssl_certificate
|
|
486
|
+
ssl_certificate /etc/letsencrypt/live/ppm.example.com/fullchain.pem;
|
|
617
487
|
ssl_certificate_key /etc/letsencrypt/live/ppm.example.com/privkey.pem;
|
|
618
488
|
|
|
619
489
|
location / {
|
|
620
490
|
proxy_pass http://ppm;
|
|
621
491
|
proxy_http_version 1.1;
|
|
622
|
-
proxy_set_header Upgrade $http_upgrade;
|
|
492
|
+
proxy_set_header Upgrade $http_upgrade; # WebSocket
|
|
623
493
|
proxy_set_header Connection "upgrade";
|
|
624
494
|
proxy_set_header Host $host;
|
|
625
495
|
proxy_set_header X-Real-IP $remote_addr;
|
|
@@ -627,140 +497,60 @@ server {
|
|
|
627
497
|
}
|
|
628
498
|
```
|
|
629
499
|
|
|
630
|
-
Then access via `https://ppm.example.com` with SSL certificate.
|
|
631
|
-
|
|
632
500
|
---
|
|
633
501
|
|
|
634
|
-
##
|
|
635
|
-
|
|
636
|
-
### From v1 to v2
|
|
502
|
+
## Monitoring
|
|
637
503
|
|
|
504
|
+
### Health check (no auth)
|
|
638
505
|
```bash
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
# 2. Stop running server
|
|
643
|
-
ppm stop
|
|
644
|
-
# Or Ctrl+C if foreground
|
|
645
|
-
|
|
646
|
-
# 3. Download/build v2 binary
|
|
647
|
-
# (See "Installation" section above)
|
|
506
|
+
curl http://localhost:3210/api/health
|
|
507
|
+
# {"ok":true,"data":{"status":"running"}}
|
|
648
508
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
# Should output: v2.0.0
|
|
652
|
-
|
|
653
|
-
# 5. Start new version
|
|
654
|
-
./dist/ppm start
|
|
655
|
-
|
|
656
|
-
# 6. Test in browser
|
|
657
|
-
# All projects and auth token should carry over
|
|
509
|
+
curl http://localhost:3210/api/info
|
|
510
|
+
# version, device_name, tunnel_active — used by the login screen
|
|
658
511
|
```
|
|
659
512
|
|
|
660
|
-
###
|
|
513
|
+
### Host metrics
|
|
514
|
+
`/api/system/resources*` streams CPU, memory, disk, network, GPU and per-process data over SSE, in a
|
|
515
|
+
light and a full tier with leases. It is the backend for the System Monitor window and is behind
|
|
516
|
+
PPM auth. On Windows a single long-lived PowerShell collector serves every tick — never spawn one
|
|
517
|
+
per tick.
|
|
661
518
|
|
|
519
|
+
### Daemon state
|
|
662
520
|
```bash
|
|
663
|
-
#
|
|
664
|
-
ppm
|
|
665
|
-
|
|
666
|
-
# 2. Switch back to v1 binary
|
|
667
|
-
# cp path/to/v1/ppm ./ppm-v1
|
|
668
|
-
# ./ppm-v1 start
|
|
669
|
-
|
|
670
|
-
# 3. Restore backup if config changed
|
|
671
|
-
# cp ~/.ppm/ppm.db.backup ~/.ppm/ppm.db
|
|
521
|
+
ppm status --json # pid, port, host, shareUrl, tunnel state
|
|
522
|
+
cat ~/.ppm/status.json # same file the supervisor writes
|
|
523
|
+
ppm logs -f
|
|
672
524
|
```
|
|
673
525
|
|
|
674
526
|
---
|
|
675
527
|
|
|
676
528
|
## Performance Tuning
|
|
677
529
|
|
|
678
|
-
###
|
|
679
|
-
|
|
680
|
-
```bash
|
|
681
|
-
# Check current limit
|
|
682
|
-
ulimit -n
|
|
683
|
-
|
|
684
|
-
# Increase to 4096 (temporary)
|
|
685
|
-
ulimit -n 4096
|
|
686
|
-
|
|
687
|
-
# Permanent: edit /etc/security/limits.conf
|
|
688
|
-
# Add: * soft nofile 4096
|
|
689
|
-
# * hard nofile 4096
|
|
690
|
-
```
|
|
691
|
-
|
|
692
|
-
### Memory Management
|
|
693
|
-
|
|
530
|
+
### File descriptor limit (Linux)
|
|
694
531
|
```bash
|
|
695
|
-
#
|
|
696
|
-
#
|
|
697
|
-
|
|
698
|
-
free -h
|
|
699
|
-
|
|
700
|
-
# macOS
|
|
701
|
-
ps aux | grep ppm
|
|
702
|
-
vm_stat | grep page
|
|
703
|
-
|
|
704
|
-
# If using too much memory:
|
|
705
|
-
# 1. Reduce number of open projects
|
|
706
|
-
# 2. Clear browser cache
|
|
707
|
-
# 3. Restart server
|
|
532
|
+
ulimit -n # check
|
|
533
|
+
ulimit -n 4096 # raise for this shell
|
|
534
|
+
# permanent: /etc/security/limits.conf → * soft nofile 4096 / * hard nofile 4096
|
|
708
535
|
```
|
|
709
536
|
|
|
710
|
-
###
|
|
537
|
+
### File watching
|
|
538
|
+
PPM never registers a recursive watch on a project root — on Linux that is one inotify watch per
|
|
539
|
+
subdirectory, `node_modules` included. Ignored directories are pruned at registration time in
|
|
540
|
+
`src/services/file-watcher/watch-tree.ts`. If you add watch surfaces, keep that invariant or you
|
|
541
|
+
will exhaust the inotify limit.
|
|
711
542
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
ws.send({type: 'message', content: 'ping'});
|
|
717
|
-
// Measure response time
|
|
718
|
-
```
|
|
543
|
+
### Memory
|
|
544
|
+
Long chat sessions are the usual growth source; the transcript is windowed rather than fully
|
|
545
|
+
materialized. If memory climbs, check for orphaned transcode or tunnel children with the System
|
|
546
|
+
Monitor, filtered to PPM's own processes.
|
|
719
547
|
|
|
720
548
|
---
|
|
721
549
|
|
|
722
|
-
##
|
|
723
|
-
|
|
724
|
-
### Health Check Endpoint
|
|
725
|
-
|
|
726
|
-
```bash
|
|
727
|
-
# Health check (no auth required)
|
|
728
|
-
curl http://localhost:8080/api/health
|
|
729
|
-
|
|
730
|
-
# Output: { ok: true, data: { status: "healthy" } }
|
|
731
|
-
```
|
|
732
|
-
|
|
733
|
-
### Activity Logging
|
|
734
|
-
|
|
735
|
-
PPM logs to stdout in foreground mode. In daemon mode, configure:
|
|
736
|
-
|
|
737
|
-
```yaml
|
|
738
|
-
# ppm.yaml
|
|
739
|
-
logging:
|
|
740
|
-
level: info # debug, info, warn, error
|
|
741
|
-
file: ~/.ppm/server.log
|
|
742
|
-
rotation: daily
|
|
743
|
-
retention: 7 # days
|
|
744
|
-
```
|
|
745
|
-
|
|
746
|
-
### Metrics Collection
|
|
747
|
-
|
|
748
|
-
For monitoring integrations (Prometheus, DataDog):
|
|
749
|
-
|
|
750
|
-
```bash
|
|
751
|
-
# Future: /api/metrics endpoint
|
|
752
|
-
# Currently not implemented; planned for v2.1
|
|
753
|
-
```
|
|
754
|
-
|
|
755
|
-
---
|
|
756
|
-
|
|
757
|
-
## Support & Troubleshooting
|
|
758
|
-
|
|
759
|
-
### Getting Help
|
|
760
|
-
|
|
761
|
-
1. **GitHub Issues:** https://github.com/hienlh/ppm/issues
|
|
762
|
-
2. **Logs:** Run `ppm start --foreground` to see real-time logs; check `~/.ppm/status.json` for daemon status
|
|
763
|
-
3. **Configuration:** Validate `ppm.yaml` syntax
|
|
764
|
-
4. **Dependencies:** Ensure Bun, Git, Node are installed and up-to-date
|
|
765
|
-
5. **Tunnel Issues:** Check `~/.ppm/bin/cloudflared` exists; re-download if corrupted
|
|
550
|
+
## Support
|
|
766
551
|
|
|
552
|
+
1. **Bug report:** `ppm report` pre-fills a GitHub issue with environment info and recent logs
|
|
553
|
+
2. **Issues:** https://github.com/hienlh/ppm/issues
|
|
554
|
+
3. **Logs:** `ppm logs -f` (`~/.ppm/ppm.log`)
|
|
555
|
+
4. **Status:** `ppm status --json`
|
|
556
|
+
5. **Known traps:** [`lessons-learned.md`](lessons-learned.md)
|