forge-openclaw-plugin 0.3.5 → 0.3.8
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/dist/assets/{action-bar-DBZ38L_6.js → action-bar-BFjWjRIM.js} +1 -1
- package/dist/assets/{activity-page-BJxUR9bD.js → activity-page-D-6yBWuZ.js} +1 -1
- package/dist/assets/{ai-surface-workspace-ehzBjTsW.js → ai-surface-workspace-BEfo9bRO.js} +1 -1
- package/dist/assets/{atlas-panel-BFUeVT69.js → atlas-panel-BfMyJXxQ.js} +1 -1
- package/dist/assets/{board-CLOHbg6t.js → board-CuxQRKPJ.js} +1 -1
- package/dist/assets/{calendar-page-Bg8W-YQ-.js → calendar-page-D4tQNJ2V.js} +1 -1
- package/dist/assets/{calendar-rules-9XQLoI96.js → calendar-rules-C-6O_uGU.js} +1 -1
- package/dist/assets/{calendar-week-toolbar-BeYnx1pE.js → calendar-week-toolbar-_NzeKsYx.js} +1 -1
- package/dist/assets/{charts-DwTguE_x.js → charts-BzT4pUPg.js} +1 -1
- package/dist/assets/{companion-sync-lab-page-BRKYkIrs.js → companion-sync-lab-page-D1Oqsf6M.js} +1 -1
- package/dist/assets/{daily-metrics-dashboard-Jt0nAHU5.js → daily-metrics-dashboard-DtE3pVOl.js} +1 -1
- package/dist/assets/date-keys-BnZV4PNO.js +1 -0
- package/dist/assets/{define-workbench-box-5h-dyvJY.js → define-workbench-box-D-32C8nM.js} +1 -1
- package/dist/assets/{entity-link-multiselect-Bb4De_e3.js → entity-link-multiselect-DcCvkesQ.js} +1 -1
- package/dist/assets/{entity-note-count-link-BzWnsOmI.js → entity-note-count-link-Cjsk5oT2.js} +1 -1
- package/dist/assets/{entity-notes-surface-CagOwdng.js → entity-notes-surface-DQQPLjxd.js} +1 -1
- package/dist/assets/{execution-board-DTmAtmqZ.js → execution-board-agWQbN-y.js} +1 -1
- package/dist/assets/{faceted-token-search-DJPRm9AY.js → faceted-token-search-DldM3-ru.js} +1 -1
- package/dist/assets/{flagship-signal-deck-CJbGZF7I.js → flagship-signal-deck-BlLYW9Kz.js} +1 -1
- package/dist/assets/{floating-action-menu-K77jh8XZ.js → floating-action-menu-D9-psbha.js} +1 -1
- package/dist/assets/{forms-C5d5hTf2.js → forms-D1qJ3oOP.js} +1 -1
- package/dist/assets/{generic-node-view-p5ePSFuG.js → generic-node-view-CcepUVhP.js} +1 -1
- package/dist/assets/{goal-detail-page-DGu_khEK.js → goal-detail-page-DP1n5-Hk.js} +1 -1
- package/dist/assets/{goal-dialog-BWD7cOv9.js → goal-dialog-Oxx8WqbZ.js} +1 -1
- package/dist/assets/{goals-page-Bgj3sj0f.js → goals-page-CUt1a4Y2.js} +1 -1
- package/dist/assets/{graph-Cd5WF3lw.js → graph-BF4IsheG.js} +1 -1
- package/dist/assets/{habits-page-Ctut1tuX.js → habits-page-5REbWAlo.js} +1 -1
- package/dist/assets/{health-boxes-Ie3horXx.js → health-boxes-sHNML3tm.js} +1 -1
- package/dist/assets/index-CQ5r7ZUz.js +2 -0
- package/dist/assets/index-FxgNSuZX.css +1 -0
- package/dist/assets/{inline-note-fields-DE6WM9uM.js → inline-note-fields-Bql_KfR9.js} +1 -1
- package/dist/assets/{insight-flow-dialog-XL8I74eJ.js → insight-flow-dialog-CN-CMSB7.js} +1 -1
- package/dist/assets/{insights-page-Bz1FLbp5.js → insights-page-B1u6ONtQ.js} +1 -1
- package/dist/assets/{kanban-boxes-BBziel7P.js → kanban-boxes-DB1kuUlY.js} +1 -1
- package/dist/assets/{kanban-page-DdQP73I3.js → kanban-page-BBW9_vMu.js} +1 -1
- package/dist/assets/{knowledge-graph-page-DdHWj4Dj.js → knowledge-graph-page-CoJaydZb.js} +1 -1
- package/dist/assets/{life-force-page-BRN-93cI.js → life-force-page-DBYbA1GF.js} +1 -1
- package/dist/assets/{life-force-workspace-BowvP5R4.js → life-force-workspace-BiD9xOEt.js} +1 -1
- package/dist/assets/{maps-D0Mm6WPG.js → maps-BTVHALP8.js} +1 -1
- package/dist/assets/{metric-tile-B6aJueRo.js → metric-tile-CuP9DOYm.js} +1 -1
- package/dist/assets/{motion-DwjmC9aq.js → motion-DcgUnXhY.js} +1 -1
- package/dist/assets/{movement-boxes-5cjWjIdR.js → movement-boxes-DZg_qPPg.js} +1 -1
- package/dist/assets/{movement-page-Dy53RWtB.js → movement-page-CmwsQGR_.js} +1 -1
- package/dist/assets/{note-markdown-CvEQCfoi.js → note-markdown-B82ncnFt.js} +1 -1
- package/dist/assets/{note-tags-input-Cg5zBXos.js → note-tags-input-C_x5WdK5.js} +1 -1
- package/dist/assets/{notes-boxes-CgZyf7mV.js → notes-boxes-BEFlp9yd.js} +1 -1
- package/dist/assets/{notes-page-Cbdcv0Ej.js → notes-page-B6Vl-GPf.js} +1 -1
- package/dist/assets/{open-in-graph-button-D31ZOEhA.js → open-in-graph-button-C-bJekoH.js} +1 -1
- package/dist/assets/{orbit-map-8eNDWek8.js → orbit-map-DHeTM15g.js} +1 -1
- package/dist/assets/{overview-page-CZ6q52Qj.js → overview-page-BRWje1F9.js} +1 -1
- package/dist/assets/{page-hero-C0MpI3MM.js → page-hero-8bITsx_x.js} +1 -1
- package/dist/assets/pill-cluster-XQjm-wPc.js +1 -0
- package/dist/assets/{preference-entity-handoff-button-CJhr5AXl.js → preference-entity-handoff-button-DwYF_5i3.js} +1 -1
- package/dist/assets/{preferences-page-8vszDNFX.js → preferences-page-C7DBPpNb.js} +1 -1
- package/dist/assets/{project-collections-sC7eAAhS.js → project-collections-mtxanSMf.js} +1 -1
- package/dist/assets/{project-detail-page-BKdnMjJy.js → project-detail-page-BT87Goqc.js} +1 -1
- package/dist/assets/{project-dialog-BiHZpOo1.js → project-dialog-DnZe757y.js} +1 -1
- package/dist/assets/{project-management-hierarchy-page-VW-hykAI.js → project-management-hierarchy-page-B3R2lNFI.js} +1 -1
- package/dist/assets/{project-management-section-nav-BEZ5zihs.js → project-management-section-nav-DyBWxHbe.js} +1 -1
- package/dist/assets/{projects-boxes-Ca6rpYeE.js → projects-boxes-CxZj3P29.js} +1 -1
- package/dist/assets/{projects-page-D86pjpTf.js → projects-page-Bec11c0x.js} +1 -1
- package/dist/assets/{psyche-behaviors-page-YLJB6CRU.js → psyche-behaviors-page-DWRpYvl1.js} +1 -1
- package/dist/assets/{psyche-flashcards-page-D3gdHLUw.js → psyche-flashcards-page-CX4rcsXZ.js} +1 -1
- package/dist/assets/{psyche-goal-map-page-DJiqSiCx.js → psyche-goal-map-page-Y6b3lCvV.js} +1 -1
- package/dist/assets/{psyche-graph-Tke0qFdt.js → psyche-graph-CQuCWKIp.js} +1 -1
- package/dist/assets/{psyche-metrics-page-DoLnvmC2.js → psyche-metrics-page-DadDJOnm.js} +1 -1
- package/dist/assets/{psyche-mode-guide-page-_Zbvg_HL.js → psyche-mode-guide-page-B1nz0uCg.js} +1 -1
- package/dist/assets/{psyche-modes-page-eAkaAzJc.js → psyche-modes-page-i3uSuhKA.js} +1 -1
- package/dist/assets/{psyche-page-CwmuBVjA.js → psyche-page-Y_s-BE2m.js} +1 -1
- package/dist/assets/{psyche-patterns-page-D7B4Ykjq.js → psyche-patterns-page-DaaOLIlN.js} +1 -1
- package/dist/assets/{psyche-questionnaire-builder-page-CHJlvCzX.js → psyche-questionnaire-builder-page-CuF7rXOv.js} +1 -1
- package/dist/assets/{psyche-questionnaire-detail-page-Bg3ll-D4.js → psyche-questionnaire-detail-page-BfFEMkRY.js} +1 -1
- package/dist/assets/{psyche-questionnaire-run-detail-page-CIEerczF.js → psyche-questionnaire-run-detail-page-BoQTvd7Q.js} +1 -1
- package/dist/assets/{psyche-questionnaire-run-page-DyxIk6Qx.js → psyche-questionnaire-run-page-C0qKiNZN.js} +1 -1
- package/dist/assets/{psyche-questionnaires-page-ZlqUxuIl.js → psyche-questionnaires-page-B6hfD448.js} +1 -1
- package/dist/assets/{psyche-report-detail-page-B2jgYnQ5.js → psyche-report-detail-page-BlFL8moM.js} +1 -1
- package/dist/assets/{psyche-reports-page-DlXr52yr.js → psyche-reports-page-DAAcYENp.js} +1 -1
- package/dist/assets/{psyche-schemas-Dtskzvv1.js → psyche-schemas-DDol0j-g.js} +1 -1
- package/dist/assets/{psyche-schemas-beliefs-page-BhrTZN9B.js → psyche-schemas-beliefs-page-CsxKSrKM.js} +1 -1
- package/dist/assets/{psyche-screen-time-page-WNGcdusx.js → psyche-screen-time-page-n4b0e58x.js} +1 -1
- package/dist/assets/{psyche-self-observation-page-XsCOglo4.js → psyche-self-observation-page-BaxEQ2-3.js} +1 -1
- package/dist/assets/{psyche-values-page-NvHI6zWK.js → psyche-values-page-DTv5NMSU.js} +1 -1
- package/dist/assets/{question-flow-dialog-Bj4PxpjS.js → question-flow-dialog-CskCt5NZ.js} +1 -1
- package/dist/assets/{report-chain-fields-mWFikZzT.js → report-chain-fields-D132-EMh.js} +1 -1
- package/dist/assets/{rewards-page-DyjwXsQN.js → rewards-page-C533lVP-.js} +1 -1
- package/dist/assets/{scheduling-rules-editor-C6FEYOxd.js → scheduling-rules-editor-CDpontGp.js} +1 -1
- package/dist/assets/{schema-badge-CCe4zkSN.js → schema-badge-B3DiMnjB.js} +1 -1
- package/dist/assets/{schemas-Cjwn6ooR.js → schemas-CH1_ngUX.js} +1 -1
- package/dist/assets/{select-menu-DeJhCsd8.js → select-menu-BOF-k4Ln.js} +1 -1
- package/dist/assets/{settings-agents-page-DYDxyKu-.js → settings-agents-page-B5OQtlZX.js} +1 -1
- package/dist/assets/{settings-bin-page-BWLfKVW1.js → settings-bin-page-D_bk3Kcu.js} +1 -1
- package/dist/assets/{settings-calendar-page-Ci-wXhCv.js → settings-calendar-page-PuSj9_kM.js} +1 -1
- package/dist/assets/{settings-data-page-DxIw-fWn.js → settings-data-page-EwFMaeq6.js} +1 -1
- package/dist/assets/{settings-logs-page-inpyIdu6.js → settings-logs-page-BKkse0DX.js} +1 -1
- package/dist/assets/{settings-mobile-page-BcJGLax8.js → settings-mobile-page-BrIVmdeB.js} +1 -1
- package/dist/assets/{settings-models-page-OWTRhfkj.js → settings-models-page-Mg84D_0K.js} +1 -1
- package/dist/assets/{settings-page-DXxF3qK2.js → settings-page-D-kul92f.js} +1 -1
- package/dist/assets/{settings-rewards-page-CCXin1n_.js → settings-rewards-page-waNyCcX_.js} +1 -1
- package/dist/assets/{settings-section-nav-CwSDNC3W.js → settings-section-nav-BmJWnrYk.js} +1 -1
- package/dist/assets/{settings-users-page-B4NEACwR.js → settings-users-page-DBgC6y56.js} +1 -1
- package/dist/assets/{settings-wiki-page-BNRK1SYc.js → settings-wiki-page-CM0te9dI.js} +1 -1
- package/dist/assets/sleep-page-C_krRE59.js +1 -0
- package/dist/assets/{sports-page-BawekFKD.js → sports-page-eg5Rfc_E.js} +1 -1
- package/dist/assets/{state-BtwEvpO6.js → state-Bpe5dF3T.js} +1 -1
- package/dist/assets/{strategies-page-BEl3NGAU.js → strategies-page-D4AqvFNW.js} +1 -1
- package/dist/assets/{strategy-detail-page-DPPI_8Ub.js → strategy-detail-page-BlYVkXaW.js} +1 -1
- package/dist/assets/{strategy-dialog-DU6wbBkQ.js → strategy-dialog-FO9Oa0dB.js} +1 -1
- package/dist/assets/{surface-BVYp-Wq9.js → surface-MVeeZGKB.js} +1 -1
- package/dist/assets/{table-BuONJH1s.js → table-U7otr5go.js} +1 -1
- package/dist/assets/{task-detail-page-BsMVAsbb.js → task-detail-page-Dy-aRyY6.js} +1 -1
- package/dist/assets/{task-dialog-BGzPc6TW.js → task-dialog-DrA9pba7.js} +1 -1
- package/dist/assets/{timebox-planning-dialog-4_XWuqkw.js → timebox-planning-dialog-C_gnfxFx.js} +1 -1
- package/dist/assets/{today-boxes-5pCvh5zS.js → today-boxes-BFOws_iC.js} +1 -1
- package/dist/assets/{today-page-BGurICpl.js → today-page-BoPj6a6q.js} +1 -1
- package/dist/assets/{training-load-page-BkoYKZ9_.js → training-load-page-DGU40Zfl.js} +1 -1
- package/dist/assets/{ui-B9O-eUim.js → ui-B9TWEtCx.js} +1 -1
- package/dist/assets/{use-anchored-overlay-position-BrQ4cqKn.js → use-anchored-overlay-position-BY4kNzPj.js} +1 -1
- package/dist/assets/{use-psyche-focus-target-Cuxni3SK.js → use-psyche-focus-target-BhNedCZB.js} +1 -1
- package/dist/assets/{user-badge-DfDv87j7.js → user-badge-CZWtYeMw.js} +1 -1
- package/dist/assets/{user-select-field-BNqv8-wd.js → user-select-field-fx129Uh6.js} +1 -1
- package/dist/assets/{utility-widgets-CbYj32he.js → utility-widgets-B3wWGxQc.js} +1 -1
- package/dist/assets/{vendor-Cpmju3nw.js → vendor-BwL6m4SE.js} +216 -211
- package/dist/assets/{vitals-page-DlxMk-L7.js → vitals-page-BXRZEP_8.js} +1 -1
- package/dist/assets/{weekly-review-page-VrEvAl1T.js → weekly-review-page-D5cebA5x.js} +1 -1
- package/dist/assets/weight-loss-page-BuUdFh9z.js +5 -0
- package/dist/assets/{wiki-article-markdown-DxTkiQRy.js → wiki-article-markdown-CvaCjg_t.js} +1 -1
- package/dist/assets/{wiki-editor-page-Beu92YnZ.js → wiki-editor-page-Dco79SLY.js} +1 -1
- package/dist/assets/{wiki-ingest-history-page-Cq_soygm.js → wiki-ingest-history-page-uvKRkRDF.js} +1 -1
- package/dist/assets/{wiki-ingest-modal-D6xs2sEn.js → wiki-ingest-modal-BW6AJPea.js} +1 -1
- package/dist/assets/{wiki-page-yF3Flgtg.js → wiki-page-BIL5zMqv.js} +1 -1
- package/dist/assets/{workbench-flow-page-CZZGg3a8.js → workbench-flow-page-Dx_nq8R_.js} +1 -1
- package/dist/assets/{workbench-page-DKENZ5Nz.js → workbench-page-BJnt_Zzf.js} +1 -1
- package/dist/assets/{workout-detail-page-CeN4QiYQ.js → workout-detail-page-CKgqyB-y.js} +2 -2
- package/dist/index.html +8 -8
- package/dist/server/server/migrations/070_health_mobile_sync_completion_index.sql +16 -0
- package/dist/server/server/src/app.js +139 -13
- package/dist/server/server/src/health-weight-loss.js +48 -6
- package/dist/server/server/src/health.js +345 -96
- package/dist/server/server/src/openapi.js +62 -0
- package/dist/server/server/src/repositories/gamification.js +25 -0
- package/dist/server/server/src/repositories/tasks.js +82 -17
- package/dist/server/server/src/services/dashboard.js +5 -4
- package/dist/server/server/src/services/gamification.js +47 -19
- package/dist/server/server/src/services/life-force.js +99 -0
- package/dist/server/src/lib/api.js +4 -0
- package/dist/server/src/lib/snapshot-normalizer.js +42 -23
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server/migrations/070_health_mobile_sync_completion_index.sql +16 -0
- package/skills/forge-openclaw/SKILL.md +1 -0
- package/skills/forge-openclaw/psyche_entity_playbooks.md +8 -0
- package/dist/assets/date-keys-Cj1G3TOn.js +0 -1
- package/dist/assets/index-BaiwtAgo.js +0 -2
- package/dist/assets/index-CEgIwgk9.css +0 -1
- package/dist/assets/pill-cluster-DGwKZQKF.js +0 -1
- package/dist/assets/sleep-page-Bara54nB.js +0 -1
- package/dist/assets/weight-loss-page-DJDnjxKF.js +0 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as o,j as e,da as Y,db as V,cl as me,dc as Z,aQ as J,dd as xe,aD as ge,ca as pe}from"./vendor-Cpmju3nw.js";import{j as he,i as X,k}from"./state-BtwEvpO6.js";import{a as ve,F as be,Q as ee}from"./question-flow-dialog-Bj4PxpjS.js";import{I as ae,k as u,S as fe,e as te,B as x,C as y,c as $,cY as je,cZ as ke,f as ye,c_ as we,c$ as Ne,d0 as Fe,d1 as Se,cU as Re,d2 as De}from"./index-BaiwtAgo.js";import{S as Ce}from"./settings-section-nav-CwSDNC3W.js";import{P as Be}from"./page-hero-C0MpI3MM.js";import{M as g}from"./metric-tile-B6aJueRo.js";import"./ui-B9O-eUim.js";import"./motion-DwjmC9aq.js";import"./board-CLOHbg6t.js";import"./forms-C5d5hTf2.js";function A(t){if(!Number.isFinite(t)||t<=0)return"0 B";const l=["B","KB","MB","GB","TB"];let i=t,m=0;for(;i>=1024&&m<l.length-1;)i/=1024,m+=1;return`${i.toFixed(i>=100?0:i>=10?1:2)} ${l[m]}`}function _e(t,l){const i=URL.createObjectURL(t),m=document.createElement("a");m.href=i,m.download=l,m.click(),URL.revokeObjectURL(i)}function Me(t){return t?t===1?"Every hour":t===24?"Every day":t===168?"Every week":`Every ${t} hours`:"Off"}function se(t){switch(t){case"manual":return"Manual";case"automatic":return"Automatic";case"pre_restore":return"Safety backup before restore";case"pre_switch_root":return"Safety backup before folder change";default:return t}}function w(t,l="Unknown time"){if(!t)return l;const i=new Date(t);return Number.isNaN(i.getTime())?l:ye(t)}function Ae({tone:t,message:l}){return e.jsx("div",{className:$("rounded-[20px] border px-4 py-3 text-sm leading-6",t==="success"?"border-[color-mix(in_srgb,var(--success)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-success-soft)] text-[var(--success)]":t==="warning"?"border-[color-mix(in_srgb,var(--warning)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-warning-soft)] text-[var(--warning)]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] text-[var(--ui-ink-soft)]"),children:l})}function z({label:t,value:l,icon:i}){return e.jsxs("div",{className:"min-w-0 overflow-hidden rounded-[24px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4",children:[e.jsxs("div",{className:"flex min-w-0 items-center gap-2 text-[11px] uppercase tracking-[0.16em] text-[var(--ui-ink-faint)]",children:[e.jsx(i,{className:"size-4"}),e.jsx("span",{className:"min-w-0 break-words",children:t})]}),e.jsx("div",{className:"mt-3 min-w-0 break-all text-sm leading-6 text-[var(--ui-ink-soft)] [overflow-wrap:anywhere]",children:l})]})}function Ie(){var G,W;const t=he(),[l,i]=o.useState(""),[m,T]=o.useState(""),[E,q]=o.useState(""),[U,O]=o.useState(!0),[b,re]=o.useState([]),[L,f]=o.useState(null),[ne,N]=o.useState(!1),[d,F]=o.useState({mode:"migrate_current",targetDataRoot:"",createSafetyBackup:!0}),[ie,j]=o.useState(null),[n,P]=o.useState(null),[K,H]=o.useState({createSafetyBackup:!0}),[oe,R]=o.useState(null),h=X({queryKey:["forge-operator-session"],queryFn:Re}),le=h.isSuccess,S=X({queryKey:["forge-data-management"],queryFn:De,enabled:le}),D=async()=>{await Promise.all([t.invalidateQueries({queryKey:["forge-operator-session"]}),t.invalidateQueries({queryKey:["forge-data-management"]})])},I=k({mutationFn:()=>we({backupDirectory:l,backupFrequencyHours:m==="off"?null:Number(m||"24"),backupRetentionDays:E==="forever"?null:Number(E||"30"),autoRepairEnabled:U}),onSuccess:async()=>{f({tone:"success",message:"Backup settings saved."}),await D()}}),C=k({mutationFn:()=>ke("Manual backup from Settings → Data"),onSuccess:async()=>{f({tone:"success",message:"Backup created."}),await D()}}),B=k({mutationFn:je,onSuccess:({candidates:a})=>{re(a),f({tone:a.some(c=>c.newerThanCurrent)?"warning":"neutral",message:a.length>0?`Found ${a.length} Forge ${a.length===1?"copy":"copies"} on disk.`:"No other Forge data copies were found in the scanned folders."})}}),_=k({mutationFn:a=>Fe({targetDataRoot:a.targetDataRoot,mode:a.mode,createSafetyBackup:a.createSafetyBackup}),onSuccess:async()=>{f({tone:"success",message:"Forge is now using the selected data folder."}),N(!1),await D()}}),M=k({mutationFn:({backupId:a,createSafetyBackup:c})=>Se(a,c),onSuccess:async()=>{f({tone:"success",message:"Backup restored. Forge is now running from that restored state."}),P(null),await D()}}),Q=k({mutationFn:async a=>{const c=await Ne(a);return _e(c.blob,c.fileName??`forge-export.${a}`),a},onSuccess:a=>{f({tone:"neutral",message:`Started download for ${a}.`})}}),s=(G=S.data)==null?void 0:G.data;o.useEffect(()=>{s&&(i(a=>a||s.settings.backupDirectory),T(a=>a||(s.settings.backupFrequencyHours?String(s.settings.backupFrequencyHours):"off")),O(s.settings.autoRepairEnabled),q(a=>a||(s.settings.backupRetentionDays?String(s.settings.backupRetentionDays):"forever")),F(a=>({...a,targetDataRoot:a.targetDataRoot||s.current.dataRoot})))},[s]);const ce=o.useMemo(()=>b.find(a=>a.newerThanCurrent),[b]),p=o.useMemo(()=>b.find(a=>a.dataRoot===d.targetDataRoot.trim()),[d.targetDataRoot,b]),de=[{id:"mode",eyebrow:"Step 1",title:"What do you want Forge to do?",description:"Choose whether Forge should move the current data into a new folder or switch to a folder that already contains the right Forge data.",render:(a,c)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(ve,{value:a.mode,onChange:v=>c({mode:v}),options:[{value:"migrate_current",label:"Move the current data",description:"Copy the live database and local secrets key into a new folder, then switch Forge to it."},{value:"adopt_existing",label:"Use an existing data folder",description:"Keep the target folder as it is and point Forge at that existing database directly."}]}),e.jsxs("label",{className:"flex items-start gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3",children:[e.jsx("input",{type:"checkbox",className:"mt-1",checked:a.createSafetyBackup,onChange:v=>c({createSafetyBackup:v.target.checked})}),e.jsx("span",{className:"text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Create one safety backup first."})]})]})},{id:"folder",eyebrow:"Step 2",title:d.mode==="migrate_current"?"Choose the new data folder":"Choose the data folder to use",description:d.mode==="migrate_current"?"Pick an empty folder for the moved Forge data.":"Pick the folder that already contains the Forge data you trust.",render:(a,c)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(be,{label:"Data folder",description:"Forge will place or read the database and backups from here.",children:e.jsx(ae,{value:a.targetDataRoot,onChange:v=>c({targetDataRoot:v.target.value}),placeholder:"/absolute/path/to/forge-data"})}),p?e.jsxs("div",{className:"rounded-[22px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:"Found on this machine"}),e.jsx("div",{className:"mt-2 break-all",children:p.databasePath}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[e.jsx(u,{tone:"meta",children:p.sourceHint}),e.jsxs(u,{tone:"meta",children:[p.counts.notes," notes"]}),e.jsxs(u,{tone:"meta",children:[p.counts.tasks," tasks"]}),p.newerThanCurrent?e.jsx(u,{className:"bg-[var(--ui-warning-soft)] text-[var(--warning)]",children:"Newer than the current copy"}):null]})]}):e.jsx("div",{className:"rounded-[22px] border border-dashed border-[var(--ui-border-subtle)] px-4 py-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:d.mode==="migrate_current"?"Forge will copy the current data into this folder and then switch over.":"If this folder already holds a Forge database, Forge will start using it after you confirm."})]})}],ue=[{id:"review",eyebrow:"Step 1",title:"Review the backup you want to restore",description:"Restoring replaces the current database with the selected backup.",render:(a,c)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"rounded-[22px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:n?w(n.createdAt):"Selected backup"}),e.jsx("div",{className:"mt-2",children:(n==null?void 0:n.note)||"Forge backup archive"}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[e.jsx(u,{tone:"meta",children:n?se(n.mode):"Backup"}),e.jsx(u,{tone:"meta",children:n?A(n.sizeBytes):"0 B"}),n!=null&&n.includesWiki?e.jsx(u,{tone:"meta",children:"Includes wiki"}):null]})]}),e.jsxs("label",{className:"flex items-start gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3",children:[e.jsx("input",{type:"checkbox",className:"mt-1",checked:a.createSafetyBackup,onChange:v=>c({createSafetyBackup:v.target.checked})}),e.jsx("span",{className:"text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Create one safety backup of the current state first."})]})]})},{id:"confirm",eyebrow:"Step 2",title:"Confirm the restore",description:"Use this only when you are confident this backup is the state you want back.",render:()=>e.jsx("div",{className:"rounded-[22px] border border-[color-mix(in_srgb,var(--warning)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-warning-soft)] p-4 text-sm leading-6 text-[var(--warning)]",children:"Forge will replace the live database with this backup, then reopen the restored copy."})}];if(h.isLoading||S.isLoading)return e.jsx(fe,{eyebrow:"Data",title:"Loading data controls",description:"Checking the live data folder, backup plan, and recovery tools.",columns:3,blocks:6});if(h.isError)return e.jsx(te,{eyebrow:"Data",error:h.error,onRetry:()=>void h.refetch()});if(S.isError||!s)return e.jsx(te,{eyebrow:"Data",error:S.error??new Error("Forge returned an empty data payload."),onRetry:()=>void S.refetch()});const r=s.current;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mx-auto grid w-full max-w-[1480px] gap-5",children:[e.jsx(Be,{eyebrow:"Data, backups, recovery",title:"Data",description:"See where Forge is saving the live data, keep it protected with backups, look for a newer copy on disk if something goes wrong, and download the database or its structure when you need it.",badge:`${r.integrityOk?"Healthy":"Needs attention"} · ${A(r.databaseSizeBytes)}`,actions:e.jsxs(e.Fragment,{children:[e.jsxs(x,{variant:"secondary",pending:B.isPending,pendingLabel:"Scanning",onClick:()=>void B.mutateAsync(),children:[e.jsx(Y,{className:"size-4"}),"Look for other Forge copies"]}),e.jsxs(x,{pending:C.isPending,pendingLabel:"Creating backup",onClick:()=>void C.mutateAsync(),children:[e.jsx(V,{className:"size-4"}),"Create backup now"]})]})}),e.jsx(Ce,{}),(W=h.data)!=null&&W.session?e.jsxs("div",{className:"rounded-[20px] border border-[color-mix(in_srgb,var(--success)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-success-soft)] px-4 py-3 text-sm text-[var(--ui-ink-medium)]",children:["You are managing Forge data as"," ",e.jsx("span",{className:"font-medium text-[var(--ui-ink-strong)]",children:h.data.session.actorLabel}),"."]}):null,L?e.jsx(Ae,{tone:L.tone,message:L.message}):null,e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.15fr)_minmax(0,0.85fr)]",children:[e.jsxs(y,{className:"grid gap-5",children:[e.jsxs("div",{className:"flex min-w-0 flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Live data folder"}),e.jsx("div",{className:"mt-2 min-w-0 break-all text-xl font-semibold text-[var(--ui-ink-strong)] [overflow-wrap:anywhere]",children:r.dataRoot}),e.jsx("div",{className:"mt-2 max-w-3xl text-sm leading-6 text-[var(--ui-ink-soft)]",children:"This is the folder Forge is reading and writing right now."})]}),e.jsx(u,{className:$(r.integrityOk?"bg-[var(--ui-success-soft)] text-[var(--success)]":"bg-[var(--ui-warning-soft)] text-[var(--warning)]"),children:r.integrityMessage})]}),e.jsxs("div",{className:"grid min-w-0 gap-3 md:grid-cols-2 xl:grid-cols-3",children:[e.jsx(z,{label:"Database file",value:r.databasePath,icon:me}),e.jsx(z,{label:"Folder layout",value:r.layout,icon:Z}),e.jsx(z,{label:"Last database change",value:r.databaseLastModifiedAt?w(r.databaseLastModifiedAt):"Unknown",icon:J})]}),e.jsxs("div",{className:"grid min-w-0 gap-3 md:grid-cols-3 xl:grid-cols-6",children:[e.jsx(g,{label:"Notes",value:r.counts.notes}),e.jsx(g,{label:"Goals",value:r.counts.goals}),e.jsx(g,{label:"Projects",value:r.counts.projects}),e.jsx(g,{label:"Tasks",value:r.counts.tasks}),e.jsx(g,{label:"Runs",value:r.counts.taskRuns}),e.jsx(g,{label:"Tags",value:r.counts.tags})]})]}),e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"flex size-11 items-center justify-center rounded-2xl border border-[color-mix(in_srgb,var(--success)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-success-soft)]",children:e.jsx(xe,{className:"size-5 text-[var(--success)]"})}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:"Protection plan"}),e.jsx("div",{className:"mt-1 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Choose where backups go, how often Forge creates them, and whether scans should call out newer copies found elsewhere on disk."})]})]}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-3",children:[e.jsx(g,{label:"Automatic backup",value:Me(s.settings.backupFrequencyHours),detail:s.settings.lastAutoBackupAt?`Last run ${w(s.settings.lastAutoBackupAt)}`:"No automatic backup recorded yet"}),e.jsx(g,{label:"Manual backup",value:s.settings.lastManualBackupAt?w(s.settings.lastManualBackupAt):"None yet",detail:`${s.backups.length} backup${s.backups.length===1?"":"s"} saved`}),e.jsx(g,{label:"Retention",value:s.settings.backupRetentionDays?`${s.settings.backupRetentionDays} days`:"Keep forever",detail:"Automatic backups only"})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-[var(--ui-ink-soft)]",children:"Backup folder"}),e.jsx(ae,{value:l,onChange:a=>i(a.target.value)})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-[var(--ui-ink-soft)]",children:"Automatic backup"}),e.jsxs("select",{className:"h-11 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-3 text-sm text-[var(--ui-ink-strong)] outline-none transition focus:border-[var(--primary)]",value:m||"24",onChange:a=>T(a.target.value),children:[e.jsx("option",{value:"off",children:"Off"}),e.jsx("option",{value:"1",children:"Every hour"}),e.jsx("option",{value:"6",children:"Every 6 hours"}),e.jsx("option",{value:"24",children:"Every day"}),e.jsx("option",{value:"168",children:"Every week"})]})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-[var(--ui-ink-soft)]",children:"Keep automatic backups"}),e.jsxs("select",{className:"h-11 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-3 text-sm text-[var(--ui-ink-strong)] outline-none transition focus:border-[var(--primary)]",value:E||"30",onChange:a=>q(a.target.value),children:[e.jsx("option",{value:"7",children:"7 days"}),e.jsx("option",{value:"14",children:"14 days"}),e.jsx("option",{value:"30",children:"30 days"}),e.jsx("option",{value:"90",children:"90 days"}),e.jsx("option",{value:"365",children:"1 year"}),e.jsx("option",{value:"forever",children:"Keep forever"})]})]}),e.jsxs("label",{className:"flex items-start gap-3 rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3",children:[e.jsx("input",{type:"checkbox",className:"mt-1",checked:U,onChange:a=>O(a.target.checked)}),e.jsx("span",{className:"text-sm leading-6 text-[var(--ui-ink-soft)]",children:"When I scan, point out Forge copies that look newer than the one I am using now."})]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(x,{pending:I.isPending,pendingLabel:"Saving",onClick:()=>void I.mutateAsync(),children:"Save backup settings"}),e.jsx(x,{variant:"secondary",pending:C.isPending,pendingLabel:"Creating backup",onClick:()=>void C.mutateAsync(),children:"Create backup now"})]})]})]})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]",children:[e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Change data folder"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Move today’s Forge data into a new folder, or switch to another folder that already contains the right Forge database."})]}),e.jsxs("div",{className:"rounded-[22px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:"Current folder"}),e.jsx("div",{className:"mt-2 break-all",children:r.dataRoot}),p?e.jsxs("div",{className:"mt-3 text-sm text-[var(--ui-ink-soft)]",children:["Selected scanned copy: ",p.dataRoot]}):null]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsxs(x,{onClick:()=>{F(a=>({...a,mode:"migrate_current",targetDataRoot:a.targetDataRoot||r.dataRoot})),j(null),N(!0)},children:[e.jsx(Z,{className:"size-4"}),"Move current data"]}),e.jsxs(x,{variant:"secondary",onClick:()=>{F(a=>({...a,mode:"adopt_existing",targetDataRoot:a.targetDataRoot||r.dataRoot})),j(null),N(!0)},children:[e.jsx(J,{className:"size-4"}),"Use existing data folder"]})]})]}),e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Downloads"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Download the live database itself, or export a structure and table snapshot in other formats."})]}),e.jsx(ge,{className:"size-5 text-[var(--ui-ink-faint)]"})]}),e.jsx("div",{className:"grid gap-3",children:s.exportOptions.map(a=>e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:a.label}),e.jsx("div",{className:"mt-1 text-sm leading-6 text-[var(--ui-ink-soft)]",children:a.description})]}),e.jsx(x,{variant:"secondary",pending:Q.isPending,pendingLabel:"Preparing",onClick:()=>void Q.mutateAsync(a.format),children:"Download"})]},a.format))})]})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.05fr)_minmax(0,0.95fr)]",children:[e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Backup history"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Go back to an older saved state if you need to undo a bad change."})]}),e.jsx(V,{className:"size-5 text-[var(--ui-ink-faint)]"})]}),e.jsx("div",{className:"grid gap-3",children:s.backups.length===0?e.jsx("div",{className:"rounded-[20px] border border-dashed border-[var(--ui-border-subtle)] px-4 py-6 text-sm text-[var(--ui-ink-soft)]",children:"No backups yet. Create one now so you have a safe restore point."}):s.backups.map(a=>e.jsxs("div",{className:"rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:w(a.createdAt)}),e.jsx(u,{tone:"meta",children:se(a.mode)})]}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:a.note||"Forge backup archive"})]}),e.jsx(x,{variant:"secondary",onClick:()=>{H({createSafetyBackup:!0}),R(null),P(a)},children:"Restore"})]}),e.jsxs("div",{className:"mt-3 grid gap-2 text-xs text-[var(--ui-ink-faint)] md:grid-cols-2",children:[e.jsx("div",{className:"break-all",children:a.archivePath}),e.jsx("div",{children:A(a.sizeBytes)})]})]},a.id))})]}),e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Find other Forge copies"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Search common folders on this machine for other Forge databases. Use this when Forge opened the wrong copy or when you think a newer copy exists somewhere else."})]}),e.jsxs(x,{variant:"secondary",pending:B.isPending,pendingLabel:"Scanning",onClick:()=>void B.mutateAsync(),children:[e.jsx(Y,{className:"size-4"}),"Scan now"]})]}),e.jsx("div",{className:"grid gap-3",children:b.length===0?e.jsx("div",{className:"rounded-[20px] border border-dashed border-[var(--ui-border-subtle)] px-4 py-6 text-sm text-[var(--ui-ink-soft)]",children:"No scan results yet. Run a scan to compare the live data folder with other Forge copies on disk."}):b.map(a=>e.jsxs("div",{className:$("rounded-[22px] border p-4",a.sameAsCurrent?"border-[color-mix(in_srgb,var(--success)_24%,var(--ui-border-subtle)_76%)] bg-[var(--ui-success-soft)]":a.newerThanCurrent?"border-[color-mix(in_srgb,var(--warning)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-warning-soft)]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)]"),children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:a.dataRoot}),e.jsx(u,{tone:"meta",children:a.sourceHint}),a.newerThanCurrent?e.jsx(u,{className:"bg-[var(--ui-warning-soft)] text-[var(--warning)]",children:"Newer than current"}):null,a.sameAsCurrent?e.jsx(u,{className:"bg-[var(--ui-success-soft)] text-[var(--success)]",children:"Current copy"}):null]}),e.jsx("div",{className:"mt-2 break-all text-sm text-[var(--ui-ink-soft)]",children:a.databasePath})]}),a.sameAsCurrent?null:e.jsx(x,{variant:"secondary",onClick:()=>{F({mode:"adopt_existing",targetDataRoot:a.dataRoot,createSafetyBackup:!0}),j(null),N(!0)},children:"Use this folder"})]}),e.jsxs("div",{className:"mt-4 grid gap-2 text-xs text-[var(--ui-ink-faint)] md:grid-cols-5",children:[e.jsx("div",{children:a.integrityMessage}),e.jsx("div",{children:w(a.databaseLastModifiedAt??new Date().toISOString())}),e.jsx("div",{children:A(a.databaseSizeBytes)}),e.jsxs("div",{children:[a.counts.notes," notes"]}),e.jsxs("div",{children:[a.counts.tasks," tasks"]})]})]},a.id))}),ce?e.jsxs("div",{className:"flex items-start gap-3 rounded-[20px] border border-[color-mix(in_srgb,var(--warning)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-warning-soft)] px-4 py-3 text-sm text-[var(--warning)]",children:[e.jsx(pe,{className:"mt-0.5 size-4 shrink-0"}),e.jsx("div",{children:"Forge found a copy on disk that looks newer than the one you are using now. Review it carefully before switching."})]}):null]})]})]}),e.jsx(ee,{open:ne,onOpenChange:a=>{N(a),a||j(null)},eyebrow:"Data folder",title:d.mode==="migrate_current"?"Move Forge data":"Use an existing Forge data folder",description:"This guided flow keeps the folder change explicit and gives you a safety backup option first.",value:d,onChange:F,draftPersistenceKey:`settings.data.root.${d.mode}`,steps:de,pending:_.isPending,pendingLabel:d.mode==="migrate_current"?"Moving data":"Switching folder",submitLabel:d.mode==="migrate_current"?"Move and switch":"Use this folder",error:ie??(_.error instanceof Error?_.error.message:null),onSubmit:async()=>{if(!d.targetDataRoot.trim()){j("Choose a data folder first.");return}j(null),await _.mutateAsync(d)}}),e.jsx(ee,{open:n!==null,onOpenChange:a=>{a||(P(null),R(null))},eyebrow:"Restore backup",title:"Restore Forge backup",description:"This flow replaces the live data with an older saved state.",value:K,onChange:H,draftPersistenceKey:n?`settings.data.restore.${n.id}`:"settings.data.restore",steps:ue,pending:M.isPending,pendingLabel:"Restoring",submitLabel:"Restore this backup",error:oe??(M.error instanceof Error?M.error.message:null),onSubmit:async()=>{if(!n){R("Choose a backup first.");return}R(null),await M.mutateAsync({backupId:n.id,createSafetyBackup:K.createSafetyBackup})}})]})}export{Ie as SettingsDataPage};
|
|
1
|
+
import{r as o,j as e,da as Y,db as V,cl as me,dc as Z,aQ as J,dd as xe,aD as ge,ca as pe}from"./vendor-BwL6m4SE.js";import{j as he,i as X,k}from"./state-Bpe5dF3T.js";import{a as ve,F as be,Q as ee}from"./question-flow-dialog-CskCt5NZ.js";import{I as ae,k as u,S as fe,e as te,B as x,C as y,c as $,cY as je,cZ as ke,f as ye,c_ as we,c$ as Ne,d0 as Fe,d1 as Se,cU as Re,d2 as De}from"./index-CQ5r7ZUz.js";import{S as Ce}from"./settings-section-nav-BmJWnrYk.js";import{P as Be}from"./page-hero-8bITsx_x.js";import{M as g}from"./metric-tile-CuP9DOYm.js";import"./ui-B9TWEtCx.js";import"./motion-DcgUnXhY.js";import"./board-CuxQRKPJ.js";import"./forms-D1qJ3oOP.js";function A(t){if(!Number.isFinite(t)||t<=0)return"0 B";const l=["B","KB","MB","GB","TB"];let i=t,m=0;for(;i>=1024&&m<l.length-1;)i/=1024,m+=1;return`${i.toFixed(i>=100?0:i>=10?1:2)} ${l[m]}`}function _e(t,l){const i=URL.createObjectURL(t),m=document.createElement("a");m.href=i,m.download=l,m.click(),URL.revokeObjectURL(i)}function Me(t){return t?t===1?"Every hour":t===24?"Every day":t===168?"Every week":`Every ${t} hours`:"Off"}function se(t){switch(t){case"manual":return"Manual";case"automatic":return"Automatic";case"pre_restore":return"Safety backup before restore";case"pre_switch_root":return"Safety backup before folder change";default:return t}}function w(t,l="Unknown time"){if(!t)return l;const i=new Date(t);return Number.isNaN(i.getTime())?l:ye(t)}function Ae({tone:t,message:l}){return e.jsx("div",{className:$("rounded-[20px] border px-4 py-3 text-sm leading-6",t==="success"?"border-[color-mix(in_srgb,var(--success)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-success-soft)] text-[var(--success)]":t==="warning"?"border-[color-mix(in_srgb,var(--warning)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-warning-soft)] text-[var(--warning)]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] text-[var(--ui-ink-soft)]"),children:l})}function z({label:t,value:l,icon:i}){return e.jsxs("div",{className:"min-w-0 overflow-hidden rounded-[24px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4",children:[e.jsxs("div",{className:"flex min-w-0 items-center gap-2 text-[11px] uppercase tracking-[0.16em] text-[var(--ui-ink-faint)]",children:[e.jsx(i,{className:"size-4"}),e.jsx("span",{className:"min-w-0 break-words",children:t})]}),e.jsx("div",{className:"mt-3 min-w-0 break-all text-sm leading-6 text-[var(--ui-ink-soft)] [overflow-wrap:anywhere]",children:l})]})}function Ie(){var G,W;const t=he(),[l,i]=o.useState(""),[m,T]=o.useState(""),[E,q]=o.useState(""),[U,O]=o.useState(!0),[b,re]=o.useState([]),[L,f]=o.useState(null),[ne,N]=o.useState(!1),[d,F]=o.useState({mode:"migrate_current",targetDataRoot:"",createSafetyBackup:!0}),[ie,j]=o.useState(null),[n,P]=o.useState(null),[K,H]=o.useState({createSafetyBackup:!0}),[oe,R]=o.useState(null),h=X({queryKey:["forge-operator-session"],queryFn:Re}),le=h.isSuccess,S=X({queryKey:["forge-data-management"],queryFn:De,enabled:le}),D=async()=>{await Promise.all([t.invalidateQueries({queryKey:["forge-operator-session"]}),t.invalidateQueries({queryKey:["forge-data-management"]})])},I=k({mutationFn:()=>we({backupDirectory:l,backupFrequencyHours:m==="off"?null:Number(m||"24"),backupRetentionDays:E==="forever"?null:Number(E||"30"),autoRepairEnabled:U}),onSuccess:async()=>{f({tone:"success",message:"Backup settings saved."}),await D()}}),C=k({mutationFn:()=>ke("Manual backup from Settings → Data"),onSuccess:async()=>{f({tone:"success",message:"Backup created."}),await D()}}),B=k({mutationFn:je,onSuccess:({candidates:a})=>{re(a),f({tone:a.some(c=>c.newerThanCurrent)?"warning":"neutral",message:a.length>0?`Found ${a.length} Forge ${a.length===1?"copy":"copies"} on disk.`:"No other Forge data copies were found in the scanned folders."})}}),_=k({mutationFn:a=>Fe({targetDataRoot:a.targetDataRoot,mode:a.mode,createSafetyBackup:a.createSafetyBackup}),onSuccess:async()=>{f({tone:"success",message:"Forge is now using the selected data folder."}),N(!1),await D()}}),M=k({mutationFn:({backupId:a,createSafetyBackup:c})=>Se(a,c),onSuccess:async()=>{f({tone:"success",message:"Backup restored. Forge is now running from that restored state."}),P(null),await D()}}),Q=k({mutationFn:async a=>{const c=await Ne(a);return _e(c.blob,c.fileName??`forge-export.${a}`),a},onSuccess:a=>{f({tone:"neutral",message:`Started download for ${a}.`})}}),s=(G=S.data)==null?void 0:G.data;o.useEffect(()=>{s&&(i(a=>a||s.settings.backupDirectory),T(a=>a||(s.settings.backupFrequencyHours?String(s.settings.backupFrequencyHours):"off")),O(s.settings.autoRepairEnabled),q(a=>a||(s.settings.backupRetentionDays?String(s.settings.backupRetentionDays):"forever")),F(a=>({...a,targetDataRoot:a.targetDataRoot||s.current.dataRoot})))},[s]);const ce=o.useMemo(()=>b.find(a=>a.newerThanCurrent),[b]),p=o.useMemo(()=>b.find(a=>a.dataRoot===d.targetDataRoot.trim()),[d.targetDataRoot,b]),de=[{id:"mode",eyebrow:"Step 1",title:"What do you want Forge to do?",description:"Choose whether Forge should move the current data into a new folder or switch to a folder that already contains the right Forge data.",render:(a,c)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(ve,{value:a.mode,onChange:v=>c({mode:v}),options:[{value:"migrate_current",label:"Move the current data",description:"Copy the live database and local secrets key into a new folder, then switch Forge to it."},{value:"adopt_existing",label:"Use an existing data folder",description:"Keep the target folder as it is and point Forge at that existing database directly."}]}),e.jsxs("label",{className:"flex items-start gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3",children:[e.jsx("input",{type:"checkbox",className:"mt-1",checked:a.createSafetyBackup,onChange:v=>c({createSafetyBackup:v.target.checked})}),e.jsx("span",{className:"text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Create one safety backup first."})]})]})},{id:"folder",eyebrow:"Step 2",title:d.mode==="migrate_current"?"Choose the new data folder":"Choose the data folder to use",description:d.mode==="migrate_current"?"Pick an empty folder for the moved Forge data.":"Pick the folder that already contains the Forge data you trust.",render:(a,c)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(be,{label:"Data folder",description:"Forge will place or read the database and backups from here.",children:e.jsx(ae,{value:a.targetDataRoot,onChange:v=>c({targetDataRoot:v.target.value}),placeholder:"/absolute/path/to/forge-data"})}),p?e.jsxs("div",{className:"rounded-[22px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:"Found on this machine"}),e.jsx("div",{className:"mt-2 break-all",children:p.databasePath}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[e.jsx(u,{tone:"meta",children:p.sourceHint}),e.jsxs(u,{tone:"meta",children:[p.counts.notes," notes"]}),e.jsxs(u,{tone:"meta",children:[p.counts.tasks," tasks"]}),p.newerThanCurrent?e.jsx(u,{className:"bg-[var(--ui-warning-soft)] text-[var(--warning)]",children:"Newer than the current copy"}):null]})]}):e.jsx("div",{className:"rounded-[22px] border border-dashed border-[var(--ui-border-subtle)] px-4 py-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:d.mode==="migrate_current"?"Forge will copy the current data into this folder and then switch over.":"If this folder already holds a Forge database, Forge will start using it after you confirm."})]})}],ue=[{id:"review",eyebrow:"Step 1",title:"Review the backup you want to restore",description:"Restoring replaces the current database with the selected backup.",render:(a,c)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"rounded-[22px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:n?w(n.createdAt):"Selected backup"}),e.jsx("div",{className:"mt-2",children:(n==null?void 0:n.note)||"Forge backup archive"}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[e.jsx(u,{tone:"meta",children:n?se(n.mode):"Backup"}),e.jsx(u,{tone:"meta",children:n?A(n.sizeBytes):"0 B"}),n!=null&&n.includesWiki?e.jsx(u,{tone:"meta",children:"Includes wiki"}):null]})]}),e.jsxs("label",{className:"flex items-start gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3",children:[e.jsx("input",{type:"checkbox",className:"mt-1",checked:a.createSafetyBackup,onChange:v=>c({createSafetyBackup:v.target.checked})}),e.jsx("span",{className:"text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Create one safety backup of the current state first."})]})]})},{id:"confirm",eyebrow:"Step 2",title:"Confirm the restore",description:"Use this only when you are confident this backup is the state you want back.",render:()=>e.jsx("div",{className:"rounded-[22px] border border-[color-mix(in_srgb,var(--warning)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-warning-soft)] p-4 text-sm leading-6 text-[var(--warning)]",children:"Forge will replace the live database with this backup, then reopen the restored copy."})}];if(h.isLoading||S.isLoading)return e.jsx(fe,{eyebrow:"Data",title:"Loading data controls",description:"Checking the live data folder, backup plan, and recovery tools.",columns:3,blocks:6});if(h.isError)return e.jsx(te,{eyebrow:"Data",error:h.error,onRetry:()=>void h.refetch()});if(S.isError||!s)return e.jsx(te,{eyebrow:"Data",error:S.error??new Error("Forge returned an empty data payload."),onRetry:()=>void S.refetch()});const r=s.current;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mx-auto grid w-full max-w-[1480px] gap-5",children:[e.jsx(Be,{eyebrow:"Data, backups, recovery",title:"Data",description:"See where Forge is saving the live data, keep it protected with backups, look for a newer copy on disk if something goes wrong, and download the database or its structure when you need it.",badge:`${r.integrityOk?"Healthy":"Needs attention"} · ${A(r.databaseSizeBytes)}`,actions:e.jsxs(e.Fragment,{children:[e.jsxs(x,{variant:"secondary",pending:B.isPending,pendingLabel:"Scanning",onClick:()=>void B.mutateAsync(),children:[e.jsx(Y,{className:"size-4"}),"Look for other Forge copies"]}),e.jsxs(x,{pending:C.isPending,pendingLabel:"Creating backup",onClick:()=>void C.mutateAsync(),children:[e.jsx(V,{className:"size-4"}),"Create backup now"]})]})}),e.jsx(Ce,{}),(W=h.data)!=null&&W.session?e.jsxs("div",{className:"rounded-[20px] border border-[color-mix(in_srgb,var(--success)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-success-soft)] px-4 py-3 text-sm text-[var(--ui-ink-medium)]",children:["You are managing Forge data as"," ",e.jsx("span",{className:"font-medium text-[var(--ui-ink-strong)]",children:h.data.session.actorLabel}),"."]}):null,L?e.jsx(Ae,{tone:L.tone,message:L.message}):null,e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.15fr)_minmax(0,0.85fr)]",children:[e.jsxs(y,{className:"grid gap-5",children:[e.jsxs("div",{className:"flex min-w-0 flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Live data folder"}),e.jsx("div",{className:"mt-2 min-w-0 break-all text-xl font-semibold text-[var(--ui-ink-strong)] [overflow-wrap:anywhere]",children:r.dataRoot}),e.jsx("div",{className:"mt-2 max-w-3xl text-sm leading-6 text-[var(--ui-ink-soft)]",children:"This is the folder Forge is reading and writing right now."})]}),e.jsx(u,{className:$(r.integrityOk?"bg-[var(--ui-success-soft)] text-[var(--success)]":"bg-[var(--ui-warning-soft)] text-[var(--warning)]"),children:r.integrityMessage})]}),e.jsxs("div",{className:"grid min-w-0 gap-3 md:grid-cols-2 xl:grid-cols-3",children:[e.jsx(z,{label:"Database file",value:r.databasePath,icon:me}),e.jsx(z,{label:"Folder layout",value:r.layout,icon:Z}),e.jsx(z,{label:"Last database change",value:r.databaseLastModifiedAt?w(r.databaseLastModifiedAt):"Unknown",icon:J})]}),e.jsxs("div",{className:"grid min-w-0 gap-3 md:grid-cols-3 xl:grid-cols-6",children:[e.jsx(g,{label:"Notes",value:r.counts.notes}),e.jsx(g,{label:"Goals",value:r.counts.goals}),e.jsx(g,{label:"Projects",value:r.counts.projects}),e.jsx(g,{label:"Tasks",value:r.counts.tasks}),e.jsx(g,{label:"Runs",value:r.counts.taskRuns}),e.jsx(g,{label:"Tags",value:r.counts.tags})]})]}),e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"flex size-11 items-center justify-center rounded-2xl border border-[color-mix(in_srgb,var(--success)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-success-soft)]",children:e.jsx(xe,{className:"size-5 text-[var(--success)]"})}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:"Protection plan"}),e.jsx("div",{className:"mt-1 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Choose where backups go, how often Forge creates them, and whether scans should call out newer copies found elsewhere on disk."})]})]}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-3",children:[e.jsx(g,{label:"Automatic backup",value:Me(s.settings.backupFrequencyHours),detail:s.settings.lastAutoBackupAt?`Last run ${w(s.settings.lastAutoBackupAt)}`:"No automatic backup recorded yet"}),e.jsx(g,{label:"Manual backup",value:s.settings.lastManualBackupAt?w(s.settings.lastManualBackupAt):"None yet",detail:`${s.backups.length} backup${s.backups.length===1?"":"s"} saved`}),e.jsx(g,{label:"Retention",value:s.settings.backupRetentionDays?`${s.settings.backupRetentionDays} days`:"Keep forever",detail:"Automatic backups only"})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-[var(--ui-ink-soft)]",children:"Backup folder"}),e.jsx(ae,{value:l,onChange:a=>i(a.target.value)})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-[var(--ui-ink-soft)]",children:"Automatic backup"}),e.jsxs("select",{className:"h-11 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-3 text-sm text-[var(--ui-ink-strong)] outline-none transition focus:border-[var(--primary)]",value:m||"24",onChange:a=>T(a.target.value),children:[e.jsx("option",{value:"off",children:"Off"}),e.jsx("option",{value:"1",children:"Every hour"}),e.jsx("option",{value:"6",children:"Every 6 hours"}),e.jsx("option",{value:"24",children:"Every day"}),e.jsx("option",{value:"168",children:"Every week"})]})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-[var(--ui-ink-soft)]",children:"Keep automatic backups"}),e.jsxs("select",{className:"h-11 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-3 text-sm text-[var(--ui-ink-strong)] outline-none transition focus:border-[var(--primary)]",value:E||"30",onChange:a=>q(a.target.value),children:[e.jsx("option",{value:"7",children:"7 days"}),e.jsx("option",{value:"14",children:"14 days"}),e.jsx("option",{value:"30",children:"30 days"}),e.jsx("option",{value:"90",children:"90 days"}),e.jsx("option",{value:"365",children:"1 year"}),e.jsx("option",{value:"forever",children:"Keep forever"})]})]}),e.jsxs("label",{className:"flex items-start gap-3 rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3",children:[e.jsx("input",{type:"checkbox",className:"mt-1",checked:U,onChange:a=>O(a.target.checked)}),e.jsx("span",{className:"text-sm leading-6 text-[var(--ui-ink-soft)]",children:"When I scan, point out Forge copies that look newer than the one I am using now."})]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(x,{pending:I.isPending,pendingLabel:"Saving",onClick:()=>void I.mutateAsync(),children:"Save backup settings"}),e.jsx(x,{variant:"secondary",pending:C.isPending,pendingLabel:"Creating backup",onClick:()=>void C.mutateAsync(),children:"Create backup now"})]})]})]})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]",children:[e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Change data folder"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Move today’s Forge data into a new folder, or switch to another folder that already contains the right Forge database."})]}),e.jsxs("div",{className:"rounded-[22px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:"Current folder"}),e.jsx("div",{className:"mt-2 break-all",children:r.dataRoot}),p?e.jsxs("div",{className:"mt-3 text-sm text-[var(--ui-ink-soft)]",children:["Selected scanned copy: ",p.dataRoot]}):null]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsxs(x,{onClick:()=>{F(a=>({...a,mode:"migrate_current",targetDataRoot:a.targetDataRoot||r.dataRoot})),j(null),N(!0)},children:[e.jsx(Z,{className:"size-4"}),"Move current data"]}),e.jsxs(x,{variant:"secondary",onClick:()=>{F(a=>({...a,mode:"adopt_existing",targetDataRoot:a.targetDataRoot||r.dataRoot})),j(null),N(!0)},children:[e.jsx(J,{className:"size-4"}),"Use existing data folder"]})]})]}),e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Downloads"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Download the live database itself, or export a structure and table snapshot in other formats."})]}),e.jsx(ge,{className:"size-5 text-[var(--ui-ink-faint)]"})]}),e.jsx("div",{className:"grid gap-3",children:s.exportOptions.map(a=>e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:a.label}),e.jsx("div",{className:"mt-1 text-sm leading-6 text-[var(--ui-ink-soft)]",children:a.description})]}),e.jsx(x,{variant:"secondary",pending:Q.isPending,pendingLabel:"Preparing",onClick:()=>void Q.mutateAsync(a.format),children:"Download"})]},a.format))})]})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.05fr)_minmax(0,0.95fr)]",children:[e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Backup history"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Go back to an older saved state if you need to undo a bad change."})]}),e.jsx(V,{className:"size-5 text-[var(--ui-ink-faint)]"})]}),e.jsx("div",{className:"grid gap-3",children:s.backups.length===0?e.jsx("div",{className:"rounded-[20px] border border-dashed border-[var(--ui-border-subtle)] px-4 py-6 text-sm text-[var(--ui-ink-soft)]",children:"No backups yet. Create one now so you have a safe restore point."}):s.backups.map(a=>e.jsxs("div",{className:"rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:w(a.createdAt)}),e.jsx(u,{tone:"meta",children:se(a.mode)})]}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:a.note||"Forge backup archive"})]}),e.jsx(x,{variant:"secondary",onClick:()=>{H({createSafetyBackup:!0}),R(null),P(a)},children:"Restore"})]}),e.jsxs("div",{className:"mt-3 grid gap-2 text-xs text-[var(--ui-ink-faint)] md:grid-cols-2",children:[e.jsx("div",{className:"break-all",children:a.archivePath}),e.jsx("div",{children:A(a.sizeBytes)})]})]},a.id))})]}),e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Find other Forge copies"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Search common folders on this machine for other Forge databases. Use this when Forge opened the wrong copy or when you think a newer copy exists somewhere else."})]}),e.jsxs(x,{variant:"secondary",pending:B.isPending,pendingLabel:"Scanning",onClick:()=>void B.mutateAsync(),children:[e.jsx(Y,{className:"size-4"}),"Scan now"]})]}),e.jsx("div",{className:"grid gap-3",children:b.length===0?e.jsx("div",{className:"rounded-[20px] border border-dashed border-[var(--ui-border-subtle)] px-4 py-6 text-sm text-[var(--ui-ink-soft)]",children:"No scan results yet. Run a scan to compare the live data folder with other Forge copies on disk."}):b.map(a=>e.jsxs("div",{className:$("rounded-[22px] border p-4",a.sameAsCurrent?"border-[color-mix(in_srgb,var(--success)_24%,var(--ui-border-subtle)_76%)] bg-[var(--ui-success-soft)]":a.newerThanCurrent?"border-[color-mix(in_srgb,var(--warning)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-warning-soft)]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)]"),children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:a.dataRoot}),e.jsx(u,{tone:"meta",children:a.sourceHint}),a.newerThanCurrent?e.jsx(u,{className:"bg-[var(--ui-warning-soft)] text-[var(--warning)]",children:"Newer than current"}):null,a.sameAsCurrent?e.jsx(u,{className:"bg-[var(--ui-success-soft)] text-[var(--success)]",children:"Current copy"}):null]}),e.jsx("div",{className:"mt-2 break-all text-sm text-[var(--ui-ink-soft)]",children:a.databasePath})]}),a.sameAsCurrent?null:e.jsx(x,{variant:"secondary",onClick:()=>{F({mode:"adopt_existing",targetDataRoot:a.dataRoot,createSafetyBackup:!0}),j(null),N(!0)},children:"Use this folder"})]}),e.jsxs("div",{className:"mt-4 grid gap-2 text-xs text-[var(--ui-ink-faint)] md:grid-cols-5",children:[e.jsx("div",{children:a.integrityMessage}),e.jsx("div",{children:w(a.databaseLastModifiedAt??new Date().toISOString())}),e.jsx("div",{children:A(a.databaseSizeBytes)}),e.jsxs("div",{children:[a.counts.notes," notes"]}),e.jsxs("div",{children:[a.counts.tasks," tasks"]})]})]},a.id))}),ce?e.jsxs("div",{className:"flex items-start gap-3 rounded-[20px] border border-[color-mix(in_srgb,var(--warning)_26%,var(--ui-border-subtle)_74%)] bg-[var(--ui-warning-soft)] px-4 py-3 text-sm text-[var(--warning)]",children:[e.jsx(pe,{className:"mt-0.5 size-4 shrink-0"}),e.jsx("div",{children:"Forge found a copy on disk that looks newer than the one you are using now. Review it carefully before switching."})]}):null]})]})]}),e.jsx(ee,{open:ne,onOpenChange:a=>{N(a),a||j(null)},eyebrow:"Data folder",title:d.mode==="migrate_current"?"Move Forge data":"Use an existing Forge data folder",description:"This guided flow keeps the folder change explicit and gives you a safety backup option first.",value:d,onChange:F,draftPersistenceKey:`settings.data.root.${d.mode}`,steps:de,pending:_.isPending,pendingLabel:d.mode==="migrate_current"?"Moving data":"Switching folder",submitLabel:d.mode==="migrate_current"?"Move and switch":"Use this folder",error:ie??(_.error instanceof Error?_.error.message:null),onSubmit:async()=>{if(!d.targetDataRoot.trim()){j("Choose a data folder first.");return}j(null),await _.mutateAsync(d)}}),e.jsx(ee,{open:n!==null,onOpenChange:a=>{a||(P(null),R(null))},eyebrow:"Restore backup",title:"Restore Forge backup",description:"This flow replaces the live data with an older saved state.",value:K,onChange:H,draftPersistenceKey:n?`settings.data.restore.${n.id}`:"settings.data.restore",steps:ue,pending:M.isPending,pendingLabel:"Restoring",submitLabel:"Restore this backup",error:oe??(M.error instanceof Error?M.error.message:null),onSubmit:async()=>{if(!n){R("Choose a backup first.");return}R(null),await M.mutateAsync({backupId:n.id,createSafetyBackup:K.createSafetyBackup})}})]})}export{Ie as SettingsDataPage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{bY as H,r as c,j as r,cn as V,aK as Q,b7 as G,F as J}from"./vendor-Cpmju3nw.js";import{x as W}from"./state-BtwEvpO6.js";import{k as q,S as Y,e as X,C as F,B as A,I as Z,dN as ee,c as z,dO as te,b as se}from"./index-BaiwtAgo.js";import{P as re}from"./page-hero-C0MpI3MM.js";import{S as ne}from"./settings-section-nav-CwSDNC3W.js";import{u as ie}from"./use-anchored-overlay-position-BrQ4cqKn.js";import"./motion-DwjmC9aq.js";import"./ui-B9O-eUim.js";import"./board-CLOHbg6t.js";import"./forms-C5d5hTf2.js";const ae=["error","warning","info","debug"],oe=["server","ui","system","agent","openclaw"],le=60,P="text-[11px] font-medium uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",T="text-[var(--ui-ink-soft)]",h="text-[var(--ui-ink-faint)]",ce="text-[var(--ui-ink-strong)]",de="bg-[var(--ui-surface-3)] text-[var(--ui-ink-medium)]",ue="relative rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-3 py-2.5",ge="inline-flex max-w-full items-center gap-1.5 rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-1.5 py-1",me="z-[80] overflow-y-auto overscroll-contain rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-popover)] p-2 shadow-[var(--ui-shadow-floating)] backdrop-blur-xl [webkit-overflow-scrolling:touch]",fe="rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3";function L(t){return t.trim().toLowerCase()}function C(t){return Array.from(new Set(t.map(n=>(n==null?void 0:n.trim())??"").filter(Boolean)))}function $(t,n){const s=C(t.getAll(n));if(s.length>0)return s;const a=t.get(n);return a!=null&&a.trim()?[a.trim()]:[]}function pe(t){return new Intl.DateTimeFormat(void 0,{dateStyle:"medium",timeStyle:"medium"}).format(new Date(t))}function U(t){return t==="error"?"border-[color-mix(in_srgb,var(--danger)_30%,var(--ui-border-subtle)_70%)] bg-[var(--ui-danger-soft)] text-[color-mix(in_srgb,var(--danger)_76%,var(--ui-ink-strong)_24%)]":t==="warning"?"border-[color-mix(in_srgb,var(--warning)_30%,var(--ui-border-subtle)_70%)] bg-[var(--ui-warning-soft)] text-[color-mix(in_srgb,var(--warning)_78%,var(--ui-ink-strong)_22%)]":t==="info"?"border-[color-mix(in_srgb,var(--primary)_30%,var(--ui-border-subtle)_70%)] bg-[var(--ui-accent-soft)] text-[var(--primary)]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-3)] text-[var(--ui-ink-medium)]"}function B(t){return t==="error"?"Errors":t==="warning"?"Warnings":t==="info"?"Info":"Debug"}function R(t){return t==="openclaw"?"OpenClaw":t.charAt(0).toUpperCase()+t.slice(1)}function xe(t){return[t.scope?`scope: ${t.scope}`:null,t.eventKey?`event: ${t.eventKey}`:null,t.route?`route: ${t.route}`:null,t.functionName?`function: ${t.functionName}`:null,t.jobId?`job: ${t.jobId}`:null,t.entityType&&t.entityId?`entity: ${t.entityType}:${t.entityId}`:null,t.requestId?`request: ${t.requestId}`:null].filter(n=>!!n)}function he(t){return L([t.message,t.scope,t.eventKey,t.route,t.functionName,t.requestId,t.entityType,t.entityId,t.jobId,JSON.stringify(t.details)].filter(Boolean).join(" "))}function j(t,n){return r.jsx(q,{size:"sm",className:z(de,n),children:t})}function K(t,n){return te(t)?r.jsx(se,{kind:t,label:n,compact:!0,gradient:!1}):j(n,"bg-[var(--ui-accent-soft)] text-[var(--primary)]")}function k({label:t,placeholder:n,options:s,selectedIds:a,onChange:m,emptyMessage:u="No matches yet."}){const[w,d]=c.useState(!1),[b,v]=c.useState(""),[I,y]=c.useState(0),E=c.useRef(null),M=c.useRef(null),O=ie(E,w,{offset:8,preferredMaxHeight:320,minHeight:160}),_=c.useMemo(()=>a.map(i=>s.find(o=>o.id===i)??null).filter(i=>i!==null),[s,a]),p=L(b),x=c.useMemo(()=>{const i=s.filter(o=>!a.includes(o.id));return p?i.filter(o=>L(`${o.label} ${o.description??""} ${o.searchText??""}`).includes(p)).slice(0,10):i.slice(0,10)},[p,s,a]),N=i=>{a.includes(i)||(m([...a,i]),v(""),y(0),d(!1))},D=i=>{m(a.filter(o=>o!==i))};return c.useEffect(()=>{if(!w)return;const i=e=>{var g,f;const l=e.target;(g=E.current)!=null&&g.contains(l)||(f=M.current)!=null&&f.contains(l)||d(!1)},o=e=>{e.key==="Escape"&&d(!1)};return document.addEventListener("pointerdown",i),document.addEventListener("keydown",o),()=>{document.removeEventListener("pointerdown",i),document.removeEventListener("keydown",o)}},[w]),r.jsxs("label",{className:"grid gap-2",children:[r.jsx("span",{className:P,children:t}),r.jsxs("div",{ref:E,className:ue,children:[_.length>0?r.jsx("div",{className:"mb-2 flex flex-wrap gap-1.5",children:_.map(i=>r.jsxs("span",{className:ge,children:[i.badge,r.jsx("button",{type:"button",className:`rounded-full p-0.5 transition hover:text-[var(--ui-ink-strong)] ${h}`,onClick:()=>D(i.id),"aria-label":`Remove ${i.label}`,children:r.jsx(Q,{className:"size-3"})})]},i.id))}):null,r.jsxs("div",{className:"flex items-center gap-2",children:[r.jsx(G,{className:`size-3.5 ${h}`}),r.jsx("input",{value:b,onChange:i=>{v(i.target.value),y(0),d(!0)},onFocus:()=>d(!0),onKeyDown:i=>{if(i.key==="Backspace"&&!b&&a.length>0){D(a[a.length-1]);return}if(i.key==="ArrowDown"){i.preventDefault(),d(!0),y(o=>x.length===0?0:Math.min(x.length-1,o+1));return}if(i.key==="ArrowUp"){i.preventDefault(),y(o=>Math.max(0,o-1));return}if(i.key==="Escape"){d(!1);return}i.key==="Enter"&&x[I]&&(i.preventDefault(),N(x[I].id))},placeholder:n,className:"min-w-0 flex-1 bg-transparent text-sm text-[var(--ui-ink-strong)] placeholder:text-[var(--ui-ink-faint)] focus:outline-none"})]}),w&&O&&typeof document<"u"?J.createPortal(r.jsx("div",{ref:M,role:"listbox","aria-multiselectable":"true",className:me,style:O,children:x.length>0?x.map((i,o)=>r.jsx("button",{type:"button",role:"option","aria-selected":!1,className:z("flex w-full items-start justify-between gap-3 rounded-[16px] px-3 py-2 text-left transition",o===I?"bg-[var(--ui-accent-soft)] text-[var(--ui-ink-strong)]":"text-[var(--ui-ink-soft)] hover:bg-[var(--ui-surface-hover)] hover:text-[var(--ui-ink-strong)]"),onMouseEnter:()=>y(o),onMouseDown:e=>e.preventDefault(),onClick:()=>N(i.id),children:r.jsxs("div",{className:"min-w-0",children:[r.jsx("div",{className:"truncate text-sm font-medium",children:i.menuBadge??i.badge}),i.description?r.jsx("div",{className:`mt-1 text-xs leading-5 ${h}`,children:i.description}):null]})},i.id)):r.jsx("div",{className:`px-3 py-2 text-sm ${h}`,children:u})}),document.body):null]})]})}function be(t,n){const s=`${n.entityType}:${n.entityId}`;t.has(s)||t.set(s,{id:s,label:n.label,description:n.description,searchText:n.searchText,badge:n.badge,menuBadge:n.menuBadge})}function ve(t){const n=new Map;for(const s of t){if(!s.entityType||!s.entityId)continue;const a=`${s.entityType}:${s.entityId}`;if(n.has(a))continue;const m=s.entityType==="wiki_ingest_job"?`Ingest ${s.entityId}`:`${s.entityType} ${s.entityId}`;be(n,{entityType:s.entityType,entityId:s.entityId,label:m,description:"Seen in diagnostics logs",searchText:L(`${m} ${s.scope} ${s.message} ${s.eventKey}`),badge:K(s.entityType,m),menuBadge:K(s.entityType,m)})}return Array.from(n.values()).sort((s,a)=>s.label.localeCompare(a.label))}const ye=c.memo(function({entry:n}){const[s,a]=c.useState(!1),m=c.useMemo(()=>s&&Object.keys(n.details).length>0?JSON.stringify(n.details,null,2):"",[s,n.details]);return r.jsxs(F,{className:"grid gap-4",children:[r.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[r.jsxs("div",{className:"grid min-w-0 gap-3",children:[r.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[r.jsx("span",{className:z("rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em]",U(n.level)),children:n.level}),r.jsx("span",{className:`rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-3)] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] ${T}`,children:n.source}),r.jsx("span",{className:`rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-3)] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] ${T}`,children:n.scope}),n.eventKey?r.jsx("span",{className:`max-w-full break-words rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-3)] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] [overflow-wrap:anywhere] ${h}`,children:n.eventKey}):null]}),r.jsx("div",{className:`break-words text-base font-medium [overflow-wrap:anywhere] ${ce}`,children:n.message}),r.jsx("div",{className:`flex flex-wrap gap-3 break-words text-xs [overflow-wrap:anywhere] ${h}`,children:xe(n).map(u=>r.jsx("span",{children:u},u))})]}),r.jsxs("div",{className:`shrink-0 text-right text-xs ${h}`,children:[r.jsx("div",{children:pe(n.createdAt)}),r.jsx("div",{className:"mt-1 font-mono text-[11px]",children:n.id})]})]}),Object.keys(n.details).length>0?r.jsxs("details",{className:fe,onToggle:u=>a(u.currentTarget.open),children:[r.jsx("summary",{className:`cursor-pointer text-sm ${T}`,children:"View structured details"}),s?r.jsx("pre",{className:`mt-3 overflow-x-auto whitespace-pre-wrap text-xs leading-6 ${T}`,children:m}):null]}):null]})});function Le(){const[t,n]=H(),s=c.useMemo(()=>{var f,S;const e=((f=t.get("entityType"))==null?void 0:f.trim())||"",l=((S=t.get("entityId"))==null?void 0:S.trim())||"",g=$(t,"entity");return g.length===0&&e&&l&&g.push(`${e}:${l}`),{search:t.get("search")||"",levels:$(t,"level"),sources:$(t,"source"),scopes:$(t,"scope"),routes:$(t,"route"),jobs:$(t,"jobId"),entities:C(g)}},[t]),a=W({queryKey:["forge-diagnostic-logs","settings-filters"],initialPageParam:null,queryFn:({pageParam:e})=>ee({limit:le,beforeCreatedAt:e==null?void 0:e.beforeCreatedAt,beforeId:e==null?void 0:e.beforeId}),getNextPageParam:e=>e.nextCursor,retry:!1,refetchOnWindowFocus:!1}),m=(e,l)=>{const g=new URLSearchParams(t);l.trim()?g.set(e,l.trim()):g.delete(e),n(g,{replace:!0})},u=(e,l,g=[])=>{const f=new URLSearchParams(t);f.delete(e);for(const S of g)f.delete(S);for(const S of C(l))f.append(e,S);n(f,{replace:!0})},w=()=>{const e=new URLSearchParams(t);["search","level","source","scope","route","jobId","entity","entityType","entityId"].forEach(l=>e.delete(l)),n(e,{replace:!0})},d=c.useMemo(()=>{var e;return((e=a.data)==null?void 0:e.pages.flatMap(l=>l.logs))??[]},[a.data]),b=L(s.search),v=c.useRef(null),I=c.useMemo(()=>ae.map(e=>({id:e,label:B(e),searchText:`${e} ${B(e)}`,badge:r.jsx(q,{size:"sm",className:U(e),children:B(e)})})),[]),y=c.useMemo(()=>oe.map(e=>({id:e,label:R(e),searchText:`${e} ${R(e)}`,badge:j(R(e))})),[]),E=c.useMemo(()=>C(d.map(e=>e.scope)).map(e=>({id:e,label:e,searchText:e,badge:j(e)})),[d]),M=c.useMemo(()=>C(d.map(e=>e.route)).map(e=>({id:e,label:e,description:"Filter logs to one or more exact routes.",searchText:e,badge:j(e,"max-w-[16rem]"),menuBadge:j(e)})),[d]),O=c.useMemo(()=>C(d.map(e=>e.jobId)).map(e=>({id:e,label:e,description:"Background job or ingest run id.",searchText:e,badge:j(e,"max-w-[14rem]"),menuBadge:j(e)})),[d]),_=c.useMemo(()=>ve(d),[d]),p=c.useMemo(()=>d.filter(e=>{if(b&&!he(e).includes(b)||s.levels.length>0&&!s.levels.includes(e.level)||s.sources.length>0&&!s.sources.includes(e.source)||s.scopes.length>0&&!s.scopes.includes(e.scope)||s.routes.length>0&&!s.routes.includes(e.route??"")||s.jobs.length>0&&!s.jobs.includes(e.jobId??""))return!1;if(s.entities.length>0){const l=e.entityType&&e.entityId?`${e.entityType}:${e.entityId}`:"";if(!l||!s.entities.includes(l))return!1}return!0}),[s,b,d]),x=[s.search,s.levels.join("|"),s.sources.join("|"),s.scopes.join("|"),s.routes.join("|"),s.jobs.join("|"),s.entities.join("|")].join("::");c.useEffect(()=>{var e;(e=v.current)==null||e.scrollTo({top:0})},[x]);const N=V({count:p.length,getScrollElement:()=>v.current,estimateSize:()=>260,overscan:8}),D=N.getVirtualItems(),i=()=>{const e=v.current;if(!e||!a.hasNextPage||a.isFetchingNextPage)return;e.scrollHeight-e.scrollTop-e.clientHeight<=800&&a.fetchNextPage()},o=s.levels.length+s.sources.length+s.scopes.length+s.routes.length+s.jobs.length+s.entities.length+(s.search.trim()?1:0);return a.isPending?r.jsx(Y,{eyebrow:"Settings",title:"Loading diagnostics",description:"Collecting the latest frontend, backend, and runtime traces.",columns:1,blocks:6}):a.isError?r.jsx(X,{eyebrow:"Settings",error:a.error,onRetry:()=>void a.refetch()}):r.jsxs("div",{className:"mx-auto grid w-full max-w-[1220px] gap-5",children:[r.jsx(re,{title:"Logs",description:"Inspect shared diagnostics from the UI, backend routes, background jobs, and LLM flows.",badge:`${p.length} matching${p.length!==d.length?` · ${d.length} loaded`:""}${a.hasNextPage?" · more available":""}`}),r.jsx(ne,{}),r.jsxs(F,{className:"grid gap-4",children:[r.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[r.jsxs("div",{children:[r.jsx("div",{className:P,children:"Filters"}),r.jsx("div",{className:`mt-2 max-w-3xl text-sm leading-6 ${T}`,children:"Use token filters with OR-style badge selections for levels, sources, routes, jobs, scopes, and linked entities. Search still matches the message body and structured details."})]}),r.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[o>0?r.jsxs(A,{variant:"ghost",size:"sm",onClick:w,children:["Clear ",o]}):null,r.jsx(A,{variant:"secondary",size:"sm",onClick:()=>void a.refetch(),pending:a.isRefetching&&!a.isFetchingNextPage,pendingLabel:"Refreshing",children:"Refresh"})]})]}),r.jsxs("label",{className:"grid gap-2",children:[r.jsx("span",{className:P,children:"Search message or details"}),r.jsx(Z,{value:s.search,onChange:e=>m("search",e.target.value),placeholder:"LLM compilation failed, wiki_ingest, request_failed…",className:"h-11 rounded-[20px]"})]}),r.jsxs("div",{className:"grid gap-3 xl:grid-cols-2",children:[r.jsx(k,{label:"Levels",placeholder:"Add one or more levels",options:I,selectedIds:s.levels,onChange:e=>u("level",e),emptyMessage:"No additional log levels."}),r.jsx(k,{label:"Sources",placeholder:"Add one or more sources",options:y,selectedIds:s.sources,onChange:e=>u("source",e),emptyMessage:"No additional log sources."}),r.jsx(k,{label:"Scopes",placeholder:"Search scopes",options:E,selectedIds:s.scopes,onChange:e=>u("scope",e),emptyMessage:"No scopes match the current logs."}),r.jsx(k,{label:"Routes",placeholder:"Search exact routes",options:M,selectedIds:s.routes,onChange:e=>u("route",e),emptyMessage:"No routes match the current logs."}),r.jsx(k,{label:"Jobs",placeholder:"Search job ids",options:O,selectedIds:s.jobs,onChange:e=>u("jobId",e),emptyMessage:"No job ids match the current logs."}),r.jsx(k,{label:"Entities",placeholder:"Search Forge entities or logged ids",options:_,selectedIds:s.entities,onChange:e=>u("entity",e,["entityType","entityId"]),emptyMessage:"No logged entities match yet."})]})]}),r.jsx("div",{className:"grid gap-3",children:p.length===0?r.jsx(F,{className:`text-sm ${T}`,children:"No diagnostic entries match the current filters yet."}):r.jsx(F,{className:"p-0",children:r.jsxs("div",{ref:v,onScroll:i,className:"h-[72vh] overflow-y-auto px-3 py-3",children:[r.jsx("div",{className:"relative",style:{height:`${N.getTotalSize()}px`},children:D.map(e=>{const l=p[e.index];return l?r.jsx("div",{"data-index":e.index,ref:N.measureElement,className:"absolute left-0 top-0 w-full pb-3",style:{transform:`translateY(${e.start}px)`},children:r.jsx(ye,{entry:l})},l.id):null})}),r.jsx("div",{className:`border-t border-[var(--ui-border-subtle)] px-1 py-3 text-center text-xs ${h}`,children:a.isFetchingNextPage?"Loading older logs...":a.hasNextPage?"Scroll to load older logs.":`Showing all ${d.length} loaded logs.`})]})})})]})}export{Le as SettingsLogsPage};
|
|
1
|
+
import{bY as H,r as c,j as r,cn as V,aK as Q,b7 as G,F as J}from"./vendor-BwL6m4SE.js";import{x as W}from"./state-Bpe5dF3T.js";import{k as q,S as Y,e as X,C as F,B as A,I as Z,dN as ee,c as z,dO as te,b as se}from"./index-CQ5r7ZUz.js";import{P as re}from"./page-hero-8bITsx_x.js";import{S as ne}from"./settings-section-nav-BmJWnrYk.js";import{u as ie}from"./use-anchored-overlay-position-BY4kNzPj.js";import"./motion-DcgUnXhY.js";import"./ui-B9TWEtCx.js";import"./board-CuxQRKPJ.js";import"./forms-D1qJ3oOP.js";const ae=["error","warning","info","debug"],oe=["server","ui","system","agent","openclaw"],le=60,P="text-[11px] font-medium uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",T="text-[var(--ui-ink-soft)]",h="text-[var(--ui-ink-faint)]",ce="text-[var(--ui-ink-strong)]",de="bg-[var(--ui-surface-3)] text-[var(--ui-ink-medium)]",ue="relative rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-3 py-2.5",ge="inline-flex max-w-full items-center gap-1.5 rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-1.5 py-1",me="z-[80] overflow-y-auto overscroll-contain rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-popover)] p-2 shadow-[var(--ui-shadow-floating)] backdrop-blur-xl [webkit-overflow-scrolling:touch]",fe="rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3";function L(t){return t.trim().toLowerCase()}function C(t){return Array.from(new Set(t.map(n=>(n==null?void 0:n.trim())??"").filter(Boolean)))}function $(t,n){const s=C(t.getAll(n));if(s.length>0)return s;const a=t.get(n);return a!=null&&a.trim()?[a.trim()]:[]}function pe(t){return new Intl.DateTimeFormat(void 0,{dateStyle:"medium",timeStyle:"medium"}).format(new Date(t))}function U(t){return t==="error"?"border-[color-mix(in_srgb,var(--danger)_30%,var(--ui-border-subtle)_70%)] bg-[var(--ui-danger-soft)] text-[color-mix(in_srgb,var(--danger)_76%,var(--ui-ink-strong)_24%)]":t==="warning"?"border-[color-mix(in_srgb,var(--warning)_30%,var(--ui-border-subtle)_70%)] bg-[var(--ui-warning-soft)] text-[color-mix(in_srgb,var(--warning)_78%,var(--ui-ink-strong)_22%)]":t==="info"?"border-[color-mix(in_srgb,var(--primary)_30%,var(--ui-border-subtle)_70%)] bg-[var(--ui-accent-soft)] text-[var(--primary)]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-3)] text-[var(--ui-ink-medium)]"}function B(t){return t==="error"?"Errors":t==="warning"?"Warnings":t==="info"?"Info":"Debug"}function R(t){return t==="openclaw"?"OpenClaw":t.charAt(0).toUpperCase()+t.slice(1)}function xe(t){return[t.scope?`scope: ${t.scope}`:null,t.eventKey?`event: ${t.eventKey}`:null,t.route?`route: ${t.route}`:null,t.functionName?`function: ${t.functionName}`:null,t.jobId?`job: ${t.jobId}`:null,t.entityType&&t.entityId?`entity: ${t.entityType}:${t.entityId}`:null,t.requestId?`request: ${t.requestId}`:null].filter(n=>!!n)}function he(t){return L([t.message,t.scope,t.eventKey,t.route,t.functionName,t.requestId,t.entityType,t.entityId,t.jobId,JSON.stringify(t.details)].filter(Boolean).join(" "))}function j(t,n){return r.jsx(q,{size:"sm",className:z(de,n),children:t})}function K(t,n){return te(t)?r.jsx(se,{kind:t,label:n,compact:!0,gradient:!1}):j(n,"bg-[var(--ui-accent-soft)] text-[var(--primary)]")}function k({label:t,placeholder:n,options:s,selectedIds:a,onChange:m,emptyMessage:u="No matches yet."}){const[w,d]=c.useState(!1),[b,v]=c.useState(""),[I,y]=c.useState(0),E=c.useRef(null),M=c.useRef(null),O=ie(E,w,{offset:8,preferredMaxHeight:320,minHeight:160}),_=c.useMemo(()=>a.map(i=>s.find(o=>o.id===i)??null).filter(i=>i!==null),[s,a]),p=L(b),x=c.useMemo(()=>{const i=s.filter(o=>!a.includes(o.id));return p?i.filter(o=>L(`${o.label} ${o.description??""} ${o.searchText??""}`).includes(p)).slice(0,10):i.slice(0,10)},[p,s,a]),N=i=>{a.includes(i)||(m([...a,i]),v(""),y(0),d(!1))},D=i=>{m(a.filter(o=>o!==i))};return c.useEffect(()=>{if(!w)return;const i=e=>{var g,f;const l=e.target;(g=E.current)!=null&&g.contains(l)||(f=M.current)!=null&&f.contains(l)||d(!1)},o=e=>{e.key==="Escape"&&d(!1)};return document.addEventListener("pointerdown",i),document.addEventListener("keydown",o),()=>{document.removeEventListener("pointerdown",i),document.removeEventListener("keydown",o)}},[w]),r.jsxs("label",{className:"grid gap-2",children:[r.jsx("span",{className:P,children:t}),r.jsxs("div",{ref:E,className:ue,children:[_.length>0?r.jsx("div",{className:"mb-2 flex flex-wrap gap-1.5",children:_.map(i=>r.jsxs("span",{className:ge,children:[i.badge,r.jsx("button",{type:"button",className:`rounded-full p-0.5 transition hover:text-[var(--ui-ink-strong)] ${h}`,onClick:()=>D(i.id),"aria-label":`Remove ${i.label}`,children:r.jsx(Q,{className:"size-3"})})]},i.id))}):null,r.jsxs("div",{className:"flex items-center gap-2",children:[r.jsx(G,{className:`size-3.5 ${h}`}),r.jsx("input",{value:b,onChange:i=>{v(i.target.value),y(0),d(!0)},onFocus:()=>d(!0),onKeyDown:i=>{if(i.key==="Backspace"&&!b&&a.length>0){D(a[a.length-1]);return}if(i.key==="ArrowDown"){i.preventDefault(),d(!0),y(o=>x.length===0?0:Math.min(x.length-1,o+1));return}if(i.key==="ArrowUp"){i.preventDefault(),y(o=>Math.max(0,o-1));return}if(i.key==="Escape"){d(!1);return}i.key==="Enter"&&x[I]&&(i.preventDefault(),N(x[I].id))},placeholder:n,className:"min-w-0 flex-1 bg-transparent text-sm text-[var(--ui-ink-strong)] placeholder:text-[var(--ui-ink-faint)] focus:outline-none"})]}),w&&O&&typeof document<"u"?J.createPortal(r.jsx("div",{ref:M,role:"listbox","aria-multiselectable":"true",className:me,style:O,children:x.length>0?x.map((i,o)=>r.jsx("button",{type:"button",role:"option","aria-selected":!1,className:z("flex w-full items-start justify-between gap-3 rounded-[16px] px-3 py-2 text-left transition",o===I?"bg-[var(--ui-accent-soft)] text-[var(--ui-ink-strong)]":"text-[var(--ui-ink-soft)] hover:bg-[var(--ui-surface-hover)] hover:text-[var(--ui-ink-strong)]"),onMouseEnter:()=>y(o),onMouseDown:e=>e.preventDefault(),onClick:()=>N(i.id),children:r.jsxs("div",{className:"min-w-0",children:[r.jsx("div",{className:"truncate text-sm font-medium",children:i.menuBadge??i.badge}),i.description?r.jsx("div",{className:`mt-1 text-xs leading-5 ${h}`,children:i.description}):null]})},i.id)):r.jsx("div",{className:`px-3 py-2 text-sm ${h}`,children:u})}),document.body):null]})]})}function be(t,n){const s=`${n.entityType}:${n.entityId}`;t.has(s)||t.set(s,{id:s,label:n.label,description:n.description,searchText:n.searchText,badge:n.badge,menuBadge:n.menuBadge})}function ve(t){const n=new Map;for(const s of t){if(!s.entityType||!s.entityId)continue;const a=`${s.entityType}:${s.entityId}`;if(n.has(a))continue;const m=s.entityType==="wiki_ingest_job"?`Ingest ${s.entityId}`:`${s.entityType} ${s.entityId}`;be(n,{entityType:s.entityType,entityId:s.entityId,label:m,description:"Seen in diagnostics logs",searchText:L(`${m} ${s.scope} ${s.message} ${s.eventKey}`),badge:K(s.entityType,m),menuBadge:K(s.entityType,m)})}return Array.from(n.values()).sort((s,a)=>s.label.localeCompare(a.label))}const ye=c.memo(function({entry:n}){const[s,a]=c.useState(!1),m=c.useMemo(()=>s&&Object.keys(n.details).length>0?JSON.stringify(n.details,null,2):"",[s,n.details]);return r.jsxs(F,{className:"grid gap-4",children:[r.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[r.jsxs("div",{className:"grid min-w-0 gap-3",children:[r.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[r.jsx("span",{className:z("rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em]",U(n.level)),children:n.level}),r.jsx("span",{className:`rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-3)] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] ${T}`,children:n.source}),r.jsx("span",{className:`rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-3)] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] ${T}`,children:n.scope}),n.eventKey?r.jsx("span",{className:`max-w-full break-words rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-3)] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] [overflow-wrap:anywhere] ${h}`,children:n.eventKey}):null]}),r.jsx("div",{className:`break-words text-base font-medium [overflow-wrap:anywhere] ${ce}`,children:n.message}),r.jsx("div",{className:`flex flex-wrap gap-3 break-words text-xs [overflow-wrap:anywhere] ${h}`,children:xe(n).map(u=>r.jsx("span",{children:u},u))})]}),r.jsxs("div",{className:`shrink-0 text-right text-xs ${h}`,children:[r.jsx("div",{children:pe(n.createdAt)}),r.jsx("div",{className:"mt-1 font-mono text-[11px]",children:n.id})]})]}),Object.keys(n.details).length>0?r.jsxs("details",{className:fe,onToggle:u=>a(u.currentTarget.open),children:[r.jsx("summary",{className:`cursor-pointer text-sm ${T}`,children:"View structured details"}),s?r.jsx("pre",{className:`mt-3 overflow-x-auto whitespace-pre-wrap text-xs leading-6 ${T}`,children:m}):null]}):null]})});function Le(){const[t,n]=H(),s=c.useMemo(()=>{var f,S;const e=((f=t.get("entityType"))==null?void 0:f.trim())||"",l=((S=t.get("entityId"))==null?void 0:S.trim())||"",g=$(t,"entity");return g.length===0&&e&&l&&g.push(`${e}:${l}`),{search:t.get("search")||"",levels:$(t,"level"),sources:$(t,"source"),scopes:$(t,"scope"),routes:$(t,"route"),jobs:$(t,"jobId"),entities:C(g)}},[t]),a=W({queryKey:["forge-diagnostic-logs","settings-filters"],initialPageParam:null,queryFn:({pageParam:e})=>ee({limit:le,beforeCreatedAt:e==null?void 0:e.beforeCreatedAt,beforeId:e==null?void 0:e.beforeId}),getNextPageParam:e=>e.nextCursor,retry:!1,refetchOnWindowFocus:!1}),m=(e,l)=>{const g=new URLSearchParams(t);l.trim()?g.set(e,l.trim()):g.delete(e),n(g,{replace:!0})},u=(e,l,g=[])=>{const f=new URLSearchParams(t);f.delete(e);for(const S of g)f.delete(S);for(const S of C(l))f.append(e,S);n(f,{replace:!0})},w=()=>{const e=new URLSearchParams(t);["search","level","source","scope","route","jobId","entity","entityType","entityId"].forEach(l=>e.delete(l)),n(e,{replace:!0})},d=c.useMemo(()=>{var e;return((e=a.data)==null?void 0:e.pages.flatMap(l=>l.logs))??[]},[a.data]),b=L(s.search),v=c.useRef(null),I=c.useMemo(()=>ae.map(e=>({id:e,label:B(e),searchText:`${e} ${B(e)}`,badge:r.jsx(q,{size:"sm",className:U(e),children:B(e)})})),[]),y=c.useMemo(()=>oe.map(e=>({id:e,label:R(e),searchText:`${e} ${R(e)}`,badge:j(R(e))})),[]),E=c.useMemo(()=>C(d.map(e=>e.scope)).map(e=>({id:e,label:e,searchText:e,badge:j(e)})),[d]),M=c.useMemo(()=>C(d.map(e=>e.route)).map(e=>({id:e,label:e,description:"Filter logs to one or more exact routes.",searchText:e,badge:j(e,"max-w-[16rem]"),menuBadge:j(e)})),[d]),O=c.useMemo(()=>C(d.map(e=>e.jobId)).map(e=>({id:e,label:e,description:"Background job or ingest run id.",searchText:e,badge:j(e,"max-w-[14rem]"),menuBadge:j(e)})),[d]),_=c.useMemo(()=>ve(d),[d]),p=c.useMemo(()=>d.filter(e=>{if(b&&!he(e).includes(b)||s.levels.length>0&&!s.levels.includes(e.level)||s.sources.length>0&&!s.sources.includes(e.source)||s.scopes.length>0&&!s.scopes.includes(e.scope)||s.routes.length>0&&!s.routes.includes(e.route??"")||s.jobs.length>0&&!s.jobs.includes(e.jobId??""))return!1;if(s.entities.length>0){const l=e.entityType&&e.entityId?`${e.entityType}:${e.entityId}`:"";if(!l||!s.entities.includes(l))return!1}return!0}),[s,b,d]),x=[s.search,s.levels.join("|"),s.sources.join("|"),s.scopes.join("|"),s.routes.join("|"),s.jobs.join("|"),s.entities.join("|")].join("::");c.useEffect(()=>{var e;(e=v.current)==null||e.scrollTo({top:0})},[x]);const N=V({count:p.length,getScrollElement:()=>v.current,estimateSize:()=>260,overscan:8}),D=N.getVirtualItems(),i=()=>{const e=v.current;if(!e||!a.hasNextPage||a.isFetchingNextPage)return;e.scrollHeight-e.scrollTop-e.clientHeight<=800&&a.fetchNextPage()},o=s.levels.length+s.sources.length+s.scopes.length+s.routes.length+s.jobs.length+s.entities.length+(s.search.trim()?1:0);return a.isPending?r.jsx(Y,{eyebrow:"Settings",title:"Loading diagnostics",description:"Collecting the latest frontend, backend, and runtime traces.",columns:1,blocks:6}):a.isError?r.jsx(X,{eyebrow:"Settings",error:a.error,onRetry:()=>void a.refetch()}):r.jsxs("div",{className:"mx-auto grid w-full max-w-[1220px] gap-5",children:[r.jsx(re,{title:"Logs",description:"Inspect shared diagnostics from the UI, backend routes, background jobs, and LLM flows.",badge:`${p.length} matching${p.length!==d.length?` · ${d.length} loaded`:""}${a.hasNextPage?" · more available":""}`}),r.jsx(ne,{}),r.jsxs(F,{className:"grid gap-4",children:[r.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[r.jsxs("div",{children:[r.jsx("div",{className:P,children:"Filters"}),r.jsx("div",{className:`mt-2 max-w-3xl text-sm leading-6 ${T}`,children:"Use token filters with OR-style badge selections for levels, sources, routes, jobs, scopes, and linked entities. Search still matches the message body and structured details."})]}),r.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[o>0?r.jsxs(A,{variant:"ghost",size:"sm",onClick:w,children:["Clear ",o]}):null,r.jsx(A,{variant:"secondary",size:"sm",onClick:()=>void a.refetch(),pending:a.isRefetching&&!a.isFetchingNextPage,pendingLabel:"Refreshing",children:"Refresh"})]})]}),r.jsxs("label",{className:"grid gap-2",children:[r.jsx("span",{className:P,children:"Search message or details"}),r.jsx(Z,{value:s.search,onChange:e=>m("search",e.target.value),placeholder:"LLM compilation failed, wiki_ingest, request_failed…",className:"h-11 rounded-[20px]"})]}),r.jsxs("div",{className:"grid gap-3 xl:grid-cols-2",children:[r.jsx(k,{label:"Levels",placeholder:"Add one or more levels",options:I,selectedIds:s.levels,onChange:e=>u("level",e),emptyMessage:"No additional log levels."}),r.jsx(k,{label:"Sources",placeholder:"Add one or more sources",options:y,selectedIds:s.sources,onChange:e=>u("source",e),emptyMessage:"No additional log sources."}),r.jsx(k,{label:"Scopes",placeholder:"Search scopes",options:E,selectedIds:s.scopes,onChange:e=>u("scope",e),emptyMessage:"No scopes match the current logs."}),r.jsx(k,{label:"Routes",placeholder:"Search exact routes",options:M,selectedIds:s.routes,onChange:e=>u("route",e),emptyMessage:"No routes match the current logs."}),r.jsx(k,{label:"Jobs",placeholder:"Search job ids",options:O,selectedIds:s.jobs,onChange:e=>u("jobId",e),emptyMessage:"No job ids match the current logs."}),r.jsx(k,{label:"Entities",placeholder:"Search Forge entities or logged ids",options:_,selectedIds:s.entities,onChange:e=>u("entity",e,["entityType","entityId"]),emptyMessage:"No logged entities match yet."})]})]}),r.jsx("div",{className:"grid gap-3",children:p.length===0?r.jsx(F,{className:`text-sm ${T}`,children:"No diagnostic entries match the current filters yet."}):r.jsx(F,{className:"p-0",children:r.jsxs("div",{ref:v,onScroll:i,className:"h-[72vh] overflow-y-auto px-3 py-3",children:[r.jsx("div",{className:"relative",style:{height:`${N.getTotalSize()}px`},children:D.map(e=>{const l=p[e.index];return l?r.jsx("div",{"data-index":e.index,ref:N.measureElement,className:"absolute left-0 top-0 w-full pb-3",style:{transform:`translateY(${e.start}px)`},children:r.jsx(ye,{entry:l})},l.id):null})}),r.jsx("div",{className:`border-t border-[var(--ui-border-subtle)] px-1 py-3 text-center text-xs ${h}`,children:a.isFetchingNextPage?"Loading older logs...":a.hasNextPage?"Scroll to load older logs.":`Showing all ${d.length} loaded logs.`})]})})})]})}export{Le as SettingsLogsPage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as u,dh as ae,j as e,di as ie,dj as ne,cr as U,cs as _,dg as te,dk as G,dl as re,bG as K,bz as B,dm as le,dn as W,aC as E,c5 as L,dp as oe}from"./vendor-Cpmju3nw.js";import{j as de,i as ce,k as P}from"./state-BtwEvpO6.js";import{d as me,S as xe,e as pe,C as Q,B as m,k as t,dB as he,dC as ue,dD as ve,dE as ge,cW as fe}from"./index-BaiwtAgo.js";import{S as je}from"./settings-section-nav-CwSDNC3W.js";import{P as we}from"./page-hero-C0MpI3MM.js";import{g as be}from"./user-ownership-DJGl4rAj.js";import"./motion-DwjmC9aq.js";import"./ui-B9O-eUim.js";import"./board-CLOHbg6t.js";import"./forms-C5d5hTf2.js";function Ne(a){return a.replaceAll("."," ")}function ye(a){const d=typeof a.sleepNights=="number"?a.sleepNights:typeof a.sleepSessions=="number"?a.sleepSessions:0,g=typeof a.sleepSegments=="number"?a.sleepSegments:0,S=typeof a.sleepRawRecords=="number"?a.sleepRawRecords:0,b=typeof a.sleepSessions=="number"?a.sleepSessions:0,N=typeof a.workouts=="number"?a.workouts:0,x=a.vitals&&typeof a.vitals=="object"&&!Array.isArray(a.vitals)&&typeof a.vitals.metricEntries=="number"?a.vitals.metricEntries:0;return`${d||b} nights · ${g} segments · ${S} raw records · ${N} workouts · ${x} vitals`}function J(a){return a?"signal":"meta"}function ke(a){return a.replaceAll("_"," ")}function Pe(a){return a?new Date(a).toLocaleString():"Waiting for device update"}function Se(a,d){return a?d?"signal":"default":"meta"}function Ce(a){return a.transportMode==="iroh"?"Iroh":"Manual HTTP"}function $e(a){return a.transportMode==="iroh"?"signal":"meta"}const j="font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",i="text-[var(--ui-ink-soft)]",v="text-[var(--ui-ink-faint)]",l="rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)]",w="rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)]",V="rounded-[24px] border border-dashed border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)]",T="inline-flex min-h-11 items-center gap-2 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-4 py-3 text-sm text-[var(--ui-ink-medium)] transition hover:bg-[var(--ui-surface-hover)] hover:text-[var(--ui-ink-strong)]";function Oe(){const a=me(),d=de(),g=Array.isArray(a.selectedUserIds)?a.selectedUserIds:[],S=be(g),[b,N]=u.useState(null),[x,C]=u.useState(!1),[$,y]=u.useState(!1),[F,R]=u.useState(!1),[r,X]=u.useState(null),p=ce({queryKey:["forge-companion-overview",...g],queryFn:async()=>(await fe(g)).overview}),c=P({mutationFn:async(s="iroh")=>he({userId:S??null,transportMode:s}),onSuccess:async s=>{X({qrPayload:s.qrPayload}),C(!0),await d.invalidateQueries({queryKey:["forge-companion-overview"]})}}),A=P({mutationFn:async s=>ve(s),onSuccess:async()=>{await d.invalidateQueries({queryKey:["forge-companion-overview"]})}}),I=P({mutationFn:async()=>ue({userIds:g,includeRevoked:!1}),onSuccess:async()=>{await d.invalidateQueries({queryKey:["forge-companion-overview"]})}}),k=P({mutationFn:async s=>ge(s.pairingSessionId,s.source,s.desiredEnabled),onSuccess:async()=>{await d.invalidateQueries({queryKey:["forge-companion-overview"]})}});if(u.useEffect(()=>{if(!r){N(null);return}ae.toDataURL(JSON.stringify(r.qrPayload),{width:320,margin:1}).then(N)},[r]),u.useEffect(()=>{y(!1),R(!1)},[r]),p.isLoading)return e.jsx(xe,{eyebrow:"Companion",title:"Loading mobile companion",description:"Checking pairing state and recent sync status.",columns:2,blocks:5});if(p.isError||!p.data)return e.jsx(pe,{eyebrow:"Companion",error:p.error??new Error("Companion overview unavailable"),onRetry:()=>void p.refetch()});const n=p.data,f=n.pairings.filter(s=>s.status!=="revoked"),M=n.pairings.length-f.length,z=r?JSON.stringify(r.qrPayload,null,2):"",Y=async()=>{if(r&&x){C(!1);return}if(r&&!x){C(!0);return}await c.mutateAsync("iroh")},Z=async()=>{await c.mutateAsync("manual-http")},ee=async()=>{if(z){if(!navigator.clipboard){y(!0);return}try{await navigator.clipboard.writeText(z),R(!0),window.setTimeout(()=>R(!1),1800)}catch{y(!0)}}};return e.jsxs("div",{className:"mx-auto grid min-w-0 w-full max-w-[1220px] gap-5 pb-24 lg:pb-0",children:[e.jsx(we,{title:"Mobile companion",description:"Pair the native iPhone companion, sync Apple Health, and keep the bridge open for watch and location signals.",badge:n.healthState.replaceAll("_"," ")}),e.jsx(je,{}),e.jsxs("section",{className:"grid min-w-0 gap-4",children:[null,e.jsxs(Q,{className:"grid min-w-0 gap-4 overflow-hidden",children:[e.jsxs("div",{className:"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:j,children:"Pair iPhone"}),e.jsx("div",{className:"mt-2 text-lg text-[var(--ui-ink-strong)]",children:"Pair your iPhone privately"}),e.jsx("div",{className:`mt-2 max-w-3xl text-sm leading-6 ${i}`,children:"Forge uses its own Iroh/QUIC companion route by default. Scan once from the iPhone app; manual HTTP stays as the advanced LAN or Tailscale path."})]}),e.jsxs("div",{className:"flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:flex-wrap sm:justify-end",children:[e.jsxs(m,{variant:"secondary",className:"w-full sm:w-auto",onClick:()=>void Z(),pending:c.isPending&&c.variables==="manual-http",pendingLabel:"Generating",children:[e.jsx(ie,{className:"size-4"}),"Advanced HTTP"]}),e.jsxs(m,{className:"w-full sm:w-auto",onClick:()=>void Y(),pending:c.isPending&&c.variables!=="manual-http",pendingLabel:"Generating",children:[e.jsx(ne,{className:"size-4"}),r?x?"Hide QR":"Show QR":"Generate Forge QR",r?x?e.jsx(U,{className:"size-4"}):e.jsx(_,{className:"size-4"}):null]})]})]}),x?e.jsxs("div",{className:"grid min-w-0 gap-4 overflow-hidden rounded-[24px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] p-4 sm:p-5",children:[e.jsxs("div",{className:"grid min-w-0 gap-4 lg:grid-cols-[minmax(260px,360px)_1fr]",children:[b?e.jsxs("div",{className:"grid justify-items-center gap-4 rounded-[24px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-6 py-6 text-[var(--ui-ink-strong)]",children:[e.jsx("img",{src:b,alt:"Forge Companion pairing QR code",className:"w-full max-w-[320px]"}),e.jsx("div",{className:`max-w-[320px] text-center text-sm ${i}`,children:"Scan this code from Forge Companion on iPhone."})]}):e.jsx("div",{className:`${V} px-5 py-8 text-center text-sm ${i}`,children:"Generating the QR code now."}),e.jsxs("div",{className:"grid content-start gap-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[r?e.jsxs(t,{tone:$e(r.qrPayload),children:[e.jsx(te,{className:"size-3"}),Ce(r.qrPayload)]}):null,e.jsxs(t,{tone:"meta",children:[e.jsx(G,{className:"size-3"}),"One-time token"]})]}),e.jsxs("div",{className:`grid gap-3 text-sm leading-6 ${i}`,children:[e.jsxs("div",{className:"flex gap-3",children:[e.jsx(re,{className:`mt-1 size-4 shrink-0 ${v}`}),e.jsx("span",{children:"Open Forge Companion and choose Scan Forge QR."})]}),e.jsxs("div",{className:"flex gap-3",children:[e.jsx(G,{className:`mt-1 size-4 shrink-0 ${v}`}),e.jsx("span",{children:"The iPhone receives the desktop node, relay hint, and pairing token for the Forge Iroh route."})]}),e.jsxs("div",{className:"flex gap-3",children:[e.jsx(K,{className:`mt-1 size-4 shrink-0 ${v}`}),e.jsx("span",{children:"After verification, the app moves straight into native permissions and first sync."})]})]}),e.jsxs("div",{className:`flex flex-wrap items-center justify-between gap-3 ${w} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:r?e.jsxs("span",{children:["Expires"," ",new Date(r.qrPayload.expiresAt).toLocaleString(),"."]}):"Generate the one-time QR and scan it from the iPhone app."}),r?e.jsxs(m,{variant:"secondary",pending:c.isPending,pendingLabel:"Generating",onClick:()=>void c.mutateAsync("iroh"),children:[e.jsx(B,{className:"size-4"}),"Regenerate QR"]}):null]})]})]}),r?e.jsxs("div",{className:`grid gap-3 ${w} p-4 text-sm ${i}`,children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"max-w-2xl",children:[e.jsx("div",{className:"text-[var(--ui-ink-strong)]",children:"Fallback pairing payload"}),e.jsx("div",{className:`mt-1 text-xs leading-5 ${v}`,children:"Use this only when the iPhone camera cannot scan the QR. The payload contains the same Forge Iroh connection recipe."})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(m,{variant:"secondary",onClick:()=>void ee(),children:[F?e.jsx(K,{className:"size-4"}):e.jsx(le,{className:"size-4"}),F?"Copied":"Copy payload"]}),e.jsxs(m,{variant:"secondary",onClick:()=>y(s=>!s),children:[$?"Hide payload":"Show payload",$?e.jsx(U,{className:"size-4"}):e.jsx(_,{className:"size-4"})]})]})]}),$?e.jsx("pre",{className:"max-h-56 overflow-auto whitespace-pre-wrap break-words rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-code-bg)] p-3 font-mono text-[11px] leading-5 text-[var(--ui-code-text)]",children:z}):null]}):null]}):e.jsx("div",{className:`${V} px-5 py-6 text-sm leading-6 ${i}`,children:"Generate a one-time Forge QR when the iPhone is in your hand. The code expires automatically and can be regenerated anytime."})]}),e.jsxs(Q,{className:"grid min-w-0 gap-4 overflow-hidden",children:[e.jsx("div",{className:j,children:"Companion state"}),e.jsxs("div",{className:"grid min-w-0 max-w-full gap-3 md:grid-cols-3",children:[e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Pairings"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:f.length}),M>0?e.jsxs("div",{className:`mt-2 text-xs ${v}`,children:[M," revoked hidden"]}):null]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Sleep sessions"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.sleepSessions})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Raw sleep records"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.sleepRawRecords})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Workouts"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.workouts})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Vitals days"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.vitalsDaySummaries??0})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Vital entries"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.vitalsMetricEntries??0})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Reflected sleep"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.reflectiveSleepSessions})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Linked workouts"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.linkedWorkouts})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Habit-generated"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.habitGeneratedWorkouts})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Reconciled"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.reconciledWorkouts})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(t,{children:n.healthState.replaceAll("_"," ")}),n.lastSyncAt?e.jsxs(t,{tone:"meta",children:["Last sync ",new Date(n.lastSyncAt).toLocaleString()]}):null,e.jsxs(t,{tone:J(n.permissions.healthKitAuthorized),children:["HealthKit"," ",n.permissions.healthKitAuthorized?"ready":"needed"]}),e.jsxs(t,{tone:J(n.permissions.backgroundRefreshEnabled),children:["Background refresh"," ",n.permissions.backgroundRefreshEnabled?"ready":"not yet"]}),e.jsxs(t,{tone:"meta",children:["Location ",n.permissions.locationReady?"ready":"later"]}),e.jsxs(t,{tone:"meta",children:["Motion ",n.permissions.motionReady?"ready":"later"]})]}),e.jsxs("div",{className:`grid gap-3 ${w} p-4`,children:[e.jsx("div",{className:j,children:"Pairing path"}),e.jsxs("div",{className:`grid gap-2 text-sm ${i}`,children:[e.jsx("div",{children:"1. Generate the Forge QR from this page."}),e.jsx("div",{children:"2. Scan it in Forge Companion to pass the desktop node and pairing token."}),e.jsx("div",{children:"3. Approve Health access on iPhone, then run the first sync."}),e.jsx("div",{children:"4. Use Advanced HTTP only for a local, Tailscale, or direct TCP route."})]})]}),e.jsxs("div",{className:"grid min-w-0 gap-3",children:[f.length>0?e.jsx("div",{className:"flex min-w-0 max-w-full justify-end overflow-hidden",children:e.jsxs(m,{variant:"secondary",pending:I.isPending,pendingLabel:"Revoking all",onClick:()=>void I.mutateAsync(),children:[e.jsx(W,{className:"size-4"}),"Revoke all"]})}):null,f.map(s=>e.jsxs("div",{className:`grid min-w-0 max-w-full gap-3 overflow-hidden ${l} px-4 py-4`,children:[e.jsxs("div",{className:"flex min-w-0 max-w-full flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-base text-[var(--ui-ink-strong)]",children:s.deviceName??s.label}),e.jsxs("div",{className:`mt-1 text-sm ${i}`,children:[s.platform??"ios"," · ",s.status]})]}),e.jsxs("div",{className:"flex min-w-0 flex-wrap gap-2",children:[e.jsx(t,{tone:s.status==="healthy"?"signal":"meta",children:s.status.replaceAll("_"," ")}),s.lastSyncAt?e.jsxs(t,{tone:"meta",children:["Synced ",new Date(s.lastSyncAt).toLocaleString()]}):null]})]}),e.jsx("div",{className:"flex min-w-0 max-w-full flex-wrap gap-2 overflow-hidden",children:s.capabilities.map(h=>e.jsx(t,{tone:"meta",size:"sm",wrap:!0,children:Ne(h)},h))}),e.jsxs("div",{className:`flex min-w-0 max-w-full flex-wrap items-center justify-between gap-3 overflow-hidden text-sm ${i}`,children:[e.jsxs("div",{className:"grid min-w-0 max-w-full flex-1 basis-[16rem] gap-1",children:[e.jsx("div",{className:"min-w-0 max-w-full break-all [overflow-wrap:anywhere]",children:s.apiBaseUrl}),e.jsxs("div",{className:"min-w-0 max-w-full break-words [overflow-wrap:anywhere]",children:["Expires ",new Date(s.expiresAt).toLocaleString()]}),s.lastSyncError?e.jsx("div",{className:"text-[color-mix(in_srgb,var(--danger)_76%,var(--ui-ink-strong)_24%)]",children:s.lastSyncError}):null]}),e.jsxs(m,{variant:"secondary",pending:A.isPending&&A.variables===s.id,pendingLabel:"Revoking",disabled:s.status==="revoked",onClick:()=>void A.mutateAsync(s.id),children:[e.jsx(W,{className:"size-4"}),s.status==="revoked"?"Revoked":"Revoke"]})]}),e.jsxs("div",{className:"grid min-w-0 gap-3 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-3",children:[e.jsx("div",{className:j,children:"Device sync sources"}),[["health","Health"],["movement","Movement"],["screenTime","Screen Time"]].map(([h,O])=>{var D,H;const o=s.sourceStates[h],se=o.desiredEnabled!==o.appliedEnabled,q=k.isPending&&((D=k.variables)==null?void 0:D.pairingSessionId)===s.id&&((H=k.variables)==null?void 0:H.source)===h;return e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-[14px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-3 py-3",children:[e.jsxs("div",{className:"grid min-w-0 gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"text-sm text-[var(--ui-ink-strong)]",children:O}),e.jsx(t,{tone:Se(o.desiredEnabled,o.syncEligible),size:"sm",children:o.desiredEnabled?"Enabled":"Off"}),se?e.jsx(t,{tone:"meta",size:"sm",children:"Pending on phone"}):e.jsx(t,{tone:"meta",size:"sm",children:"Applied"})]}),e.jsxs("div",{className:`break-words text-xs [overflow-wrap:anywhere] ${i}`,children:["Authorization"," ",ke(o.authorizationStatus)," · ","Last seen"," ",Pe(o.lastObservedAt)]})]}),e.jsx("button",{type:"button",role:"switch","aria-checked":o.desiredEnabled,"aria-label":`${O} sync source`,disabled:q,onClick:()=>void k.mutateAsync({pairingSessionId:s.id,source:h,desiredEnabled:!o.desiredEnabled}),className:`relative inline-flex h-7 w-12 items-center rounded-full border transition ${o.desiredEnabled?"border-[color-mix(in_srgb,var(--primary)_45%,var(--ui-border-subtle)_55%)] bg-[var(--ui-accent-soft)]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-3)]"} ${q?"opacity-60":""}`,children:e.jsx("span",{className:`inline-block size-5 rounded-full bg-[var(--ui-ink-strong)] shadow transition ${o.desiredEnabled?"translate-x-6":"translate-x-1"}`})})]},h)})]})]},s.id)),f.length===0?e.jsx("div",{className:`${w} px-4 py-6 text-sm ${i}`,children:"No companion paired yet. Generate a QR code, then open the iOS companion and scan it."}):null]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsxs(m,{variant:"secondary",onClick:()=>void p.refetch(),children:[e.jsx(B,{className:"size-4"}),"Refresh status"]}),e.jsxs(E,{to:"/sleep",className:T,children:[e.jsx(L,{className:"size-4"}),"Open sleep view"]}),e.jsxs(E,{to:"/sports",className:T,children:[e.jsx(L,{className:"size-4"}),"Open sports view"]}),e.jsxs(E,{to:"/vitals",className:T,children:[e.jsx(L,{className:"size-4"}),"Open vitals view"]})]})]})]}),e.jsxs(Q,{className:"grid min-w-0 gap-4 overflow-hidden",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:j,children:"Sync history"}),e.jsx("div",{className:"mt-2 text-lg text-[var(--ui-ink-strong)]",children:"Recent HealthKit import runs"})]}),e.jsxs(t,{tone:"meta",children:[n.importRuns.length," recent runs"]})]}),e.jsxs("div",{className:"grid min-w-0 gap-3",children:[n.importRuns.map(s=>e.jsxs("div",{className:`grid gap-3 ${l} px-4 py-4 lg:grid-cols-[minmax(0,1fr)_auto]`,children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(oe,{className:`size-4 ${v}`}),e.jsxs("div",{className:"text-base text-[var(--ui-ink-strong)]",children:[s.sourceDevice||"iPhone"," import"]}),e.jsx(t,{tone:s.status==="completed"?"signal":"meta",children:s.status})]}),e.jsxs("div",{className:`break-words text-sm [overflow-wrap:anywhere] ${i}`,children:[new Date(s.importedAt).toLocaleString()," ·"," ",ye(s.payloadSummary)]}),e.jsxs("div",{className:`flex flex-wrap gap-2 text-sm ${i}`,children:[e.jsxs(t,{tone:"meta",children:["Imported ",s.importedCount]}),e.jsxs(t,{tone:"meta",children:["Created ",s.createdCount]}),e.jsxs(t,{tone:"meta",children:["Updated ",s.updatedCount]}),e.jsxs(t,{tone:"meta",children:["Merged ",s.mergedCount]})]}),s.errorMessage?e.jsx("div",{className:"text-sm text-[color-mix(in_srgb,var(--danger)_76%,var(--ui-ink-strong)_24%)]",children:s.errorMessage}):null]}),s.pairingSessionId?e.jsxs("div",{className:`break-words text-sm [overflow-wrap:anywhere] ${v} lg:text-right`,children:["Pairing ",s.pairingSessionId]}):null]},s.id)),n.importRuns.length===0?e.jsx("div",{className:`${w} px-4 py-6 text-sm ${i}`,children:"No sync runs yet. Pair the iPhone companion and run the first HealthKit import."}):null]})]})]})}export{Oe as SettingsMobilePage};
|
|
1
|
+
import{r as u,dh as ae,j as e,di as ie,dj as ne,cr as U,cs as _,dg as te,dk as G,dl as re,bG as K,bz as B,dm as le,dn as W,aC as E,c5 as L,dp as oe}from"./vendor-BwL6m4SE.js";import{j as de,i as ce,k as P}from"./state-Bpe5dF3T.js";import{d as me,S as xe,e as pe,C as Q,B as m,k as t,dB as he,dC as ue,dD as ve,dE as ge,cW as fe}from"./index-CQ5r7ZUz.js";import{S as je}from"./settings-section-nav-BmJWnrYk.js";import{P as we}from"./page-hero-8bITsx_x.js";import{g as be}from"./user-ownership-DJGl4rAj.js";import"./motion-DcgUnXhY.js";import"./ui-B9TWEtCx.js";import"./board-CuxQRKPJ.js";import"./forms-D1qJ3oOP.js";function Ne(a){return a.replaceAll("."," ")}function ye(a){const d=typeof a.sleepNights=="number"?a.sleepNights:typeof a.sleepSessions=="number"?a.sleepSessions:0,g=typeof a.sleepSegments=="number"?a.sleepSegments:0,S=typeof a.sleepRawRecords=="number"?a.sleepRawRecords:0,b=typeof a.sleepSessions=="number"?a.sleepSessions:0,N=typeof a.workouts=="number"?a.workouts:0,x=a.vitals&&typeof a.vitals=="object"&&!Array.isArray(a.vitals)&&typeof a.vitals.metricEntries=="number"?a.vitals.metricEntries:0;return`${d||b} nights · ${g} segments · ${S} raw records · ${N} workouts · ${x} vitals`}function J(a){return a?"signal":"meta"}function ke(a){return a.replaceAll("_"," ")}function Pe(a){return a?new Date(a).toLocaleString():"Waiting for device update"}function Se(a,d){return a?d?"signal":"default":"meta"}function Ce(a){return a.transportMode==="iroh"?"Iroh":"Manual HTTP"}function $e(a){return a.transportMode==="iroh"?"signal":"meta"}const j="font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",i="text-[var(--ui-ink-soft)]",v="text-[var(--ui-ink-faint)]",l="rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)]",w="rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)]",V="rounded-[24px] border border-dashed border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)]",T="inline-flex min-h-11 items-center gap-2 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-4 py-3 text-sm text-[var(--ui-ink-medium)] transition hover:bg-[var(--ui-surface-hover)] hover:text-[var(--ui-ink-strong)]";function Oe(){const a=me(),d=de(),g=Array.isArray(a.selectedUserIds)?a.selectedUserIds:[],S=be(g),[b,N]=u.useState(null),[x,C]=u.useState(!1),[$,y]=u.useState(!1),[F,R]=u.useState(!1),[r,X]=u.useState(null),p=ce({queryKey:["forge-companion-overview",...g],queryFn:async()=>(await fe(g)).overview}),c=P({mutationFn:async(s="iroh")=>he({userId:S??null,transportMode:s}),onSuccess:async s=>{X({qrPayload:s.qrPayload}),C(!0),await d.invalidateQueries({queryKey:["forge-companion-overview"]})}}),A=P({mutationFn:async s=>ve(s),onSuccess:async()=>{await d.invalidateQueries({queryKey:["forge-companion-overview"]})}}),I=P({mutationFn:async()=>ue({userIds:g,includeRevoked:!1}),onSuccess:async()=>{await d.invalidateQueries({queryKey:["forge-companion-overview"]})}}),k=P({mutationFn:async s=>ge(s.pairingSessionId,s.source,s.desiredEnabled),onSuccess:async()=>{await d.invalidateQueries({queryKey:["forge-companion-overview"]})}});if(u.useEffect(()=>{if(!r){N(null);return}ae.toDataURL(JSON.stringify(r.qrPayload),{width:320,margin:1}).then(N)},[r]),u.useEffect(()=>{y(!1),R(!1)},[r]),p.isLoading)return e.jsx(xe,{eyebrow:"Companion",title:"Loading mobile companion",description:"Checking pairing state and recent sync status.",columns:2,blocks:5});if(p.isError||!p.data)return e.jsx(pe,{eyebrow:"Companion",error:p.error??new Error("Companion overview unavailable"),onRetry:()=>void p.refetch()});const n=p.data,f=n.pairings.filter(s=>s.status!=="revoked"),M=n.pairings.length-f.length,z=r?JSON.stringify(r.qrPayload,null,2):"",Y=async()=>{if(r&&x){C(!1);return}if(r&&!x){C(!0);return}await c.mutateAsync("iroh")},Z=async()=>{await c.mutateAsync("manual-http")},ee=async()=>{if(z){if(!navigator.clipboard){y(!0);return}try{await navigator.clipboard.writeText(z),R(!0),window.setTimeout(()=>R(!1),1800)}catch{y(!0)}}};return e.jsxs("div",{className:"mx-auto grid min-w-0 w-full max-w-[1220px] gap-5 pb-24 lg:pb-0",children:[e.jsx(we,{title:"Mobile companion",description:"Pair the native iPhone companion, sync Apple Health, and keep the bridge open for watch and location signals.",badge:n.healthState.replaceAll("_"," ")}),e.jsx(je,{}),e.jsxs("section",{className:"grid min-w-0 gap-4",children:[null,e.jsxs(Q,{className:"grid min-w-0 gap-4 overflow-hidden",children:[e.jsxs("div",{className:"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:j,children:"Pair iPhone"}),e.jsx("div",{className:"mt-2 text-lg text-[var(--ui-ink-strong)]",children:"Pair your iPhone privately"}),e.jsx("div",{className:`mt-2 max-w-3xl text-sm leading-6 ${i}`,children:"Forge uses its own Iroh/QUIC companion route by default. Scan once from the iPhone app; manual HTTP stays as the advanced LAN or Tailscale path."})]}),e.jsxs("div",{className:"flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:flex-wrap sm:justify-end",children:[e.jsxs(m,{variant:"secondary",className:"w-full sm:w-auto",onClick:()=>void Z(),pending:c.isPending&&c.variables==="manual-http",pendingLabel:"Generating",children:[e.jsx(ie,{className:"size-4"}),"Advanced HTTP"]}),e.jsxs(m,{className:"w-full sm:w-auto",onClick:()=>void Y(),pending:c.isPending&&c.variables!=="manual-http",pendingLabel:"Generating",children:[e.jsx(ne,{className:"size-4"}),r?x?"Hide QR":"Show QR":"Generate Forge QR",r?x?e.jsx(U,{className:"size-4"}):e.jsx(_,{className:"size-4"}):null]})]})]}),x?e.jsxs("div",{className:"grid min-w-0 gap-4 overflow-hidden rounded-[24px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] p-4 sm:p-5",children:[e.jsxs("div",{className:"grid min-w-0 gap-4 lg:grid-cols-[minmax(260px,360px)_1fr]",children:[b?e.jsxs("div",{className:"grid justify-items-center gap-4 rounded-[24px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-6 py-6 text-[var(--ui-ink-strong)]",children:[e.jsx("img",{src:b,alt:"Forge Companion pairing QR code",className:"w-full max-w-[320px]"}),e.jsx("div",{className:`max-w-[320px] text-center text-sm ${i}`,children:"Scan this code from Forge Companion on iPhone."})]}):e.jsx("div",{className:`${V} px-5 py-8 text-center text-sm ${i}`,children:"Generating the QR code now."}),e.jsxs("div",{className:"grid content-start gap-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[r?e.jsxs(t,{tone:$e(r.qrPayload),children:[e.jsx(te,{className:"size-3"}),Ce(r.qrPayload)]}):null,e.jsxs(t,{tone:"meta",children:[e.jsx(G,{className:"size-3"}),"One-time token"]})]}),e.jsxs("div",{className:`grid gap-3 text-sm leading-6 ${i}`,children:[e.jsxs("div",{className:"flex gap-3",children:[e.jsx(re,{className:`mt-1 size-4 shrink-0 ${v}`}),e.jsx("span",{children:"Open Forge Companion and choose Scan Forge QR."})]}),e.jsxs("div",{className:"flex gap-3",children:[e.jsx(G,{className:`mt-1 size-4 shrink-0 ${v}`}),e.jsx("span",{children:"The iPhone receives the desktop node, relay hint, and pairing token for the Forge Iroh route."})]}),e.jsxs("div",{className:"flex gap-3",children:[e.jsx(K,{className:`mt-1 size-4 shrink-0 ${v}`}),e.jsx("span",{children:"After verification, the app moves straight into native permissions and first sync."})]})]}),e.jsxs("div",{className:`flex flex-wrap items-center justify-between gap-3 ${w} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:r?e.jsxs("span",{children:["Expires"," ",new Date(r.qrPayload.expiresAt).toLocaleString(),"."]}):"Generate the one-time QR and scan it from the iPhone app."}),r?e.jsxs(m,{variant:"secondary",pending:c.isPending,pendingLabel:"Generating",onClick:()=>void c.mutateAsync("iroh"),children:[e.jsx(B,{className:"size-4"}),"Regenerate QR"]}):null]})]})]}),r?e.jsxs("div",{className:`grid gap-3 ${w} p-4 text-sm ${i}`,children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"max-w-2xl",children:[e.jsx("div",{className:"text-[var(--ui-ink-strong)]",children:"Fallback pairing payload"}),e.jsx("div",{className:`mt-1 text-xs leading-5 ${v}`,children:"Use this only when the iPhone camera cannot scan the QR. The payload contains the same Forge Iroh connection recipe."})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(m,{variant:"secondary",onClick:()=>void ee(),children:[F?e.jsx(K,{className:"size-4"}):e.jsx(le,{className:"size-4"}),F?"Copied":"Copy payload"]}),e.jsxs(m,{variant:"secondary",onClick:()=>y(s=>!s),children:[$?"Hide payload":"Show payload",$?e.jsx(U,{className:"size-4"}):e.jsx(_,{className:"size-4"})]})]})]}),$?e.jsx("pre",{className:"max-h-56 overflow-auto whitespace-pre-wrap break-words rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-code-bg)] p-3 font-mono text-[11px] leading-5 text-[var(--ui-code-text)]",children:z}):null]}):null]}):e.jsx("div",{className:`${V} px-5 py-6 text-sm leading-6 ${i}`,children:"Generate a one-time Forge QR when the iPhone is in your hand. The code expires automatically and can be regenerated anytime."})]}),e.jsxs(Q,{className:"grid min-w-0 gap-4 overflow-hidden",children:[e.jsx("div",{className:j,children:"Companion state"}),e.jsxs("div",{className:"grid min-w-0 max-w-full gap-3 md:grid-cols-3",children:[e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Pairings"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:f.length}),M>0?e.jsxs("div",{className:`mt-2 text-xs ${v}`,children:[M," revoked hidden"]}):null]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Sleep sessions"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.sleepSessions})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Raw sleep records"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.sleepRawRecords})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Workouts"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.workouts})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Vitals days"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.vitalsDaySummaries??0})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Vital entries"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.vitalsMetricEntries??0})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Reflected sleep"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.reflectiveSleepSessions})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Linked workouts"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.linkedWorkouts})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Habit-generated"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.habitGeneratedWorkouts})]}),e.jsxs("div",{className:`${l} p-4`,children:[e.jsx("div",{className:`text-sm ${i}`,children:"Reconciled"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-[var(--ui-ink-strong)]",children:n.counts.reconciledWorkouts})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(t,{children:n.healthState.replaceAll("_"," ")}),n.lastSyncAt?e.jsxs(t,{tone:"meta",children:["Last sync ",new Date(n.lastSyncAt).toLocaleString()]}):null,e.jsxs(t,{tone:J(n.permissions.healthKitAuthorized),children:["HealthKit"," ",n.permissions.healthKitAuthorized?"ready":"needed"]}),e.jsxs(t,{tone:J(n.permissions.backgroundRefreshEnabled),children:["Background refresh"," ",n.permissions.backgroundRefreshEnabled?"ready":"not yet"]}),e.jsxs(t,{tone:"meta",children:["Location ",n.permissions.locationReady?"ready":"later"]}),e.jsxs(t,{tone:"meta",children:["Motion ",n.permissions.motionReady?"ready":"later"]})]}),e.jsxs("div",{className:`grid gap-3 ${w} p-4`,children:[e.jsx("div",{className:j,children:"Pairing path"}),e.jsxs("div",{className:`grid gap-2 text-sm ${i}`,children:[e.jsx("div",{children:"1. Generate the Forge QR from this page."}),e.jsx("div",{children:"2. Scan it in Forge Companion to pass the desktop node and pairing token."}),e.jsx("div",{children:"3. Approve Health access on iPhone, then run the first sync."}),e.jsx("div",{children:"4. Use Advanced HTTP only for a local, Tailscale, or direct TCP route."})]})]}),e.jsxs("div",{className:"grid min-w-0 gap-3",children:[f.length>0?e.jsx("div",{className:"flex min-w-0 max-w-full justify-end overflow-hidden",children:e.jsxs(m,{variant:"secondary",pending:I.isPending,pendingLabel:"Revoking all",onClick:()=>void I.mutateAsync(),children:[e.jsx(W,{className:"size-4"}),"Revoke all"]})}):null,f.map(s=>e.jsxs("div",{className:`grid min-w-0 max-w-full gap-3 overflow-hidden ${l} px-4 py-4`,children:[e.jsxs("div",{className:"flex min-w-0 max-w-full flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-base text-[var(--ui-ink-strong)]",children:s.deviceName??s.label}),e.jsxs("div",{className:`mt-1 text-sm ${i}`,children:[s.platform??"ios"," · ",s.status]})]}),e.jsxs("div",{className:"flex min-w-0 flex-wrap gap-2",children:[e.jsx(t,{tone:s.status==="healthy"?"signal":"meta",children:s.status.replaceAll("_"," ")}),s.lastSyncAt?e.jsxs(t,{tone:"meta",children:["Synced ",new Date(s.lastSyncAt).toLocaleString()]}):null]})]}),e.jsx("div",{className:"flex min-w-0 max-w-full flex-wrap gap-2 overflow-hidden",children:s.capabilities.map(h=>e.jsx(t,{tone:"meta",size:"sm",wrap:!0,children:Ne(h)},h))}),e.jsxs("div",{className:`flex min-w-0 max-w-full flex-wrap items-center justify-between gap-3 overflow-hidden text-sm ${i}`,children:[e.jsxs("div",{className:"grid min-w-0 max-w-full flex-1 basis-[16rem] gap-1",children:[e.jsx("div",{className:"min-w-0 max-w-full break-all [overflow-wrap:anywhere]",children:s.apiBaseUrl}),e.jsxs("div",{className:"min-w-0 max-w-full break-words [overflow-wrap:anywhere]",children:["Expires ",new Date(s.expiresAt).toLocaleString()]}),s.lastSyncError?e.jsx("div",{className:"text-[color-mix(in_srgb,var(--danger)_76%,var(--ui-ink-strong)_24%)]",children:s.lastSyncError}):null]}),e.jsxs(m,{variant:"secondary",pending:A.isPending&&A.variables===s.id,pendingLabel:"Revoking",disabled:s.status==="revoked",onClick:()=>void A.mutateAsync(s.id),children:[e.jsx(W,{className:"size-4"}),s.status==="revoked"?"Revoked":"Revoke"]})]}),e.jsxs("div",{className:"grid min-w-0 gap-3 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-3",children:[e.jsx("div",{className:j,children:"Device sync sources"}),[["health","Health"],["movement","Movement"],["screenTime","Screen Time"]].map(([h,O])=>{var D,H;const o=s.sourceStates[h],se=o.desiredEnabled!==o.appliedEnabled,q=k.isPending&&((D=k.variables)==null?void 0:D.pairingSessionId)===s.id&&((H=k.variables)==null?void 0:H.source)===h;return e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-[14px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-3 py-3",children:[e.jsxs("div",{className:"grid min-w-0 gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"text-sm text-[var(--ui-ink-strong)]",children:O}),e.jsx(t,{tone:Se(o.desiredEnabled,o.syncEligible),size:"sm",children:o.desiredEnabled?"Enabled":"Off"}),se?e.jsx(t,{tone:"meta",size:"sm",children:"Pending on phone"}):e.jsx(t,{tone:"meta",size:"sm",children:"Applied"})]}),e.jsxs("div",{className:`break-words text-xs [overflow-wrap:anywhere] ${i}`,children:["Authorization"," ",ke(o.authorizationStatus)," · ","Last seen"," ",Pe(o.lastObservedAt)]})]}),e.jsx("button",{type:"button",role:"switch","aria-checked":o.desiredEnabled,"aria-label":`${O} sync source`,disabled:q,onClick:()=>void k.mutateAsync({pairingSessionId:s.id,source:h,desiredEnabled:!o.desiredEnabled}),className:`relative inline-flex h-7 w-12 items-center rounded-full border transition ${o.desiredEnabled?"border-[color-mix(in_srgb,var(--primary)_45%,var(--ui-border-subtle)_55%)] bg-[var(--ui-accent-soft)]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-3)]"} ${q?"opacity-60":""}`,children:e.jsx("span",{className:`inline-block size-5 rounded-full bg-[var(--ui-ink-strong)] shadow transition ${o.desiredEnabled?"translate-x-6":"translate-x-1"}`})})]},h)})]})]},s.id)),f.length===0?e.jsx("div",{className:`${w} px-4 py-6 text-sm ${i}`,children:"No companion paired yet. Generate a QR code, then open the iOS companion and scan it."}):null]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsxs(m,{variant:"secondary",onClick:()=>void p.refetch(),children:[e.jsx(B,{className:"size-4"}),"Refresh status"]}),e.jsxs(E,{to:"/sleep",className:T,children:[e.jsx(L,{className:"size-4"}),"Open sleep view"]}),e.jsxs(E,{to:"/sports",className:T,children:[e.jsx(L,{className:"size-4"}),"Open sports view"]}),e.jsxs(E,{to:"/vitals",className:T,children:[e.jsx(L,{className:"size-4"}),"Open vitals view"]})]})]})]}),e.jsxs(Q,{className:"grid min-w-0 gap-4 overflow-hidden",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:j,children:"Sync history"}),e.jsx("div",{className:"mt-2 text-lg text-[var(--ui-ink-strong)]",children:"Recent HealthKit import runs"})]}),e.jsxs(t,{tone:"meta",children:[n.importRuns.length," recent runs"]})]}),e.jsxs("div",{className:"grid min-w-0 gap-3",children:[n.importRuns.map(s=>e.jsxs("div",{className:`grid gap-3 ${l} px-4 py-4 lg:grid-cols-[minmax(0,1fr)_auto]`,children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(oe,{className:`size-4 ${v}`}),e.jsxs("div",{className:"text-base text-[var(--ui-ink-strong)]",children:[s.sourceDevice||"iPhone"," import"]}),e.jsx(t,{tone:s.status==="completed"?"signal":"meta",children:s.status})]}),e.jsxs("div",{className:`break-words text-sm [overflow-wrap:anywhere] ${i}`,children:[new Date(s.importedAt).toLocaleString()," ·"," ",ye(s.payloadSummary)]}),e.jsxs("div",{className:`flex flex-wrap gap-2 text-sm ${i}`,children:[e.jsxs(t,{tone:"meta",children:["Imported ",s.importedCount]}),e.jsxs(t,{tone:"meta",children:["Created ",s.createdCount]}),e.jsxs(t,{tone:"meta",children:["Updated ",s.updatedCount]}),e.jsxs(t,{tone:"meta",children:["Merged ",s.mergedCount]})]}),s.errorMessage?e.jsx("div",{className:"text-sm text-[color-mix(in_srgb,var(--danger)_76%,var(--ui-ink-strong)_24%)]",children:s.errorMessage}):null]}),s.pairingSessionId?e.jsxs("div",{className:`break-words text-sm [overflow-wrap:anywhere] ${v} lg:text-right`,children:["Pairing ",s.pairingSessionId]}):null]},s.id)),n.importRuns.length===0?e.jsx("div",{className:`${w} px-4 py-6 text-sm ${i}`,children:"No sync runs yet. Pair the iPhone companion and run the first HealthKit import."}):null]})]})]})}export{Oe as SettingsMobilePage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as n,j as e,b2 as le,dq as fe,c1 as ce,dr as ke,aG as ye,cN as Ne,de as Ce}from"./vendor-Cpmju3nw.js";import{j as we,i as I,k as h}from"./state-BtwEvpO6.js";import{S as Ae}from"./settings-section-nav-CwSDNC3W.js";import{P as Se}from"./page-hero-C0MpI3MM.js";import{L as Oe,e as Ie,C as w,B as o,k as l,cP as Me,dF as Pe,dG as Le,dH as Ee,dI as Ke,dJ as Fe,dK as Ue,dL as _e,cV as ze,bn as $e,dM as Be}from"./index-BaiwtAgo.js";import"./motion-DwjmC9aq.js";import"./ui-B9O-eUim.js";import"./board-CLOHbg6t.js";import"./forms-C5d5hTf2.js";const ue="grid min-w-0 gap-2 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] p-4",M="grid min-w-0 gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] p-4",P="rounded-[20px] border border-dashed border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-4 py-5 text-sm leading-6 text-[var(--ui-ink-soft)]",d="min-w-0 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-3 py-3 text-sm text-[var(--ui-ink-strong)] outline-none placeholder:text-[var(--ui-ink-faint)] transition focus:border-[var(--primary)]/35 focus:bg-[var(--ui-surface-3)]",j="text-sm text-[var(--ui-ink-strong)]",L="text-[var(--ui-ink-soft)]",m="text-[var(--ui-ink-faint)]",We="text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",g="bg-[var(--ui-surface-3)] text-[var(--ui-ink-medium)]",qe="bg-[var(--ui-warning-soft)] text-[color-mix(in_srgb,var(--warning)_78%,var(--ui-ink-strong)_22%)]",Qe="rounded-[20px] border border-[color-mix(in_srgb,var(--danger)_28%,var(--ui-border-subtle)_72%)] bg-[var(--ui-danger-soft)] px-4 py-5 text-sm leading-6 text-[color-mix(in_srgb,var(--danger)_76%,var(--ui-ink-strong)_24%)]";function E(i="openai-api"){return{label:i==="openai-codex"?"OpenAI Codex":i==="openai-compatible"?"Local compatible endpoint":i==="mock"?"Workbench mock runtime":"OpenAI API",provider:i,baseUrl:i==="openai-codex"?"https://chatgpt.com/backend-api":i==="openai-compatible"?"http://127.0.0.1:11434/v1":i==="mock"?"mock://workbench":"https://api.openai.com/v1",model:i==="mock"?"mock-echo":"gpt-5.4-mini",apiKey:""}}function Te(i){return{id:i.id,label:i.label,provider:i.provider,baseUrl:i.baseUrl,model:i.model,apiKey:""}}function ea(){var ie,te,ne,re,de;const i=we(),[s,x]=n.useState(()=>E()),[K,F]=n.useState(""),[U,_]=n.useState("gpt-5.4-mini"),[z,$]=n.useState(""),[B,W]=n.useState("gpt-5.4-mini"),[A,me]=n.useState("Fast wiki search"),[S,ge]=n.useState("text-embedding-3-small"),[q,he]=n.useState("https://api.openai.com/v1"),[Q,T]=n.useState(""),[R,xe]=n.useState("1200"),[D,pe]=n.useState("200"),[O,y]=n.useState(""),[c,N]=n.useState(null),[G,v]=n.useState(null),u=I({queryKey:["forge-settings"],queryFn:ze}),C=I({queryKey:["forge-wiki-settings"],queryFn:$e}),ve=I({queryKey:["forge-openai-codex-oauth",c],queryFn:async()=>{if(!c)throw new Error("Missing OAuth session id");return await Be(c)},enabled:!!c,refetchInterval:a=>{var oe;const r=(oe=a.state.data)==null?void 0:oe.session.status;return r&&["authorized","error","consumed","expired"].includes(r)?!1:1500}}),f=async()=>{await i.invalidateQueries({queryKey:["forge-settings"]}),await i.invalidateQueries({queryKey:["forge-wiki-settings"]}),await i.invalidateQueries({queryKey:["forge-wiki-search"]}),await i.invalidateQueries({queryKey:["forge-openai-codex-oauth",c]})},H=h({mutationFn:()=>Me({modelSettings:{forgeAgent:{basicChat:{connectionId:K||null,model:U},wiki:{connectionId:z||null,model:B}}}}),onSuccess:f}),Z=h({mutationFn:()=>Fe({id:s.id,label:s.label,provider:s.provider,authMode:s.provider==="openai-codex"?"oauth":"api_key",baseUrl:s.baseUrl,model:s.model,apiKey:s.provider==="openai-codex"?void 0:s.apiKey||void 0,oauthSessionId:s.provider==="openai-codex"?c??void 0:void 0}),onSuccess:async()=>{v("Connection saved."),s.provider==="openai-codex"&&(N(null),y("")),x(E(s.provider)),await f()},onError:a=>{v(a instanceof Error?a.message:"Connection save failed.")}}),J=h({mutationFn:_e,onSuccess:f}),V=h({mutationFn:()=>Le({label:A.trim(),model:S.trim(),baseUrl:q.trim(),apiKey:Q.trim()||void 0,chunkSize:Number(R),chunkOverlap:Number(D)}),onSuccess:async()=>{T(""),await f()}}),X=h({mutationFn:a=>Pe("embedding",a),onSuccess:f}),Y=h({mutationFn:async()=>Ue({connectionId:s.id,provider:s.provider,baseUrl:s.baseUrl,model:s.model,apiKey:s.provider==="openai-codex"?void 0:s.apiKey||void 0}),onSuccess:({result:a})=>{v(`Connection test succeeded: ${a.outputPreview}`)},onError:a=>{v(a instanceof Error?a.message:"Connection test failed.")}}),ee=h({mutationFn:Ee,onSuccess:({session:a})=>{N(a.id),v("OpenAI Codex OAuth started."),a.authUrl&&window.open(a.authUrl,"_blank","noopener,noreferrer")}}),ae=h({mutationFn:async()=>{if(!c)throw new Error("No OAuth session started yet.");return await Ke(c,O)},onSuccess:({session:a})=>{v(a.status==="authorized"?"OpenAI Codex OAuth authorized.":"Manual OAuth code submitted.")}});n.useEffect(()=>{var r;const a=(r=u.data)==null?void 0:r.settings;a&&(F(a.modelSettings.forgeAgent.basicChat.connectionId??""),_(a.modelSettings.forgeAgent.basicChat.model),$(a.modelSettings.forgeAgent.wiki.provider==="openai-codex"?a.modelSettings.forgeAgent.wiki.connectionId??"":""),W(a.modelSettings.forgeAgent.wiki.model))},[u.data]);const p=((ie=u.data)==null?void 0:ie.settings.modelSettings.connections)??[],se=p.filter(a=>a.provider==="openai-codex"&&a.authMode==="oauth"),be=se.filter(a=>a.hasStoredCredential),t=((te=ve.data)==null?void 0:te.session)??null,b=s.id?p.find(a=>a.id===s.id):null,je=n.useMemo(()=>!s.label.trim()||!s.model.trim()?!1:s.provider==="openai-codex"?!!((t==null?void 0:t.status)==="authorized"||s.id&&(b!=null&&b.hasStoredCredential)):s.provider==="mock"?!0:s.apiKey.trim().length>0||!!s.id,[s,b==null?void 0:b.hasStoredCredential,t==null?void 0:t.status]);if(u.isLoading)return e.jsx(Oe,{eyebrow:"Models",title:"Loading model settings",description:"Fetching Forge agent defaults and configured AI connections."});if(u.isError||!((ne=u.data)!=null&&ne.settings))return e.jsx(Ie,{eyebrow:"Models",error:u.error??new Error("Forge returned an empty model settings payload."),onRetry:()=>void u.refetch()});const k=u.data.settings;return e.jsxs("div",{className:"mx-auto grid min-w-0 w-full max-w-[1440px] gap-5",children:[e.jsx(Se,{eyebrow:"AI runtime",title:"Model Settings",description:"Manage Forge Agent defaults, OpenAI OAuth/API connections, and local OpenAI-compatible endpoints as first-class chat agents.",badge:`${p.length} model connection${p.length===1?"":"s"}`}),e.jsx(Ae,{}),e.jsxs(w,{className:"grid gap-5",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(le,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:j,children:"Forge Agent defaults"}),e.jsx("div",{className:`text-xs leading-5 ${m}`,children:"Forge Agent stays the default system agent. Choose which model connection powers basic chat and the managed wiki workflow."})]})]}),e.jsxs("div",{className:"grid gap-4 lg:grid-cols-2",children:[e.jsxs("label",{className:ue,children:[e.jsx("span",{className:`text-sm ${L}`,children:"Basic chat connection"}),e.jsxs("select",{className:d,value:K,onChange:a=>F(a.target.value),children:[e.jsx("option",{value:"",children:"No external connection"}),p.map(a=>e.jsxs("option",{value:a.id,children:[a.label," (",a.agentLabel,")"]},a.id))]}),e.jsx("input",{className:d,value:U,onChange:a=>_(a.target.value),placeholder:"Model"})]}),e.jsxs("label",{className:ue,children:[e.jsx("span",{className:`text-sm ${L}`,children:"KarpaWiki Codex OAuth connection"}),e.jsxs("select",{className:d,value:z,onChange:a=>$(a.target.value),children:[e.jsx("option",{value:"",children:"No Codex OAuth connection"}),se.map(a=>e.jsxs("option",{value:a.id,disabled:!a.hasStoredCredential,children:[a.label," (",a.accountLabel??a.agentLabel,")",a.hasStoredCredential?"":" · needs OAuth"]},a.id))]}),e.jsx("input",{className:d,value:B,onChange:a=>W(a.target.value),placeholder:"Model"}),e.jsx("span",{className:`text-xs leading-5 ${m}`,children:"KarpaWiki smart ingest uses ChatGPT/Codex OAuth only. It does not use metered OpenAI Platform API keys."})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(o,{pending:H.isPending,pendingLabel:"Saving defaults",onClick:()=>void H.mutateAsync(),children:"Save Forge Agent defaults"}),e.jsxs(l,{className:g,children:["Forge Agent",k.modelSettings.forgeAgent.basicChat.connectionLabel?` basic chat: ${k.modelSettings.forgeAgent.basicChat.connectionLabel}`:" basic chat stays local"]}),e.jsx(l,{className:g,children:k.modelSettings.forgeAgent.wiki.connectionLabel?`KarpaWiki OAuth: ${k.modelSettings.forgeAgent.wiki.connectionLabel}`:"KarpaWiki: no Codex OAuth model selected"}),be.length===0?e.jsx(l,{className:qe,children:"Add OpenAI Codex OAuth before smart ingest"}):null]})]}),e.jsxs(w,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(fe,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:j,children:"KarpaWiki embeddings"}),e.jsx("div",{className:`text-xs leading-5 ${m}`,children:"Semantic search profiles live with model settings. They remain optional; KarpaWiki text search and entity-linked search still work without embeddings."})]})]}),e.jsxs("div",{className:"grid gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(20rem,0.9fr)]",children:[e.jsxs("div",{className:"grid gap-3",children:[C.isLoading?e.jsx("div",{className:P,children:"Loading embedding profiles."}):null,C.isError?e.jsx("div",{className:Qe,children:"Could not load KarpaWiki embedding profiles."}):null,((re=C.data)==null?void 0:re.settings.embeddingProfiles.length)===0?e.jsx("div",{className:P,children:"No embedding profile yet. Add one only if you want semantic wiki search in addition to exact search and links."}):null,(de=C.data)==null?void 0:de.settings.embeddingProfiles.map(a=>e.jsxs("div",{className:"grid min-w-0 gap-2 rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-4 py-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"truncate text-[var(--ui-ink-strong)]",children:a.label}),e.jsxs("div",{className:`mt-1 break-words text-xs [overflow-wrap:anywhere] ${m}`,children:[a.model," · ",a.baseUrl]})]}),e.jsx(o,{variant:"secondary",pending:X.isPending,pendingLabel:"Deleting",onClick:()=>void X.mutateAsync(a.id),children:e.jsx(ce,{className:"size-4"})})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(l,{className:g,children:["chunk ",a.chunkSize]}),e.jsxs(l,{className:g,children:["overlap ",a.chunkOverlap]}),e.jsx(l,{className:g,children:a.enabled?"enabled":"disabled"})]})]},a.id))]}),e.jsxs("div",{className:M,children:[e.jsx("input",{className:d,value:A,onChange:a=>me(a.target.value),placeholder:"Profile label"}),e.jsx("input",{className:d,value:S,onChange:a=>ge(a.target.value),placeholder:"Embedding model"}),e.jsx("input",{className:d,value:q,onChange:a=>he(a.target.value),placeholder:"Embedding base URL"}),e.jsx("input",{className:d,value:Q,onChange:a=>T(a.target.value),placeholder:"Embedding API key (optional)",type:"password"}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-2",children:[e.jsx("input",{className:d,value:R,onChange:a=>xe(a.target.value),placeholder:"Chunk size",type:"number"}),e.jsx("input",{className:d,value:D,onChange:a=>pe(a.target.value),placeholder:"Chunk overlap",type:"number"})]}),e.jsx(o,{pending:V.isPending,pendingLabel:"Saving",disabled:!A.trim()||!S.trim(),onClick:()=>void V.mutateAsync(),children:"Save embedding profile"})]})]})]}),e.jsxs("div",{className:"grid min-w-0 gap-5 xl:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]",children:[e.jsxs(w,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(ke,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:j,children:"Connection editor"}),e.jsx("div",{className:`text-xs leading-5 ${m}`,children:"Every saved connection becomes a first-class agent layered on top of Forge Agent."})]})]}),e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx("div",{className:We,children:"Provider"}),e.jsx("div",{className:"grid gap-2 md:grid-cols-3",children:[["openai-api","OpenAI API"],["openai-codex","OpenAI Codex OAuth"],["openai-compatible","OpenAI-compatible"]].map(([a,r])=>e.jsx("button",{type:"button",className:`rounded-[18px] px-4 py-3 text-left text-sm transition ${s.provider===a?"border border-[color-mix(in_srgb,var(--primary)_34%,var(--ui-border-subtle)_66%)] bg-[var(--ui-accent-soft)] text-[var(--ui-ink-strong)] shadow-[var(--ui-shadow-soft)]":"border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] text-[var(--ui-ink-soft)] hover:bg-[var(--ui-surface-hover)] hover:text-[var(--ui-ink-strong)]"}`,onClick:()=>{x(E(a)),N(null),y("")},children:r},a))})]}),e.jsx("input",{className:d,value:s.label,onChange:a=>x(r=>({...r,label:a.target.value})),placeholder:"Connection label"}),e.jsx("input",{className:d,value:s.model,onChange:a=>x(r=>({...r,model:a.target.value})),placeholder:"Model"}),s.provider==="mock"?e.jsxs("div",{className:M,children:[e.jsx("div",{className:j,children:"The Workbench mock runtime is only meant for local development and test workflows."}),e.jsxs("div",{className:`text-xs leading-5 ${m}`,children:["Use mock models like ",e.jsx("code",{children:"mock-echo"}),","," ",e.jsx("code",{children:"mock-json"}),",",e.jsx("code",{children:"mock-tool-search"}),","," ",e.jsx("code",{children:"mock-tool-note"}),", or",e.jsx("code",{children:"mock-chat-memory"})," to exercise deterministic flow behavior without a real external model."]})]}):s.provider!=="openai-codex"?e.jsxs(e.Fragment,{children:[e.jsx("input",{className:d,value:s.baseUrl,onChange:a=>x(r=>({...r,baseUrl:a.target.value})),placeholder:"Base URL"}),e.jsx("input",{className:d,value:s.apiKey,onChange:a=>x(r=>({...r,apiKey:a.target.value})),placeholder:s.id?"Leave blank to keep the stored key":"API key",type:"password"})]}):e.jsxs("div",{className:M,children:[e.jsxs("div",{className:j,children:["OpenAI Codex uses the documented PKCE flow with the local callback at"," ",e.jsx("span",{className:"break-words [overflow-wrap:anywhere]",children:k.modelSettings.oauth.openAiCodex.callbackUrl})]}),e.jsx("div",{className:`text-xs leading-5 ${m}`,children:"Start OAuth, finish the browser sign-in, then save the resulting connection as a chat agent backed by the ChatGPT Codex runtime."}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsxs(o,{variant:"secondary",pending:ee.isPending,pendingLabel:"Starting OAuth",onClick:()=>void ee.mutateAsync(),children:[e.jsx(ye,{className:"size-4"}),"Start OAuth"]}),t!=null&&t.authUrl?e.jsxs(o,{variant:"secondary",onClick:()=>window.open(t.authUrl??"","_blank","noopener,noreferrer"),children:["Open sign-in",e.jsx(Ne,{className:"size-4"})]}):null]}),t?e.jsxs("div",{className:"grid min-w-0 gap-2 rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-code-bg)] p-3 text-sm text-[var(--ui-code-text)]",children:[e.jsxs("div",{children:["Status: ",t.status]}),t.accountLabel?e.jsxs("div",{children:["Account: ",t.accountLabel]}):null,t.error?e.jsx("div",{className:"text-[color-mix(in_srgb,var(--danger)_76%,var(--ui-ink-strong)_24%)]",children:t.error}):null]}):null,e.jsxs("div",{className:"grid gap-2",children:[e.jsx("input",{className:d,value:O,onChange:a=>y(a.target.value),placeholder:"Paste the authorization code or full redirect URL"}),e.jsx(o,{variant:"secondary",disabled:!O.trim()||!c,pending:ae.isPending,pendingLabel:"Submitting",onClick:()=>void ae.mutateAsync(),children:"Submit manual code"})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(o,{pending:Z.isPending,pendingLabel:"Saving connection",disabled:!je,onClick:()=>void Z.mutateAsync(),children:"Save connection"}),e.jsxs(o,{variant:"secondary",pending:Y.isPending,pendingLabel:"Testing",disabled:s.provider==="openai-codex"?!s.id:s.provider==="mock"?!1:!s.id&&!s.apiKey.trim(),onClick:()=>void Y.mutateAsync(),children:[e.jsx(Ce,{className:"size-4"}),"Test connection"]})]}),G?e.jsx("div",{className:`rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-4 py-3 text-sm ${L}`,children:G}):null]})]}),e.jsxs(w,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(le,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:j,children:"Connected agents"}),e.jsx("div",{className:`text-xs leading-5 ${m}`,children:"Each connection registers its own chat-facing agent identity."})]})]}),e.jsxs("div",{className:"grid gap-3",children:[p.length===0?e.jsx("div",{className:P,children:"No external model connection yet. Add one with OAuth or API credentials and Forge will expose it as a first-class agent."}):null,p.map(a=>e.jsxs("div",{className:"grid min-w-0 gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] p-4",children:[e.jsxs("div",{className:"flex min-w-0 flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"break-words text-[var(--ui-ink-strong)] [overflow-wrap:anywhere]",children:a.label}),e.jsxs("div",{className:`mt-1 break-words text-xs [overflow-wrap:anywhere] ${m}`,children:[a.agentLabel," · ",a.provider," ·"," ",a.model]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(o,{variant:"secondary",onClick:()=>{x(Te(a)),N(null),y("")},children:"Edit"}),e.jsx(o,{variant:"secondary",pending:J.isPending,pendingLabel:"Deleting",onClick:()=>void J.mutateAsync(a.id),children:e.jsx(ce,{className:"size-4"})})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(l,{className:g,children:a.authMode==="oauth"?"OAuth":"API key"}),e.jsx(l,{className:g,children:a.status}),e.jsx(l,{className:g,wrap:!0,children:a.baseUrl}),a.accountLabel?e.jsx(l,{className:g,wrap:!0,children:a.accountLabel}):null]})]},a.id))]})]})]})]})}export{ea as SettingsModelsPage};
|
|
1
|
+
import{r as n,j as e,b2 as le,dq as fe,c1 as ce,dr as ke,aG as ye,cN as Ne,de as Ce}from"./vendor-BwL6m4SE.js";import{j as we,i as I,k as h}from"./state-Bpe5dF3T.js";import{S as Ae}from"./settings-section-nav-BmJWnrYk.js";import{P as Se}from"./page-hero-8bITsx_x.js";import{L as Oe,e as Ie,C as w,B as o,k as l,cP as Me,dF as Pe,dG as Le,dH as Ee,dI as Ke,dJ as Fe,dK as Ue,dL as _e,cV as ze,bn as $e,dM as Be}from"./index-CQ5r7ZUz.js";import"./motion-DcgUnXhY.js";import"./ui-B9TWEtCx.js";import"./board-CuxQRKPJ.js";import"./forms-D1qJ3oOP.js";const ue="grid min-w-0 gap-2 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] p-4",M="grid min-w-0 gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] p-4",P="rounded-[20px] border border-dashed border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-4 py-5 text-sm leading-6 text-[var(--ui-ink-soft)]",d="min-w-0 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-3 py-3 text-sm text-[var(--ui-ink-strong)] outline-none placeholder:text-[var(--ui-ink-faint)] transition focus:border-[var(--primary)]/35 focus:bg-[var(--ui-surface-3)]",j="text-sm text-[var(--ui-ink-strong)]",L="text-[var(--ui-ink-soft)]",m="text-[var(--ui-ink-faint)]",We="text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",g="bg-[var(--ui-surface-3)] text-[var(--ui-ink-medium)]",qe="bg-[var(--ui-warning-soft)] text-[color-mix(in_srgb,var(--warning)_78%,var(--ui-ink-strong)_22%)]",Qe="rounded-[20px] border border-[color-mix(in_srgb,var(--danger)_28%,var(--ui-border-subtle)_72%)] bg-[var(--ui-danger-soft)] px-4 py-5 text-sm leading-6 text-[color-mix(in_srgb,var(--danger)_76%,var(--ui-ink-strong)_24%)]";function E(i="openai-api"){return{label:i==="openai-codex"?"OpenAI Codex":i==="openai-compatible"?"Local compatible endpoint":i==="mock"?"Workbench mock runtime":"OpenAI API",provider:i,baseUrl:i==="openai-codex"?"https://chatgpt.com/backend-api":i==="openai-compatible"?"http://127.0.0.1:11434/v1":i==="mock"?"mock://workbench":"https://api.openai.com/v1",model:i==="mock"?"mock-echo":"gpt-5.4-mini",apiKey:""}}function Te(i){return{id:i.id,label:i.label,provider:i.provider,baseUrl:i.baseUrl,model:i.model,apiKey:""}}function ea(){var ie,te,ne,re,de;const i=we(),[s,x]=n.useState(()=>E()),[K,F]=n.useState(""),[U,_]=n.useState("gpt-5.4-mini"),[z,$]=n.useState(""),[B,W]=n.useState("gpt-5.4-mini"),[A,me]=n.useState("Fast wiki search"),[S,ge]=n.useState("text-embedding-3-small"),[q,he]=n.useState("https://api.openai.com/v1"),[Q,T]=n.useState(""),[R,xe]=n.useState("1200"),[D,pe]=n.useState("200"),[O,y]=n.useState(""),[c,N]=n.useState(null),[G,v]=n.useState(null),u=I({queryKey:["forge-settings"],queryFn:ze}),C=I({queryKey:["forge-wiki-settings"],queryFn:$e}),ve=I({queryKey:["forge-openai-codex-oauth",c],queryFn:async()=>{if(!c)throw new Error("Missing OAuth session id");return await Be(c)},enabled:!!c,refetchInterval:a=>{var oe;const r=(oe=a.state.data)==null?void 0:oe.session.status;return r&&["authorized","error","consumed","expired"].includes(r)?!1:1500}}),f=async()=>{await i.invalidateQueries({queryKey:["forge-settings"]}),await i.invalidateQueries({queryKey:["forge-wiki-settings"]}),await i.invalidateQueries({queryKey:["forge-wiki-search"]}),await i.invalidateQueries({queryKey:["forge-openai-codex-oauth",c]})},H=h({mutationFn:()=>Me({modelSettings:{forgeAgent:{basicChat:{connectionId:K||null,model:U},wiki:{connectionId:z||null,model:B}}}}),onSuccess:f}),Z=h({mutationFn:()=>Fe({id:s.id,label:s.label,provider:s.provider,authMode:s.provider==="openai-codex"?"oauth":"api_key",baseUrl:s.baseUrl,model:s.model,apiKey:s.provider==="openai-codex"?void 0:s.apiKey||void 0,oauthSessionId:s.provider==="openai-codex"?c??void 0:void 0}),onSuccess:async()=>{v("Connection saved."),s.provider==="openai-codex"&&(N(null),y("")),x(E(s.provider)),await f()},onError:a=>{v(a instanceof Error?a.message:"Connection save failed.")}}),J=h({mutationFn:_e,onSuccess:f}),V=h({mutationFn:()=>Le({label:A.trim(),model:S.trim(),baseUrl:q.trim(),apiKey:Q.trim()||void 0,chunkSize:Number(R),chunkOverlap:Number(D)}),onSuccess:async()=>{T(""),await f()}}),X=h({mutationFn:a=>Pe("embedding",a),onSuccess:f}),Y=h({mutationFn:async()=>Ue({connectionId:s.id,provider:s.provider,baseUrl:s.baseUrl,model:s.model,apiKey:s.provider==="openai-codex"?void 0:s.apiKey||void 0}),onSuccess:({result:a})=>{v(`Connection test succeeded: ${a.outputPreview}`)},onError:a=>{v(a instanceof Error?a.message:"Connection test failed.")}}),ee=h({mutationFn:Ee,onSuccess:({session:a})=>{N(a.id),v("OpenAI Codex OAuth started."),a.authUrl&&window.open(a.authUrl,"_blank","noopener,noreferrer")}}),ae=h({mutationFn:async()=>{if(!c)throw new Error("No OAuth session started yet.");return await Ke(c,O)},onSuccess:({session:a})=>{v(a.status==="authorized"?"OpenAI Codex OAuth authorized.":"Manual OAuth code submitted.")}});n.useEffect(()=>{var r;const a=(r=u.data)==null?void 0:r.settings;a&&(F(a.modelSettings.forgeAgent.basicChat.connectionId??""),_(a.modelSettings.forgeAgent.basicChat.model),$(a.modelSettings.forgeAgent.wiki.provider==="openai-codex"?a.modelSettings.forgeAgent.wiki.connectionId??"":""),W(a.modelSettings.forgeAgent.wiki.model))},[u.data]);const p=((ie=u.data)==null?void 0:ie.settings.modelSettings.connections)??[],se=p.filter(a=>a.provider==="openai-codex"&&a.authMode==="oauth"),be=se.filter(a=>a.hasStoredCredential),t=((te=ve.data)==null?void 0:te.session)??null,b=s.id?p.find(a=>a.id===s.id):null,je=n.useMemo(()=>!s.label.trim()||!s.model.trim()?!1:s.provider==="openai-codex"?!!((t==null?void 0:t.status)==="authorized"||s.id&&(b!=null&&b.hasStoredCredential)):s.provider==="mock"?!0:s.apiKey.trim().length>0||!!s.id,[s,b==null?void 0:b.hasStoredCredential,t==null?void 0:t.status]);if(u.isLoading)return e.jsx(Oe,{eyebrow:"Models",title:"Loading model settings",description:"Fetching Forge agent defaults and configured AI connections."});if(u.isError||!((ne=u.data)!=null&&ne.settings))return e.jsx(Ie,{eyebrow:"Models",error:u.error??new Error("Forge returned an empty model settings payload."),onRetry:()=>void u.refetch()});const k=u.data.settings;return e.jsxs("div",{className:"mx-auto grid min-w-0 w-full max-w-[1440px] gap-5",children:[e.jsx(Se,{eyebrow:"AI runtime",title:"Model Settings",description:"Manage Forge Agent defaults, OpenAI OAuth/API connections, and local OpenAI-compatible endpoints as first-class chat agents.",badge:`${p.length} model connection${p.length===1?"":"s"}`}),e.jsx(Ae,{}),e.jsxs(w,{className:"grid gap-5",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(le,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:j,children:"Forge Agent defaults"}),e.jsx("div",{className:`text-xs leading-5 ${m}`,children:"Forge Agent stays the default system agent. Choose which model connection powers basic chat and the managed wiki workflow."})]})]}),e.jsxs("div",{className:"grid gap-4 lg:grid-cols-2",children:[e.jsxs("label",{className:ue,children:[e.jsx("span",{className:`text-sm ${L}`,children:"Basic chat connection"}),e.jsxs("select",{className:d,value:K,onChange:a=>F(a.target.value),children:[e.jsx("option",{value:"",children:"No external connection"}),p.map(a=>e.jsxs("option",{value:a.id,children:[a.label," (",a.agentLabel,")"]},a.id))]}),e.jsx("input",{className:d,value:U,onChange:a=>_(a.target.value),placeholder:"Model"})]}),e.jsxs("label",{className:ue,children:[e.jsx("span",{className:`text-sm ${L}`,children:"KarpaWiki Codex OAuth connection"}),e.jsxs("select",{className:d,value:z,onChange:a=>$(a.target.value),children:[e.jsx("option",{value:"",children:"No Codex OAuth connection"}),se.map(a=>e.jsxs("option",{value:a.id,disabled:!a.hasStoredCredential,children:[a.label," (",a.accountLabel??a.agentLabel,")",a.hasStoredCredential?"":" · needs OAuth"]},a.id))]}),e.jsx("input",{className:d,value:B,onChange:a=>W(a.target.value),placeholder:"Model"}),e.jsx("span",{className:`text-xs leading-5 ${m}`,children:"KarpaWiki smart ingest uses ChatGPT/Codex OAuth only. It does not use metered OpenAI Platform API keys."})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(o,{pending:H.isPending,pendingLabel:"Saving defaults",onClick:()=>void H.mutateAsync(),children:"Save Forge Agent defaults"}),e.jsxs(l,{className:g,children:["Forge Agent",k.modelSettings.forgeAgent.basicChat.connectionLabel?` basic chat: ${k.modelSettings.forgeAgent.basicChat.connectionLabel}`:" basic chat stays local"]}),e.jsx(l,{className:g,children:k.modelSettings.forgeAgent.wiki.connectionLabel?`KarpaWiki OAuth: ${k.modelSettings.forgeAgent.wiki.connectionLabel}`:"KarpaWiki: no Codex OAuth model selected"}),be.length===0?e.jsx(l,{className:qe,children:"Add OpenAI Codex OAuth before smart ingest"}):null]})]}),e.jsxs(w,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(fe,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:j,children:"KarpaWiki embeddings"}),e.jsx("div",{className:`text-xs leading-5 ${m}`,children:"Semantic search profiles live with model settings. They remain optional; KarpaWiki text search and entity-linked search still work without embeddings."})]})]}),e.jsxs("div",{className:"grid gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(20rem,0.9fr)]",children:[e.jsxs("div",{className:"grid gap-3",children:[C.isLoading?e.jsx("div",{className:P,children:"Loading embedding profiles."}):null,C.isError?e.jsx("div",{className:Qe,children:"Could not load KarpaWiki embedding profiles."}):null,((re=C.data)==null?void 0:re.settings.embeddingProfiles.length)===0?e.jsx("div",{className:P,children:"No embedding profile yet. Add one only if you want semantic wiki search in addition to exact search and links."}):null,(de=C.data)==null?void 0:de.settings.embeddingProfiles.map(a=>e.jsxs("div",{className:"grid min-w-0 gap-2 rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-4 py-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"truncate text-[var(--ui-ink-strong)]",children:a.label}),e.jsxs("div",{className:`mt-1 break-words text-xs [overflow-wrap:anywhere] ${m}`,children:[a.model," · ",a.baseUrl]})]}),e.jsx(o,{variant:"secondary",pending:X.isPending,pendingLabel:"Deleting",onClick:()=>void X.mutateAsync(a.id),children:e.jsx(ce,{className:"size-4"})})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(l,{className:g,children:["chunk ",a.chunkSize]}),e.jsxs(l,{className:g,children:["overlap ",a.chunkOverlap]}),e.jsx(l,{className:g,children:a.enabled?"enabled":"disabled"})]})]},a.id))]}),e.jsxs("div",{className:M,children:[e.jsx("input",{className:d,value:A,onChange:a=>me(a.target.value),placeholder:"Profile label"}),e.jsx("input",{className:d,value:S,onChange:a=>ge(a.target.value),placeholder:"Embedding model"}),e.jsx("input",{className:d,value:q,onChange:a=>he(a.target.value),placeholder:"Embedding base URL"}),e.jsx("input",{className:d,value:Q,onChange:a=>T(a.target.value),placeholder:"Embedding API key (optional)",type:"password"}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-2",children:[e.jsx("input",{className:d,value:R,onChange:a=>xe(a.target.value),placeholder:"Chunk size",type:"number"}),e.jsx("input",{className:d,value:D,onChange:a=>pe(a.target.value),placeholder:"Chunk overlap",type:"number"})]}),e.jsx(o,{pending:V.isPending,pendingLabel:"Saving",disabled:!A.trim()||!S.trim(),onClick:()=>void V.mutateAsync(),children:"Save embedding profile"})]})]})]}),e.jsxs("div",{className:"grid min-w-0 gap-5 xl:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]",children:[e.jsxs(w,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(ke,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:j,children:"Connection editor"}),e.jsx("div",{className:`text-xs leading-5 ${m}`,children:"Every saved connection becomes a first-class agent layered on top of Forge Agent."})]})]}),e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx("div",{className:We,children:"Provider"}),e.jsx("div",{className:"grid gap-2 md:grid-cols-3",children:[["openai-api","OpenAI API"],["openai-codex","OpenAI Codex OAuth"],["openai-compatible","OpenAI-compatible"]].map(([a,r])=>e.jsx("button",{type:"button",className:`rounded-[18px] px-4 py-3 text-left text-sm transition ${s.provider===a?"border border-[color-mix(in_srgb,var(--primary)_34%,var(--ui-border-subtle)_66%)] bg-[var(--ui-accent-soft)] text-[var(--ui-ink-strong)] shadow-[var(--ui-shadow-soft)]":"border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] text-[var(--ui-ink-soft)] hover:bg-[var(--ui-surface-hover)] hover:text-[var(--ui-ink-strong)]"}`,onClick:()=>{x(E(a)),N(null),y("")},children:r},a))})]}),e.jsx("input",{className:d,value:s.label,onChange:a=>x(r=>({...r,label:a.target.value})),placeholder:"Connection label"}),e.jsx("input",{className:d,value:s.model,onChange:a=>x(r=>({...r,model:a.target.value})),placeholder:"Model"}),s.provider==="mock"?e.jsxs("div",{className:M,children:[e.jsx("div",{className:j,children:"The Workbench mock runtime is only meant for local development and test workflows."}),e.jsxs("div",{className:`text-xs leading-5 ${m}`,children:["Use mock models like ",e.jsx("code",{children:"mock-echo"}),","," ",e.jsx("code",{children:"mock-json"}),",",e.jsx("code",{children:"mock-tool-search"}),","," ",e.jsx("code",{children:"mock-tool-note"}),", or",e.jsx("code",{children:"mock-chat-memory"})," to exercise deterministic flow behavior without a real external model."]})]}):s.provider!=="openai-codex"?e.jsxs(e.Fragment,{children:[e.jsx("input",{className:d,value:s.baseUrl,onChange:a=>x(r=>({...r,baseUrl:a.target.value})),placeholder:"Base URL"}),e.jsx("input",{className:d,value:s.apiKey,onChange:a=>x(r=>({...r,apiKey:a.target.value})),placeholder:s.id?"Leave blank to keep the stored key":"API key",type:"password"})]}):e.jsxs("div",{className:M,children:[e.jsxs("div",{className:j,children:["OpenAI Codex uses the documented PKCE flow with the local callback at"," ",e.jsx("span",{className:"break-words [overflow-wrap:anywhere]",children:k.modelSettings.oauth.openAiCodex.callbackUrl})]}),e.jsx("div",{className:`text-xs leading-5 ${m}`,children:"Start OAuth, finish the browser sign-in, then save the resulting connection as a chat agent backed by the ChatGPT Codex runtime."}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsxs(o,{variant:"secondary",pending:ee.isPending,pendingLabel:"Starting OAuth",onClick:()=>void ee.mutateAsync(),children:[e.jsx(ye,{className:"size-4"}),"Start OAuth"]}),t!=null&&t.authUrl?e.jsxs(o,{variant:"secondary",onClick:()=>window.open(t.authUrl??"","_blank","noopener,noreferrer"),children:["Open sign-in",e.jsx(Ne,{className:"size-4"})]}):null]}),t?e.jsxs("div",{className:"grid min-w-0 gap-2 rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-code-bg)] p-3 text-sm text-[var(--ui-code-text)]",children:[e.jsxs("div",{children:["Status: ",t.status]}),t.accountLabel?e.jsxs("div",{children:["Account: ",t.accountLabel]}):null,t.error?e.jsx("div",{className:"text-[color-mix(in_srgb,var(--danger)_76%,var(--ui-ink-strong)_24%)]",children:t.error}):null]}):null,e.jsxs("div",{className:"grid gap-2",children:[e.jsx("input",{className:d,value:O,onChange:a=>y(a.target.value),placeholder:"Paste the authorization code or full redirect URL"}),e.jsx(o,{variant:"secondary",disabled:!O.trim()||!c,pending:ae.isPending,pendingLabel:"Submitting",onClick:()=>void ae.mutateAsync(),children:"Submit manual code"})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(o,{pending:Z.isPending,pendingLabel:"Saving connection",disabled:!je,onClick:()=>void Z.mutateAsync(),children:"Save connection"}),e.jsxs(o,{variant:"secondary",pending:Y.isPending,pendingLabel:"Testing",disabled:s.provider==="openai-codex"?!s.id:s.provider==="mock"?!1:!s.id&&!s.apiKey.trim(),onClick:()=>void Y.mutateAsync(),children:[e.jsx(Ce,{className:"size-4"}),"Test connection"]})]}),G?e.jsx("div",{className:`rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-4 py-3 text-sm ${L}`,children:G}):null]})]}),e.jsxs(w,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(le,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:j,children:"Connected agents"}),e.jsx("div",{className:`text-xs leading-5 ${m}`,children:"Each connection registers its own chat-facing agent identity."})]})]}),e.jsxs("div",{className:"grid gap-3",children:[p.length===0?e.jsx("div",{className:P,children:"No external model connection yet. Add one with OAuth or API credentials and Forge will expose it as a first-class agent."}):null,p.map(a=>e.jsxs("div",{className:"grid min-w-0 gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] p-4",children:[e.jsxs("div",{className:"flex min-w-0 flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"break-words text-[var(--ui-ink-strong)] [overflow-wrap:anywhere]",children:a.label}),e.jsxs("div",{className:`mt-1 break-words text-xs [overflow-wrap:anywhere] ${m}`,children:[a.agentLabel," · ",a.provider," ·"," ",a.model]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(o,{variant:"secondary",onClick:()=>{x(Te(a)),N(null),y("")},children:"Edit"}),e.jsx(o,{variant:"secondary",pending:J.isPending,pendingLabel:"Deleting",onClick:()=>void J.mutateAsync(a.id),children:e.jsx(ce,{className:"size-4"})})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(l,{className:g,children:a.authMode==="oauth"?"OAuth":"API key"}),e.jsx(l,{className:g,children:a.status}),e.jsx(l,{className:g,wrap:!0,children:a.baseUrl}),a.accountLabel?e.jsx(l,{className:g,wrap:!0,children:a.accountLabel}):null]})]},a.id))]})]})]})]})}export{ea as SettingsModelsPage};
|