@tequila99/githuman 0.7.0 → 0.8.0
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/README.md +39 -0
- package/dist/cli/config.js +13 -1
- package/dist/cli/server-runtime.js +3 -0
- package/dist/server/app.js +36 -4
- package/dist/server/config/agents.js +2 -1
- package/dist/server/config/openapi.js +4 -0
- package/dist/server/db/migrations.js +55 -0
- package/dist/server/errors/notes.js +3 -0
- package/dist/server/hooks/notes/same-origin.js +37 -0
- package/dist/server/hooks/terminal/local-origin.js +2 -1
- package/dist/server/repositories/notes-catalog.repo.js +128 -0
- package/dist/server/repositories/notes.repo.js +402 -0
- package/dist/server/routes/notes.js +167 -0
- package/dist/server/routes/terminal.js +2 -1
- package/dist/server/services/git.service.js +15 -11
- package/dist/server/services/notes-identity.service.js +726 -0
- package/dist/server/services/notes-operations.service.js +298 -0
- package/dist/server/services/notes-watcher.service.js +44 -0
- package/dist/server/services/notes-writer.service.js +116 -0
- package/dist/server/services/notes.service.js +125 -0
- package/dist/server/services/terminal/backend.js +6 -3
- package/dist/server/services/terminal/channel.js +6 -3
- package/dist/server/services/terminal/registry.js +10 -5
- package/dist/server/services/terminal/session.js +10 -5
- package/dist/server/services/terminal/tokens.js +4 -2
- package/dist/server/utils/hash.js +4 -0
- package/dist/server/utils/note-asset-format.js +19 -0
- package/dist/server/utils/system-error.js +14 -0
- package/dist/shared/events/types.js +1 -0
- package/dist/shared/notes/asset-formats.js +39 -0
- package/dist/shared/notes/constants.js +2 -0
- package/dist/shared/notes/document.js +118 -0
- package/dist/shared/notes/identity.js +24 -0
- package/dist/shared/notes/links.js +44 -0
- package/dist/shared/notes/reference-path.js +54 -0
- package/dist/shared/notes/references.js +190 -0
- package/dist/shared/notes/schemas.js +164 -0
- package/dist/shared/notes/types.js +1 -0
- package/dist/shared/utils/heading-slug.js +7 -0
- package/dist/shared/utils/is-uuid.js +5 -0
- package/dist/shared/utils/safe-decode.js +9 -0
- package/dist/web/assets/AppPage-cl-3VfAl.js +1 -0
- package/dist/web/assets/ClosePopup-D2_HzWXW.js +1 -0
- package/dist/web/assets/CreateButton-pmDRGwna.js +93 -0
- package/dist/web/assets/CreateReviewFabButton-CcXWnmSN.js +1 -0
- package/dist/web/assets/{ErrorNotFound-CYOZg8yN.js → ErrorNotFound-Cq0wNQMu.js} +1 -1
- package/dist/web/assets/IndexPage-CmBmgu4A.js +1 -0
- package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-gV2CO0n9.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/web/assets/MainLayout-DM30ynlR.css +1 -0
- package/dist/web/assets/MainLayout-DOGoQ-1m.js +6 -0
- package/dist/web/assets/NoteVisualEditor-CClIKW0X.css +1 -0
- package/dist/web/assets/NoteVisualEditor-zjZr9aod.js +1056 -0
- package/dist/web/assets/NotesPage-C5VXA9Bb.css +1 -0
- package/dist/web/assets/NotesPage-Jeva3Jta.js +114 -0
- package/dist/web/assets/{PdfPreview-CIiKnzQN.js → PdfPreview-CdgeqqEv.js} +1 -1
- package/dist/web/assets/QBtn-DoggJe1Q.js +1 -0
- package/dist/web/assets/QFab-DyUFgj0W.js +1 -0
- package/dist/web/assets/QForm-BiRkV9BY.js +4 -0
- package/dist/web/assets/QInput-DJgTh2Qy.js +1 -0
- package/dist/web/assets/QScrollArea-DfPW35JQ.js +1 -0
- package/dist/web/assets/QSelect-BpZ5KfWP.js +1 -0
- package/dist/web/assets/QSpace-BRLIXkHB.js +1 -0
- package/dist/web/assets/ReviewDetailPage-CpJPrSKO.js +1 -0
- package/dist/web/assets/ReviewsPage-BaxUZzUZ.js +1 -0
- package/dist/web/assets/{StatusSwitcher-DTD5inU1.css → StatusSwitcher-BCv_9MtI.css} +1 -1
- package/dist/web/assets/StatusSwitcher-D5UG_YWP.js +1 -0
- package/dist/web/assets/{TerminalView-BurzSD2L.css → TerminalView-C1jFlfLH.css} +1 -1
- package/dist/web/assets/{TerminalView-Ch-ndYr6.js → TerminalView-DMJTXE-G.js} +2 -2
- package/dist/web/assets/_baseMerge-BzZFQ6mI.js +1 -0
- package/dist/web/assets/{abnfDiagram-O67JEVCF-Cab71FlB.js → abnfDiagram-O67JEVCF-CiOkMSRz.js} +1 -1
- package/dist/web/assets/agent-icon-Dx8WBYX_.js +1 -0
- package/dist/web/assets/agent-store-B1VK6S0D.js +1 -0
- package/dist/web/assets/apl-gfMMiTNf.js +1 -0
- package/dist/web/assets/{app-info-store-BmD_P8q2.js → app-info-store-D76h_OdJ.js} +1 -1
- package/dist/web/assets/architecture-7GRP2DOG-Byc4Oz95.js +1 -0
- package/dist/web/assets/{architectureDiagram-NJMV4G6O-Dl1WKOEi.js → architectureDiagram-NJMV4G6O-BexHJffj.js} +1 -1
- package/dist/web/assets/asciiarmor-C_eisQCp.js +1 -0
- package/dist/web/assets/asn1-DCl_8MCW.js +1 -0
- package/dist/web/assets/asterisk-BEn0Cwpx.js +1 -0
- package/dist/web/assets/{blockDiagram-BEXU5L5S-CZ3Lxybj.js → blockDiagram-BEXU5L5S-CEyB_5a1.js} +1 -1
- package/dist/web/assets/brainfuck-D5EjA2JK.js +1 -0
- package/dist/web/assets/{c4Diagram-YGBWAQC7-ULi06PEd.js → c4Diagram-YGBWAQC7-BRNWA7xI.js} +1 -1
- package/dist/web/assets/ccount-CcG1m-Yh.js +1 -0
- package/dist/web/assets/channel-DbRAFIx1.js +1 -0
- package/dist/web/assets/{chunk-3FUC2YCW-B1f60wx3.js → chunk-3FUC2YCW-BcQR1JDF.js} +1 -1
- package/dist/web/assets/{chunk-5DYCD2WN-f6Pcl3dF.js → chunk-5DYCD2WN-D6aQ1hFt.js} +1 -1
- package/dist/web/assets/{chunk-742MDFTN-szX1QirW.js → chunk-742MDFTN-BRgrFtkf.js} +1 -1
- package/dist/web/assets/{chunk-7INBJB4K-CP_ynmAQ.js → chunk-7INBJB4K-3RBjXeq6.js} +1 -1
- package/dist/web/assets/{chunk-7M6MHVWA-DPL74uZE.js → chunk-7M6MHVWA-Malugc_N.js} +5 -5
- package/dist/web/assets/{chunk-7PRAP22T-DH9TawZY.js → chunk-7PRAP22T-Bb3gaISA.js} +1 -1
- package/dist/web/assets/{chunk-GTNCS2PH-CKAuGvnf.js → chunk-GTNCS2PH-Cps7XhUC.js} +1 -1
- package/dist/web/assets/{chunk-GWA4HPMP-DTbHCHSN.js → chunk-GWA4HPMP-Bfp2Tg3_.js} +1 -1
- package/dist/web/assets/{chunk-MBY4JIJT-ClgvJMtC.js → chunk-MBY4JIJT-IfXbX1Ur.js} +1 -1
- package/dist/web/assets/{chunk-NETBCI7D-Dq5Z7z8S.js → chunk-NETBCI7D-r2fmahwk.js} +1 -1
- package/dist/web/assets/{chunk-O7XYJQB3-C0By5mcm.js → chunk-O7XYJQB3-sadsiWmA.js} +1 -1
- package/dist/web/assets/{chunk-UA2S7LBM-BtquYpxe.js → chunk-UA2S7LBM-DibfwtDn.js} +1 -1
- package/dist/web/assets/{chunk-WEXAMYUT-BlZL42XJ.js → chunk-WEXAMYUT-DBouMgEO.js} +1 -1
- package/dist/web/assets/{chunk-Z7XXMR3K-BbtQbAvv.js → chunk-Z7XXMR3K-fAHToON5.js} +1 -1
- package/dist/web/assets/{chunk-ZIGJFQKS-tC_YdRrm.js → chunk-ZIGJFQKS-CJG1UIHO.js} +1 -1
- package/dist/web/assets/{classDiagram-v2-NBCMYWYE-CvlA_A4N.js → classDiagram-v2-NBCMYWYE-CPHP5ynj.js} +4 -4
- package/dist/web/assets/clike-D_6L3tnO.js +1 -0
- package/dist/web/assets/clojure-BflJGmDX.js +1 -0
- package/dist/web/assets/cmake-84nbDH0I.js +1 -0
- package/dist/web/assets/cobol-DHLQUbN7.js +1 -0
- package/dist/web/assets/coffeescript-De_zI4J0.js +1 -0
- package/dist/web/assets/commonlisp-DgAKBe0r.js +1 -0
- package/dist/web/assets/core-Bumj8M77.js +12 -0
- package/dist/web/assets/crystal-Bsdphhtm.js +1 -0
- package/dist/web/assets/css-CnaYoQib.js +1 -0
- package/dist/web/assets/{cynefin-OW5HDTMX-DFbhKkIi.js → cynefin-OW5HDTMX-BU7_LYGR.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-VND7K2PF-DHGaLNQN.js → cynefinDiagram-VND7K2PF-BXFEy9Io.js} +1 -1
- package/dist/web/assets/cypher-p9eYesGn.js +1 -0
- package/dist/web/assets/d-DWkQyNnU.js +1 -0
- package/dist/web/assets/dagre-6A5THRUB-aKpdpQ18.js +4 -0
- package/dist/web/assets/{diagram-22UHCM2B-Djjo5ftL.js → diagram-22UHCM2B-ddbRgIQ9.js} +8 -8
- package/dist/web/assets/{diagram-3UASUU5V-BcP7pJru.js → diagram-3UASUU5V-vNYy6WP_.js} +1 -1
- package/dist/web/assets/{diagram-ATOU4E4O-o_vsc8em.js → diagram-ATOU4E4O-B9Z3zFfp.js} +1 -1
- package/dist/web/assets/{diagram-CDSNMT55-eyN9Aru8.js → diagram-CDSNMT55-D3TaDPXU.js} +1 -1
- package/dist/web/assets/{diagram-MLGK6HIB-Dfjipnvb.js → diagram-MLGK6HIB-DOXcXm2Y.js} +1 -1
- package/dist/web/assets/{diagram-MPIPVDR6-C2chocRe.js → diagram-MPIPVDR6-B5E2J8pO.js} +1 -1
- package/dist/web/assets/diff-ChtP43wD.js +1 -0
- package/dist/web/assets/dist-3B0OaUZ-.js +1 -0
- package/dist/web/assets/dist-BFbA030x.js +1 -0
- package/dist/web/assets/dist-BGzvKGEu.js +1 -0
- package/dist/web/assets/dist-BX8UA0fl.js +11 -0
- package/dist/web/assets/dist-BXUopzfH.js +2 -0
- package/dist/web/assets/dist-BY24_62d.js +1 -0
- package/dist/web/assets/dist-C3sBgvRy.js +1 -0
- package/dist/web/assets/dist-C9STut2J.js +1 -0
- package/dist/web/assets/dist-C9cJQvJH.js +23 -0
- package/dist/web/assets/dist-CRoJr3t6.js +6 -0
- package/dist/web/assets/dist-CqGqStPp.js +1 -0
- package/dist/web/assets/dist-Cxd9qKh7.js +1 -0
- package/dist/web/assets/dist-D2Ce45aH.js +13 -0
- package/dist/web/assets/dist-D7Llw4iH.js +1 -0
- package/dist/web/assets/dist-DSPzgfNo.js +1 -0
- package/dist/web/assets/dist-DUt0feNB.js +1 -0
- package/dist/web/assets/dist-DZQ2IsS9.js +1 -0
- package/dist/web/assets/dist-DpKJcdvz.js +1 -0
- package/dist/web/assets/dist-DuZv0LJj.js +1 -0
- package/dist/web/assets/dist-Kd0W7Y_b.js +9 -0
- package/dist/web/assets/dist-LFPPEX39.js +1 -0
- package/dist/web/assets/dist-PDsGXJi3.js +1 -0
- package/dist/web/assets/dist-lC0EKTFH.js +1 -0
- package/dist/web/assets/dockerfile-DJkHQgkl.js +1 -0
- package/dist/web/assets/dtd-DTF72YNO.js +1 -0
- package/dist/web/assets/dylan-BCDoL_-p.js +1 -0
- package/dist/web/assets/ebnf-D4c0_ac3.js +1 -0
- package/dist/web/assets/{ebnfDiagram-ZINNZB2B-CE58dwC-.js → ebnfDiagram-ZINNZB2B-D-OCB_ud.js} +1 -1
- package/dist/web/assets/ecl-BVIeWmwY.js +1 -0
- package/dist/web/assets/eiffel-BEjRio4Q.js +1 -0
- package/dist/web/assets/{elk-276RUBZZ-KyTn9aJi.js → elk-276RUBZZ-CzjP8RHy.js} +1 -1
- package/dist/web/assets/elm-Cshzl8qu.js +1 -0
- package/dist/web/assets/equal-arrays-GA_7ZCAb.js +1 -0
- package/dist/web/assets/{erDiagram-OPXOYQCR-D9aOi7ZD.js → erDiagram-OPXOYQCR-Clohps7p.js} +1 -1
- package/dist/web/assets/erlang-BV0c4Hdn.js +1 -0
- package/dist/web/assets/eventmodeling-NTZA5JFV-FWK4tnN_.js +1 -0
- package/dist/web/assets/factor-LKH5gN8L.js +1 -0
- package/dist/web/assets/fcl-ClOhbFR7.js +1 -0
- package/dist/web/assets/flowDiagram-KWPJA3E3-C10B5_6J.js +1 -0
- package/dist/web/assets/forth-D6RzAl64.js +1 -0
- package/dist/web/assets/fortran-Bt6PBEDR.js +1 -0
- package/dist/web/assets/{ganttDiagram-FUAMR5RP-DRAI6xWM.js → ganttDiagram-FUAMR5RP-ZWH4HYq5.js} +1 -1
- package/dist/web/assets/gas-BHEdbvp9.js +1 -0
- package/dist/web/assets/gherkin-oBAE_ms0.js +1 -0
- package/dist/web/assets/{gitGraph-4MIJSDKK-D1lAB6tr.js → gitGraph-4MIJSDKK-C3AfRnC8.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-X574FWY7-77GVnwya.js → gitGraphDiagram-X574FWY7-BobkQARX.js} +1 -1
- package/dist/web/assets/graphlib-C64HifUL.js +1 -0
- package/dist/web/assets/groovy-CUpZ7dEl.js +1 -0
- package/dist/web/assets/haskell-BRsoo5mP.js +1 -0
- package/dist/web/assets/haxe-DjVOVvNP.js +1 -0
- package/dist/web/assets/http-CLVgA2GD.js +1 -0
- package/dist/web/assets/i18n-CC_rvfan.js +1 -0
- package/dist/web/assets/idl-BUZw3wgd.js +1 -0
- package/dist/web/assets/index-Ic8yFbJg.js +2 -0
- package/dist/web/assets/{info-A6RAGUB7-Di1qRpwO.js → info-A6RAGUB7-Dh_SAe09.js} +1 -1
- package/dist/web/assets/{infoDiagram-VRGFBTTK-gceHneJ0.js → infoDiagram-VRGFBTTK-izDlhNTw.js} +1 -1
- package/dist/web/assets/{init-app-IHgDyoRH.js → init-app-C1a6BWWN.js} +1 -1
- package/dist/web/assets/{is-DssfAlMe.js → is-CE4jkrGQ.js} +1 -1
- package/dist/web/assets/isArrayLikeObject-BbaDyxId.js +1 -0
- package/dist/web/assets/{ishikawaDiagram-OU5B5YK6-B9QDQoSG.js → ishikawaDiagram-OU5B5YK6-BJ89XzVJ.js} +1 -1
- package/dist/web/assets/javascript-Bu8mWwtz.js +1 -0
- package/dist/web/assets/{journeyDiagram-ZHPQQLJL-CVTMW0pg.js → journeyDiagram-ZHPQQLJL-poV-f08K.js} +1 -1
- package/dist/web/assets/julia-CQfgDRfP.js +1 -0
- package/dist/web/assets/{kanban-definition-PNTS6WVX-TNoWYrUr.js → kanban-definition-PNTS6WVX-Cn3FEnH7.js} +1 -1
- package/dist/web/assets/{line-B_1CHIjZ.js → line-bE9Mqcqy.js} +1 -1
- package/dist/web/assets/livescript-BXxG0Yva.js +1 -0
- package/dist/web/assets/lua-DPCEkfD_.js +1 -0
- package/dist/web/assets/markdown-D85iiL_9.js +15 -0
- package/dist/web/assets/mathematica-u8YMmbU0.js +1 -0
- package/dist/web/assets/mbox-BEMVcqjs.js +1 -0
- package/dist/web/assets/{mermaid-parser.core-LAeoGxkL.js → mermaid-parser.core-Cua7H5pF.js} +3 -3
- package/dist/web/assets/{mermaid.core-DMppSzfM.js → mermaid.core-BMPOA8T-.js} +7 -7
- package/dist/web/assets/{mindmap-definition-NLK3R4M7-DJ-6nTWg.js → mindmap-definition-NLK3R4M7-DaTGr8Fs.js} +1 -1
- package/dist/web/assets/mirc-C9zpzAZU.js +1 -0
- package/dist/web/assets/mllike-B45xgp2S.js +1 -0
- package/dist/web/assets/modelica-CqHI_q-D.js +1 -0
- package/dist/web/assets/mscgen-qgSLujhx.js +1 -0
- package/dist/web/assets/mumps-BSzj6Xyz.js +1 -0
- package/dist/web/assets/nginx-8H7HVH4w.js +1 -0
- package/dist/web/assets/nsis-viPvXFiq.js +1 -0
- package/dist/web/assets/ntriples-B9h1VB_g.js +1 -0
- package/dist/web/assets/octave-D2Q8cUp1.js +1 -0
- package/dist/web/assets/oz-BwTct_5T.js +1 -0
- package/dist/web/assets/{packet-AYTQ26CC-B4tvN4nf.js → packet-AYTQ26CC-DmLfghd9.js} +1 -1
- package/dist/web/assets/pascal-Dp_KdFgX.js +1 -0
- package/dist/web/assets/{pegDiagram-GJSIUBJH-BwQ6jaVw.js → pegDiagram-GJSIUBJH-CTlxXcbf.js} +1 -1
- package/dist/web/assets/perl-BkSkiI9m.js +1 -0
- package/dist/web/assets/{pie-WAS4IAKB-ZwlyCxls.js → pie-WAS4IAKB-52oNsEtc.js} +1 -1
- package/dist/web/assets/{pieDiagram-5QR66LMP-BDYLBnB1.js → pieDiagram-5QR66LMP-CbJtB1te.js} +1 -1
- package/dist/web/assets/pig-AF4Hwhju.js +1 -0
- package/dist/web/assets/pinia-BlCzIRX-.js +1 -0
- package/dist/web/assets/powershell-BcIto6Sf.js +1 -0
- package/dist/web/assets/properties-C357ku5U.js +1 -0
- package/dist/web/assets/protobuf-D1ij_kNL.js +1 -0
- package/dist/web/assets/pug-3K-JMW4g.js +1 -0
- package/dist/web/assets/puppet-BZyAS7I4.js +1 -0
- package/dist/web/assets/purify.es--06brOip.js +3 -0
- package/dist/web/assets/python-B_1Jd8HM.js +1 -0
- package/dist/web/assets/q-B9NhS7L_.js +1 -0
- package/dist/web/assets/{quadrantDiagram-O4NWA36T-CkmLCxOG.js → quadrantDiagram-O4NWA36T-DCg-uD08.js} +1 -1
- package/dist/web/assets/r-CxDmU1I4.js +1 -0
- package/dist/web/assets/{radar-RG4KPBEZ-Ca7H5QOY.js → radar-RG4KPBEZ-9uA3AOZR.js} +1 -1
- package/dist/web/assets/{railroad-74A4TZTK-CX3Z2QYJ.js → railroad-74A4TZTK-BPxQfpxv.js} +1 -1
- package/dist/web/assets/railroad-abnf-HS5TGJTU-CPVHNg05.js +1 -0
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-DAjTaOUg.js +1 -0
- package/dist/web/assets/railroad-peg-WCYAUIDC-DkxyKsj4.js +1 -0
- package/dist/web/assets/{railroadDiagram-XR7U4H2S-D8ii6sM4.js → railroadDiagram-XR7U4H2S-CwBNr6fr.js} +1 -1
- package/dist/web/assets/{requirementDiagram-PLB6GJNP-iHY-tE7c.js → requirementDiagram-PLB6GJNP-BbtZt0St.js} +1 -1
- package/dist/web/assets/rpm-gpDK5sbt.js +1 -0
- package/dist/web/assets/ruby-ChfNwlCY.js +1 -0
- package/dist/web/assets/{safe-storage-BCP757jk.js → safe-storage-Bn-sHAYw.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-IPEJSGJF-CBprSUZk.js → sankeyDiagram-IPEJSGJF-DRWdMnFl.js} +1 -1
- package/dist/web/assets/sas-C2OyD2Y6.js +1 -0
- package/dist/web/assets/scheme-D9qYN0V5.js +1 -0
- package/dist/web/assets/{sequenceDiagram-PO4LG4MO-BkphpOQ_.js → sequenceDiagram-PO4LG4MO-C4tWeWpt.js} +1 -1
- package/dist/web/assets/shell-DwuoZtxw.js +1 -0
- package/dist/web/assets/sieve-tLWDfEkZ.js +1 -0
- package/dist/web/assets/simple-mode-DXiLM1-G.js +1 -0
- package/dist/web/assets/smalltalk-BLp5-jwC.js +1 -0
- package/dist/web/assets/solr-B78wSQJQ.js +1 -0
- package/dist/web/assets/sparql-Dz-mlCAC.js +1 -0
- package/dist/web/assets/spreadsheet-CTIncYxj.js +1 -0
- package/dist/web/assets/sql-DuQMFDvy.js +1 -0
- package/dist/web/assets/{stateDiagram-v2-GCMORJYK-HN1RwAPZ.js → stateDiagram-v2-GCMORJYK-pE0T1U5E.js} +2 -2
- package/dist/web/assets/stex-DNzd62Q_.js +1 -0
- package/dist/web/assets/stylus-BOVgKnng.js +1 -0
- package/dist/web/assets/swift-DKB6_1j6.js +1 -0
- package/dist/web/assets/{swimlanes-2SLR337P-Cc8jyETz.js → swimlanes-2SLR337P-DKky6E3p.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-CPhibEqM.js +8 -0
- package/dist/web/assets/tcl-BGfruO1u.js +1 -0
- package/dist/web/assets/textile-C4jVoHG1.js +1 -0
- package/dist/web/assets/theme-B-g7wQEs.js +1 -0
- package/dist/web/assets/tiddlywiki-VlUiK86J.js +1 -0
- package/dist/web/assets/tiki-AK6FwT8q.js +1 -0
- package/dist/web/assets/{timeline-definition-EJHVYXUP-Bas0Ksw6.js → timeline-definition-EJHVYXUP-CsRzcMLr.js} +1 -1
- package/dist/web/assets/toml-BPTmHmyx.js +1 -0
- package/dist/web/assets/{treeView-Q6P3EWNA-Ck-xt3KO.js → treeView-Q6P3EWNA-CQYqoPG3.js} +1 -1
- package/dist/web/assets/{treemap-WGGIJYW6-k9Ay9d-c.js → treemap-WGGIJYW6-BzFw4gFs.js} +1 -1
- package/dist/web/assets/troff-C2dAgh7P.js +1 -0
- package/dist/web/assets/ttcn-PPSTk1ow.js +1 -0
- package/dist/web/assets/ttcn-cfg-2b4Gb5sE.js +1 -0
- package/dist/web/assets/turtle-Cx3rYX2g.js +1 -0
- package/dist/web/assets/{use-app-theme-BfRqhHi_.js → use-app-theme-9qFZUBqz.js} +1 -1
- package/dist/web/assets/use-dark-BHObfh0O.js +1 -0
- package/dist/web/assets/use-panel-width-Dyh49bod.js +1 -0
- package/dist/web/assets/use-router-link-BGc0noIO.js +1 -0
- package/dist/web/assets/use-server-events-24_soFuj.js +1 -0
- package/dist/web/assets/use-virtual-scroll-BSXYZjZ5.js +1 -0
- package/dist/web/assets/{usecaseDiagram-POWQR4AR-BlzYgvXB.js → usecaseDiagram-POWQR4AR-IMfiBw6h.js} +1 -1
- package/dist/web/assets/vb-BthdM_4N.js +1 -0
- package/dist/web/assets/vbscript-D9f6rSsU.js +1 -0
- package/dist/web/assets/velocity-CqftRsjg.js +1 -0
- package/dist/web/assets/{vennDiagram-UO4OBE2U-gjloIQdf.js → vennDiagram-UO4OBE2U-JKdzpNy2.js} +1 -1
- package/dist/web/assets/verilog-CjI9Y6RI.js +1 -0
- package/dist/web/assets/vhdl-kS471soi.js +1 -0
- package/dist/web/assets/{wardley-WFR3VGLG-BnsYd7B2.js → wardley-WFR3VGLG-B9Yiwlp8.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-VNRHLVJA-ktflnFLZ.js → wardleyDiagram-VNRHLVJA-BVoc2hGS.js} +1 -1
- package/dist/web/assets/webidl-D5jiJvOU.js +1 -0
- package/dist/web/assets/xquery-BKJx4mf9.js +1 -0
- package/dist/web/assets/{xychartDiagram-PMCCYNJV-Ch5MYgz0.js → xychartDiagram-PMCCYNJV-B_XV1aim.js} +1 -1
- package/dist/web/assets/yacas-CXXgtw0p.js +1 -0
- package/dist/web/assets/z80-Co3PbHdE.js +1 -0
- package/dist/web/index.html +6 -3
- package/package.json +8 -2
- package/dist/web/assets/AppPage-BGcEFW_o.js +0 -93
- package/dist/web/assets/CreateReviewFabButton-CdUXVriU.js +0 -1
- package/dist/web/assets/IndexPage-OqgW0yH8.js +0 -1
- package/dist/web/assets/MainLayout-Bi0JE3ER.js +0 -11
- package/dist/web/assets/MainLayout-DPkSlqMr.css +0 -1
- package/dist/web/assets/QBtn-CzrOO1zA.js +0 -1
- package/dist/web/assets/QScrollArea-C4BKutrt.js +0 -1
- package/dist/web/assets/QSelect-BXUaq4ky.js +0 -1
- package/dist/web/assets/QSpace-BMpRu3a-.js +0 -13
- package/dist/web/assets/ReviewDetailPage-DlR7Vxkw.js +0 -1
- package/dist/web/assets/ReviewsPage-DM8XtlUK.js +0 -1
- package/dist/web/assets/StatusSwitcher-Blg5JmAa.js +0 -1
- package/dist/web/assets/agent-store-CDuiBhST.js +0 -1
- package/dist/web/assets/architecture-7GRP2DOG-DMgDJZyQ.js +0 -1
- package/dist/web/assets/channel-BnUyOMnk.js +0 -1
- package/dist/web/assets/core-C37KF-j0.js +0 -12
- package/dist/web/assets/dagre-6A5THRUB-Bk3Po5o5.js +0 -4
- package/dist/web/assets/eventmodeling-NTZA5JFV-7YdTAmVS.js +0 -1
- package/dist/web/assets/flowDiagram-KWPJA3E3-eOIiY2oF.js +0 -1
- package/dist/web/assets/graphlib-DS17s2tU.js +0 -1
- package/dist/web/assets/i18n-C5Xnmkwe.js +0 -1
- package/dist/web/assets/index-BqedItFI.js +0 -2
- package/dist/web/assets/pinia-BKoxNmoW.js +0 -1
- package/dist/web/assets/railroad-abnf-HS5TGJTU-DZSn8MK2.js +0 -1
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-BVTJtDBq.js +0 -1
- package/dist/web/assets/railroad-peg-WCYAUIDC-DMzsNGzj.js +0 -1
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-BxXXHQ70.js +0 -8
- package/dist/web/assets/theme-CPoPdFci.js +0 -1
- package/dist/web/assets/use-panel-width-C9dWftsJ.js +0 -1
- package/dist/web/assets/use-server-events-znzHKZZx.js +0 -1
- package/dist/web/assets/use-virtual-scroll-CIwaJCUj.js +0 -1
package/README.md
CHANGED
|
@@ -203,3 +203,42 @@ MIT, см. [LICENSE](LICENSE).
|
|
|
203
203
|
Если платформенный бинарник PTY недоступен, терминал работает в ограниченном режиме с баннером: команды вводятся в поле под выводом, Ctrl+C прерывает команду, Ctrl+D закрывает shell. `vim`, `less` и другие интерактивные программы требуют PTY. В LAN терминал отключён. Переключатель исходных цветов отключает минимальный контраст для программ со своей палитрой.
|
|
204
204
|
|
|
205
205
|
Для разработки на другом порту backend можно передать `GITHUMAN_DEV_API=http://localhost:3848` при запуске Quasar dev-сервера.
|
|
206
|
+
|
|
207
|
+
## Проектные заметки
|
|
208
|
+
|
|
209
|
+
Раздел **Notes** хранит Markdown-заметки в `.githuman/notes/` относительно
|
|
210
|
+
каталога запуска приложения. Поддерживаются папки, визуальный редактор, полный
|
|
211
|
+
исходник Markdown, редактируемые свойства YAML frontmatter и обычные относительные ссылки.
|
|
212
|
+
Внутренние ссылки активируют заметку в текущем окне; внешние открываются в новой вкладке.
|
|
213
|
+
Кнопка **Link to note** помогает выбрать заметку для ссылки; теги со счётчиками
|
|
214
|
+
в дереве фильтруют список. Изменения автоматически сохраняются после паузы ввода.
|
|
215
|
+
|
|
216
|
+
Другой каталог задаётся через `serve --notes-dir ./notes` или
|
|
217
|
+
`GITHUMAN_NOTES_DIR`; относительный путь считается от каталога запуска.
|
|
218
|
+
Такой каталог можно версионировать. Личное хранилище по умолчанию
|
|
219
|
+
исключается локально через Git `info/exclude`; уже отслеживаемые файлы
|
|
220
|
+
автоматически из индекса не удаляются.
|
|
221
|
+
|
|
222
|
+
При внешнем изменении файла редактор сохраняет черновик и предлагает сравнить
|
|
223
|
+
его с диском, загрузить дисковую версию или сохранить черновик отдельной
|
|
224
|
+
заметкой. Резервная предыдущая версия каждого изменённого файла лежит в
|
|
225
|
+
скрытом каталоге `.history` внутри хранилища; этот каталог не показывается
|
|
226
|
+
в дереве. При альтернативном Git-хранилище исключите `.history/` из Git,
|
|
227
|
+
если резервные копии не нужно публиковать.
|
|
228
|
+
|
|
229
|
+
Визуальное редактирование может нормализовать оформление списков, таблиц
|
|
230
|
+
и reference-ссылок. Открытие и переключение режимов без правок файл не
|
|
231
|
+
перезаписывают. Если при открытии визуальный редактор теряет конструкции,
|
|
232
|
+
приложение сохраняет исходный текст и переключается в Markdown. Вставленные PNG, JPEG, GIF и WebP (до 10 МБ) сохраняются в `assets/` внутри
|
|
233
|
+
хранилища заметок и доступны в визуальном редакторе после перезапуска. Ссылки
|
|
234
|
+
на вложения не зависят от хоста или порта сервиса. Внешние изображения
|
|
235
|
+
остаются в исходном режиме. Размер заметки ограничен 1 МБ; символические ссылки в
|
|
236
|
+
пути хранилища не поддерживаются. Черновик после аварии браузера пока
|
|
237
|
+
не восстанавливается.
|
|
238
|
+
|
|
239
|
+
Заметки имеют UUID в SQLite-каталоге; необязательный `githuman_id` в YAML помогает
|
|
240
|
+
распознавать внешние перемещения. Back/Forward и история браузера возвращают между
|
|
241
|
+
заметками. Rename в контекстном меню сохраняет ID и исправляет относительные ссылки;
|
|
242
|
+
дополнительное поле папки позволяет переместить элемент. Отсутствующие файлы показывают
|
|
243
|
+
заглушку; неоднозначные внешние изменения и незавершённые исправления доступны в Notes.
|
|
244
|
+
Markdown-ссылки остаются переносимыми. [Правила идентичности, восстановления и API](docs/notes-identity.md).
|
package/dist/cli/config.js
CHANGED
|
@@ -53,6 +53,7 @@ export function parseServeArgs(argv) {
|
|
|
53
53
|
host: { type: 'string' },
|
|
54
54
|
open: { type: 'boolean', default: true },
|
|
55
55
|
'no-open': { type: 'boolean', default: false },
|
|
56
|
+
'notes-dir': { type: 'string' },
|
|
56
57
|
'db-prefix': { type: 'string' },
|
|
57
58
|
'api-docs': { type: 'boolean', default: false }
|
|
58
59
|
},
|
|
@@ -63,5 +64,16 @@ export function parseServeArgs(argv) {
|
|
|
63
64
|
const open = values['no-open'] === true ? false : values.open !== false;
|
|
64
65
|
const dbPrefix = resolveDbPrefix(typeof values['db-prefix'] === 'string' ? values['db-prefix'] : undefined);
|
|
65
66
|
const apiDocs = values['api-docs'] === true;
|
|
66
|
-
return {
|
|
67
|
+
return {
|
|
68
|
+
port,
|
|
69
|
+
host,
|
|
70
|
+
open,
|
|
71
|
+
dbPrefix,
|
|
72
|
+
apiDocs,
|
|
73
|
+
...(typeof values['notes-dir'] === 'string'
|
|
74
|
+
? { notesDir: values['notes-dir'] }
|
|
75
|
+
: process.env.GITHUMAN_NOTES_DIR
|
|
76
|
+
? { notesDir: process.env.GITHUMAN_NOTES_DIR }
|
|
77
|
+
: {})
|
|
78
|
+
};
|
|
67
79
|
}
|
|
@@ -61,9 +61,12 @@ export async function startServer(options) {
|
|
|
61
61
|
const app = buildApp({
|
|
62
62
|
staticRoot: resolveStaticRoot(),
|
|
63
63
|
repositoryPath,
|
|
64
|
+
projectPath: process.cwd(),
|
|
65
|
+
notesDir: options.notesDir,
|
|
64
66
|
db,
|
|
65
67
|
watchFiles: true,
|
|
66
68
|
apiDocs: options.apiDocs === true,
|
|
69
|
+
loopbackBind: isLoopbackHost(options.host),
|
|
67
70
|
terminalEnabled: isLoopbackHost(options.host),
|
|
68
71
|
// Agents can run commands, so they are only offered on a loopback bind.
|
|
69
72
|
...(isLoopbackHost(options.host)
|
package/dist/server/app.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { watchNotes } from "./services/notes-watcher.service.js";
|
|
2
|
+
import { notesRoutes } from "./routes/notes.js";
|
|
3
|
+
import { NotesService } from "./services/notes.service.js";
|
|
1
4
|
import { NotFoundError } from "./errors/http.js";
|
|
2
5
|
import { randomUUID } from 'node:crypto';
|
|
3
6
|
import { readFileSync } from 'node:fs';
|
|
4
|
-
import { join } from 'node:path';
|
|
7
|
+
import { join, resolve } from 'node:path';
|
|
5
8
|
import Fastify from 'fastify';
|
|
6
9
|
import fastifyStatic from '@fastify/static';
|
|
10
|
+
import { ajvFilePlugin } from '@fastify/multipart';
|
|
7
11
|
import fastifyWebsocket from '@fastify/websocket';
|
|
8
12
|
import { terminalRoutes, TERMINAL_WEBSOCKET_OPTIONS } from "./routes/terminal.js";
|
|
9
13
|
import { TerminalRegistry } from "./services/terminal/registry.js";
|
|
@@ -32,14 +36,26 @@ import { watchRepository } from "./services/file-watcher.service.js";
|
|
|
32
36
|
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- documented workaround above
|
|
33
37
|
const fastifySse = fastifySseImport;
|
|
34
38
|
export function buildApp(options = {}) {
|
|
35
|
-
const app = Fastify({
|
|
39
|
+
const app = Fastify({
|
|
40
|
+
logger: false,
|
|
41
|
+
forceCloseConnections: true,
|
|
42
|
+
ajv: {
|
|
43
|
+
plugins: [
|
|
44
|
+
ajv => {
|
|
45
|
+
ajvFilePlugin(ajv);
|
|
46
|
+
return ajv;
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
});
|
|
36
51
|
const repositoryPath = options.repositoryPath ?? process.cwd();
|
|
37
52
|
const db = options.db ?? createTestDatabase();
|
|
38
53
|
const eventBus = options.eventBus ?? createEventBus();
|
|
39
54
|
// Windows includes a PTY binary, but the shell and process list are Unix-only.
|
|
40
55
|
const terminalEnabled = options.terminalEnabled === true && terminalSupported();
|
|
41
|
-
if (terminalEnabled)
|
|
56
|
+
if (terminalEnabled) {
|
|
42
57
|
app.register(fastifyWebsocket, TERMINAL_WEBSOCKET_OPTIONS);
|
|
58
|
+
}
|
|
43
59
|
app.register(fastifySse);
|
|
44
60
|
// The spec collects routes as they are added, so it comes before them.
|
|
45
61
|
app.register(fastifySwagger, openApiOptions());
|
|
@@ -54,6 +70,21 @@ export function buildApp(options = {}) {
|
|
|
54
70
|
mode: terminalEnabled ? ((await loadPty()) ? 'pty' : 'pipe') : null
|
|
55
71
|
})
|
|
56
72
|
});
|
|
73
|
+
const projectPath = options.projectPath ?? repositoryPath;
|
|
74
|
+
const notes = new NotesService(projectPath, resolve(projectPath, options.notesDir ?? '.githuman/notes'), options.notesDir === undefined, eventBus, db);
|
|
75
|
+
app.register(notesRoutes, {
|
|
76
|
+
service: notes,
|
|
77
|
+
loopbackBind: options.loopbackBind === true
|
|
78
|
+
});
|
|
79
|
+
app.addHook('onClose', async () => {
|
|
80
|
+
await notes.identity.close();
|
|
81
|
+
});
|
|
82
|
+
if (options.watchFiles) {
|
|
83
|
+
const watcher = watchNotes(notes, () => eventBus.publish({ type: 'notes:changed' }));
|
|
84
|
+
app.addHook('onClose', async () => {
|
|
85
|
+
watcher.close();
|
|
86
|
+
});
|
|
87
|
+
}
|
|
57
88
|
app.register(diffRoutes, { repositoryPath });
|
|
58
89
|
app.register(gitRoutes, { repositoryPath });
|
|
59
90
|
app.register(reviewRoutes, { repositoryPath, db, eventBus });
|
|
@@ -63,7 +94,7 @@ export function buildApp(options = {}) {
|
|
|
63
94
|
eventBus,
|
|
64
95
|
instanceId: options.instanceId ?? randomUUID()
|
|
65
96
|
});
|
|
66
|
-
if (terminalEnabled)
|
|
97
|
+
if (terminalEnabled) {
|
|
67
98
|
app.register(terminalRoutes, {
|
|
68
99
|
registry: options.terminalRegistry ??
|
|
69
100
|
new TerminalRegistry({
|
|
@@ -71,6 +102,7 @@ export function buildApp(options = {}) {
|
|
|
71
102
|
onLifecycle: event => app.log.info({ terminal: event }, 'Terminal lifecycle')
|
|
72
103
|
})
|
|
73
104
|
});
|
|
105
|
+
}
|
|
74
106
|
if (options.agentPresets) {
|
|
75
107
|
app.register(agentRoutes, {
|
|
76
108
|
registry: createSessionRegistry({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isSystemError } from "../utils/system-error.js";
|
|
1
2
|
import { readFileSync } from 'node:fs';
|
|
2
3
|
import { Type } from '@sinclair/typebox';
|
|
3
4
|
import { Value } from '@sinclair/typebox/value';
|
|
@@ -85,7 +86,7 @@ function readOverrides(overridesPath) {
|
|
|
85
86
|
raw = readFileSync(overridesPath, 'utf-8');
|
|
86
87
|
}
|
|
87
88
|
catch (error) {
|
|
88
|
-
if (error
|
|
89
|
+
if (isSystemError(error, 'ENOENT')) {
|
|
89
90
|
return {};
|
|
90
91
|
}
|
|
91
92
|
throw error;
|
|
@@ -17,6 +17,10 @@ export function openApiOptions() {
|
|
|
17
17
|
{ name: 'git', description: 'Repository facts, files and index.' },
|
|
18
18
|
{ name: 'reviews', description: 'Reviews and their export.' },
|
|
19
19
|
{ name: 'comments', description: 'Comments of reviews.' },
|
|
20
|
+
{
|
|
21
|
+
name: 'notes',
|
|
22
|
+
description: 'Project Markdown notes, folders and conditional saves.'
|
|
23
|
+
},
|
|
20
24
|
{ name: 'events', description: 'Server-sent change events.' },
|
|
21
25
|
{ name: 'app', description: 'Server version and health.' },
|
|
22
26
|
{
|
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
export function applyMigrations(db) {
|
|
2
2
|
db.exec(`
|
|
3
|
+
CREATE TABLE IF NOT EXISTS note_storages (
|
|
4
|
+
id TEXT PRIMARY KEY,
|
|
5
|
+
root TEXT NOT NULL UNIQUE
|
|
6
|
+
);
|
|
7
|
+
CREATE TABLE IF NOT EXISTS note_catalog (
|
|
8
|
+
storage_id TEXT NOT NULL REFERENCES note_storages(id),
|
|
9
|
+
id TEXT NOT NULL,
|
|
10
|
+
path TEXT NOT NULL,
|
|
11
|
+
presence TEXT NOT NULL,
|
|
12
|
+
version TEXT NOT NULL,
|
|
13
|
+
created_at TEXT NOT NULL,
|
|
14
|
+
updated_at TEXT NOT NULL,
|
|
15
|
+
path_changed_at TEXT NOT NULL,
|
|
16
|
+
redirect_id TEXT,
|
|
17
|
+
PRIMARY KEY(storage_id, id)
|
|
18
|
+
);
|
|
19
|
+
CREATE UNIQUE INDEX IF NOT EXISTS note_current_path ON note_catalog(storage_id, path) WHERE presence = 'present' AND redirect_id IS NULL;
|
|
20
|
+
CREATE TABLE IF NOT EXISTS note_path_history (
|
|
21
|
+
storage_id TEXT NOT NULL,
|
|
22
|
+
note_id TEXT NOT NULL,
|
|
23
|
+
old_path TEXT NOT NULL,
|
|
24
|
+
new_path TEXT NOT NULL,
|
|
25
|
+
changed_at TEXT NOT NULL,
|
|
26
|
+
operation_id TEXT NOT NULL,
|
|
27
|
+
FOREIGN KEY(storage_id, note_id) REFERENCES note_catalog(storage_id, id)
|
|
28
|
+
);
|
|
29
|
+
CREATE TABLE IF NOT EXISTS note_links (
|
|
30
|
+
storage_id TEXT NOT NULL,
|
|
31
|
+
source_id TEXT NOT NULL,
|
|
32
|
+
ordinal INTEGER NOT NULL,
|
|
33
|
+
target_id TEXT,
|
|
34
|
+
data TEXT NOT NULL,
|
|
35
|
+
FOREIGN KEY(storage_id, source_id) REFERENCES note_catalog(storage_id, id),
|
|
36
|
+
FOREIGN KEY(storage_id, target_id) REFERENCES note_catalog(storage_id, id),
|
|
37
|
+
PRIMARY KEY(storage_id, source_id, ordinal)
|
|
38
|
+
);
|
|
39
|
+
CREATE INDEX IF NOT EXISTS note_link_target ON note_links(storage_id, target_id);
|
|
40
|
+
CREATE TABLE IF NOT EXISTS note_issues (
|
|
41
|
+
storage_id TEXT NOT NULL REFERENCES note_storages(id),
|
|
42
|
+
id TEXT NOT NULL,
|
|
43
|
+
note_id TEXT,
|
|
44
|
+
candidate_id TEXT,
|
|
45
|
+
data TEXT NOT NULL,
|
|
46
|
+
PRIMARY KEY(storage_id, id),
|
|
47
|
+
FOREIGN KEY(storage_id,note_id) REFERENCES note_catalog(storage_id,id),
|
|
48
|
+
FOREIGN KEY(storage_id,candidate_id) REFERENCES note_catalog(storage_id,id)
|
|
49
|
+
);
|
|
50
|
+
CREATE TABLE IF NOT EXISTS note_issue_decisions (storage_id TEXT NOT NULL REFERENCES note_storages(id), id TEXT NOT NULL, PRIMARY KEY(storage_id,id));
|
|
51
|
+
CREATE TABLE IF NOT EXISTS note_operations (
|
|
52
|
+
storage_id TEXT NOT NULL REFERENCES note_storages(id),
|
|
53
|
+
id TEXT NOT NULL,
|
|
54
|
+
data TEXT NOT NULL,
|
|
55
|
+
PRIMARY KEY(storage_id, id)
|
|
56
|
+
);
|
|
57
|
+
|
|
3
58
|
CREATE TABLE IF NOT EXISTS reviews (
|
|
4
59
|
id TEXT PRIMARY KEY,
|
|
5
60
|
repository_path TEXT NOT NULL,
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import createError from '@fastify/error';
|
|
2
|
+
export const NoteConflictError = createError('GHT_NOTE_CONFLICT', 'The note changed on disk. Keep your draft and compare it with the disk version.', 409);
|
|
3
|
+
export const NoteExistsError = createError('GHT_NOTE_EXISTS', 'This path already exists.', 409);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { isLoopbackHost } from "../../../shared/network/loopback.js";
|
|
2
|
+
import { ForbiddenError } from "../../errors/http.js";
|
|
3
|
+
// Returns false on any malformed value: an invalid URL means an invalid origin.
|
|
4
|
+
function isSameOrigin(host, origin) {
|
|
5
|
+
if (!host)
|
|
6
|
+
return false;
|
|
7
|
+
try {
|
|
8
|
+
return new URL(origin).host === new URL(`http://${host}`).host;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function isLoopbackRequestHost(host) {
|
|
15
|
+
if (!host)
|
|
16
|
+
return false;
|
|
17
|
+
try {
|
|
18
|
+
return isLoopbackHost(new URL(`http://${host}`).hostname);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// A loopback bind also needs a loopback Host. A rebound hostile domain sends
|
|
25
|
+
// matching Origin and Host, so the match alone does not stop DNS rebinding.
|
|
26
|
+
// ADR 0008 allows LAN access without a password, so other binds skip this check.
|
|
27
|
+
export function createNotesOriginHook(options) {
|
|
28
|
+
return async function requireNotesOrigin(request) {
|
|
29
|
+
const { host, origin } = request.headers;
|
|
30
|
+
if (options.loopbackBind && !isLoopbackRequestHost(host)) {
|
|
31
|
+
throw new ForbiddenError('Notes only accept requests from this local server. Open the app via localhost.');
|
|
32
|
+
}
|
|
33
|
+
if (origin && !isSameOrigin(host, origin)) {
|
|
34
|
+
throw new ForbiddenError('Notes require the same origin as this server');
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -20,6 +20,7 @@ function isTerminalOrigin(host, origin) {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
export async function requireTerminalOrigin(request) {
|
|
23
|
-
if (!isTerminalOrigin(request.headers.host, request.headers.origin))
|
|
23
|
+
if (!isTerminalOrigin(request.headers.host, request.headers.origin)) {
|
|
24
24
|
throw new ForbiddenError('Terminal endpoints only accept requests from this local server. Open the app via localhost.');
|
|
25
|
+
}
|
|
25
26
|
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
function toNote(row) {
|
|
3
|
+
return {
|
|
4
|
+
id: row.id,
|
|
5
|
+
path: row.path,
|
|
6
|
+
presence: row.presence,
|
|
7
|
+
version: row.version,
|
|
8
|
+
createdAt: row.created_at,
|
|
9
|
+
updatedAt: row.updated_at,
|
|
10
|
+
redirectId: row.redirect_id
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export class NotesCatalogRepository {
|
|
14
|
+
storageId;
|
|
15
|
+
db;
|
|
16
|
+
constructor(db, root) {
|
|
17
|
+
this.db = db;
|
|
18
|
+
const row = db
|
|
19
|
+
.prepare('SELECT id FROM note_storages WHERE root = ?')
|
|
20
|
+
.get(root);
|
|
21
|
+
this.storageId = row?.id ?? randomUUID();
|
|
22
|
+
if (!row) {
|
|
23
|
+
db.prepare('INSERT INTO note_storages(id,root) VALUES(?,?)').run(this.storageId, root);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
transaction(run) {
|
|
27
|
+
this.db.exec('SAVEPOINT notes_catalog');
|
|
28
|
+
try {
|
|
29
|
+
const value = run();
|
|
30
|
+
this.db.exec('RELEASE notes_catalog');
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
this.db.exec('ROLLBACK TO notes_catalog; RELEASE notes_catalog');
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
all() {
|
|
39
|
+
return this.db
|
|
40
|
+
.prepare('SELECT * FROM note_catalog WHERE storage_id = ? ORDER BY path, id')
|
|
41
|
+
.all(this.storageId).map(toNote);
|
|
42
|
+
}
|
|
43
|
+
get(id) {
|
|
44
|
+
const row = this.db
|
|
45
|
+
.prepare('SELECT * FROM note_catalog WHERE storage_id = ? AND id = ?')
|
|
46
|
+
.get(this.storageId, id);
|
|
47
|
+
return row ? toNote(row) : undefined;
|
|
48
|
+
}
|
|
49
|
+
put(note) {
|
|
50
|
+
this.db
|
|
51
|
+
.prepare(`INSERT INTO note_catalog(storage_id,id,path,presence,version,created_at,updated_at,path_changed_at,redirect_id) VALUES(?,?,?,?,?,?,?,?,?)
|
|
52
|
+
ON CONFLICT(storage_id,id) DO UPDATE SET path=excluded.path,presence=excluded.presence,version=excluded.version,updated_at=excluded.updated_at,path_changed_at=CASE WHEN note_catalog.path != excluded.path THEN strftime('%Y-%m-%dT%H:%M:%fZ','now') ELSE note_catalog.path_changed_at END,redirect_id=excluded.redirect_id`)
|
|
53
|
+
.run(this.storageId, note.id, note.path, note.presence, note.version, note.createdAt, note.updatedAt, note.updatedAt, note.redirectId);
|
|
54
|
+
}
|
|
55
|
+
links(id) {
|
|
56
|
+
const rows = this.db
|
|
57
|
+
.prepare('SELECT data FROM note_links WHERE storage_id = ? AND source_id = ? ORDER BY ordinal')
|
|
58
|
+
.all(this.storageId, id);
|
|
59
|
+
return rows.map(row => JSON.parse(row.data));
|
|
60
|
+
}
|
|
61
|
+
setLinks(id, links) {
|
|
62
|
+
this.transaction(() => {
|
|
63
|
+
this.db
|
|
64
|
+
.prepare('DELETE FROM note_links WHERE storage_id = ? AND source_id = ?')
|
|
65
|
+
.run(this.storageId, id);
|
|
66
|
+
const stmt = this.db.prepare('INSERT INTO note_links(storage_id,source_id,ordinal,target_id,data) VALUES(?,?,?,?,?)');
|
|
67
|
+
links.forEach((link, ordinal) => stmt.run(this.storageId, id, ordinal, link.targetId, JSON.stringify(link)));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
history(id, from, to, operationId) {
|
|
71
|
+
this.db
|
|
72
|
+
.prepare('INSERT INTO note_path_history VALUES(?,?,?,?,?,?)')
|
|
73
|
+
.run(this.storageId, id, from, to, new Date().toISOString(), operationId);
|
|
74
|
+
}
|
|
75
|
+
historical(path) {
|
|
76
|
+
const rows = this.db
|
|
77
|
+
.prepare('SELECT DISTINCT note_id FROM note_path_history WHERE storage_id = ? AND old_path = ?')
|
|
78
|
+
.all(this.storageId, path);
|
|
79
|
+
return rows.map(row => row.note_id);
|
|
80
|
+
}
|
|
81
|
+
issues() {
|
|
82
|
+
const rows = this.db
|
|
83
|
+
.prepare('SELECT data FROM note_issues WHERE storage_id = ? ORDER BY id')
|
|
84
|
+
.all(this.storageId);
|
|
85
|
+
return rows.map(row => JSON.parse(row.data));
|
|
86
|
+
}
|
|
87
|
+
issue(issue) {
|
|
88
|
+
if (this.db
|
|
89
|
+
.prepare('SELECT 1 FROM note_issue_decisions WHERE storage_id = ? AND id = ?')
|
|
90
|
+
.get(this.storageId, issue.id)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this.db
|
|
94
|
+
.prepare('INSERT OR REPLACE INTO note_issues(storage_id,id,note_id,candidate_id,data) VALUES(?,?,?,?,?)')
|
|
95
|
+
.run(this.storageId, issue.id, issue.noteId, issue.candidateId, JSON.stringify(issue));
|
|
96
|
+
}
|
|
97
|
+
reopen(id) {
|
|
98
|
+
this.db
|
|
99
|
+
.prepare('DELETE FROM note_issue_decisions WHERE storage_id = ? AND id = ?')
|
|
100
|
+
.run(this.storageId, id);
|
|
101
|
+
}
|
|
102
|
+
dismiss(id, permanent = false) {
|
|
103
|
+
if (permanent) {
|
|
104
|
+
this.db
|
|
105
|
+
.prepare('INSERT OR IGNORE INTO note_issue_decisions VALUES(?,?)')
|
|
106
|
+
.run(this.storageId, id);
|
|
107
|
+
}
|
|
108
|
+
this.db
|
|
109
|
+
.prepare('DELETE FROM note_issues WHERE storage_id = ? AND id = ?')
|
|
110
|
+
.run(this.storageId, id);
|
|
111
|
+
}
|
|
112
|
+
operations() {
|
|
113
|
+
const rows = this.db
|
|
114
|
+
.prepare('SELECT data FROM note_operations WHERE storage_id = ? ORDER BY rowid')
|
|
115
|
+
.all(this.storageId);
|
|
116
|
+
return rows.map(row => JSON.parse(row.data));
|
|
117
|
+
}
|
|
118
|
+
operation(operation) {
|
|
119
|
+
this.db
|
|
120
|
+
.prepare('INSERT OR REPLACE INTO note_operations VALUES(?,?,?)')
|
|
121
|
+
.run(this.storageId, operation.id, JSON.stringify(operation));
|
|
122
|
+
}
|
|
123
|
+
finishOperation(id) {
|
|
124
|
+
this.db
|
|
125
|
+
.prepare('DELETE FROM note_operations WHERE storage_id = ? AND id = ?')
|
|
126
|
+
.run(this.storageId, id);
|
|
127
|
+
}
|
|
128
|
+
}
|