@hienlh/ppm 0.19.2 → 0.19.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/CLAUDE.md +1 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +3 -2
- package/dist/web/assets/accounts-settings-section-CCFQV-RB.js +1 -0
- package/dist/web/assets/ai-resource-editor-BTWds-aC.js +1 -0
- package/dist/web/assets/ai-settings-section-CmoBsSpY.js +1 -0
- package/dist/web/assets/ai-settings-section-DjbYj4wK.js +1 -0
- package/dist/web/assets/{angular-html-BlcrLjUx.js → angular-html-BuHNQIbQ.js} +1 -1
- package/dist/web/assets/{angular-ts-BUjtceAJ.js → angular-ts-DHRWoLc-.js} +1 -1
- package/dist/web/assets/api-client-BogqsFna.js +1 -0
- package/dist/web/assets/api-settings-CTMdz_VF.js +1 -0
- package/dist/web/assets/{api-themes-YsZgf6Xj.js → api-themes-Cknp3Q-P.js} +1 -1
- package/dist/web/assets/{apl-B3g0v1pk.js → apl-C1VSWVei.js} +1 -1
- package/dist/web/assets/appearance-settings-section-vLmakLtA.js +1 -0
- package/dist/web/assets/architecture-PBZL5I3N-Ca5IpdzP.js +1 -0
- package/dist/web/assets/arrow-left-CyFcsyzD.js +1 -0
- package/dist/web/assets/{astro-FRnyn7cH.js → astro-RX-rChsZ.js} +1 -1
- package/dist/web/assets/{audio-preview-DWTRm4HC.js → audio-preview-CCd1jdje.js} +1 -1
- package/dist/web/assets/{blade-NLdOqUKw.js → blade-CZ6bxMbK.js} +1 -1
- package/dist/web/assets/{pencil-BlIIg6RH.js → brain-KDa9jFRq.js} +1 -1
- package/dist/web/assets/{bsl-CenHZfaU.js → bsl-BhgCXLWk.js} +1 -1
- package/dist/web/assets/{button-Cq8yixjf.js → button-BZtEJcUv.js} +1 -1
- package/dist/web/assets/{cairo-B_WR0aiQ.js → cairo-BrwygPkn.js} +1 -1
- package/dist/web/assets/calendar-clock-C1asT-gk.js +1 -0
- package/dist/web/assets/chat-tab-CLRlS8Jc.js +15 -0
- package/dist/web/assets/check-DN75Ucvz.js +1 -0
- package/dist/web/assets/chevron-up-8PbsNiJp.js +1 -0
- package/dist/web/assets/{cobol-DOynhWYj.js → cobol-C5TGW1Ir.js} +1 -1
- package/dist/web/assets/code-editor-CCwVu5F5.js +7 -0
- package/dist/web/assets/{coffee-Bn6dbw4P.js → coffee-CFgKlmgI.js} +1 -1
- package/dist/web/assets/{conflict-editor-Cgb-z12D.js → conflict-editor-CvWYcbwD.js} +1 -1
- package/dist/web/assets/context-menu-C13b1uT3.js +1 -0
- package/dist/web/assets/{cpp-CoZR9t8r.js → cpp-BhG5q3-d.js} +1 -1
- package/dist/web/assets/{crystal-BSheONSg.js → crystal-DvuI7_tY.js} +1 -1
- package/dist/web/assets/{csv-preview-BZMHfFH3.js → csv-preview-DzuDuyE_.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-gwPoVSCU.js → data-grid-overlay-editor-DP1xkog4.js} +1 -1
- package/dist/web/assets/database-viewer-D4XGEDHm.js +1 -0
- package/dist/web/assets/diff-viewer-B5N1X61R.js +4 -0
- package/dist/web/assets/{docx-preview-DqVDOMmv.js → docx-preview-CWIDVNZn.js} +1 -1
- package/dist/web/assets/{edge-DTtoslQu.js → edge-BSIEsmlI.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-CXSbSUBX.js → edit-diff-preview-DeHb85DN.js} +1 -1
- package/dist/web/assets/{elixir-CIBCZ3Zi.js → elixir-BF-lrGXM.js} +1 -1
- package/dist/web/assets/{elm-BLmb7K1H.js → elm-8mCsJOeN.js} +1 -1
- package/dist/web/assets/{erb-BBY8ApRd.js → erb-Dw5PUVKa.js} +1 -1
- package/dist/web/assets/{erlang-D5Zb5_P0.js → erlang-BvjBIA6O.js} +1 -1
- package/dist/web/assets/{esm-6F8v1jLL.js → esm-Bt9OwSnU.js} +1 -1
- package/dist/web/assets/explorer-body-BxLLjthF.js +2 -0
- package/dist/web/assets/explorer-window-content-CL1Cipj3.js +1 -0
- package/dist/web/assets/extension-manager-section-BpyGq15A.js +1 -0
- package/dist/web/assets/{extension-webview-BSh6KGd7.js → extension-webview-BM8FXhuN.js} +1 -1
- package/dist/web/assets/{plus-BR0qewJI.js → eye-gWwaF4Lg.js} +1 -1
- package/dist/web/assets/eye-off-GjXVuAOn.js +1 -0
- package/dist/web/assets/files-settings-section-B0_aR1nL.js +1 -0
- package/dist/web/assets/flask-conical-tp8gyZGh.js +1 -0
- package/dist/web/assets/{fortran-fixed-form-CBdwkEUJ.js → fortran-fixed-form-CRjUJe9K.js} +1 -1
- package/dist/web/assets/{fsharp-AT4XdVYH.js → fsharp-CjUIHIHp.js} +1 -1
- package/dist/web/assets/{gdresource-D852fWBR.js → gdresource-x_NUQFrZ.js} +1 -1
- package/dist/web/assets/general-settings-section-C1EJzjhU.js +1 -0
- package/dist/web/assets/{git-commit-DWfWAyxy.js → git-commit-BOpxSbns.js} +1 -1
- package/dist/web/assets/git-log-panel-D1yGTUE_.js +1 -0
- package/dist/web/assets/{git-rebase-C6opk8gr.js → git-rebase-BW4xlK7k.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-BloZfB0Q.js +1 -0
- package/dist/web/assets/{glide-data-grid-CICFjJon.js → glide-data-grid-Cu0STKML.js} +12 -12
- package/dist/web/assets/{glimmer-js-DLi5mWYO.js → glimmer-js-CT9jrmFj.js} +1 -1
- package/dist/web/assets/{glimmer-ts-D-scFX30.js → glimmer-ts-CjQT1lxK.js} +1 -1
- package/dist/web/assets/{glsl-dbQzF4iA.js → glsl-DsFJvtg5.js} +1 -1
- package/dist/web/assets/{graphql-D1m5Wen2.js → graphql-Dhlnmkn_.js} +1 -1
- package/dist/web/assets/group-chat-tab-BfcvkRX5.js +1 -0
- package/dist/web/assets/{hack-CqYmpO7u.js → hack-BKHbsJ7u.js} +1 -1
- package/dist/web/assets/{haml-BXzKWEag.js → haml-C1Ih25Y2.js} +1 -1
- package/dist/web/assets/{handlebars-DXnrtHtq.js → handlebars-CaFitvmC.js} +1 -1
- package/dist/web/assets/{html-DhgQJ-xL.js → html-BwpKIE6V.js} +1 -1
- package/dist/web/assets/{html-derivative-xZRft-YE.js → html-derivative-uuTEquZU.js} +1 -1
- package/dist/web/assets/{http-B53mSj14.js → http-Cv4Pg5cR.js} +1 -1
- package/dist/web/assets/{hurl-CsomVy04.js → hurl-DubkI6TG.js} +1 -1
- package/dist/web/assets/{hxml-LffjWwKA.js → hxml-B9OVZFAB.js} +1 -1
- package/dist/web/assets/{image-preview-CNA6XMNS.js → image-preview-DRbZ0FA2.js} +1 -1
- package/dist/web/assets/index-B1bzKRjJ.js +52 -0
- package/dist/web/assets/index-nP3uxXvR.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-c0W8wp5o.js +1 -0
- package/dist/web/assets/{jinja-CCHURl7V.js → jinja-BHb1jyl6.js} +1 -1
- package/dist/web/assets/jira-watcher-section-DZh-Z2MK.js +1 -0
- package/dist/web/assets/{jison-7qBd8dnR.js → jison-CtpfXDzp.js} +1 -1
- package/dist/web/assets/{julia-BY9pnTcy.js → julia-TYjgpazU.js} +1 -1
- package/dist/web/assets/{just-D7wRSNRr.js → just-D27bzZuW.js} +1 -1
- package/dist/web/assets/key-round-CQpDrDxg.js +1 -0
- package/dist/web/assets/keybindings-store-CFwgcnpZ.js +1 -0
- package/dist/web/assets/keyboard-shortcuts-section-JBtcJGM3.js +1 -0
- package/dist/web/assets/{latex-RgsCae55.js → latex-D_MzopTn.js} +1 -1
- package/dist/web/assets/{liquid-CnDFzvOZ.js → liquid-BG_FG0Pe.js} +1 -1
- package/dist/web/assets/{lua-0lj5W8sm.js → lua-Bl29oC2L.js} +1 -1
- package/dist/web/assets/{markdown-renderer-dbLIvU2M.js → markdown-renderer-Bo8GgGXl.js} +3 -3
- package/dist/web/assets/markdown-renderer-DY60UZNW.js +1 -0
- package/dist/web/assets/{marko-CQgqAhbV.js → marko-D-HI7dbm.js} +1 -1
- package/dist/web/assets/{mdc-BkIcTiIy.js → mdc-y444JQTQ.js} +1 -1
- package/dist/web/assets/{media-url-DDciwvLU.js → media-url-VzecHk9g.js} +1 -1
- package/dist/web/assets/{mobile-bottom-sheet-pjcHKorA.js → mobile-bottom-sheet-BD5b7KJF.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-C59rPw7Z.js +1 -0
- package/dist/web/assets/{nextflow-DvIW68DS.js → nextflow-C5sKcldC.js} +1 -1
- package/dist/web/assets/{nginx-O-hft0gG.js → nginx-bXnEC3wm.js} +1 -1
- package/dist/web/assets/{nim-BxrR4HwQ.js → nim-pevhf4WD.js} +1 -1
- package/dist/web/assets/notification-store-Bd6L0K_Q.js +1 -0
- package/dist/web/assets/notifications-settings-section-ARQlF-6E.js +1 -0
- package/dist/web/assets/{number-overlay-editor-BoLRYuZT.js → number-overlay-editor-B7WINIW4.js} +1 -1
- package/dist/web/assets/{overview-panel-l3g1gT5e.js → overview-panel-mhN0qw6Q.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-D_BoHr_M.js +1 -0
- package/dist/web/assets/panel-store-BRrnDO_i.js +1 -0
- package/dist/web/assets/pdf-preview-CRShdbBS.js +1 -0
- package/dist/web/assets/{perl-Da-uNqmL.js → perl-B1KUtMnW.js} +1 -1
- package/dist/web/assets/{php-JMu45mEx.js → php-BGmVZBAJ.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-BaLfuEf8.js +1 -0
- package/dist/web/assets/{postgres-viewer-DstZwUai.js → postgres-viewer-BNT-4yYl.js} +3 -3
- package/dist/web/assets/power-CriQkeK5.js +1 -0
- package/dist/web/assets/ppmbot-settings-section-Bq4YAcFW.js +1 -0
- package/dist/web/assets/{process-table-kmQ2-8qJ.js → process-table-CjiXW0rg.js} +1 -1
- package/dist/web/assets/{project-store-DTUCS65m.js → project-store-BuY7rxn_.js} +1 -1
- package/dist/web/assets/proxy-settings-section-wRbiyQiA.js +3 -0
- package/dist/web/assets/{pug-CLzyQhia.js → pug-BfN8CpEH.js} +1 -1
- package/dist/web/assets/{qml-BHXfGB1l.js → qml-D6fRdLZt.js} +1 -1
- package/dist/web/assets/query-audit-section-C5RmhRSu.js +1 -0
- package/dist/web/assets/radar-KQ55EAFF-DBIZEaIU.js +1 -0
- package/dist/web/assets/{razor-BqetJLN3.js → razor-fg-9AScR.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-BF-75_03.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-view-C9KR9I9G.js +1 -0
- package/dist/web/assets/remote-desktop-readiness-gate-BnKJicB2.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-awXsNw_R.js +1 -0
- package/dist/web/assets/{rst-iQdJZ0BP.js → rst-BZgx076b.js} +1 -1
- package/dist/web/assets/{ruby-CNwzZGdH.js → ruby-iUkWDcLo.js} +1 -1
- package/dist/web/assets/{run-in-terminal-CBXmVGWa.js → run-in-terminal-bKRwuO2z.js} +1 -1
- package/dist/web/assets/{sas-BpBIT2eR.js → sas-CLXO0lZ6.js} +1 -1
- package/dist/web/assets/schedules-settings-section-BOecKJzl.js +1 -0
- package/dist/web/assets/{scss-D1MotuEp.js → scss-DQqteGaG.js} +1 -1
- package/dist/web/assets/send-Bb0jtcR6.js +1 -0
- package/dist/web/assets/{send-to-chat-DJAdlvJ8.js → send-to-chat-S8LCNX7V.js} +1 -1
- package/dist/web/assets/separator-DqGg3f9c.js +1 -0
- package/dist/web/assets/settings-body-DGi5DXY6.js +2 -0
- package/dist/web/assets/settings-store-Brjd0QnO.js +2 -0
- package/dist/web/assets/settings-tab-GM9zTRul.js +1 -0
- package/dist/web/assets/settings-window-content-Dvhxo4_H.js +1 -0
- package/dist/web/assets/{shaderlab-BNqmcPQi.js → shaderlab-CeMTqagR.js} +1 -1
- package/dist/web/assets/{shellsession-BBLOVOO-.js → shellsession-BAkquZAV.js} +1 -1
- package/dist/web/assets/{soy-BpTGo9uy.js → soy-Bxm9Ez55.js} +1 -1
- package/dist/web/assets/{sparql-D7A3yKob.js → sparql-C1phwdLc.js} +1 -1
- package/dist/web/assets/sql-query-editor-BmkGFzcL.js +1 -0
- package/dist/web/assets/sqlite-viewer-DbziVQXQ.js +1 -0
- package/dist/web/assets/{stata-B7N56ptS.js → stata-DGNMQdEb.js} +1 -1
- package/dist/web/assets/{surrealql-CTmnD-lv.js → surrealql-ByVrV320.js} +1 -1
- package/dist/web/assets/{svelte-BppwY9TR.js → svelte-CNWjIMhl.js} +1 -1
- package/dist/web/assets/system-monitor-body-CbHW5aYm.js +2 -0
- package/dist/web/assets/system-monitor-tab-C7EZLMIo.js +1 -0
- package/dist/web/assets/{system-monitor-window-content-B9Y98UW6.js → system-monitor-window-content-C_w4w81e.js} +1 -1
- package/dist/web/assets/{tab-host-window-content-C1j8zr68.js → tab-host-window-content-BSP1SEXS.js} +1 -1
- package/dist/web/assets/{tab-store-DzYSsw5a.js → tab-store-PZsP5ZwG.js} +1 -1
- package/dist/web/assets/team-member-sheet-C9N0iA1-.js +2 -0
- package/dist/web/assets/team-member-window-content-CM2QFv-s.js +1 -0
- package/dist/web/assets/{templ-CvTMKKra.js → templ-Cf0gQL4I.js} +1 -1
- package/dist/web/assets/{terminal-tab-B9I_HlES.js → terminal-tab-jWYELm8y.js} +3 -3
- package/dist/web/assets/{tex--c4POEUE.js → tex-BTIqPw_R.js} +1 -1
- package/dist/web/assets/tool-cards-jefdOWVJ.js +9 -0
- package/dist/web/assets/treemap-KZPCXAKY-DFiG9UYW.js +1 -0
- package/dist/web/assets/{ts-tags--kx7D-Hw.js → ts-tags-B8dN_Yf6.js} +1 -1
- package/dist/web/assets/{twig-UG9uMHGd.js → twig-BgemonbJ.js} +1 -1
- package/dist/web/assets/use-accounts-data-MhMl0Y4Z.js +1 -0
- package/dist/web/assets/{use-blob-url-Bdxopwwc.js → use-blob-url-Gfi69PtP.js} +1 -1
- package/dist/web/assets/use-monaco-theme-BbAd7DXr.js +1 -0
- package/dist/web/assets/{use-open-team-member-D9EOB8-i.js → use-open-team-member-CruUTqzD.js} +1 -1
- package/dist/web/assets/use-remote-desktop-display-choice-DlfMIWq3.js +1 -0
- package/dist/web/assets/{use-websocket-xOOwBdwP.js → use-websocket-Bq8X_SUI.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-0Nt-ew76.js → vendor-mermaid-BKWscKt0.js} +1 -1
- package/dist/web/assets/video-preview-BGh3B0Lu.js +1 -0
- package/dist/web/assets/{vue-jjTomlbt.js → vue-D3D4lbXz.js} +1 -1
- package/dist/web/assets/{vue-html-8KEW6-I9.js → vue-html-DYEQFAiK.js} +1 -1
- package/dist/web/assets/{vue-vine-C5tohCkU.js → vue-vine-D0OPNscN.js} +1 -1
- package/dist/web/assets/{window-pip-registry-FdZdGF7h.js → window-pip-registry-BEN0QNSW.js} +1 -1
- package/dist/web/assets/window-store-DGKf9rPG.js +1 -0
- package/dist/web/assets/ws-auth-Dawx17PM.js +1 -0
- package/dist/web/assets/{xml-ByFFosqL.js → xml-DHaWgpya.js} +1 -1
- package/dist/web/assets/{xsl-CZUwiLkj.js → xsl-DVRN8JsA.js} +1 -1
- package/dist/web/index.html +32 -55
- package/dist/web/sw.js +1 -1
- package/docs/codebase-summary.md +9 -5
- package/docs/lessons-learned.md +11 -0
- package/package.json +2 -2
- package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
- package/src/providers/codex-app-server/codex-event-mapper.ts +70 -5
- package/src/providers/codex-app-server/codex-history.ts +24 -0
- package/src/providers/codex-app-server/codex-jsonrpc-client.ts +39 -2
- package/src/providers/codex-app-server/codex-protocol.ts +24 -0
- package/src/providers/codex-app-server/codex-provider.ts +159 -17
- package/src/providers/codex-app-server/codex-rollout-items.ts +149 -0
- package/src/providers/codex-app-server/codex-skill-parser.ts +63 -0
- package/src/providers/codex-app-server/codex-usage-fetch.ts +22 -20
- package/src/providers/codex-app-server/codex-usage-source.ts +37 -0
- package/src/server/routes/chat.ts +67 -9
- package/src/server/routes/codex-accounts.ts +9 -5
- package/src/server/ws/chat.ts +46 -1
- package/src/services/claude-usage-source.ts +40 -0
- package/src/services/claude-usage.service.ts +77 -146
- package/src/services/codex-account-login.ts +123 -55
- package/src/services/codex-account.service.ts +27 -4
- package/src/services/db.service.ts +161 -20
- package/src/services/edge-forwarder.ts +191 -191
- package/src/services/fs-credential-path-guard.ts +35 -8
- package/src/services/fs-path-guard.service.ts +1 -0
- package/src/services/postgres.service.ts +144 -72
- package/src/services/provider-usage/index.ts +63 -0
- package/src/services/provider-usage/register-usage-sources.ts +18 -0
- package/src/services/provider-usage/usage-memory-cache.ts +71 -0
- package/src/services/provider-usage/usage-registry.ts +157 -0
- package/src/services/provider-usage/usage-scheduler.ts +117 -0
- package/src/services/provider-usage/usage-snapshot-store.ts +126 -0
- package/src/services/provider-usage/usage-source.ts +82 -0
- package/src/services/proxy-agent-anthropic-bridge.ts +93 -0
- package/src/services/proxy-agent-bridge.ts +100 -0
- package/src/services/proxy-agent-turn.ts +161 -0
- package/src/services/proxy-anthropic-format.ts +157 -0
- package/src/services/proxy-openai-format.ts +148 -0
- package/src/services/slash-discovery/builtin-commands.ts +13 -0
- package/src/services/slash-discovery/codex-skill-items.ts +57 -0
- package/src/services/slash-discovery/provider-skill-sigil.ts +19 -0
- package/src/services/slash-discovery/types.ts +19 -0
- package/src/services/windows-process-tree.ts +351 -351
- package/src/types/chat.ts +7 -1
- package/src/web/app.tsx +1 -7
- package/src/web/components/chat/chat-history-bar.tsx +10 -1
- package/src/web/components/chat/chat-tab.tsx +17 -1
- package/src/web/components/chat/message-input.tsx +11 -4
- package/src/web/components/chat/message-list.tsx +14 -0
- package/src/web/components/chat/slash-command-picker.tsx +22 -3
- package/src/web/components/chat/tool-cards.tsx +47 -4
- package/src/web/components/chat/usage-badge.tsx +59 -426
- package/src/web/components/floating-window/window-content-registry.ts +2 -0
- package/src/web/components/floating-window/window-store-types.ts +1 -1
- package/src/web/components/layout/command-palette.tsx +2 -2
- package/src/web/components/layout/mobile-drawer.tsx +5 -4
- package/src/web/components/layout/mobile-nav.tsx +5 -1
- package/src/web/components/layout/nav-section-rail.tsx +2 -1
- package/src/web/components/layout/project-bottom-sheet.tsx +3 -9
- package/src/web/components/layout/sidebar.tsx +0 -2
- package/src/web/components/layout/tab-pop-out-menu-item.tsx +3 -2
- package/src/web/components/settings/accounts/account-add-dialog.tsx +155 -0
- package/src/web/components/settings/accounts/account-backup-format.ts +19 -0
- package/src/web/components/settings/accounts/account-bucket-row.tsx +55 -0
- package/src/web/components/settings/accounts/account-card.tsx +151 -0
- package/src/web/components/settings/accounts/account-delete-confirm.tsx +62 -0
- package/src/web/components/settings/accounts/account-export-dialog.tsx +154 -0
- package/src/web/components/settings/accounts/account-export-simulation.tsx +196 -0
- package/src/web/components/settings/accounts/account-import-dialog.tsx +72 -0
- package/src/web/components/settings/accounts/account-profile-panel.tsx +52 -0
- package/src/web/components/{chat → settings/accounts}/account-rotation-settings.tsx +1 -1
- package/src/web/components/settings/accounts/account-token-test-dialog.tsx +147 -0
- package/src/web/components/settings/accounts/account-usage-format.ts +92 -0
- package/src/web/components/{chat/usage-pattern-chart.tsx → settings/accounts/account-usage-pattern-chart.tsx} +1 -1
- package/src/web/components/settings/accounts/accounts-pane-header.tsx +113 -0
- package/src/web/components/settings/accounts/accounts-settings-section.tsx +80 -0
- package/src/web/components/settings/accounts/claude-accounts-section.tsx +169 -0
- package/src/web/components/settings/accounts/codex-accounts-section.tsx +144 -0
- package/src/web/components/settings/accounts/codex-add-account-dialog.tsx +130 -0
- package/src/web/components/settings/accounts/codex-backup-dialog.tsx +101 -0
- package/src/web/components/settings/accounts/codex-rotation-dialog.tsx +65 -0
- package/src/web/components/settings/accounts/use-accounts-data.ts +81 -0
- package/src/web/components/settings/accounts/use-codex-accounts.ts +151 -0
- package/src/web/components/settings/ai-settings-section.tsx +14 -4
- package/src/web/components/settings/appearance-settings-section.tsx +125 -0
- package/src/web/components/settings/general-settings-section.tsx +87 -0
- package/src/web/components/settings/jira-watcher-section.tsx +34 -0
- package/src/web/components/settings/notifications-settings-section.tsx +37 -0
- package/src/web/components/settings/open-settings.ts +42 -0
- package/src/web/components/settings/resolve-open-settings-action.ts +45 -0
- package/src/web/components/settings/settings-body.tsx +110 -0
- package/src/web/components/settings/settings-categories.ts +102 -0
- package/src/web/components/settings/settings-category-list.tsx +56 -0
- package/src/web/components/settings/settings-category-rail.tsx +62 -0
- package/src/web/components/settings/settings-section-content.tsx +43 -0
- package/src/web/components/settings/settings-tab.tsx +15 -329
- package/src/web/components/settings/settings-window-content.tsx +24 -0
- package/src/web/hooks/use-chat.ts +38 -1
- package/src/web/hooks/use-global-keybindings.ts +3 -4
- package/src/web/hooks/use-url-sync.ts +30 -0
- package/src/web/hooks/use-usage.ts +23 -11
- package/src/web/lib/sidebar-tabs/tab-registry.ts +9 -9
- package/src/web/lib/slash-items-cache.ts +27 -7
- package/src/web/stores/panel-utils.ts +11 -0
- package/src/web/stores/settings-store.ts +4 -2
- package/src/web/stores/window-panel-actions.ts +1 -3
- package/src/web/stores/window-panel-persistence.ts +9 -4
- package/dist/web/assets/adaptive-context-menu-BbuRVTLn.js +0 -1
- package/dist/web/assets/ai-resource-editor-BCCOUzox.js +0 -1
- package/dist/web/assets/ai-settings-section-BEM1z7kp.js +0 -1
- package/dist/web/assets/api-client-D1CePgQ4.js +0 -1
- package/dist/web/assets/api-settings-CNtKkHqW.js +0 -1
- package/dist/web/assets/api-settings-Cubuqjsu.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-6konx-J1.js +0 -1
- package/dist/web/assets/chat-tab-CmXGsJGc.js +0 -15
- package/dist/web/assets/clipboard-B-gwJ8DF.js +0 -1
- package/dist/web/assets/code-editor-DtHXzNZ1.js +0 -7
- package/dist/web/assets/context-menu-DfWZAxQy.js +0 -1
- package/dist/web/assets/database-viewer-GVaQVMdb.js +0 -1
- package/dist/web/assets/dialog-BSfuiTkJ.js +0 -1
- package/dist/web/assets/diff-viewer-BG5_fH1E.js +0 -4
- package/dist/web/assets/explorer-body-BPFnjxYj.js +0 -2
- package/dist/web/assets/explorer-window-content-Da1T9uM4.js +0 -1
- package/dist/web/assets/extension-store-Bhu--fPX.js +0 -1
- package/dist/web/assets/external-link-B6Hl0U4X.js +0 -1
- package/dist/web/assets/eye-off-CUdzgmX8.js +0 -1
- package/dist/web/assets/file-store-6HW2Lfl4.js +0 -1
- package/dist/web/assets/git-log-panel-DNC9fV0M.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-ikUwsekd.js +0 -1
- package/dist/web/assets/group-chat-tab-DbUkcOaJ.js +0 -1
- package/dist/web/assets/index-DTqbMiVc.js +0 -52
- package/dist/web/assets/index-SFFv2-VM.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-BAgmboBp.js +0 -1
- package/dist/web/assets/input-D0ol5jW0.js +0 -1
- package/dist/web/assets/keybindings-store-BGkB72gM.js +0 -1
- package/dist/web/assets/keybindings-store-Bq6VWl5X.js +0 -1
- package/dist/web/assets/lock-CNxUGpTk.js +0 -1
- package/dist/web/assets/markdown-renderer-DEAVpo0C.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-CD_kl-jA.js +0 -1
- package/dist/web/assets/monitor-smartphone-DLZ6Q05s.js +0 -1
- package/dist/web/assets/notification-store-Dgbsw9p9.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-RVlbbDRS.js +0 -1
- package/dist/web/assets/panel-store-UOV8wrfR.js +0 -1
- package/dist/web/assets/pdf-preview-B2CJ_EKv.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-ZWb4izpk.js +0 -1
- package/dist/web/assets/play-DpEEBJTT.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-bsP5x1Bx.js +0 -1
- package/dist/web/assets/refresh-cw-BQU5g2CY.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-KKTRNjOL.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-view-C1ST4-Fm.js +0 -1
- package/dist/web/assets/remote-desktop-readiness-gate-BH3BE5wA.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-BaZJQt_N.js +0 -1
- package/dist/web/assets/rotate-ccw-CpjRo90J.js +0 -1
- package/dist/web/assets/scroll-area-lc0ZHORr.js +0 -1
- package/dist/web/assets/send-C_sLFt56.js +0 -1
- package/dist/web/assets/settings-store-zbPkG7o-.js +0 -2
- package/dist/web/assets/settings-tab-Cn-AqUP_.js +0 -1
- package/dist/web/assets/settings-tab-xyRpt2gq.js +0 -3
- package/dist/web/assets/shallow-CmPMAPte.js +0 -1
- package/dist/web/assets/sql-query-editor-B86NiZHI.js +0 -1
- package/dist/web/assets/sqlite-viewer-DB775F6C.js +0 -1
- package/dist/web/assets/switch-BmjKoIpR.js +0 -1
- package/dist/web/assets/system-monitor-body-BDxHQvy9.js +0 -2
- package/dist/web/assets/system-monitor-tab-BoTHLx6B.js +0 -1
- package/dist/web/assets/team-member-sheet-Cxz6h5Ne.js +0 -2
- package/dist/web/assets/team-member-window-content-CUSuRHCB.js +0 -1
- package/dist/web/assets/tool-cards-D3KSzd2K.js +0 -8
- package/dist/web/assets/trash-2-By4VMbC4.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-Dh1oxNdQ.js +0 -1
- package/dist/web/assets/triangle-alert-CUTURFbG.js +0 -1
- package/dist/web/assets/upload-BNlX8D07.js +0 -1
- package/dist/web/assets/use-monaco-theme-CVCye2kq.js +0 -1
- package/dist/web/assets/use-remote-desktop-display-choice-neUqyE3p.js +0 -1
- package/dist/web/assets/video-preview-DvpgBDhM.js +0 -1
- package/dist/web/assets/window-store-D0x_fxr0.js +0 -1
- package/src/web/components/chat/account-dialogs.tsx +0 -384
- package/src/web/components/settings/accounts-settings-section.tsx +0 -1090
- package/src/web/components/settings/codex-accounts-section.tsx +0 -198
- package/src/web/components/settings/telegram-settings-section.tsx +0 -113
- /package/dist/web/assets/{abap-C5DFF0s3.js → abap-h3QyH8MW.js} +0 -0
- /package/dist/web/assets/{actionscript-3-B0qyRNbc.js → actionscript-3-mkxkq-FN.js} +0 -0
- /package/dist/web/assets/{ada-bAJzplug.js → ada-DhISK_EH.js} +0 -0
- /package/dist/web/assets/{andromeeda-DUCpISy6.js → andromeeda-DnlWWesX.js} +0 -0
- /package/dist/web/assets/{apache-BhAr84Z_.js → apache-P5AK3sfA.js} +0 -0
- /package/dist/web/assets/{apex-CRv8YnNq.js → apex-CJUPehg2.js} +0 -0
- /package/dist/web/assets/{api-client-BzWM7XPR.js → api-client-oY1tC3tM.js} +0 -0
- /package/dist/web/assets/{applescript-CD-Cw8bt.js → applescript-Dx6GGbay.js} +0 -0
- /package/dist/web/assets/{apply-theme-DJ794zSQ.js → apply-theme-DxTXOAcV.js} +0 -0
- /package/dist/web/assets/{ara-BUzeQYoG.js → ara-95Kx3qKb.js} +0 -0
- /package/dist/web/assets/{asciidoc-CT2hTg-v.js → asciidoc-Dp0RbIej.js} +0 -0
- /package/dist/web/assets/{asm-CAu35JeY.js → asm-C82coUjU.js} +0 -0
- /package/dist/web/assets/{aurora-x-BeFJoIA1.js → aurora-x-BFc3zeop.js} +0 -0
- /package/dist/web/assets/{awk-Vau-DrGN.js → awk-ChjC0icr.js} +0 -0
- /package/dist/web/assets/{ayu-dark-CLe-OTsQ.js → ayu-dark-DYfUf_PB.js} +0 -0
- /package/dist/web/assets/{ayu-light-CJbQfu4M.js → ayu-light-Bh6O0plO.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-GWaKwdrx.js → ayu-mirage-DlNhHTGq.js} +0 -0
- /package/dist/web/assets/{ballerina-DWu0USI5.js → ballerina-Ceoll3Sk.js} +0 -0
- /package/dist/web/assets/{bat-_07Huw7E.js → bat-C7QS6Lfq.js} +0 -0
- /package/dist/web/assets/{beancount-EcvogrcF.js → beancount-5NMEAZgs.js} +0 -0
- /package/dist/web/assets/{berry-BBB87SY7.js → berry-BBL83Vbk.js} +0 -0
- /package/dist/web/assets/{bibtex-DbueS87A.js → bibtex-L7rPkPSG.js} +0 -0
- /package/dist/web/assets/{bicep-tcmXnUo4.js → bicep-BOwHIINh.js} +0 -0
- /package/dist/web/assets/{bird2-B2qwilIR.js → bird2-CWLsMom2.js} +0 -0
- /package/dist/web/assets/{c-Z58oivSt.js → c-CD4Ku5Cr.js} +0 -0
- /package/dist/web/assets/{c3-U40cGT9p.js → c3-CpMl-w3G.js} +0 -0
- /package/dist/web/assets/{cadence-BFcD-LyM.js → cadence-CvgF6ehN.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-CdCK2c2a.js → can-open-in-ppm-j3jh7fUo.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-RkC9AX6J.js → catppuccin-frappe-eo_dTm3F.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-Bsi4l-nO.js → catppuccin-latte-DoiMCU_7.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-B8JIdTW-.js → catppuccin-macchiato-UQxsK2Vh.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-oH8wwrDj.js → catppuccin-mocha-J0i-8RNy.js} +0 -0
- /package/dist/web/assets/{clarity-C3WNeRCR.js → clarity-DXYM8-SA.js} +0 -0
- /package/dist/web/assets/{clojure-CFoAz7u9.js → clojure-DzamsL69.js} +0 -0
- /package/dist/web/assets/{cmake-Bcsqp9yR.js → cmake-CR6RP_T_.js} +0 -0
- /package/dist/web/assets/{codeowners-DC2Z7heP.js → codeowners-D1s6-IyY.js} +0 -0
- /package/dist/web/assets/{codeql-BfG68Al5.js → codeql-DAqNWMkS.js} +0 -0
- /package/dist/web/assets/{common-lisp-Z5P-lKQe.js → common-lisp-8e-KtitB.js} +0 -0
- /package/dist/web/assets/{coq-BJslqrnv.js → coq-UEq0WUcO.js} +0 -0
- /package/dist/web/assets/{csharp-DhhZTOTs.js → csharp-wxJ0TuCm.js} +0 -0
- /package/dist/web/assets/{css-DiFIpMfE.js → css-Cerub-yB.js} +0 -0
- /package/dist/web/assets/{csv-DViLbHxI.js → csv-Bh9_WD_h.js} +0 -0
- /package/dist/web/assets/{csv-parser-B2v8MoUy.js → csv-parser-BPIDt6ni.js} +0 -0
- /package/dist/web/assets/{cue-CoG3mg2I.js → cue-rzM1ztqU.js} +0 -0
- /package/dist/web/assets/{cypher-jTxC8NAB.js → cypher-DGaTQ8m0.js} +0 -0
- /package/dist/web/assets/{d-6hKIUAbU.js → d-DbkZGuhB.js} +0 -0
- /package/dist/web/assets/{dark-plus-D_-np2Sr.js → dark-plus-BO2bzZcA.js} +0 -0
- /package/dist/web/assets/{dart-CVpxLpVn.js → dart-BDhCoqVg.js} +0 -0
- /package/dist/web/assets/{data-grid-types-Dq_H1IPa.js → data-grid-types-CdAg-4W1.js} +0 -0
- /package/dist/web/assets/{dax-BPqJ8qIY.js → dax-Bh03stWh.js} +0 -0
- /package/dist/web/assets/{desktop-u_y5_Hr5.js → desktop-BOdr_fwq.js} +0 -0
- /package/dist/web/assets/{diff-Duj1XMrd.js → diff-Bb_gTsS2.js} +0 -0
- /package/dist/web/assets/{dist-CEZ4plgH.js → dist-BUMDu0av.js} +0 -0
- /package/dist/web/assets/{dist-aDSxTR_v.js → dist-DonmFWG8.js} +0 -0
- /package/dist/web/assets/{docker-8UGSCc7N.js → docker-BDsTF5ce.js} +0 -0
- /package/dist/web/assets/{dotenv-DVnj8kyR.js → dotenv-CbCWp9Ti.js} +0 -0
- /package/dist/web/assets/{dracula-D0cEmSg7.js → dracula-Cd1fxvoX.js} +0 -0
- /package/dist/web/assets/{dracula-soft-DfGS5Yfr.js → dracula-soft-B7eXkfXG.js} +0 -0
- /package/dist/web/assets/{dream-maker-qG8kMGTF.js → dream-maker-XlzuS21R.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-iVqyMLyT.js → emacs-lisp-CXV1Ki_7.js} +0 -0
- /package/dist/web/assets/{everforest-dark-Cruygd5U.js → everforest-dark-DuqR60Dg.js} +0 -0
- /package/dist/web/assets/{everforest-light-BiJa8RHL.js → everforest-light-q4BPnenD.js} +0 -0
- /package/dist/web/assets/{fennel-H6XSEIoz.js → fennel-B-e0TX2Q.js} +0 -0
- /package/dist/web/assets/{fish-ho_7CxX6.js → fish-Bzb6-TtF.js} +0 -0
- /package/dist/web/assets/{fluent-1l5ssJTF.js → fluent-B-szH2-f.js} +0 -0
- /package/dist/web/assets/{folder-symlink-Dx1hOk8X.js → folder-symlink-fQRoG_rV.js} +0 -0
- /package/dist/web/assets/{format-bytes-gQw5wzqa.js → format-bytes-CKXk9k2d.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-Bo1x233A.js → fortran-free-form-OS6SGYC0.js} +0 -0
- /package/dist/web/assets/{gdscript-DffFMp_k.js → gdscript-FYq4OP2d.js} +0 -0
- /package/dist/web/assets/{gdshader-CvnpAiAF.js → gdshader-BpG6P8rw.js} +0 -0
- /package/dist/web/assets/{genie-2eOvAEzW.js → genie-BS9RLAna.js} +0 -0
- /package/dist/web/assets/{gherkin-DL-5OUlV.js → gherkin-B_9FdtGs.js} +0 -0
- /package/dist/web/assets/{github-dark-DrTZprgG.js → github-dark-cfaIlnBV.js} +0 -0
- /package/dist/web/assets/{github-dark-default-_mDH8IMP.js → github-dark-default-B2Wv65He.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-C48hJuLn.js → github-dark-dimmed-CtM9X76s.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-BQ-zGGNe.js → github-dark-high-contrast-DLHyk0tG.js} +0 -0
- /package/dist/web/assets/{github-light-BYc90Yx8.js → github-light-DWEI10iG.js} +0 -0
- /package/dist/web/assets/{github-light-default-Daecj4J5.js → github-light-default-DcJkK1YN.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-DoafCbsU.js → github-light-high-contrast-Bcx9iKDt.js} +0 -0
- /package/dist/web/assets/{gleam-hUWWjmnp.js → gleam-DVpiM6b2.js} +0 -0
- /package/dist/web/assets/{gn-7PJ3R70o.js → gn-B80DNc0i.js} +0 -0
- /package/dist/web/assets/{gnuplot-V-Pxck7b.js → gnuplot-D9i3MaT-.js} +0 -0
- /package/dist/web/assets/{go-ARF6DprD.js → go-CwCBf_Pt.js} +0 -0
- /package/dist/web/assets/{groovy-CKGBIPOz.js → groovy-D7mEfwmW.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-Cm9wqdI3.js → gruvbox-dark-hard-C4R4MOoH.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-Cmsd6dG8.js → gruvbox-dark-medium-CZnFC0s8.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-BBGlGGCz.js → gruvbox-dark-soft-DFcJlEBl.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-BCR7KmqG.js → gruvbox-light-hard-B6IF_1L-.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-CP32bga8.js → gruvbox-light-medium-C19AZJv2.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-qjxk8ps6.js → gruvbox-light-soft-BAnpDm9B.js} +0 -0
- /package/dist/web/assets/{haskell-C5DzwGRa.js → haskell-CsXSYXRG.js} +0 -0
- /package/dist/web/assets/{haxe-C8f_jCVv.js → haxe-B1uyiI9t.js} +0 -0
- /package/dist/web/assets/{hcl-DetJkf6E.js → hcl-DlYKn5q9.js} +0 -0
- /package/dist/web/assets/{hjson-DeZhwIdo.js → hjson-C_0VMGJJ.js} +0 -0
- /package/dist/web/assets/{hlsl-SMIDLRyX.js → hlsl-zt2PEzbg.js} +0 -0
- /package/dist/web/assets/{horizon-BMAVDxMx.js → horizon-6wQfyOK0.js} +0 -0
- /package/dist/web/assets/{horizon-bright-3BaV_VGD.js → horizon-bright-CqI2qTim.js} +0 -0
- /package/dist/web/assets/{houston-BWBbEPvb.js → houston-BljpHDoG.js} +0 -0
- /package/dist/web/assets/{hy-DcsmE-Nm.js → hy-XzuL55dw.js} +0 -0
- /package/dist/web/assets/{image-gallery-Bqb-wjNw.js → image-gallery-Cj8nd4xW.js} +0 -0
- /package/dist/web/assets/{imba-CnkgnYMf.js → imba-CqhhjBrP.js} +0 -0
- /package/dist/web/assets/{ini-BnvTdau7.js → ini-CiFDi6cY.js} +0 -0
- /package/dist/web/assets/{java-BLFACXat.js → java-OsQgTL5-.js} +0 -0
- /package/dist/web/assets/{javascript-BKcFWENk.js → javascript-qWAOScxl.js} +0 -0
- /package/dist/web/assets/{json-3AJtJADf.js → json-RiAKsaD1.js} +0 -0
- /package/dist/web/assets/{json5-DLyDVlwe.js → json5-BeCnS3H2.js} +0 -0
- /package/dist/web/assets/{jsonc-B5DgF1jW.js → jsonc-CbTW1Mka.js} +0 -0
- /package/dist/web/assets/{jsonl-CV_O71a2.js → jsonl-BLSi_669.js} +0 -0
- /package/dist/web/assets/{jsonnet-DZfPLgYz.js → jsonnet-C3xAggou.js} +0 -0
- /package/dist/web/assets/{jssm-Cr1zYOsY.js → jssm-CLdiagC9.js} +0 -0
- /package/dist/web/assets/{jsx-VN-JS2_q.js → jsx-lYE1lb50.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-D9CcT3xg.js → kanagawa-dragon-Cd1vcrpD.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-DLXsB8fr.js → kanagawa-lotus-Dw3QKtk9.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-weDs3Wjz.js → kanagawa-wave-DIq5Zv5G.js} +0 -0
- /package/dist/web/assets/{kdl-0XF56jnT.js → kdl-BfDV0825.js} +0 -0
- /package/dist/web/assets/{keyboard-DBBaoQSu.js → keyboard-DiOYrs6C.js} +0 -0
- /package/dist/web/assets/{kotlin-BPkH9vzk.js → kotlin-DONxR4wD.js} +0 -0
- /package/dist/web/assets/{kusto-DMVpADb9.js → kusto-BDP63Fh5.js} +0 -0
- /package/dist/web/assets/{laserwave-Cl6T2cGP.js → laserwave-BeBrWApL.js} +0 -0
- /package/dist/web/assets/{lean-BvwzQGl1.js → lean-DOZc0N1A.js} +0 -0
- /package/dist/web/assets/{less-DI_03xkC.js → less-C3H9NlDv.js} +0 -0
- /package/dist/web/assets/{lib-v9x_qXgI.js → lib-xrSJ4EZX.js} +0 -0
- /package/dist/web/assets/{libesm-dcbw4_18.js → libesm-DLBE59ul.js} +0 -0
- /package/dist/web/assets/{light-plus-hIiIsQN_.js → light-plus-C_kTL608.js} +0 -0
- /package/dist/web/assets/{llvm-B5hjjSWc.js → llvm-Dsp27U3P.js} +0 -0
- /package/dist/web/assets/{loader-circle-DouKgIXy.js → loader-circle-DPMrnLQ2.js} +0 -0
- /package/dist/web/assets/{log-D28raQiE.js → log-BywQaTCy.js} +0 -0
- /package/dist/web/assets/{logo-6Cdd4ASb.js → logo-BirJgciO.js} +0 -0
- /package/dist/web/assets/{luau-CK9nKpOX.js → luau-Btrz5kJB.js} +0 -0
- /package/dist/web/assets/{make-CVnxKCB6.js → make-Kl7nFQrS.js} +0 -0
- /package/dist/web/assets/{markdown-B9mMQzD5.js → markdown-qsC4P8S-.js} +0 -0
- /package/dist/web/assets/{material-theme-BZSs2o0j.js → material-theme-CC__ui3p.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-BeAQBzQ_.js → material-theme-darker-D4FxG2FZ.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-BAe0IXcs.js → material-theme-lighter-zGqiWcxn.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-CiPIf0Np.js → material-theme-ocean-CZIdTTB1.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-DJBb4_XN.js → material-theme-palenight-CEIs0GcK.js} +0 -0
- /package/dist/web/assets/{matlab-CY0dbp_s.js → matlab-Cf0aUjN9.js} +0 -0
- /package/dist/web/assets/{mdx-DU9zbF7h.js → mdx-CIsXjH86.js} +0 -0
- /package/dist/web/assets/{mermaid-UmmjGwdh.js → mermaid-B06WO9Qc.js} +0 -0
- /package/dist/web/assets/{min-dark-C59GkzOm.js → min-dark-z8fyp0FT.js} +0 -0
- /package/dist/web/assets/{min-light-B9QglrdQ.js → min-light-Dr-qesbW.js} +0 -0
- /package/dist/web/assets/{mipsasm-Dc6Jsr_D.js → mipsasm-CWHzYLcE.js} +0 -0
- /package/dist/web/assets/{mojo-D5ij-nGW.js → mojo-D9zXrKmv.js} +0 -0
- /package/dist/web/assets/{monitor-CxPV_fQI.js → monitor-C835ucWH.js} +0 -0
- /package/dist/web/assets/{monokai-QAtE_yCP.js → monokai-4b-AKOpX.js} +0 -0
- /package/dist/web/assets/{moonbit-BMtIdiTL.js → moonbit-Dl4dhOZJ.js} +0 -0
- /package/dist/web/assets/{move-BB_jMHYZ.js → move-DTYKJmXy.js} +0 -0
- /package/dist/web/assets/{narrat-BvvoKGVn.js → narrat-DnvXOS-o.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-CqxtAsnF.js → nextflow-groovy-Di8QnEXg.js} +0 -0
- /package/dist/web/assets/{night-owl-CLoE9kjt.js → night-owl-Czh0yq-H.js} +0 -0
- /package/dist/web/assets/{night-owl-light-BwIFT5Xd.js → night-owl-light-D_OpZqOR.js} +0 -0
- /package/dist/web/assets/{nix-BKlnVT9r.js → nix-2MvcjpK3.js} +0 -0
- /package/dist/web/assets/{nord-B7R1KRAK.js → nord-CG_r4cyk.js} +0 -0
- /package/dist/web/assets/{nushell-CzUme-NJ.js → nushell-DINskMcU.js} +0 -0
- /package/dist/web/assets/{objective-c-D-UKKiOc.js → objective-c-Dv7BIicR.js} +0 -0
- /package/dist/web/assets/{objective-cpp-BucWn4Fx.js → objective-cpp-CpqsCxPb.js} +0 -0
- /package/dist/web/assets/{ocaml-EJCNXMGo.js → ocaml-DwTsYSmW.js} +0 -0
- /package/dist/web/assets/{odin-CEjnRU_3.js → odin-G-4O4k4t.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-Bv469NX5.js → one-dark-pro-13Pv5SjI.js} +0 -0
- /package/dist/web/assets/{one-light-BlzO5RWI.js → one-light-Bi2e86mS.js} +0 -0
- /package/dist/web/assets/{openscad-Czl6alLw.js → openscad-D0WsOTij.js} +0 -0
- /package/dist/web/assets/{pascal-BI9fLvG4.js → pascal-DmDStuXr.js} +0 -0
- /package/dist/web/assets/{pkl-ChQLsyjU.js → pkl-Bl6Qjtuo.js} +0 -0
- /package/dist/web/assets/{plastic-DGL3mtdL.js → plastic-UeSVSjTI.js} +0 -0
- /package/dist/web/assets/{plsql-BJDjqcWp.js → plsql-DreFC689.js} +0 -0
- /package/dist/web/assets/{po-DK5O3OpF.js → po-ZIjccxsX.js} +0 -0
- /package/dist/web/assets/{poimandres-CnuqZT4T.js → poimandres-CvQHJPrI.js} +0 -0
- /package/dist/web/assets/{polar-DCsUxSsQ.js → polar-BrMB0Kgh.js} +0 -0
- /package/dist/web/assets/{portal-container-context-D-495m5C.js → portal-container-context-a399Hd9F.js} +0 -0
- /package/dist/web/assets/{postcss-8UjdFmis.js → postcss-pgUsil1T.js} +0 -0
- /package/dist/web/assets/{powerquery-CAp0CGQj.js → powerquery-CTsZkCg_.js} +0 -0
- /package/dist/web/assets/{powershell-CbBsKZJP.js → powershell-CcwVuBAp.js} +0 -0
- /package/dist/web/assets/{prisma-BnNpXCJN.js → prisma-spjnAI5W.js} +0 -0
- /package/dist/web/assets/{prolog-CC-l9E8Y.js → prolog-ChCkZpDO.js} +0 -0
- /package/dist/web/assets/{proto-CV_1k2rL.js → proto-wVGqK4gB.js} +0 -0
- /package/dist/web/assets/{puppet-2D8HU2bv.js → puppet-CED7iwPQ.js} +0 -0
- /package/dist/web/assets/{purescript-BEJAORgU.js → purescript-u9lGiQKV.js} +0 -0
- /package/dist/web/assets/{python-BBdbb7nn.js → python-DeqTx6ef.js} +0 -0
- /package/dist/web/assets/{qmldir-D5ZYI4Ie.js → qmldir-BH1uoPrX.js} +0 -0
- /package/dist/web/assets/{qss-BOJVGyXE.js → qss-CUVKA_13.js} +0 -0
- /package/dist/web/assets/{r-B5dlEtkj.js → r-BqdPzqYH.js} +0 -0
- /package/dist/web/assets/{racket-BUAEygJ6.js → racket-C2eTgPN3.js} +0 -0
- /package/dist/web/assets/{raku-BG0Ss0ID.js → raku-uAay1sWx.js} +0 -0
- /package/dist/web/assets/{react-B549sK_T.js → react-X4jUntEf.js} +0 -0
- /package/dist/web/assets/{red-C5yyQbtG.js → red-DTZP1ZfC.js} +0 -0
- /package/dist/web/assets/{reg-DHoBWtLf.js → reg-Cdk3YsxY.js} +0 -0
- /package/dist/web/assets/{regexp-DDtJrlKv.js → regexp-Bpa2aS7K.js} +0 -0
- /package/dist/web/assets/{rel-CR6WJDRD.js → rel-bNsb1-3L.js} +0 -0
- /package/dist/web/assets/{resolve-theme-4fexHWl6.js → resolve-theme-DQk_YcsT.js} +0 -0
- /package/dist/web/assets/{riscv-2V9tC-nx.js → riscv-DSaubByW.js} +0 -0
- /package/dist/web/assets/{ron-QLTmqGUw.js → ron-DbQzYM6i.js} +0 -0
- /package/dist/web/assets/{rose-pine-be0__X3A.js → rose-pine-C7RsprTu.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-n_WQJwsW.js → rose-pine-dawn-VP976YzL.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-t2aLtzgB.js → rose-pine-moon-XHZNhOqd.js} +0 -0
- /package/dist/web/assets/{rosmsg-Ce1JD8vt.js → rosmsg-BVQlx0Lj.js} +0 -0
- /package/dist/web/assets/{rust-5fHH-ZoW.js → rust-VHaQ3rh3.js} +0 -0
- /package/dist/web/assets/{sass-DPmGFiOJ.js → sass-CO-kMkwD.js} +0 -0
- /package/dist/web/assets/{save-DYLiVzU8.js → save-CipGrG1k.js} +0 -0
- /package/dist/web/assets/{scala-BRMVFbZF.js → scala-cY0GXkiz.js} +0 -0
- /package/dist/web/assets/{scheme-BMSJWevF.js → scheme-D4LNZE0X.js} +0 -0
- /package/dist/web/assets/{sdbl-DTZ-pEHI.js → sdbl-Bh2Fd2cn.js} +0 -0
- /package/dist/web/assets/{shellscript-6-9yg5Cz.js → shellscript-KKclmCnt.js} +0 -0
- /package/dist/web/assets/{shield-check-CUI36aSc.js → shield-check-BsG3LV8i.js} +0 -0
- /package/dist/web/assets/{shield-off-GdkkVhb3.js → shield-off-7jKWpJBD.js} +0 -0
- /package/dist/web/assets/{slack-dark-DKJgiR7e.js → slack-dark-D6YQ-fqf.js} +0 -0
- /package/dist/web/assets/{slack-ochin-WjehVgyK.js → slack-ochin-CDf66CDj.js} +0 -0
- /package/dist/web/assets/{smalltalk-BChf4SN1.js → smalltalk-D2OH_QIl.js} +0 -0
- /package/dist/web/assets/{snazzy-light-C1WAwOx6.js → snazzy-light-CQeF8G1K.js} +0 -0
- /package/dist/web/assets/{solarized-dark-BxREZrGx.js → solarized-dark-LTPf1iLZ.js} +0 -0
- /package/dist/web/assets/{solarized-light-DG29B1pR.js → solarized-light-Ose1n88k.js} +0 -0
- /package/dist/web/assets/{solidity-bDbtGwdR.js → solidity-lFuOMHki.js} +0 -0
- /package/dist/web/assets/{splunk-Ceqx5njI.js → splunk-Bov-sB5S.js} +0 -0
- /package/dist/web/assets/{sql-OwMEKbz8.js → sql-BKyZ6wmk.js} +0 -0
- /package/dist/web/assets/{ssh-config-WAR3lu2k.js → ssh-config-CqJoMGMb.js} +0 -0
- /package/dist/web/assets/{stylus-Cjmoz3d8.js → stylus-Bf5pWRLI.js} +0 -0
- /package/dist/web/assets/{swift-S_ZSBG1q.js → swift-D5d1hn_u.js} +0 -0
- /package/dist/web/assets/{synthwave-84-DiUeWMSh.js → synthwave-84-B4c6YAgO.js} +0 -0
- /package/dist/web/assets/{system-verilog-RRjqPjUV.js → system-verilog-D7fXyDsI.js} +0 -0
- /package/dist/web/assets/{systemd-BD3SkXoU.js → systemd-oNagzlBK.js} +0 -0
- /package/dist/web/assets/{table-D5Q4ap4W.js → table-CRJsmfeg.js} +0 -0
- /package/dist/web/assets/{talonscript-DWefISOm.js → talonscript-C6Nqm9Dm.js} +0 -0
- /package/dist/web/assets/{tasl-DCjSS-09.js → tasl-CaWy-cBX.js} +0 -0
- /package/dist/web/assets/{tcl-DTYqT_66.js → tcl-C435P5Mq.js} +0 -0
- /package/dist/web/assets/{terraform-CkbP5QnR.js → terraform-CVDxqdPf.js} +0 -0
- /package/dist/web/assets/{text-wrap-DBvQD3kc.js → text-wrap-oiekm5SB.js} +0 -0
- /package/dist/web/assets/{tokyo-night-qVSqO9xy.js → tokyo-night-Uhs17tQ3.js} +0 -0
- /package/dist/web/assets/{toml-D9F5Osqs.js → toml-j6fPOJ6P.js} +0 -0
- /package/dist/web/assets/{tsv-C5tpHoxm.js → tsv-h78O6xrL.js} +0 -0
- /package/dist/web/assets/{tsx-CMWkGtGm.js → tsx-Bol-vCrQ.js} +0 -0
- /package/dist/web/assets/{turtle-Cn4z3xOi.js → turtle-Dw8eFf04.js} +0 -0
- /package/dist/web/assets/{typescript-DSyAEWsn.js → typescript-Dtz7DPci.js} +0 -0
- /package/dist/web/assets/{typespec-B93Qap7y.js → typespec-BIOQ7dMP.js} +0 -0
- /package/dist/web/assets/{typst-DtlOmFlX.js → typst-CoaGMjzu.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-B9UZNwSm.js → use-is-mobile-CYW3FJFE.js} +0 -0
- /package/dist/web/assets/{use-visual-viewport-Sfb6CZ80.js → use-visual-viewport-rnvuooQZ.js} +0 -0
- /package/dist/web/assets/{utils-QHe_Q6UF.js → utils-C9OjCrou.js} +0 -0
- /package/dist/web/assets/{v-Dfzf-szS.js → v-BoqFdpJ7.js} +0 -0
- /package/dist/web/assets/{vala-CyiQZQ9f.js → vala-COBpNnCC.js} +0 -0
- /package/dist/web/assets/{vb-C7DGSldd.js → vb-DxI86znh.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-BHKF_Nsf.js → vendor-xterm-BaMOj65g.js} +0 -0
- /package/dist/web/assets/{verilog-kF-hClY2.js → verilog-DcTAamuQ.js} +0 -0
- /package/dist/web/assets/{vesper-BmKcADuz.js → vesper-DO298JSv.js} +0 -0
- /package/dist/web/assets/{vhdl-CDnb16KJ.js → vhdl-Dq-bDVSN.js} +0 -0
- /package/dist/web/assets/{viml-B8cs6Ady.js → viml-zHTRWuQh.js} +0 -0
- /package/dist/web/assets/{vitesse-black-BR6o9Gto.js → vitesse-black-jlYMJCBf.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-Dye14-KB.js → vitesse-dark-DS0sUlSZ.js} +0 -0
- /package/dist/web/assets/{vitesse-light-BLpswIxf.js → vitesse-light-HSeZ2YhG.js} +0 -0
- /package/dist/web/assets/{vyper-DU51Z97W.js → vyper-BQfKVO3M.js} +0 -0
- /package/dist/web/assets/{wasm-ChtccNfv.js → wasm-B1xp9bLp.js} +0 -0
- /package/dist/web/assets/{wasm-CVqlJAR2.js → wasm-B6mCuI8h.js} +0 -0
- /package/dist/web/assets/{wenyan-DhCa3hCn.js → wenyan-CfpS05sP.js} +0 -0
- /package/dist/web/assets/{wgsl-Bj1Ec4vv.js → wgsl-14GDsWRD.js} +0 -0
- /package/dist/web/assets/{wikitext-C90DHNa0.js → wikitext-Ccbq5EVX.js} +0 -0
- /package/dist/web/assets/{wit-DUgbOD7Z.js → wit-C19hb3R5.js} +0 -0
- /package/dist/web/assets/{wolfram-BgwUqD1I.js → wolfram-B-ZSwGwP.js} +0 -0
- /package/dist/web/assets/{x-DiOUR_mp.js → x-YDu4m2Iq.js} +0 -0
- /package/dist/web/assets/{yaml-DEQulj-8.js → yaml-mw_JUeio.js} +0 -0
- /package/dist/web/assets/{zenscript-C7Jp7TgT.js → zenscript-WbzDRjvF.js} +0 -0
- /package/dist/web/assets/{zig-9x4qXYLg.js → zig-F0vvImTJ.js} +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Left pane of the split layout: every category visible at once, grouped.
|
|
3
|
+
*
|
|
4
|
+
* Nothing collapses and nothing hides behind a disclosure — the whole point of the split
|
|
5
|
+
* layout is that a wide container can afford to show the full tree, so switching panes is one
|
|
6
|
+
* click from anywhere.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
10
|
+
import { cn } from "@/lib/utils";
|
|
11
|
+
import {
|
|
12
|
+
SETTINGS_GROUPS, settingsCategoriesInGroup,
|
|
13
|
+
type SettingsCategoryId,
|
|
14
|
+
} from "./settings-categories";
|
|
15
|
+
|
|
16
|
+
interface SettingsCategoryRailProps {
|
|
17
|
+
active: SettingsCategoryId;
|
|
18
|
+
onSelect: (id: SettingsCategoryId) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function SettingsCategoryRail({ active, onSelect }: SettingsCategoryRailProps) {
|
|
22
|
+
return (
|
|
23
|
+
<ScrollArea className="h-full">
|
|
24
|
+
<nav className="p-2 space-y-4" aria-label="Settings categories">
|
|
25
|
+
{SETTINGS_GROUPS.map((group) => {
|
|
26
|
+
const categories = settingsCategoriesInGroup(group.id);
|
|
27
|
+
if (categories.length === 0) return null;
|
|
28
|
+
return (
|
|
29
|
+
<div key={group.id} className="space-y-1">
|
|
30
|
+
{group.label && (
|
|
31
|
+
<h3 className="px-2 pt-1 text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
|
32
|
+
{group.label}
|
|
33
|
+
</h3>
|
|
34
|
+
)}
|
|
35
|
+
{categories.map((cat) => {
|
|
36
|
+
const Icon = cat.icon;
|
|
37
|
+
const isActive = cat.id === active;
|
|
38
|
+
return (
|
|
39
|
+
<button
|
|
40
|
+
key={cat.id}
|
|
41
|
+
onClick={() => onSelect(cat.id)}
|
|
42
|
+
data-testid={`settings-rail-${cat.id}`}
|
|
43
|
+
aria-current={isActive ? "page" : undefined}
|
|
44
|
+
className={cn(
|
|
45
|
+
"w-full flex items-center gap-2.5 px-2.5 py-2 rounded-md text-left cursor-pointer transition-colors",
|
|
46
|
+
isActive
|
|
47
|
+
? "bg-accent text-accent-foreground"
|
|
48
|
+
: "hover:bg-accent/50 active:bg-accent",
|
|
49
|
+
)}
|
|
50
|
+
>
|
|
51
|
+
<Icon className={cn("size-4 shrink-0", isActive ? "text-foreground" : "text-muted-foreground")} />
|
|
52
|
+
<span className="text-sm truncate">{cat.label}</span>
|
|
53
|
+
</button>
|
|
54
|
+
);
|
|
55
|
+
})}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
})}
|
|
59
|
+
</nav>
|
|
60
|
+
</ScrollArea>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps a settings category to the component that fills the content pane.
|
|
3
|
+
*
|
|
4
|
+
* The only coupling point between the settings shell and the individual panes: adding a
|
|
5
|
+
* category means adding an entry here plus one in `settings-categories.ts`, and neither the
|
|
6
|
+
* rail, the stacked list, nor the window frame changes. Entries are lazy so opening Settings
|
|
7
|
+
* does not pull every pane's dependencies (charts, editors, cron pickers) into the bundle.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Suspense, lazy, type ComponentType, type LazyExoticComponent } from "react";
|
|
11
|
+
import { Loader2 } from "lucide-react";
|
|
12
|
+
import type { SettingsCategoryId } from "./settings-categories";
|
|
13
|
+
|
|
14
|
+
const SECTIONS: Record<SettingsCategoryId, LazyExoticComponent<ComponentType>> = {
|
|
15
|
+
general: lazy(() => import("./general-settings-section").then((m) => ({ default: m.GeneralSettingsSection }))),
|
|
16
|
+
appearance: lazy(() => import("./appearance-settings-section").then((m) => ({ default: m.AppearanceSettingsSection }))),
|
|
17
|
+
"ai-provider": lazy(() => import("./ai-settings-section").then((m) => ({ default: m.AISettingsSection }))),
|
|
18
|
+
accounts: lazy(() => import("./accounts/accounts-settings-section").then((m) => ({ default: m.AccountsSettingsSection }))),
|
|
19
|
+
ppmbot: lazy(() => import("./ppmbot-settings-section").then((m) => ({ default: m.PPMBotSettingsSection }))),
|
|
20
|
+
notifications: lazy(() => import("./notifications-settings-section").then((m) => ({ default: m.NotificationsSettingsSection }))),
|
|
21
|
+
jira: lazy(() => import("./jira-watcher-section").then((m) => ({ default: m.JiraWatcherSection }))),
|
|
22
|
+
extensions: lazy(() => import("./extension-manager-section").then((m) => ({ default: m.ExtensionManagerSection }))),
|
|
23
|
+
proxy: lazy(() => import("./proxy-settings-section").then((m) => ({ default: m.ProxySettingsSection }))),
|
|
24
|
+
schedules: lazy(() => import("./schedules/schedules-settings-section").then((m) => ({ default: m.SchedulesSettingsSection }))),
|
|
25
|
+
shortcuts: lazy(() => import("./keyboard-shortcuts-section").then((m) => ({ default: m.KeyboardShortcutsSection }))),
|
|
26
|
+
files: lazy(() => import("./files-settings-section").then((m) => ({ default: m.FilesSettingsSection }))),
|
|
27
|
+
"query-audit": lazy(() => import("./query-audit-section").then((m) => ({ default: m.QueryAuditSection }))),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function SettingsSectionContent({ category }: { category: SettingsCategoryId }) {
|
|
31
|
+
const Section = SECTIONS[category];
|
|
32
|
+
return (
|
|
33
|
+
<Suspense
|
|
34
|
+
fallback={
|
|
35
|
+
<div className="flex items-center justify-center py-12">
|
|
36
|
+
<Loader2 className="size-5 animate-spin text-muted-foreground" />
|
|
37
|
+
</div>
|
|
38
|
+
}
|
|
39
|
+
>
|
|
40
|
+
<Section />
|
|
41
|
+
</Suspense>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -1,329 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import { ProxySettingsSection } from "./proxy-settings-section";
|
|
17
|
-
import { ExtensionManagerSection } from "./extension-manager-section";
|
|
18
|
-
import { PPMBotSettingsSection } from "./ppmbot-settings-section";
|
|
19
|
-
import { ChangePasswordSection } from "./change-password-section";
|
|
20
|
-
import { FilesSettingsSection } from "./files-settings-section";
|
|
21
|
-
import { SchedulesSettingsSection } from "./schedules/schedules-settings-section";
|
|
22
|
-
import { ThemeManagerSection } from "./theme-manager-section";
|
|
23
|
-
import { QueryAuditSection } from "./query-audit-section";
|
|
24
|
-
import { ThemeGrid } from "./theme-grid";
|
|
25
|
-
import { THEME_MODE_OPTIONS } from "@/theme/theme-mode-options";
|
|
26
|
-
|
|
27
|
-
const TAB_STYLE_OPTIONS: { value: EditorTabStyle; label: string }[] = [
|
|
28
|
-
{ value: "default", label: "Default" },
|
|
29
|
-
{ value: "boxed", label: "Boxed" },
|
|
30
|
-
{ value: "pill", label: "Pill" },
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
const EXPLORER_SKIN_OPTIONS: { value: ExplorerSkinPref; label: string }[] = [
|
|
34
|
-
{ value: "auto", label: "Auto" },
|
|
35
|
-
{ value: "windows", label: "Windows" },
|
|
36
|
-
{ value: "macos", label: "macOS" },
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
type SettingsCategory = "ai" | "notifications" | "clawbot" | "schedules" | "jira" | "proxy" | "shortcuts" | "extensions" | "files" | "queryAudit";
|
|
40
|
-
|
|
41
|
-
const CATEGORIES: { value: SettingsCategory; label: string; subtitle: string; icon: React.ElementType }[] = [
|
|
42
|
-
{ value: "ai", label: "AI Provider", subtitle: "Model, execution mode, limits", icon: Bot },
|
|
43
|
-
{ value: "notifications", label: "Notifications", subtitle: "Push & Telegram alerts", icon: BellRing },
|
|
44
|
-
{ value: "clawbot", label: "PPMBot", subtitle: "Telegram AI bot", icon: Bot },
|
|
45
|
-
{ value: "schedules", label: "Scheduled Agents", subtitle: "Run Claude on a cron schedule", icon: CalendarClock },
|
|
46
|
-
// Jira is now a toggle, not a full settings category
|
|
47
|
-
{ value: "proxy", label: "API Proxy", subtitle: "Expose accounts as Anthropic API", icon: Globe },
|
|
48
|
-
{ value: "shortcuts", label: "Keyboard Shortcuts", subtitle: "Customize key bindings", icon: Keyboard },
|
|
49
|
-
{ value: "extensions", label: "Extensions", subtitle: "Install and manage extensions", icon: Puzzle },
|
|
50
|
-
{ value: "files", label: "File Filters", subtitle: "Exclude patterns, ignore files", icon: FolderSearch },
|
|
51
|
-
{ value: "queryAudit", label: "Query Audit Log", subtitle: "SQL history retention and size", icon: DatabaseZap },
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
export function SettingsTab() {
|
|
55
|
-
const { theme, setTheme, deviceName, setDeviceName, version, jiraEnabled, setJiraEnabled, tabWrap, toggleTabWrap, editorTabStyle, setEditorTabStyle, explorerSkin, setExplorerSkin } = useSettingsStore(useShallow((s) => ({ theme: s.themeMode, setTheme: s.setThemeMode, deviceName: s.deviceName, setDeviceName: s.setDeviceName, version: s.version, jiraEnabled: s.jiraEnabled, setJiraEnabled: s.setJiraEnabled, tabWrap: s.tabWrap, toggleTabWrap: s.toggleTabWrap, editorTabStyle: s.editorTabStyle, setEditorTabStyle: s.setEditorTabStyle, explorerSkin: s.explorerSkin, setExplorerSkin: s.setExplorerSkin })));
|
|
56
|
-
const [activeCategory, setActiveCategory] = useState<SettingsCategory | null>(null);
|
|
57
|
-
const [nameInput, setNameInput] = useState(deviceName ?? "");
|
|
58
|
-
const [nameSaving, setNameSaving] = useState(false);
|
|
59
|
-
const [nameSaved, setNameSaved] = useState(false);
|
|
60
|
-
const savedTimer = useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
61
|
-
const nameChanged = nameInput.trim() !== (deviceName ?? "");
|
|
62
|
-
|
|
63
|
-
const handleSaveName = useCallback(async () => {
|
|
64
|
-
if (!nameChanged) return;
|
|
65
|
-
setNameSaving(true);
|
|
66
|
-
try {
|
|
67
|
-
await setDeviceName(nameInput);
|
|
68
|
-
setNameSaved(true);
|
|
69
|
-
clearTimeout(savedTimer.current);
|
|
70
|
-
savedTimer.current = setTimeout(() => setNameSaved(false), 2000);
|
|
71
|
-
} finally {
|
|
72
|
-
setNameSaving(false);
|
|
73
|
-
}
|
|
74
|
-
}, [nameInput, nameChanged, setDeviceName]);
|
|
75
|
-
|
|
76
|
-
// Detail view for a category
|
|
77
|
-
if (activeCategory) {
|
|
78
|
-
const cat = CATEGORIES.find((c) => c.value === activeCategory)!;
|
|
79
|
-
const Icon = cat.icon;
|
|
80
|
-
return (
|
|
81
|
-
<div className="h-full w-full flex flex-col">
|
|
82
|
-
{/* Detail header with back */}
|
|
83
|
-
<div className="shrink-0 px-2 pt-3 pb-1 flex items-center gap-1">
|
|
84
|
-
<Button
|
|
85
|
-
variant="ghost"
|
|
86
|
-
size="icon"
|
|
87
|
-
className="size-8 cursor-pointer shrink-0"
|
|
88
|
-
onClick={() => setActiveCategory(null)}
|
|
89
|
-
>
|
|
90
|
-
<ArrowLeft className="size-4" />
|
|
91
|
-
</Button>
|
|
92
|
-
<Icon className="size-4 text-muted-foreground shrink-0" />
|
|
93
|
-
<h2 className="text-sm font-semibold truncate">{cat.label}</h2>
|
|
94
|
-
</div>
|
|
95
|
-
<Separator />
|
|
96
|
-
{/* Detail content */}
|
|
97
|
-
<ScrollArea className="flex-1 min-h-0">
|
|
98
|
-
<div className="p-3">
|
|
99
|
-
{activeCategory === "ai" && <AISettingsSection compact />}
|
|
100
|
-
{activeCategory === "notifications" && <NotificationsContent />}
|
|
101
|
-
{activeCategory === "clawbot" && <PPMBotSettingsSection />}
|
|
102
|
-
{activeCategory === "schedules" && <SchedulesSettingsSection />}
|
|
103
|
-
{/* Jira is now a sidebar tab with a toggle below */}
|
|
104
|
-
{activeCategory === "proxy" && <ProxySettingsSection />}
|
|
105
|
-
{activeCategory === "shortcuts" && <KeyboardShortcutsSection />}
|
|
106
|
-
{activeCategory === "extensions" && <ExtensionManagerSection />}
|
|
107
|
-
{activeCategory === "files" && <FilesSettingsSection />}
|
|
108
|
-
{activeCategory === "queryAudit" && <QueryAuditSection />}
|
|
109
|
-
</div>
|
|
110
|
-
</ScrollArea>
|
|
111
|
-
</div>
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Main settings list
|
|
116
|
-
return (
|
|
117
|
-
<div className="h-full w-full flex flex-col">
|
|
118
|
-
<div className="shrink-0 px-3 pt-3 pb-1">
|
|
119
|
-
<h2 className="text-sm font-semibold">Settings</h2>
|
|
120
|
-
</div>
|
|
121
|
-
<ScrollArea className="flex-1 min-h-0">
|
|
122
|
-
<div className="p-3 space-y-4">
|
|
123
|
-
{/* Quick: Device Name */}
|
|
124
|
-
<section className="space-y-2">
|
|
125
|
-
<h3 className="text-xs font-medium text-muted-foreground">Device Name</h3>
|
|
126
|
-
<div className="flex gap-1.5">
|
|
127
|
-
<Input
|
|
128
|
-
value={nameInput}
|
|
129
|
-
onChange={(e) => setNameInput(e.target.value)}
|
|
130
|
-
onKeyDown={(e) => { if (e.key === "Enter") handleSaveName(); }}
|
|
131
|
-
placeholder="My Device"
|
|
132
|
-
className="h-8 text-xs flex-1"
|
|
133
|
-
maxLength={100}
|
|
134
|
-
/>
|
|
135
|
-
<Button
|
|
136
|
-
variant={nameSaved ? "default" : "outline"}
|
|
137
|
-
size="sm"
|
|
138
|
-
className="h-8 text-xs px-3 cursor-pointer"
|
|
139
|
-
disabled={!nameChanged || nameSaving}
|
|
140
|
-
onClick={handleSaveName}
|
|
141
|
-
>
|
|
142
|
-
{nameSaving ? "..." : nameSaved ? <Check className="size-3.5" /> : "Save"}
|
|
143
|
-
</Button>
|
|
144
|
-
</div>
|
|
145
|
-
<p className="text-[11px] text-muted-foreground">
|
|
146
|
-
Shown in page title and synced to PPM Cloud.
|
|
147
|
-
</p>
|
|
148
|
-
</section>
|
|
149
|
-
|
|
150
|
-
{/* Security: Change Password */}
|
|
151
|
-
<ChangePasswordSection />
|
|
152
|
-
|
|
153
|
-
{/* Theme — visual grid of the 6 built-in styles */}
|
|
154
|
-
<section className="space-y-2">
|
|
155
|
-
<h3 className="text-xs font-medium text-muted-foreground">Theme</h3>
|
|
156
|
-
<ThemeGrid />
|
|
157
|
-
{/* Mode override (applies within the selected style; System follows OS) */}
|
|
158
|
-
<div className="flex gap-1.5 pt-1">
|
|
159
|
-
{THEME_MODE_OPTIONS.map((opt) => {
|
|
160
|
-
const Icon = opt.icon;
|
|
161
|
-
return (
|
|
162
|
-
<Button
|
|
163
|
-
key={opt.value}
|
|
164
|
-
variant={theme === opt.value ? "default" : "outline"}
|
|
165
|
-
size="sm"
|
|
166
|
-
onClick={() => setTheme(opt.value)}
|
|
167
|
-
className={cn(
|
|
168
|
-
"flex-1 gap-1.5 text-xs h-8 cursor-pointer",
|
|
169
|
-
theme === opt.value && "ring-2 ring-primary",
|
|
170
|
-
)}
|
|
171
|
-
>
|
|
172
|
-
<Icon className="size-3.5" />
|
|
173
|
-
{opt.label}
|
|
174
|
-
</Button>
|
|
175
|
-
);
|
|
176
|
-
})}
|
|
177
|
-
</div>
|
|
178
|
-
</section>
|
|
179
|
-
|
|
180
|
-
{/* Imported themes (VSCode import) */}
|
|
181
|
-
<ThemeManagerSection />
|
|
182
|
-
|
|
183
|
-
{/* Jira toggle */}
|
|
184
|
-
<section className="space-y-1">
|
|
185
|
-
<div className="flex items-center justify-between">
|
|
186
|
-
<div className="flex items-center gap-2">
|
|
187
|
-
<Bug className="size-4 text-muted-foreground" />
|
|
188
|
-
<div>
|
|
189
|
-
<p className="text-xs font-medium">Jira Watcher</p>
|
|
190
|
-
<p className="text-[11px] text-muted-foreground">Auto-debug Jira tickets</p>
|
|
191
|
-
</div>
|
|
192
|
-
</div>
|
|
193
|
-
<Switch checked={jiraEnabled} onCheckedChange={setJiraEnabled} />
|
|
194
|
-
</div>
|
|
195
|
-
</section>
|
|
196
|
-
|
|
197
|
-
{/* Wrap Tabs toggle */}
|
|
198
|
-
<section className="space-y-1">
|
|
199
|
-
<div className="flex items-center justify-between">
|
|
200
|
-
<div className="flex items-center gap-2">
|
|
201
|
-
<WrapText className="size-4 text-muted-foreground" />
|
|
202
|
-
<div>
|
|
203
|
-
<p className="text-xs font-medium">Wrap Tabs</p>
|
|
204
|
-
<p className="text-[11px] text-muted-foreground">Stack tabs in rows instead of scrolling</p>
|
|
205
|
-
</div>
|
|
206
|
-
</div>
|
|
207
|
-
<Switch checked={tabWrap} onCheckedChange={toggleTabWrap} />
|
|
208
|
-
</div>
|
|
209
|
-
</section>
|
|
210
|
-
|
|
211
|
-
{/* Tab Style */}
|
|
212
|
-
<section className="space-y-2">
|
|
213
|
-
<h3 className="text-xs font-medium text-muted-foreground">Tab Style</h3>
|
|
214
|
-
<div className="flex gap-1.5">
|
|
215
|
-
{TAB_STYLE_OPTIONS.map((opt) => (
|
|
216
|
-
<Button
|
|
217
|
-
key={opt.value}
|
|
218
|
-
variant={editorTabStyle === opt.value ? "default" : "outline"}
|
|
219
|
-
size="sm"
|
|
220
|
-
onClick={() => setEditorTabStyle(opt.value)}
|
|
221
|
-
className={cn(
|
|
222
|
-
"flex-1 text-xs h-8 cursor-pointer",
|
|
223
|
-
editorTabStyle === opt.value && "ring-2 ring-primary",
|
|
224
|
-
)}
|
|
225
|
-
>
|
|
226
|
-
{opt.label}
|
|
227
|
-
</Button>
|
|
228
|
-
))}
|
|
229
|
-
</div>
|
|
230
|
-
</section>
|
|
231
|
-
|
|
232
|
-
{/* Explorer Skin — chrome the OS File Explorer window wears; Auto follows platform */}
|
|
233
|
-
<section className="space-y-2">
|
|
234
|
-
<h3 className="text-xs font-medium text-muted-foreground">Explorer Skin</h3>
|
|
235
|
-
<div className="flex gap-1.5">
|
|
236
|
-
{EXPLORER_SKIN_OPTIONS.map((opt) => (
|
|
237
|
-
<Button
|
|
238
|
-
key={opt.value}
|
|
239
|
-
variant={explorerSkin === opt.value ? "default" : "outline"}
|
|
240
|
-
size="sm"
|
|
241
|
-
onClick={() => setExplorerSkin(opt.value)}
|
|
242
|
-
className={cn(
|
|
243
|
-
"flex-1 text-xs h-8 cursor-pointer",
|
|
244
|
-
explorerSkin === opt.value && "ring-2 ring-primary",
|
|
245
|
-
)}
|
|
246
|
-
>
|
|
247
|
-
{opt.label}
|
|
248
|
-
</Button>
|
|
249
|
-
))}
|
|
250
|
-
</div>
|
|
251
|
-
</section>
|
|
252
|
-
|
|
253
|
-
<Separator />
|
|
254
|
-
|
|
255
|
-
{/* Category navigation list */}
|
|
256
|
-
<nav className="space-y-1" aria-label="Settings categories">
|
|
257
|
-
{CATEGORIES.map((cat) => {
|
|
258
|
-
const Icon = cat.icon;
|
|
259
|
-
return (
|
|
260
|
-
<button
|
|
261
|
-
key={cat.value}
|
|
262
|
-
onClick={() => setActiveCategory(cat.value)}
|
|
263
|
-
className="w-full flex items-center gap-3 px-2.5 py-2.5 rounded-lg hover:bg-accent/50 active:bg-accent transition-colors cursor-pointer text-left group"
|
|
264
|
-
>
|
|
265
|
-
<div className="size-8 rounded-md bg-muted flex items-center justify-center shrink-0 group-hover:bg-accent">
|
|
266
|
-
<Icon className="size-4 text-muted-foreground" />
|
|
267
|
-
</div>
|
|
268
|
-
<div className="flex-1 min-w-0">
|
|
269
|
-
<p className="text-xs font-medium text-foreground truncate">{cat.label}</p>
|
|
270
|
-
<p className="text-[11px] text-muted-foreground truncate">{cat.subtitle}</p>
|
|
271
|
-
</div>
|
|
272
|
-
<ChevronRight className="size-4 text-muted-foreground shrink-0" />
|
|
273
|
-
</button>
|
|
274
|
-
);
|
|
275
|
-
})}
|
|
276
|
-
</nav>
|
|
277
|
-
|
|
278
|
-
<Separator />
|
|
279
|
-
|
|
280
|
-
{/* About — footer */}
|
|
281
|
-
<section className="space-y-1 pb-2">
|
|
282
|
-
<p className="text-xs text-muted-foreground">
|
|
283
|
-
PPM — Personal Project Manager
|
|
284
|
-
</p>
|
|
285
|
-
<p className="text-[11px] text-muted-foreground">
|
|
286
|
-
A mobile-first web IDE for managing your projects.
|
|
287
|
-
</p>
|
|
288
|
-
{version && (
|
|
289
|
-
<p className="text-[11px] text-muted-foreground tabular-nums">
|
|
290
|
-
Version {version}
|
|
291
|
-
</p>
|
|
292
|
-
)}
|
|
293
|
-
</section>
|
|
294
|
-
</div>
|
|
295
|
-
</ScrollArea>
|
|
296
|
-
</div>
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/** Notifications detail content — extracted to keep SettingsTab clean */
|
|
301
|
-
function NotificationsContent() {
|
|
302
|
-
return (
|
|
303
|
-
<div className="space-y-4">
|
|
304
|
-
{/* Browser push */}
|
|
305
|
-
<section className="space-y-2">
|
|
306
|
-
<h3 className="text-xs font-medium text-muted-foreground">Push Notifications</h3>
|
|
307
|
-
<div className="flex items-center gap-1.5">
|
|
308
|
-
<Bell className="size-3.5 text-muted-foreground" />
|
|
309
|
-
<span className="text-xs">Not available yet</span>
|
|
310
|
-
</div>
|
|
311
|
-
<p className="text-[11px] text-muted-foreground">
|
|
312
|
-
Browser push does not deliver right now.
|
|
313
|
-
Use Telegram below to get alerted when a session finishes or needs approval.
|
|
314
|
-
</p>
|
|
315
|
-
</section>
|
|
316
|
-
|
|
317
|
-
<Separator />
|
|
318
|
-
|
|
319
|
-
{/* Telegram — redirect to PPMBot */}
|
|
320
|
-
<section className="space-y-1">
|
|
321
|
-
<h3 className="text-xs font-medium text-muted-foreground">Telegram</h3>
|
|
322
|
-
<p className="text-[11px] text-muted-foreground">
|
|
323
|
-
Telegram notifications are sent to all approved devices in PPMBot settings.
|
|
324
|
-
Configure your bot token and pair devices there.
|
|
325
|
-
</p>
|
|
326
|
-
</section>
|
|
327
|
-
</div>
|
|
328
|
-
);
|
|
329
|
-
}
|
|
1
|
+
import { isSettingsCategoryId } from "./settings-categories";
|
|
2
|
+
import { SettingsBody } from "./settings-body";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Settings as a tab — the mobile route, since the window layer does not render there.
|
|
6
|
+
*
|
|
7
|
+
* Layout comes from the shell's own width, so no viewport hint is passed. A category in the
|
|
8
|
+
* tab's metadata is a deep link (open Accounts, not the index); tabs already carry and persist
|
|
9
|
+
* metadata, so this needed no new tab field.
|
|
10
|
+
*/
|
|
11
|
+
export const SettingsTab = ({ metadata }: { metadata?: Record<string, unknown> }) => (
|
|
12
|
+
<SettingsBody
|
|
13
|
+
initialCategory={isSettingsCategoryId(metadata?.category) ? metadata.category : undefined}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Floating-window body for Settings.
|
|
3
|
+
*
|
|
4
|
+
* The open category rides on the window's payload, so a reload puts the user back on the pane
|
|
5
|
+
* they were reading instead of the default one. The payload is untrusted (it survives in
|
|
6
|
+
* localStorage and can be hand-edited), hence the narrowing before it reaches the shell.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useWindowStore } from "@/components/floating-window/window-store";
|
|
10
|
+
import type { WindowContentProps } from "@/components/floating-window/window-content-registry";
|
|
11
|
+
import { isSettingsCategoryId } from "./settings-categories";
|
|
12
|
+
import { SettingsBody } from "./settings-body";
|
|
13
|
+
|
|
14
|
+
export default function SettingsWindowContent({ id, payload }: WindowContentProps) {
|
|
15
|
+
const setPayload = useWindowStore((s) => s.setPayload);
|
|
16
|
+
const category = isSettingsCategoryId(payload?.category) ? payload.category : undefined;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<SettingsBody
|
|
20
|
+
initialCategory={category}
|
|
21
|
+
onCategoryChange={(next) => setPayload(id, { category: next })}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -109,7 +109,21 @@ function isSessionTabActive(sid: string): boolean {
|
|
|
109
109
|
return false;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
export function useChat(
|
|
112
|
+
export function useChat(
|
|
113
|
+
sessionId: string | null,
|
|
114
|
+
providerId = "claude",
|
|
115
|
+
projectName = "",
|
|
116
|
+
/**
|
|
117
|
+
* Called when the provider replaces the session id mid-turn.
|
|
118
|
+
*
|
|
119
|
+
* Codex and the Claude SDK both mint their own id and adopt it: PPM creates
|
|
120
|
+
* the session under a uuid of its own, then the provider reports the real one.
|
|
121
|
+
* The server re-keys itself, but the tab keeps whatever id it created with
|
|
122
|
+
* unless it is told — and that stale id owns no transcript, so the tab reloads
|
|
123
|
+
* empty even though the conversation is on disk under the new id.
|
|
124
|
+
*/
|
|
125
|
+
onSessionMigrated?: (newSessionId: string) => void,
|
|
126
|
+
): UseChatReturn {
|
|
113
127
|
const [messages, setMessages] = useState<ChatMessage[]>([]);
|
|
114
128
|
/** Map of compactMessageId → pre-compact messages (already ID-prefixed). Ephemeral. */
|
|
115
129
|
const [expansions, setExpansions] = useState<Map<string, ChatMessage[]>>(new Map());
|
|
@@ -173,6 +187,10 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
173
187
|
const historyLoadedAtRef = useRef(0);
|
|
174
188
|
const sessionIdRef = useRef(sessionId);
|
|
175
189
|
sessionIdRef.current = sessionId;
|
|
190
|
+
// Held in a ref so the socket handler always calls the latest callback without
|
|
191
|
+
// the socket effect having to re-run (and reconnect) when it changes identity.
|
|
192
|
+
const onSessionMigratedRef = useRef(onSessionMigrated);
|
|
193
|
+
onSessionMigratedRef.current = onSessionMigrated;
|
|
176
194
|
// Mirror of `messages` for synchronous reads (e.g. snapshotting the previous
|
|
177
195
|
// session's messages when sessionId changes, without adding `messages` to
|
|
178
196
|
// effect deps).
|
|
@@ -744,6 +762,18 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
744
762
|
return;
|
|
745
763
|
}
|
|
746
764
|
|
|
765
|
+
// The provider adopted its own session id for this conversation. Tell the
|
|
766
|
+
// owner so the tab follows: the server has already re-keyed itself, and the
|
|
767
|
+
// transcript from here on is written under the new id, so a tab still
|
|
768
|
+
// holding the old one would reload into an empty conversation.
|
|
769
|
+
if ((data as any).type === "session_migrated") {
|
|
770
|
+
const migratedTo = (data as any).newSessionId as string | undefined;
|
|
771
|
+
if (migratedTo && migratedTo !== sessionIdRef.current) {
|
|
772
|
+
onSessionMigratedRef.current?.(migratedTo);
|
|
773
|
+
}
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
|
|
747
777
|
// Handle compact status events
|
|
748
778
|
if ((data as any).type === "compact_status") {
|
|
749
779
|
const status = (data as any).status;
|
|
@@ -1001,6 +1031,13 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
1001
1031
|
const payload = Array.isArray(data) ? { messages: data, versionMap: {} } : data;
|
|
1002
1032
|
let history: ChatMessage[] = Array.isArray(payload?.messages) ? payload.messages : [];
|
|
1003
1033
|
if (payload?.versionMap) setVersionMap(payload.versionMap);
|
|
1034
|
+
// The server served this transcript from a different id than the one
|
|
1035
|
+
// asked for: the provider had renamed the session and this tab kept the
|
|
1036
|
+
// original. Adopt the real id, so the next turn continues the
|
|
1037
|
+
// conversation instead of starting a fresh one beside it.
|
|
1038
|
+
if (payload?.canonicalSessionId && payload.canonicalSessionId !== sessionIdRef.current) {
|
|
1039
|
+
onSessionMigratedRef.current?.(payload.canonicalSessionId);
|
|
1040
|
+
}
|
|
1004
1041
|
// If a live turn_events replay already owns the active (unfinished) turn,
|
|
1005
1042
|
// the REST history still contains that same turn — trim it (from its last
|
|
1006
1043
|
// user message onward) so it isn't rendered twice.
|
|
@@ -6,6 +6,7 @@ import { usePanelStore } from "@/stores/panel-store";
|
|
|
6
6
|
import { useKeybindingsStore, parseCombo, eventMatchesCombo } from "@/stores/keybindings-store";
|
|
7
7
|
import { useExtensionStore } from "@/stores/extension-store";
|
|
8
8
|
import { useCompareStore } from "@/stores/compare-store";
|
|
9
|
+
import { openSettings } from "@/components/settings/open-settings";
|
|
9
10
|
import { basename } from "@/lib/utils";
|
|
10
11
|
|
|
11
12
|
/** Dispatch this event to open the command palette from anywhere, optionally with initial query */
|
|
@@ -171,12 +172,10 @@ export function useGlobalKeybindings() {
|
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
174
|
|
|
174
|
-
// Open settings
|
|
175
|
+
// Open settings — its own window on desktop, a tab on mobile.
|
|
175
176
|
if (match(e, "open-settings")) {
|
|
176
177
|
e.preventDefault();
|
|
177
|
-
|
|
178
|
-
if (settings.sidebarCollapsed) settings.toggleSidebar();
|
|
179
|
-
settings.setSidebarActiveTab("settings");
|
|
178
|
+
openSettings();
|
|
180
179
|
return;
|
|
181
180
|
}
|
|
182
181
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
2
|
import { useTabStore, type TabType } from "@/stores/tab-store";
|
|
3
|
+
import { useWindowStore } from "@/components/floating-window/window-store";
|
|
4
|
+
import { openSettings } from "@/components/settings/open-settings";
|
|
5
|
+
import { isMobileDevice } from "@/hooks/use-is-mobile";
|
|
3
6
|
|
|
4
7
|
// ---------------------------------------------------------------------------
|
|
5
8
|
// URL state types
|
|
@@ -146,12 +149,39 @@ function buildTitleFromUrl(type: TabType, identifier: string | null): string {
|
|
|
146
149
|
}
|
|
147
150
|
}
|
|
148
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Settings has no desktop tab — it opens as its own floating window, so a URL naming it has
|
|
154
|
+
* to go through the same router every other entry point uses.
|
|
155
|
+
*
|
|
156
|
+
* The wait matters: `restoreAll` REPLACES the window map when the desktop layer mounts, so a
|
|
157
|
+
* window opened before that runs is silently discarded and the URL looks like it did nothing.
|
|
158
|
+
* This is reachable in practice because the URL open happens inside async project resolution,
|
|
159
|
+
* which can beat the layer's layout effect. Mobile needs no wait — it gets a tab, and the
|
|
160
|
+
* window layer never mounts (so `restored` would never flip and this would hang).
|
|
161
|
+
*/
|
|
162
|
+
function openSettingsOnceWindowLayerIsReady(): void {
|
|
163
|
+
if (isMobileDevice() || useWindowStore.getState().restored) {
|
|
164
|
+
openSettings();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const unsubscribe = useWindowStore.subscribe((state) => {
|
|
168
|
+
if (!state.restored) return;
|
|
169
|
+
unsubscribe();
|
|
170
|
+
openSettings();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
149
174
|
/** Auto-open or focus a tab based on URL state */
|
|
150
175
|
export function autoOpenFromUrl(
|
|
151
176
|
tabType: TabType,
|
|
152
177
|
tabIdentifier: string | null,
|
|
153
178
|
projectName: string,
|
|
154
179
|
): void {
|
|
180
|
+
if (tabType === "settings") {
|
|
181
|
+
openSettingsOnceWindowLayerIsReady();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
155
185
|
const { tabs, setActiveTab, openTab } = useTabStore.getState();
|
|
156
186
|
const expectedId = tabIdFromUrl(tabType, tabIdentifier);
|
|
157
187
|
|